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.
- 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
data/lib/moco/options.rb
ADDED
@@ -0,0 +1,336 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
module MoCo
|
5
|
+
|
6
|
+
class Options
|
7
|
+
|
8
|
+
def self.moco_files
|
9
|
+
files = ['~/.moco', '~/moco.rb', './.moco', './moco.rb']
|
10
|
+
files = files.map { |file| File.expand_path(file) }
|
11
|
+
files.select { |file| File.file?(file) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.args(args)
|
15
|
+
@args ||= []
|
16
|
+
@args += args.shellsplit
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.parse(args)
|
20
|
+
new.parse(args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse(command_line_args)
|
24
|
+
@options = {}
|
25
|
+
args = moco_file_args + command_line_args
|
26
|
+
display_help if args.empty?
|
27
|
+
option_parser.order(args) { |option| path(option) }
|
28
|
+
validate_options
|
29
|
+
default_options.merge(@options)
|
30
|
+
rescue OptionParser::ParseError => e
|
31
|
+
raise OptionError.new(e)
|
32
|
+
end
|
33
|
+
|
34
|
+
def option_parser
|
35
|
+
OptionParser.new do |op|
|
36
|
+
op.version = MoCo::VERSION
|
37
|
+
op.on( '--[no-]monitor', method(:monitor))
|
38
|
+
op.on('-c', '--[no-]compile [EXT,EXT]', method(:compile), Array)
|
39
|
+
op.on('-f', '--[no-]force', method(:force))
|
40
|
+
op.on('-m', '--[no-]source-map', method(:source_map))
|
41
|
+
op.on('-o', '--option EXT:KEY:VAL', method(:compiler_option))
|
42
|
+
op.on('-r', '--[no-]reload [EXT,EXT]', method(:reload), Array)
|
43
|
+
op.on('-b', '--browser BRO,BRO', method(:browsers), Array)
|
44
|
+
op.on('-u', '--url URL,URL', method(:urls), Array)
|
45
|
+
op.on( '--require LIB', method(:require_lib))
|
46
|
+
op.on('-q', '--[no-]quiet', method(:quiet))
|
47
|
+
op.on('-l', '--list', method(:display_list))
|
48
|
+
op.on('-h', '--help', method(:display_help))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def default_options
|
53
|
+
{
|
54
|
+
:monitor => true,
|
55
|
+
:compile => true,
|
56
|
+
:compile_exts => MoCo.compilers.keys.sort,
|
57
|
+
:force => false,
|
58
|
+
:source_map => false,
|
59
|
+
:reload => true,
|
60
|
+
:reload_exts => Browser.extensions,
|
61
|
+
:browsers => Browser.browsers,
|
62
|
+
:urls => Browser.localhost,
|
63
|
+
:quiet => false,
|
64
|
+
:source_files => [],
|
65
|
+
:source_dirs => [],
|
66
|
+
:compiled_files => {},
|
67
|
+
:compiled_dirs => {}
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def help
|
72
|
+
<<-EOF.gsub(/^ {8}/, '').gsub(/`(.+?)`/, AnsiEscape.green('\1'))
|
73
|
+
Usage:
|
74
|
+
`moco [options] SOURCE ...`
|
75
|
+
`moco [options] SOURCE:COMPILED ...`
|
76
|
+
|
77
|
+
Description:
|
78
|
+
MoCo monitors web templates. On updates the templates are compiled and
|
79
|
+
the browser reloaded. MoCo currently supports CoffeeScript, Sass, LESS,
|
80
|
+
Markdown and Haml.
|
81
|
+
|
82
|
+
Files and directories:
|
83
|
+
The given source files and directories will be monitored for updates.
|
84
|
+
Use the SOURCE:COMPILED format to save the compiled files to another
|
85
|
+
directory or to change the compiled filename:
|
86
|
+
`moco .:/www sass:/www/css README.md:/www/index.html`
|
87
|
+
|
88
|
+
Options:
|
89
|
+
--monitor Keep running until Ctrl-C is pressed [DEFAULT]
|
90
|
+
--no-monitor Exit after the initial compilation
|
91
|
+
|
92
|
+
-c, --compile Compile all the supported file types [DEFAULT]
|
93
|
+
-c, --compile EXT,EXT Compile the given file types
|
94
|
+
--no-compile Disable compilation
|
95
|
+
`moco -c coffee -c sass,scss .`
|
96
|
+
|
97
|
+
-f, --force Force recompilation at startup
|
98
|
+
--no-force Do not compile up-to-date files [DEFAULT]
|
99
|
+
|
100
|
+
-m, --source-map Make source maps if the compiler supports it
|
101
|
+
--no-source-map Do not make source maps [DEFAULT]
|
102
|
+
|
103
|
+
-o, --option EXT:KEY:VAL Set a compiler option
|
104
|
+
`moco -o coffee:header` # header = true
|
105
|
+
` -o haml:ugly:false` # ugly = false
|
106
|
+
` -o haml:format::xhtml` # format = :xhtml
|
107
|
+
` -o md:layout:md.html` # layout = 'md.html'
|
108
|
+
` -o less:paths:css: .` # paths = ['css']
|
109
|
+
|
110
|
+
-r, --reload Reload after css/html/js file updates [DEFAULT]
|
111
|
+
-r, --reload EXT,EXT Set the file types that triggers reloading
|
112
|
+
--no-reload Disable reloading
|
113
|
+
`moco -r rb -r css,html,js .`
|
114
|
+
|
115
|
+
-b, --browser BRO,BRO The browsers to reload [all by DEFAULT]
|
116
|
+
`moco -b safari -b chrome,canary .`
|
117
|
+
|
118
|
+
-u, --url all Reload all active tabs
|
119
|
+
-u, --url localhost Reload active tabs with localhost urls [DEFAULT]
|
120
|
+
-u, --url URL,URL Reload active tabs where the url starts with URL
|
121
|
+
`moco -u localhost -u http://app.dev/ .`
|
122
|
+
|
123
|
+
--require LIB Require the library
|
124
|
+
`moco --require path/to/compiler.rb .`
|
125
|
+
|
126
|
+
-q, --quiet Log errors only
|
127
|
+
--no-quiet Log errors and file updates [DEFAULT]
|
128
|
+
|
129
|
+
-l, --list List the supported file types and browsers
|
130
|
+
|
131
|
+
-h, --help Display this message
|
132
|
+
|
133
|
+
The moco file:
|
134
|
+
MoCo looks for files named '.moco' and 'moco.rb' in the working directory
|
135
|
+
and in the home directory. The purpose of these files is to set options
|
136
|
+
and to define new compilers. The command line options have precedence.
|
137
|
+
|
138
|
+
More information:
|
139
|
+
https://github.com/asharbitz/moco#readme
|
140
|
+
EOF
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def moco_file_args
|
146
|
+
load_moco_files
|
147
|
+
Options.instance_variable_get(:@args) || []
|
148
|
+
end
|
149
|
+
|
150
|
+
def load_moco_files
|
151
|
+
Options.moco_files.each do |file|
|
152
|
+
load file
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
[:monitor, :force, :browsers, :urls].each do |key|
|
157
|
+
define_method(key) do |option|
|
158
|
+
set_option(key, option)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
[:compile, :reload].each do |key|
|
163
|
+
define_method(key) do |option|
|
164
|
+
case option
|
165
|
+
when Array
|
166
|
+
option.map! { |ext| FileUtil.normalized_extension(ext) }
|
167
|
+
set_option("#{key}_exts".to_sym, option)
|
168
|
+
set_option(key, true)
|
169
|
+
when nil
|
170
|
+
set_option(key, true)
|
171
|
+
else
|
172
|
+
set_option(key, option)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_option(key, option)
|
178
|
+
case option
|
179
|
+
when Array
|
180
|
+
@options[key] ||= []
|
181
|
+
@options[key] += option
|
182
|
+
@options[key].uniq!
|
183
|
+
when Hash
|
184
|
+
@options[key] ||= {}
|
185
|
+
@options[key].merge!(option)
|
186
|
+
else
|
187
|
+
@options[key] = option
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def compiler_option(option)
|
192
|
+
ext, key, value = option.split(':', 3)
|
193
|
+
compiler = MoCo.compiler_for(ext)
|
194
|
+
raise OptionError.new(:missing_option_key) unless key
|
195
|
+
raise OptionError.new(:invalid_extension, ext) unless compiler
|
196
|
+
key, value = compiler.convert_option(key, value)
|
197
|
+
compiler.set_option(key, value)
|
198
|
+
end
|
199
|
+
|
200
|
+
def source_map(option)
|
201
|
+
MoCo.compilers.each_value do |compiler|
|
202
|
+
if compiler < SourceMap
|
203
|
+
compiler.set_option(compiler.source_map_key, option)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def require_lib(option)
|
209
|
+
require option
|
210
|
+
rescue LoadError
|
211
|
+
require File.expand_path(option)
|
212
|
+
end
|
213
|
+
|
214
|
+
def quiet(option)
|
215
|
+
set_option(:quiet, option)
|
216
|
+
SassCompiler.set_option(:quiet, option)
|
217
|
+
end
|
218
|
+
|
219
|
+
def display_list(option)
|
220
|
+
display(list)
|
221
|
+
end
|
222
|
+
|
223
|
+
def display_help(option = nil)
|
224
|
+
display(help)
|
225
|
+
end
|
226
|
+
|
227
|
+
def display(text)
|
228
|
+
puts
|
229
|
+
puts text
|
230
|
+
puts
|
231
|
+
exit 0
|
232
|
+
end
|
233
|
+
|
234
|
+
def list
|
235
|
+
[ ['Compile:', :compile_exts],
|
236
|
+
['Reload:', :reload_exts],
|
237
|
+
['Browsers:', :browsers],
|
238
|
+
['Localhost:', :urls]
|
239
|
+
].map do |header, key|
|
240
|
+
[header, *default_options[key]].join("\n ")
|
241
|
+
end.join("\n\n")
|
242
|
+
end
|
243
|
+
|
244
|
+
def path(option)
|
245
|
+
source, compiled = option.split(':')
|
246
|
+
source = File.expand_path(source)
|
247
|
+
compiled = File.expand_path(compiled) if compiled
|
248
|
+
if File.directory?(source)
|
249
|
+
set_option(:source_dirs, [source])
|
250
|
+
set_option(:compiled_dirs, source => compiled)
|
251
|
+
elsif File.file?(source)
|
252
|
+
set_option(:source_files, [source])
|
253
|
+
set_option(:compiled_files, source => compiled)
|
254
|
+
else
|
255
|
+
raise OptionError.new(:invalid_file, source)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def validate_options
|
260
|
+
validate_files
|
261
|
+
validate_compilers
|
262
|
+
validate_browsers
|
263
|
+
end
|
264
|
+
|
265
|
+
def validate_files
|
266
|
+
unless @options[:source_dirs] || @options[:source_files]
|
267
|
+
raise OptionError.new(:missing_file)
|
268
|
+
end
|
269
|
+
(@options[:compiled_dirs] || {}).each_value do |dir|
|
270
|
+
if dir && File.file?(dir)
|
271
|
+
raise OptionError.new(:dir_expected, dir)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
(@options[:compiled_files] || {}).each_value do |file|
|
275
|
+
if file && File.directory?(file)
|
276
|
+
raise OptionError.new(:file_expected, file)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def validate_compilers
|
282
|
+
(@options[:compile_exts] || []).each do |ext|
|
283
|
+
unless MoCo.compiler_for(ext)
|
284
|
+
raise OptionError.new(:invalid_extension, ext)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def validate_browsers
|
290
|
+
supported_browsers = Browser.browsers.map(&:downcase)
|
291
|
+
(@options[:browsers] || []).each do |browser|
|
292
|
+
unless supported_browsers.include?(browser.downcase)
|
293
|
+
raise OptionError.new(:invalid_browser, browser)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
|
300
|
+
class OptionError < Error
|
301
|
+
|
302
|
+
def initialize(error, *args)
|
303
|
+
super(error_message(error) % args)
|
304
|
+
end
|
305
|
+
|
306
|
+
private
|
307
|
+
|
308
|
+
def error_message(error)
|
309
|
+
case error
|
310
|
+
when :missing_file
|
311
|
+
[ 'No directory or file provided. ' +
|
312
|
+
'To monitor files in the current directory:',
|
313
|
+
'moco .' ]
|
314
|
+
when :invalid_file
|
315
|
+
[ "No such file or directory: '%s'" ]
|
316
|
+
when :dir_expected
|
317
|
+
[ "Expected a directory, but got a filename: '%s'" ]
|
318
|
+
when :file_expected
|
319
|
+
[ "Expected a filename, but got a directory: '%s'" ]
|
320
|
+
when :invalid_extension
|
321
|
+
[ "No compiler registered for '%s' files. The supported file types are:",
|
322
|
+
MoCo.compilers.keys.sort.join(' ') ]
|
323
|
+
when :missing_option_key
|
324
|
+
[ 'The option key is missing. Set compiler options like this:',
|
325
|
+
'-o coffee:header -o haml:format::xhtml' ]
|
326
|
+
when :invalid_browser
|
327
|
+
[ "Unknown browser '%s'. The supported browsers are:",
|
328
|
+
Browser.browsers.join(' ') ]
|
329
|
+
when Exception
|
330
|
+
[ error.message ]
|
331
|
+
end.join("\n")
|
332
|
+
end
|
333
|
+
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module MoCo
|
2
|
+
|
3
|
+
module SourceMap
|
4
|
+
|
5
|
+
def self.source_map_key
|
6
|
+
raise NotImplementedError
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :source_map_text
|
10
|
+
|
11
|
+
def compile
|
12
|
+
super
|
13
|
+
write_file(source_map_file, source_map_text) if source_map_text
|
14
|
+
end
|
15
|
+
|
16
|
+
def source_map_file
|
17
|
+
compiled_file + '.map'
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
body:before {
|
2
|
+
content: "%s";
|
3
|
+
white-space: pre-wrap;
|
4
|
+
font-family: Menlo, Monaco, monospace;
|
5
|
+
font-size: 14px;
|
6
|
+
line-height: 1.5;
|
7
|
+
background: white;
|
8
|
+
border: 3px solid red;
|
9
|
+
border-radius: 5px;
|
10
|
+
box-shadow: 5px 5px 15px #CCC;
|
11
|
+
display: block;
|
12
|
+
position: fixed;
|
13
|
+
top: 0;
|
14
|
+
left: 0;
|
15
|
+
padding: 20px;
|
16
|
+
margin: 20px;
|
17
|
+
z-index: 10000;
|
18
|
+
}
|
19
|
+
|
20
|
+
body:hover:before {
|
21
|
+
z-index: 10001;
|
22
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
// Generated by CoffeeScript 1.6.2
|
2
|
+
(function() {
|
3
|
+
var MoCo;
|
4
|
+
|
5
|
+
MoCo = {};
|
6
|
+
|
7
|
+
MoCo.errorMessage = "%s";
|
8
|
+
|
9
|
+
MoCo.css = '\
|
10
|
+
.moco-compile-error {\
|
11
|
+
white-space: pre-wrap;\
|
12
|
+
font-family: Menlo, Monaco, monospace;\
|
13
|
+
font-size: 14px;\
|
14
|
+
line-height: 1.5;\
|
15
|
+
color: black;\
|
16
|
+
background: white;\
|
17
|
+
border: 3px solid red;\
|
18
|
+
border-radius: 5px;\
|
19
|
+
box-shadow: 5px 5px 15px #CCC;\
|
20
|
+
display: block;\
|
21
|
+
position: fixed;\
|
22
|
+
top: 0;\
|
23
|
+
left: 0;\
|
24
|
+
padding: 20px;\
|
25
|
+
margin: 20px;\
|
26
|
+
z-index: 10000;\
|
27
|
+
}\
|
28
|
+
.moco-compile-error:hover {\
|
29
|
+
z-index: 10001;\
|
30
|
+
}\
|
31
|
+
.moco-compile-error span {\
|
32
|
+
color: red;\
|
33
|
+
}\
|
34
|
+
.moco-compile-error a, .moco-compile-error a:visited {\
|
35
|
+
color: black;\
|
36
|
+
text-decoration: none;\
|
37
|
+
}\
|
38
|
+
.moco-compile-error a:hover, .moco-compile-error a:active {\
|
39
|
+
color: red;\
|
40
|
+
text-decoration: none;\
|
41
|
+
}\
|
42
|
+
';
|
43
|
+
|
44
|
+
MoCo.appendErrorElement = function() {
|
45
|
+
var pre, style;
|
46
|
+
|
47
|
+
style = document.createElement('style');
|
48
|
+
style.innerHTML = MoCo.css;
|
49
|
+
pre = document.createElement('pre');
|
50
|
+
pre.innerHTML = MoCo.errorMessage;
|
51
|
+
pre.className = 'moco-compile-error';
|
52
|
+
document.body.appendChild(style);
|
53
|
+
return document.body.appendChild(pre);
|
54
|
+
};
|
55
|
+
|
56
|
+
window.addEventListener('load', MoCo.appendErrorElement, false);
|
57
|
+
|
58
|
+
}).call(this);
|
Binary file
|
data/lib/moco.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module MoCo
|
2
|
+
|
3
|
+
VERSION = '0.1.0'
|
4
|
+
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.compilers
|
9
|
+
CompilerRegister.instance.compilers
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.register(compiler, extension)
|
13
|
+
CompilerRegister.instance.register(compiler, extension)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.compiler_for(file)
|
17
|
+
CompilerRegister.instance.compiler_for(file)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.args(args)
|
21
|
+
Options.args(args)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'moco/ansi_escape'
|
27
|
+
require 'moco/application'
|
28
|
+
require 'moco/browser_error'
|
29
|
+
require 'moco/browser'
|
30
|
+
require 'moco/compile_error'
|
31
|
+
require 'moco/compiler_option'
|
32
|
+
require 'moco/compiler_register'
|
33
|
+
require 'moco/compiler'
|
34
|
+
require 'moco/file_util'
|
35
|
+
require 'moco/log'
|
36
|
+
require 'moco/monitor'
|
37
|
+
require 'moco/options'
|
38
|
+
require 'moco/source_map'
|
39
|
+
|
40
|
+
require 'moco/compilers/coffee_compiler'
|
41
|
+
require 'moco/compilers/haml_compiler'
|
42
|
+
require 'moco/compilers/less_compiler'
|
43
|
+
require 'moco/compilers/markdown_compiler'
|
44
|
+
require 'moco/compilers/sass_compiler'
|
data/moco.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = 'moco'
|
3
|
+
spec.version = '0.1.0'
|
4
|
+
spec.license = 'MIT'
|
5
|
+
|
6
|
+
spec.author = 'AS Harbitz'
|
7
|
+
spec.email = 'asharbitz@gmail.com'
|
8
|
+
spec.homepage = 'https://github.com/asharbitz/moco'
|
9
|
+
|
10
|
+
spec.summary = 'Monitors and compiles web templates. Reloads the browser.'
|
11
|
+
spec.description = 'MoCo monitors web templates. On updates the templates ' +
|
12
|
+
'are compiled and the browser reloaded. MoCo currently ' +
|
13
|
+
'supports CoffeeScript, Sass, LESS, Markdown and Haml. ' +
|
14
|
+
'Mac OS X only.'
|
15
|
+
|
16
|
+
spec.files = Dir['LICENSE', 'moco.gemspec', 'moco.rb', 'Rakefile',
|
17
|
+
'README.txt', '{lib,src}/**/*.*']
|
18
|
+
spec.test_files = Dir['test/**/*.*']
|
19
|
+
spec.executables << 'moco'
|
20
|
+
|
21
|
+
spec.add_dependency 'rb-fsevent', '~> 0.9'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'minitest', '~> 4.0'
|
24
|
+
spec.add_development_dependency 'coffee-script-source', '>= 1.6.2'
|
25
|
+
spec.add_development_dependency 'runjs'
|
26
|
+
spec.add_development_dependency 'haml'
|
27
|
+
spec.add_development_dependency 'less'
|
28
|
+
spec.add_development_dependency 'therubyracer'
|
29
|
+
spec.add_development_dependency 'redcarpet'
|
30
|
+
spec.add_development_dependency 'pygments.rb'
|
31
|
+
spec.add_development_dependency 'sass'
|
32
|
+
|
33
|
+
spec.required_ruby_version = '>= 1.8.7'
|
34
|
+
spec.requirements << 'Mac OS X'
|
35
|
+
end
|
data/moco.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
MoCo.args '--option coffee:header src:lib/moco/support'
|
2
|
+
|
3
|
+
class AppleScriptCompiler < MoCo::Compiler
|
4
|
+
|
5
|
+
require_library 'open3'
|
6
|
+
register 'applescript'
|
7
|
+
|
8
|
+
def self.compiled_extension
|
9
|
+
'scpt'
|
10
|
+
end
|
11
|
+
|
12
|
+
def compile
|
13
|
+
cmd = ['osacompile', '-o', compiled_file, source_file]
|
14
|
+
message = Open3.popen3(*cmd) { |_, _, stderr| stderr.read.strip }
|
15
|
+
unless message.empty?
|
16
|
+
error = StandardError.new(message)
|
17
|
+
error = MoCo::CompileError.new(error, source_file)
|
18
|
+
write_compiled(error_text(error))
|
19
|
+
raise error
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def error_text(error)
|
24
|
+
applescript = <<-EOF
|
25
|
+
tell application "AppleScript Runner"
|
26
|
+
display alert "%s" giving up after 10
|
27
|
+
return
|
28
|
+
end
|
29
|
+
EOF
|
30
|
+
message = "File: #{error.file}\n\nLine: #{error.line}\n\n#{error.message}"
|
31
|
+
message = message.gsub('\\') { '\\\\' }.gsub('"', '\"')
|
32
|
+
applescript % message
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
MoCo = {}
|
2
|
+
|
3
|
+
MoCo.errorMessage = "%s"
|
4
|
+
|
5
|
+
MoCo.css = '
|
6
|
+
.moco-compile-error {
|
7
|
+
white-space: pre-wrap;
|
8
|
+
font-family: Menlo, Monaco, monospace;
|
9
|
+
font-size: 14px;
|
10
|
+
line-height: 1.5;
|
11
|
+
color: black;
|
12
|
+
background: white;
|
13
|
+
border: 3px solid red;
|
14
|
+
border-radius: 5px;
|
15
|
+
box-shadow: 5px 5px 15px #CCC;
|
16
|
+
display: block;
|
17
|
+
position: fixed;
|
18
|
+
top: 0;
|
19
|
+
left: 0;
|
20
|
+
padding: 20px;
|
21
|
+
margin: 20px;
|
22
|
+
z-index: 10000;
|
23
|
+
}
|
24
|
+
.moco-compile-error:hover {
|
25
|
+
z-index: 10001;
|
26
|
+
}
|
27
|
+
.moco-compile-error span {
|
28
|
+
color: red;
|
29
|
+
}
|
30
|
+
.moco-compile-error a, .moco-compile-error a:visited {
|
31
|
+
color: black;
|
32
|
+
text-decoration: none;
|
33
|
+
}
|
34
|
+
.moco-compile-error a:hover, .moco-compile-error a:active {
|
35
|
+
color: red;
|
36
|
+
text-decoration: none;
|
37
|
+
}
|
38
|
+
'
|
39
|
+
|
40
|
+
MoCo.appendErrorElement = ->
|
41
|
+
style = document.createElement('style')
|
42
|
+
style.innerHTML = MoCo.css
|
43
|
+
pre = document.createElement('pre')
|
44
|
+
pre.innerHTML = MoCo.errorMessage
|
45
|
+
pre.className = 'moco-compile-error'
|
46
|
+
document.body.appendChild(style)
|
47
|
+
document.body.appendChild(pre)
|
48
|
+
|
49
|
+
window.addEventListener('load', MoCo.appendErrorElement, false)
|