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.
- data/Gemfile +2 -1
- data/Gemfile.lock +2 -0
- data/HISTORY +13 -0
- data/README.md +148 -0
- data/Rakefile +6 -3
- data/bin/jim +1 -2
- data/default +0 -0
- data/jim.gemspec +142 -105
- data/lib/jim.rb +1 -1
- data/lib/jim/bundler.rb +168 -73
- data/lib/jim/cli.rb +200 -151
- data/lib/jim/index.rb +20 -9
- data/lib/jim/installer.rb +46 -46
- data/lib/jim/rack.rb +57 -20
- data/lib/jim/templates/jimfile +11 -5
- data/lib/jim/version_parser.rb +3 -3
- data/test/fixtures/infoincomments.js +1 -1
- data/test/fixtures/jimfile +14 -7
- data/test/fixtures/jquery-1.4.1.js +3 -6057
- data/test/fixtures/jquery.color.js +1 -1
- data/test/fixtures/localfile.js +1 -1
- data/test/fixtures/mustache.js/package.json +1 -1
- data/test/fixtures/noversion.js +1 -1
- data/test/fixtures/old_jimfile +7 -0
- data/test/fixtures/sammy-0.5.0/examples/backend/app.rb +4 -4
- data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/app.js +18 -18
- data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.cloudkit.js +1 -1
- data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.js +1 -1
- data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/sammy.js +161 -161
- data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task.html.erb +1 -1
- data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task_details.html.erb +1 -1
- data/test/fixtures/sammy-0.5.0/examples/backend/views/app.sass +6 -6
- data/test/fixtures/sammy-0.5.0/examples/backend/views/index.haml +5 -5
- data/test/fixtures/sammy-0.5.0/examples/form_handling/index.html +16 -16
- data/test/fixtures/sammy-0.5.0/examples/hello_world/index.html +13 -13
- data/test/fixtures/sammy-0.5.0/examples/location_override/data.html +28 -28
- data/test/fixtures/sammy-0.5.0/examples/location_override/index.html +18 -18
- data/test/fixtures/sammy-0.5.0/examples/location_override/test.html +36 -36
- data/test/fixtures/sammy-0.5.0/lib/min/sammy-0.5.0.min.js +1 -1
- data/test/fixtures/sammy-0.5.0/lib/min/sammy-lastest.min.js +1 -1
- data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.cache.js +13 -13
- data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.haml.js +2 -2
- data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.json.js +15 -15
- data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.mustache.js +46 -46
- data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.nested_params.js +29 -29
- data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.storage.js +54 -54
- data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.template.js +17 -17
- data/test/fixtures/sammy-0.5.0/lib/sammy.js +220 -220
- data/test/fixtures/sammy-0.5.0/test/fixtures/partial.html +1 -1
- data/test/fixtures/sammy-0.5.0/test/index.html +26 -26
- data/test/fixtures/sammy-0.5.0/test/test_sammy_application.js +60 -60
- data/test/fixtures/sammy-0.5.0/test/test_sammy_event_context.js +21 -21
- data/test/fixtures/sammy-0.5.0/test/test_sammy_location_proxy.js +3 -3
- data/test/fixtures/sammy-0.5.0/test/test_sammy_plugins.js +17 -17
- data/test/fixtures/sammy-0.5.0/test/test_sammy_storage.js +4 -4
- data/test/helper.rb +15 -0
- data/test/test_jim_bundler.rb +114 -74
- data/test/test_jim_cli.rb +34 -18
- data/test/test_jim_index.rb +19 -19
- data/test/test_jim_installer.rb +13 -13
- data/test/test_jim_rack.rb +41 -0
- data/test/test_jim_version_parser.rb +4 -4
- metadata +204 -41
- data/.gitignore +0 -24
- data/README.rdoc +0 -105
- 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
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
36
|
-
#
|
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
|
-
#
|
44
|
-
#
|
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 "
|
46
|
+
logger.info "Fetching #{fetch_path}"
|
47
47
|
@fetched_path = Downlow.get(fetch_path, tmp_path, :tmp_dir => tmp_root)
|
48
|
-
logger.debug "
|
48
|
+
logger.debug "Fetched #{@fetched_path}"
|
49
49
|
@fetched_path
|
50
50
|
end
|
51
51
|
|
52
|
-
#
|
53
|
-
#
|
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, "
|
67
|
+
raise(Jim::InstallError, "Could not determine name for #{@fetched_path}")
|
68
68
|
end
|
69
|
-
|
70
|
-
logger.info "
|
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 "
|
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 "
|
93
|
+
logger.info "Extracted to #{install_path}, #{installed_paths.length} file(s)"
|
94
94
|
return installed_paths
|
95
95
|
end
|
96
|
-
|
97
|
-
logger.debug "
|
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 "
|
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 "
|
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
|
-
#
|
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
|
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
|
-
# :
|
11
|
-
#
|
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
|
-
|
20
|
-
@
|
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
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
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, {
|
75
|
+
[200, {
|
76
|
+
'Content-Type' => 'text/javascript'
|
77
|
+
}, [@bundler.send(action , *args)]]
|
41
78
|
rescue => e
|
42
|
-
|
43
|
-
<p>Jim failed in helping you out. There was an error when trying to #{
|
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
|
data/lib/jim/templates/jimfile
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
|
data/lib/jim/version_parser.rb
CHANGED
@@ -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
|
data/test/fixtures/jimfile
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
+
}
|