jsus 0.3.6 → 0.4.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.
Files changed (71) hide show
  1. data/.travis.yml +2 -0
  2. data/CHANGELOG +5 -0
  3. data/Gemfile +7 -4
  4. data/VERSION +1 -1
  5. data/bin/jsus +1 -5
  6. data/cucumber.yml +1 -1
  7. data/features/command-line/external_dependency_resolution.feature +4 -4
  8. data/features/command-line/generate_includes.feature +34 -0
  9. data/features/command-line/mooforge_compatibility_layer.feature +1 -1
  10. data/features/command-line/postproc.feature +12 -3
  11. data/features/command-line/structure_json.feature +5 -40
  12. data/features/data/ExternalDependencyWithExternalDependency/Leonardo/Source/Core.js +2 -2
  13. data/features/step_definitions/cli_steps.rb +15 -9
  14. data/features/support/env.rb +1 -1
  15. data/jsus.gemspec +25 -7
  16. data/lib/extensions/rgl.rb +2 -1
  17. data/lib/jsus/cli.rb +43 -27
  18. data/lib/jsus/container.rb +71 -51
  19. data/lib/jsus/middleware.rb +2 -3
  20. data/lib/jsus/package.rb +27 -129
  21. data/lib/jsus/packager.rb +10 -6
  22. data/lib/jsus/pool.rb +48 -20
  23. data/lib/jsus/source_file.rb +119 -198
  24. data/lib/jsus/tag.rb +72 -106
  25. data/lib/jsus/util.rb +14 -4
  26. data/lib/jsus/util/compressor.rb +1 -1
  27. data/lib/jsus/util/documenter.rb +1 -1
  28. data/lib/jsus/util/mixins.rb +7 -0
  29. data/lib/jsus/util/mixins/operates_on_sources.rb +29 -0
  30. data/lib/jsus/util/post_processor.rb +35 -0
  31. data/lib/jsus/util/post_processor/base.rb +32 -0
  32. data/lib/jsus/util/post_processor/moocompat12.rb +19 -0
  33. data/lib/jsus/util/post_processor/mooltie8.rb +19 -0
  34. data/lib/jsus/util/post_processor/semicolon.rb +18 -0
  35. data/lib/jsus/util/validator/base.rb +3 -23
  36. data/lib/jsus/util/watcher.rb +8 -6
  37. data/spec/data/Extensions/app/javascripts/Core/Source/Hash.js +13 -0
  38. data/spec/data/Extensions/app/javascripts/Core/Source/Mash.js +13 -0
  39. data/spec/data/Extensions/app/javascripts/Core/package.yml +3 -1
  40. data/spec/data/Extensions/app/javascripts/Orwik/Extensions/Mash.js +16 -0
  41. data/spec/data/Extensions/app/javascripts/Orwik/package.yml +2 -1
  42. data/spec/data/OutsideDependencies/app/javascripts/Orwik/package.yml +3 -3
  43. data/spec/data/SimpleSources/dependent_source_one.js +15 -0
  44. data/spec/data/SimpleSources/replacement_source_one.js +13 -0
  45. data/spec/data/SimpleSources/simple_source_one.js +13 -0
  46. data/spec/data/SimpleSources/simple_source_two.js +13 -0
  47. data/spec/data/extension_1.js +15 -0
  48. data/spec/data/extension_2.js +15 -0
  49. data/spec/data/replacement.js +15 -0
  50. data/spec/jsus/container_spec.rb +72 -14
  51. data/spec/jsus/package_spec.rb +10 -128
  52. data/spec/jsus/packager_spec.rb +11 -11
  53. data/spec/jsus/pool_spec.rb +13 -22
  54. data/spec/jsus/source_file_spec.rb +66 -215
  55. data/spec/jsus/tag_spec.rb +24 -69
  56. data/spec/jsus/util/documenter_spec.rb +1 -1
  57. data/spec/jsus/util/post_processor/moocompat12_spec.rb +23 -0
  58. data/spec/jsus/util/post_processor/mooltie8_spec.rb +23 -0
  59. data/spec/jsus/util/post_processor/semicolon_spec.rb +21 -0
  60. data/spec/jsus/util/post_processors/base_spec.rb +6 -0
  61. data/spec/jsus/util/tree_spec.rb +3 -3
  62. data/spec/jsus/util/validator/base_spec.rb +4 -2
  63. data/spec/jsus/util/watcher_spec.rb +12 -2
  64. data/spec/shared/mixins_segs.rb +38 -0
  65. data/spec/spec_helper.rb +6 -0
  66. metadata +28 -10
  67. data/features/data/tmp2/package.js +0 -35
  68. data/features/data/tmp2/scripts.json +0 -13
  69. data/features/data/tmp2/tree.json +0 -26
  70. data/lib/jsus/compiler.rb +0 -28
  71. data/spec/shared/class_stubs.rb +0 -31
