RUIC 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY +23 -0
  3. data/README.md +2 -2
  4. data/lib/ruic.rb +11 -3
  5. data/lib/ruic/application.rb +28 -22
  6. data/lib/ruic/attributes.rb +10 -2
  7. data/lib/ruic/behaviors.rb +2 -15
  8. data/lib/ruic/effect.rb +32 -0
  9. data/lib/ruic/interfaces.rb +51 -13
  10. data/lib/ruic/presentation.rb +46 -20
  11. data/lib/ruic/renderplugin.rb +18 -0
  12. data/lib/ruic/ripl.rb +45 -0
  13. data/lib/ruic/statemachine.rb +142 -25
  14. data/lib/ruic/version.rb +1 -1
  15. data/test/customclasses.ruic +0 -1
  16. data/test/filtering.ruic +0 -1
  17. data/test/futureassets.ruic +0 -1
  18. data/test/nonmaster.ruic +0 -1
  19. data/test/paths.ruic +0 -2
  20. data/test/projects/MissingAssets/Existing.uip +87 -0
  21. data/test/projects/MissingAssets/MissingAssets.uia +21 -0
  22. data/test/projects/MissingAssets/MissingAssets.uia-user +14 -0
  23. data/test/projects/MissingAssets/RoundedPlane-1/RoundedPlane-1.import +18 -0
  24. data/test/projects/MissingAssets/RoundedPlane-1/meshes/RoundedPlane.mesh +0 -0
  25. data/test/projects/MissingAssets/effects/effects.txt +3 -0
  26. data/test/projects/MissingAssets/effects/existing.effect +38 -0
  27. data/test/projects/MissingAssets/fonts/Arimo-Regular.ttf +0 -0
  28. data/test/projects/MissingAssets/fonts/Chivo-Black.ttf +0 -0
  29. data/test/projects/MissingAssets/fonts/OFL.txt +92 -0
  30. data/test/projects/MissingAssets/maps/effects/brushnoise.dds +0 -0
  31. data/test/projects/MissingAssets/maps/existing.png +0 -0
  32. data/test/projects/MissingAssets/maps/existing2.png +0 -0
  33. data/test/projects/MissingAssets/maps/maps.txt +2 -0
  34. data/test/projects/MissingAssets/maps/materials/concrete_plain.png +0 -0
  35. data/test/projects/MissingAssets/maps/materials/concrete_plain_bump.png +0 -0
  36. data/test/projects/MissingAssets/maps/materials/spherical_checker.png +0 -0
  37. data/test/projects/MissingAssets/maps/unused.png +0 -0
  38. data/test/projects/MissingAssets/materials/concrete.material +251 -0
  39. data/test/projects/MissingAssets/materials/materials.txt +3 -0
  40. data/test/projects/MissingAssets/scripts/existing1.lua +2 -0
  41. data/test/projects/MissingAssets/scripts/existing2.lua +470 -0
  42. data/test/projects/MissingAssets/states/existing.scxml +4 -0
  43. data/test/projects/MissingAssets/tests/interface-navigation.scxml-test +3 -0
  44. data/test/properties.ruic +0 -2
  45. data/test/referencematerials.ruic +0 -2
  46. data/test/usage.ruic +38 -4
  47. metadata +53 -3
  48. data/lib/ruic/ripl-after-result.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 105e49557e0d92a463d1630cd6fa42d078048e44
4
- data.tar.gz: 21db139d873cbcfa3ad7f9c66c85a2ffc151f9ac
3
+ metadata.gz: 2a99bfd85a630d1804e5c38b33296883a2f43342
4
+ data.tar.gz: f3233b7830899344bcee0c969fdb130e88143b1d
5
5
  SHA512:
6
- metadata.gz: 2e4f62d1164c63510bb3cc931870b3b353e28439fecf38076b6ac8ad3dca09a528c5fedb32c6b613115b1d248fda324a11fac912d873da83e57fd16bd1a82586
7
- data.tar.gz: 0eeb2a2ab41c848feef5859a7f0810584de7f89beb785c9bb29a1c7f55a72495a7234ecc5514e8e45b765ba13aea650a0e7685f7d9a903fcd08baa45527fa19e
6
+ metadata.gz: 474bf2cda9e565b3a050fadb9b266980f3b36075f0a953eabf69106695e623575e980fab75c007e78e47f6de6f5e58f0fad217261008392616b47eeca66207d7
7
+ data.tar.gz: 5a3066ad987ce4597b0ef47d935c8db28bc477ffb281300406184d1119539f84d6130478e3f7ca6dbb3b025d0603567cea0c208fa89867c75d81031832d1a8a0
data/HISTORY CHANGED
@@ -1,3 +1,26 @@
1
+ ## v0.6.0
2
+
3
+ ### Backwards Incompatible Changes
4
+
5
+ * Changed `FileBacked#resolve_file_path` to `FileBacked#absolute_path`, and added `FileBacked#relative_path`.
6
+ * Removed `.errors?` and `.errors` for application and assets.
7
+
8
+ ### New/Changed Features
9
+
10
+ * State machines properly report on visual actions.
11
+ * _Only `<set-attribute>` properly implemented so far._
12
+ * Added much improved `Presentation#referenced_files`, `Application#missing_files`, `Application#unused_files`.
13
+ * Tweaked REPL output.
14
+ * `nil` results no longer print `#=> nil` in the REPL.
15
+ * `show` prefixes the result with `#=>`.
16
+ * Multi-line results are now wrapped, with each line prefixed with `#=>`.
17
+ * Added beginnings of support for effects and renderplugins.
18
+ * Presentations do not cause a runtime error if a custom class (e.g. behavior, effect, custom material) cannot be found.
19
+
20
+ ### Bug Fixes
21
+ * Fix bug that caused some properties to report their type as `nil` or `float` instead of `Float`.
22
+ * Presentations are slightly more capable if they are created without an existing file.
23
+
1
24
  ## v0.5.0 - 2014-Nov-26
2
25
 
3
26
  * Fix bug that prevented loading an application from the command line in another directory.
data/README.md CHANGED
@@ -167,7 +167,7 @@ There are two ways to enter interactive mode:
167
167
  the application and enter the REPL:
168
168
 
169
169
  $ ruic myapp.uia
170
- (RUIC v0.2.2 interactive session; 'quit' or ctrl-d to end)
170
+ (RUIC v0.6.0 interactive session; 'quit' or ctrl-d to end)
171
171
 
172
172
  uia "test/projects/SimpleScene/SimpleScene.uia"
173
173
  #=> <UIC::Application 'SimpleScene.uia'>
@@ -176,7 +176,7 @@ There are two ways to enter interactive mode:
176
176
  by supplying the `-i` command-line switch:
177
177
 
178
178
  $ ruic -i test/referencematerials.ruic
179
- (RUIC v0.2.2 interactive session; 'quit' or ctrl-d to end)
179
+ (RUIC v0.6.0 interactive session; 'quit' or ctrl-d to end)
180
180
 
181
181
  app
182
182
  #=> <UIC::Application 'ReferencedMaterials.uia'>
@@ -10,8 +10,11 @@ require_relative 'ruic/assets'
10
10
  require_relative 'ruic/interfaces'
11
11
  require_relative 'ruic/application'
12
12
  require_relative 'ruic/behaviors'
13
+ require_relative 'ruic/effect'
14
+ require_relative 'ruic/renderplugin'
13
15
  require_relative 'ruic/statemachine'
14
16
  require_relative 'ruic/presentation'
17
+ require_relative 'ruic/ripl'
15
18
 
16
19
  # The `RUIC` class provides the interface for running scripts using the special DSL,
17
20
  # and for running the interactive REPL.
@@ -67,11 +70,11 @@ class RUIC
67
70
  require 'ripl/irb'
68
71
  require 'ripl/multi_line'
69
72
  require 'ripl/multi_line/live_error.rb'
70
- require_relative 'ruic/ripl-after-result'
71
73
  Ripl::MultiLine.engine = Ripl::MultiLine::LiveError
72
74
  Ripl::Shell.include Ripl::MultiLine.engine
73
75
  Ripl::Shell.include Ripl::AfterResult
