jim 0.2.3 → 0.3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/Gemfile +2 -1
  2. data/Gemfile.lock +2 -0
  3. data/HISTORY +13 -0
  4. data/README.md +148 -0
  5. data/Rakefile +6 -3
  6. data/bin/jim +1 -2
  7. data/default +0 -0
  8. data/jim.gemspec +142 -105
  9. data/lib/jim.rb +1 -1
  10. data/lib/jim/bundler.rb +168 -73
  11. data/lib/jim/cli.rb +200 -151
  12. data/lib/jim/index.rb +20 -9
  13. data/lib/jim/installer.rb +46 -46
  14. data/lib/jim/rack.rb +57 -20
  15. data/lib/jim/templates/jimfile +11 -5
  16. data/lib/jim/version_parser.rb +3 -3
  17. data/test/fixtures/infoincomments.js +1 -1
  18. data/test/fixtures/jimfile +14 -7
  19. data/test/fixtures/jquery-1.4.1.js +3 -6057
  20. data/test/fixtures/jquery.color.js +1 -1
  21. data/test/fixtures/localfile.js +1 -1
  22. data/test/fixtures/mustache.js/package.json +1 -1
  23. data/test/fixtures/noversion.js +1 -1
  24. data/test/fixtures/old_jimfile +7 -0
  25. data/test/fixtures/sammy-0.5.0/examples/backend/app.rb +4 -4
  26. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/app.js +18 -18
  27. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.cloudkit.js +1 -1
  28. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.js +1 -1
  29. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/sammy.js +161 -161
  30. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task.html.erb +1 -1
  31. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task_details.html.erb +1 -1
  32. data/test/fixtures/sammy-0.5.0/examples/backend/views/app.sass +6 -6
  33. data/test/fixtures/sammy-0.5.0/examples/backend/views/index.haml +5 -5
  34. data/test/fixtures/sammy-0.5.0/examples/form_handling/index.html +16 -16
  35. data/test/fixtures/sammy-0.5.0/examples/hello_world/index.html +13 -13
  36. data/test/fixtures/sammy-0.5.0/examples/location_override/data.html +28 -28
  37. data/test/fixtures/sammy-0.5.0/examples/location_override/index.html +18 -18
  38. data/test/fixtures/sammy-0.5.0/examples/location_override/test.html +36 -36
  39. data/test/fixtures/sammy-0.5.0/lib/min/sammy-0.5.0.min.js +1 -1
  40. data/test/fixtures/sammy-0.5.0/lib/min/sammy-lastest.min.js +1 -1
  41. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.cache.js +13 -13
  42. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.haml.js +2 -2
  43. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.json.js +15 -15
  44. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.mustache.js +46 -46
  45. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.nested_params.js +29 -29
  46. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.storage.js +54 -54
  47. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.template.js +17 -17
  48. data/test/fixtures/sammy-0.5.0/lib/sammy.js +220 -220
  49. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.html +1 -1
  50. data/test/fixtures/sammy-0.5.0/test/index.html +26 -26
  51. data/test/fixtures/sammy-0.5.0/test/test_sammy_application.js +60 -60
  52. data/test/fixtures/sammy-0.5.0/test/test_sammy_event_context.js +21 -21
  53. data/test/fixtures/sammy-0.5.0/test/test_sammy_location_proxy.js +3 -3
  54. data/test/fixtures/sammy-0.5.0/test/test_sammy_plugins.js +17 -17
  55. data/test/fixtures/sammy-0.5.0/test/test_sammy_storage.js +4 -4
  56. data/test/helper.rb +15 -0
  57. data/test/test_jim_bundler.rb +114 -74
  58. data/test/test_jim_cli.rb +34 -18
  59. data/test/test_jim_index.rb +19 -19
  60. data/test/test_jim_installer.rb +13 -13
  61. data/test/test_jim_rack.rb +41 -0
  62. data/test/test_jim_version_parser.rb +4 -4
  63. metadata +204 -41
  64. data/.gitignore +0 -24
  65. data/README.rdoc +0 -105
  66. data/lib/jim/templates/commands +0 -58
data/lib/jim/index.rb CHANGED
@@ -2,16 +2,21 @@ module Jim
2
2
  # Index managages a list of directories which are searched to find requirements
3
3
  class Index
4
4
  attr_reader :directories
