Class: Monolens::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/monolens/command.rb,
lib/monolens/command/tester.rb

Defined Under Namespace

Classes: Tester

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv, stdin, stdout, stderr) ⇒ Command

Returns a new instance of Command.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/monolens/command.rb', line 8

def initialize(argv, stdin, stdout, stderr)
  @argv = argv
  @stdin = stdin
  @stdout = stdout
  @stderr = stderr
  @pretty = false
  @enclose = []
  @output_format = :json
  @stream = false
  @fail_strategy = 'fail'
  @override = false
  @execute_tests = false
  #
  @input_file = nil
  @use_stdin = false
  #
  @use_paint = true
end

Instance Attribute Details

#argvObject (readonly)

Returns the value of attribute argv.



26
27
28
# File 'lib/monolens/command.rb', line 26

def argv
  @argv
end

#enclose_mapObject (readonly)

Returns the value of attribute enclose_map.



28
29
30
# File 'lib/monolens/command.rb', line 28

def enclose_map
  @enclose_map
end

#execute_testsObject (readonly) Also known as: execute_tests?

Returns the value of attribute execute_tests.



32
33
34
# File 'lib/monolens/command.rb', line 32

def execute_tests
  @execute_tests
end

#fail_strategyObject (readonly)

Returns the value of attribute fail_strategy.



28
29
30
# File 'lib/monolens/command.rb', line 28

def fail_strategy
  @fail_strategy
end

#input_fileObject (readonly)

Returns the value of attribute input_file.



29
30
31
# File 'lib/monolens/command.rb', line 29

def input_file
  @input_file
end

#overrideObject (readonly)

Returns the value of attribute override.



27
28
29
# File 'lib/monolens/command.rb', line 27

def override
  @override
end

#prettyObject (readonly)

Returns the value of attribute pretty.



27
28
29
# File 'lib/monolens/command.rb', line 27

def pretty
  @pretty
end

#stderrObject (readonly)

Returns the value of attribute stderr.



26
27
28
# File 'lib/monolens/command.rb', line 26

def stderr
  @stderr
end

#stdinObject (readonly)

Returns the value of attribute stdin.



26
27
28
# File 'lib/monolens/command.rb', line 26

def stdin
  @stdin
end

#stdoutObject (readonly)

Returns the value of attribute stdout.



26
27
28
# File 'lib/monolens/command.rb', line 26

def stdout
  @stdout
end

#streamObject (readonly)

Returns the value of attribute stream.



27
28
29
# File 'lib/monolens/command.rb', line 27

def stream
  @stream
end

#use_paintObject (readonly) Also known as: use_paint?

Returns the value of attribute use_paint.



30
31
32
# File 'lib/monolens/command.rb', line 30

def use_paint
  @use_paint
end

#use_stdinObject (readonly)

Returns the value of attribute use_stdin.



29
30
31
# File 'lib/monolens/command.rb', line 29

def use_stdin
  @use_stdin
end

Class Method Details

.call(argv, stdin = $stdin, stdout = $stdout, stderr = $stderr) ⇒ Object



35
36
37
# File 'lib/monolens/command.rb', line 35

def self.call(argv, stdin = $stdin, stdout = $stdout, stderr = $stderr)
  new(argv, stdin, stdout, stderr).call
end

Instance Method Details

#build_lens(lens_data) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/monolens/command.rb', line 158

def build_lens(lens_data)
  lens_data = @enclose.inject(lens_data) do |memo, lens_name|
    case lens_name
    when :map
      {
        'array.map' => {
          'on_error' => ['handler', fail_strategy].compact,
          'lenses' => memo,
        }
      }
    when :literal
      {
        'core.literal' => {
          'defn' => memo,
        }
      }
    end
  end unless execute_tests?
  Monolens.lens(lens_data)
end

#callObject



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

def call
  lens, @input_file = options.parse!(argv)
  show_help_and_exit if lens.nil? || (@input_file.nil? && !use_stdin && !execute_tests?)

  lens = build_lens(read_file(lens))
  if execute_tests?
    execute_tests!(lens)
  else
    input = read_input
    error_handler = ErrorHandler.new
    result = lens.call(input, error_handler: error_handler)

    unless error_handler.empty?
      stderr.puts(error_handler.report)
    end

    output_result(result) if result
  end
rescue Monolens::LensError => ex
  stderr.puts("[#{ex.location.join('/')}] #{ex.message}")
  do_exit(1)
end

#do_exit(status) ⇒ Object



