Module: Guard::CoffeeScript::Runner

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

Class Method Summary (collapse)

Class Method Details

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

Compile the CoffeeScript and generate the source map.

Parameters:

  • filename (String)

    the CoffeeScript file n

  • options (Hash)

    the options for the execution

Options Hash (options):

  • :source_map (Boolean)

    generate the source map files

Returns:

  • (Array<String, String>)

    the JavaScript source and the source map



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

def compile(filename, options)
  file = File.read(filename)
  file_options = options_for_file(file, 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.

Parameters:

  • files (Array<String>)

    the files to compile

  • watchers (Array<Guard::Watcher>)

    the Guard watchers in the block

  • options (Hash)

    the options for the execution

Returns:

  • (Array<Array<String>, Array<String>] the result for the compilation run)

    Array, Array] the result for the compilation run



82
83
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
# File 'lib/guard/coffeescript/runner.rb', line 82

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.

Parameters:

  • watchers (Array<Guard::Watcher>)

    the Guard watchers in the block

  • files (Array<String>)

    the CoffeeScript files

  • options (Hash)

    the options for the execution

Options Hash (options):

  • :output (String)

    the output directory

  • :shallow (Boolean)

    do not create nested directories



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/guard/coffeescript/runner.rb', line 217

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

Parameters:

  • file (string)

    the CoffeeScript file name

  • directory (String)

    the output directory



203
204
205
# File 'lib/guard/coffeescript/runner.rb', line 203

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

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

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

Parameters:

  • changed_files (Array<String>)

    the changed JavaScript files

  • errors (Array<String>)

    the error messages

  • options (Hash) (defaults to: { })

    the options for the execution

Options Hash (options):

  • :hide_success (Boolean)

    hide success message notification

  • :noop (Boolean)

    do not generate an output file



244
245
246
247
248
249
250
251
252
# File 'lib/guard/coffeescript/runner.rb', line 244

def notify_result(changed_files, errors, options = { })
  if !errors.empty?
    Formatter.notify(errors.join("\n"), :title => 'CoffeeScript results', :image => :failed, :priority => 2)
  elsif !options[:hide_success]
    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.

Parameters:

  • files (Array<String>)

    the generated files

  • options (Hash)

    the options for the execution

Options Hash (options):

  • :noop (Boolean)

    do not generate an output file



70
71
72
73
# File 'lib/guard/coffeescript/runner.rb', line 70

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

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

Gets the CoffeeScript compilation options.

Parameters:

  • file (String)

    the CoffeeScript file

  • options (Hash)

    the options for the execution

Options Hash (options):

  • :bare (Boolean)

    do not wrap the output in a top level function



137
138
139
140
141
142
143
144
145
# File 'lib/guard/coffeescript/runner.rb', line 137

def options_for_file(file, options)
  return options unless options[:bare].respond_to? :include?

  file_options        = options.clone
  filename            = file[/([^\/]*)\.coffee/]
  file_options[:bare] = file_options[:bare].include?(filename)

  file_options
end

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

Gets the CoffeeScript source map options.

Parameters:

  • filename (String)

    the CoffeeScript filename

  • options (Hash)

    the options for the execution



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/guard/coffeescript/runner.rb', line 152

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)$/, '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.

Parameters:

  • files (Array<String>)

    the spec files or directories

  • watchers (Array<Guard::Watcher>)

    the Guard watchers in the block

  • options (Hash) (defaults to: { })

    the options for the removal

Options Hash (options):

  • :output (String)

    the output directory

  • :shallow (Boolean)

    do not create nested directories



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

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.

Parameters:

  • files (Array<String>)

    the spec files or directories

  • watchers (Array<Guard::Watcher>)

    the Guard watchers in the block

  • options (Hash) (defaults to: { })

    the options for the execution

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

Returns:

  • (Array<Array<String>, Boolean>)

    the result for the compilation run



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

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.

Parameters:

  • js (String)

    the JavaScript content

  • map (String)

    the source map content

  • file (String)

    the CoffeeScript file name

  • directory (String)

    the output directory

  • options (Hash)

    the options for the execution

Options Hash (options):

  • :noop (Boolean)

    do not generate an output file

Returns:

  • (String)

    the JavaScript file name



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/guard/coffeescript/runner.rb', line 175

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