RUIC 0.0.1 → 0.1.0

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.
@@ -4,7 +4,8 @@ module UIC; end
4
4
 
5
5
  require 'nokogiri'
6
6
  require_relative 'ruic/version'
7
- require_relative 'ruic/asset_classes'
7
+ require_relative 'ruic/attributes'
8
+ require_relative 'ruic/assets'
8
9
  require_relative 'ruic/interfaces'
9
10
  require_relative 'ruic/application'
10
11
  require_relative 'ruic/behaviors'
@@ -13,27 +14,57 @@ require_relative 'ruic/presentation'
13
14
 
14
15
  class RUIC
15
16
  DEFAULTMETADATA = 'C:/Program Files (x86)/NVIDIA Corporation/UI Composer 8.0/res/DataModelMetadata/en-us/MetaData.xml'
16
- def self.run(ruic_path)
17
- script = File.read(ruic_path,encoding:'utf-8')
18
- Dir.chdir(File.dirname(ruic_path)) do
19
- self.new.instance_eval(script,ruic_path)
17
+ def self.run(opts={})
18
+ ruic = nil
19
+ if opts[:script]
20
+ script = File.read(opts[:script],encoding:'utf-8')
21
+ Dir.chdir(File.dirname(opts[:script])) do
22
+ ruic = self.new
23
+ ruic.uia(opts[:uia]) if opts[:uia]
24
+ ruic.instance_eval(script,opts[:script])
25
+ end
26
+ end
27
+
28
+ if opts[:repl]
29
+ ruic ||= self.new.tap{ |r| r.uia(opts[:uia]) if opts[:uia] }
30
+
31
+ require 'ripl'
32
+ require 'ripl/multi_line'
33
+ require 'ripl/multi_line/live_error.rb'
34
+ Ripl::MultiLine.engine = Ripl::MultiLine::LiveError
35
+ Ripl::Shell.include Ripl::MultiLine.engine
36
+ Ripl.config.merge! prompt:' ', result_prompt:'#=> ', multi_line_prompt:' '
37
+ ARGV.clear # So that RIPL doesn't try to interpret the options
38
+ puts "(starting interactive RUIC session; 'quit' or ctrl-d to end)"
39
+ Ripl.start binding:ruic.instance_eval{ binding }
20
40
  end
21
41
  end
42
+
22
43
  def initialize( metadata=DEFAULTMETADATA )
23
44
  @metadata = metadata
24
45
  @apps = {}
25
46
  end
47
+
26
48
  def metadata(path)
27
49
  @metadata = path
28
50
  end
51
+
29
52
  def uia(path)
30
53
  meta = UIC.Meta @metadata
31
54
  name = @apps.empty? ? :app : :"app#{@apps.length+1}"
32
55
  @apps[name] = UIC.App(meta,path)
33
56
  end
57
+
58
+ module SelfInspecting
59
+ def inspect
60
+ to_s
61
+ end
62
+ end
63
+
34
64
  def method_missing(name,*a)
35
- @apps[name] || super
65
+ @apps[name] || (name=~/^app\d*/ ? "(no #{name} loaded)".extend(SelfInspecting) : super)
36
66
  end
67
+
37
68
  def assert(condition=:CONDITIONNOTSUPPLIED,msg=nil,&block)
38
69
  if block && condition==:CONDITIONNOTSUPPLIED || condition.is_a?(String)
39
70
  msg = condition.is_a?(String) ? condition : yield
@@ -45,15 +76,20 @@ class RUIC
45
76
  exit 1
46
77
  end
47
78
  end
79
+
48
80
  def show(*a); puts *a.map(&:to_s); end
81
+
82
+ def inspect
83
+ "<RUIC #{@apps.empty? ? "(no app loaded)" : Hash[ @apps.map{ |id,app| [id,File.basename(app.file)] } ]}>"
84
+ end
49
85
  end
50
86
 
51
- def RUIC(file_path=nil,&block)
87
+ def RUIC(opts={},&block)
52
88
  if block
53
89
  Dir.chdir(File.dirname($0)) do
