shift 0.1.0 → 0.4.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/CHANGELOG +20 -0
- data/README.md +105 -37
- data/Rakefile +1 -1
- data/TODO +3 -0
- data/bin/shifter +5 -0
- data/lib/shift.rb +42 -36
- data/lib/shift/action_map.rb +106 -0
- data/lib/shift/cli.rb +43 -0
- data/lib/shift/errors.rb +7 -3
- data/lib/shift/i/closure_compiler.rb +23 -0
- data/lib/shift/{c → i}/coffee_script.rb +6 -3
- data/lib/shift/i/echo.rb +9 -0
- data/lib/shift/{c → i}/rdiscount.rb +6 -2
- data/lib/shift/{c → i}/redcarpet.rb +6 -2
- data/lib/shift/{c → i}/sass.rb +6 -2
- data/lib/shift/{c → i}/uglify_js.rb +7 -3
- data/lib/shift/{c → i}/yui_compressor.rb +7 -3
- data/lib/shift/i/zlib_reader.rb +23 -0
- data/lib/shift/i/zlib_writer.rb +27 -0
- data/lib/shift/{c/identity.rb → interface.rb} +39 -42
- data/lib/shift/interface_list.rb +67 -0
- data/lib/shift/interfaces.rb +20 -0
- data/lib/shift/mapper.rb +95 -0
- data/lib/shift/mappings.rb +51 -28
- data/lib/shift/mappings.yml +6 -0
- data/lib/shift/string.rb +125 -0
- data/shift.gemspec +3 -2
- data/test/data/letter.echo +0 -5
- data/test/helper.rb +2 -12
- data/test/{c → i}/closure_compiler_test.rb +6 -2
- data/test/{c → i}/coffee_script_test.rb +6 -2
- data/test/i/rdiscount_test.rb +22 -0
- data/test/i/redcarpet_test.rb +22 -0
- data/test/i/sass_test.rb +19 -0
- data/test/{c → i}/uglify_js_test.rb +6 -2
- data/test/{c → i}/yui_compressor_test.rb +6 -2
- data/test/i/zlib_reader.rb +24 -0
- data/test/interface_test.rb +60 -0
- data/test/mapper_test.rb +144 -0
- data/test/shift_test.rb +12 -43
- data/test/string_test.rb +39 -0
- metadata +39 -24
- data/lib/shift/c/closure_compiler.rb +0 -19
- data/test/c/identity_test.rb +0 -79
- data/test/c/rdiscount_test.rb +0 -18
- data/test/c/redcarpet_test.rb +0 -18
- data/test/c/sass_test.rb +0 -14
- data/test/support.rb +0 -37
data/lib/shift/cli.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
require 'shift'
|
3
|
+
|
4
|
+
|
5
|
+
module Shift
|
6
|
+
|
7
|
+
# The `shifter` command line interface.
|
8
|
+
#
|
9
|
+
class CLI
|
10
|
+
|
11
|
+
USAGE = "Usage: shifter <file> [action] [format]\n" +
|
12
|
+
"In pipe: shifter - format [action]\n\n" +
|
13
|
+
"Available formats and actions:\n\n" +
|
14
|
+
Shift.inspect_actions
|
15
|
+
|
16
|
+
def self.new
|
17
|
+
begin
|
18
|
+
super(*ARGV)
|
19
|
+
rescue ArgumentError
|
20
|
+
abort USAGE
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(path, a=nil, b=nil)
|
25
|
+
@path = path
|
26
|
+
@format, @action = stdin? ? [a,b] : [b,a]
|
27
|
+
@format ||= :echo
|
28
|
+
@action ||= :default
|
29
|
+
end
|
30
|
+
|
31
|
+
def stdin?
|
32
|
+
@path == '-'
|
33
|
+
end
|
34
|
+
|
35
|
+
def data
|
36
|
+
stdin? ? STDIN.read : File.read(@path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def run!
|
40
|
+
puts Shift(data, @format).process(@action)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/shift/errors.rb
CHANGED
@@ -12,9 +12,13 @@ module Shift
|
|
12
12
|
#
|
13
13
|
class DependencyError < Error; end
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
class LookupError < Error; end
|
16
|
+
class UnknownFormatError < LookupError; end
|
17
|
+
class UnknownActionError < LookupError; end
|
18
|
+
|
19
|
+
# Raised when encountering invalid mappings, like
|
20
|
+
# when there is a cycle in the map.
|
17
21
|
#
|
18
|
-
class
|
22
|
+
class MappingError < Error; end
|
19
23
|
|
20
24
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Shift
|
4
|
+
class ClosureCompiler < Interface
|
5
|
+
|
6
|
+
def self.gem_dependencies
|
7
|
+
%w{closure-compiler}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.engine_class
|
11
|
+
Closure::Compiler
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.target_format
|
15
|
+
'min.js'
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(str)
|
19
|
+
@engine.compile(str)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
2
|
module Shift
|
3
|
-
class CoffeeScript <
|
3
|
+
class CoffeeScript < Interface
|
4
4
|
|
5
5
|
def self.gem_dependencies
|
6
6
|
%w{coffee-script}
|
@@ -10,12 +10,15 @@ module Shift
|
|
10
10
|
%w{coffee-script}
|
11
11
|
end
|
12
12
|
|
13
|
+
def self.target_format
|
14
|
+
'js'
|
15
|
+
end
|
16
|
+
|
13
17
|
def initialize(opts={})
|
14
18
|
@opts = opts
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
def process_plain(str)
|
21
|
+
def process(str)
|
19
22
|
::CoffeeScript.compile(str, @opts)
|
20
23
|
end
|
21
24
|
|
data/lib/shift/i/echo.rb
ADDED
@@ -1,16 +1,20 @@
|
|
1
1
|
|
2
2
|
module Shift
|
3
|
-
class RDiscount <
|
3
|
+
class RDiscount < Interface
|
4
4
|
|
5
5
|
def self.gem_dependencies
|
6
6
|
%w{rdiscount}
|
7
7
|
end
|
8
8
|
|
9
|
+
def self.target_format
|
10
|
+
'html'
|
11
|
+
end
|
12
|
+
|
9
13
|
def initialize(*switches)
|
10
14
|
@switches = switches
|
11
15
|
end
|
12
16
|
|
13
|
-
def
|
17
|
+
def process(str)
|
14
18
|
::RDiscount.new(str, *@switches).to_html
|
15
19
|
end
|
16
20
|
|
@@ -1,15 +1,19 @@
|
|
1
1
|
module Shift
|
2
|
-
class Redcarpet <
|
2
|
+
class Redcarpet < Interface
|
3
3
|
|
4
4
|
def self.gem_dependencies
|
5
5
|
%w{redcarpet}
|
6
6
|
end
|
7
7
|
|
8
|
+
def self.target_format
|
9
|
+
'html'
|
10
|
+
end
|
11
|
+
|
8
12
|
def initialize(*switches)
|
9
13
|
@switches = switches
|
10
14
|
end
|
11
15
|
|
12
|
-
def
|
16
|
+
def process(str)
|
13
17
|
::Redcarpet.new(str, *@switches).to_html
|
14
18
|
end
|
15
19
|
|
data/lib/shift/{c → i}/sass.rb
RENAMED
@@ -1,15 +1,19 @@
|
|
1
1
|
module Shift
|
2
|
-
class Sass <
|
2
|
+
class Sass < Interface
|
3
3
|
|
4
4
|
def self.gem_dependencies
|
5
5
|
%w{sass}
|
6
6
|
end
|
7
7
|
|
8
|
+
def self.target_format
|
9
|
+
'css'
|
10
|
+
end
|
11
|
+
|
8
12
|
def initialize(opts={})
|
9
13
|
@opts = opts
|
10
14
|
end
|
11
15
|
|
12
|
-
def
|
16
|
+
def process(str)
|
13
17
|
::Sass::Engine.new(str, @opts).render
|
14
18
|
end
|
15
19
|
|
@@ -1,17 +1,21 @@
|
|
1
1
|
|
2
2
|
|
3
3
|
module Shift
|
4
|
-
class UglifyJS <
|
4
|
+
class UglifyJS < Interface
|
5
5
|
|
6
6
|
def self.gem_dependencies
|
7
7
|
%w{uglifier}
|
8
8
|
end
|
9
9
|
|
10
|
-
def self.
|
10
|
+
def self.engine_class
|
11
11
|
Uglifier
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def self.target_format
|
15
|
+
'min.js'
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(str)
|
15
19
|
@engine.compile(str)
|
16
20
|
end
|
17
21
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
2
|
module Shift
|
3
|
-
class YUICompressor <
|
3
|
+
class YUICompressor < Interface
|
4
4
|
|
5
5
|
def self.gem_dependencies
|
6
6
|
%w{yui-compressor}
|
@@ -10,11 +10,15 @@ module Shift
|
|
10
10
|
%w{yui/compressor}
|
11
11
|
end
|
12
12
|
|
13
|
-
def self.
|
13
|
+
def self.engine_class
|
14
14
|
YUI::JavaScriptCompressor
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def self.target_format
|
18
|
+
'min.js'
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(str)
|
18
22
|
@engine.compress(str)
|
19
23
|
end
|
20
24
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Shift
|
2
|
+
class ZlibReader < Interface
|
3
|
+
|
4
|
+
def self.keep_extension?
|
5
|
+
false
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.target_format
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
require 'zlib'
|
14
|
+
require 'stringio'
|
15
|
+
end
|
16
|
+
|
17
|
+
def process(data)
|
18
|
+
gz = Zlib::GzipReader.new(StringIO.new(data))
|
19
|
+
gz.read
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Shift
|
2
|
+
class ZlibWriter < Interface
|
3
|
+
|
4
|
+
def self.keep_extension?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.target_format
|
9
|
+
'gz'
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
require 'zlib'
|
14
|
+
require 'stringio'
|
15
|
+
end
|
16
|
+
|
17
|
+
def process(str)
|
18
|
+
StringIO.open('', 'w') do |io|
|
19
|
+
gz = Zlib::GzipWriter.new(io)
|
20
|
+
gz.write(str)
|
21
|
+
gz.close
|
22
|
+
io.string
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -1,28 +1,13 @@
|
|
1
1
|
|
2
|
-
|
3
2
|
module Shift
|
4
3
|
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# The default Shift interface, from which other interfaces must
|
5
|
+
# inherit. Also works as an identity function or echo server, in
|
6
|
+
# that it echoes what it is given.
|
7
7
|
#
|
8
|
-
class
|
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
|
-
|
8
|
+
class Interface
|
24
9
|
|
25
|
-
# One-liner on what the user
|
10
|
+
# One-liner on what the user can do to make it available.
|
26
11
|
# Used in DependencyError.
|
27
12
|
#
|
28
13
|
def self.instructions
|
@@ -41,7 +26,7 @@ module Shift
|
|
41
26
|
gem_dependencies.all? {|d| Gem.available?(d) }
|
42
27
|
end
|
43
28
|
|
44
|
-
# A list of Rubygems needed for the
|
29
|
+
# A list of Rubygems needed for the interface to work.
|
45
30
|
#
|
46
31
|
def self.gem_dependencies
|
47
32
|
[]
|
@@ -53,10 +38,23 @@ module Shift
|
|
53
38
|
gem_dependencies
|
54
39
|
end
|
55
40
|
|
56
|
-
# The class of the wrapped
|
41
|
+
# The class of the wrapped generator, or false if none
|
57
42
|
# is used.
|
58
43
|
#
|
59
|
-
def self.
|
44
|
+
def self.engine_class
|
45
|
+
false
|
46
|
+
end
|
47
|
+
|
48
|
+
# The format typically produced by the generator.
|
49
|
+
#
|
50
|
+
def self.target_format
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
# Whether to leave the old extension as is and append, like
|
55
|
+
# something.css => something.css.gzip
|
56
|
+
#
|
57
|
+
def self.keep_extension?
|
60
58
|
false
|
61
59
|
end
|
62
60
|
|
@@ -75,42 +73,41 @@ module Shift
|
|
75
73
|
super
|
76
74
|
end
|
77
75
|
|
78
|
-
# Create a new instance
|
76
|
+
# Create a new instance with the given options.
|
79
77
|
#
|
80
78
|
def initialize(*prms)
|
81
|
-
if self.class.
|
82
|
-
@engine = self.class.
|
79
|
+
if self.class.engine_class
|
80
|
+
@engine = self.class.engine_class.new(*prms)
|
83
81
|
end
|
84
82
|
end
|
85
83
|
|
86
|
-
# Process the supplied string, returning the resulting `String
|
84
|
+
# Process the supplied string, returning the resulting `String`.
|
87
85
|
#
|
88
86
|
def process(str)
|
89
|
-
|
87
|
+
str.dup
|
90
88
|
end
|
91
89
|
alias :compress :process
|
92
90
|
alias :compile :process
|
93
91
|
alias :transform :process
|
94
92
|
|
95
|
-
#
|
93
|
+
# Get the default filename of a transformed file.
|
94
|
+
# @param [String] file Path of the original file
|
95
|
+
# @return [String] default file name for the result.
|
96
96
|
#
|
97
|
-
def
|
98
|
-
|
99
|
-
end
|
97
|
+
def rename(file)
|
98
|
+
return nil if file.nil?
|
100
99
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
process(File.read(path)).extend(StringExtension)
|
100
|
+
unless self.class.keep_extension?
|
101
|
+
file = file.is_a?(Symbol) ?
|
102
|
+
file.to_s : file.chomp(File.extname(file))
|
103
|
+
end
|
104
|
+
if self.class.target_format
|
105
|
+
file = file + '.' + self.class.target_format.to_s
|
106
|
+
end
|
107
|
+
file
|
110
108
|
end
|
111
109
|
|
112
110
|
end
|
113
|
-
Echo = Identity
|
114
111
|
end
|
115
112
|
|
116
113
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Shift
|
2
|
+
class InterfaceList
|
3
|
+
|
4
|
+
# Create a new InterfaceList, given an array of class names
|
5
|
+
# of shift interfaces. Immutable once created.
|
6
|
+
#
|
7
|
+
def initialize(ifaces)
|
8
|
+
@interfaces = ifaces
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_hash
|
12
|
+
@interfaces.dup
|
13
|
+
end
|
14
|
+
|
15
|
+
def eql?(other)
|
16
|
+
@interfaces.eql? other.to_hash
|
17
|
+
end
|
18
|
+
alias :== :eql?
|
19
|
+
|
20
|
+
def hash
|
21
|
+
@interfaces.hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
'InterfaceList' + @interfaces.inspect
|
26
|
+
end
|
27
|
+
|
28
|
+
# Pick the preferred available interface.
|
29
|
+
#
|
30
|
+
# @raise [DependencyError] when none of the interfaces
|
31
|
+
# are available.
|
32
|
+
#
|
33
|
+
# @return [Class] The preferred available class
|
34
|
+
#
|
35
|
+
def pick
|
36
|
+
each_class {|kls| return kls if kls.available? }
|
37
|
+
raise DependencyError, "nothing available: " +
|
38
|
+
help_string
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def help_string
|
44
|
+
if @interfaces.any?
|
45
|
+
@interfaces.inspect + " Possible solution: " +
|
46
|
+
first_class.instructions
|
47
|
+
else
|
48
|
+
'no interfaces mapped'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def each_class
|
53
|
+
@interfaces.each do |name|
|
54
|
+
yield get_iface(name)
|
55
|
+
end; nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def first_class
|
59
|
+
get_iface(@interfaces.first)
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_iface(name)
|
63
|
+
Shift.const_get(name)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|