paste 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +0,0 @@
1
- module Paste
2
- module CSS
3
- class Base < Glue
4
- end
5
- end
6
- end
data/lib/paste/js/base.rb DELETED
@@ -1,26 +0,0 @@
1
- module Paste
2
- module JS
3
- class Base < Glue
4
-
5
- include Cache
6
- include Compress
7
-
8
- def initialize
9
- config.load_path << erb_path
10
- end
11
-
12
- def paste *sources
13
- raise 'Implement me!'
14
- end
15
-
16
- def result_name sources
17
- raise 'Implement me!'
18
- end
19
-
20
- def write_result result
21
- raise 'Implement me!'
22
- end
23
-
24
- end
25
- end
26
- end
@@ -1,111 +0,0 @@
1
- require 'active_support/core_ext/module/synchronization'
2
-
3
- require 'yaml'
4
-
5
- module Paste
6
- module JS
7
- module Cache
8
-
9
- def rebuild
10
- rebuild_if do |result, sources|
11
- needs_update? result
12
- end
13
- end
14
-
15
- def rebuild!
16
- rebuild_if { |r, s| true }
17
- end
18
-
19
- def rebuild_if &blk
20
- render_all_erb
21
- results.each_pair do |result, sources|
22
- begin
23
- if blk.call(result, sources[:sources])
24
- sources[:parser].reset!
25
- write_result result
26
- end
27
- rescue ResolveError
28
- results.delete result
29
- end
30
- end
31
- end
32
-
33
- def register sources, into_hash = nil
34
- into_hash ||= results
35
-
36
- if into_hash[result_name(sources)][:sources] != sources
37
- into_hash[result_name(sources)] = {
38
- :sources => sources,
39
- :parser => config.parser.new(self, sources)
40
- }
41
-
42
- write_cache_to_disk into_hash
43
- end
44
- end
45
-
46
- def registered? sources
47
- results.key? result_name(sources)
48
- end
49
-
50
- def needs_update? result
51
- needs_update_relative_to_sources result do
52
- results[result][:sources]
53
- end
54
- end
55
-
56
- def needs_dependency_update? result
57
- needs_update_relative_to_sources result do
58
- results[result][:parser].js_dependencies
59
- end
60
- end
61
-
62
- def results
63
- return @results if defined?(@results)
64
-
65
- @results = Hash.new { {} }
66
-
67
- begin
68
- cached = YAML.load_file tmp_path(config.cache_file)
69
-
70
- if cached
71
- cached.each do |sources|
72
- register sources, @results
73
- end
74
- end
75
- rescue
76
- end
77
-
78
- @results
79
- end
80
-
81
- @@results_lock = Mutex.new
82
- synchronize :results, :with => :@@results_lock
83
-
84
- protected
85
-
86
- def needs_update_relative_to_sources result
87
- path = destination result
88
- return true unless File.exists?(path) && results.key?(result)
89
-
90
- yield.inject(false) do |prev, source|
91
- prev || File.mtime(path) < File.mtime(find(source))
92
- end
93
- end
94
-
95
- def write_cache_to_disk cache
96
- file = tmp_path config.cache_file
97
- FileUtils.mkdir_p File.dirname(file)
98
-
99
- to_write = []
100
- cache.each do |result, hash|
101
- to_write << hash[:sources]
102
- end
103
-
104
- File.open(file, 'w') do |f|
105
- f << YAML.dump(to_write)
106
- end
107
- end
108
-
109
- end
110
- end
111
- end
@@ -1,55 +0,0 @@
1
- module Paste
2
- module JS
3
- class Chain < Base
4
-
5
- def paste *sources
6
- js_dependencies = []
7
- css_dependencies = []
8
-
9
- sources.each do |source|
10
- name = result_name [source]
11
- if registered? [source]
12
- if needs_update?(name) || needs_dependency_update?(name)
13
- results[name][:parser].reset!
14
- end
15
- else
16
- register [source]
17
- end
18
-
19
- source_deps = results[name][:parser].js_dependencies
20
- js_dependencies = source_deps | js_dependencies
21
- end
22
-
23
- js_dependencies.map! do |d|
24
- result = result_name [d]
25
- register [d] unless registered? [d] # implicit dependencies
26
- write_result result if needs_update?(result)
27
-
28
- css_dependencies = css_dependencies |
29
- results[result][:parser].css_dependencies
30
-
31
- result
32
- end
33
-
34
- {
35
- :javascript => js_dependencies,
36
- :css => css_dependencies
37
- }
38
- end
39
-
40
- def write_result result
41
- file = destination result
42
-
43
- FileUtils.mkdir_p File.dirname(file)
44
- FileUtils.cp find(result), file
45
- end
46
-
47
- def result_name sources
48
- result = sources.first
49
- result += '.js' unless result.end_with?('.js')
50
- result
51
- end
52
-
53
- end
54
- end
55
- end
@@ -1,46 +0,0 @@
1
- require 'closure-compiler'
2
- require 'active_support/core_ext/hash/except'
3
-
4
- module Paste
5
- module JS
6
- module Compress
7
- extend ActiveSupport::Concern
8
-
9
- included do
10
- alias_method_chain :rebuild!, :compression
11
- end
12
-
13
- def rebuild_with_compression! options = {}
14
- rebuild_without_compression!
15
-
16
- results.keys.each do |result|
17
- compress result, options
18
- end
19
- end
20
-
21
- def compress result, options = {}
22
- case options[:compress]
23
- when 'google'
24
- google_compress result, options.except(:compress)
25
- when nil, false
26
- # Compression not asked for
27
- else
28
- raise "Unknown compression technique: #{options[:compress]}"
29
- end
30
- end
31
-
32
- protected
33
-
34
- def google_compress result, options = {}
35
- file, output = destination(result), ''
36
- handle = File.open(file, 'a+')
37
- File.open(file, 'r') do |f|
38
- output = Closure::Compiler.new(options).compile f
39
- end
40
-
41
- File.open(file, 'w+') { |f| f << output.chomp }
42
- end
43
-
44
- end
45
- end
46
- end
@@ -1,55 +0,0 @@
1
- require 'erb'
2
-
3
- module Paste
4
- module JS
5
- module ERBRenderer
6
-
7
- def render_all_erb
8
- erb_sources.each { |s| render_erb s }
9
- end
10
-
11
- def render_erb source
12
- to_generate = erb_path source.sub(/\.erb$/, '')
13
- source = find source
14
-
15
- if !File.exists?(to_generate) ||
16
- File.mtime(source) > File.mtime(to_generate)
17
-
18
- FileUtils.mkdir_p File.dirname(to_generate)
19
- contents = PasteERBHelper.new(File.read(source)).result
20
- File.open(to_generate, 'w') { |f| f << contents }
21
- end
22
- end
23
-
24
- protected
25
-
26
- def erb_sources
27
- sources = load_path.map do |path|
28
- Dir[path + '/**/*.js.erb'].map do |erb|
29
- erb.gsub(path + '/', '')
30
- end
31
- end
32
- sources.flatten
33
- end
34
-
35
- end
36
- end
37
- end
38
-
39
- # This needs to be outside of the module because we don't want to
40
- # force templates to always do ::Rails
41
- class PasteERBHelper < ERB
42
- include ActionView::Helpers if defined?(ActionView::Helpers)
43
-
44
- def config
45
- Rails.application.config.action_controller if defined?(Rails)
46
- end
47
-
48
- def result *args
49
- super binding
50
- end
51
-
52
- def controller
53
- nil
54
- end
55
- end
@@ -1,38 +0,0 @@
1
- require 'digest/sha1'
2
-
3
- module Paste
4
- module JS
5
- class Unify < Base
6
-
7
- def paste *sources
8
- result = result_name sources
9
-
10
- register sources unless registered?(sources)
11
-
12
- if needs_update?(result) || needs_dependency_update?(result)
13
- results[result][:parser].reset!
14
- write_result result
15
- end
16
-
17
- {
18
- :javascript => [result],
19
- :css => results[result][:parser].css_dependencies
20
- }
21
- end
22
-
23
- def write_result result
24
- path = destination result
25
- FileUtils.mkdir_p File.dirname(path)
26
-
27
- results[result][:parser].reset!
28
- results[result][:parser].concatenation.save_to path
29
- end
30
-
31
- def result_name sources
32
- to_digest = sources.map{ |s| s.gsub /\.js$/, '' }.sort.join
33
- Digest::SHA1.hexdigest(to_digest)[0..12] + '.js'
34
- end
35
-
36
- end
37
- end
38
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- shared_examples_for 'a css provider' do
4
- before :each do
5
- Paste::JS::Test.write 'foo', '//= require_css <foo>'
6
- Paste::CSS::Test.write 'foo', ''
7
- end
8
-
9
- it "should require the css" do
10
- result = subject.paste 'foo'
11
- result[:css].should == ['foo']
12
- end
13
-
14
- it "should not require multiple css twice" do
15
- Paste::JS::Test.write 'bar', '//= require_css <foo>'
16
-
17
- subject.paste('foo', 'bar')[:css].should == ['foo']
18
- end
19
- end
20
-
21
- describe 'Providing CSS from javascript' do
22
- describe Paste::JS::Unify do
23
- it_should_behave_like 'a css provider'
24
- end
25
-
26
- describe Paste::JS::Chain do
27
- it_should_behave_like 'a css provider'
28
- end
29
- end
@@ -1,47 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Paste::JS::Unify, 'building cached concatenations' do
4
-
5
- before :each do
6
- Paste::JS::Test.write 'foo', 'foo()'
7
- Paste::JS::Test.write 'bar', 'bar()'
8
- Paste::JS::Test.write 'foo/baz', 'baz()'
9
-
10
- @result = subject.paste('foo', 'bar', 'foo/baz')[:javascript].first
11
- Paste::JS::Test.delete @result
12
- end
13
-
14
- it "should rebuild within the same instance of the unifier" do
15
- subject.rebuild!
16
-
17
- subject.should have_in_result(@result, "foo()\nbar()\nbaz()")
18
- end
19
-
20
- it "should allow another watcher to rebuild it" do
21
- subject = Paste::JS::Unify.new
22
- subject.rebuild!
23
-
24
- subject.should have_in_result(@result, "foo()\nbar()\nbaz()")
25
- end
26
-
27
- it "should rebuild pre-existing results despite modification times" do
28
- # Make the file exist and have the last modified time of the sources
29
- # to be previous to now
30
- subject.paste('foo', 'bar', 'foo/baz')
31
- Paste::JS::Test.write 'foo', 'foo2()', Time.now - 42
32
- Paste::JS::Test.write 'bar', 'bar2()', Time.now - 42
33
- Paste::JS::Test.write 'foo/baz', 'baz2()', Time.now - 42
34
-
35
- subject.rebuild!
36
-
37
- subject.should have_in_result(@result, "foo2()\nbar2()\nbaz2()")
38
- end
39
-
40
- it "should ignore cached results which no longer exist" do
41
- Paste::JS::Test.delete_source 'foo'
42
- Paste::JS::Test.delete_source 'bar'
43
-
44
- subject.rebuild!
45
- subject.destination(@result).should_not exist
46
- end
47
- end
@@ -1,133 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Paste::JS::Chain do
4
- before :each do
5
- Paste::JS::Test.write 'foo', 'foo()'
6
- Paste::JS::Test.write 'bar', 'bar()'
7
- Paste::JS::Test.write 'foo/baz', 'baz()'
8
- end
9
-
10
- it "should return the sources given" do
11
- results = subject.paste('foo', 'bar', 'foo/baz')[:javascript]
12
-
13
- results.sort.should == ['bar.js', 'foo.js', 'foo/baz.js']
14
- end
15
-
16
- it "should generate the concatenation when the destination doesn't exist" do
17
- subject.paste('foo', 'bar', 'foo/baz')
18
-
19
- subject.should have_in_result('foo', 'foo()')
20
- subject.should have_in_result('bar', 'bar()')
21
- subject.should have_in_result('foo/baz', 'baz()')
22
- end
23
-
24
- it "should return the sources with dependencies satisfied" do
25
- Paste::JS::Test.write 'foo', "//= require <foo/bar>\n//= require <bar>"
26
- Paste::JS::Test.write 'bar', '//= require <foo/bar>'
27
- Paste::JS::Test.write 'foo/bar', 'foobar()'
28
-
29
- subject.paste('foo', 'bar', 'foo/bar')[:javascript].should == ['foo/bar.js', 'bar.js', 'foo.js']
30
- end
31
-
32
- it "should raise an exception on circular dependencies" do
33
- Paste::JS::Test.write 'foo', '//= require <bar>'
34
- Paste::JS::Test.write 'bar', '//= require <foo>'
35
-
36
- lambda {
37
- subject.paste('foo', 'bar')
38
- }.should raise_exception(/circular dependency/i)
39
- end
40
-
41
- describe "regenerating files" do
42
- it "should only regenerate modified files" do
43
- subject.paste('foo', 'bar', 'foo/baz')
44
-
45
- Paste::JS::Test.write 'foo', 'foo(foo)', Time.now - 42
46
- Paste::JS::Test.write 'bar', 'bar(bar)', Time.now + 42
47
-
48
- subject.paste('foo', 'bar', 'foo/baz')
49
-
50
- subject.should have_in_result('foo', 'foo()')
51
- subject.should have_in_result('bar', 'bar(bar)')
52
- subject.should have_in_result('foo/baz', 'baz()')
53
- end
54
-
55
- it "should update the results only if the sources have changed" do
56
- subject = described_class.new
57
-
58
- subject.paste('foo')
59
- subject.paste('bar')
60
- Paste::JS::Test.write 'foo', 'foobar()', Time.now - 42
61
- Paste::JS::Test.write 'bar', 'barbar()', Time.now + 42
62
-
63
- subject.rebuild
64
-
65
- subject.should have_in_result('foo', 'foo()')
66
- subject.should have_in_result('bar', 'barbar()')
67
- end
68
-
69
- it "should watch for changes in dependencies as well" do
70
- Paste::JS::Test.write 'foo', '//= require <bar>'
71
- Paste::JS::Test.write 'bar', ''
72
- Paste::JS::Test.write 'baz', ''
73
- subject.paste('foo')
74
-
75
- Paste::JS::Test.write 'bar', '//= require <baz>', Time.now + 42
76
-
77
- subject.paste('foo')[:javascript].should == ['baz.js', 'bar.js', 'foo.js']
78
- end
79
-
80
- it "should watch for changes in dependencies as well" do
81
- Paste::JS::Test.write 'foo', '//= require <bar>'
82
- Paste::JS::Test.write 'bar', ''
83
- Paste::JS::Test.write 'baz', ''
84
- subject.paste('foo')
85
-
86
- Paste::JS::Test.write 'bar', '//= require <baz>', Time.now + 42
87
-
88
- subject.paste('foo')[:javascript].should == ['baz.js', 'bar.js', 'foo.js']
89
- end
90
-
91
- it "should watch for changes in very deep dependencies" do
92
- Paste::JS::Test.write 'foo', ''
93
- Paste::JS::Test.write 'bar', ''
94
- subject.paste('foo')
95
-
96
- Paste::JS::Test.write 'foo', '//= require <bar>', Time.now + 42
97
-
98
- subject.paste('foo')[:javascript].should == ['bar.js', 'foo.js']
99
- end
100
-
101
- it "should update dependencies when they've been rewritten using rebuild" do
102
- Paste::JS::Test.write 'foo', ''
103
- Paste::JS::Test.write 'baz', 'foobar'
104
-
105
- subject.paste('foo')
106
- Paste::JS::Test.write 'foo', '//= require <baz>', Time.now + 42
107
- subject.rebuild
108
- Paste::JS::Test.touch 'foo', Time.now - 1
109
-
110
- @result = subject.paste('foo')[:javascript].should == ['baz.js', 'foo.js']
111
- end
112
- end
113
-
114
- describe "implicit dependencies" do
115
- before :each do
116
- Paste::JS::Test.write 'foo', ''
117
- Paste::JS::Test.write 'bar', '//= require <foo>'
118
- end
119
-
120
- it "should be included when pasting" do
121
- subject.paste('bar')[:javascript].should == ['foo.js', 'bar.js']
122
- end
123
-
124
- it "should be regenerated" do
125
- result = subject.paste('bar')[:javascript].first
126
-
127
- Paste::JS::Test.write 'foo', 'foobar()', Time.now + 42
128
-
129
- subject.paste('bar')
130
- subject.should have_in_result(result, 'foobar()')
131
- end
132
- end
133
- end
@@ -1,43 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Paste::JS::Unify, 'compression' do
4
- before :each do
5
- Paste::JS::Test.write 'foo', "function foo() {};\n foo()"
6
- Paste::JS::Test.write 'bar', "function bar() {};\n bar()"
7
- end
8
-
9
- it "should not compress the files when pasting" do
10
- result = subject.paste('foo')[:javascript].first
11
-
12
- subject.should have_in_result(result, "function foo() {};\n foo()")
13
- end
14
-
15
- it "should compress the previously generated result" do
16
- result = subject.paste('foo', 'bar')[:javascript].first
17
-
18
- begin
19
- subject.rebuild! :compress => 'google'
20
- rescue SocketError
21
- pending 'Error connecting to google'
22
- end
23
-
24
- contents = File.read subject.destination(result)
25
- contents.should_not contain("\n")
26
- contents.should =~ /function/
27
- end
28
-
29
- it "should allow the compilation level to be specified" do
30
- result = subject.paste('foo', 'bar')[:javascript].first
31
-
32
- begin
33
- subject.rebuild! :compress => 'google',
34
- :compilation_level => 'ADVANCED_OPTIMIZATIONS'
35
- rescue SocketError
36
- pending 'Error connecting to google'
37
- end
38
-
39
- # Everything should be optimized out
40
- subject.should have_in_result(result, '')
41
- end
42
-
43
- end