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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/Gemfile.lock +1 -1
  4. data/VERSION +1 -1
  5. data/bin/code +27 -3
  6. data/lib/code/error.rb +10 -5
  7. data/lib/code/extensions/active_support.rb +9 -0
  8. data/lib/code/extensions/array.rb +7 -0
  9. data/lib/code/extensions/big_decimal.rb +9 -0
  10. data/lib/code/extensions/class.rb +7 -0
  11. data/lib/code/extensions/false_class.rb +7 -0
  12. data/lib/code/extensions/float.rb +9 -0
  13. data/lib/code/extensions/hash.rb +7 -0
  14. data/lib/code/extensions/integer.rb +9 -0
  15. data/lib/code/extensions/module.rb +7 -0
  16. data/lib/code/extensions/nil_class.rb +7 -0
  17. data/lib/code/extensions/nokogiri.rb +11 -0
  18. data/lib/code/extensions/object.rb +9 -0
  19. data/lib/code/extensions/string.rb +7 -0
  20. data/lib/code/extensions/symbol.rb +7 -0
  21. data/lib/code/extensions/true_class.rb +7 -0
  22. data/lib/code/extensions/word_number_comparaisons.rb +407 -0
  23. data/lib/code/format.rb +73 -56
  24. data/lib/code/node/code.rb +2 -1
  25. data/lib/code/node/statement.rb +4 -2
  26. data/lib/code/node/string.rb +1 -1
  27. data/lib/code/node/while.rb +8 -10
  28. data/lib/code/object/date.rb +37 -17
  29. data/lib/code/object/function.rb +23 -11
  30. data/lib/code/object/global.rb +5 -4
  31. data/lib/code/object/html.rb +169 -52
  32. data/lib/code/object/http.rb +8 -8
  33. data/lib/code/object/ics.rb +22 -18
  34. data/lib/code/object/identifier_list.rb +12 -10
  35. data/lib/code/object/list.rb +1 -5
  36. data/lib/code/object/super.rb +2 -1
  37. data/lib/code/object/time.rb +46 -44
  38. data/lib/code/parser.rb +342 -121
  39. data/lib/code-ruby.rb +16 -149
  40. data/spec/bin/code_spec.rb +32 -0
  41. data/spec/code/format_spec.rb +7 -10
  42. data/spec/code/node/call_spec.rb +1 -3
  43. data/spec/code/object/function_spec.rb +4 -8
  44. data/spec/code/object/http_spec.rb +20 -0
  45. data/spec/code/object/ics_spec.rb +5 -5
  46. data/spec/code/object/list_spec.rb +1 -1
  47. data/spec/code/parser_spec.rb +22 -0
  48. data/spec/code_spec.rb +347 -328
  49. metadata +18 -2
  50. 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
- module WordNumberComparaisons
25
- def zero?
26
- zero?
27
- end
28
-
29
- def one?
30
- self == 1
31
- end
32
-
33
- def two?
34
- self == 2
35
- end
36
-
37
- def three?
38
- self == 3
39
- end
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"
@@ -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
@@ -6,19 +6,16 @@ require "json"
6
6
  RSpec.describe Code::Format do
7
7
  describe ".format" do
8
8
  [
9
- ["Time.now.second", "Time.now.second"],
10
- ["{}", "{}"],
9
+ %w[Time.now.second Time.now.second],
10
+ %w[{} {}],
11
11
  ["[]", "[]"],
12
- ['""', '""'],
13
- ["100000", "100_000"],
14
- ["1000000", "1_000_000"],
15
- ["1.0000000001", "1.000_000_000_1"],
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"
@@ -3,9 +3,7 @@
3
3
  require "spec_helper"
4
4
 
5
5
  RSpec.describe "parser call" do
6
- [
7
- "f(end: 2)"
8
- ].each do |input|
6
+ ["f(end: 2)"].each do |input|
9
7
  it "parses #{input}" do
10
8
  Code::Parser.parse(input)
11
9
  end
@@ -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 { expect(events.to_json).to include("Joséphine") }.not_to output.to_stderr
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
- ["(1..100).to_list.one_hundredth", "100"],
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
@@ -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