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
@@ -6,46 +6,51 @@ module Jsus
6
6
  # @example
7
7
  # "Core/Class" is a tag
8
8
  class Tag
9
- # Owner package
10
- attr_accessor :package
11
- # Whether tag is external
12
- attr_accessor :external
9
+ # Default separator of full name parts
10
+ SEPARATOR = "/".freeze
13
11
 
14
12
  # Constructors
15
13
 
16
14
  #
17
- # Creates a tag from given name/options.
18
- #
19
- # The way it works may seem a bit tricky but actually it parses name/options
20
- # combinations in different ways and may be best described by examples:
15
+ # Creates a tag from given string.
21
16
  #
22
17
  # @example
23
18
  #
24
- # a = Tag.new("Class") # :package_name => "", :name => "Class", :external => false
25
- # b = Tag.new("Core/Class") # :package_name => "Core", :name => "Class", :external => true
26
- # core = Package.new(...) # let's consider its name is 'Core'
27
- # c = Tag.new("Class", :package => core) # :package_name => "Core", :name => "Class", :external => false
28
- # d = Tag.new("Core/Class", :package => core) # :package_name => "Core", :name => "Class", :external => false
29
- # mash = Package.new(...) # let's consider its name is 'Mash'
30
- # e = Tag.new("Core/Class", :package => mash) # :package_name => "Core", :name => "Class", :external => true
31
- #
32
- # Between all those, tags b,c,d and e are equal, meaning they all use
33
- # the same spot in Hash or wherever else.
19
+ # a = Tag.new("Class") # :namespace => nil, :name => "Class"
20
+ # b = Tag.new("Core/Class") # :namespace => "Core", :name => "Class"
21
+ # c = Tag.new("Mootools/Core") # :namespace => "Mootools/Core", :name => "Class"
34
22
  #
35
- # @param [String] name tag name
36
- # @param [Hash] options
37
- # @option options [String] :package_name owner package name
38
- # @option options [Jsus::Package] :package :owner package
39
- # @option options [Boolean] :external whether tag is considered external
23
+ # @param [String] name full tag name
40
24
  # @api public
41
- def initialize(name, options = {})
42
- normalized_options = Tag.normalize_name_and_options(name, options)
43
- [:name, :package, :package_name, :external].each do |field|
44
- self.send("#{field}=", normalized_options[field])
45
- end
25
+ def initialize(full_name)
26
+ self.full_name = full_name
46
27
  end
47
28
 
48
- # When given a tag instead of tag name, just returns it.
29
+ # Full name, including namespace
30
+ # @return [String]
31
+ # @api public
32
+ def full_name
33
+ if namespace
34
+ "#{namespace}#{SEPARATOR}#{name}"
35
+ else
36
+ "#{name}"
37
+ end
38
+ end # full_name
39
+ alias_method :to_s, :full_name
40
+
41
+
42
+ # Assigns full name
43
+ # @param [String] full_name full tag name, including namespace
44
+ # @api semipublic
45
+ def full_name=(full_name)
46
+ @full_name = full_name
47
+ name_parts = @full_name.split(SEPARATOR)
48
+ self.namespace = name_parts[0..-2].join(SEPARATOR) if name_parts.size > 1
49
+ self.name = name_parts[-1]
50
+ end # full_name=
51
+
52
+ # Instantiates a tag.
53
+ # @note When given a tag instead of tag name, returns the input
49
54
  # @api public
50
55
  def self.new(tag_or_name, *args, &block)
51
56
  if tag_or_name.kind_of?(Tag)
@@ -63,46 +68,56 @@ module Jsus
63
68
 
64
69
  # Public API
65
70
 
66
- # @returns [Boolean] whether tag is external
67
- # @api public
68
- def external?
69
- !!external
70
- end
71
-
72
- # @param [Hash] options
73
- # @option options [Boolean] :short whether the tag should try using short form
74
- # @note only non-external tags support short forms.
71
+ # Returns the last part of the tag.
75
72
  # @example
76
- # Tag.new('Core/Class').name(:short => true) # => 'Core/Class'
77
- # core = Package.new(...) # let's consider its name is 'Core'
78
- # Tag.new('Core/Class', :package => core).name(:short => true) # => 'Class'
79
- # @return [String] a well-formed name for the tag.
73
+ # Tag.new('Core/Class').name # => 'Class'
74
+ # @return [String] last part of the tag
80
75
  # @api public
