shift 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+
2
+ .rvmrc
3
+ .yardoc
4
+ doc
5
+ *.swp
6
+ *.gem
data/.yardopts ADDED
@@ -0,0 +1,7 @@
1
+ --hide-void-return
2
+ -m markdown
3
+ -M rdiscount
4
+ --title "Shift - State and logic-less compiler and compressor interface"
5
+ lib/**/*.rb
6
+ --no-private
7
+ --main README.md
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
@@ -0,0 +1,17 @@
1
+ module Shift
2
+ class Sass < Identity
3
+
4
+ def self.gem_dependencies
5
+ %w{sass}
6
+ end
7
+
8
+ def initialize(opts={})
9
+ @opts = opts
10
+ end
11
+
12
+ def process_plain(str)
13
+ ::Sass::Engine.new(str, @opts).render
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+
2
+
3
+ module Shift
4
+ class UglifyJS < Identity
5
+
6
+ def self.gem_dependencies
7
+ %w{uglifier}
8
+ end
9
+
10
+ def self.compiler_class
11
+ Uglifier
12
+ end
13
+
14
+ def process_plain(str)
15
+ @engine.compile(str)
16
+ end
17
+
18
+ end
19
+ end
@@ -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
@@ -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
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), 'identity_test')
2
+
3
+
4
+ class SassTest < IdentityTest
5
+
6
+ def subject
7
+ Shift::Sass
8
+ end
9
+
10
+ def transformations
11
+ {"#footer\n :height 200px" => "#footer {\n height: 200px; }\n"}
12
+ end
13
+
14
+ end
@@ -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
@@ -0,0 +1,6 @@
1
+
2
+ Hello dear.
3
+
4
+ Could you please bring with you my electric power drill, a cup of baking soda, three rolls of duct tape and The Brothers Karamazov when you come back from the apartment? I'm going on a mission again.
5
+
6
+ Thanks.
@@ -0,0 +1,5 @@
1
+
2
+
3
+ piglet = -> 'grunt grunt'
4
+
5
+ piglet()
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
+
@@ -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
+