74
- Ripl.config.merge! prompt:"", result_prompt:'#=> ', multi_line_prompt:' ', irb_verbose:false, after_result:"\n"
76
+ Ripl::Shell.include Ripl::FormatResult
77
+ Ripl.config.merge! prompt:"", result_prompt:'#=> ', multi_line_prompt:' ', irb_verbose:false, after_result:"\n", result_line_limit:120, prefix_result_lines:true, skip_nil_results:true
75
78
  ARGV.clear # So that RIPL doesn't try to interpret the options
76
79
  puts "(RUIC v#{RUIC::VERSION} interactive session; 'quit' or ctrl-d to end)"
77
80
  ruic.instance_eval{ puts @apps.map{ |n,app| "(#{n} is #{app.inspect})" } }
@@ -150,7 +153,12 @@ class RUIC
150
153
 
151
154
  # Nicer name for `puts` to be used in the DSL, printing the
152
155
  # 'nice' string equivalent for all supplied arguments.
153
- def show(*a); puts *a.map(&:to_s); end
156
+ def show(*a)
157
+ a=a.first if a.length==1 && a.first.is_a?(Array)
158
+ opts = { result_prompt:'# ', result_line_limit:120, prefix_result_lines:true, to_s:true }
159
+ a.each{ |x| puts Ripl::FormatResult.format_result(x,opts) }
160
+ nil # so that Ripl won't show the result
161
+ end
154
162
 
155
163
  def inspect
156
164
  "<RUIC #{@apps.empty? ? "(no app loaded)" : Hash[ @apps.map{ |id,app| [id,File.basename(app.file)] } ]}>"
@@ -1,6 +1,6 @@
1
1
  # The `Application` represents the root of your UIC application, corresponding to a `.uia` file.
2
2
  class UIC::Application
3
- include UIC::FileBacked
3
+ include UIC::XMLFileBacked
4
4
 
5
5
  def inspect
6
6
  "<UIC::Application '#{File.basename(file)}'#{:' FILENOTFOUND' unless file_found?}>"
@@ -14,18 +14,16 @@ class UIC::Application
14
14
  # If omitted you will need to later set the `.file = ` for the
15
15
  # instance and then call {#load_from_file}.
16
16
  def initialize(metadata,uia_path=nil)
17
+ @assets = {}
17
18
  @metadata = metadata
18
19
  self.file = uia_path
19
- @assets = {}
20
- load_from_file if file_found?
21
20
  end
22
21
 
23
22
  # Loads the application from the file. If you pass the path to your `.uia`
24
23
  # to {#initialize} then this method is called automatically.
25
24
  #
26
25
  # @return [nil]
27
- def load_from_file
28
- self.doc = Nokogiri.XML(File.read(file,encoding:'utf-8'))
26
+ def on_doc_loaded
29
27
  @assets = @doc.search('assets *').map do |el|
30
28
  case el.name
31
29
  when 'behavior' then UIC::Application::Behavior
@@ -37,18 +35,6 @@ class UIC::Application
37
35
  nil
38
36
  end
39
37
 
40
- # @return [Boolean] true if there are any errors with the application.
41
- def errors?
42
- !errors.empty?
43
- end
44
-
45
- # @example
46
- # show app.errors if app.errors?
47
- # @return [Array<String>] an array (possibly empty) of all errors in this application (including referenced assets).
48
- def errors
49
- file_found? ? assets.flat_map(&:errors) : ["File not found: '#{file}'"]
50
- end
51
-
52
38
  # Find an asset by `.uia` identifier or path to the asset.
53
39
  # @example
54
40
  # main1 = app['#main']
@@ -71,17 +57,37 @@ class UIC::Application
71
57
  end
72
58
  end
73
59
 
74
- # @private do not document until working
60
+ # Files in the application directory not used by the application.
61
+ #
62
+ # @return [Array<String>] absolute paths of files in the directory not used by the application.
75
63
  def unused_files
76
- referenced_files - directory_files
64
+ (directory_files - referenced_files).sort
77
65
  end
78
66
 
