Module: Guard::CoffeeScript::Runner

Defined in:
lib/guard/coffeescript/runner.rb

Class Attribute Summary (collapse)

Class Method Summary (collapse)

Class Attribute Details

+ (Object) last_run_failed

Returns the value of attribute last_run_failed



8
9
10
# File 'lib/guard/coffeescript/runner.rb', line 8

def last_run_failed
  @last_run_failed
end

Class Method Details

+ (Array<String, String>) compile(filename, options) (private)

Compile the CoffeeScript and generate the source map.

Options Hash (options):

  • :source_map (Boolean)

    generate the source map files



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/guard/coffeescript/runner.rb', line 119

def compile(filename, options)
  file = File.read(filename)
  file_options = options_for_file(filename, options)

  if options[:source_map]
    file_options.merge! options_for_source_map(filename, options)
    result = ::CoffeeScript.compile(file, file_options)
    js, map = result['js'], result['v3SourceMap']
  else
    js  = ::CoffeeScript.compile(file, file_options)
  end

  [js, map]
end

+ (Array<Array<String>, Array<String>] the result for the compilation run) compile_files(files, watchers, options) (private)

Compiles all CoffeeScript files and writes the JavaScript files.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/guard/coffeescript/runner.rb', line 84

def compile_files(files, watchers, options)
  errors        = []
  changed_files = []
  directories   = detect_nested_directories(watchers, files, options)

  directories.each do |directory, scripts|
    scripts.each do |file|
      begin
        js, map = compile(file, options)
        changed_files << write_javascript_file(js, map, file, directory, options)

      rescue => e
        error_message = file + ': ' + e.message.to_s

        if options[:error_to_js]
          js_error_message = "throw \"#{ error_message }\";"
          changed_files << write_javascript_file(js_error_message, nil, file, directory, options)
        end

        errors << error_message
        Formatter.error(error_message)
      end
    end
  end

  [changed_files.flatten.compact, errors]
end

+ (Object) detect_nested_directories(watchers, files, options) (private)

Detects the output directory for each CoffeeScript file. Builds the product of all watchers and assigns to each directory the files to which it belongs to.

Options Hash (options):

  • :output (String)

    the output directory

  • :shallow (Boolean)

    do not create nested directories



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/guard/coffeescript/runner.rb', line 227

def detect_nested_directories(watchers, files, options)
  return { options[:output] => files } if options[:shallow]

  directories = { }

  watchers.product(files).each do |watcher, file|
    if matches = file.match(watcher.pattern)
      target = matches[1] ? File.join(options[:output], File.dirname(matches[1])).gsub(/\/\.$/, '') : options[:output] || File.dirname(file)
      if directories[target]
        directories[target] << file
      else
        directories[target] = [file]
      end
    end
  end

  directories
end

+ (Object) javascript_file_name(file, directory) (private)

Calculates the output filename from the coffescript filename and the output directory



213
214
215
# File 'lib/guard/coffeescript/runner.rb', line 213

def javascript_file_name(file, directory)
  File.join(directory, File.basename(file.gsub(/((?:js\.)?(?:coffee|coffee\.md|litcoffee))$/, 'js')))
end

+ (Object) notify_result(changed_files, errors, options = { }) (private)

Writes console and system notifications about the result of the compilation.

Options Hash (options):

  • :hide_success (Boolean)

    hide success message notification

  • :noop (Boolean)

    do not generate an output file



254
255
256
257
258
259
260
261
262
263
264
# File 'lib/guard/coffeescript/runner.rb', line 254

def notify_result(changed_files, errors, options = { })
  if !errors.empty?
    self.last_run_failed = true
    Formatter.notify(errors.join("\n"), :title => 'CoffeeScript results', :image => :failed, :priority => 2)
  elsif !options[:hide_success] || last_run_failed
    self.last_run_failed = false
    message = "Successfully #{ options[:noop] ? 'verified' : 'generated' } #{ changed_files.join(', ') }"
    Formatter.success(message)
    Formatter.notify(message, :title => 'CoffeeScript results')
  end
end

+ (Object) notify_start(files, options) (private)

Generates a start compilation notification.

Options Hash (options):

  • :noop (Boolean)

    do not generate an output file



72
73
74
75
# File 'lib/guard/coffeescript/runner.rb', line 72

