code-ruby 0.7.3 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/bin/code +28 -28
- data/lib/code/node/base_10.rb +4 -1
- data/lib/code/node/call.rb +1 -1
- data/lib/code/node/decimal.rb +4 -1
- data/lib/code/node/dictionary.rb +1 -1
- data/lib/code/node/if.rb +5 -5
- data/lib/code/node/string.rb +10 -1
- data/lib/code/object/decimal.rb +3 -1
- data/lib/code/object/dictionary.rb +9 -3
- data/lib/code/object/function.rb +1 -1
- data/lib/code/object/integer.rb +5 -3
- data/lib/code/object/ruby_function.rb +2 -2
- data/lib/code/object/string.rb +2 -2
- data/lib/code/object.rb +3 -1
- data/lib/code/parser/list.rb +1 -2
- data/lib/code/parser/multiplication.rb +9 -1
- data/lib/code/ruby.rb +1 -1
- data/lib/code/type/hash.rb +4 -1
- data/lib/code/type/maybe.rb +1 -2
- data/lib/code/version.rb +1 -1
- data/lib/code.rb +7 -1
- data/spec/code/object/string_spec.rb +16 -0
- data/spec/code_spec.rb +4 -3
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 463ae3dc79fc4e22a6822e556ffbc299483203343ede2978409e9cfff74ba406
|
|
4
|
+
data.tar.gz: c1cf9ecfff4ea81e9e523f7c5951d8e51ded3595dae6b51c729f1d89c6d55e46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fab95b9f2f6c0e46c3ae1e7fc77b6b55198bad7354c89b35947a4c326a84b68853d9b817a5779d409a35ea79496ada6d4ad3b344ec8201cdb720d3a5b320ed86
|
|
7
|
+
data.tar.gz: 8c4133efb5de0813fea888156341a35edf3daf458730a19080cfae9681d6c8dfa2e36d13ec87552327744f19e46775e4bbc1c73019e17860a2d08dec62ce0693
|
data/Gemfile.lock
CHANGED
data/bin/code
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require_relative
|
|
4
|
+
require "optparse"
|
|
5
|
+
require_relative "../lib/code-ruby"
|
|
6
6
|
|
|
7
7
|
options = {
|
|
8
8
|
timeout: 0,
|
|
9
9
|
profile: false,
|
|
10
|
-
profiler:
|
|
10
|
+
profiler: "text",
|
|
11
11
|
input: "",
|
|
12
12
|
context: "",
|
|
13
13
|
parse: false
|
|
@@ -15,17 +15,17 @@ options = {
|
|
|
15
15
|
|
|
16
16
|
OptionParser
|
|
17
17
|
.new do |opts|
|
|
18
|
-
opts.banner =
|
|
18
|
+
opts.banner = "Usage: code [options]"
|
|
19
19
|
|
|
20
|
-
opts.on(
|
|
20
|
+
opts.on("-v", "--version", "Version of template") do |_input|
|
|
21
21
|
puts Code::Version
|
|
22
22
|
exit
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
opts.on(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
"-i INPUT",
|
|
27
|
+
"--input INPUT",
|
|
28
|
+
"Input in the code language (String or File)"
|
|
29
29
|
) do |input|
|
|
30
30
|
input = File.read(input) if File.exist?(input)
|
|
31
31
|
|
|
@@ -33,35 +33,35 @@ OptionParser
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
opts.on(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
"-c CONTEXT",
|
|
37
|
+
"--context CONTEXT",
|
|
38
|
+
"Context in the code language (String or File)"
|
|
39
39
|
) do |context|
|
|
40
40
|
context = File.read(context) if File.exist?(context)
|
|
41
41
|
|
|
42
42
|
options[:context] = context
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
opts.on(
|
|
45
|
+
opts.on("-p", "--parse", "Get parser results for input") do |parse|
|
|
46
46
|
options[:parse] = parse
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
opts.on(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
"-t TIMEOUT",
|
|
51
|
+
"--timeout TIMEOUT",
|
|
52
|
+
"Set timeout in seconds"
|
|
53
53
|
) { |timeout| options[:timeout] = timeout.to_f }
|
|
54
54
|
|
|
55
|
-
opts.on(
|
|
56
|
-
require
|
|
55
|
+
opts.on("--profile", "Profile Ruby code") do |_timeout|
|
|
56
|
+
require "ruby-prof"
|
|
57
57
|
options[:profile] = true
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
opts.on(
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
"--profiler TYPE",
|
|
62
|
+
"Profiler output type (text (default) or html)"
|
|
63
63
|
) do |profiler|
|
|
64
|
-
require
|
|
64
|
+
require "ruby-prof"
|
|
65
65
|
options[:profile] = true
|
|
66
66
|
options[:profiler] = profiler
|
|
67
67
|
end
|
|
@@ -74,21 +74,21 @@ if options[:parse]
|
|
|
74
74
|
pp Code::Parser.parse(options[:input]).to_raw
|
|
75
75
|
else
|
|
76
76
|
print Code.evaluate(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
options[:input],
|
|
78
|
+
options[:context],
|
|
79
|
+
output: $stdout,
|
|
80
|
+
error: $stderr,
|
|
81
|
+
timeout: options[:timeout]
|
|
82
|
+
)
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
if options[:profile]
|
|
86
86
|
result = RubyProf.stop
|
|
87
87
|
|
|
88
|
-
if options[:profiler] ==
|
|
88
|
+
if options[:profiler] == "text"
|
|
89
89
|
printer = RubyProf::FlatPrinter.new(result)
|
|
90
90
|
printer.print($stdout)
|
|
91
|
-
elsif options[:profiler] ==
|
|
91
|
+
elsif options[:profiler] == "html"
|
|
92
92
|
printer = RubyProf::GraphHtmlPrinter.new(result)
|
|
93
93
|
printer.print($stdout)
|
|
94
94
|
else
|
data/lib/code/node/base_10.rb
CHANGED
|
@@ -6,7 +6,10 @@ class Code
|
|
|
6
6
|
def initialize(parsed)
|
|
7
7
|
@whole = parsed.delete(:whole)
|
|
8
8
|
|
|
9
|
-
@exponent =
|
|
9
|
+
@exponent =
|
|
10
|
+
Node::Statement.new(parsed.delete(:exponent)) if parsed.key?(
|
|
11
|
+
:exponent
|
|
12
|
+
)
|
|
10
13
|
|
|
11
14
|
super(parsed)
|
|
12
15
|
end
|
data/lib/code/node/call.rb
CHANGED
data/lib/code/node/decimal.rb
CHANGED
|
@@ -6,7 +6,10 @@ class Code
|
|
|
6
6
|
def initialize(parsed)
|
|
7
7
|
@decimal = parsed.delete(:decimal)
|
|
8
8
|
|
|
9
|
-
@exponent =
|
|
9
|
+
@exponent =
|
|
10
|
+
Node::Statement.new(parsed.delete(:exponent)) if parsed.key?(
|
|
11
|
+
:exponent
|
|
12
|
+
)
|
|
10
13
|
|
|
11
14
|
super(parsed)
|
|
12
15
|
end
|
data/lib/code/node/dictionary.rb
CHANGED
|
@@ -8,7 +8,7 @@ class Code
|
|
|
8
8
|
if parsed.key?(:statement)
|
|
9
9
|
@key = Node::Statement.new(parsed.delete(:statement))
|
|
10
10
|
elsif parsed.key?(:name)
|
|
11
|
-
@key = Node::String.new([{text: parsed.delete(:name)}])
|
|
11
|
+
@key = Node::String.new([{ text: parsed.delete(:name) }])
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
@value = Node::Code.new(parsed.delete(:value)) if parsed[:value]
|
data/lib/code/node/if.rb
CHANGED
|
@@ -32,21 +32,21 @@ class Code
|
|
|
32
32
|
|
|
33
33
|
def evaluate(**args)
|
|
34
34
|
if @first_operator == IF_KEYWORD &&
|
|
35
|
-
|
|
35
|
+
@first_statement.evaluate(**args).truthy?
|
|
36
36
|
@first_body.evaluate(**args)
|
|
37
37
|
elsif @first_operator == UNLESS_KEYWORD &&
|
|
38
|
-
|
|
38
|
+
@first_statement.evaluate(**args).falsy?
|
|
39
39
|
@first_body.evaluate(**args)
|
|
40
40
|
else
|
|
41
41
|
@elses.each do |elses|
|
|
42
42
|
if elses.operator == ELSIF_KEYWORD &&
|
|
43
|
-
|
|
43
|
+
elses.statement.evaluate(**args).truthy?
|
|
44
44
|
return elses.body.evaluate(**args)
|
|
45
45
|
elsif elses.operator == IF_KEYWORD &&
|
|
46
|
-
|
|
46
|
+
elses.statement.evaluate(**args).truthy?
|
|
47
47
|
return elses.body.evaluate(**args)
|
|
48
48
|
elsif elses.operator == UNLESS_KEYWORD &&
|
|
49
|
-
|
|
49
|
+
elses.statement.evaluate(**args).falsy?
|
|
50
50
|
return elses.body.evaluate(**args)
|
|
51
51
|
elsif elses.operator == ELSE_KEYWORD
|
|
52
52
|
return elses.body.evaluate(**args)
|
data/lib/code/node/string.rb
CHANGED
|
@@ -20,7 +20,16 @@ class Code
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def evaluate(**_args)
|
|
23
|
-
::Code::Object::String.new(
|
|
23
|
+
::Code::Object::String.new(
|
|
24
|
+
@text
|
|
25
|
+
.gsub('\n', "\n")
|
|
26
|
+
.gsub('\r', "\r")
|
|
27
|
+
.gsub('\t', "\t")
|
|
28
|
+
.gsub('\b', "\b")
|
|
29
|
+
.gsub('\f', "\f")
|
|
30
|
+
.gsub('\a', "\a")
|
|
31
|
+
.gsub('\e', "\e")
|
|
32
|
+
)
|
|
24
33
|
end
|
|
25
34
|
end
|
|
26
35
|
|
data/lib/code/object/decimal.rb
CHANGED
|
@@ -9,7 +9,9 @@ class Code
|
|
|
9
9
|
@raw = BigDecimal(decimal)
|
|
10
10
|
|
|
11
11
|
return unless exponent
|
|
12
|
-
|
|
12
|
+
unless exponent.is_a?(Number)
|
|
13
|
+
raise ::Code::Error::TypeError, "exponent is not a number"
|
|
14
|
+
end
|
|
13
15
|
|
|
14
16
|
@raw *= 10**exponent.raw
|
|
15
17
|
end
|
|
@@ -215,7 +215,9 @@ class Code
|
|
|
215
215
|
def code_delete(*arguments, index: Integer.new(0), **globals)
|
|
216
216
|
default =
|
|
217
217
|
(
|
|
218
|
-
|
|
218
|
+
if arguments.last.is_a?(Function) && arguments.size > 1
|
|
219
|
+
arguments.last
|
|
220
|
+
end
|
|
219
221
|
)
|
|
220
222
|
|
|
221
223
|
arguments = arguments[..-2] if default
|
|
@@ -340,7 +342,9 @@ class Code
|
|
|
340
342
|
def code_fetch(*arguments, index: Integer.new(0), **globals)
|
|
341
343
|
default =
|
|
342
344
|
(
|
|
343
|
-
|
|
345
|
+
if arguments.last.is_a?(Function) && arguments.size > 1
|
|
346
|
+
arguments.last
|
|
347
|
+
end
|
|
344
348
|
)
|
|
345
349
|
|
|
346
350
|
arguments = arguments[..-2] if default
|
|
@@ -490,7 +494,9 @@ class Code
|
|
|
490
494
|
def code_merge(*arguments, **globals)
|
|
491
495
|
conflict =
|
|
492
496
|
(
|
|
493
|
-
|
|
497
|
+
if arguments.last.is_a?(Function) && arguments.size > 1
|
|
498
|
+
arguments.last
|
|
499
|
+
end
|
|
494
500
|
)
|
|
495
501
|
|
|
496
502
|
arguments = arguments[..-2] if conflict
|
data/lib/code/object/function.rb
CHANGED
data/lib/code/object/integer.rb
CHANGED
|
@@ -10,7 +10,9 @@ class Code
|
|
|
10
10
|
|
|
11
11
|
return unless exponent
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
unless exponent.is_a?(Number)
|
|
14
|
+
raise Code::Error::TypeError, "exponent is not a number"
|
|
15
|
+
end
|
|
14
16
|
|
|
15
17
|
@raw *= 10**exponent.raw
|
|
16
18
|
end
|
|
@@ -32,7 +34,7 @@ class Code
|
|
|
32
34
|
when "&", "bitwise_and"
|
|
33
35
|
sig(args) { Number }
|
|
34
36
|
code_bitwise_and(value)
|
|
35
|
-
when "*", "multiplication"
|
|
37
|
+
when "*", "multiplication", "×"
|
|
36
38
|
sig(args) { Number | String }
|
|
37
39
|
code_multiplication(value)
|
|
38
40
|
when "**", "power"
|
|
@@ -44,7 +46,7 @@ class Code
|
|
|
44
46
|
when "-", "minus", "unary_minus"
|
|
45
47
|
sig(args) { Number.maybe }
|
|
46
48
|
value ? code_minus(value) : code_unary_minus
|
|
47
|
-
when "/", "division"
|
|
49
|
+
when "/", "division", "÷"
|
|
48
50
|
sig(args) { Number }
|
|
49
51
|
code_division(value)
|
|
50
52
|
when "<", "inferior"
|
|
@@ -25,8 +25,8 @@ class Code
|
|
|
25
25
|
args
|
|
26
26
|
.select(&:keyword?)
|
|
27
27
|
.map do |argument|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
[argument.name.to_sym, Ruby.from_code(argument.value)]
|
|
29
|
+
end
|
|
30
30
|
.to_h
|
|
31
31
|
|
|
32
32
|
Ruby.to_code(raw.call(*regular_arguments, **keyword_arguments))
|
data/lib/code/object/string.rb
CHANGED
|
@@ -68,7 +68,7 @@ class Code
|
|
|
68
68
|
[
|
|
69
69
|
{
|
|
70
70
|
function: {
|
|
71
|
-
parameters: [{name: "_"}],
|
|
71
|
+
parameters: [{ name: "_" }],
|
|
72
72
|
body: [
|
|
73
73
|
{
|
|
74
74
|
left_operation: {
|
|
@@ -78,7 +78,7 @@ class Code
|
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
others: [
|
|
81
|
-
{operator: ".", statement: {call: {name: raw}}}
|
|
81
|
+
{ operator: ".", statement: { call: { name: raw } } }
|
|
82
82
|
]
|
|
83
83
|
}
|
|
84
84
|
}
|
data/lib/code/object.rb
CHANGED
|
@@ -149,7 +149,9 @@ class Code
|
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
def hash
|
|
152
|
-
|
|
152
|
+
unless respond_to?(:raw)
|
|
153
|
+
raise NotImplementedError, "#{self.class.name}#hash"
|
|
154
|
+
end
|
|
153
155
|
|
|
154
156
|
[self.class, raw].hash
|
|
155
157
|
end
|
data/lib/code/parser/list.rb
CHANGED
|
@@ -38,8 +38,7 @@ class Code
|
|
|
38
38
|
|
|
39
39
|
def root
|
|
40
40
|
(
|
|
41
|
-
opening_square_bracket.ignore << whitespace? <<
|
|
42
|
-
element.repeat <<
|
|
41
|
+
opening_square_bracket.ignore << whitespace? << element.repeat <<
|
|
43
42
|
(whitespace? << closing_square_bracket.ignore).maybe
|
|
44
43
|
).aka(:list) | String
|
|
45
44
|
end
|
|
@@ -11,6 +11,10 @@ class Code
|
|
|
11
11
|
str("*")
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def multiplication_sign
|
|
15
|
+
str("×")
|
|
16
|
+
end
|
|
17
|
+
|
|
14
18
|
def slash
|
|
15
19
|
str("/")
|
|
16
20
|
end
|
|
@@ -19,8 +23,12 @@ class Code
|
|
|
19
23
|
str("%")
|
|
20
24
|
end
|
|
21
25
|
|
|
26
|
+
def division_sign
|
|
27
|
+
str("÷")
|
|
28
|
+
end
|
|
29
|
+
|
|
22
30
|
def operator
|
|
23
|
-
asterisk | slash | percent
|
|
31
|
+
asterisk | slash | percent | multiplication_sign | division_sign
|
|
24
32
|
end
|
|
25
33
|
end
|
|
26
34
|
end
|
data/lib/code/ruby.rb
CHANGED
data/lib/code/type/hash.rb
CHANGED
|
@@ -15,7 +15,10 @@ class Code
|
|
|
15
15
|
argument = argument.raw
|
|
16
16
|
(argument.keys + hash.keys).uniq.all? do |key|
|
|
17
17
|
if hash[key]
|
|
18
|
-
valid_for?(
|
|
18
|
+
valid_for?(
|
|
19
|
+
expected: hash[key],
|
|
20
|
+
actual: argument[key] || Object::Nothing.new
|
|
21
|
+
)
|
|
19
22
|
else
|
|
20
23
|
false
|
|
21
24
|
end
|
data/lib/code/type/maybe.rb
CHANGED
data/lib/code/version.rb
CHANGED
data/lib/code.rb
CHANGED
|
@@ -37,7 +37,13 @@ class Code
|
|
|
37
37
|
if context == EMPTY_STRING
|
|
38
38
|
Object::Context.new
|
|
39
39
|
else
|
|
40
|
-
Code.evaluate(
|
|
40
|
+
Code.evaluate(
|
|
41
|
+
context,
|
|
42
|
+
timeout:,
|
|
43
|
+
output:,
|
|
44
|
+
error:,
|
|
45
|
+
ruby:
|
|
46
|
+
).code_to_context
|
|
41
47
|
end
|
|
42
48
|
|
|
43
49
|
context = ruby.merge(context)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Code::Object::String do
|
|
4
|
+
[
|
|
5
|
+
[":a", "a"],
|
|
6
|
+
[":a_b_c_0123", "a_b_c_0123"],
|
|
7
|
+
['"Hello"', "Hello"],
|
|
8
|
+
["'Hello'", "Hello"],
|
|
9
|
+
['"Hello\nWorld"', "Hello\nWorld"],
|
|
10
|
+
["'Hello\\nWorld'", "Hello\nWorld"],
|
|
11
|
+
].each do |input, expected|
|
|
12
|
+
it "(#{input}).to_s == #{expected.inspect}" do
|
|
13
|
+
expect(Code.evaluate(input).to_s).to eq(expected)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/spec/code_spec.rb
CHANGED
|
@@ -4,6 +4,7 @@ require "spec_helper"
|
|
|
4
4
|
|
|
5
5
|
RSpec.describe Code do
|
|
6
6
|
[
|
|
7
|
+
%w[9975×14÷8 17456.25],
|
|
7
8
|
["\r\n", "nothing"],
|
|
8
9
|
["1 + 1", "2"],
|
|
9
10
|
["a = 1", "1"],
|
|
@@ -147,7 +148,7 @@ RSpec.describe Code do
|
|
|
147
148
|
end
|
|
148
149
|
|
|
149
150
|
it "converts nil" do
|
|
150
|
-
ruby = Code::Ruby.from_code(Code.evaluate("a", ruby: {a: nil}))
|
|
151
|
+
ruby = Code::Ruby.from_code(Code.evaluate("a", ruby: { a: nil }))
|
|
151
152
|
|
|
152
153
|
expect(ruby).to eq(nil)
|
|
153
154
|
end
|
|
@@ -160,7 +161,7 @@ RSpec.describe Code do
|
|
|
160
161
|
|
|
161
162
|
it "works with nested objects" do
|
|
162
163
|
expect(
|
|
163
|
-
Code.evaluate("items.first.title", ruby: {items: [{title: "Hello"}]})
|
|
164
|
+
Code.evaluate("items.first.title", ruby: { items: [{ title: "Hello" }] })
|
|
164
165
|
).to eq(Code.evaluate(":Hello"))
|
|
165
166
|
end
|
|
166
167
|
|
|
@@ -169,7 +170,7 @@ RSpec.describe Code do
|
|
|
169
170
|
Code.evaluate(
|
|
170
171
|
"items.map { |item| item.title }",
|
|
171
172
|
ruby: {
|
|
172
|
-
items: [{title: "Hello"}]
|
|
173
|
+
items: [{ title: "Hello" }]
|
|
173
174
|
}
|
|
174
175
|
)
|
|
175
176
|
).to eq(Code.evaluate("[:Hello]"))
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: code-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dorian Marié
|
|
@@ -174,6 +174,7 @@ files:
|
|
|
174
174
|
- spec/code/object/list_spec.rb
|
|
175
175
|
- spec/code/object/nothing_spec.rb
|
|
176
176
|
- spec/code/object/range_spec.rb
|
|
177
|
+
- spec/code/object/string_spec.rb
|
|
177
178
|
- spec/code/parser/boolean_spec.rb
|
|
178
179
|
- spec/code/parser/chained_call.rb
|
|
179
180
|
- spec/code/parser/dictionary_spec.rb
|