79
- # @private do not document until working
67
+ # Files referenced by the application but not present in the directory.
68
+ #
69
+ # @return [Array<String>] absolute paths of files referenced but gone.
70
+ def missing_files
71
+ (referenced_files - directory_files).sort
72
+ end
73
+
74
+
75
+ # @return [Array<String>] absolute paths of files referenced by the application.
80
76
  def referenced_files
81
77
  # TODO: state machines can reference external scripts
82
78
  # TODO: behaviors can reference external scripts
83
- assets.map{ |asset| resolve_file_path(asset.src) }
84
- + presentations.flat_map{ |pres| pres.referenced_files }
79
+ (
80
+ [file] +
81
+ assets.map{ |asset| absolute_path(asset.src) } +
82
+ statemachines.flat_map(&:referenced_files) +
83
+ presentations.flat_map(&:referenced_files)
84
+ ).uniq
85
+ end
86
+
87
+ # @return [Array<String>] absolute paths of all files present in the application directory (used or not).
88
+ def directory_files
89
+ dir = File.dirname(file)
90
+ Dir.chdir(dir){ Dir['**/*.*'] }.map{ |f| File.expand_path(f,dir) }
85
91
  end
86
92
 
87
93
  # @return [Array] all assets referenced by the application. Ordered by the order they appear in the `.uia`.
@@ -7,7 +7,7 @@ class UIC::Property
7
7
  attr_accessor :default
8
8
  def initialize(el); @el = el; end
9
9
  def name; @name||=@el['name']; end
10
- def type; @type||=@el['type']; end
10
+ def type; @type||=@el['type'] ? (@el['type']=='float' ? 'Float' : @el['type']) : 'Float'; end
11
11
  def formal; @formal||=@el['formalName'] || @el['name']; end
12
12
  def min; @el['min']; end
13
13
  def max; @el['max']; end
@@ -129,10 +129,18 @@ class UIC::Property
129
129
  end
130
130
  end
131
131
 
132
+ class Font < self
133
+ self.default = 'Arimo-Regular'
134
+ def get(asset,slide); "fonts/#{super}.ttf"; end # TODO: how to support non-ttf fonts?
135
+ def set(asset,new_value,slide_name_or_index)
136
+ # TODO: how to support non-ttf fonts?
137
+ super( asset, new_value.sub(%r{^\.[/\\]},'').sub(%r{^fonts[/\\]},'').sub(%r{\.ttf$},''), slide_name_or_index )
138
+ end
139
+ end
140
+
132
141
  Import = String #TODO: a real class
133
142
  Mesh = String #TODO: a real class
134
143
  Renderable = String #TODO: a real class
135
- Font = String #TODO: a real class
136
144
  FontSize = Long
137
145
 
138
146
  StringListOrInt = String #TODO: a real class
@@ -1,22 +1,9 @@
1
1
  class UIC::Behavior
2
2
  include UIC::FileBacked
3
- attr_reader :lua
4
3
  def initialize( lua_path )
5
4
  self.file = lua_path
6
- load_from_file if file_found?
7
5
  end
8
- def load_from_file
9
- @lua = File.read(file,encoding:'utf-8')
10
- end
11
-
12
- def errors?
13
- !errors.empty?
14
- end
15
-
16
- def errors
17
- file_found? ? [] : ["File not found: '#{file}'"]
18
- end
19
-
6
+ alias_method :lua, :file_content
20
7
  end
21
8
 
22
9
  class UIC::Application::Behavior < UIC::Behavior
@@ -27,6 +14,6 @@ class UIC::Application::Behavior < UIC::Behavior
27
14
  def initialize(application,el)
28
15
  self.owner = application
29
16
  self.el = el
30
- super( application.resolve_file_path(src) )
17
+ super( application.absolute_path(src) )
31
18
  end
32
19
  end