54
- RUIC.new.instance_eval(&block)
90
+ RUIC.new.tap{ |r| r.uia(opts[:uia]) if opts[:uia] }.instance_eval(&block)
55
91
  end
56
92
  else
57
- RUIC.run(file_path)
93
+ RUIC.run(opts)
58
94
  end
59
95
  end
@@ -1,6 +1,10 @@
1
1
  class UIC::Application
2
2
  include UIC::FileBacked
3
3
 
4
+ def inspect
5
+ "<UIC::Application '#{File.basename(file)}'>"
6
+ end
7
+
4
8
  attr_reader :metadata
5
9
  def initialize(metadata,uia_path)
6
10
  @metadata = metadata
@@ -1,448 +1,282 @@
1
- #encoding: utf-8
2
- require 'set'
3
- $depth = 0
4
- class UIC::Asset
5
- class Root
6
- @properties = {}
7
- class << self
8
- attr_reader :name
9
- def properties
10
- (ancestors[1].respond_to?(:properties) ? ancestors[1].properties : {}).merge(@properties)
11
- end
12
-
13
- def each
14
- (@by_name.values - [self]).each{ |klass| yield klass }
15
- end
16
- include Enumerable
17
-
18
- def inspect
19
- "<#{@name}>"
20
- end
21
- end
22
-
23
- def properties
24
- self.class.properties
25
- end
26
-
27
- def at(sub_path)
28
- presentation.at(sub_path,@el)
29
- end
30
- alias_method :/, :at
31
-
32
- attr_accessor :presentation, :el
33
- def initialize( presentation, element )
34
- @presentation = presentation
35
- @el = element
36
- end
37
-
38
- def type
39
- self.class.name
40
- # self.class.name.split('::').last
41
- end
42
-
43
- def parent
44
- presentation.parent_asset(@el)
45
- end
46
-
47
- def children
48
- presentation.child_assets(@el)
49
- end
50
-
51
- def find(criteria={},&block)
52
- criteria[:under] ||= self
53
- presentation.find(criteria,&block)
54
- end
55
-
56
- # Find the owning component (even if you are a component)
57
- def component
58
- presentation.owning_component(@el)
59
- end
60
-
61
- def component?
62
- @el.name == 'Component'
63
- end
64
-
65
- def master?
66
- presentation.master?(@el)
67
- end
68
-
69
- def slide?
70
- false
71
- end
72
-
73
- def has_slide?(slide_name_or_index)
74
- presentation.has_slide?(@el,slide_name_or_index)
75
- end
76
-
77
- def slides
78
- presentation.slides_for(@el)
79
- end
80
-
81
- def on_slide(slide_name_or_index)
82
- if has_slide?(slide_name_or_index)
83
- UIC::SlideValues.new( self, slide_name_or_index )
84
- end
85
- end
86
-
87
- def path
88
- @path ||= @presentation.path_to(@el)
89
- end
90
-
91
- def name
92
- properties['name'].get( self, presentation.slide_index(@el) )
93
- end
94
-
95
- def name=( new_name )
96
- properties['name'].set( self, new_name, presentation.slide_index(@el) )
97
- end
98
-
99
- # Get the value(s) of an attribute
100
- def [](attribute_name, slide_name_or_index=nil)
101
- if property = properties[attribute_name]
102
- if slide_name_or_index
103
- property.get( self, slide_name_or_index ) if has_slide?(slide_name_or_index)
104
- else
105
- UIC::ValuesPerSlide.new(@presentation,self,property)
106
- end
107
- end
108
- end
109
-
110
- # Set the value of an attribute, either across all slides, or on a particular slide
111
- # el['foo'] = 42
112
- # el['foo',0] = 42
113
- def []=( attribute_name, slide_name_or_index=nil, new_value )
114
- if property = properties[attribute_name] then
115
- property.set(self,new_value,slide_name_or_index)
116
- end
117
- end
118
-
119
- def to_xml
120
- @el.to_xml
121
- end
122
- def inspect
123
- "<asset #{@el.name}##{@el['id']}>"
124
- end
125
-
126
- def to_s
127
- "<#{type} #{path}>"
128
- end
129
-
130
- def ==(other)
131
- (self.class==other.class) && (el==other.el)
132
- end
133
- alias_method :eql?, :==
134
- end
135
-
136
- attr_reader :by_name
137
-
138
- HIER = {}
139
- %w[Asset Slide Scene].each{ |s| HIER[s] = 'Root' }
140
- %w[Node Behavior Effect Image Layer MaterialBase RenderPlugin].each{ |s| HIER[s]='Asset' }
141
- %w[Camera Component Group Light Model Text].each{ |s| HIER[s]='Node' }
142
- %w[Material ReferencedMaterial].each{ |s| HIER[s]='MaterialBase' }
143
-
144
- def initialize(xml)
145
- @by_name = {'Root'=>Root}
146
-
147
- doc = Nokogiri.XML(xml)
148
- hack_in_slide_names!(doc)
149
-
150
- HIER.each do |class_name,parent_class_name|
151
- parent_class = @by_name[parent_class_name]
152
- el = doc.root.at(class_name)
153
- @by_name[class_name] = create_class(el,parent_class,el.name)
154
- UIC::Asset.const_set( el.name, @by_name[class_name] ) # give the class instance a name by pointing a constant to it :/
155
- end
156
-
157
- # Extend well-known classes with script interfaces after they are created
158
- @by_name['State'] = @by_name['Slide']
159
- @by_name['Slide'].instance_eval do
160
- attr_accessor :index, :name
161
- define_method :inspect do
162
- "<slide ##{index} of #{@el['component'] || @el.parent['component']}>"
163
- end
164
- define_method(:slide?){ true }
165
- end
166
-
167
- refmat = @by_name['ReferencedMaterial']
168
- @by_name['MaterialBase'].instance_eval do
169
- define_method :replace_with_referenced_material do
170
- type=='ReferencedMaterial' ? self : presentation.replace_asset( self, 'ReferencedMaterial', name:name )
171
- end
172
- end
173
- end
174
-
175
- # Creates a class from MetaData.xml with accessors for the <Property> listed.
176
- # Instances of the class are associated with a presentation and know how to
177
- # get/set values in that XML based on value types, slides, defaults.
178
- # Also used to create classes from effects, materials, and behavior preambles.
179
- def create_class(el,parent_class,name='CustomAsset')
180
- Class.new(parent_class) do
181
- @name = name
182
- @properties = Hash[ el.css("Property").map do |e|
183
- type = e['type'] || (e['list'] ? 'String' : 'Float')
184
- type = "Float" if type=="float"
185
- property = UIC::Property.const_get(type).new(e)
186
- [ property.name, UIC::Property.const_get(type).new(e) ]
187
- end ]
188
- end
189
- end
190
-
191
- def new_instance(presentation,el)
192
- @by_name[el.name].new(presentation,el)
193
- end
194
-
195
- def hack_in_slide_names!(doc)
196
- doc.at('Slide') << '<Property name="name" formalName="Name" type="String" default="Slide" hidden="True" />'
197
- end
198
- end
199
-
200
- def UIC.Meta(metadata_path)
201
- UIC::Asset.new(File.read(metadata_path,encoding:'utf-8'))
202
- end
203
-
204
- class UIC::Property
205
- class << self; attr_accessor :default; end
206
- def initialize(el); @el = el; end
207
- def name; @name||=@el['name']; end
208
- def type; @type||=@el['type']; end
209
- def formal; @formal||=@el['formalName'] || @el['name']; end
210
- def min; @el['min']; end
211
- def max; @el['max']; end
212
- def description; @desc||=@el['description']; end
213
- def default; @def ||= (@el['default'] || self.class.default); end
214
- def get(asset,slide)
215
- if asset.slide? || asset.has_slide?(slide)
216
- asset.presentation.get_attribute(asset.el,name,slide) || default
217
- end
218
- end
219
- def set(asset,new_value,slide_name_or_index)
220
- asset.presentation.set_attribute(asset.el,name,slide_name_or_index,new_value)
221
- end
222
- def inspect
223
- "<#{type} '#{name}'>"
224
- end
225
-
226
- class String < self
227
- self.default = ''
228
- end
229
- MultiLineString = String
230
-
231
- class Float < self
232
- self.default = 0.0
233
- def get(asset,slide); super.to_f; end
234
- end
235
- class Long < self
236
- self.default = 0
237
- def get(asset,slide); super.to_i; end
238
- end
239
- class Boolean < self
240
- self.default = false
241
- def get(asset,slide); super=='True'; end
242
- def set(asset,new_value,slide_name_or_index)
243
- super( asset, new_value ? 'True' : 'False', slide_name_or_index )
244
- end
245
- end
246
- class Vector < self
247
- self.default = '0 0 0'
248
- def get(asset,slide)
249
- VectorValue.new(asset,self,slide,super)
250
- end
251
- def set(asset,new_value,slide_name_or_index)
252
- new_value = new_value.join(' ') if new_value.is_a?(Array)
253
- super( asset, new_value, slide_name_or_index )
254
- end
255
- end
256
- Rotation = Vector
257
- Color = Vector
258
- class Image < self
259
- self.default = nil
260
- def get(asset,slide)
261
- if idref = super
262
- result = asset.presentation.asset_by_id( idref[1..-1] )
263
- slide ? result.on_slide( slide ) : result
264
- end
265
- end
266
- def set(asset,new_value,slide)
267
- raise "Setting image attributes not yet supported"
268
- end
269
- end
270
- class Texture < String
271
- def get(asset,slide)
272
- if path=super
273
- path.empty? ? nil : path
274
- end
275
- end
276
- end
277
-
278
- class ObjectRef < self
279
- self.default = nil
280
- def get(asset,slide)
281
- ref = super
282
- type = :absolute
283
- obj = nil
284
- unless ref=='' || ref.nil?
285
- type = ref[0]=='#' ? :absolute : :path
286
- ref = type==:absolute ? asset.presentation.asset_by_id( ref[1..-1] ) : asset.presentation.at( ref, asset.el )
287
- end
288
- ObjectReference.new(asset,self,slide,ref,type)
289
- end
290
- def set(asset,new_object,slide)
291
- get(asset,slide).object = new_object
292
- end
293
- end
294
-
295
- class ObjectReference
296
- attr_reader :object, :type
297
- def initialize(asset,property,slide,object=nil,type=nil)
298
- @asset = asset
299
- @name = property.name
300
- @slide = slide
301
- @object = object
302
- @type = type
303
- end
304
- def object=(new_object)
305
- raise "ObjectRef must be set to an asset (not a #{new_object.class.name})" unless new_object.is_a?(UIC::Asset::Root)
306
- @object = new_object
307
- write_value!
308
- end
309
- def type=(new_type)
310
- raise "ObjectRef types must be either :absolute or :path (not #{new_type.inspect})" unless [:absolute,:path].include?(new_type)
311
- @type = new_type
312
- write_value!
313
- end
314
- private
315
- def write_value!
316
- path = case @object
317
- when NilClass then ""
318
- else case @type
319
- when :absolute then "##{@object.el['id']}"
320
- when :path then @asset.presentation.path_to( @object.el, @asset.el ).sub(/^[^:.]+:/,'')
321
- # when :root then @asset.presentation.path_to( @object.el ).sub(/^[^:.]+:/,'')
322
- end
323
- end
324
- @asset.presentation.set_attribute( @asset.el, @name, @slide, path )
325
- end
326
- end
327
-
328
- Import = String #TODO: a real class
329
- Mesh = String #TODO: a real class
330
- Renderable = String #TODO: a real class
331
- Font = String #TODO: a real class
332
- FontSize = Long
333
-
334
- StringListOrInt = String #TODO: a real class
335
-
336
- class VectorValue
337
- attr_reader :x, :y, :z
338
- def initialize(asset,property,slide,str)
339
- @asset = asset
340
- @property = property
341
- @slide = slide
342
- @x, @y, @z = str.split(/\s+/).map(&:to_f)
343
- end
344
- def setall
345
- @property.set( @asset, to_s, @slide )
346
- end
347
- def x=(n); @x=n; setall end
348
- def y=(n); @y=n; setall end
349
- def z=(n); @z=n; setall end
350
- alias_method :r, :x
351
- alias_method :g, :y
352
- alias_method :b, :z
353
- alias_method :r=, :x=
354
- alias_method :g=, :y=
355
- alias_method :b=, :z=
356
- def inspect
357
- "<#{@asset.path}.#{@property.name}: #{self}>"
358
- end
359
- def to_s
360
- to_a.join(' ')
361
- end
362
- def to_a
363
- [x,y,z]
364
- end
365
- end
366
- end
367
-
368
- class UIC::SlideCollection
369
- include Enumerable
370
- attr_reader :length
371
- def initialize(slides)
372
- @length = slides.length-1
373
- @slides = slides
374
- @lookup = {}
375
- slides.each do |s|
376
- @lookup[s.index] = s
377
- @lookup[s.name] = s
378
- end
379
- end
380
- def each
381
- @slides.each{ |s| yield(s) }
382
- end
383
- def [](index_or_name)
384
- @lookup[ index_or_name ]
385
- end
386
- def inspect
387
- "[ #{@slides.map(&:inspect).join ', '} ]"
388
- end
389
- def to_ary
390
- @slides
391
- end
392
- end
393
-
394
- class UIC::ValuesPerSlide
395
- def initialize(presentation,asset,property)
396
- raise unless presentation.is_a?(UIC::Presentation)
397
- raise unless asset.is_a?(UIC::Asset::Root)
398
- raise unless property.is_a?(UIC::Property)
399
- @preso = presentation
400
- @asset = asset
401
- @el = asset.el
402
- @property = property
403
- end
404
- def value
405
- values.first
406
- end
407
- def [](slide_name_or_index)
408
- @property.get( @asset, slide_name_or_index )
409
- end
410
- def []=(slide_name_or_index,new_value)
411
- @property.set( @asset, new_value, slide_name_or_index )
412
- end
413
- def linked?
414
- @preso.attribute_linked?(@el,@property.name)
415
- end
416
- def unlink
417
- @preso.unlink_attribute( @el, @property.name )
418
- end
419
- def link
420
- @preso.link_attribute( @el, @property.name )
421
- end
422
- def values
423
- @asset.slides.map{ |s| self[s.name] }
424
- end
425
- def inspect
426
- "<Values of '#{@asset.name}.#{@property.name}' across slides>"
427
- end
428
- alias_method :to_s, :inspect
429
- end
430
-
431
- class UIC::SlideValues
432
- def initialize( asset, slide )
433
- @asset = asset
434
- @slide = slide
435
- end
436
- def [](attribute_name)
437
- @asset[attribute_name,@slide]
438
- end
439
- def []=( attribute_name, new_value )
440
- @asset[attribute_name,@slide] = new_value
441
- end
442
- def method_missing( name, *args, &blk )
443
- asset.send(name,*args,&blk)
444
- end
445
- def inspect
446
- "<#{@asset.inspect} on slide #{@slide.inspect}>"
447
- end
1
+ #encoding: utf-8
2
+ class UIC::Asset
3
+ class Root
4
+ @properties = {}
5
+ class << self
6
+ attr_reader :name
7
+ def properties
8
+ (ancestors[1].respond_to?(:properties) ? ancestors[1].properties : {}).merge(@properties)
9
+ end
10
+
11
+ def each
12
+ (@by_name.values - [self]).each{ |klass| yield klass }
13
+ end
14
+ include Enumerable
15
+
16
+ def inspect
17
+ "<#{@name}>"
18
+ end
19
+ end
20
+
21
+ def properties
22
+ self.class.properties
23
+ end
24
+
25
+ def at(sub_path)
26
+ presentation.at(sub_path,@el)
27
+ end
28
+ alias_method :/, :at
29
+
30
+ attr_accessor :presentation, :el
31
+ def initialize( presentation, element )
32
+ @presentation = presentation
33
+ @el = element
34
+ end
35
+
36
+ def type
37
+ self.class.name
38
+ # self.class.name.split('::').last
39
+ end
40
+
41
+ def parent
42
+ presentation.parent_asset(@el)
43
+ end
44
+
45
+ def children
46
+ presentation.child_assets(@el)
47
+ end
48
+
49
+ def find(criteria={},&block)
50
+ criteria[:under] ||= self
51
+ presentation.find(criteria,&block)
52
+ end
53
+
54
+ # Find the owning component (even if you are a component)
55
+ def component
56
+ presentation.owning_component(@el)
57
+ end
58
+
59
+ def component?
60
+ @el.name == 'Component'
61
+ end
62
+
63
+ def master?
64
+ presentation.master?(@el)
65
+ end
66
+
67
+ def slide?
68
+ false
69
+ end
70
+
71
+ def has_slide?(slide_name_or_index)
72
+ presentation.has_slide?(@el,slide_name_or_index)
73
+ end
74
+
75
+ def slides
76
+ presentation.slides_for(@el)
77
+ end
78
+
79
+ def on_slide(slide_name_or_index)
80
+ if has_slide?(slide_name_or_index)
81
+ UIC::SlideValues.new( self, slide_name_or_index )
82
+ end
83
+ end
84
+
85
+ def path
86
+ @path ||= @presentation.path_to(@el)
87
+ end
88
+
89
+ def name
90
+ properties['name'].get( self, presentation.slide_index(@el) )
91
+ end
92
+
93
+ def name=( new_name )
94
+ properties['name'].set( self, new_name, presentation.slide_index(@el) )
95
+ end
96
+
97
+ # Get the value(s) of an attribute
98
+ def [](attribute_name, slide_name_or_index=nil)
99
+ if property = properties[attribute_name]
100
+ if slide_name_or_index
101
+ property.get( self, slide_name_or_index ) if has_slide?(slide_name_or_index)
102
+ else
103
+ UIC::ValuesPerSlide.new(@presentation,self,property)
104
+ end
105
+ end
106
+ end
107
+
108
+ # Set the value of an attribute, either across all slides, or on a particular slide
109
+ # el['foo'] = 42
110
+ # el['foo',0] = 42
111
+ def []=( attribute_name, slide_name_or_index=nil, new_value )
112
+ if property = properties[attribute_name] then
113
+ property.set(self,new_value,slide_name_or_index)
114
+ end
115
+ end
116
+
117
+ def to_xml
118
+ @el.to_xml
119
+ end
120
+ def inspect
121
+ "<asset #{@el.name}##{@el['id']}>"
122
+ end
123
+
124
+ def to_s
125
+ "<#{type} #{path}>"
126
+ end
127
+
128
+ def ==(other)
129
+ (self.class==other.class) && (el==other.el)
130
+ end
131
+ alias_method :eql?, :==
132
+ end
133
+
134
+ attr_reader :by_name
135
+
136
+ HIER = {}
137
+ %w[Asset Slide Scene].each{ |s| HIER[s] = 'Root' }
138
+ %w[Node Behavior Effect Image Layer MaterialBase RenderPlugin].each{ |s| HIER[s]='Asset' }
139
+ %w[Camera Component Group Light Model Text].each{ |s| HIER[s]='Node' }
140
+ %w[Material ReferencedMaterial].each{ |s| HIER[s]='MaterialBase' }
141
+
142
+ def initialize(xml)
143
+ @by_name = {'Root'=>Root}
144
+
145
+ doc = Nokogiri.XML(xml)
146
+ hack_in_slide_names!(doc)
147
+
148
+ HIER.each do |class_name,parent_class_name|
149
+ parent_class = @by_name[parent_class_name]
150
+ el = doc.root.at(class_name)
151
+ @by_name[class_name] = create_class(el,parent_class,el.name)
152
+ UIC::Asset.const_set( el.name, @by_name[class_name] ) # give the class instance a name by pointing a constant to it :/
153
+ end
154
+
155
+ # Extend well-known classes with script interfaces after they are created
156
+ @by_name['State'] = @by_name['Slide']
157
+ @by_name['Slide'].instance_eval do
158
+ attr_accessor :index, :name
159
+ define_method :inspect do
160
+ "<slide ##{index} of #{@el['component'] || @el.parent['component']}>"
161
+ end
162
+ define_method(:slide?){ true }
163
+ end
164
+
165
+ refmat = @by_name['ReferencedMaterial']
166
+ @by_name['MaterialBase'].instance_eval do
167
+ define_method :replace_with_referenced_material do
168
+ type=='ReferencedMaterial' ? self : presentation.replace_asset( self, 'ReferencedMaterial', name:name )
169
+ end
170
+ end
171
+ end
172
+
173
+ # Creates a class from MetaData.xml with accessors for the <Property> listed.
174
+ # Instances of the class are associated with a presentation and know how to
175
+ # get/set values in that XML based on value types, slides, defaults.
176
+ # Also used to create classes from effects, materials, and behavior preambles.
177
+ def create_class(el,parent_class,name='CustomAsset')
178
+ Class.new(parent_class) do
179
+ @name = name
180
+ @properties = Hash[ el.css("Property").map do |e|
181
+ type = e['type'] || (e['list'] ? 'String' : 'Float')
182
+ type = "Float" if type=="float"
183
+ property = UIC::Property.const_get(type).new(e)
184
+ [ property.name, UIC::Property.const_get(type).new(e) ]
185
+ end ]
186
+ end
187
+ end
188
+
189
+ def new_instance(presentation,el)
190
+ @by_name[el.name].new(presentation,el)
191
+ end
192
+
193
+ def hack_in_slide_names!(doc)
194
+ doc.at('Slide') << '<Property name="name" formalName="Name" type="String" default="Slide" hidden="True" />'
195
+ end
196
+ end
197
+
198
+ def UIC.Meta(metadata_path)
199
+ UIC::Asset.new(File.read(metadata_path,encoding:'utf-8'))
200
+ end
201
+
202
+ class UIC::SlideCollection
203
+ include Enumerable
204
+ attr_reader :length
205
+ def initialize(slides)
206
+ @length = slides.length-1
207
+ @slides = slides
208
+ @lookup = {}
209
+ slides.each do |s|
210
+ @lookup[s.index] = s
211
+ @lookup[s.name] = s
212
+ end
213
+ end
214
+ def each
215
+ @slides.each{ |s| yield(s) }
216
+ end
217
+ def [](index_or_name)
218
+ @lookup[ index_or_name ]
219
+ end
220
+ def inspect
221
+ "[ #{@slides.map(&:inspect).join ', '} ]"
222
+ end
223
+ def to_ary
224
+ @slides
225
+ end
226
+ end
227
+
228
+ class UIC::ValuesPerSlide
229
+ def initialize(presentation,asset,property)
230
+ raise unless presentation.is_a?(UIC::Presentation)
231
+ raise unless asset.is_a?(UIC::Asset::Root)
232
+ raise unless property.is_a?(UIC::Property)
233
+ @preso = presentation
234
+ @asset = asset
235
+ @el = asset.el
236
+ @property = property
237
+ end
238
+ def value
239
+ values.first
240
+ end
241
+ def [](slide_name_or_index)
242
+ @property.get( @asset, slide_name_or_index )
243
+ end
244
+ def []=(slide_name_or_index,new_value)
245
+ @property.set( @asset, new_value, slide_name_or_index )
246
+ end
247
+ def linked?
248
+ @preso.attribute_linked?(@el,@property.name)
249
+ end
250
+ def unlink
251
+ @preso.unlink_attribute( @el, @property.name )
252
+ end
253
+ def link
254
+ @preso.link_attribute( @el, @property.name )
255
+ end
256
+ def values
257
+ @asset.slides.map{ |s| self[s.name] }
258
+ end
259
+ def inspect
260
+ "<Values of '#{@asset.name}.#{@property.name}' across slides>"
261
+ end
262
+ alias_method :to_s, :inspect
263
+ end
264
+
265
+ class UIC::SlideValues
266
+ def initialize( asset, slide )
267
+ @asset = asset
268
+ @slide = slide
269
+ end
270
+ def [](attribute_name)
271
+ @asset[attribute_name,@slide]
272
+ end
273
+ def []=( attribute_name, new_value )
274
+ @asset[attribute_name,@slide] = new_value
275
+ end
276
+ def method_missing( name, *args, &blk )
277
+ asset.send(name,*args,&blk)
278
+ end
279
+ def inspect
280
+ "<#{@asset.inspect} on slide #{@slide.inspect}>"
281
+ end
448
282
  end