code-ruby 0.7.4 → 0.7.6
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/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/global.rb +4 -1
- data/lib/code/object/integer.rb +3 -1
- 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/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 +18 -4
- 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: 64c95ed04939ffd5a6ef493a612ecd1e6b8d877d84be3d3f5bf3420a91642651
|
4
|
+
data.tar.gz: e8b9314d611e70a621f003ddf70d1e848a34dd479c907701c7bbddfdba7c136c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4fd860c6788054132fab89667660dde0907f816cc9c07d251569a3599b1504a23b620145173243cc2d2e0f22cd35bedec8e695bd589b195de22adf6ee12ddbc
|
7
|
+
data.tar.gz: 627970ecc40ebc5831be9a099fab08d8372564fd036baa247ae1b953ffa693feda02da7c9d23dbbe217afd57ec807184ecb40f75a59cdd97aab97ff897ee44dd
|
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/global.rb
CHANGED
@@ -12,7 +12,7 @@ class Code
|
|
12
12
|
arguments = args.fetch(:arguments, [])
|
13
13
|
output = args.fetch(:output)
|
14
14
|
context = args.fetch(:context)
|
15
|
-
multi_fetch(args, *GLOBALS)
|
15
|
+
globals = multi_fetch(args, *GLOBALS)
|
16
16
|
value = arguments.first&.value
|
17
17
|
|
18
18
|
case operator.to_s
|
@@ -28,6 +28,9 @@ class Code
|
|
28
28
|
when "Dictionary"
|
29
29
|
sig(args) { Object.maybe }
|
30
30
|
value ? value.code_to_dictionnary : Class.new(Dictionary)
|
31
|
+
when "fetch"
|
32
|
+
sig(args) { [Object, Function.maybe] }
|
33
|
+
context.code_fetch(*arguments.map(&:value), **globals)
|
31
34
|
when "Function"
|
32
35
|
sig(args) { Object.maybe }
|
33
36
|
value ? value.code_to_function : Class.new(Function)
|
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
|
@@ -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
|
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,7 +4,7 @@ require "spec_helper"
|
|
4
4
|
|
5
5
|
RSpec.describe Code do
|
6
6
|
[
|
7
|
-
[
|
7
|
+
%w[9975×14÷8 17456.25],
|
8
8
|
["\r\n", "nothing"],
|
9
9
|
["1 + 1", "2"],
|
10
10
|
["a = 1", "1"],
|
@@ -148,7 +148,7 @@ RSpec.describe Code do
|
|
148
148
|
end
|
149
149
|
|
150
150
|
it "converts nil" do
|
151
|
-
ruby = Code::Ruby.from_code(Code.evaluate("a", ruby: {a: nil}))
|
151
|
+
ruby = Code::Ruby.from_code(Code.evaluate("a", ruby: { a: nil }))
|
152
152
|
|
153
153
|
expect(ruby).to eq(nil)
|
154
154
|
end
|
@@ -159,9 +159,23 @@ RSpec.describe Code do
|
|
159
159
|
)
|
160
160
|
end
|
161
161
|
|
162
|
+
describe "#fetch" do
|
163
|
+
it "returns the value when present" do
|
164
|
+
expect(Code.evaluate("fetch(:downcase)", "{ downcase: 1 }")).to eq(
|
165
|
+
Code.evaluate("1")
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "returns the default value when not present" do
|
170
|
+
expect(Code.evaluate("fetch(:downcase) { 2 }")).to eq(
|
171
|
+
Code.evaluate("2")
|
172
|
+
)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
162
176
|
it "works with nested objects" do
|
163
177
|
expect(
|
164
|
-
Code.evaluate("items.first.title", ruby: {items: [{title: "Hello"}]})
|
178
|
+
Code.evaluate("items.first.title", ruby: { items: [{ title: "Hello" }] })
|
165
179
|
).to eq(Code.evaluate(":Hello"))
|
166
180
|
end
|
167
181
|
|
@@ -170,7 +184,7 @@ RSpec.describe Code do
|
|
170
184
|
Code.evaluate(
|
171
185
|
"items.map { |item| item.title }",
|
172
186
|
ruby: {
|
173
|
-
items: [{title: "Hello"}]
|
187
|
+
items: [{ title: "Hello" }]
|
174
188
|
}
|
175
189
|
)
|
176
190
|
).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.6
|
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
|