jsus 0.2.7 → 0.3.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 (45) hide show
  1. data/.travis.yml +6 -0
  2. data/CHANGELOG +4 -1
  3. data/Gemfile +4 -1
  4. data/VERSION +1 -1
  5. data/bin/jsus +30 -9
  6. data/features/command-line/compression.feature +24 -0
  7. data/features/command-line/mooforge_compatibility_layer.feature +75 -0
  8. data/features/data/Compression/Source/Library/Color.js +17 -0
  9. data/features/data/Compression/Source/Widget/Input/Input.Color.js +21 -0
  10. data/features/data/Compression/package.yml +9 -0
  11. data/features/data/MooforgePlugin/Core/Source/Core.js +16 -0
  12. data/features/data/MooforgePlugin/Core/package.yml +8 -0
  13. data/features/data/MooforgePlugin/Plugin/Source/plugin-support.js +20 -0
  14. data/features/data/MooforgePlugin/Plugin/Source/plugin.js +21 -0
  15. data/features/data/MooforgePlugin/Plugin/package.yml +9 -0
  16. data/features/data/compression.min.js +1 -0
  17. data/jsus.gemspec +45 -22
  18. data/lib/jsus/middleware.rb +178 -0
  19. data/lib/jsus/package.rb +10 -10
  20. data/lib/jsus/source_file.rb +58 -30
  21. data/lib/jsus/tag.rb +18 -10
  22. data/lib/jsus/util/file_cache.rb +57 -0
  23. data/lib/jsus/util/inflection.rb +39 -0
  24. data/lib/jsus/util.rb +2 -0
  25. data/lib/jsus.rb +2 -0
  26. data/spec/data/ComplexDependencies/Mootools/Source/Core.js +16 -0
  27. data/spec/data/ComplexDependencies/Mootools/package.yml +8 -0
  28. data/spec/data/ComplexDependencies/Output/package.js +70 -0
  29. data/spec/data/ComplexDependencies/Output/scripts.json +14 -0
  30. data/spec/data/ComplexDependencies/Output/tree.json +33 -0
  31. data/spec/data/ComplexDependencies/Source/Library/Color.js +19 -0
  32. data/spec/data/ComplexDependencies/Source/Widget/Input/Input.Color.js +20 -0
  33. data/spec/data/ComplexDependencies/Source/Widget/Input.js +16 -0
  34. data/spec/data/ComplexDependencies/package.yml +10 -0
  35. data/spec/data/mooforge_quirky_source.js +20 -0
  36. data/spec/data/unicode_source.js +23 -0
  37. data/spec/data/unicode_source_with_bom.js +23 -0
  38. data/spec/jsus/middleware_spec.rb +216 -0
  39. data/spec/jsus/package_spec.rb +12 -6
  40. data/spec/jsus/source_file_spec.rb +42 -14
  41. data/spec/jsus/tag_spec.rb +8 -2
  42. data/spec/jsus/util/file_cache_spec.rb +67 -0
  43. data/spec/jsus/util/inflection_spec.rb +42 -0
  44. metadata +124 -62
  45. data/Gemfile.lock +0 -79