@@ -12,16 +12,21 @@ module Jsus
12
12
  #
13
13
  # Inits packager with the given sources.
14
14
  #
15
- # @param [*SourceFile] sources source files
15
+ # @param [Container, Array] sources source files
16
16
  # @api public
17
- def initialize(*sources)
18
- self.container = Container.new(*sources)
17
+ def initialize(sources)
18
+ @sources = case sources
19
+ when Array
20
+ Container.new(*sources)
21
+ else
22
+ sources
23
+ end
19
24
  end
20
25
 
21
26
  # @return [Jsus::Container] container with source files
22
27
  # @api public
23
28
  def sources
24
- container
29
+ @sources
25
30
  end
26
31
 
27
32
  # Concatenates all the sources' contents into a single string.
@@ -31,8 +36,7 @@ module Jsus
31
36
  # @return [String] concatenated source files
32
37
  # @api public
33
38
  def pack(output_file = nil)
34
- result = sources.map {|s| s.content }.join("\n")
35
-
39
+ result = sources.map {|s| s.source }.join("\n")
36
40
  if output_file
37
41
  FileUtils.mkdir_p(File.dirname(output_file))
38
42
  File.open(output_file, "w") {|f| f << result }
@@ -23,7 +23,7 @@ module Jsus
23
23
  # one level of symlinks
24
24
  # See also: http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
25
25
  Dir[File.join(dir, '**{,/*/**}', 'package.{yml,json}')].uniq.each do |package_path|
26
- Package.new(File.dirname(package_path), :pool => self)
26
+ self << Package.new(File.dirname(package_path))
27
27
  end
28
28
  end
29
29
  end
@@ -54,15 +54,17 @@ module Jsus
54
54
  # @api public
55
55
  def lookup(source_or_key)
56
56
  case source_or_key
57
- when String
58
- lookup(Tag[source_or_key])
59
- when Tag
60
- replacement_map[source_or_key] || provides_map[source_or_key]
61
- when SourceFile
62
- source_or_key
63
- else
64
- raise "Illegal lookup query. Expected String, Tag or SourceFile, " <<
65
- "given #{source_or_key.inspect}, an instance of #{source_or_key.class.name}."
57
+ when nil
58
+ nil
59
+ when String
60
+ lookup(Tag[source_or_key])
61
+ when Tag
62
+ provides_map[source_or_key]
63
+ when SourceFile
64
+ source_or_key
65
+ else
66
+ raise "Illegal lookup query. Expected String, Tag or SourceFile, " <<
67
+ "given #{source_or_key.inspect}, an instance of #{source_or_key.class.name}."
66
68
  end
67
69
  end
68
70
 
@@ -75,7 +77,7 @@ module Jsus
75
77
  # @api public
76
78
  def lookup_dependencies(source_or_source_key)
77
79
  source = lookup(source_or_source_key)
78
- result = Container.new
80
+ result = []
79
81
  looked_up = []
80
82
  if source
81
83
  dependencies = lookup_direct_dependencies(source)
@@ -84,15 +86,22 @@ module Jsus
84
86
  dependencies = dependencies.map {|d| lookup_direct_dependencies(d).to_a }.flatten.uniq
85
87
  end
86
88
  end
87
- result.sort!
89
+ result
88
90
  end
89
91
 
90
- # @param [String, Jsus::Tag] tag_or_tag_key
91
- # @return [Array] array with source files with extensions for given tag.
92
+ # Returns replacement for given source file.
93
+ # @param [Jsus::SourceFile]
94
+ # @return [Jsus::SourceFile, nil]
95
+ # @api public
96
+ def lookup_replacement(source)
97
+ source.provides.map {|tag| replacement_map[tag] }.compact[0]
98
+ end # lookup_replacement
99
+
100
+ # @param [Jsus::SourceFile]
101
+ # @return [Array] array with source files with extensions for given source file
92
102
  # @api public