@@ -0,0 +1,32 @@
1
+ class UIC::Effect
2
+ include UIC::FileBacked
3
+ attr_reader :lua
4
+ def initialize( lua_path )
5
+ self.file = lua_path
6
+ load_from_file if file_found?
7
+ end
8
+ def load_from_file
9
+ @lua = File.read(file,encoding:'utf-8')
10
+ end
11
+
12
+ def errors?
13
+ !errors.empty?
14
+ end
15
+
16
+ def errors
17
+ file_found? ? [] : ["File not found: '#{file}'"]
18
+ end
19
+
20
+ end
21
+
22
+ class UIC::Application::Effect < UIC::Effect
23
+ include UIC::ElementBacked
24
+ # @!parse extend UIC::ElementBacked::ClassMethods
25
+ xmlattribute :id
26
+ xmlattribute :src
27
+ def initialize(application,el)
28
+ self.owner = application
29
+ self.el = el
30
+ super( application.absolute_path(src) )
31
+ end
32
+ end
@@ -1,17 +1,23 @@
1
- # Supports classes that represent an XML file on disk (e.g. `.uia` and `.uip`).
1
+ # Supports classes that represent a file on disk (e.g. `.uia` and `.uip`).
2
2
  module UIC::FileBacked
3
- # @return [Nokogiri::XML::Document] the Nokogiri document representing the instance.
4
- attr_accessor :doc
5
-
6
3
  # @return [String] the absolute path to the underlying file.
7
4
  attr_accessor :file
8
5
 
6
+ # @return [String] the content of the file.
7
+ attr_accessor :file_content
8
+
9
9
  # @param relative [String] a file path relative to this file.
10
10
  # @return [String] the full path resolved relative to this file.
11
- def resolve_file_path( relative )
11
+ def absolute_path( relative )
12
12
  File.expand_path( relative.gsub('\\','/'), File.dirname(file) )
13
13
  end
14
14
 
15
+ def relative_path(path)
16
+ my_dir = File.dirname(file) << "/"
17
+ absolute_path(path).tap{ |s| s.slice!(my_dir) }
18
+
19
+ end
20
+
15
21
  # @return [String] the name of the file (without any directories).
16
22
  def filename
17
23
  File.basename(file)
@@ -27,6 +33,39 @@ module UIC::FileBacked
27
33
  # @return [String]
28
34
  def file=( new_path )
29
35
  @file = File.expand_path(new_path)
36
+ if file_found?
37
+ @file_content = File.read(@file,encoding:'utf-8')
38
+ on_file_loaded if respond_to?(:on_file_loaded)
39
+ end
40
+ end
41
+
42
+ # Overwrite the associated file on disk with the `@file_content` of this class.
43
+ # @return [true]
44
+ def save!
45
+ File.open(file,'w:utf-8'){ |f| f << @file_content }
46
+ true
47
+ end
48
+
49
+ # Save to the supplied file path. Subsequent calls to {#save!} will save to the new file, not the original file name.
50
+ def save_as(new_file)
51
+ File.open(new_file,'w:utf-8'){ |f| f << @file_content }
52
+ self.file = new_file
53
+ end
54
+ end
55
+
56
+ # Supports classes that represent an XML file on disk.
57
+ module UIC::XMLFileBacked
58
+ include UIC::FileBacked
59
+
60
+ # @return [Nokogiri::XML::Document] the Nokogiri document representing the instance.
61
+ attr_accessor :doc
62
+
63
+ def file=( new_path )
64
+ super
65
+ if file_found?
66
+ @doc = Nokogiri.XML(file_content,&:noblanks)
67
+ on_doc_loaded if respond_to?(:on_doc_loaded)
68
+ end
30
69
  end
31
70
 
32
71
  # @return [String] the XML representation of the document.
@@ -37,20 +76,19 @@ module UIC::FileBacked
37
76
  # Overwrite the associated file on disk with the {#to_xml} representation of this class.
38
77
  # @return [true]
39
78
  def save!
40
- File.open(file,'w:utf-8'){ |f| f << to_xml }
41
- true
79
+ self.file_content = to_xml
80
+ super
42
81
  end
43
82
 
44
83
  # Save to the supplied file path. Subsequent calls to {#save!} will save to the new file, not the original file name.
45
84
  def save_as(new_file)
46
- File.open(new_file,'w:utf-8'){ |f| f << to_xml }
47
- self.file = new_file
85
+ self.file_content = to_xml
86
+ super
48
87
  end
49
88
  end
50
89
 
