jsus 0.2.7 → 0.3.0

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