93
- def lookup_extensions(tag_or_tag_key)
94
- tag = Tag[tag_or_tag_key]
95
- extensions_map[tag]
103
+ def lookup_extensions(source)
104
+ source.provides.map {|tag| extensions_map[tag] }.flatten.compact
96
105
  end
97
106
 
98
107
  #
@@ -119,13 +128,13 @@ module Jsus
119
128
  provides_map[p] = source
120
129
  end
121
130
 
122
- replacement_map[source.replaces] = source if source.replaces if source.replaces
131
+ replacement_map[source.replaces] = source if source.replaces
123
132
  end
124
133
  when source_or_sources_or_package.kind_of?(Package)
125
134
  package = source_or_sources_or_package
126
135
  packages << package
127
- package.source_files.each {|s| s.pool = self }
128
- package.extensions.each {|e| e.pool = self }
136
+ package.source_files.each {|s| self << s }
137
+ package.extensions.each {|e| self << e }
129
138
  when source_or_sources_or_package.kind_of?(Array) || source_or_sources_or_package.kind_of?(Container)
130
139
  sources = source_or_sources_or_package
131
140
  sources.each {|s| self << s}
@@ -133,6 +142,25 @@ module Jsus
133
142
  self
134
143
  end
135
144
 
145
+ # @param [Jsus::Package]
146
+ # @return [Array]
147
+ # @api public
148
+ def compile_package(package)
149
+ result = []
150
+ package.source_files.each do |source|
151
+ result << source
152
+ result << lookup_dependencies(source) unless source.extension? || source.replacement?
153
+ end
154
+ result = result.flatten.compact
155
+ extra_files = []
156
+ result.each_with_index do |source, i|
157
+ extra_files << lookup_replacement(source)
158
+ extra_files << lookup_extensions(source)
159
+ end
160
+ result = (result + extra_files).flatten.compact
161
+ Container.new(result)
162
+ end # compile_package
163
+
136
164
  #
137
165
  # Drops any cached info
138
166
  # @api public
@@ -8,32 +8,44 @@ module Jsus
8
8
  # It contains general info about source as well as file content.
9
9
  #
10
10
  class SourceFile
11
- # Filename relative to package root
12
- attr_accessor :relative_filename
13
- # Full filename
14
- attr_accessor :filename
15
11
  # Package owning the sourcefile
12
+ # Is not directly used in SourceFile, but might be useful for introspection.
16
13
  attr_accessor :package
17
14
 
15
+ # Original filename (immutable)
16
+ attr_accessor :original_filename
17
+
18
+ # Full filename (when initialized from file)
19
+ attr_accessor :filename
20
+ alias_method :path, :filename
21
+ alias_method :path=, :filename=
22
+
23
+ # Original source code (immutable)
24
+ attr_reader :original_source
25
+
26
+ # Source code (mutable)
27
+ attr_accessor :source
28
+
29
+ # Default namespace for source
30
+ attr_reader :namespace
31
+
32
+
18
33
  # Constructors
19
34
 
20
35
  # Basic constructor.
21
36
  #
22
- # You probably should use SourceFile.from_file instead of this one.
23
- #
37
+ # Initializes a file from source.
38
+ # @param [String] source original source for the file
24
39
  # @param [Hash] options
25
- # @option options [Jsus::Package] :package package to assign source file to.
26
- # @option options [String] :relative_filename used in Package to generate
27
- # tree structure of the source files
28
- # @option options [String] :filename full filename for the given source file
29
- # @option options [String] :content file content of the source file
30
- # @option options [Jsus::Pool] :pool owner pool for that file
31
- # @option options [String] :header header of the file
40
+ # @option options [String] :namespace source file namespace
32
41
  # @api semipublic
33
- def initialize(options = {})
34
- [:package, :header, :relative_filename, :filename, :content, :pool].each do |field|
35
- send("#{field}=", options[field]) if options[field]
36
- end
42
+ def initialize(source, options = {})
43
+ @namespace = options[:namespace]
44
+ @original_source = source.dup
45
+ prepare_original_source
46
+ @source = @original_source.dup
47
+ parse_header
48
+ @original_source.freeze
37
49
  end