99
100
101
# File 'lib/monolens/command.rb', line 99

def do_exit(status)
  exit(status)
end

#execute_tests!(lens) ⇒ Object



62
63
64
65
# File 'lib/monolens/command.rb', line 62

def execute_tests!(lens)
  require_relative 'command/tester'
  Tester.new(self).call(lens)
end

#fail!(msg) ⇒ Object



94
95
96
97
# File 'lib/monolens/command.rb', line 94

def fail!(msg)
  stderr.puts(msg)
  do_exit(1)
end

#optionsObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/monolens/command.rb', line 108

def options
  @options ||= OptionParser.new do |opts|
    opts.banner = 'Usage: monolens [options] LENS INPUT'

    opts.on('--version', 'Show version and exit') do
      stdout.puts "Monolens v#{VERSION} - (c) Enspirit #{Date.today.year}"
      do_exit(0)
    end
    opts.on('-m', '--map', 'Enclose the loaded lens inside an array.map') do
      @enclose << :map
    end
    opts.on('-l', '--literal', 'Enclose the loaded lens inside core.literal') do
      @enclose << :literal
    end
    opts.on('--on-error=STRATEGY', 'Apply a specific strategy on error') do |strategy|
      @fail_strategy = strategy
    end
    opts.on('-ILIB', 'Add a folder to ruby load path') do |lib|
      $LOAD_PATH.unshift(lib)
    end
    opts.on('-rLIB', 'Add a ruby require of a lib') do |lib|
      require(lib)
    end
    opts.on( '--stdin', 'Takes input data from STDIN') do
      @use_stdin = true
    end
    opts.on('-p', '--[no-]pretty', 'Show version and exit') do |pretty|
      @pretty = pretty
    end
    opts.on('-y', '--yaml', 'Print output in YAML') do
      @output_format = :yaml
    end
    opts.on('-s', '--stream', 'Stream mode: output each result item separately') do
      @stream = true
    end
    opts.on('-j', '--json', 'Print output in JSON') do
      @output_format = :json
    end
    opts.on('--override', 'Write output back to the input file') do
      @override = true
    end
    opts.on('--test', 'Execute tests embedded in the lens file') do
      @execute_tests = true
    end
    opts.on('--[no-]paint', 'Do (not) paint error messages') do |flag|
      @use_paint = flag
    end
  end
end

#output_json(result, io) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
# File 'lib/monolens/command.rb', line 198

def output_json(result, io)
  method = pretty ? :pretty_generate : :generate
  if stream
    fail!("Stream mode only works with an output Array") unless result.is_a?(::Enumerable)
    result.each do |item|
      io.puts JSON.send(method, item)
    end
  else
    io.puts JSON.send(method, result)
  end
end

#output_result(result) ⇒ Object



179
180
181
182
183
184
185
186
187
188
# File 'lib/monolens/command.rb', line 179

def output_result(result)
  with_output_io do |io|
    output = case @output_format
    when :json
      output_json(result, io)
    when :yaml
      output_yaml(result, io)
    end
  end
end

#output_yaml(result, io) ⇒ Object



210
211
212
213
# File 'lib/monolens/command.rb', line 210

def output_yaml(result, io)
  output = stream ? YAML.dump_stream(*result) : YAML.dump(result)
  io.puts output
end

#read_file(file) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/monolens/command.rb', line 75

def read_file(file)
  case ::File.extname(file)
  when /json$/
    content = ::File.read(file)
    JSON.parse(content)
  when /ya?ml$/
    content = ::File.read(file)
    YAML.safe_load(content)
  when /csv$/
    require 'bmg'
    Bmg.csv(file).to_a
  when /xlsx?$/
    require 'bmg'
    Bmg.excel(file).to_a
  else
    fail!("Unable to use #{file}")
  end
end

#read_inputObject



67
68
69
70
71
72
73
# File 'lib/monolens/command.rb', line 67

def read_input
  if use_stdin
    JSON.parse(stdin.read)
  else
    read_file(@input_file)
  end
end

#show_help_and_exitObject



103
104
105
106
# File 'lib/monolens/command.rb', line 103

def show_help_and_exit
  stdout.puts options
  do_exit(0)
end

#with_output_io(&block) ⇒ Object



190
191
192
193
194
195
196
# File 'lib/monolens/command.rb', line 190

def with_output_io(&block)
  if override
    ::File.open(@input_file, 'w', &block)
  else
    block.call(stdout)
  end
end