81
- def name(options = {})
82
- if !package_name || package_name.empty? || (options[:short] && !external?)
83
- @name
84
- else
85
- "#{package_name}/#{@name}"
86
- end
76
+ def name
77
+ @name
87
78
  end
88
- alias_method :to_s, :name
89
79
 
90
- # @returns [String] package name or an empty string
80
+ # Set name.
81
+ # @param [String] name
82
+ # @api semipublic
83
+ def name=(name)
84
+ @name = normalize(name)
85
+ end # name=
86
+
87
+
88
+ # Name without namespace
89
+ # @return [String]
91
90
  # @api public
92
- def package_name
93
- @package_name ||= (@package ? @package.name : "")
94
- end
91
+ attr_reader :namespace
92
+
93
+ # Set namespace
94
+ # @param [String] namespace
95
+ # @api semipublic
96
+ def namespace=(namespace)
97
+ @namespace = normalize(namespace)
98
+ end # namespace=
99
+
100
+ # Normalizes name or namespace (converts snake_case to MixedCase)
101
+ # @param [String] string
102
+ # @return [String]
103
+ # @api semipublic
104
+ def normalize(string)
105
+ return unless string
106
+ return string if string.include?("*")
107
+ parts = string.split(SEPARATOR)
108
+ parts.map {|part| Util::Inflection.random_case_to_mixed_case_preserve_dots(part) }.join(SEPARATOR)
109
+ end # normalize
95
110
 
96
111
  # @return [Boolean] whether name is empty
97
112
  # @api public
98
113
  def empty?
99
- @name.empty?
114
+ !@name || @name.empty?
100
115
  end
101
116
 
102
117
  # @api public
103
118
  def ==(other)
104
119
  if other.kind_of?(Tag)
105
- self.name == other.name
120
+ self.name == other.name && self.namespace == other.namespace
106
121
  else
107
122
  super
108
123
  end
@@ -115,62 +130,13 @@ module Jsus
115
130
 
116
131
  # @api semipublic
117
132
  def hash
118
- self.name.hash
133
+ [self.name, self.namespace].hash
119
134
  end
120
135
 
121
136
  # @return [String] human-readable representation
122
137
  # @api public
123
138
  def inspect
124
- "<Jsus::Tag: #{name}>"
125
- end
126
-
127
- # Private API
128
-
129
- # @api private
130
- def self.normalize_name_and_options(name, options = {})
131
- result = {}
132
- name.gsub!(%r(^(\.)?/), "")
133
- if name.index("/")
134
- parsed_name = name.split("/")
135
- result[:package_name], result[:name] = parsed_name[0..-2].join("/"), parsed_name[-1]
136
- result[:external] = options[:package] ? (result[:package_name] != options[:package].name) : true
137
- else
138
- if options[:package]
139
- result[:package] = options[:package]
140
- result[:package_name] = options[:package].name
141
- end
142
- result[:name] = name
143
- end
144
- result[:package_name] = normalize_package_name(result[:package_name]) if result[:package_name]
145
- result
146
- end
147
-
148
- # @api private
149
- def self.normalized_options_to_full_name(options)
150
- [options[:package_name], options[:name]].compact.join("/")
151
- end
152
-
153
- # @api private
154
- def self.name_and_options_to_full_name(name, options = {})
155
- normalized_options_to_full_name(normalize_name_and_options(name, options))
156
- end
157
-
158
- # @api private
159
- def self.normalize_package_name(name)
160
- package_chunks = name.split("/")
161
- package_chunks.map do |pc|
162
- Jsus::Util::Inflection.random_case_to_mixed_case(pc)
163
- end.join("/")
164
- end # normalize_name
165
-
166
- # @api private
167
- def package_name=(new_value)
168
- @package_name = new_value
169
- end
170
-
171
- # @api private
172
- def name=(new_value)
173
- @name = new_value
139
+ "<Jsus::Tag: #{full_name}>"
174
140
  end
175
141
  end
176
142
  end
@@ -1,14 +1,16 @@
1
1
  module Jsus
2
2
  # Utility namespace.
3
3
  module Util
4
+ autoload :CodeGenerator, 'jsus/util/code_generator'
4
5
  autoload :Compressor, 'jsus/util/compressor'
5
- autoload :Tree, 'jsus/util/tree'
6
6
  autoload :Documenter, 'jsus/util/documenter'
7
- autoload :Validator, 'jsus/util/validator'
8
- autoload :Inflection, 'jsus/util/inflection'
9
7
  autoload :FileCache, 'jsus/util/file_cache'