38
50
 
39
51
  #
@@ -41,44 +53,28 @@ module Jsus
41
53
  #
42
54
  # @param [String] filename
43
55
  # @param [Hash] options
44
- # @option options [Jsus::Pool] :pool owning pool
45
- # @option options [Jsus::Package] :package owning package
56
+ # @option options [String] :namespace namespace to which the source file by default belongs
46
57
  # @return [Jsus::SourceFile]
47
- # @raise [Jsus::BadSourceFileException] when file cannot be parsed
58
+ # @raise [Jsus::BadSourceFileException] when file cannot be parsed or does not exist
48
59
  # @api public
49
60
  def self.from_file(filename, options = {})
50
- if File.exists?(filename)
51
- source = File.open(filename, 'r:utf-8') {|f| f.read }
52
- bom = RUBY_VERSION =~ /1.9/ ? "\uFEFF" : "\xEF\xBB\xBF"
53
- source.gsub!(bom, "")
54
- yaml_data = source.match(%r(^/\*\s*(---.*?)\*/)m)
55
- if (yaml_data && yaml_data[1] && header = YAML.load(yaml_data[1]))
56
- options[:header] = header
57
- options[:relative_filename] = filename
58
- options[:filename] = File.expand_path(filename)
59
- options[:content] = source
60
- new(options)
61
- else
62
- raise BadSourceFileException, "#{filename} is missing a header or header is invalid"
63
- end
64
- else
65
- raise BadSourceFileException, "Referenced #{filename} does not exist. #{options[:package] ? "Referenced from package #{options[:package].name}" : ""}"
66
- end
61
+ filename = File.expand_path(filename)
62
+ raise BadSourceFileException, "File does not exist." unless File.exists?(filename)
63
+ source = Jsus::Util.read_file(filename)
64
+ source_file = new(source, options)
65
+ source_file.filename = source_file.original_filename = filename
66
+ source_file.original_filename.freeze
67
+ source_file
67
68
  rescue Exception => e
68
- if !e.kind_of?(BadSourceFileException) # if we didn't raise the error; like in YAML, for example
69
- raise "Exception #{e.inspect} happened on #{filename}. Please take appropriate measures"
70
- else # if we did it, just reraise
71
- raise e
72
- end
69
+ e.message.sub! /^/, "Unexpected exception happened while processing #{filename}: "
70
+ Jsus.logger.error e.message
71
+ raise e
73
72
  end
74
73
 
75
- # Public API
76
-
77
74
  # @return [Hash] a header parsed from YAML-formatted source file first comment.
78
75
  # @api public
79
76
  def header
80
- self.header = {} unless @header
81
- @header
77
+ @header ||= {}
82
78
  end
83
79
 
84
80
  # @return [String] description of the source file.
@@ -87,54 +83,32 @@ module Jsus
87
83
  header["description"]
88
84
  end
89
85
 
90
- # @return [Array] list of dependencies for given file
91
- # @api public
92
- def dependencies
93
- @dependencies
94
- end
95
- alias_method :requires, :dependencies
86
+ # @return [String] license of source file
87
+ def license
88
+ header["license"]
89
+ end # license
96
90
 
97
- #
98
- # @param [Hash] options
99
- # @option options [Boolean] :short whether inner dependencies should not
100
- # prepend package name, e.g. 'Class' instead of 'Core/Class' when in
101
- # package 'Core'.
102
- #
103
- # Note Doesn't change anything for external dependencies
104
- #
105
- # @return [Array] array with names of dependencies. Unordered.
106
- # @api public
107
- def dependencies_names(options = {})
108
- dependencies.map {|d| d.name(options) }
109
- end
110
- alias_method :requires_names, :dependencies_names
111
-
112
- # @return [Array] array of external dependencies tags. Unordered.
91
+ # @return [Array] list of authors
113
92
  # @api public
114
- def external_dependencies
115
- dependencies.select {|d| d.external? }
116
- end
93
+ def authors
94
+ @authors
95
+ end # authors
117
96
 
118
- # @returns [Array] array with names for external dependencies. Unordered.
97
+ # @return [Array] list of dependencies for given file
119
98
  # @api public
120
- def external_dependencies_names
121
- external_dependencies.map {|d| d.name }
99
+ def requires
100
+ @requires
122
101
  end