5
-
5
+
6
+ # Initialize an Index with a list of directories. The firse directory
7
+ # is assumed to be the JIMHOME
6
8
  def initialize(*directories)
7
9
  @directories = [directories].flatten.compact
8
10
  @jimhome_re = /#{Pathname.new(@directories.first).expand_path.to_s}/
9
11
  end
10
12
 
13
+ # Add a directory to the index
11
14
  def add(directory)
12
15
  @directories.unshift directory
13
16
  end
14
-
17
+
18
+ # List all available files in the directories or only those matching `search`.
19
+ # Returns a sorted array of arrays.
15
20
  def list(search = nil)
16
21
  list = {}
17
22
  each_file_in_index('.js') do |filename|
@@ -33,9 +38,12 @@ module Jim
33
38
  list.sort
34
39
  end
35
40
 
41
+ # Find a file in the index by `name` and an optional `version`.
42
+ # If found, returns a `Pathname` where the file can be retrieved.
36
43
  def find(name, version = nil)
37
44
  name = Pathname.new(name)
38
45
  stem = name.basename
46
+ version = version && version.strip != '' ? version.strip : nil
39
47
  ext = '.js'
40
48
  possible_paths = if version
41
49
  [
@@ -60,20 +68,23 @@ module Jim
60
68
  end
61
69
  final
62
70
  end
63
-
64
- def in_jimhome?(path)
65
- !!(path.to_s =~ @jimhome_re)
66
- end
67
-
71
+
72
+ # Find _all_ paths matching `name` and `version`. Returning an array.
68
73
  def find_all(name, version = nil)
69
74
  matched = []
70
75
  find(name, version) {|p| matched << p }
71
76
  matched
72
77
  end
73
-
78
+
79
+ # Is this path in the JIMHOME
80
+ def in_jimhome?(path)
81
+ !!(path.to_s =~ @jimhome_re)
82
+ end
83
+
84
+ # Iterate through every file in the index yielding the path to the block
74
85
  def each_file_in_index(ext, &block)
75
86
  Jim.each_path_in_directories(@directories, ext, [], &block)
76
87
  end
77
88
 
78
89
  end
79
- end
90
+ end
data/lib/jim/installer.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  module Jim
2
- # Installer is the workhorse of Jim. It handles taking an install path
3
- # (a url, a local path, anything that Downlow.get can handle), staging it
4
- # into a temporary directory and extracting the file(s) into a path for the
5
- # specific name and version of the lib. names and versions are determined
6
- # automatically or can be passed in as options.
2
+ # Installer is the workhorse of Jim. It handles taking an install path
3
+ # (a url, a local path, anything that Downlow.get can handle), staging it
4
+ # into a temporary directory and extracting the file(s) into a path for the
5
+ # specific name and version of the lib. names and versions are determined
6
+ # automatically or can be passed in as options.
7
7
  class Installer
8
-
8
+
9
9
  IGNORE_DIRS = %w{
10
10
  vendor
11
11
  external
@@ -19,113 +19,113 @@ module Jim
19
19
  \_([^\/]+)
20
20
  \.([^\/]+)
21
21
  }
22
-
23
- # get the tmp_root where files are staged
22
+
23
+ # Get the tmp_root where files are staged
24
24
  def self.tmp_root
25
25
  @tmp_root ||= Pathname.new('/tmp/jim')
26
26
  end
27
-
28
- # set the tmp_root where files are staged. Default: '/tmp/jim'
27
+
28
+ # Set the tmp_root where files are staged. Default: '/tmp/jim'
29
29
  def self.tmp_root=(new_tmp_root)
30
30
  @tmp_root = Pathname.new(new_tmp_root)
31
31
  end
32
-
32
+
33
33
  attr_reader :fetch_path, :install_path, :options, :fetched_path, :name, :version, :package_json
34
-
35
- # create an installer. fetch_path is anything that Downlow can understand.
36
- # install path is the final directory
34
+
35
+ # Create an installer. fetch_path is anything that Downlow can understand.
36
+ # Install path is the final directory
37
37
  def initialize(fetch_path, install_path, options = {})
38
38
  @fetch_path = Pathname.new(fetch_path)
39
39
  @install_path = Pathname.new(install_path)
40
40
  @options = options
41
41
  end
42
42
 
43
- # fetch the file at fetch_path with and stage into a tmp directory.
44
- # returns the staged directory of fetched file(s).
43
+ # Fetch the file at fetch_path with and stage into a tmp directory.
44
+ # Returns the staged directory of fetched file(s).
45
45
  def fetch
46
- logger.info "fetching #{fetch_path}"
46
+ logger.info "Fetching #{fetch_path}"
47
47
  @fetched_path = Downlow.get(fetch_path, tmp_path, :tmp_dir => tmp_root)
48
- logger.debug "fetched #{@fetched_path}"
48
+ logger.debug "Fetched #{@fetched_path}"
49
49
  @fetched_path
50
50
  end
51
51
 
52
- # fetch and install the files determining their name and version if not provided.
53
- # if the fetch_path contains a directory of files, it itterates over the directory
52
+ # Fetch and install the files determining their name and version if not provided.
53
+ # If the fetch_path contains a directory of files, it iterates over the directory
54
54
  # installing each file that isn't in IGNORE_DIRS and a name and version can be
55
55
  # determined for. It also installs a package.json file along side the JS file
56
56
  # that contains meta data including the name and version, also merging with the
57
57
  # original package.json if found.
58
- #
58
+ #
59
59
  # If options[:shallow] == true it will just copy the single file without any leading
60
60
  # directories or a package.json. 'shallow' installation is used for Bundle#vendor
61
61
  def install
62
62
  fetch
63
63
  parse_package_json
64
64
  determine_name_and_version
65
-
65
+
66
66
  if !name || name.to_s =~ /^\s*$/ # blank
67
- raise(Jim::InstallError, "could not determine name for #{@fetched_path}")
67
+ raise(Jim::InstallError, "Could not determine name for #{@fetched_path}")
68
68
  end
69
-
70
- logger.info "installing #{name} #{version}"
69
+
70
+ logger.info "Installing #{name} #{version}"
71
71
  logger.debug "fetched_path #{@fetched_path}"
72
-
72
+
73
73
  if options[:shallow]
74
74
  shallow_filename = [name, (version == "0" ? nil : version)].compact.join('-')
75
75
  final_path = install_path + "#{shallow_filename}#{fetched_path.extname}"
76
76
  else
77
77
  final_path = install_path + 'lib' + "#{name}-#{version}" + "#{name}.js"
78
78
  end
79
-
79
+
80
80
  if @fetched_path.directory?
81
81
  # install every js file
82
82
  installed_paths = []
83
83
  sub_options = options.merge({
84
- :name => nil,
84
+ :name => nil,
85
85
  :version => nil,
86
- :parent_version => version,
86
+ :parent_version => version,
87
87
  :package_json => package_json.merge("name" => nil)
88
88
  })
89
89
  Jim.each_path_in_directories([@fetched_path], '.js', IGNORE_DIRS) do |subfile|
90
- logger.info "found file #{subfile}"
90
+ logger.info "Found file #{subfile}"
91
91
  installed_paths << Jim::Installer.new(subfile, install_path, sub_options).install
92
92
  end
93
- logger.info "extracted to #{install_path}, #{installed_paths.length} file(s)"
93
+ logger.info "Extracted to #{install_path}, #{installed_paths.length} file(s)"
94
94
  return installed_paths
95
95
  end
96
-
97
- logger.debug "installing to #{final_path}"
98
- if final_path.exist?
96
+
97
+ logger.debug "Installing to #{final_path}"
98
+ if final_path.exist?
99
99
  logger.debug "#{final_path} already exists"
100
100
  if options[:force]
101
101
  FileUtils.rm_rf(final_path)
102
102
  elsif Digest::MD5.hexdigest(File.read(final_path)) == Digest::MD5.hexdigest(File.read(@fetched_path))
103
- logger.info "duplicate file, skipping"
103
+ logger.info "Duplicate file, skipping"
104
104
  return final_path
105
105
  else
106
106
  raise(Jim::FileExists.new(final_path))
107
107
  end
108
108
  end
109
-
109
+
110
110
  Downlow.extract(@fetched_path, :destination => final_path, :tmp_dir => tmp_root)
111
111
  # install json
112
112
  install_package_json(final_path.dirname + 'package.json') if !options[:shallow]
113
113
  installed = final_path.directory? ? Dir.glob(final_path + '**/*').length : 1
114
- logger.info "extracted to #{final_path}, #{installed} file(s)"
114
+ logger.info "Extracted to #{final_path}, #{installed} file(s)"
115
115
  final_path
116
116
  ensure
117
117
  FileUtils.rm_rf(@fetched_path) if @fetched_path && @fetched_path.exist?
118
118
  final_path
119
119
  end
120
-
121
- # determine the name and version of the @fetched_path. Tries a number of
120
+
121
+ # Determine the name and version of the @fetched_path. Tries a number of
122
122
  # strategies in order until both name and version are found:
123
123
  #
124
124
  # * from options (options[:name] ...)
125
125
  # * from comments (// name: )
126
126
  # * from a package.json ({"name": })
127
127
  # * from the filename (name-1.0.js)
128
- #
128
+ #
129
129
  # If no version can be found, version is set as "0"
130
130
  def determine_name_and_version
131
131
  (name && version) ||
@@ -138,7 +138,7 @@ module Jim
138
138
 
139
139
  private
140
140
  def tmp_root
141
- @tmp_root ||= make_tmp_root
141
+ @tmp_root ||= make_tmp_root
142
142
  end
143
143
 
144
144
  def tmp_dir
@@ -152,17 +152,17 @@ module Jim
152
152
  def logger
153
153
  Jim.logger
154
154
  end
155
-
155
+
156
156
  def make_tmp_root
157
157
  self.class.tmp_root + (Time.now.to_i + rand(10000)).to_s
158
158
  end
159
-
159
+
160
160
  def make_tmp_dir
161
161
  dir = tmp_root + fetch_path.stem
162
162
  dir.mkpath
163
163
  dir
164
164
  end
165
-
165
+
166
166
  def parse_package_json
167
167
  @package_json = @options[:package_json] || {}
168
168
  package_json_path = if fetched_path.directory?
@@ -180,7 +180,7 @@ module Jim
180
180
 
181
181
  def install_package_json(to_path, options = {})
182
182
  hash = @package_json.merge({
183
- "name" => name,
183
+ "name" => name,
184
184
  "version" => version,
185
185
  "install" => {
186
186
  "at" => Time.now.httpdate,
@@ -235,4 +235,4 @@ module Jim
235
235
  end
236
236
 
237
237
  end
238
- end
238
+ end
data/lib/jim/rack.rb CHANGED
@@ -2,51 +2,88 @@ require 'jim'
2
2
 
3
3
  module Jim
4
4
  # Jim::Rack is a Rack middleware for allowing live bundling and compression
5
- # of the requirements in your Jimfile without having to rebundle using the command
5
+ # of the bunldes in your Jimfile without having to rebundle using the command
6
6
  # line. You can specify a number of options:
7
7
  #
8
8
  # :jimfile: Path to your Jimfile (default ./Jimfile)
9
9
  # :jimhome: Path to your JIMHOME directory (default ENV['JIMHOME'] or ~/.jim)
10
- # :bundled_uri: URI to serve the bundled requirements
11
- # :compressed_uri: URI to serve the compressed requirements
10
+ # :bundle_uri: URI to serve the bundled requirements (default '/javascripts/')
11
+ #
12
+ # The `bundle_uri` should be ~ a directory and a bundle can be generated by
13
+ # requesting the bundlename.js behind the directory. For example, given a Jimfile
14
+ # like:
15
+ #
16
+ # {
17
+ # "bundles": {
18
+ # "default": [
19
+ # "jquery",
20
+ # "jquery.color",
21
+ # ["sammy", "0.6.3"]
22
+ # ]
23
+ # }
24
+ # }
25
+ #
26
+ # You could get the 'default' bundle by
27
+ #
28
+ # GET /javascripts/default.js
29
+ #
30
+ # Or the compressed version with:
31
+ #
32
+ # GET /javascripts/default.min.js
33
+ #
12
34
  class Rack
13
-
35
+
14
36
  def initialize(app, options = {})
15
37
  @app = app
16
38
  jimfile = Pathname.new(options[:jimfile] || 'Jimfile')
17
39
  jimhome = Pathname.new(options[:jimhome] || ENV['JIMHOME'] || '~/.jim').expand_path
18
40
  @bundler = Jim::Bundler.new(jimfile, Jim::Index.new(jimhome), options)
19
- @bundled_uri = options[:bundled_uri] || @bundler.options[:bundled_path]
20
- @compressed_uri = options[:compressed_uri] || @bundler.options[:compressed_path]
41
+ # unset the bundlers bundle dir so it returns a string
42
+ @bundler.bundle_dir = nil
43
+ @bundle_uri = options[:bundle_uri] || '/javascripts/'
21
44
  end
22
-
45
+
23
46
  def call(env)
24
47
  dup._call(env)
25
48
  end
26
-
49
+
27
50
  def _call(env)
28
51
  uri = env['PATH_INFO']
29
- if uri == @bundled_uri
30
- run_action(:bundle!)
31
- elsif uri == @compressed_uri
32
- run_action(:compress!)
52
+ if uri =~ bundle_matcher
53
+ name = $1
54
+ if name =~ compressed_matcher
55
+ run_action(:compress!, name.gsub(compressed_matcher, ''))
56
+ else
57
+ run_action(:bundle!, name)
58
+ end
33
59
  else
34
60
  @app.call(env)
35
61
  end
36
62
  end
37
-
38
- def run_action(which)
63
+
64
+ private
65
+ def bundle_matcher
66
+ @bundle_matcher ||= /^#{@bundle_uri}([\w\d\-\.]+)\.js$/
67
+ end
68
+
69
+ def compressed_matcher
70
+ @compressed_matcher ||= /#{@bundler.options[:compressed_suffix]}$/
71
+ end
72
+
73
+ def run_action(action, *args)
39
74
  begin
40
- [200, {'Content-Type' => 'text/javascript'}, @bundler.send(which, false)]
75
+ [200, {
76
+ 'Content-Type' => 'text/javascript'
77
+ }, [@bundler.send(action , *args)]]
41
78
  rescue => e
42
- [500, {'Content-Type' => 'text/html'}, <<-EOT
43
- <p>Jim failed in helping you out. There was an error when trying to #{which}.</p>
79
+ response = <<-EOT
80
+ <p>Jim failed in helping you out. There was an error when trying to run #{action}(#{args}).</p>
44
81
  <p>#{e}</p>
45
82
  <pre>#{e.backtrace}</pre>
46
83
  EOT
47
- ]
84
+ [500, {'Content-Type' => 'text/html'}, [response]]
48
85
  end
49
86
  end
50
-
87
+
51
88
  end
52
- end
89
+ end
@@ -1,6 +1,12 @@
1
- // bundled_path: public/javascripts/bundled.js
2
- // compressed_path: public/javascripts/compressed.js
3
- // vendor_dir: public/javascripts/vendor
4
-
5
- / start adding your requirements below:
1
+ {
2
+ "bundle_dir": "public/javascripts/",
3
+ "vendor_dir": "public/javascripts/vendor",
4
+ "bundles": {
5
+ /*
6
+ "default": [
7
+ "jquery"
8
+ ]
9
+ */
10
+ }
11
+ }
6
12
 
@@ -8,9 +8,9 @@ module Jim
8
8
  extension = f.scan(/\.[^\.\d\s\-\_][^\.]*$/)[0]
9
9
  if NOT_EXTENSIONS.include?(extension)
10
10
  extension = nil
11
- else
11
+ else
12
12
  f.gsub!(/#{extension}$/, '')
13
- end
13
+ end
14
14
 
15
15
  name, after_name, delimiter, version = f.scan(/^([a-z\.\-\_]+)(([\.\-\_\s])v?(([\w\d]{6,7})|(\d[\d\w\.]*)))?$/i)[0]
16
16
  [name || f, version || "0"]
@@ -23,4 +23,4 @@ module Jim
23
23
 
24
24
 
25
25
  end
26
- end
26
+ end
@@ -1,4 +1,4 @@
1
1
  // This file has its info in the comments
2
2
  // name: myproject
3
3
  // version: 1.2.2
4
- (function() {});
4
+ (function() {});
@@ -1,7 +1,14 @@
1
- // bundled_path: test/tmp/public/javascripts/bundled.js
2
- // compressed_path: test/tmp/public/javascripts/compressed.js
3
- // vendor_dir: test/tmp/public/javascripts/vendor
4
-
5
- jquery 1.4.1
6
- myproject
7
- localfile
1
+ {
2
+ "bundle_dir": "test/tmp/",
3
+ "vendor_dir": "test/tmp/public/javascripts/vendor",
4
+ "bundles": {
5
+ "default": [
6
+ ["jquery", "1.4.1"],
7
+ "myproject",
8
+ "localfile"
9
+ ],
10
+ "base": [
11
+ "jquery"
12
+ ]
13
+ }
14
+ }