def notify_start(files, options)
  message = options[:message] || (options[:noop] ? 'Verify ' : 'Compile ') + files.join(', ')
  Formatter.info(message, :reset => true)
end

+ (Hash) options_for_file(file, options) (private)

Gets the CoffeeScript compilation options.

Options Hash (options):

  • :bare (Boolean)

    do not wrap the output in a top level function



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/guard/coffeescript/runner.rb', line 141

def options_for_file(file, options)
  file_options = options.clone

  # if :bare was provided an array of filenames, check for file's inclusion
  if file_options[:bare].respond_to? :include?
    filename            = file[/([^\/]*)\.(?:coffee|coffee\.md|litcoffee)$/]
    file_options[:bare] = file_options[:bare].include?(filename)
  end

  if file[/\.(?:coffee\.md|litcoffee)$/]
    file_options[:literate] = true
  end

  file_options
end

+ (Object) options_for_source_map(filename, options) (private)

Gets the CoffeeScript source map options.



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/guard/coffeescript/runner.rb', line 162

def options_for_source_map(filename, options)
  # if :input was provided, make all filenames relative to that
  filename = Pathname.new(filename).relative_path_from(Pathname.new(options[:input])).to_s if options[:input]

  {
    :sourceMap => true,
    :generatedFile => filename.gsub(/((?:js\.)?(?:coffee|coffee\.md|litcoffee))$/, 'js'),
    :sourceFiles => [filename],
    :sourceRoot => options[:source_root] || options[:input] || '',
  }
end

+ (Object) remove(files, watchers, options = { })

The remove function deals with CoffeeScript file removal by locating the output javascript file and removing it.

Options Hash (options):

  • :output (String)

    the output directory

  • :shallow (Boolean)

    do not create nested directories



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/guard/coffeescript/runner.rb', line 43

def remove(files, watchers, options = { })
  removed_files = []
  directories   = detect_nested_directories(watchers, files, options)

  directories.each do |directory, scripts|
    scripts.each do |file|
      javascript = javascript_file_name(file, directory)
      if File.exists?(javascript)
        FileUtils.remove_file(javascript)
        removed_files << javascript
      end
    end
  end

  if removed_files.length > 0
    message = "Removed #{ removed_files.join(', ') }"
    Formatter.success(message)
    Formatter.notify(message, :title => 'CoffeeScript results')
  end
end

+ (Array<Array<String>, Boolean>) run(files, watchers, options = { })

The CoffeeScript runner handles the CoffeeScript compilation, creates nested directories and the output file, writes the result to the console and triggers optional system notifications.

Options Hash (options):

  • :input (String)

    the input directory

  • :output (String)

    the output directory

  • :bare (Boolean)

    do not wrap the output in a top level function

  • :shallow (Boolean)

    do not create nested directories

  • :hide_success (Boolean)

    hide success message notification

  • :noop (Boolean)

    do not generate an output file

  • :source_map (Boolean)

    generate the source map files



26
27
28
29
30
31
32
# File 'lib/guard/coffeescript/runner.rb', line 26

def run(files, watchers, options = { })
  notify_start(files, options)
  changed_files, errors = compile_files(files, watchers, options)
  notify_result(changed_files, errors, options)

  [changed_files, errors.empty?]
end

+ (String) write_javascript_file(js, map, file, directory, options) (private)

Analyzes the CoffeeScript compilation output and creates the nested directories and writes the output file.

Options Hash (options):

  • :noop (Boolean)

    do not generate an output file



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/guard/coffeescript/runner.rb', line 185

def write_javascript_file(js, map, file, directory, options)
  directory = Dir.pwd if !directory || directory.empty?
  filename = javascript_file_name(file, directory)

  return filename if options[:noop]

  if options[:source_map]
    map_name = filename + '.map'
    js += "\n/*\n//@ sourceMappingURL=#{File.basename(map_name)}\n*/\n"
  end

  FileUtils.mkdir_p(File.expand_path(directory)) if !File.directory?(directory)
  File.open(File.expand_path(filename), 'w') { |f| f.write(js) }

  if options[:source_map]
    File.open(File.expand_path(map_name), 'w') { |f| f.write(map) }
    [filename, map_name]
  else
    filename
  end
end