102
+ alias_method :dependencies, :requires
103
+ alias_method :requirements, :requires
123
104
 
124
105
  # @return [Array] array with provides tags.
125
106
  # @api public
126
107
  def provides
127
108
  @provides
128
109
  end
110
+ alias_method :provisions, :provides
129
111
 
130
- # @param [Hash] options
131
- # @option options [Boolean] :short whether provides should not prepend package
132
- # name, e.g. 'Class' instead of 'Core/Class' when in package 'Core'.
133
- # @return [Array] array with provides names.
134
- # @api public
135
- def provides_names(options = {})
136
- provides.map {|p| p.name(options)}
137
- end
138
112
 
139
113
  # @return [Jsus::Tag] tag for replaced file, if any
140
114
  # @api public
@@ -142,7 +116,6 @@ module Jsus
142
116
  @replaces
143
117
  end
144
118
 
145
-
146
119
  # @returns [Jsus::Tag] tag for source file, for which this one is an extension.
147
120
  # @example file Foo.js in package Core provides ['Class', 'Hash']. File
148
121
  # Bar.js in package Bar extends 'Core/Class'. That means its contents would be
@@ -158,45 +131,23 @@ module Jsus
158
131
  extends && !extends.empty?
159
132
  end
160
133
 
161
- # @return [Array] new_value array of included extensions for given source.
134
+ # @return [Boolean] whether the source file is an extension.
162
135
  # @api public
163
- def extensions
164
- @extensions ||= []
165
- @extensions = @extensions.flatten.compact.uniq
166
- @extensions
167
- end
168
-
169
- # @param [Array] new_value list of extensions for given file
170
- # @api semipublic
171
- def extensions=(new_value)
172
- @extensions = new_value
173
- end
174
-
175
- # Looks up for extensions in the pool and then includes
176
- # extensions for all the provides tag this source file has.
177
- # Caches the result.
178
- #
179
- # @api semipublic
180
- def include_extensions
181
- @included_extensions ||= include_extensions!
182
- end
136
+ def replacement?
137
+ replaces && !replaces.empty?
138
+ end # replacement?
183
139
 
184
- # @see #include_extensions
185
- # @api semipublic
186
- def include_extensions!
187
- if pool
188
- provides.each do |p|
189
- extensions << pool.lookup_extensions(p)
190
- end
191
- end
192
- end
140
+ # @api private
141
+ def reset
142
+ @source = @original_source.dup
143
+ @filename = @original_filename.dup if @original_filename
144
+ end # reset_linked
193
145
 
194
146
  # @return [Array] array of files required by this files including all the filenames for extensions.
195
147
  # SourceFile filename always goes first, all the extensions are unordered.
196
148
  # @api public
197
149
  def required_files
198
- include_extensions
199
- [filename, extensions.map {|e| e.filename}].flatten
150
+ [filename].flatten
200
151
  end
201
152
 
202
153
  # @return [Hash] hash containing basic info with dependencies/provides tags' names
@@ -206,8 +157,8 @@ module Jsus
206
157
  def to_hash
207
158
  {
208
159
  "desc" => description,
209
- "requires" => dependencies_names(:short => true),
210
- "provides" => provides_names(:short => true)
160
+ "requires" => requires.map {|tag| tag.namespace == namespace ? tag.name : tag.full_name},
161
+ "provides" => provides.map {|tag| tag.name}
211
162
  }
212
163
  end
213
164
 
@@ -215,87 +166,7 @@ module Jsus
215
166
  # @return [String]
216
167
  # @api public
217
168
  def inspect
