slidefield 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +674 -0
- data/README.md +254 -0
- data/Rakefile +7 -0
- data/bin/slidefield +89 -0
- data/examples/complete/assets/K2.jpg +0 -0
- data/examples/complete/assets/gobi.jpg +0 -0
- data/examples/complete/assets/mount_everest.jpg +0 -0
- data/examples/complete/assets/sahara.jpg +0 -0
- data/examples/complete/main.sfp +7 -0
- data/examples/complete/slides/deserts.sfi +19 -0
- data/examples/complete/slides/mountains.sfi +25 -0
- data/examples/complete/templates.sfi +95 -0
- data/examples/complete/variables.sfi +6 -0
- data/examples/minimal/main.sfp +43 -0
- data/examples/minimal/ruby-logo.png +0 -0
- data/lib/slidefield/animator.rb +104 -0
- data/lib/slidefield/errors.rb +6 -0
- data/lib/slidefield/interpreter.rb +414 -0
- data/lib/slidefield/object_data.rb +78 -0
- data/lib/slidefield/object_manager.rb +29 -0
- data/lib/slidefield/object_rules.rb +79 -0
- data/lib/slidefield/objects/_base.rb +29 -0
- data/lib/slidefield/objects/_root.rb +10 -0
- data/lib/slidefield/objects/animation.rb +10 -0
- data/lib/slidefield/objects/debug.rb +18 -0
- data/lib/slidefield/objects/image.rb +47 -0
- data/lib/slidefield/objects/include.rb +9 -0
- data/lib/slidefield/objects/layout.rb +10 -0
- data/lib/slidefield/objects/rect.rb +44 -0
- data/lib/slidefield/objects/slide.rb +43 -0
- data/lib/slidefield/objects/song.rb +31 -0
- data/lib/slidefield/objects/text.rb +57 -0
- data/lib/slidefield/parser.rb +99 -0
- data/lib/slidefield/version.rb +3 -0
- data/lib/slidefield/viewer.rb +89 -0
- data/lib/slidefield.rb +27 -0
- data/slidefield.gemspec +27 -0
- data/test/helper.rb +11 -0
- data/test/resources/include_sub.sfp +1 -0
- data/test/resources/parse_error.sfp +1 -0
- data/test/resources/recursive_include.sfp +1 -0
- data/test/resources/sub/include_parent.sfp +1 -0
- data/test/resources/unclosed_object.sfp +2 -0
- data/test/resources/unknown_object.sfp +1 -0
- data/test/resources/wrong_template.sfp +4 -0
- data/test/test_animator.rb +244 -0
- data/test/test_examples.rb +29 -0
- data/test/test_interpreter.rb +1766 -0
- data/test/test_object_data.rb +108 -0
- data/test/test_object_manager.rb +48 -0
- data/test/test_object_rules.rb +87 -0
- data/test/test_parser.rb +408 -0
- metadata +199 -0
@@ -0,0 +1,414 @@
|
|
1
|
+
class SlideField::Interpreter
|
2
|
+
attr_accessor :root
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@parser = SlideField::Parser.new
|
6
|
+
@files = []
|
7
|
+
@root = SlideField::ObjectData.new(:ROOT, 'line 0 char 0')
|
8
|
+
end
|
9
|
+
|
10
|
+
def run_file(path, parent_obj = nil)
|
11
|
+
if @files.include? path
|
12
|
+
raise SlideField::InterpreterError,
|
13
|
+
"File already interpreted: '#{path}'"
|
14
|
+
else
|
15
|
+
@files << path
|
16
|
+
end
|
17
|
+
|
18
|
+
file = Pathname.new path
|
19
|
+
|
20
|
+
begin
|
21
|
+
input = file.read
|
22
|
+
rescue => e
|
23
|
+
raise SlideField::InterpreterError, e.message
|
24
|
+
end
|
25
|
+
|
26
|
+
include_path = file.dirname.to_s
|
27
|
+
@rootpath = Pathname.new(include_path) if parent_obj.nil? || @rootpath.nil?
|
28
|
+
context = file.relative_path_from(@rootpath).to_s
|
29
|
+
|
30
|
+
run_string input, include_path, context, parent_obj
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_string(input, include_path = '.', context = 'input', parent_obj = nil)
|
34
|
+
include_path = File.absolute_path(include_path) + File::SEPARATOR
|
35
|
+
|
36
|
+
object = parent_obj || @root
|
37
|
+
object.include_path = include_path unless object.include_path
|
38
|
+
object.context = context unless object.context
|
39
|
+
|
40
|
+
close = parent_obj.nil?
|
41
|
+
|
42
|
+
begin
|
43
|
+
tree = @parser.parse input, reporter: Parslet::ErrorReporter::Deepest.new
|
44
|
+
rescue Parslet::ParseFailed => error
|
45
|
+
cause = error.cause
|
46
|
+
reason = nil
|
47
|
+
|
48
|
+
while cause
|
49
|
+
reason = cause.to_s
|
50
|
+
cause = cause.children.last
|
51
|
+
end
|
52
|
+
|
53
|
+
raise SlideField::ParseError, reason
|
54
|
+
end
|
55
|
+
|
56
|
+
interpret_tree tree, object, include_path, context, close
|
57
|
+
rescue SlideField::Error => error
|
58
|
+
message = error.message
|
59
|
+
|
60
|
+
if !message.start_with?('[') && message =~ /line (\d+) char (\d+)/
|
61
|
+
line = $1.to_i - 1
|
62
|
+
column = $2.to_i - 1
|
63
|
+
|
64
|
+
if line > -1 && source = input.lines[line]
|
65
|
+
excerpt = source.strip
|
66
|
+
column -= source.index excerpt
|
67
|
+
arrow = "#{"\x20" * column}^"
|
68
|
+
|
69
|
+
message += "\n\t#{excerpt}\n\t#{arrow}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
raise error.class, "[#{context}] #{message}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def interpret_tree(tree, object, child_path = nil, child_context = nil, close_object = true)
|
77
|
+
tree.respond_to? :each and tree.each {|stmt|
|
78
|
+
if stmt_data = stmt[:assignment]
|
79
|
+
interpret_assignment stmt_data, object
|
80
|
+
elsif stmt_data = stmt[:object]
|
81
|
+
interpret_object stmt_data, object, child_path, child_context
|
82
|
+
else
|
83
|
+
# we got strange data from the parser?!
|
84
|
+
raise "Unsupported statement '#{stmt.keys.first}'"
|
85
|
+
end
|
86
|
+
}
|
87
|
+
|
88
|
+
if close_object
|
89
|
+
# finalize the object once all its content has been processed
|
90
|
+
|
91
|
+
rules = object.rules
|
92
|
+
rules.required_properties.each {|name|
|
93
|
+
unless object.get name
|
94
|
+
raise SlideField::InterpreterError,
|
95
|
+
"Missing property '#{name}' for object '#{object.type}' at #{object.loc}"
|
96
|
+
end
|
97
|
+
}
|
98
|
+
|
99
|
+
rules.optional_properties.each {|name|
|
100
|
+
next unless object.get(name).nil?
|
101
|
+
|
102
|
+
default = rules.default_value name
|
103
|
+
type = rules.type_of_property name
|
104
|
+
|
105
|
+
object.set name, default, 'default', type
|
106
|
+
}
|
107
|
+
|
108
|
+
rules.accepted_children.each {|type|
|
109
|
+
min, max = rules.requirements_of_child type
|
110
|
+
count = object[type].count
|
111
|
+
|
112
|
+
if count < min
|
113
|
+
raise SlideField::InterpreterError,
|
114
|
+
"Object '#{object.type}' must have at least #{min} '#{type}', #{count} found at #{object.loc}"
|
115
|
+
end
|
116
|
+
|
117
|
+
if max > 0 && count > max
|
118
|
+
raise SlideField::InterpreterError,
|
119
|
+
"Object '#{object.type}' can not have more than #{max} '#{type}', #{count} found at #{object.loc}"
|
120
|
+
end
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
object
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
def interpret_assignment(stmt_data, object)
|
129
|
+
var_name_t = stmt_data[:variable]
|
130
|
+
var_name = var_name_t.to_sym
|
131
|
+
|
132
|
+
operator_t = stmt_data[:operator]
|
133
|
+
operator = operator_t.to_s
|
134
|
+
|
135
|
+
var_type, var_value_t, var_value = extract_value stmt_data[:value], object
|
136
|
+
|
137
|
+
case operator
|
138
|
+
when '='
|
139
|
+
if object.has? var_name
|
140
|
+
raise SlideField::InterpreterError,
|
141
|
+
"Variable '#{var_name}' is already defined at #{get_loc var_name_t}"
|
142
|
+
end
|
143
|
+
|
144
|
+
if valid_type = object.rules.type_of_property(var_name)
|
145
|
+
if var_type != valid_type
|
146
|
+
raise SlideField::InterpreterError,
|
147
|
+
"Unexpected '#{var_type}', expecting '#{valid_type}' for property '#{var_name}' at #{get_loc var_value_t}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
object.set var_name, var_value, get_loc(var_value_t), var_type
|
152
|
+
when '+=', '-=', '*=', '/='
|
153
|
+
origin_val = object.get var_name
|
154
|
+
unless origin_val
|
155
|
+
raise SlideField::InterpreterError,
|
156
|
+
"Undefined variable '#{var_name}' at #{get_loc var_name_t}"
|
157
|
+
end
|
158
|
+
origin_type = object.var_type var_name
|
159
|
+
|
160
|
+
method = operator[0]
|
161
|
+
|
162
|
+
if var_type != origin_type
|
163
|
+
raise SlideField::InterpreterError,
|
164
|
+
"Unexpected '#{var_type}', expecting '#{origin_type}' for variable or property '#{var_name}' at #{get_loc var_value_t}"
|
165
|
+
end
|
166
|
+
|
167
|
+
value = nil
|
168
|
+
|
169
|
+
case origin_type
|
170
|
+
when :integer
|
171
|
+
value = origin_val.send method, var_value
|
172
|
+
when :point, :color
|
173
|
+
if origin_type != :color || ['+=', '-='].include?(operator)
|
174
|
+
value = origin_val.collect.with_index {|v, i| v.send method, var_value[i] }
|
175
|
+
|
176
|
+
if origin_type == :color
|
177
|
+
# normalize
|
178
|
+
value.collect! {|v|
|
179
|
+
v = 0 if v < 0
|
180
|
+
v = 255 if v > 255
|
181
|
+
v
|
182
|
+
}
|
183
|
+
end
|
184
|
+
end
|
185
|
+
when :string
|
186
|
+
case operator
|
187
|
+
when '+='
|
188
|
+
value = origin_val + var_value
|
189
|
+
when '-='
|
190
|
+
copy = origin_val.dup
|
191
|
+
copy[var_value] = '' while copy.include? var_value
|
192
|
+
value = copy
|
193
|
+
when '*='
|
194
|
+
multiplier = var_value.to_i
|
195
|
+
if multiplier < 1
|
196
|
+
raise SlideField::InterpreterError,
|
197
|
+
"Invalid string multiplier '#{var_value}', integer > 0 required at #{get_loc var_value_t}"
|
198
|
+
end
|
199
|
+
value = origin_val * multiplier
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
unless value
|
204
|
+
raise SlideField::InterpreterError,
|
205
|
+
"Invalid operator '#{operator}' for type '#{origin_type}' at #{get_loc operator_t}"
|
206
|
+
end
|
207
|
+
|
208
|
+
object.set var_name, value, get_loc(var_value_t)
|
209
|
+
else
|
210
|
+
# the parser gave us strange data?!
|
211
|
+
raise "Unsupported operator '#{operator}' at #{get_loc operator_t}"
|
212
|
+
end
|
213
|
+
rescue ZeroDivisionError
|
214
|
+
raise SlideField::InterpreterError,
|
215
|
+
"divided by zero at #{get_loc var_value_t}"
|
216
|
+
end
|
217
|
+
|
218
|
+
def interpret_object(stmt_data, object, include_path, context)
|
219
|
+
type_t = stmt_data[:type]
|
220
|
+
type = type_t.to_sym
|
221
|
+
value_data = stmt_data[:value]
|
222
|
+
tpl_value_data = nil
|
223
|
+
body = stmt_data[:body] || []
|
224
|
+
|
225
|
+
if stmt_data[:template]
|
226
|
+
template = object.get type
|
227
|
+
unless template
|
228
|
+
raise SlideField::InterpreterError,
|
229
|
+
"Undefined variable '#{type}' at #{get_loc type_t}"
|
230
|
+
end
|
231
|
+
|
232
|
+
unless :object == tpl_type = object.var_type(type)
|
233
|
+
raise SlideField::InterpreterError,
|
234
|
+
"Unexpected '#{tpl_type}', expecting 'object' at #{get_loc type_t}"
|
235
|
+
end
|
236
|
+
|
237
|
+
type = template[:type].to_sym
|
238
|
+
|
239
|
+
if template[:value]
|
240
|
+
tpl_value_data = rebind_tokens template[:value], stmt_data[:template]
|
241
|
+
end
|
242
|
+
|
243
|
+
if template[:body]
|
244
|
+
tpl_body = rebind_tokens template[:body], stmt_data[:template]
|
245
|
+
body += tpl_body
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
unless object.rules.accepted_children.include?(type)
|
250
|
+
raise SlideField::InterpreterError,
|
251
|
+
"Unexpected object '#{type}', expecting one of #{object.rules.accepted_children.sort} at #{get_loc type_t}"
|
252
|
+
end
|
253
|
+
|
254
|
+
child = SlideField::ObjectData.new type, get_loc(type_t)
|
255
|
+
child.include_path = include_path
|
256
|
+
child.context = context
|
257
|
+
child.parent = object # enable variable inheritance
|
258
|
+
|
259
|
+
unless child.rules
|
260
|
+
# the object was allowed but we don't know anything about it?!
|
261
|
+
raise "Unsupported object '#{child.type}'"
|
262
|
+
end
|
263
|
+
|
264
|
+
interpret_anon_value tpl_value_data, child if tpl_value_data
|
265
|
+
interpret_anon_value value_data, child if value_data
|
266
|
+
interpret_tree body, child || [], include_path, context
|
267
|
+
|
268
|
+
# process special objects
|
269
|
+
case child.type
|
270
|
+
when :include
|
271
|
+
source = File.expand_path child.get(:source), include_path
|
272
|
+
run_file source, object
|
273
|
+
when :debug
|
274
|
+
debug_infos = {
|
275
|
+
:type=>child.var_type(:thing),
|
276
|
+
:value=>child.get(:thing)
|
277
|
+
}
|
278
|
+
|
279
|
+
puts "DEBUG in #{child.context} at #{child.loc}:"
|
280
|
+
ap debug_infos
|
281
|
+
puts
|
282
|
+
else
|
283
|
+
object << child
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def interpret_anon_value(value_data, object)
|
288
|
+
val_type, value_t, value = extract_value value_data, object
|
289
|
+
var_name = object.rules.matching_properties(val_type).first # guess variable name
|
290
|
+
|
291
|
+
unless var_name
|
292
|
+
raise SlideField::InterpreterError,
|
293
|
+
"Unexpected '#{val_type}', expecting one of #{object.rules.properties_types} at #{get_loc value_t}"
|
294
|
+
end
|
295
|
+
|
296
|
+
if object.has? var_name
|
297
|
+
raise SlideField::InterpreterError,
|
298
|
+
"Variable '#{var_name}' is already defined at #{get_loc value_t}"
|
299
|
+
end
|
300
|
+
|
301
|
+
object.set var_name, value, get_loc(value_t), val_type
|
302
|
+
end
|
303
|
+
|
304
|
+
def get_loc(token)
|
305
|
+
pos = token.line_and_column
|
306
|
+
"line #{pos.first} char #{pos.last}"
|
307
|
+
end
|
308
|
+
|
309
|
+
def extract_value(data, object)
|
310
|
+
filters = data.delete :filters
|
311
|
+
value_data = data.first
|
312
|
+
type = value_data[0]
|
313
|
+
token = value_data[1]
|
314
|
+
value = convert type, token
|
315
|
+
|
316
|
+
if type == :identifier
|
317
|
+
if id_value = object.get(value.to_sym)
|
318
|
+
type = object.var_type value.to_sym
|
319
|
+
value = id_value
|
320
|
+
else
|
321
|
+
raise SlideField::InterpreterError,
|
322
|
+
"Undefined variable '#{value}' at #{get_loc token}"
|
323
|
+
end
|
324
|
+
elsif type == :object
|
325
|
+
token = token[:type]
|
326
|
+
|
327
|
+
if value[:template]
|
328
|
+
# we got something like `alias = \&template`
|
329
|
+
# a template must be copied using the standard syntax `alias = template`
|
330
|
+
# otherwise the reference would not be resolved
|
331
|
+
raise SlideField::InterpreterError,
|
332
|
+
"Unexpected template reference at #{get_loc token}"
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
filters.reverse_each {|filter_token|
|
337
|
+
type, value = filter filter_token, type, value
|
338
|
+
}
|
339
|
+
|
340
|
+
return type, token, value
|
341
|
+
end
|
342
|
+
|
343
|
+
def convert(type, token)
|
344
|
+
case type
|
345
|
+
when :identifier, :object
|
346
|
+
token
|
347
|
+
when :integer
|
348
|
+
token.to_i
|
349
|
+
when :point
|
350
|
+
token.to_s.split('x').collect &:to_i
|
351
|
+
when :string
|
352
|
+
escape_sequences = {
|
353
|
+
'n'=>"\n"
|
354
|
+
}
|
355
|
+
|
356
|
+
token.to_s[1..-2].gsub(/\\(.)/) {
|
357
|
+
escape_sequences[$1] || $1
|
358
|
+
}
|
359
|
+
when :color
|
360
|
+
int = token.to_s[1..-1].hex
|
361
|
+
|
362
|
+
r = (int >> 24) & 255
|
363
|
+
g = (int >> 16) & 255
|
364
|
+
b = (int >> 8) & 255
|
365
|
+
a = (int) & 255
|
366
|
+
[r, g, b, a]
|
367
|
+
when :boolean
|
368
|
+
token == ':true'
|
369
|
+
else
|
370
|
+
# the parser gave us strange data?!
|
371
|
+
raise "Unsupported type '#{type}' at #{get_loc token}"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def filter(token, type, value)
|
376
|
+
name_t = token[:name]
|
377
|
+
name = name_t.to_sym
|
378
|
+
|
379
|
+
case [type, name]
|
380
|
+
when [:point, :x]
|
381
|
+
type = :integer
|
382
|
+
value = value[0]
|
383
|
+
when [:point, :y]
|
384
|
+
type = :integer
|
385
|
+
value = value[1]
|
386
|
+
when [:integer, :x]
|
387
|
+
type = :point
|
388
|
+
value = [value, 0]
|
389
|
+
when [:integer, :y]
|
390
|
+
type = :point
|
391
|
+
value = [0, value]
|
392
|
+
when [:string, :lines]
|
393
|
+
type = :integer
|
394
|
+
value = value.lines.count
|
395
|
+
else
|
396
|
+
raise SlideField::InterpreterError,
|
397
|
+
"Invalid filter '#{name}' for type '#{type}' at #{get_loc name_t}"
|
398
|
+
end
|
399
|
+
|
400
|
+
return type, value
|
401
|
+
end
|
402
|
+
|
403
|
+
def rebind_tokens(tree, dest)
|
404
|
+
case tree
|
405
|
+
when Array
|
406
|
+
tree.collect {|h| rebind_tokens h, dest }
|
407
|
+
when Hash
|
408
|
+
tree = tree.dup
|
409
|
+
tree.each {|k, v| tree[k] = rebind_tokens v, dest }
|
410
|
+
when Parslet::Slice
|
411
|
+
Parslet::Slice.new dest.position, tree.str, dest.line_cache
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class SlideField::ObjectData
|
2
|
+
attr_reader :type, :loc, :children
|
3
|
+
attr_accessor :context, :include_path, :parent
|
4
|
+
|
5
|
+
def initialize(type, loc)
|
6
|
+
@type = type
|
7
|
+
@loc = loc
|
8
|
+
@variables = {}
|
9
|
+
@children = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def has?(var)
|
13
|
+
@variables.has_key? var
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(var, val, loc = nil, type = nil)
|
17
|
+
loc ||= var_loc var
|
18
|
+
type ||= var_type var
|
19
|
+
|
20
|
+
@variables[var] = [type, val, loc]
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(var)
|
24
|
+
if has? var
|
25
|
+
@variables[var][1]
|
26
|
+
elsif parent
|
27
|
+
parent.get var
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def var_type(var)
|
32
|
+
if has? var
|
33
|
+
@variables[var][0]
|
34
|
+
elsif parent
|
35
|
+
parent.var_type var
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def var_loc(var)
|
40
|
+
if has? var
|
41
|
+
@variables[var][2]
|
42
|
+
elsif parent
|
43
|
+
parent.var_loc var
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def <<(child)
|
48
|
+
child.parent = self
|
49
|
+
@children << child
|
50
|
+
end
|
51
|
+
|
52
|
+
def [](selector)
|
53
|
+
@children.select {|o| o.type == selector }
|
54
|
+
end
|
55
|
+
|
56
|
+
def ancestor(selector)
|
57
|
+
p = @parent
|
58
|
+
while p
|
59
|
+
return p if p.type == selector
|
60
|
+
p = p.parent
|
61
|
+
end
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def context_string
|
66
|
+
array = [@context]
|
67
|
+
parent = @parent
|
68
|
+
while parent
|
69
|
+
array.unshift parent.context unless array.first == parent.context
|
70
|
+
parent = parent.parent
|
71
|
+
end
|
72
|
+
"[#{array.join '] ['}]"
|
73
|
+
end
|
74
|
+
|
75
|
+
def rules
|
76
|
+
SlideField::ObjectRules[@type]
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SlideField::ObjectManager
|
2
|
+
def self.new(obj, window)
|
3
|
+
type = obj.type.to_s
|
4
|
+
type[0] = type[0].upcase
|
5
|
+
const_get(type).new obj, window
|
6
|
+
rescue NameError
|
7
|
+
end
|
8
|
+
|
9
|
+
class Base
|
10
|
+
def initialize(obj, window)
|
11
|
+
@obj = obj
|
12
|
+
@window = window
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(event, *args)
|
16
|
+
send event, *args
|
17
|
+
rescue => e
|
18
|
+
raise SlideField::RuntimeError,
|
19
|
+
"#{@obj.context_string} An error occured while executing the '#{event}' event on the object '#{@obj.type}' at #{@obj.loc}:\n" +
|
20
|
+
"\t(#{e.class}) #{e.message}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def load; end
|
24
|
+
def activate; end
|
25
|
+
def draw(animator); end
|
26
|
+
def deactivate; end
|
27
|
+
def unload; end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module SlideField::ObjectRules
|
2
|
+
def self.[](type)
|
3
|
+
type = type.to_s
|
4
|
+
type[0] = type[0].upcase
|
5
|
+
|
6
|
+
SlideField::ObjectRules.const_get(type).get
|
7
|
+
rescue NameError
|
8
|
+
end
|
9
|
+
|
10
|
+
class Base
|
11
|
+
@@cache = {}
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@properties = []
|
15
|
+
@children = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def properties_names
|
19
|
+
@properties.collect {|hash| hash[:name] }
|
20
|
+
end
|
21
|
+
|
22
|
+
def properties_types
|
23
|
+
@properties.collect {|hash| hash[:type] }.uniq
|
24
|
+
end
|
25
|
+
|
26
|
+
def required_properties
|
27
|
+
required = @properties.select {|hash| hash[:default].nil? }
|
28
|
+
required.collect {|hash| hash[:name] }
|
29
|
+
end
|
30
|
+
|
31
|
+
def optional_properties
|
32
|
+
required = @properties.select {|hash| !hash[:default].nil? }
|
33
|
+
required.collect {|hash| hash[:name] }
|
34
|
+
end
|
35
|
+
|
36
|
+
def type_of_property(name)
|
37
|
+
rule = @properties.select {|hash| hash[:name] == name }.first
|
38
|
+
rule[:type] if rule
|
39
|
+
end
|
40
|
+
|
41
|
+
def matching_properties(type)
|
42
|
+
matches = @properties.select {|hash| hash[:type] == type }
|
43
|
+
matches.collect {|hash| hash[:name] }
|
44
|
+
end
|
45
|
+
|
46
|
+
def default_value(name)
|
47
|
+
rule = @properties.select {|hash| hash[:name] == name }.first
|
48
|
+
rule[:default] if rule
|
49
|
+
end
|
50
|
+
|
51
|
+
def accepted_children
|
52
|
+
@children.collect {|hash| hash[:type] }
|
53
|
+
end
|
54
|
+
|
55
|
+
def requirements_of_child(type)
|
56
|
+
rule = @children.select {|hash| hash[:type] == type }.first
|
57
|
+
rule[:requirements] if rule
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.get
|
61
|
+
if instance = @@cache[self]
|
62
|
+
instance
|
63
|
+
else
|
64
|
+
instance = self.new
|
65
|
+
instance.rules
|
66
|
+
@@cache[self] = instance
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
def property(name, type, default = nil)
|
72
|
+
@properties << {:name=>name, :type=>type, :default=>default}
|
73
|
+
end
|
74
|
+
|
75
|
+
def child(type, min = 0, max = 0)
|
76
|
+
@children << {:type=>type, :requirements=>[min, max]}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SlideField::ObjectRules
|
2
|
+
class Base
|
3
|
+
def rules
|
4
|
+
child :include
|
5
|
+
child :debug
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class SBase < Base
|
10
|
+
def rules
|
11
|
+
child :animation
|
12
|
+
child :image
|
13
|
+
child :rect
|
14
|
+
child :song
|
15
|
+
child :text
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class GBase < SBase
|
22
|
+
def rules
|
23
|
+
property :position, :point, [0,0]
|
24
|
+
property :z_order, :integer, 0
|
25
|
+
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SlideField::ObjectRules
|
2
|
+
class Debug < Base
|
3
|
+
def rules
|
4
|
+
# hack
|
5
|
+
# `thing = 10x10` or anything but an integer will raise an error
|
6
|
+
# however `\debug 10x10` works as expected
|
7
|
+
|
8
|
+
property :thing, :integer
|
9
|
+
property :thing, :string
|
10
|
+
property :thing, :point
|
11
|
+
property :thing, :color
|
12
|
+
property :thing, :boolean
|
13
|
+
property :thing, :object
|
14
|
+
|
15
|
+
# don't call super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|