moco 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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.txt +67 -0
  4. data/Rakefile +15 -0
  5. data/bin/moco +6 -0
  6. data/lib/moco/ansi_escape.rb +37 -0
  7. data/lib/moco/application.rb +109 -0
  8. data/lib/moco/browser.rb +64 -0
  9. data/lib/moco/browser_error.rb +105 -0
  10. data/lib/moco/compile_error.rb +66 -0
  11. data/lib/moco/compiler.rb +151 -0
  12. data/lib/moco/compiler_option.rb +60 -0
  13. data/lib/moco/compiler_register.rb +29 -0
  14. data/lib/moco/compilers/coffee_compiler.rb +70 -0
  15. data/lib/moco/compilers/haml_compiler.rb +21 -0
  16. data/lib/moco/compilers/less_compiler.rb +15 -0
  17. data/lib/moco/compilers/markdown_compiler.rb +139 -0
  18. data/lib/moco/compilers/sass_compiler.rb +25 -0
  19. data/lib/moco/file_util.rb +54 -0
  20. data/lib/moco/log.rb +108 -0
  21. data/lib/moco/monitor.rb +83 -0
  22. data/lib/moco/options.rb +336 -0
  23. data/lib/moco/source_map.rb +22 -0
  24. data/lib/moco/support/error/error.css +22 -0
  25. data/lib/moco/support/error/error.html +7 -0
  26. data/lib/moco/support/error/error.js +58 -0
  27. data/lib/moco/support/reload.scpt +0 -0
  28. data/lib/moco.rb +44 -0
  29. data/moco.gemspec +35 -0
  30. data/moco.rb +35 -0
  31. data/src/error/error.coffee +49 -0
  32. data/src/reload.applescript +135 -0
  33. data/test/ansi_escape_test.rb +52 -0
  34. data/test/application_test.rb +40 -0
  35. data/test/browser_error_test.rb +101 -0
  36. data/test/browser_test.rb +29 -0
  37. data/test/compile_error_test.rb +82 -0
  38. data/test/compiler_option_test.rb +121 -0
  39. data/test/compiler_register_test.rb +41 -0
  40. data/test/compiler_test.rb +243 -0
  41. data/test/compilers/coffee_compiler_test.rb +117 -0
  42. data/test/compilers/haml_compiler_test.rb +86 -0
  43. data/test/compilers/less_compiler_test.rb +72 -0
  44. data/test/compilers/markdown_compiler_test.rb +211 -0
  45. data/test/compilers/sass_compiler_test.rb +84 -0
  46. data/test/file_util_test.rb +37 -0
  47. data/test/fixtures/_color.scss +1 -0
  48. data/test/fixtures/color.less +1 -0
  49. data/test/fixtures/css_lib.rb +2 -0
  50. data/test/fixtures/html_lib.rb +2 -0
  51. data/test/fixtures/js_lib.rb +2 -0
  52. data/test/fixtures/layout.html +13 -0
  53. data/test/fixtures/moco.rb +8 -0
  54. data/test/fixtures/options_lib.rb +2 -0
  55. data/test/fixtures/source.txt +1 -0
  56. data/test/monitor_test.rb +68 -0
  57. data/test/options_test.rb +177 -0
  58. data/test/test_helper.rb +57 -0
  59. 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>&hellip;</h1>', compiled_text
45
+ end
46
+
47
+ it 'works with the Pygments renderer' do
48
+ MarkdownCompiler.set_option(:pygments)
49
+ assert_equal '<h1>&hellip;</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">&hellip;</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 = '&quot;&#39;&lt;&amp;&gt;'
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,2 @@
1
+ class CssLib
2
+ end
@@ -0,0 +1,2 @@
1
+ class HtmlLib
2
+ end
@@ -0,0 +1,2 @@
1
+ class JsLib
2
+ end
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>{{TITLE}}</title>
6
+ <link rel="stylesheet" href="style.css" />
7
+ </head>
8
+ <body>
9
+ <span>{{FILE}}</span>
10
+ <nav>{{TOC}}</nav>
11
+ <article>{{BODY}}</article>
12
+ </body>
13
+ </html>
@@ -0,0 +1,8 @@
1
+ MoCo.args '--no-reload -o txt:preserve:pre: .'
2
+
3
+ class TextCompiler < MoCo::HtmlCompiler
4
+ register 'txt'
5
+ set_option :ugly
6
+ end
7
+
8
+ TextCompiler.set_option(:format, :html5)
@@ -0,0 +1,2 @@
1
+ class OptionsLib
2
+ end
@@ -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
@@ -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