code-ruby 1.3.0 → 1.5.1

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.node-version +1 -1
  3. data/.npm-version +1 -1
  4. data/.rubocop.yml +8 -7
  5. data/.ruby-version +1 -1
  6. data/.tool-versions +2 -2
  7. data/Gemfile +1 -1
  8. data/Gemfile.lock +81 -65
  9. data/VERSION +1 -1
  10. data/bin/code +14 -7
  11. data/code-ruby.gemspec +2 -2
  12. data/lib/code/concerns/shared.rb +17 -61
  13. data/lib/code/concerns.rb +2 -0
  14. data/lib/code/node/code.rb +10 -0
  15. data/lib/code/node/dictionary.rb +34 -15
  16. data/lib/code/node/function_parameter.rb +1 -1
  17. data/lib/code/object/boolean.rb +2 -2
  18. data/lib/code/object/class.rb +2 -2
  19. data/lib/code/object/code.rb +8 -2
  20. data/lib/code/object/context.rb +1 -1
  21. data/lib/code/object/date.rb +3 -3
  22. data/lib/code/object/decimal.rb +3 -3
  23. data/lib/code/object/dictionary.rb +23 -7
  24. data/lib/code/object/duration.rb +3 -3
  25. data/lib/code/object/function.rb +2 -2
  26. data/lib/code/object/global.rb +7 -6
  27. data/lib/code/object/html.rb +4 -5
  28. data/lib/code/object/http.rb +0 -2
  29. data/lib/code/object/integer.rb +3 -3
  30. data/lib/code/object/list.rb +10 -3
  31. data/lib/code/object/nothing.rb +2 -2
  32. data/lib/code/object/parameter.rb +2 -2
  33. data/lib/code/object/range.rb +2 -2
  34. data/lib/code/object/string.rb +13 -12
  35. data/lib/code/object/time.rb +2 -6
  36. data/lib/code/object.rb +2 -6
  37. data/lib/code/parser/call.rb +11 -5
  38. data/lib/code/parser/class.rb +1 -34
  39. data/lib/code/parser/dictionary.rb +7 -5
  40. data/lib/code/parser/equal.rb +0 -4
  41. data/lib/code/parser/function.rb +24 -2
  42. data/lib/code/parser/group.rb +32 -2
  43. data/lib/code/parser/if.rb +31 -4
  44. data/lib/code/parser/name.rb +7 -2
  45. data/lib/code/parser/while.rb +32 -1
  46. data/lib/code/type/sig.rb +2 -2
  47. data/lib/code/type.rb +1 -1
  48. data/lib/code.rb +25 -18
  49. data/package-lock.json +2 -2
  50. data/package.json +2 -2
  51. data/spec/code/object/http_spec.rb +70 -66
  52. data/spec/code_spec.rb +6 -2
  53. metadata +4 -6
  54. data/TODO +0 -219
  55. data/bin/console +0 -6
@@ -83,6 +83,10 @@ class Code
83
83
  str("do")
84
84
  end
85
85
 
86
+ def begin_keyword
87
+ str("begin")
88
+ end
89
+
86
90
  def end_keyword
87
91
  str("end")
88
92
  end
@@ -113,8 +117,9 @@ class Code
113
117
 
114
118
  def root
115
119
  (do_keyword << separator).absent << (
116
- else_keyword << separator
117
- ).absent << (elsif_keyword << separator).absent <<
120
+ begin_keyword << separator
121
+ ).absent << (else_keyword << separator).absent <<
122
+ (elsif_keyword << separator).absent <<
118
123
  (end_keyword << separator).absent << character.repeat(1)
119
124
  end
120
125
  end
@@ -11,6 +11,10 @@ class Code
11
11
  Whitespace
12
12
  end
13
13
 
14
+ def whitespace?
15
+ whitespace.maybe
16
+ end
17
+
14
18
  def code
15
19
  Code
16
20
  end
@@ -27,10 +31,37 @@ class Code
27
31
  str("end")
28
32
  end
29
33
 
34
+ def do_keyword
35
+ str("do")
36
+ end
37
+
38
+ def begin_keyword
39
+ str("begin")
40
+ end
41
+
30
42
  def loop_keyword
31
43
  str("loop")
32
44
  end
33
45
 
