code-ruby 3.0.6 → 3.0.7
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/.rubocop.yml +8 -0
- data/Gemfile.lock +1 -1
- data/VERSION +1 -1
- data/bin/code +27 -3
- data/lib/code/error.rb +10 -5
- data/lib/code/extensions/active_support.rb +9 -0
- data/lib/code/extensions/array.rb +7 -0
- data/lib/code/extensions/big_decimal.rb +9 -0
- data/lib/code/extensions/class.rb +7 -0
- data/lib/code/extensions/false_class.rb +7 -0
- data/lib/code/extensions/float.rb +9 -0
- data/lib/code/extensions/hash.rb +7 -0
- data/lib/code/extensions/integer.rb +9 -0
- data/lib/code/extensions/module.rb +7 -0
- data/lib/code/extensions/nil_class.rb +7 -0
- data/lib/code/extensions/nokogiri.rb +11 -0
- data/lib/code/extensions/object.rb +9 -0
- data/lib/code/extensions/string.rb +7 -0
- data/lib/code/extensions/symbol.rb +7 -0
- data/lib/code/extensions/true_class.rb +7 -0
- data/lib/code/extensions/word_number_comparaisons.rb +407 -0
- data/lib/code/format.rb +73 -56
- data/lib/code/node/code.rb +2 -1
- data/lib/code/node/statement.rb +4 -2
- data/lib/code/node/string.rb +1 -1
- data/lib/code/node/while.rb +8 -10
- data/lib/code/object/date.rb +37 -17
- data/lib/code/object/function.rb +23 -11
- data/lib/code/object/global.rb +5 -4
- data/lib/code/object/html.rb +169 -52
- data/lib/code/object/http.rb +8 -8
- data/lib/code/object/ics.rb +22 -18
- data/lib/code/object/identifier_list.rb +12 -10
- data/lib/code/object/list.rb +1 -5
- data/lib/code/object/super.rb +2 -1
- data/lib/code/object/time.rb +46 -44
- data/lib/code/parser.rb +342 -121
- data/lib/code-ruby.rb +16 -149
- data/spec/bin/code_spec.rb +32 -0
- data/spec/code/format_spec.rb +7 -10
- data/spec/code/node/call_spec.rb +1 -3
- data/spec/code/object/function_spec.rb +4 -8
- data/spec/code/object/http_spec.rb +20 -0
- data/spec/code/object/ics_spec.rb +5 -5
- data/spec/code/object/list_spec.rb +1 -1
- data/spec/code/parser_spec.rb +22 -0
- data/spec/code_spec.rb +347 -328
- metadata +18 -2
- data/applies +0 -0
data/lib/code-ruby.rb
CHANGED
|
@@ -21,152 +21,19 @@ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
|
|
|
21
21
|
loader.ignore("#{__dir__}/code-ruby.rb")
|
|
22
22
|
loader.setup
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def four?
|
|
42
|
-
self == 4
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def five?
|
|
46
|
-
self == 5
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def six?
|
|
50
|
-
self == 6
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def seven?
|
|
54
|
-
self == 7
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def eight?
|
|
58
|
-
self == 8
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def nine?
|
|
62
|
-
self == 9
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def ten?
|
|
66
|
-
self == 10
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
class Object
|
|
71
|
-
alias is_an? is_a?
|
|
72
|
-
|
|
73
|
-
def to_code
|
|
74
|
-
raise NotImplementedError, "to_code not defined on #{self.class.name}"
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
class Class
|
|
79
|
-
def to_code
|
|
80
|
-
Code::Object::Class.new(self)
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
class Module
|
|
85
|
-
def to_code
|
|
86
|
-
Code::Object::Class.new(self)
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
class NilClass
|
|
91
|
-
def to_code
|
|
92
|
-
Code::Object::Nothing.new(self)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
class TrueClass
|
|
97
|
-
def to_code
|
|
98
|
-
Code::Object::Boolean.new(self)
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
class FalseClass
|
|
103
|
-
def to_code
|
|
104
|
-
Code::Object::Boolean.new(self)
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
class String
|
|
109
|
-
def to_code
|
|
110
|
-
Code::Object::String.new(self)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
class Symbol
|
|
115
|
-
def to_code
|
|
116
|
-
Code::Object::String.new(self)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
class Integer
|
|
121
|
-
include WordNumberComparaisons
|
|
122
|
-
|
|
123
|
-
def to_code
|
|
124
|
-
Code::Object::Integer.new(self)
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
class Float
|
|
129
|
-
include WordNumberComparaisons
|
|
130
|
-
|
|
131
|
-
def to_code
|
|
132
|
-
Code::Object::Decimal.new(self)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
class BigDecimal
|
|
137
|
-
include WordNumberComparaisons
|
|
138
|
-
|
|
139
|
-
def to_code
|
|
140
|
-
Code::Object::Decimal.new(self)
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
class Array
|
|
145
|
-
def to_code
|
|
146
|
-
Code::Object::List.new(self)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
class Hash
|
|
151
|
-
def to_code
|
|
152
|
-
Code::Object::Dictionary.new(self)
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
module Nokogiri
|
|
157
|
-
module XML
|
|
158
|
-
class Element
|
|
159
|
-
def to_code
|
|
160
|
-
Code::Object::Html.new(self)
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
module ActiveSupport
|
|
167
|
-
class TimeWithZone
|
|
168
|
-
def to_code
|
|
169
|
-
Code::Object::Time.new(self)
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
end
|
|
24
|
+
require_relative "code/extensions/word_number_comparaisons"
|
|
25
|
+
require_relative "code/extensions/object"
|
|
26
|
+
require_relative "code/extensions/class"
|
|
27
|
+
require_relative "code/extensions/module"
|
|
28
|
+
require_relative "code/extensions/nil_class"
|
|
29
|
+
require_relative "code/extensions/true_class"
|
|
30
|
+
require_relative "code/extensions/false_class"
|
|
31
|
+
require_relative "code/extensions/string"
|
|
32
|
+
require_relative "code/extensions/symbol"
|
|
33
|
+
require_relative "code/extensions/integer"
|
|
34
|
+
require_relative "code/extensions/float"
|
|
35
|
+
require_relative "code/extensions/big_decimal"
|
|
36
|
+
require_relative "code/extensions/array"
|
|
37
|
+
require_relative "code/extensions/hash"
|
|
38
|
+
require_relative "code/extensions/nokogiri"
|
|
39
|
+
require_relative "code/extensions/active_support"
|
data/spec/bin/code_spec.rb
CHANGED
|
@@ -5,6 +5,9 @@ require "spec_helper"
|
|
|
5
5
|
|
|
6
6
|
RSpec.describe "bin/code" do
|
|
7
7
|
let(:bin) { File.expand_path("../../bin/code", __dir__) }
|
|
8
|
+
let(:tmp_glob_dir) { File.expand_path("../tmp/code_glob", __dir__) }
|
|
9
|
+
|
|
10
|
+
after { FileUtils.rm_rf(tmp_glob_dir) }
|
|
8
11
|
|
|
9
12
|
it "formats input with -f" do
|
|
10
13
|
stdout, stderr, status = Open3.capture3(bin, "-f", "{a:1}")
|
|
@@ -13,4 +16,33 @@ RSpec.describe "bin/code" do
|
|
|
13
16
|
expect(stderr).to eq("")
|
|
14
17
|
expect(stdout).to eq("{ a: 1 }")
|
|
15
18
|
end
|
|
19
|
+
|
|
20
|
+
it "formats quoted globbed files with -f" do
|
|
21
|
+
FileUtils.mkdir_p(File.join(tmp_glob_dir, "a"))
|
|
22
|
+
FileUtils.mkdir_p(File.join(tmp_glob_dir, "b"))
|
|
23
|
+
File.write(File.join(tmp_glob_dir, "a", "first.code"), "{a:1}")
|
|
24
|
+
File.write(File.join(tmp_glob_dir, "b", "second.code"), "{b:2}")
|
|
25
|
+
|
|
26
|
+
stdout, stderr, status =
|
|
27
|
+
Open3.capture3(bin, "-f", File.join(tmp_glob_dir, "**", "*.code"))
|
|
28
|
+
|
|
29
|
+
expect(status.success?).to be(true)
|
|
30
|
+
expect(stderr).to eq("")
|
|
31
|
+
expect(stdout).to eq("{ a: 1 }\n\n{ b: 2 }")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "formats shell-expanded globbed files with -f" do
|
|
35
|
+
FileUtils.mkdir_p(File.join(tmp_glob_dir, "a"))
|
|
36
|
+
FileUtils.mkdir_p(File.join(tmp_glob_dir, "b"))
|
|
37
|
+
first = File.join(tmp_glob_dir, "a", "first.code")
|
|
38
|
+
second = File.join(tmp_glob_dir, "b", "second.code")
|
|
39
|
+
File.write(first, "{a:1}")
|
|
40
|
+
File.write(second, "{b:2}")
|
|
41
|
+
|
|
42
|
+
stdout, stderr, status = Open3.capture3(bin, "-f", first, second)
|
|
43
|
+
|
|
44
|
+
expect(status.success?).to be(true)
|
|
45
|
+
expect(stderr).to eq("")
|
|
46
|
+
expect(stdout).to eq("{ a: 1 }\n\n{ b: 2 }")
|
|
47
|
+
end
|
|
16
48
|
end
|
data/spec/code/format_spec.rb
CHANGED
|
@@ -6,19 +6,16 @@ require "json"
|
|
|
6
6
|
RSpec.describe Code::Format do
|
|
7
7
|
describe ".format" do
|
|
8
8
|
[
|
|
9
|
-
[
|
|
10
|
-
[
|
|
9
|
+
%w[Time.now.second Time.now.second],
|
|
10
|
+
%w[{} {}],
|
|
11
11
|
["[]", "[]"],
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[
|
|
12
|
+
%w["" ""],
|
|
13
|
+
%w[100000 100_000],
|
|
14
|
+
%w[1000000 1_000_000],
|
|
15
|
+
%w[1.0000000001 1.000_000_000_1],
|
|
16
16
|
["{a:1}", "{ a: 1 }"],
|
|
17
17
|
["[1,2,3]", "[1, 2, 3]"],
|
|
18
|
-
[
|
|
19
|
-
"[1, 2, 3].select { |n| n.even? }",
|
|
20
|
-
"[1, 2, 3].select { |n| n.even? }"
|
|
21
|
-
],
|
|
18
|
+
["[1, 2, 3].select { |n| n.even? }", "[1, 2, 3].select { |n| n.even? }"],
|
|
22
19
|
[
|
|
23
20
|
"if true 1 elsif false 2 else 3 end",
|
|
24
21
|
"if true\n 1\nelsif false\n 2\nelse\n 3\nend"
|
data/spec/code/node/call_spec.rb
CHANGED
|
@@ -39,8 +39,7 @@ RSpec.describe Code::Object::Function do
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
it "captures self for constructor-like functions that return self" do
|
|
42
|
-
result =
|
|
43
|
-
Code.evaluate(<<~CODE)
|
|
42
|
+
result = Code.evaluate(<<~CODE)
|
|
44
43
|
User = (given_name:, family_name:, birth_date:) => {
|
|
45
44
|
self.given_name = given_name.to_string.presence
|
|
46
45
|
self.family_name = family_name.to_string.presence
|
|
@@ -74,8 +73,7 @@ RSpec.describe Code::Object::Function do
|
|
|
74
73
|
end
|
|
75
74
|
|
|
76
75
|
it "supports constructor methods on functions" do
|
|
77
|
-
result =
|
|
78
|
-
Code.evaluate(<<~CODE)
|
|
76
|
+
result = Code.evaluate(<<~CODE)
|
|
79
77
|
User = (given_name:, family_name:) => {
|
|
80
78
|
self.given_name = given_name
|
|
81
79
|
self.family_name = family_name
|
|
@@ -103,8 +101,7 @@ RSpec.describe Code::Object::Function do
|
|
|
103
101
|
end
|
|
104
102
|
|
|
105
103
|
it "supports extending constructors and forwarding super arguments" do
|
|
106
|
-
result =
|
|
107
|
-
Code.evaluate(<<~CODE)
|
|
104
|
+
result = Code.evaluate(<<~CODE)
|
|
108
105
|
Person = (given_name:, family_name:) => {
|
|
109
106
|
self.given_name = given_name
|
|
110
107
|
self.family_name = family_name
|
|
@@ -135,8 +132,7 @@ RSpec.describe Code::Object::Function do
|
|
|
135
132
|
end
|
|
136
133
|
|
|
137
134
|
it "distinguishes super from super()" do
|
|
138
|
-
result =
|
|
139
|
-
Code.evaluate(<<~CODE)
|
|
135
|
+
result = Code.evaluate(<<~CODE)
|
|
140
136
|
Person = (given_name:, family_name:) => {
|
|
141
137
|
self.full_name = () => {
|
|
142
138
|
[given_name, family_name].join(" ")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Code::Object::Http do
|
|
6
|
+
describe ".code_get" do
|
|
7
|
+
it "wraps connection reset errors as Code::Error" do
|
|
8
|
+
allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(
|
|
9
|
+
Errno::ECONNRESET,
|
|
10
|
+
"Connection reset by peer - SSL_connect"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
expect do
|
|
14
|
+
described_class.code_get(
|
|
15
|
+
Code::Object::String.new("https://httpbin.org/status/200")
|
|
16
|
+
)
|
|
17
|
+
end.to raise_error(Code::Error, "http error")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -4,8 +4,7 @@ require "spec_helper"
|
|
|
4
4
|
|
|
5
5
|
RSpec.describe Code::Object::Ics do
|
|
6
6
|
it "normalizes binary event strings before json serialization" do
|
|
7
|
-
source =
|
|
8
|
-
<<~ICS
|
|
7
|
+
source = <<~ICS
|
|
9
8
|
BEGIN:VCALENDAR
|
|
10
9
|
VERSION:2.0
|
|
11
10
|
PRODID:-//code-ruby//EN
|
|
@@ -21,12 +20,13 @@ RSpec.describe Code::Object::Ics do
|
|
|
21
20
|
|
|
22
21
|
events = described_class.code_parse(Code::Object::String.new(source.b))
|
|
23
22
|
|
|
24
|
-
expect
|
|
23
|
+
expect do
|
|
24
|
+
expect(events.to_json).to include("Joséphine")
|
|
25
|
+
end.not_to output.to_stderr
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
it "serializes comma-separated descriptions as strings" do
|
|
28
|
-
source =
|
|
29
|
-
<<~ICS
|
|
29
|
+
source = <<~ICS
|
|
30
30
|
BEGIN:VCALENDAR
|
|
31
31
|
VERSION:2.0
|
|
32
32
|
PRODID:-//code-ruby//EN
|
|
@@ -10,7 +10,7 @@ RSpec.describe Code::Object::List do
|
|
|
10
10
|
["[] + []", "[]"],
|
|
11
11
|
["[1, 2, 3].second", "2"],
|
|
12
12
|
["[1, 2, 3].third", "3"],
|
|
13
|
-
[
|
|
13
|
+
%w[(1..100).to_list.one_hundredth 100],
|
|
14
14
|
["[1, 2, 3].one_hundredth", "nothing"]
|
|
15
15
|
].each do |input, expected|
|
|
16
16
|
it "#{input} == #{expected}" do
|
data/spec/code/parser_spec.rb
CHANGED
|
@@ -27,4 +27,26 @@ RSpec.describe Code::Parser do
|
|
|
27
27
|
described_class.parse(File.read(filename))
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
|
+
|
|
31
|
+
it "raises instead of hanging when lexing makes no progress" do
|
|
32
|
+
parser = described_class.new('"hello"')
|
|
33
|
+
|
|
34
|
+
allow(parser).to receive(:scan_string).and_return({ parts: [], index: 0 })
|
|
35
|
+
|
|
36
|
+
expect { parser.send(:lex, '"hello"') }.to raise_error(
|
|
37
|
+
Code::Parser::Error,
|
|
38
|
+
/lexer made no progress/
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "raises instead of hanging when parsing makes no progress" do
|
|
43
|
+
parser = described_class.new("a\n.b")
|
|
44
|
+
|
|
45
|
+
allow(parser).to receive(:skip_newlines)
|
|
46
|
+
|
|
47
|
+
expect { parser.parse }.to raise_error(
|
|
48
|
+
Code::Parser::Error,
|
|
49
|
+
/parser made no progress/
|
|
50
|
+
)
|
|
51
|
+
end
|
|
30
52
|
end
|