jsus 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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