46
+ def opening_curly_bracket
47
+ str("{")
48
+ end
49
+
50
+ def closing_curly_bracket
51
+ str("}")
52
+ end
53
+
54
+ def body
55
+ (
56
+ (begin_keyword | do_keyword).ignore << whitespace << code <<
57
+ (whitespace? << end_keyword).maybe.ignore
58
+ ) |
59
+ (
60
+ opening_curly_bracket.ignore << whitespace? << code <<
61
+ (whitespace? << closing_curly_bracket).maybe.ignore
62
+ ) | (code << (whitespace? << end_keyword).maybe.ignore)
63
+ end
64
+
34
65
  def root
35
66
  (
36
67
  (
@@ -38,7 +69,7 @@ class Code
38
69
  (while_keyword | until_keyword).aka(:operator) << whitespace <<
39
70
  statement.aka(:statement)
40
71
  ) | (loop_keyword.aka(:operator) << whitespace)
41
- ) << code.aka(:body) << end_keyword.maybe
72
+ ) << body.aka(:body)
42
73
  ).aka(:while) | statement
43
74
  end
44
75
  end
data/lib/code/type/sig.rb CHANGED
@@ -111,7 +111,7 @@ class Code
111
111
  actual_arguments.each do |actual|
112
112
  expected = expected_arguments[expected_index]
113
113
  if expected.is_a?(Repeat)
114
- if valid_for?(expected:, actual:)
114
+ if valid_for?(expected: expected, actual: actual)
115
115
  repeat_index += 1
116
116
  elsif repeat_index >= expected.min_arguments
117
117
  expected_index += 1
@@ -122,7 +122,7 @@ class Code
122
122
  "#{function}: expected #{expected.name}, got #{actual.inspect}"
123
123
  )
124
124
  end
125
- elsif valid_for?(expected:, actual:)
125
+ elsif valid_for?(expected: expected, actual: actual)
126
126
  expected_index += 1
127
127
  repeat_index = 0
128
128
  else
data/lib/code/type.rb CHANGED
@@ -7,7 +7,7 @@ class Code
7
7
  end
8
8
 
9
9
  def repeat(minimum = 0, maximum = nil)
10
- Repeat.new(self, minimum:, maximum:)
10
+ Repeat.new(self, minimum: minimum, maximum: maximum)
11
11
  end
12
12
 
13
13
  def |(other)
data/lib/code.rb CHANGED
@@ -1,43 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Code
4
- GLOBALS = %i[output error context object].freeze
4
+ GLOBALS = %i[context error input object output source object].freeze
5
5
  DEFAULT_TIMEOUT = 0
6
6
 
7
7
  def initialize(
8
- input,
9
- output: StringIO.new,
8
+ source,
9
+ context: Object::Context.new,
10
10
  error: StringIO.new,
11
+ input: StringIO.new,
12
+ object: Object::Global.new,
13
+ output: StringIO.new,
11
14
  timeout: DEFAULT_TIMEOUT
12
15
  )
16
+ @context = context
17
+ @error = error
13
18
  @input = input
19
+ @object = object
14
20
  @output = output
15
- @error = error
16
- @timeout = timeout || DEFAULT_TIMEOUT
17
- @context = Object::Context.new
21
+ @source = source
22
+ @timeout = timeout
18
23
  end
19
24
 
20
- def self.parse(input, timeout: DEFAULT_TIMEOUT)
21
- Timeout.timeout(timeout) { Parser.parse(input).to_raw }
25
+ def self.parse(source, timeout: DEFAULT_TIMEOUT)
26
+ Timeout.timeout(timeout) { Parser.parse(source).to_raw }
22
27
  end
23
28
 
24
- def self.evaluate(
25
- input,
26
- output: StringIO.new,
27
- error: StringIO.new,
28
- timeout: DEFAULT_TIMEOUT
29
- )
30
- new(input, output:, error:, timeout:).evaluate
29
+ def self.evaluate(...)
30
+ new(...).evaluate
31
31
  end
32
32
 
33
33
  def evaluate
34
34
  Timeout.timeout(timeout) do
35
- parsed = Code.parse(input)
36
- Node::Code.new(parsed).evaluate(context:, output:, error:)
35
+ Node::Code.new(Code.parse(source)).evaluate(
36
+ context: context,
37
+ error: error,
38
+ input: input,
39
+ object: object,
40
+ output: output,
41
+ source: source,
42
+ timeout: timeout
43
+ )
37
44
  end
