shift 0.1.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.
- data/.gitignore +6 -0
- data/.yardopts +7 -0
- data/LICENSE +20 -0
- data/README.md +100 -0
- data/Rakefile +17 -0
- data/lib/shift/c/closure_compiler.rb +19 -0
- data/lib/shift/c/coffee_script.rb +23 -0
- data/lib/shift/c/identity.rb +116 -0
- data/lib/shift/c/rdiscount.rb +18 -0
- data/lib/shift/c/redcarpet.rb +18 -0
- data/lib/shift/c/sass.rb +17 -0
- data/lib/shift/c/uglify_js.rb +19 -0
- data/lib/shift/c/yui_compressor.rb +22 -0
- data/lib/shift/errors.rb +20 -0
- data/lib/shift/mappings.rb +32 -0
- data/lib/shift.rb +60 -0
- data/shift.gemspec +23 -0
- data/test/c/closure_compiler_test.rb +33 -0
- data/test/c/coffee_script_test.rb +23 -0
- data/test/c/identity_test.rb +79 -0
- data/test/c/rdiscount_test.rb +18 -0
- data/test/c/redcarpet_test.rb +18 -0
- data/test/c/sass_test.rb +14 -0
- data/test/c/uglify_js_test.rb +33 -0
- data/test/c/yui_compressor_test.rb +33 -0
- data/test/data/letter.echo +6 -0
- data/test/data/piglet.coffee +5 -0
- data/test/helper.rb +37 -0
- data/test/shift_test.rb +65 -0
- data/test/support.rb +37 -0
- metadata +93 -0
data/.yardopts
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Jostein Berre Eliassen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
|
2
|
+
Shift (draft)
|
3
|
+
=====
|
4
|
+
|
5
|
+
**State and logic-less compiler and compressor interface**
|
6
|
+
|
7
|
+
---
|
8
|
+
|
9
|
+
Shift is a generic Ruby interface to different compilers, compressors, transformers and so on. What the [Tilt](https://github.com/rtomayko/tilt) gem does for template languages, Shift does for stuff that compiles in one step, without stateful template logic.
|
10
|
+
|
11
|
+
* [Documentation](http://rubydoc.info/github/jbe/shift/master/frames)
|
12
|
+
* [File type mappings](http://rubydoc.info/github/jbe/shift/master/Shift)
|
13
|
+
|
14
|
+
### Installation
|
15
|
+
|
16
|
+
gem install tilt
|
17
|
+
|
18
|
+
|
19
|
+
### Usage
|
20
|
+
|
21
|
+
To read and process a file, using the preferred available default component for that filetype:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
|
25
|
+
Shift.read('thefile.js') # => minified js string
|
26
|
+
|
27
|
+
```
|
28
|
+
|
29
|
+
Or to read, process, and then write:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
|
33
|
+
Shift.read('canopy.sass').write('canopy.css')
|
34
|
+
|
35
|
+
```
|
36
|
+
|
37
|
+
The components can also be used directly:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
|
41
|
+
cc = Shift::ClosureCompiler.new(:compilation_level => 'ADVANCED_OPTIMIZATIONS')
|
42
|
+
minified_js_string = cc.read(path)
|
43
|
+
|
44
|
+
```
|
45
|
+
|
46
|
+
To simply process a string, or to process and save a string:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
|
50
|
+
md = Shift::RDiscount.new
|
51
|
+
md.process("hello *there*") # => "<p>hello <em>there</em></p>"
|
52
|
+
md.process("hello *there*").write('message.html')
|
53
|
+
|
54
|
+
```
|
55
|
+
To see if a component is available (check if the gem is installed and so on):
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
|
59
|
+
Shift::YUICompressor.available?.
|
60
|
+
|
61
|
+
```
|
62
|
+
|
63
|
+
To get the first available preferred default component class for a file:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
|
67
|
+
Shift['somefile.js'] # => Shift::UglifyJS
|
68
|
+
|
69
|
+
```
|
70
|
+
|
71
|
+
You can also do:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
|
75
|
+
Shift[:md] # => Shift::RDiscount
|
76
|
+
|
77
|
+
```
|
78
|
+
|
79
|
+
### Available engines
|
80
|
+
|
81
|
+
* UglifyJS
|
82
|
+
* ClosureCompiler
|
83
|
+
* YUICompressor
|
84
|
+
* CoffeeScript
|
85
|
+
* Sass
|
86
|
+
* RDiscount
|
87
|
+
* Redcarpet
|
88
|
+
|
89
|
+
|
90
|
+
### Why not use or extend Tilt instead?
|
91
|
+
|
92
|
+
I am making a separate library for this rather than extending Tilt, because i would usually only need one of the two in a given context. One and two step compilation are somewhat different things. Shift is more on the build side. Tilt is more on the dynamic side.
|
93
|
+
|
94
|
+
### Bye
|
95
|
+
|
96
|
+
Bye Bye, see you. There are proper [docs](http://rubydoc.info/github/jbe/shift/master/frames) if you want more. And once again, [the mappings are there too](http://rubydoc.info/github/jbe/shift/master/Shift). Contributions and feedback is welcome, of course.
|
97
|
+
|
98
|
+
---
|
99
|
+
|
100
|
+
© 2011 Jostein Berre Eliassen. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
task :test do
|
3
|
+
$LOAD_PATH.unshift './lib'
|
4
|
+
require 'shift'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
begin; require 'turn'; rescue LoadError; end
|
7
|
+
Dir.glob("test/**/*_test.rb").each { |test| require "./#{test}" }
|
8
|
+
end
|
9
|
+
|
10
|
+
task :shell do
|
11
|
+
system 'pry -I lib -r shift'
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :test
|
15
|
+
|
16
|
+
|
17
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Shift
|
4
|
+
class ClosureCompiler < Identity
|
5
|
+
|
6
|
+
def self.gem_dependencies
|
7
|
+
%w{closure-compiler}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.compiler_class
|
11
|
+
Closure::Compiler
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_plain(str)
|
15
|
+
@engine.compile(str)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
module Shift
|
3
|
+
class CoffeeScript < Identity
|
4
|
+
|
5
|
+
def self.gem_dependencies
|
6
|
+
%w{coffee-script}
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.require_libs
|
10
|
+
%w{coffee-script}
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(opts={})
|
14
|
+
@opts = opts
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def process_plain(str)
|
19
|
+
::CoffeeScript.compile(str, @opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Shift
|
4
|
+
|
5
|
+
# Returns the input unaltered. The purpose is mainly to inherit
|
6
|
+
# from this when defining other, more useful compilers.
|
7
|
+
#
|
8
|
+
class Identity
|
9
|
+
|
10
|
+
# Mixed into the resulting strings to make them easy to save.
|
11
|
+
#
|
12
|
+
module StringExtension
|
13
|
+
|
14
|
+
# Write the string to a sepcified path.
|
15
|
+
#
|
16
|
+
def write(path)
|
17
|
+
File.open(path, 'w') do |file|
|
18
|
+
file.write(self)
|
19
|
+
end
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# One-liner on what the user must have/do to make it available.
|
26
|
+
# Used in DependencyError.
|
27
|
+
#
|
28
|
+
def self.instructions
|
29
|
+
if gem_dependencies.any?
|
30
|
+
'gem install ' + gem_dependencies.join(' ')
|
31
|
+
else
|
32
|
+
'Google it :)'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Wether the requirements are met in the current environment.
|
37
|
+
# Typically checks if the required gems and/or command line
|
38
|
+
# stuff is available.
|
39
|
+
#
|
40
|
+
def self.available?
|
41
|
+
gem_dependencies.all? {|d| Gem.available?(d) }
|
42
|
+
end
|
43
|
+
|
44
|
+
# A list of Rubygems needed for the component to work.
|
45
|
+
#
|
46
|
+
def self.gem_dependencies
|
47
|
+
[]
|
48
|
+
end
|
49
|
+
|
50
|
+
# A list of things to be required on initialization.
|
51
|
+
#
|
52
|
+
def self.require_libs
|
53
|
+
gem_dependencies
|
54
|
+
end
|
55
|
+
|
56
|
+
# The class of the wrapped compiler, or false if none
|
57
|
+
# is used.
|
58
|
+
#
|
59
|
+
def self.compiler_class
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
# A default instance without options.
|
64
|
+
#
|
65
|
+
def self.default
|
66
|
+
@default ||= new
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.new(*prms)
|
70
|
+
unless available?
|
71
|
+
raise Shift::DependencyError, "#{self} not available. " +
|
72
|
+
"Possible fix: #{instructions}"
|
73
|
+
end
|
74
|
+
@req ||= require_libs.each {|str| require str }
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
# Create a new instance. Ignores the given options.
|
79
|
+
#
|
80
|
+
def initialize(*prms)
|
81
|
+
if self.class.compiler_class
|
82
|
+
@engine = self.class.compiler_class.new(*prms)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Process the supplied string, returning the resulting `String` (with a #write method attached to it).
|
87
|
+
#
|
88
|
+
def process(str)
|
89
|
+
process_plain(str).extend(StringExtension)
|
90
|
+
end
|
91
|
+
alias :compress :process
|
92
|
+
alias :compile :process
|
93
|
+
alias :transform :process
|
94
|
+
|
95
|
+
# Process the supplied string, returning the resulting `String`.
|
96
|
+
#
|
97
|
+
def process_plain(str)
|
98
|
+
str.dup
|
99
|
+
end
|
100
|
+
|
101
|
+
# Read and process a file.
|
102
|
+
#
|
103
|
+
# @raise [DependencyError] when none of the mapped
|
104
|
+
# implementations are available.
|
105
|
+
#
|
106
|
+
# @return [String] The processed `String`
|
107
|
+
#
|
108
|
+
def read(path)
|
109
|
+
process(File.read(path)).extend(StringExtension)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
Echo = Identity
|
114
|
+
end
|
115
|
+
|
116
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module Shift
|
3
|
+
class RDiscount < Identity
|
4
|
+
|
5
|
+
def self.gem_dependencies
|
6
|
+
%w{rdiscount}
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(*switches)
|
10
|
+
@switches = switches
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_plain(str)
|
14
|
+
::RDiscount.new(str, *@switches).to_html
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Shift
|
2
|
+
class Redcarpet < Identity
|
3
|
+
|
4
|
+
def self.gem_dependencies
|
5
|
+
%w{redcarpet}
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(*switches)
|
9
|
+
@switches = switches
|
10
|
+
end
|
11
|
+
|
12
|
+
def process_plain(str)
|
13
|
+
::Redcarpet.new(str, *@switches).to_html
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
RedCarpet = Redcarpet
|
18
|
+
end
|
data/lib/shift/c/sass.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
module Shift
|
3
|
+
class YUICompressor < Identity
|
4
|
+
|
5
|
+
def self.gem_dependencies
|
6
|
+
%w{yui-compressor}
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.require_libs
|
10
|
+
%w{yui/compressor}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.compiler_class
|
14
|
+
YUI::JavaScriptCompressor
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_plain(str)
|
18
|
+
@engine.compress(str)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/shift/errors.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Shift
|
4
|
+
|
5
|
+
# Shift base error, from which other errors inherit.
|
6
|
+
#
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
# Raised when the environment needed to perform a given
|
10
|
+
# action is not available. Typically, you will need to
|
11
|
+
# install another gem or some library/software.
|
12
|
+
#
|
13
|
+
class DependencyError < Error; end
|
14
|
+
|
15
|
+
# Raised when you try to read a file for which there are
|
16
|
+
# no mappings without specifying its type.
|
17
|
+
#
|
18
|
+
class UnknownFormatError < Error; end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module Shift
|
3
|
+
|
4
|
+
# Mappings from file names to implementation classes. The
|
5
|
+
# classes are listed in order of preference per type.
|
6
|
+
#
|
7
|
+
MAPPINGS = {
|
8
|
+
'echo' => %w{ Identity },
|
9
|
+
'js' => %w{ UglifyJS ClosureCompiler YUICompressor },
|
10
|
+
'coffee' => %w{ CoffeeScript },
|
11
|
+
'sass' => %w{ Sass },
|
12
|
+
'md' => %w{ RDiscount Redcarpet }
|
13
|
+
}
|
14
|
+
|
15
|
+
# @raise [DependencyError] when none of the mapped
|
16
|
+
# implementations are available.
|
17
|
+
#
|
18
|
+
# @return [Class] The preferred available class associated
|
19
|
+
# with the file or extension.
|
20
|
+
#
|
21
|
+
def self.best_available_mapping_for(key)
|
22
|
+
MAPPINGS[key].each do |kls_name|
|
23
|
+
kls = const_get(kls_name)
|
24
|
+
return kls if kls.available?
|
25
|
+
end
|
26
|
+
help = const_get(MAPPINGS[key].first)::INSTRUCTIONS
|
27
|
+
raise DependencyError, "no implementation available for " +
|
28
|
+
"#{key.inspect}. Possible solution: #{help}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
data/lib/shift.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# SHIFT
|
4
|
+
#
|
5
|
+
# State and logic-less compiler and compressor interface
|
6
|
+
#
|
7
|
+
# (c) 2011 Jostein Berre Eliassen - MIT licence
|
8
|
+
|
9
|
+
|
10
|
+
module Shift
|
11
|
+
|
12
|
+
VERSION = '0.1.0'
|
13
|
+
|
14
|
+
require 'shift/errors'
|
15
|
+
require 'shift/mappings'
|
16
|
+
|
17
|
+
|
18
|
+
# components
|
19
|
+
|
20
|
+
autoload :Identity, 'shift/c/identity'
|
21
|
+
autoload :UglifyJS, 'shift/c/uglify_js'
|
22
|
+
autoload :ClosureCompiler, 'shift/c/closure_compiler'
|
23
|
+
autoload :YUICompressor, 'shift/c/yui_compressor'
|
24
|
+
autoload :CoffeeScript, 'shift/c/coffee_script'
|
25
|
+
autoload :Sass, 'shift/c/sass'
|
26
|
+
autoload :RDiscount, 'shift/c/rdiscount'
|
27
|
+
autoload :Redcarpet, 'shift/c/redcarpet'
|
28
|
+
autoload :RedCarpet, 'shift/c/redcarpet'
|
29
|
+
|
30
|
+
|
31
|
+
# Read and process a file with the mapped component.
|
32
|
+
#
|
33
|
+
# @see Shift.[]
|
34
|
+
#
|
35
|
+
# (see Identity#read)
|
36
|
+
#
|
37
|
+
def self.read(path, opts={})
|
38
|
+
self[path].new(opts).read(path)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get the preferred available class mapped to match the
|
42
|
+
# given filename or extension.
|
43
|
+
#
|
44
|
+
# @raise [UnknownFormatError] when none of the mappings match.
|
45
|
+
#
|
46
|
+
# (see Shift.best_available_mapping_for)
|
47
|
+
#
|
48
|
+
def self.[](file)
|
49
|
+
pattern = File.basename(file.to_s.downcase)
|
50
|
+
until pattern.empty?
|
51
|
+
if MAPPINGS[pattern]
|
52
|
+
return best_available_mapping_for(pattern)
|
53
|
+
end
|
54
|
+
pattern.sub!(/^[^.]*\.?/, '')
|
55
|
+
end
|
56
|
+
raise UnknownFormatError, "no mapping matches #{file}"
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
data/shift.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
2
|
+
require 'shift'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
|
6
|
+
s.name = 'shift'
|
7
|
+
|
8
|
+
s.author = 'Jostein Berre Eliassen'
|
9
|
+
s.email = 'josteinpost@gmail.com'
|
10
|
+
s.homepage = "http://github.com/jbe/shift"
|
11
|
+
s.license = "MIT"
|
12
|
+
|
13
|
+
s.version = Shift::VERSION
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
|
16
|
+
s.summary = 'Shift is a generic interface to different compilers, compressors, etc.'
|
17
|
+
s.description = 'Shift is a generic interface to different compilers, compressors, etc. What the Tilt gem does for template languages, Shift does for compilers and compressors.'
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
21
|
+
s.require_path = 'lib'
|
22
|
+
s.bindir = 'bin'
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'identity_test')
|
2
|
+
|
3
|
+
|
4
|
+
class ClosureCompilerTest < IdentityTest
|
5
|
+
|
6
|
+
FUNCTION = <<-eos
|
7
|
+
function hello(name) {
|
8
|
+
alert('Hello, ' + name);
|
9
|
+
}
|
10
|
+
eos
|
11
|
+
|
12
|
+
INVOCATION = <<-eos
|
13
|
+
hello('New user');
|
14
|
+
eos
|
15
|
+
|
16
|
+
def subject
|
17
|
+
Shift::ClosureCompiler
|
18
|
+
end
|
19
|
+
|
20
|
+
def options
|
21
|
+
{:compilation_level => 'ADVANCED_OPTIMIZATIONS'}
|
22
|
+
end
|
23
|
+
|
24
|
+
def transformations
|
25
|
+
{
|
26
|
+
[FUNCTION, INVOCATION].join("\n") =>
|
27
|
+
"alert(\"Hello, New user\");\n",
|
28
|
+
FUNCTION => "\n",
|
29
|
+
INVOCATION => "hello(\"New user\");\n"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'identity_test')
|
2
|
+
|
3
|
+
|
4
|
+
class CoffeeScriptTest < IdentityTest
|
5
|
+
|
6
|
+
def subject
|
7
|
+
Shift::CoffeeScript
|
8
|
+
end
|
9
|
+
|
10
|
+
def options
|
11
|
+
{:bare => true}
|
12
|
+
end
|
13
|
+
|
14
|
+
def transformations
|
15
|
+
{
|
16
|
+
'hello' => 'hello;',
|
17
|
+
'x = 23' => "var x;\nx = 23;",
|
18
|
+
'frog -> "croak"' =>
|
19
|
+
"frog(function() {\n return \"croak\";\n});"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'helper')
|
2
|
+
|
3
|
+
# Test Shift::Identity.
|
4
|
+
class IdentityTest < TestCase
|
5
|
+
|
6
|
+
def subject
|
7
|
+
Shift::Identity
|
8
|
+
end
|
9
|
+
|
10
|
+
def instance
|
11
|
+
@instance ||= subject.new(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def options
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
|
18
|
+
def transformations
|
19
|
+
{
|
20
|
+
'echo' => 'echo',
|
21
|
+
'' => ''
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
test 'instructions' do
|
26
|
+
unless subject == Shift::Identity
|
27
|
+
refute_same subject.instructions,
|
28
|
+
subject.superclass.instructions,
|
29
|
+
'gives instructions'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
test 'has_default_instance' do
|
34
|
+
assert_instance_of subject, subject.default
|
35
|
+
end
|
36
|
+
|
37
|
+
test 'process' do
|
38
|
+
transformations.each do |a, b|
|
39
|
+
assert_equal b, instance.process(a)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# the usual ruby system file errors will just pass through,
|
44
|
+
# no use in testing for them.
|
45
|
+
|
46
|
+
test 'read' do
|
47
|
+
transformations.each do |a, b|
|
48
|
+
with_tempfile(a) do |path|
|
49
|
+
assert_equal b, instance.read(path)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
test 'read and write' do
|
55
|
+
transformations.each do |a, b|
|
56
|
+
with_tempfile(a) do |src_path|
|
57
|
+
with_tempfile do |trg_path|
|
58
|
+
instance.read(src_path).write(trg_path)
|
59
|
+
assert_equal b, IO.read(trg_path)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
test 'process and write' do
|
66
|
+
transformations.each do |a, b|
|
67
|
+
with_tempfile do |path|
|
68
|
+
instance.process(a).write(path)
|
69
|
+
assert_equal b, IO.read(path)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
test 'initialize when unavailable' do
|
75
|
+
wrap = Class.new(subject).extend(Unavabelizer)
|
76
|
+
assert_raises(Shift::DependencyError) { wrap.new }
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'identity_test')
|
2
|
+
|
3
|
+
|
4
|
+
class RDiscountTest < IdentityTest
|
5
|
+
|
6
|
+
def subject
|
7
|
+
Shift::RDiscount
|
8
|
+
end
|
9
|
+
|
10
|
+
def instance
|
11
|
+
subject.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def transformations
|
15
|
+
{ 'hello' => "<p>hello</p>\n" }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'identity_test')
|
2
|
+
|
3
|
+
|
4
|
+
class RedCarpetTest < IdentityTest
|
5
|
+
|
6
|
+
def subject
|
7
|
+
Shift::Redcarpet
|
8
|
+
end
|
9
|
+
|
10
|
+
def instance
|
11
|
+
subject.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def transformations
|
15
|
+
{ 'hello' => "<p>hello</p>\n" }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/test/c/sass_test.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'identity_test')
|
2
|
+
|
3
|
+
|
4
|
+
class UglifyJSTest < IdentityTest
|
5
|
+
|
6
|
+
FUNCTION = <<-eos
|
7
|
+
function hello(name) {
|
8
|
+
alert('Hello, ' + name);
|
9
|
+
}
|
10
|
+
eos
|
11
|
+
|
12
|
+
INVOCATION = <<-eos
|
13
|
+
hello('New user');
|
14
|
+
eos
|
15
|
+
|
16
|
+
def subject
|
17
|
+
Shift::UglifyJS
|
18
|
+
end
|
19
|
+
|
20
|
+
def options
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
def transformations
|
25
|
+
{
|
26
|
+
[FUNCTION, INVOCATION].join("\n") =>
|
27
|
+
"function hello(a){alert(\"Hello, \"+a)}hello(\"New user\")",
|
28
|
+
FUNCTION => "function hello(a){alert(\"Hello, \"+a)}",
|
29
|
+
INVOCATION => "hello(\"New user\")"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'identity_test')
|
2
|
+
|
3
|
+
|
4
|
+
class YUICompressorTest < IdentityTest
|
5
|
+
|
6
|
+
FUNCTION = <<-eos
|
7
|
+
function hello(name) {
|
8
|
+
alert('Hello, ' + name);
|
9
|
+
}
|
10
|
+
eos
|
11
|
+
|
12
|
+
INVOCATION = <<-eos
|
13
|
+
hello('New user');
|
14
|
+
eos
|
15
|
+
|
16
|
+
def subject
|
17
|
+
Shift::YUICompressor
|
18
|
+
end
|
19
|
+
|
20
|
+
def options
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
def transformations
|
25
|
+
{
|
26
|
+
[FUNCTION, INVOCATION].join("\n") =>
|
27
|
+
"function hello(name){alert(\"Hello, \"+name)}hello(\"New user\");",
|
28
|
+
FUNCTION => "function hello(name){alert(\"Hello, \"+name)};",
|
29
|
+
INVOCATION => "hello(\"New user\");"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
class TestCase < MiniTest::Unit::TestCase
|
4
|
+
def self.test(name, &block)
|
5
|
+
test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
|
6
|
+
defined = instance_method(test_name) rescue false
|
7
|
+
raise "#{test_name} already defined in #{self}" if defined
|
8
|
+
|
9
|
+
block ||= proc { skip }
|
10
|
+
define_method(test_name, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_tempfile(data=nil)
|
14
|
+
file = Tempfile.new('shift_test')
|
15
|
+
file.write(data) if data
|
16
|
+
file.close
|
17
|
+
yield(file.path)
|
18
|
+
file.unlink
|
19
|
+
end
|
20
|
+
|
21
|
+
def file(name)
|
22
|
+
File.join(File.dirname(__FILE__), 'data', name)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
module Unavabelizer
|
32
|
+
def available?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
data/test/shift_test.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
require File.join(File.dirname(__FILE__), 'support')
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
# Test Shift base module methods
|
8
|
+
class ShiftTest < TestCase
|
9
|
+
|
10
|
+
test 'read nonexistant file' do
|
11
|
+
assert_raises(Errno::ENOENT) do
|
12
|
+
Shift.read('/ubongobaluba-hepp-piglets/seriously.echo')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
test 'read file' do
|
17
|
+
assert_match Shift.read(file 'letter.echo'),
|
18
|
+
/electric power drill/
|
19
|
+
end
|
20
|
+
|
21
|
+
test 'reads existing file and writes result' do
|
22
|
+
with_tempfile do |path|
|
23
|
+
Shift.read(file('letter.echo')).write(path)
|
24
|
+
assert_equal(IO.read(file 'letter.echo'), IO.read(path))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# mappings
|
30
|
+
|
31
|
+
test 'has mappings' do
|
32
|
+
assert_kind_of Hash, Shift::MAPPINGS
|
33
|
+
end
|
34
|
+
|
35
|
+
test 'reads unmapped file' do
|
36
|
+
assert_raises(Shift::UnknownFormatError) do
|
37
|
+
Shift.read('oy-oy-oy.noformatforthis')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
test 'gets available mapping' do
|
42
|
+
assert_equal Shift[:echo], Shift::Identity, 'given type'
|
43
|
+
assert_equal Shift['treaty.null'], NullComponent, 'given path'
|
44
|
+
assert_equal Shift['some/path/hey.bingo.bongo'],
|
45
|
+
NullComponent, 'with detailed mapping'
|
46
|
+
end
|
47
|
+
|
48
|
+
test 'prioritizes' do
|
49
|
+
assert_equal Shift['file.null'], NullComponent,
|
50
|
+
'first when available'
|
51
|
+
assert_equal Shift['file.prioritized'], NullComponent,
|
52
|
+
'second when available but not first'
|
53
|
+
end
|
54
|
+
|
55
|
+
test 'raises DependencyError' do
|
56
|
+
begin
|
57
|
+
Shift[:unavailable] # defined in test/support.rb
|
58
|
+
assert false, 'when no components available'
|
59
|
+
rescue Shift::DependencyError => err
|
60
|
+
assert_match /meditate/, err.message, 'with helpful message'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
data/test/support.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
class UnavailableComponent < Shift::Identity
|
3
|
+
|
4
|
+
INSTRUCTIONS = 'meditate.'
|
5
|
+
|
6
|
+
def self.available?
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
class NullComponent < Shift::Identity
|
13
|
+
|
14
|
+
def self.available?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(str)
|
19
|
+
''
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
Shift::MAPPINGS['unavailable'] = ['UnavailableComponent'] * 10
|
25
|
+
|
26
|
+
Shift::MAPPINGS['null'] = %w{NullComponent}
|
27
|
+
Shift::MAPPINGS['bingo.bongo'] = %w{NullComponent}
|
28
|
+
|
29
|
+
Shift::MAPPINGS['prioritized'] = %w{UnavailableComponent
|
30
|
+
NullComponent Identity}
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shift
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jostein Berre Eliassen
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-05-09 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Shift is a generic interface to different compilers, compressors, etc. What the Tilt gem does for template languages, Shift does for compilers and compressors.
|
22
|
+
email: josteinpost@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- .gitignore
|
31
|
+
- .yardopts
|
32
|
+
- LICENSE
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- lib/shift.rb
|
36
|
+
- lib/shift/c/closure_compiler.rb
|
37
|
+
- lib/shift/c/coffee_script.rb
|
38
|
+
- lib/shift/c/identity.rb
|
39
|
+
- lib/shift/c/rdiscount.rb
|
40
|
+
- lib/shift/c/redcarpet.rb
|
41
|
+
- lib/shift/c/sass.rb
|
42
|
+
- lib/shift/c/uglify_js.rb
|
43
|
+
- lib/shift/c/yui_compressor.rb
|
44
|
+
- lib/shift/errors.rb
|
45
|
+
- lib/shift/mappings.rb
|
46
|
+
- shift.gemspec
|
47
|
+
- test/c/closure_compiler_test.rb
|
48
|
+
- test/c/coffee_script_test.rb
|
49
|
+
- test/c/identity_test.rb
|
50
|
+
- test/c/rdiscount_test.rb
|
51
|
+
- test/c/redcarpet_test.rb
|
52
|
+
- test/c/sass_test.rb
|
53
|
+
- test/c/uglify_js_test.rb
|
54
|
+
- test/c/yui_compressor_test.rb
|
55
|
+
- test/data/letter.echo
|
56
|
+
- test/data/piglet.coffee
|
57
|
+
- test/helper.rb
|
58
|
+
- test/shift_test.rb
|
59
|
+
- test/support.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://github.com/jbe/shift
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.7
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Shift is a generic interface to different compilers, compressors, etc.
|
92
|
+
test_files: []
|
93
|
+
|