moco 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.txt +67 -0
- data/Rakefile +15 -0
- data/bin/moco +6 -0
- data/lib/moco/ansi_escape.rb +37 -0
- data/lib/moco/application.rb +109 -0
- data/lib/moco/browser.rb +64 -0
- data/lib/moco/browser_error.rb +105 -0
- data/lib/moco/compile_error.rb +66 -0
- data/lib/moco/compiler.rb +151 -0
- data/lib/moco/compiler_option.rb +60 -0
- data/lib/moco/compiler_register.rb +29 -0
- data/lib/moco/compilers/coffee_compiler.rb +70 -0
- data/lib/moco/compilers/haml_compiler.rb +21 -0
- data/lib/moco/compilers/less_compiler.rb +15 -0
- data/lib/moco/compilers/markdown_compiler.rb +139 -0
- data/lib/moco/compilers/sass_compiler.rb +25 -0
- data/lib/moco/file_util.rb +54 -0
- data/lib/moco/log.rb +108 -0
- data/lib/moco/monitor.rb +83 -0
- data/lib/moco/options.rb +336 -0
- data/lib/moco/source_map.rb +22 -0
- data/lib/moco/support/error/error.css +22 -0
- data/lib/moco/support/error/error.html +7 -0
- data/lib/moco/support/error/error.js +58 -0
- data/lib/moco/support/reload.scpt +0 -0
- data/lib/moco.rb +44 -0
- data/moco.gemspec +35 -0
- data/moco.rb +35 -0
- data/src/error/error.coffee +49 -0
- data/src/reload.applescript +135 -0
- data/test/ansi_escape_test.rb +52 -0
- data/test/application_test.rb +40 -0
- data/test/browser_error_test.rb +101 -0
- data/test/browser_test.rb +29 -0
- data/test/compile_error_test.rb +82 -0
- data/test/compiler_option_test.rb +121 -0
- data/test/compiler_register_test.rb +41 -0
- data/test/compiler_test.rb +243 -0
- data/test/compilers/coffee_compiler_test.rb +117 -0
- data/test/compilers/haml_compiler_test.rb +86 -0
- data/test/compilers/less_compiler_test.rb +72 -0
- data/test/compilers/markdown_compiler_test.rb +211 -0
- data/test/compilers/sass_compiler_test.rb +84 -0
- data/test/file_util_test.rb +37 -0
- data/test/fixtures/_color.scss +1 -0
- data/test/fixtures/color.less +1 -0
- data/test/fixtures/css_lib.rb +2 -0
- data/test/fixtures/html_lib.rb +2 -0
- data/test/fixtures/js_lib.rb +2 -0
- data/test/fixtures/layout.html +13 -0
- data/test/fixtures/moco.rb +8 -0
- data/test/fixtures/options_lib.rb +2 -0
- data/test/fixtures/source.txt +1 -0
- data/test/monitor_test.rb +68 -0
- data/test/options_test.rb +177 -0
- data/test/test_helper.rb +57 -0
- metadata +270 -0
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe Compiler do
|
6
|
+
|
7
|
+
describe 'require libraries' do
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift(fixtures_path)
|
10
|
+
|
11
|
+
it 'will not require the library at the time of registration' do
|
12
|
+
JsCompiler.require_library('js_lib')
|
13
|
+
refute defined? JsLib
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'requires the library when the compiler is instantiated' do
|
17
|
+
CssCompiler.require_library('css_lib')
|
18
|
+
refute defined? CssLib
|
19
|
+
CssCompiler.new('')
|
20
|
+
assert defined? CssLib
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'requires the superclass libraries' do
|
24
|
+
HtmlCompiler.require_library('html_lib')
|
25
|
+
refute defined? HtmlLib
|
26
|
+
Class.new(Class.new(HtmlCompiler)).new('')
|
27
|
+
assert defined? HtmlLib
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'require uninstalled libraries' do
|
33
|
+
|
34
|
+
class CorruptCompiler < HtmlCompiler
|
35
|
+
require_library 'not_installed', 'not-installed-gem', '~> 2'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises a LoadError with installation instructions' do
|
39
|
+
e = assert_raises(Gem::LoadError) { CorruptCompiler.new('') }
|
40
|
+
assert_match "gem install not-installed-gem -v '~> 2'", e.message
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'compiler options' do
|
46
|
+
|
47
|
+
after { reset_options(HtmlCompiler) }
|
48
|
+
|
49
|
+
it 'sets the option' do
|
50
|
+
HtmlCompiler.set_option(:format, :html5)
|
51
|
+
assert_equal :html5, HtmlCompiler.options[:format]
|
52
|
+
assert_equal :html5, HtmlCompiler.new('').options[:format]
|
53
|
+
end
|
54
|
+
|
55
|
+
specify 'the default value is true' do
|
56
|
+
HtmlCompiler.set_option(:ugly)
|
57
|
+
assert_equal true, HtmlCompiler.options[:ugly]
|
58
|
+
end
|
59
|
+
|
60
|
+
specify 'updating the options hash directly has no effect' do
|
61
|
+
HtmlCompiler.options[:format] = :xhtml
|
62
|
+
compiler = HtmlCompiler.new('')
|
63
|
+
compiler.options[:format] = :xhtml
|
64
|
+
assert_empty HtmlCompiler.options
|
65
|
+
assert_empty compiler.options
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'the compiled filename' do
|
71
|
+
|
72
|
+
it 'cannot be equal to the source filename' do
|
73
|
+
e = assert_raises(Error) do
|
74
|
+
HtmlCompiler.new('index.html', Dir.pwd + '/index.html')
|
75
|
+
end
|
76
|
+
assert_match 'validate_filenames', e.backtrace.first
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'will keep the compiled filename unchanged, if provided' do
|
80
|
+
compiler = HtmlCompiler.new('source.md', 'compiled.xml', 'dir')
|
81
|
+
assert_equal 'compiled.xml', compiler.compiled_file
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'the compiled filename extension' do
|
87
|
+
|
88
|
+
def compiled_file(source_file)
|
89
|
+
JsCompiler.new(source_file).compiled_file
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'has the compiled extension' do
|
93
|
+
assert_equal 'script.js', compiled_file('script.coffee')
|
94
|
+
end
|
95
|
+
|
96
|
+
specify 'the compiler must implement compiled_extension' do
|
97
|
+
e = assert_raises(NotImplementedError) { Compiler.new('') }
|
98
|
+
assert_match 'compiled_extension', e.backtrace.first
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'nested source extension' do
|
102
|
+
|
103
|
+
it 'will not duplicate the compiled extension' do
|
104
|
+
assert_equal 'script.js', compiled_file('script.js.coffee')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'will keep other extensions' do
|
108
|
+
assert_equal 'script.min.js', compiled_file('script.min.coffee')
|
109
|
+
end
|
110
|
+
|
111
|
+
specify 'not duplicate extension' do
|
112
|
+
assert_equal 'about_js.js', compiled_file('about_js.coffee')
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'nested compiled extension' do
|
118
|
+
|
119
|
+
class Minify < JsCompiler
|
120
|
+
define_singleton_method(:compiled_extension) { '.min.js' }
|
121
|
+
end
|
122
|
+
|
123
|
+
specify do
|
124
|
+
assert_equal 'script.min.js', Minify.new('script.js').compiled_file
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
describe 'no extensions' do
|
130
|
+
|
131
|
+
class Readme < Compiler
|
132
|
+
define_singleton_method(:compiled_extension) { '' }
|
133
|
+
end
|
134
|
+
|
135
|
+
specify 'the compiled extension is empty' do
|
136
|
+
assert_equal 'README', Readme.new('README.txt').compiled_file
|
137
|
+
end
|
138
|
+
|
139
|
+
specify 'the source file has no extension' do
|
140
|
+
assert_equal 'README.html', HtmlCompiler.new('README').compiled_file
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'the compiled filename directory' do
|
148
|
+
|
149
|
+
def compiled_file(source_file, compiled_dir = nil)
|
150
|
+
CssCompiler.new(source_file, nil, compiled_dir).compiled_file
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'has the same directory as the source file by default' do
|
154
|
+
assert_equal 'css/style.css', compiled_file('css/style.sass')
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'replaces the directory if one is provided' do
|
158
|
+
assert_equal 'css/style.css', compiled_file('style.scss', 'css')
|
159
|
+
assert_equal 'css/style.css', compiled_file('/sass/style.scss', 'css/')
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'removes the source directory if compiled_dir is empty' do
|
163
|
+
assert_equal 'style.css', compiled_file('templates/style.scss', '')
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
describe 'compile' do
|
169
|
+
|
170
|
+
class GoodCompiler < Compiler
|
171
|
+
define_method(:compiled_text) { 'The compiled text' }
|
172
|
+
end
|
173
|
+
|
174
|
+
let(:compiler) do
|
175
|
+
GoodCompiler.new(fixtures_path('source.txt'), tmp_dir + '/dir/out.txt')
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'reads the source file' do
|
179
|
+
assert_equal 'The source text', compiler.source_text
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'makes the necessary directories for the compiled file' do
|
183
|
+
compiler.compile
|
184
|
+
assert File.directory?(File.dirname(compiler.compiled_file))
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'writes the compiled text to the compiled file' do
|
188
|
+
compiler.compile
|
189
|
+
assert_equal 'The compiled text', File.read(compiler.compiled_file)
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
describe 'failed compilation' do
|
195
|
+
|
196
|
+
class BadCompiler < Compiler
|
197
|
+
define_method(:compiled_text) { raise 'The error text' }
|
198
|
+
end
|
199
|
+
|
200
|
+
let(:compiler) { BadCompiler.new('', tmp_dir + '/dir/out.txt') }
|
201
|
+
|
202
|
+
it 'raises a CompileError' do
|
203
|
+
assert_raises(CompileError) { compiler.compile }
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'writes the error message to the compiled file' do
|
207
|
+
compiler.compile rescue
|
208
|
+
assert_equal 'The error text', File.read(compiler.compiled_file)
|
209
|
+
end
|
210
|
+
|
211
|
+
specify 'the compiler must implement compiled_text' do
|
212
|
+
e = assert_raises(NotImplementedError) { JsCompiler.new('').compile }
|
213
|
+
assert_match 'compiled_text', e.backtrace.first
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
describe 'should_compile?' do
|
219
|
+
|
220
|
+
let(:compiler) { JsCompiler.new(tmp_dir + '/script.coffee') }
|
221
|
+
|
222
|
+
it 'is true if the compiled file does not exist' do
|
223
|
+
touch(compiler.source_file)
|
224
|
+
assert compiler.should_compile?
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'is true when the source file is updated' do
|
228
|
+
touch(compiler.compiled_file, :mtime => 0)
|
229
|
+
touch(compiler.source_file, :mtime => 1)
|
230
|
+
assert compiler.should_compile?
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'is false if the compiled file is up to date' do
|
234
|
+
touch(compiler.source_file)
|
235
|
+
touch(compiler.compiled_file)
|
236
|
+
refute compiler.should_compile?
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe CoffeeCompiler do
|
6
|
+
|
7
|
+
let(:compiler) { mock_compiler(CoffeeCompiler, 'alert yes') }
|
8
|
+
let(:compiled_text) { compiler.compiled_text }
|
9
|
+
|
10
|
+
it 'is registered for coffee files' do
|
11
|
+
assert_equal CoffeeCompiler, MoCo.compiler_for('coffee')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'is a JavaScript compiler' do
|
15
|
+
assert CoffeeCompiler < JsCompiler
|
16
|
+
assert_equal 'js', CoffeeCompiler.compiled_extension
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'compiles CoffeeScript into JavaScript' do
|
20
|
+
assert_match 'alert(true);', compiled_text
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'options' do
|
24
|
+
|
25
|
+
after { reset_options(CoffeeCompiler) }
|
26
|
+
|
27
|
+
it 'has a function wrapper by default' do
|
28
|
+
assert compiled_text.start_with?('(function() {')
|
29
|
+
assert compiled_text.strip.end_with?('}).call(this);')
|
30
|
+
end
|
31
|
+
|
32
|
+
specify 'the bare option disables the function wrapper' do
|
33
|
+
CoffeeCompiler.set_option(:bare)
|
34
|
+
assert_equal 'alert(true);', compiled_text.strip
|
35
|
+
end
|
36
|
+
|
37
|
+
specify 'the header includes the version number' do
|
38
|
+
CoffeeCompiler.set_option(:header)
|
39
|
+
version = CoffeeCompiler.context.run('return CoffeeScript.VERSION;')
|
40
|
+
assert_match "// Generated by CoffeeScript #{version}", compiled_text
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'source maps' do
|
46
|
+
|
47
|
+
before { CoffeeCompiler.set_option(:sourceMap) }
|
48
|
+
after { reset_options(CoffeeCompiler) }
|
49
|
+
|
50
|
+
let(:compiler) do
|
51
|
+
mock_compiler(CoffeeCompiler, 'alert', 'app.coffee', 'dir/the app.js')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'produces a source map with relative paths' do
|
55
|
+
compiler.compile
|
56
|
+
map = JSON.load(compiler.source_map_text)
|
57
|
+
assert_equal 3, map['version']
|
58
|
+
assert_equal 'the app.js', map['file']
|
59
|
+
assert_equal '../app.coffee', map['sources'].first
|
60
|
+
assert_match 'AAA', map['mappings']
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'adds a comment, with the source map URI, to the compiled text' do
|
64
|
+
assert_match '//@ sourceMappingURL=the%20app.js.map', compiled_text
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'will be saved to the same directory as the compiled file' do
|
68
|
+
assert_equal File.dirname(compiler.source_map_file),
|
69
|
+
File.dirname(compiler.compiled_file)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'writes the source map file' do
|
73
|
+
compiler = CoffeeCompiler.new('/script.coffee', nil, tmp_dir)
|
74
|
+
compiler.define_singleton_method(:source_text) { 'alert' }
|
75
|
+
compiler.compile
|
76
|
+
assert_equal compiler.source_map_text, File.read(compiler.source_map_file)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'compile error' do
|
82
|
+
|
83
|
+
let(:compiler) { mock_compiler(CoffeeCompiler, 'evil = (eval) ->') }
|
84
|
+
let(:error) { compiler.compile rescue $! }
|
85
|
+
|
86
|
+
it 'raises a CompileError' do
|
87
|
+
assert_raises(CompileError) { compiler.compile }
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'captures the error location' do
|
91
|
+
assert_equal 1, error.line
|
92
|
+
assert_equal 9, error.column
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'the error message' do
|
96
|
+
|
97
|
+
it 'removes the filename and location from the original message' do
|
98
|
+
message = error.error.message
|
99
|
+
assert message.start_with?('mock.coffee:1:9: error: parameter name')
|
100
|
+
|
101
|
+
message = error.message
|
102
|
+
assert message.start_with?('Parameter name')
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'marks the erroneous code with red (using ANSI escape codes)' do
|
106
|
+
message = error.message.split("\n")
|
107
|
+
assert_equal "evil = (\e[1;31meval\e[0m) ->", message[-2]
|
108
|
+
assert_equal "\e[1;31m ^^^^\e[0m" , message[-1]
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end if run_compiler_tests?(CoffeeCompiler)
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe HamlCompiler do
|
6
|
+
|
7
|
+
let(:compiler) { mock_compiler(HamlCompiler, '#haml= 2 + 2') }
|
8
|
+
|
9
|
+
it 'is registered for haml files' do
|
10
|
+
assert_equal HamlCompiler, MoCo.compiler_for('haml')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is a Html compiler' do
|
14
|
+
assert HamlCompiler < HtmlCompiler
|
15
|
+
assert_equal 'html', HamlCompiler.compiled_extension
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'compiles haml into html' do
|
19
|
+
assert_equal "<div id='haml'>4</div>", compiler.compiled_text.strip
|
20
|
+
end
|
21
|
+
|
22
|
+
specify 'options are passed on to the haml compiler' do
|
23
|
+
HamlCompiler.set_option(:attr_wrapper, '@')
|
24
|
+
assert_match '<div id=@haml@>', compiler.compiled_text
|
25
|
+
reset_options(HamlCompiler)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'compile error' do
|
29
|
+
|
30
|
+
def compile(haml)
|
31
|
+
mock_compiler(HamlCompiler, haml, 'mock.haml').compile
|
32
|
+
rescue CompileError => error
|
33
|
+
error
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'removes the filename and line number from the error message' do
|
37
|
+
error = compile('.haml= [}')
|
38
|
+
refute_match 'mock.haml', error.message
|
39
|
+
refute_match /[:\d]/, error.message
|
40
|
+
|
41
|
+
# The original error
|
42
|
+
assert_match 'mock.haml:1:', error.error.message
|
43
|
+
assert_match 'mock.haml:2:', error.error.message
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'the line number' do
|
47
|
+
|
48
|
+
specify 'line numbers fetched from @line start at 1' do
|
49
|
+
error = compile(' %p')
|
50
|
+
assert_equal 1, error.line
|
51
|
+
|
52
|
+
# The original error
|
53
|
+
assert error.error.line
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'finds the line number in the backtrace' do
|
57
|
+
error = compile("\n.time= Date.tomorrow")
|
58
|
+
assert_equal 2, error.line
|
59
|
+
|
60
|
+
# The original error
|
61
|
+
refute defined? error.error.line
|
62
|
+
assert_match 'mock.haml:2:', error.error.backtrace.first
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'finds the line number in the error message' do
|
66
|
+
error = compile("\n\n.unbalanced= [}")
|
67
|
+
assert_equal 3, error.line
|
68
|
+
|
69
|
+
# The original error
|
70
|
+
assert_nil error.error.line
|
71
|
+
refute_match ':3:', error.error.backtrace.to_s
|
72
|
+
assert_match 'mock.haml:3:', error.error.message
|
73
|
+
end
|
74
|
+
|
75
|
+
specify 'line can be nil' do
|
76
|
+
error = compile("%p= eval '2 *** 10'")
|
77
|
+
assert_nil error.line
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end if run_compiler_tests?(HamlCompiler)
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe LessCompiler do
|
6
|
+
|
7
|
+
it 'is registered for less files' do
|
8
|
+
assert_equal LessCompiler, MoCo.compiler_for('less')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'is a CSS compiler' do
|
12
|
+
assert LessCompiler < CssCompiler
|
13
|
+
assert_equal 'css', LessCompiler.compiled_extension
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'compile' do
|
17
|
+
|
18
|
+
css = <<-EOF
|
19
|
+
.less {
|
20
|
+
color: #d9eef2;
|
21
|
+
}
|
22
|
+
EOF
|
23
|
+
|
24
|
+
less = <<-EOF
|
25
|
+
@blue: #D9EEF2;
|
26
|
+
.less {
|
27
|
+
color: @blue;
|
28
|
+
}
|
29
|
+
EOF
|
30
|
+
|
31
|
+
import = <<-EOF
|
32
|
+
@import 'color';
|
33
|
+
.less {
|
34
|
+
color: @blue;
|
35
|
+
}
|
36
|
+
EOF
|
37
|
+
|
38
|
+
[css, less, import].each { |style| style.gsub!(/^ {8}/, '') }
|
39
|
+
|
40
|
+
it 'compiles less into css' do
|
41
|
+
compiler = mock_compiler(LessCompiler, less)
|
42
|
+
assert_equal css, compiler.compiled_text
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'handles the @import directive' do
|
46
|
+
LessCompiler.set_option(:paths, [fixtures_path])
|
47
|
+
compiler = mock_compiler(LessCompiler, import)
|
48
|
+
assert_equal css, compiler.compiled_text
|
49
|
+
reset_options(LessCompiler)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'compile error' do
|
55
|
+
|
56
|
+
let(:compiler) do
|
57
|
+
mock_compiler(LessCompiler, '.less { color: @pink; }')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'raises a CompileError' do
|
61
|
+
assert_raises(CompileError) { compiler.compile }
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'has a line number' do
|
65
|
+
assert_equal 1, (compiler.compile rescue $!).line
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end if run_compiler_tests?(LessCompiler)
|
71
|
+
|
72
|
+
end
|