51
90
  # Supports classes that represent an XML element (e.g. `<presentation id="main" src="foo.uip"/>`).
52
91
  module UIC::ElementBacked
53
-
54
92
  # @return [Object] the object in charge of this instance.
55
93
  attr_accessor :owner
56
94
 
@@ -65,10 +103,10 @@ module UIC::ElementBacked
65
103
  module ClassMethods
66
104
  # Add methods to instances of the class which gets/sets from an XML attribute.
67
105
  # @param name [String] the name of an XML attribute to expose.
68
- # @param getblock [Proc] a proc to run
106
+ # @param getblock [Proc] a proc to run to fetch the value.
69
107
  def xmlattribute(name,getblock=nil,&setblock)
70
- define_method(name){ getblock ? getblock[@el[name]] : @el[name] }
71
- define_method("#{name}="){ |new_value| @el[name] = (setblock ? setblock[new_value] : new_value).to_s }
108
+ define_method(name){ getblock ? getblock[@el[name],self] : @el[name] }
109
+ define_method("#{name}="){ |new_value| @el[name] = (setblock ? setblock[new_value,self] : new_value).to_s }
72
110
  end
73
111
  end
74
112
  end
@@ -1,22 +1,28 @@
1
1
  # A `Presentation` represents a `.uip` presentation, created and edited by UI Composer Studio.
2
2
  class UIC::Presentation
3
- include UIC::FileBacked
3
+ include UIC::XMLFileBacked
4
4
 
5
5
  # Create a new presentation. If you do not specify the `uip_path` to load from, you must
6
6
  # later set the `.file = `for the presentation, and then call the {#load_from_file} method.
7
7
  # @param uip_path [String] path to the `.uip` to load.
8
8
  def initialize( uip_path=nil )
9
- self.file = uip_path
10
- load_from_file if file_found?
9
+ @doc = Nokogiri.XML('<UIP version="3"><Project><Graph><Scene id="Scene"/></Graph><Logic><State name="Master Slide" component="#Scene"/></Logic></Project></UIP>')
10
+ @graph = @doc.at('Graph')
11
+ @scene = @graph.at('Scene')
12
+ @logic = @doc.at('Logic')
13
+ @missing_classes = []
14
+ @asset_by_el = {} # indexed by asset graph element
15
+ @slides_for = {} # indexed by asset graph element
16
+ @slides_by_el = {} # indexed by slide state element
17
+ self.file = uip_path if uip_path
11
18
  end
12
19
 
13
20
  # Load information for the presentation from disk.
14
21
  # If you supply a path to a `.uip` file when creating the presentation
15
22
  # this method is automatically called.
23
+ #
16
24
  # @return [nil]
17
- def load_from_file
18
- # TODO: this method assumes an application to find the metadata on; the metadata should be part of this class instance instead, shared with the app when present
19
- @doc = Nokogiri.XML( File.read( file, encoding:'utf-8' ), &:noblanks )
25
+ def on_doc_loaded
20
26
  @graph = @doc.at('Graph')
21
27
  @scene = @graph.at('Scene')
22
28
  @logic = @doc.at('Logic')
@@ -24,10 +30,6 @@ class UIC::Presentation
24
30
  generate_custom_classes
25
31
  rebuild_caches_from_document
26
32
 
27
- @asset_by_el = {} # indexed by asset graph element
28
- @slides_for = {} # indexed by asset graph element
29
- @slides_by_el = {} # indexed by slide state element
30
-
31
33
  nil
32
34
  end
33
35
 
@@ -42,6 +44,7 @@ class UIC::Presentation
42
44
  # Called once during initial load of the file.
43
45
  # @return [nil]
44
46
  def generate_custom_classes
47
+ # TODO: this method assumes an application to find the metadata on; the metadata should be part of this class instance instead, shared with the app when present
45
48
  parent_class_name = {
46
49
  'CustomMaterial' => 'MaterialBase',
47
50
  'Effect' => 'Effect',
@@ -49,8 +52,8 @@ class UIC::Presentation
49
52
  }
50
53
  @class_by_ref = {}
51
54
  @doc.xpath('/UIP/Project/Classes/*').each do |reference|