38
45
  end
39
46
 
40
47
  private
41
48
 
42
- attr_reader :input, :timeout, :output, :error, :context
49
+ attr_reader :context, :error, :input, :object, :output, :source, :timeout
43
50
  end
data/package-lock.json CHANGED
@@ -6,8 +6,8 @@
6
6
  "": {
7
7
  "license": "MIT",
8
8
  "engines": {
9
- "node": "22.5.1",
10
- "npm": "10.8.2"
9
+ "node": "23.11.0",
10
+ "npm": "11.2.0"
11
11
  }
12
12
  }
13
13
  }
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "license": "MIT",
3
3
  "engines": {
4
- "node": "22.5.1",
5
- "npm": "10.8.2"
4
+ "node": "23.11.0",
5
+ "npm": "11.2.0"
6
6
  }
7
7
  }
@@ -3,73 +3,77 @@
3
3
  require "spec_helper"
4
4
 
5
5
  RSpec.describe Code::Object::Http do
6
- %w[get head post put delete options trace patch].each do |verb|
6
+ VERBS = %w[get head post put delete options trace patch].freeze
7
+
8
+ RESPONSE_CODES = {
9
+ continue: 100,
10
+ switching_protocols: 101,
11
+ processing: 102,
12
+ early_hints: 103,
13
+ ok: 200,
14
+ created: 201,
15
+ accepted: 202,
16
+ non_authoritative_information: 203,
17
+ no_content: 204,
18
+ reset_content: 205,
19
+ partial_content: 206,
20
+ multi_status: 207,
21
+ already_reported: 208,
22
+ im_used: 226,
23
+ multiple_choices: 300,
24
+ moved_permanently: 301,
25
+ found: 302,
26
+ see_other: 303,
27
+ not_modified: 304,
28
+ use_proxy: 305,
29
+ reserved: 306,
30
+ temporary_redirect: 307,
31
+ permanent_redirect: 308,
32
+ bad_request: 400,
33
+ unauthorized: 401,
34
+ payment_required: 402,
35
+ forbidden: 403,
36
+ not_found: 404,
37
+ method_not_allowed: 405,
38
+ not_acceptable: 406,
39
+ proxy_authentication_required: 407,
40
+ request_timeout: 408,
41
+ conflict: 409,
42
+ gone: 410,
43
+ length_required: 411,
44
+ precondition_failed: 412,
45
+ request_entity_too_large: 413,
46
+ request_uri_too_long: 414,
47
+ unsupported_media_type: 415,
48
+ requested_range_not_satisfiable: 416,
49
+ expectation_failed: 417,
50
+ misdirected_request: 421,
51
+ unprocessable_entity: 422,
52
+ locked: 423,
53
+ failed_dependency: 424,
54
+ too_early: 425,
55
+ upgrade_required: 426,
56
+ precondition_required: 428,
57
+ too_many_requests: 429,
58
+ request_header_fields_too_large: 431,
59
+ unavailable_for_legal_reasons: 451,
60
+ internal_server_error: 500,
61
+ not_implemented: 501,
62
+ bad_gateway: 502,
63
+ service_unavailable: 503,
64
+ gateway_timeout: 504,
65
+ http_version_not_supported: 505,
66
+ variant_also_negotiates: 506,
67
+ insufficient_storage: 507,
68
+ loop_detected: 508,
69
+ bandwidth_limit_exceeded: 509,
70
+ not_extended: 510,
71
+ network_authentication_required: 511
72
+ }.freeze
73
+
74
+ VERBS.each do |verb|
7
75
  describe ".#{verb}" do