@@ -0,0 +1,178 @@
1
+ require 'rack/utils'
2
+ module Jsus
3
+ #
4
+ # Rack middleware
5
+ #
6
+ # Just "use Jsus::Middleware" in your rack application and all the requests
7
+ # to /javascripts/jsus/* are redirected to the middleware.
8
+ #
9
+ # Configuration:
10
+ #
11
+ # Use Jsus::Middleware.settings= method to change some settings, such as:
12
+ # :packages_dir - path to where you store your packages
13
+ # :cache - enable simple file caching
14
+ # :cache_path - directory for file caching
15
+ # :prefix - change /jsus/ to something else or remove it altogether (set to nil)
16
+ # :cache_pool - cache js pool between requests. Can save you some time
17
+ # between requests but annoys a lot during development.
18
+ #
19
+ #
20
+ # Examples:
21
+ #
22
+ # GET /javascripts/jsus/Mootools.Core+Mootools.More
23
+ # merges packages named Mootools.Core and Mootools.More with all the
24
+ # dependencies and outputs the result.
25
+ #
26
+ # GET /javascripts/jsus/Mootools.More~Mootools.Core
27
+ # returns package Mootools.More with all the dependencies MINUS any of
28
+ # Mootools.Core dependencies.
29
+ #
30
+ # GET /javascripts/jsus/Mootools.Core:Class+Mootools.More:Fx
31
+ # same thing but for source files providing Mootools.Core/Class and
32
+ # Mootools.More/Fx
33
+ #
34
+ #
35
+ # Also see sinatra example https://github.com/jsus/jsus-sinatra-app
36
+ #
37
+ class Middleware
38
+ include Rack
39
+ class <<self
40
+ DEFAULT_SETTINGS = {
41
+ :packages_dir => ".",
42
+ :cache => false,
43
+ :cache_path => nil,
44
+ :prefix => "jsus",
45
+ :cache_pool => true
46
+ }.freeze
47
+
48
+ def settings
49
+ @settings ||= DEFAULT_SETTINGS.dup
50
+ end # settings
51
+
52
+ def settings=(new_settings)
53
+ settings.merge!(new_settings)
54
+ end # settings=
55
+
56
+ def pool
57
+ @pool ||= Jsus::Pool.new(settings[:packages_dir])
58
+ end # pool
59
+
60
+ def cache?
61
+ settings[:cache]
62
+ end # cache?
63
+
64
+ def cache
65
+ @cache ||= cache? ? Util::FileCache.new(settings[:cache_path]) : nil
66
+ end # cache
67
+ end # class <<self
68
+
69
+ def initialize(app)
70
+ @app = app
71
+ end # initialize
72
+
73
+ def _call(env)
74
+ path = Utils.unescape(env["PATH_INFO"])
75
+ return @app.call(env) unless handled_by_jsus?(path)
76
+ path.sub!(path_prefix_regex, "")
77
+ components = path.split("/")
78
+ return @app.call(env) unless components.size >= 2
79
+ if components[0] == "require"
80
+ generate(components[1])
81
+ else
82
+ not_found!
83
+ end
84
+ end # _call
85
+
86
+ def call(env)
87
+ dup._call(env)
88
+ end # call
89
+
90
+ protected
91
+
92
+ def generate(path_string)
93
+ path_args = parse_path_string(path_string.sub(/.js$/, ""))
94
+ files = []
95
+ path_args[:include].each {|tag| files += get_associated_files(tag).to_a }
96
+ path_args[:exclude].each {|tag| files -= get_associated_files(tag).to_a }
97
+ if !files.empty?
98
+ response = Container.new(*files).map {|f| f.content }.join("\n")
99
+ cache.write(path_string, response) if cache?
100
+ respond_with(response)
101
+ else
102
+ not_found!
103
+ end
104
+ end # generate
105
+
106
+ # Notice: + is a space after url decoding
107
+ # input:
108
+ # "Package:A~Package:C Package:B~Other:D"
109
+ # output:
110
+ # {:include => ["Package/A", "Package/B"], :exclude => ["Package/C", "Other/D"]}
111
+ def parse_path_string(path_string)
112
+ path_string = " " + path_string unless path_string[0,1] =~ /\+\-/
113
+ included = []
114
+ excluded = []
115
+ path_string.scan(/([ ~])([^ ~]*)/) do |op, arg|
116
+ arg = arg.gsub(":", "/")
117
+ if op == " "
118
+ included << arg
119
+ else
120
+ excluded << arg
121
+ end
122
+ end
123
+ {:include => included, :exclude => excluded}
124
+ end # parse_path_string
125
+
126
+ def get_associated_files(source_file_or_package)
127
+ if package = pool.packages.detect {|pkg| pkg.name == source_file_or_package}
128
+ package.include_dependencies!
129
+ package.linked_external_dependencies.to_a + package.source_files.to_a
130
+ elsif source_file = pool.lookup(source_file_or_package)
131
+ pool.lookup_dependencies(source_file) << source_file
132
+ else
133
+ []
134
+ end
135
+ end # get_associated_files
136
+
137
+ def not_found!
138
+ [404, {"Content-Type" => "text/plain"}, ["Jsus doesn't know anything about this entity"]]
139
+ end # not_found!
140
+
141
+ def respond_with(text)
142
+ [200, {"Content-Type" => "text/javascript"}, [text]]
143
+ end # respond_with
144
+
145
+
146
+ def handled_by_jsus?(path)
147
+ path =~ path_prefix_regex
148
+ end # handled_by_jsus?
149
+
150
+ def path_prefix
151
+ @path_prefix ||= self.class.settings[:prefix] ? "/javascripts/#{self.class.settings[:prefix]}/" : "/javascripts/"
152
+ end # path_prefix
153
+
154
+ def path_prefix_regex
155
+ @path_prefix_regex ||= %r{^#{path_prefix}}
156
+ end # path_prefix_regex
157
+
158
+ def pool
159
+ if cache_pool?
160
+ self.class.pool
161
+ else
162
+ @pool ||= Jsus::Pool.new(self.class.settings[:packages_dir])
163
+ end
164
+ end # pool
165
+
166
+ def cache?
167
+ self.class.cache?
168
+ end # cache?
169
+
170
+ def cache
171
+ self.class.cache
172
+ end # cache
173
+
174
+ def cache_pool?
175
+ self.class.settings[:cache_pool]
176
+ end # cache_pool?
177
+ end # class Middleware
178
+ end # module Jsus
data/lib/jsus/package.rb CHANGED
@@ -7,7 +7,7 @@ module Jsus
7
7
  attr_accessor :directory # directory which this package resides in (full path)
8
8
  attr_accessor :pool # an instance of Pool
9
9
  # Constructors
10
-
10
+
11
11
  #
12
12
  # Creates a package from given directory.
13
13
  #
@@ -48,7 +48,7 @@ module Jsus
48
48
 
49
49
 
50
50
  # Public API
51
-
51
+
52
52
  # Returns a package.yml header.
53
53
  def header
54
54
  @header ||= {}
@@ -58,15 +58,15 @@ module Jsus
58
58
  def name
59
59
  header["name"] ||= ""
60
60
  end
61
-
61
+
62
62
  # Returns a package description.
63
63
  def description
64
64
  header["description"] ||= ""
65
- end
65
+ end
66
66
 
67
67
  # Returns a filename for compiled package.
68
68
  def filename
69
- header["filename"] ||= name + ".js"
69
+ header["filename"] ||= Jsus::Util::Inflection.snake_case(name) + ".js"
70
70
  end
71
71
 
72
72
  # Returns a list of sources filenames.
@@ -81,7 +81,7 @@ module Jsus
81
81
  end
82
82
 
83
83
  # Returns an array of provided tags names including those provided by linked external dependencies.
84
- def provides_names
84
+ def provides_names
85
85
  source_files.map {|s| s.provides_names(:short => true) }.flatten |
86
86
  linked_external_dependencies.map {|d| d.provides_names }.flatten
87
87
  end
@@ -103,7 +103,7 @@ module Jsus
103
103
  def external_dependencies
104
104
  source_files.map {|s| s.external_dependencies }.flatten
105
105
  end
106
-
106
+
107
107
  # Returns an array of external dependencies' names (including resolved ones).
108
108
  def external_dependencies_names
109
109
  external_dependencies.map {|d| d.name }
@@ -113,7 +113,7 @@ module Jsus
113
113
  def linked_external_dependencies
114
114
  @linked_external_dependencies ||= Container.new
115
115
  end
116
-
116
+
117
117
  # Compiles source files and linked external source files into a given category.
118
118
  def compile(directory = ".")
119
119
  fn = directory ? File.join(directory, filename) : nil
@@ -164,7 +164,7 @@ module Jsus
164
164
  end
165
165
 
166
166
  # Lists the required files for the package.
167
- def required_files
167
+ def required_files
168
168
  source_files.map {|s| s.required_files }.flatten
169
169
  end
170
170
 
@@ -189,7 +189,7 @@ module Jsus
189
189
  end
190
190
 
191
191
  # Private API
192
-
192
+
193
193
  def header=(new_header) # :nodoc:
194
194
  @header = new_header
195
195
  end
@@ -1,10 +1,10 @@
1
1
  module Jsus
2
2
  # Generic exception for 'bad' source files (no yaml header, for example)
3
3
  class BadSourceFileException < Exception; end
4
-
4
+
5
5
  #
6
6
  # SourceFile is a base for any Jsus operation.
7
- #
7
+ #
8
8
  # It contains basic info about source as well as file content.
9
9
  #
10
10
  class SourceFile
@@ -29,7 +29,7 @@ module Jsus
29
29
 
30
30
  #
31
31
  # Initializes a SourceFile given the filename and options
32
- #
32
+ #
33
33
  # options:
34
34
  # * <tt>:pool:</tt> -- an instance of Pool
35
35
  # * <tt>:package:</tt> -- an instance of Package
@@ -38,9 +38,11 @@ module Jsus
38
38
  #
39
39
  def self.from_file(filename, options = {})
40
40
  if File.exists?(filename)
41
- source = File.read(filename)
41
+ source = File.open(filename, 'r:utf-8') {|f| f.read }
42
+ bom = RUBY_VERSION =~ /1.9/ ? "\uFEFF" : "\xEF\xBB\xBF"
43
+ source.gsub!(bom, "")
42
44
  yaml_data = source.match(%r(^/\*\s*(---.*?)\*/)m)
43
- if (yaml_data && yaml_data[1] && header = YAML.load(yaml_data[1]))
45
+ if (yaml_data && yaml_data[1] && header = YAML.load(yaml_data[1]))
44
46
  options[:header] = header
45
47
  options[:relative_filename] = filename
46
48
  options[:filename] = File.expand_path(filename)
@@ -78,7 +80,7 @@ module Jsus
78
80
  header["description"]
79
81
  end
80
82
 
81
- #
83
+ #
82
84
  # Returns an array of dependencies tags. Unordered.
83
85
  #
84
86
  def dependencies
@@ -95,7 +97,7 @@ module Jsus
95
97
  #
96
98
  def dependencies_names(options = {})
97
99
  dependencies.map {|d| d.name(options) }
98
- end
100
+ end
99
101
  alias_method :requires_names, :dependencies_names
100
102
 
101
103
  #
@@ -112,15 +114,15 @@ module Jsus
112
114
  external_dependencies.map {|d| d.name }
113
115
  end
114
116
 
115
- #
117
+ #
116
118
  # Returns an array with provides tags.
117
119
  #
118
120
  def provides
119
121
  @provides
120
122
  end
121
-
122
- #
123
- # Returns an array with provides names.
123
+
124
+ #
125
+ # Returns an array with provides names.
124
126
  # Accepts options:
125
127
  # * <tt>:short:</tt> -- whether provides should not prepend package name
126
128
  # e.g. 'Class' instead of 'Core/Class' when in package 'Core')
@@ -134,13 +136,13 @@ module Jsus
134
136
  def replaces
135
137
  @replaces
136
138
  end
137
-
139
+
138
140
 
139
141
  #
140
142
  # Returns a tag for source file, which this one is an extension for.
141
143
  #
142
144
  # E.g.: file Foo.js in package Core provides ['Class', 'Hash']. File Bar.js in package Bar
143
- # extends 'Core/Class'. That means its contents would be appended to the Foo.js when compiling
145
+ # extends 'Core/Class'. That means its contents would be appended to the Foo.js when compiling
144
146
  # the result.
145
147
  #
146
148
  def extends
@@ -162,7 +164,7 @@ module Jsus
162
164
  @extensions = @extensions.flatten.compact.uniq
163
165
  @extensions
164
166
  end
165
-
167
+
166
168
  def extensions=(new_value) # :nodoc:
167
169
  @extensions = new_value
168
170
  end
@@ -177,14 +179,14 @@ module Jsus
177
179
  end
178
180
 
179
181
  def include_extensions! # :nodoc:
180
- if pool
182
+ if pool
181
183
  provides.each do |p|
182
184
  extensions << pool.lookup_extensions(p)
183
185
  end
184
186
  end
185
187
  end
186
188
 
187
- #
189
+ #
188
190
  # Returns an array of files required by this files including all the filenames for extensions.
189
191
  # SourceFile filename always goes first, all the extensions are unordered.
190
192
  #
@@ -193,7 +195,7 @@ module Jsus
193
195
  [filename, extensions.map {|e| e.filename}].flatten
194
196
  end
195
197
 
196
- #
198
+ #
197
199
  # Returns a hash containing basic info with dependencies/provides tags' names
198
200
  # and description for source file.
199
201
  #
@@ -209,18 +211,26 @@ module Jsus
209
211
  self.to_hash.inspect
210
212
  end
211
213
  # Private API
212
-
214
+
213
215
  def header=(new_header) # :nodoc:
214
216
  @header = new_header
215
217
  # prepare defaults
216
218
  @header["description"] ||= ""
217
219
  # handle tags
218
- @dependencies = [@header["requires"] || []].flatten
219
- @dependencies.map! {|tag_name| Tag.new(tag_name, :package => package) }
220
- @provides = [@header["provides"] || []].flatten
221
- @provides.map! {|tag_name| Tag.new(tag_name, :package => package) }
222
- @extends = (@header["extends"] && !@header["extends"].empty?) ? Tag.new(@header["extends"]) : nil
223
- @replaces = @header["replaces"] ? Tag.new(@header["replaces"]) : nil
220
+ @dependencies = parse_tag_list(Array(@header["requires"]))
221
+ @provides = parse_tag_list(Array(@header["provides"]))
222
+
223
+ @extends = case @header["extends"]
224
+ when Array then Tag.new(@header["extends"][0])
225
+ when String then Tag.new(@header["extends"])
226
+ else nil
227
+ end
228
+
229
+ @replaces = case @header["replaces"]
230
+ when Array then Tag.new(@header["replaces"][0])
231
+ when String then Tag.new(@header["replaces"])
232
+ else nil
233
+ end
224
234
  end
225
235
 
226
236
  def content=(new_value) # :nodoc:
@@ -230,12 +240,30 @@ module Jsus
230
240
  def content # :nodoc:
231
241
  include_extensions
232
242
  [@content, extensions.map {|e| e.content}].flatten.compact.join("\n")
233
- end
234
-
243
+ end
244
+
235
245
  def original_content # :nodoc:
236
246
  @content
237
247
  end
238
248
 
249
+ def parse_tag_list(tag_list)
250
+ tag_list.map do |tag_name|
251
+ case tag_name
252
+ when String
253
+ Tag.new(tag_name, :package => package)
254
+ when Hash
255
+ tags = []
256
+ tag_name.each do |pkg_name, sources|
257
+ normalized_package_name = pkg_name.sub(/(.+)\/.*$/, "\\1")
258
+ Array(sources).each do |source|
259
+ tags << Tag.new([normalized_package_name, source].join("/"))
260
+ end
261
+ end
262
+ tags
263
+ end
264
+ end.flatten
265
+ end # parse_tag_list
266
+
239
267
  # Assigns an instance of Jsus::Pool to the source file.
240
268
  # Also performs push to that pool.
241
269
  def pool=(new_value)
@@ -247,17 +275,17 @@ module Jsus
247
275
  def pool
248
276
  @pool
249
277
  end
250
-
278
+
251
279
  def ==(other) # :nodoc:
252
280
  eql?(other)
253
281
  end
254
-
282
+
255
283
  def eql?(other) # :nodoc:
256
284
  other.kind_of?(SourceFile) && filename == other.filename
257
285
  end
258
-
286
+
259
287
  def hash
260
288
  [self.class, filename].hash
261
289
  end
262
290
  end
263
- end
291
+ end
data/lib/jsus/tag.rb CHANGED
@@ -2,15 +2,15 @@ module Jsus
2
2
  #
3
3
  # Tag is basically just a string that contains a package name and a name for class
4
4
  # (or not necessarily a class) which the given SourceFile provides/requires/extends/replaces.
5
- #
5
+ #
6
6
  class Tag
7
7
  attr_accessor :package, :external # :nodoc:
8
8
 
9
9
  # Constructors
10
-
10
+
11
11
  #
12
12
  # Creates a tag from given name/options.
13
- #
13
+ #
14
14
  # The way it works may seem a bit tricky but actually it parses name/options
15
15
  # combinations in different ways and may be best described by examples:
16
16
  #
@@ -21,8 +21,8 @@ module Jsus
21
21
  # d = Tag.new("Core/Class", :package => core) # :package_name => "Core", :name => "Class", :external => false
22
22
  # mash = Package.new(...) # let's consider its name is 'Mash'
23
23
  # e = Tag.new("Core/Class", :package => mash) # :package_name => "Core", :name => "Class", :external => true
24
- #
25
- # Between all those, tags b,c,d and e are equal, meaning they all use
24
+ #
25
+ # Between all those, tags b,c,d and e are equal, meaning they all use
26
26
  # the same spot in Hash or whatever else.
27
27
  #
28
28
  def initialize(name, options = {})
@@ -60,7 +60,7 @@ module Jsus
60
60
  # * +:short:+ -- whether the tag should try using short form
61
61
  #
62
62
  # Important note: only non-external tags support short forms.
63
- #
63
+ #
64
64
  # Tag.new('Core/Class').name(:short => true) # => 'Core/Class'
65
65
  # core = Package.new(...) # let's consider its name is 'Core'
66
66
  # Tag.new('Core/Class', :package => core).name(:short => true) # => 'Class'
@@ -91,9 +91,9 @@ module Jsus
91
91
  super
92
92
  end
93
93
  end
94
-
94
+
95
95
  # Private API
96
-
96
+
97
97
  def self.normalize_name_and_options(name, options = {}) # :nodoc:
98
98
  result = {}
99
99
  name.gsub!(%r(^(\.)?/), "")
@@ -108,6 +108,7 @@ module Jsus
108
108
  end
109
109
  result[:name] = name
110
110
  end
111
+ result[:package_name] = normalize_package_name(result[:package_name]) if result[:package_name]
111
112
  result
112
113
  end
113
114
 
@@ -118,7 +119,14 @@ module Jsus
118
119
  def self.name_and_options_to_full_name(name, options = {}) # :nodoc:
119
120
  normalized_options_to_full_name(normalize_name_and_options(name, options))
120
121
  end
121
-
122
+
123
+ def self.normalize_package_name(name) # :nodoc:
124
+ package_chunks = name.split("/")
125
+ package_chunks.map do |pc|
126
+ Jsus::Util::Inflection.random_case_to_mixed_case(pc)
127
+ end.join("/")
128
+ end # normalize_name
129
+
122
130
  def package_name=(new_value) # :nodoc:
123
131
  @package_name = new_value
124
132
  end
@@ -137,6 +145,6 @@ module Jsus
137
145
 
138
146
  def inspect # :nodoc
139
147
  "<Jsus::Tag: #{name}>"
140
- end
148
+ end
141
149
  end
142
150
  end
@@ -0,0 +1,57 @@
1
+ require 'fileutils'
2
+ module Jsus
3
+ module Util
4
+ #
5
+ # Simple file cache manager.
6
+ #
7
+ class FileCache
8
+ # Initializes filecache to given directory
9
+ def initialize(path)
10
+ @path = path
11
+ end # initialize
12
+
13
+ # Creates a file with given value for given key in cache directory
14
+ #
15
+ # Returns actual path for stored file.
16
+ def write(key, value)
17
+ item_path = generate_path(key)
18
+ FileUtils.mkdir_p(File.dirname(item_path))
19
+ File.open(item_path, 'w+') {|f| f.write(value) }
20
+ item_path
21
+ end # write
22
+
23
+ # If file exists for given cache key, returns path to that file.
24
+ # If file doesn't exist, returns nil.
25
+ def read(key)
26
+ item_path = generate_path(key)
27
+ File.exists?(item_path) ? item_path : nil
28
+ end # read
29
+ alias_method :exists?, :read
30
+
31
+ # If file with given key exists, returns path to it.
32
+ # Otherwise, writes value of yielded block.
33
+ def fetch(key, &block)
34
+ read(key) || write(key, yield)
35
+ end # fetch
36
+
37
+ # Deletes cache entry for given key.
38
+ def delete(key)
39
+ item_path = generate_path(key)
40
+ if File.exists?(item_path)
41
+ FileUtils.rm_f(item_path)
42
+ end
43
+ end # delete
44
+
45
+ protected
46
+
47
+ # Generates path by cache key.
48
+ #
49
+ # Default strategy: append key to cache directory
50
+ # (slashes are replaced with dots)
51
+ def generate_path(key)
52
+ key = key.gsub(File::SEPARATOR, ".")
53
+ File.join(@path, key)
54
+ end # generate_path
55
+ end # class FileCache
56
+ end # module Util
57
+ end # module Jsus
@@ -0,0 +1,39 @@
1
+ module Jsus
2
+ module Util
3
+ # Various inflection helpers
4
+ module Inflection
5
+ class <<self
6
+ # Converts strings with various punctuation to pascal case
7
+ # hello_world => HelloWorld
8
+ # Oh.My.God => OhMyGod
9
+ # iAmCamelCase => IAmCamelCase
10
+ # some_Weird_._punctuation => SomeWeirdPunctuation
11
+ def random_case_to_mixed_case(string)
12
+ string.split(/[^a-zA-Z]+/).map {|chunk| capitalize(chunk) }.join
13
+ end # random_case_to_mixed_case
14
+
15
+ # Same as #random_case_to_mixed_case, but preserves dots
16
+ # color.fx => Color.Fx
17
+ def random_case_to_mixed_case_preserve_dots(string)
18
+ string.split(".").map {|c| random_case_to_mixed_case(c) }.join(".")
19
+ end # random_case_to_mixed_case
20
+
21
+ # Capitalizes first letter (doesn't do anything else to other letters, unlike String#capitalize)
22
+ def capitalize(string)
23
+ string[0,1].capitalize + string[1..-1].to_s
24
+ end # capitalize
25
+
26
+ # Downcases first letter
27
+ def decapitalize(string)
28
+ string[0,1].downcase + string[1..-1].to_s
29
+ end # decapitalize
30
+
31
+ # Translates MixedCase string to camel-case
32
+ def snake_case(string)
33
+ decapitalize(string.gsub(/(.)([A-Z])([a-z]+)/) {|_| "#{$1}_#{$2.downcase}#{$3}"}.
34
+ gsub(/[^A-Za-z_]+/, "_"))
35
+ end # snake_case
36
+ end # class <<self
37
+ end # module Inflection
38
+ end # module Util
39
+ end # module Jsus
data/lib/jsus/util.rb CHANGED
@@ -3,5 +3,7 @@ module Jsus
3
3
  autoload :Tree, 'jsus/util/tree'
4
4
  autoload :Documenter, 'jsus/util/documenter'
5
5
  autoload :Validator, 'jsus/util/validator'
6
+ autoload :Inflection, 'jsus/util/inflection'
7
+ autoload :FileCache, 'jsus/util/file_cache'
6
8
  end # Util
7
9
  end # Jsus
data/lib/jsus.rb CHANGED
@@ -24,6 +24,8 @@ module Jsus
24
24
  autoload :Packager, 'jsus/packager'
25
25
  autoload :Pool, 'jsus/pool'
26
26
  autoload :Util, 'jsus/util'
27
+ autoload :Middleware, 'jsus/middleware'
28
+
27
29
  # Returns whether or not jsus is in verbose mode
28
30
  def self.verbose?
29
31
  !!@verbose
@@ -0,0 +1,16 @@
1
+ /*
2
+ ---
3
+
4
+ script: Core.js
5
+
6
+ description: Mootools fake core
7
+
8
+ license: MIT-style license
9
+
10
+ authors:
11
+ - Valerio Proietti
12
+
13
+ provides: [Core]
14
+
15
+ ...
16
+ */
@@ -0,0 +1,8 @@
1
+ name: Mootools
2
+ filename: mootools.js
3
+ web: http://mootools.net
4
+ description: Fake mootools package
5
+ license: Public Domain, http://unlicense.org/UNLICENSE
6
+ authors: mootools authors
7
+ sources:
8
+ - "Source/Core.js"