218
- self.to_hash.inspect
219
- end
220
-
221
- # Parses header and gets info from it.
222
- # @param [String] new_header header content
223
- # @api private
224
- def header=(new_header)
225
- @header = new_header
226
- # prepare defaults
227
- @header["description"] ||= ""
228
- # handle tags
229
- @dependencies = parse_tag_list(Array(@header["requires"]))
230
- @provides = parse_tag_list(Array(@header["provides"]))
231
-
232
- @extends = case @header["extends"]
233
- when Array then Tag.new(@header["extends"][0])
234
- when String then Tag.new(@header["extends"])
235
- else nil
236
- end
237
-
238
- @replaces = case @header["replaces"]
239
- when Array then Tag.new(@header["replaces"][0])
240
- when String then Tag.new(@header["replaces"])
241
- else nil
242
- end
243
- end
244
-
245
- # @param [String] new_value file content
246
- # @api private
247
- def content=(new_value)
248
- @content = new_value
249
- end
250
-
251
- # @return [String] file contents, *including* extensions
252
- # @api semipublic
253
- def content
254
- include_extensions
255
- [@content, extensions.map {|e| e.content}].flatten.compact.join("\n")
256
- end
257
-
258
- # @return [String] Original file contents
259
- # @api semipublic
260
- def original_content
261
- @content
262
- end
263
-
264
- # @param [Enumerable] tag_list list of tags
265
- # @return [Array] normalized tags list
266
- # @api private
267
- def parse_tag_list(tag_list)
268
- tag_list.map do |tag_name|
269
- case tag_name
270
- when String
271
- Tag.new(tag_name, :package => package)
272
- when Hash
273
- tags = []
274
- tag_name.each do |pkg_name, sources|
275
- normalized_package_name = pkg_name.sub(/(.+)\/.*$/, "\\1")
276
- Array(sources).each do |source|
277
- tags << Tag.new([normalized_package_name, source].join("/"))
278
- end
279
- end
280
- tags
281
- end
282
- end.flatten
283
- end # parse_tag_list
284
-
285
- # Assigns an instance of Jsus::Pool to the source file.
286
- # Also performs push to that pool.
287
- # @param [Jsus::Pool] new_value
288
- # @api private
289
- def pool=(new_value)
290
- @pool = new_value
291
- @pool << self if @pool
292
- end
293
-
294
- # A pool which the source file is assigned to. Used in #include_extensions!
295
- # @return [Jsus::Pool]
296
- # @api semipublic
297
- def pool
298
- @pool
169
+ self.to_hash.merge("namespace" => namespace).inspect
299
170
  end
300
171
 
301
172
  # @api public
@@ -312,5 +183,55 @@ module Jsus
312
183
  def hash
313
184
  [self.class, filename].hash
314
185
  end
186
+
187
+ private
188
+
189
+ # @api private
190
+ def prepare_original_source
191
+ bom = RUBY_VERSION[/1.9/] ? "\uFEFF" : "\xEF\xBB\xBF"
192
+ original_source.gsub!(bom, "")
193
+ end # prepare_original_source
194
+
195
+ # @api private
196
+ def parse_header
197
+ yaml_data = source.match(%r(^/\*\s*(---.*?)\*/)m)
198
+ if yaml_data && yaml_data[1] && header = YAML.load(yaml_data[1])
199
+ @header = header
200
+ @authors = Array(@header["author"] || @header["authors"])
201
+ @requires = process_tag_list(@header["requires"])
202
+ @provides = process_tag_list(@header["provides"])
203
+ @replaces = process_tag(@header["replaces"]) if @header["replaces"]
204
+ @extends = process_tag(@header["extends"]) if @header["extends"]
205
+ else
206
+ raise BadSourceFileException, "#{filename} is missing a header or header is invalid"
207
+ end
208
+ end # parse_header
209
+
210
+ # @api private
211
+ def process_tag(tag_name)
212
+ if tag_name.kind_of?(String)
213
+ tag_name.sub!(%r{^\.?/}, "") # remove leading slash / dot+slash
214
+ if tag_name.index("/") || !namespace
215
+ Tag[tag_name]
216
+ else
217
+ Tag["#{namespace}/#{tag_name}"]
218
+ end
219
+ elsif tag_name.kind_of?(Hash)
220
+ # Quirky mootools tags
221
+ ns, tag = tag_name.first[0], tag_name.first[1]
222
+ # Removes strings like "/1.3.0" from the end of namespace part
223
+ ns = ns.sub(%r{/(\d+\.?)+\d+$}, "")
224
+ ns = Util::Inflection.random_case_to_mixed_case(ns)
225
+ "#{ns}/#{tag}"
226
+ else
227
+ nil
228
+ end
229
+ end # process_tag
230
+
231
+ # @api private
232
+ def process_tag_list(tag_list)
233
+ Array(tag_list).map {|tag| process_tag(tag) }.compact
234
+ end # process_tag_list
235
+
315
236
  end
316
237
  end