52
- path = resolve_file_path( reference['sourcepath'] )
53
- raise "Cannot find file '#{path}' referenced by #{self.inspect}" unless File.exist?( path )
55
+ path = absolute_path( reference['sourcepath'] )
56
+ next unless File.exist?( path )
54
57
  parent_class = app.metadata.by_name[ parent_class_name[reference.name] ]
55
58
  parent_props = parent_class.properties
56
59
  new_defaults = Hash[ reference.attributes.map{ |name,attr| [name,attr.value] }.select{ |name,val| parent_props[name] } ]
@@ -169,16 +172,39 @@ class UIC::Presentation
169
172
  # Find or create an asset for a scene graph element.
170
173
  # @param el [Nokogiri::XML::Element] the scene graph element.
171
174
  def asset_for_el(el)
172
- (@asset_by_el[el] ||= el['class'] ? @class_by_ref[el['class']].new(self,el) : app.metadata.new_instance(self,el))
175
+ @asset_by_el[el] ||= begin
176
+ if el['class'] && @class_by_ref[el['class']]
177
+ @class_by_ref[el['class']].new(self,el)
178
+ else
179
+ app.metadata.new_instance(self,el)
180
+ end
181
+ end
173
182
  end
174
183
  private :asset_for_el
175
184
 
185
+ # Which files are used by the presentation.
186
+ # @return [Array<String>] array of absolute file paths referenced by this presentation.
176
187
  def referenced_files
177
188
  (
178
- (images + behaviors + effects + meshes + materials ).map(&:file)
179
- + effects.flat_map(&:images)
180
- + fonts
181
- ).sort_by{ |f| parts = f.split(/[\/\\]/); [parts.length,parts] }
189
+ [file] +
190
+ %w[sourcepath importfile].flat_map do |att|
191
+ find(att=>/./).flat_map do |asset|
192
+ asset[att].values.compact.map do |path|
193
+ path.sub!(/#.+/,'')
194
+ absolute_path(path) unless path.empty?
195
+ end.compact
196
+ end
197
+ end +
198
+ find.flat_map do |asset|
199
+ asset.properties.select{ |name,prop| prop.type=='Texture' }.flat_map do |name,prop|
200
+ asset[name].values.compact.uniq.map{ |path| absolute_path(path) }
201
+ end
202
+ end +
203
+ find(_type:'Text').flat_map do |asset|
204
+ asset['font'].values.compact.map{ |font| absolute_path(font) }
205
+ end +
206
+ @doc.xpath('/UIP/Project/Classes/*/@sourcepath').map{ |att| absolute_path att.value }
207
+ ).uniq
182
208
  end
183
209
 
184
210
  # @return [MetaData::Scene] the root scene asset for the presentation.
@@ -243,7 +269,7 @@ class UIC::Presentation
243
269
 
244
270
  # @return [Array<String>] an array (possibly empty) of all errors in this presentation.
245
271
  def errors
246
- (file_found? ? [] : ["File not found: '#{file}'"])
272
+ @errors
247
273
  end
248
274
 
249
275
  # Find an element or asset in this presentation by scripting path.
@@ -599,7 +625,7 @@ class UIC::Presentation
599
625
  cols = hier.map{ |i,a| a ? [ [i,a.name].join, a.type, elide[a.path] ] : [i,"",""] }
600
626
  maxs = cols.transpose.map{ |col| col.map(&:length).max }
601
627
  tmpl = maxs.map{ |n| "%-#{n}s" }.join(' ')
602
- cols.map{ |a| tmpl % a }.join("\n").prepend("\n").extend(RUIC::SelfInspecting)
628
+ cols.map{ |a| tmpl % a }.join("\n").extend(RUIC::SelfInspecting)
603
629
  end
604
630
 
605
631
  # @private
@@ -643,7 +669,7 @@ class UIC::Application::Presentation < UIC::Presentation
643
669
  def initialize(application,el)
644
670
  self.owner = application
645
671
  self.el = el
646
- super( application.resolve_file_path(src) )
672
+ super( application.absolute_path(src) )
647
673
  end
648
674
  alias_method :app, :owner
649
675