8
- {
9
- continue: 100,
10
- switching_protocols: 101,
11
- processing: 102,
12
- early_hints: 103,
13
- ok: 200,
14
- created: 201,
15
- accepted: 202,
16
- non_authoritative_information: 203,
17
- no_content: 204,
18
- reset_content: 205,
19
- partial_content: 206,
20
- multi_status: 207,
21
- already_reported: 208,
22
- im_used: 226,
23
- multiple_choices: 300,
24
- moved_permanently: 301,
25
- found: 302,
26
- see_other: 303,
27
- not_modified: 304,
28
- use_proxy: 305,
29
- reserved: 306,
30
- temporary_redirect: 307,
31
- permanent_redirect: 308,
32
- bad_request: 400,
33
- unauthorized: 401,
34
- payment_required: 402,
35
- forbidden: 403,
36
- not_found: 404,
37
- method_not_allowed: 405,
38
- not_acceptable: 406,
39
- proxy_authentication_required: 407,
40
- request_timeout: 408,
41
- conflict: 409,
42
- gone: 410,
43
- length_required: 411,
44
- precondition_failed: 412,
45
- request_entity_too_large: 413,
46
- request_uri_too_long: 414,
47
- unsupported_media_type: 415,
48
- requested_range_not_satisfiable: 416,
49
- expectation_failed: 417,
50
- misdirected_request: 421,
51
- unprocessable_entity: 422,
52
- locked: 423,
53
- failed_dependency: 424,
54
- too_early: 425,
55
- upgrade_required: 426,
56
- precondition_required: 428,
57
- too_many_requests: 429,
58
- request_header_fields_too_large: 431,
59
- unavailable_for_legal_reasons: 451,
60
- internal_server_error: 500,
61
- not_implemented: 501,
62
- bad_gateway: 502,
63
- service_unavailable: 503,
64
- gateway_timeout: 504,
65
- http_version_not_supported: 505,
66
- variant_also_negotiates: 506,
67
- insufficient_storage: 507,
68
- loop_detected: 508,
69
- bandwidth_limit_exceeded: 509,
70
- not_extended: 510,
71
- network_authentication_required: 511
72
- }.each do |status, code|
76
+ RESPONSE_CODES.each do |status, code|
73
77
  it "returns #{code} as code and #{status} as status" do
74
78
  expect(Code.evaluate(<<~INPUT)).to eq(Code.evaluate(<<~OUTPUT))
75
79
  response = Http.#{verb}("https://httpbin.org/status/#{code}")
data/spec/code_spec.rb CHANGED
@@ -339,6 +339,8 @@ RSpec.describe Code do
339
339
  ["[1, 2, 3].any?(&:even?)", "true"],
340
340
  ["[1, 2, 3].none?", "false"],
341
341
  ["[1, 2, 3].none?(&:even?)", "false"],
342
+ ["subject = 1 { subject }", "{ subject: 1 }"],
343
+ ["subject = 1 { subject: }", "{ subject: 1 }"],
342
344
  ["'{1} {2}'", "'1 2'"],
343
345
  %w[Json.parse("1") 1],
344
346
  %w[{a:1}.to_query "a=1"],
@@ -346,20 +348,22 @@ RSpec.describe Code do
346
348
  ].each do |input, expected|
347
349
  it "#{input} == #{expected}" do
348
350
  output = StringIO.new
349
- code_input = described_class.evaluate(input, output:)
351
+ code_input = described_class.evaluate(input, output: output)
350
352
  code_expected = described_class.evaluate(expected)
351
353
  expect(code_input).to eq(code_expected)
352
354
  expect(output.string).to eq("")
353
355
  next if code_input.is_a?(Code::Object::Decimal)
354
356
 
355
357
  expect(code_input.to_json).to eq(code_expected.to_json)
358
+ YAML.unsafe_load(code_input.to_yaml)
359
+ YAML.unsafe_load(code_expected.to_yaml)
356
360
  end
357
361
  end
358
362
 
359
363
  [["puts(true)", "true\n"], %w[print(false) false]].each do |input, expected|
360
364
  it "#{input} prints #{expected}" do
361
365
  output = StringIO.new
362
- described_class.evaluate(input, output:)
366
+ described_class.evaluate(input, output: output)
363
367
  expect(output.string).to eq(expected)
364
368
  end
365
369
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-28 00:00:00.000000000 Z
10
+ date: 2025-05-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -164,7 +164,7 @@ dependencies:
164
164
  - !ruby/object:Gem::Version
165
165
  version: '0'
166
166
  description: a programming language for the internet
167
- email: dorian@dorianmarie.fr
167
+ email: dorian@dorianmarie.com
168
168
  executables:
169
169
  - code
170
170
  extensions: []
@@ -185,13 +185,11 @@ files:
185
185
  - LICENSE
186
186
  - README.md
187
187
  - Rakefile
188
- - TODO
189
188
  - VERSION
190
189
  - bin/bundle
191
190
  - bin/bundle-audit
192
191
  - bin/bundler-audit
193
192
  - bin/code
194
- - bin/console
195
193
  - bin/dorian
196
194
  - bin/rspec