10
- autoload :CodeGenerator, 'jsus/util/code_generator'
8
+ autoload :Inflection, 'jsus/util/inflection'
11
9
  autoload :Logger, 'jsus/util/logger'
10
+ autoload :Mixins, 'jsus/util/mixins'
11
+ autoload :PostProcessor, 'jsus/util/post_processor'
12
+ autoload :Tree, 'jsus/util/tree'
13
+ autoload :Validator, 'jsus/util/validator'
12
14
  autoload :Watcher, 'jsus/util/watcher'
13
15
 
14
16
  class <<self
@@ -28,6 +30,14 @@ module Jsus
28
30
  false
29
31
  end
30
32
  end
33
+
34
+ # Reads file in UTF-8 encoding in a safe way.
35
+ # Some ruby versions mess up the encodings and some spill out lots of warnings
36
+ # unless you do the right thing
37
+ def read_file(filename)
38
+ mode_string = RUBY_VERSION =~ /^1.9/ ? 'r:utf-8' : 'r'
39
+ File.open(filename, mode_string) {|f| f.read }
40
+ end # read_file
31
41
  end # class <<self
32
42
  end # Util
33
43
  end # Jsus
@@ -56,7 +56,7 @@ module Jsus
56
56
 
57
57
  # @api private
58
58
  def try_compress(source, library, libname = nil)
59
- if Jsus::Util.try_load(library, libname) then
59
+ if Jsus::Util.try_load(library, libname)
60
60
  yield
61
61
  else
62
62
  source
@@ -127,7 +127,7 @@ module Jsus
127
127
  # @api private
128
128
  def create_documentation_for_source(source, template) # :nodoc:
129
129
  skipped_lines = 0
