Class: Opal::CliRunners::Compiler

Inherits:
Object
  • Object
show all
Defined in:
opal/lib/opal/cli_runners/compiler.rb

Overview

The compiler runner will just output the compiled JavaScript

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Compiler

Returns a new instance of Compiler.



11
12
13
14
15
16
17
# File 'opal/lib/opal/cli_runners/compiler.rb', line 11

def initialize(data)
  @options         = data[:options] || {}
  @builder_factory = data.fetch(:builder)
  @map_file        = @options[:map_file]
  @output          = data.fetch(:output)
  @watch           = @options[:watch]
end

Class Method Details

.call(data) ⇒ Object



7
8
9
# File 'opal/lib/opal/cli_runners/compiler.rb', line 7

def self.call(data)
  new(data).start
end

Instance Method Details

#compileObject



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'opal/lib/opal/cli_runners/compiler.rb', line 19

def compile
  builder = @builder_factory.call
  compiled_source = builder.to_s
  compiled_source += "\n" + builder.source_map.to_data_uri_comment unless @options[:no_source_map]

  rewind_output if @watch

  @output.puts compiled_source
  @output.flush

  File.write(@map_file, builder.source_map.to_json) if @map_file

  builder
end

#compile_noraiseObject



34
35
36
37
38
39
# File 'opal/lib/opal/cli_runners/compiler.rb', line 34

def compile_noraise
  compile
rescue StandardError, Opal::SyntaxError => e
  $stderr.puts "* Compilation failed: #{e.message}"
  nil
end

#fail_no_listen!Object



62
63
64
65
66
67
68
69
70
71
# File 'opal/lib/opal/cli_runners/compiler.rb', line 62

def fail_no_listen!
  warn <<~ERROR
    --watch mode requires the `listen` gem present. Please try to run:

        gem install listen

    Or if you are using bundler, add listen to your Gemfile.
  ERROR
  exit 1
end

#fail_unrewindable!Object



54
55
56
57
58
59
60
# File 'opal/lib/opal/cli_runners/compiler.rb', line 54

def fail_unrewindable!
  warn <<~ERROR
    You have specified --watch, but for watch to work, you must specify an
    --output file.
  ERROR
  exit 1
end

#files_to_directoriesObject



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'opal/lib/opal/cli_runners/compiler.rb', line 117

def files_to_directories
  directories = @files.map { |file| File.dirname(file) }.uniq

  previous_dir = nil
  # Only get the topmost directories
  directories = directories.sort.map do |dir|
    if previous_dir && dir.start_with?(previous_dir + '/')
      nil
    else
      previous_dir = dir
    end
  end

  directories.compact
end

#on_code_change(modified) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'opal/lib/opal/cli_runners/compiler.rb', line 97

def on_code_change(modified)
  if !(modified & @opal_deps).empty?
    $stderr.puts "* Modified core Opal files: #{modified.join(', ')}; reexecuting"
    reexec
  elsif !modified.all? { |file| @directories.any? { |dir| file.start_with?(dir + '/') } }
    $stderr.puts "* New unwatched files: #{modified.join(', ')}; reexecuting"
    reexec
  end

  $stderr.puts "* Modified code: #{modified.join(', ')}; rebuilding"

  builder = compile_noraise

  # Ignore the bad compilation
  if builder
    code_deps = builder.dependent_files
    @files = @opal_deps + code_deps
  end
end

#reexecObject



93
94
95
# File 'opal/lib/opal/cli_runners/compiler.rb', line 93

def reexec
  system($0, *OriginalARGV) && exit
end

#rewind_outputObject



41
42
43
44
45
46
47
48
49
50
51
52
# File 'opal/lib/opal/cli_runners/compiler.rb', line 41

def rewind_output
  if !@output.is_a?(File) || @output.tty?
    fail_unrewindable!
  else
    begin
      @output.rewind
      @output.truncate(0)
    rescue Errno::ESPIPE
      fail_unrewindable!
    end
  end
end

#startObject



142
143
144
145
146
147
148
149
150
# File 'opal/lib/opal/cli_runners/compiler.rb', line 142

def start
  if @watch
    watch_compile
  else
    compile
  end

  0
end

#watch_compileObject



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'opal/lib/opal/cli_runners/compiler.rb', line 73

def watch_compile
  begin
    require 'listen'
  rescue LoadError
    fail_no_listen!
  end

  @opal_deps = Opal.dependent_files

  builder = compile
  code_deps = builder.dependent_files
  @files = @opal_deps + code_deps
  @code_listener = watch_files
  @code_listener.start

  $stderr.puts "* Opal v#{Opal::VERSION} successfully compiled your program in --watch mode"

  sleep
end

#watch_filesObject



133
134
135
136
137
138
139
140
# File 'opal/lib/opal/cli_runners/compiler.rb', line 133

def watch_files
  @directories = files_to_directories

  Listen.to(*@directories) do |modified, added, removed|
    our_modified = @files & (modified + added + removed)
    on_code_change(our_modified) unless our_modified.empty?
  end
end