197
195
  - bin/rubocop
@@ -338,7 +336,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
338
336
  requirements:
339
337
  - - ">="
340
338
  - !ruby/object:Gem::Version
341
- version: '3.1'
339
+ version: '3.0'
342
340
  required_rubygems_version: !ruby/object:Gem::Requirement
343
341
  requirements:
344
342
  - - ">="
data/TODO DELETED
@@ -1,219 +0,0 @@
1
- to_query
2
- to_h
3
- include?
4
- &
5
- shelljoin
6
- *
7
- +
8
- blank?
9
- -
10
- present?
11
- from
12
- extract!
13
- at
14
- fetch
15
- union
16
- difference
17
- intersection
18
- intersect?
19
- push
20
- append
21
- pop
22
- shift
23
- unshift
24
- each_index
25
- join
26
- rotate
27
- rotate!
28
- sort!
29
- sort_by!
30
- collect!
31
- map!
32
- select!
33
- filter!
34
- keep_if
35
- values_at
36
- sort
37
- delete_if
38
- reject!
39
- delete_at
40
- count
41
- fill
42
- find_index
43
- rassoc
44
- select
45
- filter
46
- uniq!
47
- reject
48
- collect
49
- map
50
- compact!
51
- assoc
52
- flatten!
53
- permutation
54
- transpose
55
- flatten
56
- repeated_combination
57
- product
58
- combination
59
- repeated_permutation
60
- any?
61
- all?
62
- minmax
63
- bsearch_index
64
- none?
65
- one?
66
- bsearch
67
- reverse_each
68
- deconstruct
69
- |
70
- first
71
- zip
72
- take
73
- take_while
74
- drop
75
- drop_while
76
- cycle
77
- shuffle!
78
- shuffle
79
- sample
80
- <=>
81
- <<
82
- sum
83
- uniq
84
- compact
85
- ==
86
- second
87
- pack
88
- to
89
- []
90
- []=
91
- empty?
92
- eql?
93
- insert
94
- compact_blank!
95
- index
96
- rindex
97
- replace
98
- clear
99
- max
100
- min
101
- hash
102
- inspect
103
- including
104
- excluding
105
- length
106
- size
107
- third
108
- without
109
- each
110
- fourth
111
- fifth
112
- forty_two
113
- third_to_last
114
- second_to_last
115
- extract_options!
116
- in_groups_of
117
- reverse
118
- to_ary
119
- concat
120
- prepend
121
- reverse!
122
- in_groups
123
- to_a
124
- to_s
125
- split
126
- inquiry
127
- to_sentence
128
- as_json
129
- pretty_print
130
- delete
131
- to_formatted_s
132
- pretty_print_cycle
133
- to_xml
134
- to_fs
135
- slice
136
- slice!
137
- dig
138
- to_json
139
- chunk
140
- slice_before
141
- slice_after
142
- slice_when
143
- chunk_while
144
- maximum
145
- chain
146
- to_set
147
- lazy
148
- many?
149
- sole
150
- exclude?
151
- minimum
152
- pick
153
- index_by
154
- index_with
155
- pluck
156
- in_order_of
157
- compact_blank
158
- find
159
- entries
160
- sort_by
161
- grep
162
- grep_v
163
- detect
164
- find_all
165
- filter_map
166
- flat_map
167
- collect_concat
168
- inject
169
- reduce
170
- partition
171
- group_by
172
- tally
173
- min_by
174
- max_by
175
- minmax_by
176
- member?
177
- each_with_index
178
- each_entry
179
- each_slice
180
- each_cons
181
- each_with_object
182
- to_yaml
183
- duplicable?
184
- in?
185
- with
186
- presence_in
187
- presence
188
- acts_like?
189
- html_safe?
190
- with_options
191
- try!
192
- try
193
- pretty_print_inspect
194
- singleton_class
195
- dup
196
- itself
197
- kind_of?
198
- is_a?
199
- display
200
- class_eval
201
- extend
202
- clone
203
- frozen?
204
- then
205
- tap
206
- yield_self
207
- ===
208
- class
209
- !~
210
- nil?
211
- respond_to?
212
- freeze
213
- object_id
214
- to_enum
215
- enum_for
216
- pretty_inspect
217
- equal?
218
- !
219
- !=
data/bin/console DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative "../lib/code-ruby"
5
-
6
- binding.irb