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,211 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe MarkdownCompiler do
|
6
|
+
|
7
|
+
after { reset_options(MarkdownCompiler) }
|
8
|
+
|
9
|
+
let(:markdown) { '#Title' }
|
10
|
+
let(:compiler) { mock_compiler(MarkdownCompiler, markdown) }
|
11
|
+
let(:compiled_text) { compiler.compiled_text.strip }
|
12
|
+
|
13
|
+
it 'is registered for md and markdown files' do
|
14
|
+
assert_equal MarkdownCompiler, MoCo.compiler_for('md')
|
15
|
+
assert_equal MarkdownCompiler, MoCo.compiler_for('markdown')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'is a Html compiler' do
|
19
|
+
assert MarkdownCompiler < HtmlCompiler
|
20
|
+
assert_equal 'html', MarkdownCompiler.compiled_extension
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'compiles markdown into html' do
|
24
|
+
assert_equal '<h1>Title</h1>', compiled_text
|
25
|
+
end
|
26
|
+
|
27
|
+
specify 'the options are used to specify markdown extensions' do
|
28
|
+
MarkdownCompiler.set_option(:space_after_headers)
|
29
|
+
assert_equal '<p>#Title</p>', compiled_text
|
30
|
+
end
|
31
|
+
|
32
|
+
specify 'the options are passed on to the html renderer' do
|
33
|
+
MarkdownCompiler.set_option(:with_toc_data)
|
34
|
+
assert_equal '<h1 id="toc_0">Title</h1>', compiled_text
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'the :smarty option' do
|
38
|
+
|
39
|
+
before { MarkdownCompiler.set_option(:smarty) }
|
40
|
+
|
41
|
+
let(:markdown) { '# ...' }
|
42
|
+
|
43
|
+
it 'performs SmartyPants substitutions' do
|
44
|
+
assert_equal '<h1>…</h1>', compiled_text
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'works with the Pygments renderer' do
|
48
|
+
MarkdownCompiler.set_option(:pygments)
|
49
|
+
assert_equal '<h1>…</h1>', compiled_text
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'works with the table of contents renderer' do
|
53
|
+
MarkdownCompiler.set_option(:toc)
|
54
|
+
assert_match '<a href="#toc_0">…</a>', compiled_text
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'the :toc option' do
|
60
|
+
|
61
|
+
before { MarkdownCompiler.set_option(:toc) }
|
62
|
+
|
63
|
+
it 'produces a table of contents' do
|
64
|
+
assert_match '<a href="#toc_0">Title</a>', compiled_text
|
65
|
+
assert_match '<h1 id="toc_0">Title</h1>', compiled_text
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'the :layout option' do
|
71
|
+
|
72
|
+
before { MarkdownCompiler.set_option(:layout, layout_file) }
|
73
|
+
|
74
|
+
let(:layout_file) { fixtures_path('layout.html') }
|
75
|
+
let(:layout) { File.read(layout_file) }
|
76
|
+
|
77
|
+
it 'replaces {{BODY}} with the rendered markdown' do
|
78
|
+
assert_match '<article>{{BODY}}</article>', layout
|
79
|
+
assert_match "<article><h1>Title</h1>\n</article>", compiled_text
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '{{TOC}}' do
|
83
|
+
|
84
|
+
before { MarkdownCompiler.set_option(:toc) }
|
85
|
+
|
86
|
+
it 'replaces {{TOC}} with the table of contents' do
|
87
|
+
assert_match '<nav>{{TOC}}</nav>', layout
|
88
|
+
assert_match "<nav><ul>\n<li>\n<a href", compiled_text
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'removes {{TOC}} if there is no table of contents' do
|
92
|
+
MarkdownCompiler.set_option(:toc, false)
|
93
|
+
assert_match '<nav></nav>', compiled_text
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'adds the toc to the {{BODY}} if there is no {{TOC}} tag' do
|
97
|
+
layout_file = tmp_dir + '/layout.html'
|
98
|
+
FileUtil.write(layout_file, layout.sub('{{TOC}}', ''))
|
99
|
+
|
100
|
+
MarkdownCompiler.set_option(:layout, layout_file)
|
101
|
+
assert_match "<article><ul>\n<li>\n<a href=", compiled_text
|
102
|
+
assert_match "Title</h1>\n</article>", compiled_text
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '{{TITLE}}' do
|
108
|
+
|
109
|
+
it 'replaces {{TITLE}} with the first h1 element' do
|
110
|
+
assert_match '<title>{{TITLE}}</title>', layout
|
111
|
+
assert_match '<title>Title</title>', compiled_text
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'accepts an h1 element with attributes' do
|
115
|
+
MarkdownCompiler.set_option(:toc)
|
116
|
+
assert_match '<title>Title</title>', compiled_text
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'removes nested tags from the title' do
|
120
|
+
markdown = '# The [![Home](logo.png)](/index.html) Title'
|
121
|
+
compiler = mock_compiler(MarkdownCompiler, markdown)
|
122
|
+
assert_match '<title>The Title</title>', compiler.compiled_text
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'replaces {{TITLE}} with the filename if there are no h1 elements' do
|
126
|
+
compiler = mock_compiler(MarkdownCompiler, '## h2')
|
127
|
+
assert_match '<title>mock.md</title>', compiler.compiled_text
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'replaces {{FILE}} with the filename' do
|
133
|
+
assert_match '<span>{{FILE}}</span>', layout
|
134
|
+
assert_match '<span>mock.md</span>', compiled_text
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'the :pygments option' do
|
140
|
+
|
141
|
+
before { MarkdownCompiler.set_option(:pygments) }
|
142
|
+
|
143
|
+
def code_block(statement, language)
|
144
|
+
code_block = "```#{language}\n#{statement}\n```"
|
145
|
+
mock_compiler(MarkdownCompiler, code_block).compiled_text.strip
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'adds syntax highlighting hooks to fenced code blocks' do
|
149
|
+
expected = '<div class="highlight"><pre><span class="nb">puts</span>'
|
150
|
+
assert_match expected, code_block('puts', 'RUBY')
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'ignores code blocks with no language specified' do
|
154
|
+
expected = "<pre><code>puts\n</code></pre>"
|
155
|
+
assert_equal expected, code_block('puts', nil)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'adds a class for unknown languages' do
|
159
|
+
expected = "<pre><code class=\"dummy\">puts\n</code></pre>"
|
160
|
+
assert_equal expected, code_block('puts', 'dummy')
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'escapes the html' do
|
164
|
+
expected = '"'<&>'
|
165
|
+
assert_match expected, code_block(%("'<&>'"), 'ruby')
|
166
|
+
assert_match expected, code_block(%("'<&>'"), nil)
|
167
|
+
end
|
168
|
+
|
169
|
+
describe 'the :pygments options are passed on to Pygments' do
|
170
|
+
|
171
|
+
let(:markdown) { "```ruby\nputs\nputs\nputs\nputs\n\n```" }
|
172
|
+
|
173
|
+
it 'accepts a Hash' do
|
174
|
+
MarkdownCompiler.set_option(:pygments, :linenos => 'inline')
|
175
|
+
assert_equal 'inline', MarkdownCompiler.options[:pygments][:linenos]
|
176
|
+
assert_match '<span class="lineno">1</span>', compiled_text
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'accepts an Array' do
|
180
|
+
MarkdownCompiler.set_option(:pygments, [:hl_lines, 2, 3])
|
181
|
+
assert_equal [2, 3], MarkdownCompiler.options[:pygments][:hl_lines]
|
182
|
+
compiled_text.split(/\n/).each_with_index do |line, index|
|
183
|
+
if [2, 3].include?(index + 1)
|
184
|
+
assert_match '<span class="hll">', line
|
185
|
+
else
|
186
|
+
refute_match '<span class="hll">', line
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'can set an option to false' do
|
192
|
+
MarkdownCompiler.set_option(:pygments, ['stripnl', false])
|
193
|
+
assert_equal false, MarkdownCompiler.options[:pygments]['stripnl']
|
194
|
+
assert_match "\n\n</pre></div>", compiled_text
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'can be repeated' do
|
198
|
+
MarkdownCompiler.set_option(:pygments, 'noclasses')
|
199
|
+
MarkdownCompiler.set_option(:pygments, ['style', 'vim'])
|
200
|
+
assert_equal true, MarkdownCompiler.options[:pygments]['noclasses']
|
201
|
+
assert_equal 'vim', MarkdownCompiler.options[:pygments]['style']
|
202
|
+
assert_match '<span style="color: #cd00cd">puts', compiled_text
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end if run_compiler_tests?(MarkdownCompiler)
|
210
|
+
|
211
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe SassCompiler do
|
6
|
+
|
7
|
+
it 'is registered for sass and scss files' do
|
8
|
+
assert_equal SassCompiler, MoCo.compiler_for('sass')
|
9
|
+
assert_equal SassCompiler, MoCo.compiler_for('scss')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'is a CSS compiler' do
|
13
|
+
assert SassCompiler < CssCompiler
|
14
|
+
assert_equal 'css', SassCompiler.compiled_extension
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'selects the correct syntax' do
|
18
|
+
assert_equal :sass, SassCompiler.new('style.sass').options[:syntax]
|
19
|
+
assert_equal :scss, SassCompiler.new('style.scss').options[:syntax]
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'compile' do
|
23
|
+
|
24
|
+
css = <<-EOF
|
25
|
+
.sass {
|
26
|
+
color: #ce4dd6; }
|
27
|
+
EOF
|
28
|
+
|
29
|
+
sass = <<-EOF
|
30
|
+
$pink: #CE4DD6
|
31
|
+
.sass
|
32
|
+
color: $pink
|
33
|
+
EOF
|
34
|
+
|
35
|
+
scss = <<-EOF
|
36
|
+
$pink: #CE4DD6;
|
37
|
+
.sass { color: $pink; }
|
38
|
+
EOF
|
39
|
+
|
40
|
+
import = <<-EOF
|
41
|
+
@import 'color';
|
42
|
+
.sass { color: $pink; }
|
43
|
+
EOF
|
44
|
+
|
45
|
+
[css, sass, scss, import].each { |style| style.gsub!(/^ {8}/, '') }
|
46
|
+
|
47
|
+
it 'compiles sass into css' do
|
48
|
+
compiler = mock_compiler(SassCompiler, sass, 'style.sass')
|
49
|
+
assert_equal css, compiler.compiled_text
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'compiles scss into css' do
|
53
|
+
compiler = mock_compiler(SassCompiler, scss, 'style.scss')
|
54
|
+
assert_equal css, compiler.compiled_text
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'handles the @import directive' do
|
58
|
+
SassCompiler.set_option(:load_paths, [fixtures_path])
|
59
|
+
compiler = mock_compiler(SassCompiler, import, 'style.scss')
|
60
|
+
assert_equal css, compiler.compiled_text
|
61
|
+
reset_options(SassCompiler)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'compile error' do
|
67
|
+
|
68
|
+
let(:compiler) do
|
69
|
+
mock_compiler(SassCompiler, '.sass { color: $blue; }', 'style.scss')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'raises a CompileError' do
|
73
|
+
assert_raises(CompileError) { compiler.compile }
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'has a line number' do
|
77
|
+
assert_equal 1, (compiler.compile rescue $!).line
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end if run_compiler_tests?(SassCompiler)
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe FileUtil do
|
6
|
+
|
7
|
+
describe 'normalized extension' do
|
8
|
+
|
9
|
+
specify do
|
10
|
+
assert_equal 'less', FileUtil.normalized_extension('less')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'removes the period' do
|
14
|
+
assert_equal 'less', FileUtil.normalized_extension('.less')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'accepts a symbol' do
|
18
|
+
assert_equal 'less', FileUtil.normalized_extension(:less)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'accepts a filename' do
|
22
|
+
assert_equal 'sass', FileUtil.normalized_extension('/dir/file.sass')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'works with spaces' do
|
26
|
+
assert_equal 'sass', FileUtil.normalized_extension(' file with spaces .sass ')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'works with nested extensions' do
|
30
|
+
assert_equal 'sass', FileUtil.normalized_extension('file.css.sass')
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
$pink: #CE4DD6;
|
@@ -0,0 +1 @@
|
|
1
|
+
@blue: #D9EEF2;
|
@@ -0,0 +1 @@
|
|
1
|
+
The source text
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe Monitor do
|
6
|
+
|
7
|
+
before { skip unless __FILE__ == $0 }
|
8
|
+
|
9
|
+
def tmp
|
10
|
+
Pathname.new(tmp_dir).realpath().to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def updated(&block)
|
14
|
+
updated = []
|
15
|
+
thread = Thread.new do
|
16
|
+
monitor.monitor { |file| updated << file }
|
17
|
+
end
|
18
|
+
sleep 0.05
|
19
|
+
yield
|
20
|
+
sleep 0.5
|
21
|
+
thread.kill
|
22
|
+
updated.sort
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:dirs) { [tmp, tmp].sort }
|
26
|
+
let(:files) { %W[#{dirs[0]}/file.haml #{dirs[1]}/nested/dir/file.sass] }
|
27
|
+
let(:txt_file) { "#{dirs[1]}/file.txt" }
|
28
|
+
|
29
|
+
describe 'monitor directories' do
|
30
|
+
|
31
|
+
let(:monitor) { Monitor.new([], dirs, [:sass, :haml]) }
|
32
|
+
|
33
|
+
it 'captures new files' do
|
34
|
+
assert_equal files, updated { touch(files) }
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'captures file updates' do
|
38
|
+
touch(files, :mtime => 0)
|
39
|
+
assert_equal files, updated { touch(files) }
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'ignores files with other extensions' do
|
43
|
+
assert_empty updated { touch(txt_file) }
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'lists all the files currently being monitored' do
|
47
|
+
Dir.mkdir("#{dirs[0]}/dir.sass")
|
48
|
+
assert_empty monitor.files
|
49
|
+
touch(files + [txt_file])
|
50
|
+
assert_equal files, monitor.files.sort
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'monitor files' do
|
56
|
+
|
57
|
+
let(:monitor) { Monitor.new(files, [], []) }
|
58
|
+
|
59
|
+
it 'captures file updates' do
|
60
|
+
touch(files, :mtime => 0)
|
61
|
+
assert_equal files, updated { touch(files + [txt_file]) }
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MoCo
|
4
|
+
|
5
|
+
describe Options do
|
6
|
+
|
7
|
+
class MockOptions < Options
|
8
|
+
define_method(:load_moco_files) {}
|
9
|
+
define_method(:validate_files) {}
|
10
|
+
define_method(:display_help) {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(args = '')
|
14
|
+
MockOptions.parse(args.shellsplit)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'parse command line options' do
|
18
|
+
|
19
|
+
it 'sets the default options' do
|
20
|
+
assert_equal Options.new.default_options, parse
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'sets boolean options' do
|
24
|
+
assert_equal true, parse('--force')[:force]
|
25
|
+
assert_equal false, parse('--no-force')[:force]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'sets array options' do
|
29
|
+
assert_equal %w[Chrome], parse('-b Chrome')[:browsers]
|
30
|
+
assert_equal %w[Chrome], parse('-b Chrome,Chrome')[:browsers]
|
31
|
+
assert_equal %w[Chrome Opera], parse('-b Chrome,Opera')[:browsers]
|
32
|
+
assert_equal %w[Chrome Opera], parse('-b Chrome -b Opera')[:browsers]
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'the compile option' do
|
36
|
+
|
37
|
+
it 'sets the compile flag' do
|
38
|
+
assert_equal true, parse('-c sass')[:compile]
|
39
|
+
assert_equal true, parse('--compile')[:compile]
|
40
|
+
assert_equal false, parse('--no-compile')[:compile]
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'sets the compile extensions' do
|
44
|
+
assert_equal ['sass'], parse('--compile .sass')[:compile_exts]
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'raises an OptionError if an extension is unregistered' do
|
48
|
+
assert_raises(OptionError) { parse('-c cofe') }
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'setting compiler options' do
|
54
|
+
|
55
|
+
it 'sets the options' do
|
56
|
+
parse('--option haml:ugly -o haml:preserve:pre:code')
|
57
|
+
assert_equal true, HamlCompiler.options[:ugly]
|
58
|
+
assert_equal %w[pre code], HamlCompiler.options[:preserve]
|
59
|
+
reset_options(HamlCompiler)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises an OptionError if the option key is missing' do
|
63
|
+
assert_raises(OptionError) { parse('-o haml') }
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'raises an OptionError if the extension is unregistered' do
|
67
|
+
assert_raises(OptionError) { parse('-o aml:ugly') }
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'sets the source map flag' do
|
73
|
+
parse('--source-map')
|
74
|
+
assert_equal true, CoffeeCompiler.options[:sourceMap]
|
75
|
+
reset_options(CoffeeCompiler)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'requires the library' do
|
79
|
+
refute defined? OptionsLib
|
80
|
+
parse('--require ' + fixtures_path('options_lib'))
|
81
|
+
assert defined? OptionsLib
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'parse command line path arguments' do
|
87
|
+
|
88
|
+
before { MockOptions.send(:define_method, :validate_files) { super() } }
|
89
|
+
after { MockOptions.send(:define_method, :validate_files) {} }
|
90
|
+
|
91
|
+
let(:dir) { fixtures_path }
|
92
|
+
let(:file) { fixtures_path('moco.rb') }
|
93
|
+
|
94
|
+
it 'sets the source files and directories' do
|
95
|
+
assert_equal [file], parse("#{dir} #{file}")[:source_files]
|
96
|
+
assert_equal [dir], parse("#{dir} #{file}")[:source_dirs]
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'sets the compiled files and directories' do
|
100
|
+
assert_equal '/file', parse("#{file}:/file")[:compiled_files][file]
|
101
|
+
assert_equal '/dir', parse("#{dir}:/dir")[:compiled_dirs][dir]
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'raises an OptionError if no path is provided' do
|
105
|
+
assert_raises(OptionError) { parse }
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'raises an OptionError if the path does not exists' do
|
109
|
+
assert_raises(OptionError) { parse('no_such_file') }
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'raises an OptionError if the compiled file is a directory' do
|
113
|
+
assert_raises(OptionError) { parse("#{file}:#{dir}") }
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'raises an OptionError if the compiled directory is a file' do
|
117
|
+
assert_raises(OptionError) { parse("#{dir}:#{file}") }
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
describe 'the moco file' do
|
123
|
+
|
124
|
+
before do
|
125
|
+
moco_file = fixtures_path('moco.rb')
|
126
|
+
MockOptions.send(:define_method, :load_moco_files) { load moco_file }
|
127
|
+
end
|
128
|
+
|
129
|
+
after do
|
130
|
+
MockOptions.send(:define_method, :load_moco_files) {}
|
131
|
+
Options.instance_variable_set(:@args, nil)
|
132
|
+
reset_register
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'can register new compilers' do
|
136
|
+
parse
|
137
|
+
assert_equal TextCompiler, MoCo.compiler_for('txt')
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'sets compiler options' do
|
141
|
+
parse
|
142
|
+
assert_equal ['pre'], TextCompiler.options[:preserve]
|
143
|
+
assert_equal :html5, TextCompiler.options[:format]
|
144
|
+
assert_equal true, TextCompiler.options[:ugly]
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'sets general options' do
|
148
|
+
assert_equal false, parse[:reload]
|
149
|
+
end
|
150
|
+
|
151
|
+
specify 'the command line options have precedence' do
|
152
|
+
assert_equal true, parse('-r -o txt:format:xml')[:reload]
|
153
|
+
assert_equal 'xml', TextCompiler.options[:format]
|
154
|
+
end
|
155
|
+
|
156
|
+
specify 'MoCo.args expects a shell escaped string' do
|
157
|
+
MoCo.args(%(-o txt:foo:'The "Quote"'))
|
158
|
+
MoCo.args(%(-o txt:bar:The\\ \\"Quote\\"))
|
159
|
+
parse
|
160
|
+
assert_equal 'The "Quote"', TextCompiler.options[:foo]
|
161
|
+
assert_equal 'The "Quote"', TextCompiler.options[:bar]
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'finds the moco files in the current working directory' do
|
165
|
+
current_dir = Dir.pwd
|
166
|
+
Dir.chdir(tmp_dir)
|
167
|
+
touch([Dir.pwd + '/moco.rb', Dir.pwd + '/.moco'])
|
168
|
+
assert_includes Options.moco_files, Dir.pwd + '/moco.rb'
|
169
|
+
assert_includes Options.moco_files, Dir.pwd + '/.moco'
|
170
|
+
Dir.chdir(current_dir)
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path('../../lib/moco', __FILE__)
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
COMPILERS = MoCo.compilers
|
6
|
+
TMP_DIR = Dir.mktmpdir('MoCo')
|
7
|
+
|
8
|
+
MiniTest::Unit.after_tests do
|
9
|
+
FileUtils.rm_rf(TMP_DIR)
|
10
|
+
end
|
11
|
+
|
12
|
+
def tmp_dir
|
13
|
+
Dir.mktmpdir(nil, TMP_DIR)
|
14
|
+
end
|
15
|
+
|
16
|
+
def fixtures_path(file = nil)
|
17
|
+
fixtures_dir = File.expand_path('../fixtures', __FILE__)
|
18
|
+
file ? File.join(fixtures_dir, file) : fixtures_dir
|
19
|
+
end
|
20
|
+
|
21
|
+
def touch(files, options = {})
|
22
|
+
Array(files).each do |file|
|
23
|
+
FileUtils.makedirs(File.dirname(file))
|
24
|
+
FileUtils.touch(file, options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_register
|
29
|
+
register = MoCo::CompilerRegister.instance
|
30
|
+
register.instance_variable_set(:@compilers, COMPILERS.dup)
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset_options(klass)
|
34
|
+
klass.instance_variable_set(:@options, {})
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_compiler_tests?(klass)
|
38
|
+
klass.new('')
|
39
|
+
rescue LoadError => e
|
40
|
+
warn "Skipping #{klass} tests (#{e.message.split("\n").first})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def mock_compiler(klass, source_text, source_file = nil, compiled_file = nil)
|
44
|
+
source_file ||= "mock.#{MoCo.compilers.invert[klass]}"
|
45
|
+
mock = klass.new(source_file, compiled_file)
|
46
|
+
mock.define_singleton_method(:source_text) { source_text }
|
47
|
+
mock.define_singleton_method(:write_file) { |filename, text| }
|
48
|
+
mock
|
49
|
+
end
|
50
|
+
|
51
|
+
unless respond_to?(:define_singleton_method)
|
52
|
+
Object.send(:define_method, :define_singleton_method) do |name, &block|
|
53
|
+
singleton = class << self; self end
|
54
|
+
singleton.send(:define_method, name, &block)
|
55
|
+
end
|
56
|
+
Object.send(:public, :define_singleton_method)
|
57
|
+
end
|