Class: Dorian::Eval

Inherits:
Object
  • Object
show all
Defined in:
lib/dorian/eval.rb

Constant Summary collapse

Return =
Data.define(:stdout, :stderr, :returned) do
  def initialize(stdout: "", stderr: "", returned: nil)
    super
  end
end
COLORS =
{ red: "\e[31m", green: "\e[32m", reset: "\e[0m" }.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ruby: nil, it: nil, debug: false, stdout: true, stderr: true, colorize: false, rails: false, returns: false, fast: false) ⇒ Eval

Returns a new instance of Eval.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/dorian/eval.rb', line 26

def initialize(
  ruby: nil,
  it: nil,
  debug: false,
  stdout: true,
  stderr: true,
  colorize: false,
  rails: false,
  returns: false,
  fast: false
)
  @ruby = ruby.to_s.empty? ? "nil" : ruby
  @it = it.to_s.empty? ? nil : it
  @debug = !!debug
  @stdout = !!stdout
  @stderr = !!stderr
  @colorize = !!colorize
  @rails = !!rails
  @returns = !!returns
  @fast = !!fast
end

Instance Attribute Details

#colorizeObject (readonly)

Returns the value of attribute colorize.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def colorize
  @colorize
end

#debugObject (readonly)

Returns the value of attribute debug.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def debug
  @debug
end

#fastObject (readonly)

Returns the value of attribute fast.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def fast
  @fast
end

#itObject (readonly)

Returns the value of attribute it.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def it
  @it
end

#railsObject (readonly)

Returns the value of attribute rails.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def rails
  @rails
end

#returnsObject (readonly)

Returns the value of attribute returns.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def returns
  @returns
end

#rubyObject (readonly)

Returns the value of attribute ruby.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def ruby
  @ruby
end

#stderrObject (readonly)

Returns the value of attribute stderr.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def stderr
  @stderr
end

#stdoutObject (readonly)

Returns the value of attribute stdout.



14
15
16
# File 'lib/dorian/eval.rb', line 14

def stdout
  @stdout
end

Class Method Details

.evalObject



48
49
50
# File 'lib/dorian/eval.rb', line 48

def self.eval(...)
  new(...).eval
end

Instance Method Details

#colorize?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/dorian/eval.rb', line 100

def colorize?
  !!colorize
end

#colorize_string(string, color) ⇒ Object



185
186
187
188
189
# File 'lib/dorian/eval.rb', line 185

def colorize_string(string, color)
  return string unless color

  [COLORS.fetch(color), string, COLORS.fetch(:reset)].join
end

#debug?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/dorian/eval.rb', line 88

def debug?
  !!debug
end

#evalObject



52
53
54
# File 'lib/dorian/eval.rb', line 52

def eval
  fast? ? eval_fast : eval_slow
end

#eval_fastObject



56
57
58
# File 'lib/dorian/eval.rb', line 56

def eval_fast
  Return.new(returned: Kernel.eval(full_ruby))
end

#eval_slowObject



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/dorian/eval.rb', line 60

def eval_slow
  read_out, write_out = IO.pipe
  read_err, write_err = IO.pipe

  spawn(write_out:, write_err:)

  write_out.close
  write_err.close

  out = ""
  err = ""

  while !read_out.eof? || !read_err.eof?
    out += gets(read_out, print: stdout?, method: :puts).to_s
    err += gets(read_err, color: :red, print: stderr?, method: :warn).to_s
  end

  if returns?
    Return.new(stdout: out, stderr: err, returned: YAML.safe_load(out))
  else
    Return.new(stdout: out, stderr: err)
  end
end

#fast?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/dorian/eval.rb', line 84

def fast?
  !!fast
end

#full_rubyObject



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/dorian/eval.rb', line 137

def full_ruby
  full_ruby = "it = #{to_ruby(it)}\n"
  full_ruby +=
    if returns? && slow?
      <<~RUBY
        require "yaml"
        puts (#{ruby}).to_yaml
      RUBY
    else
      <<~RUBY
        #{ruby}
      RUBY
    end

  full_ruby = <<~RUBY if rails?
    require "#{Dir.pwd}/config/environment"
    #{full_ruby}
  RUBY

  full_ruby
end

#gets(read, color: nil, print: true, method: :puts) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/dorian/eval.rb', line 169

def gets(read, color: nil, print: true, method: :puts)
  original_string = read.gets
  return unless original_string

  string = original_string.rstrip
  string = colorize_string(string, color) if colorize? && color

  if method == :puts && print
    puts [prefix, string].join
  elsif method == :warn && print
    warn [prefix, string].join
  end

  original_string
end

#prefixObject



112
113
114
# File 'lib/dorian/eval.rb', line 112

def prefix
  debug? && !returns? && it ? "[#{it}] " : ""
end

#rails?Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/dorian/eval.rb', line 104

def rails?
  !!rails
end

#returns?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/dorian/eval.rb', line 108

def returns?
  !!returns
end

#slow?Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/dorian/eval.rb', line 133

def slow?
  !fast?
end

#spawn(write_out:, write_err:) ⇒ Object



159
160
161
162
163
164
165
166
167
# File 'lib/dorian/eval.rb', line 159

def spawn(write_out:, write_err:)
  Process.spawn(
    RbConfig.ruby,
    "-e",
    full_ruby,
    out: write_out,
    err: write_err
  )
end

#stderr?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/dorian/eval.rb', line 96

def stderr?
  !!stderr
end

#stdout?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/dorian/eval.rb', line 92

def stdout?
  !!stdout
end

#to_ruby(ruby) ⇒ Object



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

def to_ruby(ruby)
  case ruby
  when Struct
    keys = ruby.to_h.keys.map { |key| to_ruby(key) }
    values = ruby.to_h.values.map { |value| to_ruby(value) }
    "Struct.new(#{keys.join(", ")}).new(#{values.join(", ")})"
  when String, Symbol, NilClass, TrueClass, FalseClass, Float, Integer
    ruby.inspect
  when Array
    "[#{ruby.map { |element| to_ruby(element) }.join(", ")}]"
  when Hash
    "{#{ruby.map { |key, value| "#{to_ruby(key)} => #{to_ruby(value)}" }}}"
  else
    raise "#{ruby.class} not supported"
  end
end