130
- content = source.original_content.gsub(/\A\s*\/\*.*?\*\//m) {|w| skipped_lines += w.split("\n").size; "" }
130
+ content = source.original_source.gsub(/\A\s*\/\*.*?\*\//m) {|w| skipped_lines += w.split("\n").size; "" }
131
131
  annotator = Murdoc::Annotator.new(content, :javascript, options)
132
132
  Murdoc::Formatter.new(template).render(:paragraphs => annotator.paragraphs, :header => source.header, :source => source, :skipped_lines => skipped_lines)
133
133
  end
@@ -0,0 +1,7 @@
1
+ module Jsus
2
+ module Util
3
+ module Mixins
4
+ autoload :OperatesOnSources, 'jsus/util/mixins/operates_on_sources'
5
+ end # module Mixins
6
+ end # module Util
7
+ end # module Jsus
@@ -0,0 +1,29 @@
1
+ module Jsus
2
+ module Util
3
+ module Mixins
4
+ module OperatesOnSources
5
+ # @return [Array] source files for validation
6
+ # @api public
7
+ def source_files
8
+ @source_files ||= []
9
+ end
10
+ alias_method :sources, :source_files
11
+
12
+ # @param [Jsus::Pool, Jsus::Container, Array] pool_or_array_or_container
13
+ # source files for validation
14
+ # @api public
15
+ def source_files=(pool_or_array_or_container)
16
+ case pool_or_array_or_container
17
+ when Pool
18
+ @source_files = pool_or_array_or_container.sources.to_a
19
+ when Array
20
+ @source_files = pool_or_array_or_container
21
+ when Container
22
+ @source_files = pool_or_array_or_container.to_a
23
+ end
24
+ end
25
+ alias_method :sources=, :source_files=
26
+ end # module OperatesOnSources
27
+ end # module Mixins
28
+ end # module Util
29
+ end # module Jsus
@@ -0,0 +1,35 @@
1
+ module Jsus
2
+ module Util
3
+ module PostProcessor
4
+ autoload :Base, "jsus/util/post_processor/base"
5
+ autoload :Moocompat12, "jsus/util/post_processor/moocompat12"
6
+ autoload :MooltIE8, "jsus/util/post_processor/mooltie8"
7
+ autoload :Semicolon, "jsus/util/post_processor/semicolon"
8
+
9
+ AVAILABLE_PROCESSORS = ["mooltie8", "moocompat12", "semicolon"].freeze
10
+ # Accepts a collection of source files and list of processors and applies
11
+ # these processors to the sources.
12
+ #
13
+ # @param [Array, Pool, Container] source_files source files
14
+ # @param [Array] processors array with names of processors
15
+ # Available postprocs: "mooltie8", "moocompat12"
16
+ # @return [Array] processed sources
17
+ def self.process(source_files, processors)
18
+ Array(processors).each do |processor|
19
+ source_files = case processor.strip
20
+ when /moocompat12/i
21
+ Moocompat12.new(source_files).process
22
+ when /mooltie8/i
23
+ MooltIE8.new(source_files).process
24
+ when /semicolon/i
25
+ Semicolon.new(source_files).process
26
+ else
27
+ Jsus.logger.error "Unknown post-processor: #{processor}"
28
+ source_files
29
+ end
30
+ end
31
+ source_files
32
+ end # self.process
33
+ end # module PostProcessor
34
+ end # module Util
35
+ end # module Jsus
@@ -0,0 +1,32 @@
1
+ module Jsus
2
+ module Util
3
+ module PostProcessor
4
+ # Base class for post-processing routines.
5
+ # Post-processors are non-mutating boxes that accept a collection of
6
+ # SourceFile-s on input and return a collection of SourceFiles on output.
7
+ #
8
+ # Post-processing is not mutating the arguments, but dupes them instead
9
+ class Base
10
+ include Jsus::Util::Mixins::OperatesOnSources
11
+
12
+ # Constructor accepts pool or array or container and adds every file
13
+ # to its source files set.
14
+ # @param [Jsus::Pool, Jsus::Container, Array] source files to validate
15
+ # @api public
16
+ def initialize(pool_or_array_or_container = [])
17
+ self.source_files = pool_or_array_or_container
18
+ end # initialize
19
+
20
+ # Processes input source files, return a resulting collection
21
+ # @note This method should not mutate input sources
22
+ # @abstract Override in subclasses
23
+ # @param [Hash] options options hash
24
+ # @return [Array] processed source files
25
+ # @api public
26
+ def process(options = {})
27
+ raise NotImplementedError, "override #process in subclasses"
28
+ end # process
29
+ end # class Base
30
+ end # module PostProcessor
31
+ end # module Util
32
+ end # module Jsus
@@ -0,0 +1,19 @@
1
+ module Jsus
2
+ module Util
3
+ module PostProcessor
4
+ class Moocompat12 < Base
5
+ # Removes everything between <1.2compat> </1.2compat> tags
6
+ # @return [Array]
7
+ # @see Jsus::Util::PostProcessor::Base#process
8
+ def process(options = {})
9
+ source_files.map do |file|
10
+ file = file.dup
11
+ file.source = file.source.gsub(/\/\/<1.2compat>.*?\/\/<\/1.2compat>/m, '')
12
+ file.source = file.source.gsub(/\/\*<1.2compat>\*\/.*?\/\*<\/1.2compat>\*\//m, '')
13
+ file
14
+ end
15
+ end # process
16
+ end # class Moocompat12
17
+ end # module PostProcessor
18
+ end # module Util
19
+ end # module Jsus
@@ -0,0 +1,19 @@
1
+ module Jsus
2
+ module Util
3
+ module PostProcessor
4
+ class MooltIE8 < Base
5
+ # Removes everything between <ltIE8> </ltIE8> tags
6
+ # @return [Array]
7
+ # @see Jsus::Util::PostProcessor::Base#process
8
+ def process(options = {})
9
+ source_files.map do |file|
10
+ file = file.dup
11
+ file.source = file.source.gsub(/\/\/<ltIE8>.*?\/\/<\/ltIE8>/m, '')
12
+ file.source = file.source.gsub(/\/\*<ltIE8>\*\/.*?\/\*<\/ltIE8>\*\//m, '')
13
+ file
14
+ end
15
+ end # process
16
+ end # class MooltIE8
17
+ end # module PostProcessor
18
+ end # module Util
19
+ end # module Jsus
@@ -0,0 +1,18 @@
1
+ module Jsus
2
+ module Util
3
+ module PostProcessor
4
+ class Semicolon < Base
5
+ # Adds a semicolon to the beginning of every file
6
+ # @return [Array]
7
+ # @see Jsus::Util::PostProcessor::Base#process
8
+ def process(options = {})
9
+ source_files.map do |file|
10
+ file = file.dup
11
+ file.source = file.source.gsub(/^([^;])/, ";\n")
12
+ file
13
+ end
14
+ end # process
15
+ end # class Semicolon
16
+ end # module PostProcessor
17
+ end # module Util
18
+ end # module Jsus