Skip to content

Commit ef7fb8e

Browse files
committed
Modifier Variable Type
The `modifier` variable type has been added to Canvas and can be used in site builder schemas. - Added `modifier` to `Canvas::Constants::PRIMITIVE_TYPES` - Created `Canvas::Validator::SchemaAttribute::Modifier` validator class - Supports `random` as a default value (similar to product/variant types) - Can be used as single values or arrays - Follows the same validation patterns as other Canvas variable types
1 parent 02f9d39 commit ef7fb8e

File tree

5 files changed

+310
-1
lines changed

5 files changed

+310
-1
lines changed

lib/canvas/constants.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module Constants
1616
color
1717
image
1818
link
19+
modifier
1920
number
2021
page
2122
post

lib/canvas/validators/schema_attribute.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module Validator
2020
class SchemaAttribute
2121
VALIDATORS = {
2222
"image" => SchemaAttribute::Image,
23+
"modifier" => SchemaAttribute::Modifier,
2324
"product" => SchemaAttribute::Product,
2425
"post" => SchemaAttribute::Post,
2526
"page" => SchemaAttribute::Page,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
module Canvas
4+
module Validator
5+
class SchemaAttribute
6+
# :documented:
7+
# Attribute validations specific to modifier-type variables.
8+
# Modifier drops expose name and id properties for use in site builder schemas.
9+
class Modifier < Base
10+
ALLOWED_DEFAULT_VALUES = %w[random].freeze
11+
12+
def validate
13+
super &&
14+
ensure_default_values_are_valid
15+
end
16+
17+
private
18+
19+
def permitted_values_for_default_key
20+
if attribute["array"]
21+
Array
22+
else
23+
String
24+
end
25+
end
26+
27+
def ensure_default_values_are_valid
28+
return true unless attribute.key?("default")
29+
30+
if attribute["array"]
31+
attribute["default"].all? { |value| default_value_is_valid?(value) }
32+
else
33+
default_value_is_valid?(attribute["default"])
34+
end
35+
end
36+
37+
def default_value_is_valid?(value)
38+
value = value.downcase
39+
if !ALLOWED_DEFAULT_VALUES.include?(value)
40+
@errors << %["default" for modifier-type variables must be one of: #{ALLOWED_DEFAULT_VALUES.join(', ')}]
41+
false
42+
else
43+
true
44+
end
45+
end
46+
end
47+
end
48+
end
49+
end

spec/lib/canvas/checks/valid_json_check_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
it "adds an offense when a file contains invalid json" do
1616
copy_example_directory("vagabond")
1717
subject.run
18-
message_pattern = /Invalid JSON: .+ - \nunexpected \w+(?:: | at )'This is an invalid custom type\.\n'/
18+
message_pattern = /Invalid JSON: .*types\/card\.json - \nunexpected character: 'This' at line 1 column 1/
1919

2020
expect(subject.offenses).to match_array(
2121
[
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# frozen_string_literal: true
2+
3+
describe Canvas::Validator::SchemaAttribute::Modifier do
4+
subject(:validator) { described_class.new(attribute) }
5+
6+
describe "#validate" do
7+
context "when the attribute has only required keys" do
8+
let(:attribute) {
9+
{
10+
"name" => "my_modifier",
11+
"type" => "modifier"
12+
}
13+
}
14+
15+
it "returns true" do
16+
expect(validator.validate).to eq(true)
17+
end
18+
end
19+
20+
context "when the attribute has optional keys" do
21+
let(:attribute) {
22+
{
23+
"name" => "featured_modifier",
24+
"type" => "modifier",
25+
"label" => "Featured Modifier",
26+
"hint" => "Select a modifier to feature",
27+
"group" => "content"
28+
}
29+
}
30+
31+
it "returns true" do
32+
expect(validator.validate).to eq(true)
33+
end
34+
end
35+
36+
describe "validating an optional 'default' key" do
37+
context "when unknown default value is provided" do
38+
let(:attribute) {
39+
{
40+
"name" => "my_modifier",
41+
"type" => "modifier",
42+
"default" => "invalid_value"
43+
}
44+
}
45+
46+
it "adds an error and fails the validation" do
47+
expect(validator.validate).to eq(false)
48+
expect(validator.errors).to include(
49+
"\"default\" for modifier-type variables must be one of: random"
50+
)
51+
end
52+
end
53+
54+
context "when 'random' default value is provided" do
55+
let(:attribute) {
56+
{
57+
"name" => "my_modifier",
58+
"type" => "modifier",
59+
"default" => "random"
60+
}
61+
}
62+
63+
it "passes the validation" do
64+
expect(validator.validate).to eq(true)
65+
end
66+
end
67+
68+
context "when 'Random' (capitalized) default value is provided" do
69+
let(:attribute) {
70+
{
71+
"name" => "my_modifier",
72+
"type" => "modifier",
73+
"default" => "Random"
74+
}
75+
}
76+
77+
it "passes the validation" do
78+
expect(validator.validate).to eq(true)
79+
end
80+
end
81+
82+
context "when modifier is an array" do
83+
context "when 'default' is an array of invalid options" do
84+
let(:attribute) {
85+
{
86+
"name" => "my_modifiers",
87+
"type" => "modifier",
88+
"array" => true,
89+
"default" => %w[random invalid_value]
90+
}
91+
}
92+
93+
it "returns false" do
94+
expect(validator.validate).to eq(false)
95+
expect(validator.errors).to include(
96+
"\"default\" for modifier-type variables must be one of: random"
97+
)
98+
end
99+
end
100+
101+
context "when 'default' is an array of valid options" do
102+
let(:attribute) {
103+
{
104+
"name" => "my_modifiers",
105+
"type" => "modifier",
106+
"array" => true,
107+
"default" => %w[Random random]
108+
}
109+
}
110+
111+
it "returns true" do
112+
expect(validator.validate).to eq(true)
113+
end
114+
end
115+
116+
context "when 'default' is not an array for array type" do
117+
let(:attribute) {
118+
{
119+
"name" => "my_modifiers",
120+
"type" => "modifier",
121+
"array" => true,
122+
"default" => "random"
123+
}
124+
}
125+
126+
it "returns false" do
127+
expect(validator.validate).to eq(false)
128+
expect(validator.errors).to include(
129+
"\"default\" is a String, expected Array"
130+
)
131+
end
132+
end
133+
end
134+
135+
context "when modifier is not an array" do
136+
context "when 'default' is an array for non-array type" do
137+
let(:attribute) {
138+
{
139+
"name" => "my_modifier",
140+
"type" => "modifier",
141+
"default" => ["random"]
142+
}
143+
}
144+
145+
it "returns false" do
146+
expect(validator.validate).to eq(false)
147+
expect(validator.errors).to include(
148+
"\"default\" is a Array, expected String"
149+
)
150+
end
151+
end
152+
end
153+
end
154+
155+
describe "array support" do
156+
context "when modifier is defined as an array" do
157+
let(:attribute) {
158+
{
159+
"name" => "modifier_list",
160+
"type" => "modifier",
161+
"array" => true
162+
}
163+
}
164+
165+
it "returns true" do
166+
expect(validator.validate).to eq(true)
167+
end
168+
end
169+
170+
context "when modifier array has a valid default" do
171+
let(:attribute) {
172+
{
173+
"name" => "modifier_list",
174+
"type" => "modifier",
175+
"array" => true,
176+
"default" => ["random"]
177+
}
178+
}
179+
180+
it "returns true" do
181+
expect(validator.validate).to eq(true)
182+
end
183+
end
184+
end
185+
186+
describe "inheritance from base validator" do
187+
context "when missing required 'name' key" do
188+
let(:attribute) {
189+
{
190+
"type" => "modifier"
191+
}
192+
}
193+
194+
it "returns false with errors" do
195+
expect(validator.validate).to eq(false)
196+
expect(validator.errors).to include("Missing required keys: name")
197+
end
198+
end
199+
200+
context "when missing required 'type' key" do
201+
let(:attribute) {
202+
{
203+
"name" => "my_modifier"
204+
}
205+
}
206+
207+
it "returns false with errors" do
208+
expect(validator.validate).to eq(false)
209+
expect(validator.errors).to include("Missing required keys: type")
210+
end
211+
end
212+
213+
context "when using unrecognized keys" do
214+
let(:attribute) {
215+
{
216+
"name" => "my_modifier",
217+
"type" => "modifier",
218+
"invalid_key" => "value"
219+
}
220+
}
221+
222+
it "returns false with errors" do
223+
expect(validator.validate).to eq(false)
224+
expect(validator.errors).to include("Unrecognized keys: invalid_key")
225+
end
226+
end
227+
228+
context "when name is not a string" do
229+
let(:attribute) {
230+
{
231+
"name" => 123,
232+
"type" => "modifier"
233+
}
234+
}
235+
236+
it "returns false with errors" do
237+
expect(validator.validate).to eq(false)
238+
expect(validator.errors).to include("\"name\" is a Integer, expected String")
239+
end
240+
end
241+
242+
context "when array is not a boolean" do
243+
let(:attribute) {
244+
{
245+
"name" => "my_modifier",
246+
"type" => "modifier",
247+
"array" => "yes"
248+
}
249+
}
250+
251+
it "returns false with errors" do
252+
expect(validator.validate).to eq(false)
253+
expect(validator.errors).to include("\"array\" is 'yes', expected one of: true, false")
254+
end
255+
end
256+
end
257+
end
258+
end

0 commit comments

Comments
 (0)