code-ruby 0.11.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +5 -3
  4. data/Rakefile +5 -0
  5. data/bin/code +6 -0
  6. data/lib/code/node/base_10.rb +2 -2
  7. data/lib/code/node/base_16.rb +1 -5
  8. data/lib/code/node/base_2.rb +1 -5
  9. data/lib/code/node/base_8.rb +1 -5
  10. data/lib/code/node/call.rb +4 -4
  11. data/lib/code/node/code.rb +2 -1
  12. data/lib/code/node/decimal.rb +1 -4
  13. data/lib/code/node/dictionary.rb +6 -2
  14. data/lib/code/node/function.rb +3 -3
  15. data/lib/code/node/function_parameter.rb +5 -1
  16. data/lib/code/node/if.rb +2 -1
  17. data/lib/code/node/list.rb +2 -1
  18. data/lib/code/node/statement.rb +23 -23
  19. data/lib/code/node/string.rb +2 -1
  20. data/lib/code/object/argument.rb +4 -3
  21. data/lib/code/object/boolean.rb +4 -24
  22. data/lib/code/object/class.rb +3 -19
  23. data/lib/code/object/code.rb +16 -0
  24. data/lib/code/object/context.rb +6 -9
  25. data/lib/code/object/date.rb +25 -17
  26. data/lib/code/object/decimal.rb +30 -38
  27. data/lib/code/object/dictionary.rb +6 -21
  28. data/lib/code/object/duration.rb +7 -21
  29. data/lib/code/object/function.rb +29 -45
  30. data/lib/code/object/global.rb +56 -40
  31. data/lib/code/object/identifier_list.rb +0 -4
  32. data/lib/code/object/integer.rb +23 -46
  33. data/lib/code/object/json.rb +29 -0
  34. data/lib/code/object/list.rb +4 -21
  35. data/lib/code/object/nothing.rb +2 -20
  36. data/lib/code/object/parameter.rb +51 -0
  37. data/lib/code/object/range.rb +12 -27
  38. data/lib/code/object/string.rb +6 -27
  39. data/lib/code/object/time.rb +14 -24
  40. data/lib/code/object.rb +155 -15
  41. data/lib/code/parser.rb +1 -1
  42. data/lib/code/type.rb +10 -2
  43. data/lib/code/version.rb +1 -1
  44. data/lib/code-ruby.rb +6 -0
  45. data/lib/code.rb +8 -5
  46. data/spec/code/object/dictionary_spec.rb +0 -2
  47. data/spec/code_spec.rb +141 -29
  48. metadata +6 -3
  49. data/lib/code/object/number.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97ce31f3a36a57e14f607ded3383aa3c71866824c6e57541c70d48962c77b9ef
4
- data.tar.gz: '0229023c391084763f03d2ffbfd82af81da2d996666719a49ad169d7740c4d6c'
3
+ metadata.gz: dd20de2ab8f69a2256eb18bd2eea8cc2876d8f828cbdf7c086996934ef8b6eb7
4
+ data.tar.gz: df97885df1ee89d2e3766090980a1fd8467091b982dacf9c1505cb0684d7b466
5
5
  SHA512:
6
- metadata.gz: 996b1594dbc1192dbad2b0c64d605d9eccff6d5622437ef5974464648e5f2cd2ee57aad50fce9279f8027f1378fc7c2652106265a2fc79bbe21b224210228c9d
7
- data.tar.gz: ec405b4bc88648344f4860fb7350695aa447a5905e9a56e7230c771d5ea76e22515fe74ac0fc30771e27a9d67f4eda85b0d2475484d81a5d2c604c5a901913ae
6
+ metadata.gz: 29c23d759b84cfb83e9dbc16913d77c6e2b95b86d3a5a65e2f8571199d58c671810806ed49939fe1e1931446571681c216fa261828b07908c43aa0832dfc8177
7
+ data.tar.gz: 46cbd45a6b53094ed19e2058728cbf6e76ba2fa34d253de4e6be6083cf61a8c26d84a3d943358311321cd32fd44201a55c00ee8605f2adee8216f46a0cfe715e
data/Gemfile CHANGED
@@ -6,5 +6,6 @@ gemspec
6
6
 
7
7
  ruby "3.3.0"
8
8
 
9
+ gem "rake"
9
10
  gem "rspec"
10
11
  gem "ruby-prof"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- code-ruby (0.10.4)
4
+ code-ruby (0.13.0)
5
5
  activesupport (~> 7)
6
6
  bigdecimal (~> 3)
7
7
  json (~> 2)
@@ -27,13 +27,14 @@ GEM
27
27
  connection_pool (2.4.1)
28
28
  diff-lcs (1.5.1)
29
29
  drb (2.2.1)
30
- i18n (1.14.1)
30
+ i18n (1.14.4)
31
31
  concurrent-ruby (~> 1.0)
32
32
  json (2.7.1)
33
- language-ruby (0.7.0)
33
+ language-ruby (0.8.0)
34
34
  zeitwerk (~> 2)
35
35
  minitest (5.22.2)
36
36
  mutex_m (0.2.0)
37
+ rake (13.1.0)
37
38
  rspec (3.13.0)
38
39
  rspec-core (~> 3.13.0)
39
40
  rspec-expectations (~> 3.13.0)
@@ -58,6 +59,7 @@ PLATFORMS
58
59
 
59
60
  DEPENDENCIES
60
61
  code-ruby!
62
+ rake
61
63
  rspec
62
64
  ruby-prof
63
65
 
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:default) { |task| task.verbose = false }
data/bin/code CHANGED
@@ -42,6 +42,12 @@ argv =
42
42
  "Set timeout in seconds"
43
43
  ) { |timeout| options[:timeout] = timeout.to_f }
44
44
 
45
+ opts.on(
46
+ "-z TIME_ZONE",
47
+ "--time-zone TIME_ZONE",
48
+ "Set time zone"
49
+ ) { |time_zone| Time.zone = time_zone }
50
+
45
51
  opts.on("--profile", "Profile Ruby code") do |_timeout|
46
52
  require "ruby-prof"
47
53
  options[:profile] = true
@@ -16,9 +16,9 @@ class Code
16
16
  if @exponent && @whole
17
17
  exponent = @exponent.evaluate(**args)
18
18
  if exponent.is_a?(Object::Integer)
19
- Object::Integer.new(@whole, exponent:)
19
+ Object::Integer.new(@whole, exponent)
20
20
  else
21
- Object::Decimal.new(@whole, exponent:)
21
+ Object::Decimal.new(@whole, exponent)
22
22
  end
23
23
  elsif @whole
24
24
  Object::Integer.new(@whole.to_i)
@@ -9,11 +9,7 @@ class Code
9
9
  end
10
10
 
11
11
  def evaluate(**_args)
12
- if @base_16
13
- Object::Integer.new(@base_16.to_i(16))
14
- else
15
- Object::Nothing.new
16
- end
12
+ @base_16 ? Object::Integer.new(@base_16.to_i(16)) : Object::Nothing.new
17
13
  end
18
14
  end
19
15
  end
@@ -9,11 +9,7 @@ class Code
9
9
  end
10
10
 
11
11
  def evaluate(**_args)
12
- if @base_2
13
- Object::Integer.new(@base_2.to_i(2))
14
- else
15
- Object::Nothing.new
16
- end
12
+ @base_2 ? Object::Integer.new(@base_2.to_i(2)) : Object::Nothing.new
17
13
  end
18
14
  end
19
15
  end
@@ -9,11 +9,7 @@ class Code
9
9
  end
10
10
 
11
11
  def evaluate(**_args)
12
- if @base_8
13
- Object::Integer.new(@base_8.to_i(8))
14
- else
15
- Object::Nothing.new
16
- end
12
+ @base_8 ? Object::Integer.new(@base_8.to_i(8)) : Object::Nothing.new
17
13
  end
18
14
  end
19
15
  end
@@ -13,9 +13,7 @@ class Code
13
13
  end
14
14
 
15
15
  def evaluate(**_args)
16
- Object::Argument.new(
17
- Object::Function.new(parameters: @parameters, body: @body)
18
- )
16
+ Object::Argument.new(Object::Function.new(@parameters, @body))
19
17
  end
20
18
  end
21
19
 
@@ -25,7 +23,9 @@ class Code
25
23
  @arguments = parsed.delete(:arguments).presence || []
26
24
  @arguments.map! { |argument| CallArgument.new(argument) }
27
25
 
28
- @block = Call::Block.new(parsed.delete(:block).presence) if parsed.key?(:block)
26
+ if parsed.key?(:block)
27
+ @block = Call::Block.new(parsed.delete(:block).presence)
28
+ end
29
29
  end
30
30
 
31
31
  def evaluate(**args)
@@ -5,7 +5,8 @@ class Code
5
5
  class Code < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
- @statements = (parsed.presence || []).map { |statement| Statement.new(statement) }
8
+ @statements =
9
+ (parsed.presence || []).map { |statement| Statement.new(statement) }
9
10
  end
10
11
 
11
12
  def evaluate(**args)
@@ -14,10 +14,7 @@ class Code
14
14
 
15
15
  def evaluate(**args)
16
16
  if @exponent && @decimal
17
- Object::Decimal.new(
18
- @decimal,
19
- exponent: @exponent.evaluate(**args)
20
- )
17
+ Object::Decimal.new(@decimal, @exponent.evaluate(**args))
21
18
  elsif @decimal
22
19
  Object::Decimal.new(@decimal)
23
20
  else
@@ -32,12 +32,16 @@ class Code
32
32
  def initialize(parsed)
33
33
  return if parsed.blank?
34
34
  @key_values = parsed.presence || []
35
- @key_values.map! { |key_value| Node::Dictionary::KeyValue.new(key_value) }
35
+ @key_values.map! do |key_value|
36
+ Node::Dictionary::KeyValue.new(key_value)
37
+ end
36
38
  end
37
39
 
38
40
  def evaluate(**args)
39
41
  ::Code::Object::Dictionary.new(
40
- (@key_values || []).map { |key_value| key_value.evaluate(**args) }.to_h
42
+ (@key_values || [])
43
+ .map { |key_value| key_value.evaluate(**args) }
44
+ .to_h
41
45
  )
42
46
  end
43
47
  end
@@ -6,13 +6,13 @@ class Code
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
8
  @parameters = parsed.delete(:parameters).presence || []
9
- @parameters.map! { |parameter| Node::FunctionParameter.new(parameter) }
9
+ @parameters.map! { |parameter| FunctionParameter.new(parameter) }
10
10
 
11
- @body = Node::Code.new(parsed.delete(:body).presence)
11
+ @body = Code.new(parsed.delete(:body).presence)
12
12
  end
13
13
 
14
14
  def evaluate(**_args)
15
- ::Code::Object::Function.new(parameters: @parameters, body: @body)
15
+ Object::Function.new(@parameters, @body)
16
16
  end
17
17
  end
18
18
  end
@@ -10,7 +10,7 @@ class Code
10
10
  end
11
11
 
12
12
  def name
13
- ::Code::Object::String.new(@name)
13
+ Object::String.new(@name)
14
14
  end
15
15
 
16
16
  def regular?
@@ -28,6 +28,10 @@ class Code
28
28
  def keyword_splat?
29
29
  false
30
30
  end
31
+
32
+ def default
33
+ nil
34
+ end
31
35
  end
32
36
  end
33
37
  end
data/lib/code/node/if.rb CHANGED
@@ -25,7 +25,8 @@ class Code
25
25
  def initialize(parsed)
26
26
  return if parsed.blank?
27
27
  @first_operator = parsed.delete(:first_operator).presence
28
- @first_statement = Node::Statement.new(parsed.delete(:first_statement).presence)
28
+ @first_statement =
29
+ Node::Statement.new(parsed.delete(:first_statement).presence)
29
30
  @first_body = Node::Code.new(parsed.delete(:first_body).presence)
30
31
  @elses = (parsed.delete(:elses).presence || [])
31
32
  @elses.map! { |elses| Node::If::Else.new(elses) }
@@ -5,7 +5,8 @@ class Code
5
5
  class List < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
- @elements = (parsed.presence || []).map { |element| Node::Code.new(element) }
8
+ @elements =
9
+ (parsed.presence || []).map { |element| Node::Code.new(element) }
9
10
  end
10
11
 
11
12
  def evaluate(**args)
@@ -7,51 +7,51 @@ class Code
7
7
  return if parsed.blank?
8
8
 
9
9
  if parsed.key?(:nothing)
10
- @statement = Node::Nothing.new(parsed.delete(:nothing))
10
+ @statement = Nothing.new(parsed.delete(:nothing))
11
11
  elsif parsed.key?(:boolean)
12
- @statement = Node::Boolean.new(parsed.delete(:boolean))
12
+ @statement = Boolean.new(parsed.delete(:boolean))
13
13
  elsif parsed.key?(:group)
14
- @statement = Node::Code.new(parsed.delete(:group))
14
+ @statement = Code.new(parsed.delete(:group))
15
15
  elsif parsed.key?(:call)
16
- @statement = Node::Call.new(parsed.delete(:call))
16
+ @statement = Call.new(parsed.delete(:call))
17
17
  elsif parsed.key?(:number)
18
- @statement = Node::Number.new(parsed.delete(:number))
18
+ @statement = Number.new(parsed.delete(:number))
19
19
  elsif parsed.key?(:string)
20
- @statement = Node::String.new(parsed.delete(:string))
20
+ @statement = String.new(parsed.delete(:string))
21
21
  elsif parsed.key?(:list)
22
- @statement = Node::List.new(parsed.delete(:list))
22
+ @statement = List.new(parsed.delete(:list))
23
23
  elsif parsed.key?(:dictionnary)
24
- @statement = Node::Dictionary.new(parsed.delete(:dictionnary))
24
+ @statement = Dictionary.new(parsed.delete(:dictionnary))
25
25
  elsif parsed.key?(:chained_call)
26
- @statement = Node::ChainedCall.new(parsed.delete(:chained_call))
26
+ @statement = ChainedCall.new(parsed.delete(:chained_call))
27
27
  elsif parsed.key?(:left_operation)
28
- @statement = Node::LeftOperation.new(parsed.delete(:left_operation))
28
+ @statement = LeftOperation.new(parsed.delete(:left_operation))
29
29
  elsif parsed.key?(:right_operation)
30
- @statement = Node::RightOperation.new(parsed.delete(:right_operation))
30
+ @statement = RightOperation.new(parsed.delete(:right_operation))
31
31
  elsif parsed.key?(:function)
32
- @statement = Node::Function.new(parsed.delete(:function))
32
+ @statement = Function.new(parsed.delete(:function))
33
33
  elsif parsed.key?(:negation)
34
- @statement = Node::Negation.new(parsed.delete(:negation))
34
+ @statement = Negation.new(parsed.delete(:negation))
35
35
  elsif parsed.key?(:power)
36
- @statement = Node::Power.new(parsed.delete(:power))
36
+ @statement = Power.new(parsed.delete(:power))
37
37
  elsif parsed.key?(:unary_minus)
38
- @statement = Node::UnaryMinus.new(parsed.delete(:unary_minus))
38
+ @statement = UnaryMinus.new(parsed.delete(:unary_minus))
39
39
  elsif parsed.key?(:ternary)
40
- @statement = Node::Ternary.new(parsed.delete(:ternary))
40
+ @statement = Ternary.new(parsed.delete(:ternary))
41
41
  elsif parsed.key?(:rescue)
42
- @statement = Node::Rescue.new(parsed.delete(:rescue))
42
+ @statement = Rescue.new(parsed.delete(:rescue))
43
43
  elsif parsed.key?(:not)
44
- @statement = Node::Not.new(parsed.delete(:not))
44
+ @statement = Not.new(parsed.delete(:not))
45
45
  elsif parsed.key?(:if_modifier)
46
- @statement = Node::IfModifier.new(parsed.delete(:if_modifier))
46
+ @statement = IfModifier.new(parsed.delete(:if_modifier))
47
47
  elsif parsed.key?(:if)
48
- @statement = Node::If.new(parsed.delete(:if))
48
+ @statement = If.new(parsed.delete(:if))
49
49
  elsif parsed.key?(:while)
50
- @statement = Node::While.new(parsed.delete(:while))
50
+ @statement = While.new(parsed.delete(:while))
51
51
  elsif parsed.key?(:splat)
52
- @statement = Node::Splat.new(parsed.delete(:splat))
52
+ @statement = Splat.new(parsed.delete(:splat))
53
53
  elsif parsed.key?(:square_bracket)
54
- @statement = Node::SquareBracket.new(parsed.delete(:square_bracket))
54
+ @statement = SquareBracket.new(parsed.delete(:square_bracket))
55
55
  end
56
56
  end
57
57
 
@@ -53,7 +53,8 @@ class Code
53
53
 
54
54
  def initialize(parsed)
55
55
  return if parsed.blank?
56
- @parts = (parsed.presence || []).map { |part| Node::String::Part.new(part) }
56
+ @parts =
57
+ (parsed.presence || []).map { |part| Node::String::Part.new(part) }
57
58
  end
58
59
 
59
60
  def evaluate(**args)
@@ -5,9 +5,10 @@ class Code
5
5
  class Argument < Object
6
6
  attr_reader :value, :name
7
7
 
8
- def initialize(value, name: nil)
9
- @value = value
10
- @name = name
8
+ def initialize(*args, **_kargs, &_block)
9
+ @value = args.first.presence || Nothing.new
10
+ @name = args.second.present? ? String.new(args.second) : nil
11
+ @raw = List.new([@value, @name])
11
12
  end
12
13
 
13
14
  def keyword?
@@ -3,14 +3,10 @@
3
3
  class Code
4
4
  class Object
5
5
  class Boolean < ::Code::Object
6
- attr_reader :raw
7
-
8
- def initialize(raw)
9
- @raw = (raw.is_a?(Object) ? raw.truthy? : !!raw)
10
- end
11
-
12
- def self.name
13
- "Boolean"
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || Nothing.new
8
+ raw = raw.raw if raw.is_a?(Object)
9
+ @raw = !!raw
14
10
  end
15
11
 
16
12
  def call(**args)
@@ -45,25 +41,9 @@ class Code
45
41
  Boolean.new(raw ^ value.raw)
46
42
  end
47
43
 
48
- def inspect
49
- to_s
50
- end
51
-
52
- def succ
53
- Boolean.new(!raw)
54
- end
55
-
56
- def to_s
57
- raw.to_s
58
- end
59
-
60
44
  def truthy?
61
45
  raw
62
46
  end
63
-
64
- def as_json(...)
65
- raw.as_json(...)
66
- end
67
47
  end
68
48
  end
69
49
  end
@@ -3,32 +3,16 @@
3
3
  class Code
4
4
  class Object
5
5
  class Class < Object
6
- attr_reader :raw
7
-
8
- def initialize(raw)
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || Nothing.new
9
8
  raw = raw.raw if raw.is_a?(Class)
9
+ raw = raw.class if raw.is_an?(Object)
10
10
  @raw = raw
11
11
  end
12
12
 
13
13
  def call(...)
14
14
  raw.call(...)
15
15
  end
16
-
17
- def to_s
18
- raw.name
19
- end
20
-
21
- def inspect
22
- to_s
23
- end
24
-
25
- def self.name
26
- "Class"
27
- end
28
-
29
- def as_json(...)
30
- raw.name.as_json(...)
31
- end
32
16
  end
33
17
  end
34
18
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Code
4
+ class Object
5
+ class Code < Object
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first.presence || Nothing.new
8
+ @raw = raw.is_a?(Node) ? raw : Node::Code.new(::Code.parse(raw.to_s))
9
+ end
10
+
11
+ def evaluate(...)
12
+ raw.evaluate(...)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -5,14 +5,11 @@ class Code
5
5
  class Context < Dictionary
6
6
  attr_reader :parent
7
7
 
8
- def initialize(raw = {}, parent: nil)
9
- raw = raw.raw if raw.is_a?(Dictionary)
8
+ def initialize(*args, **_kargs, &_block)
9
+ raw = args.first || Dictionary.new
10
+ raw = raw.raw if raw.is_a?(Object)
10
11
  @raw = raw.to_h
11
- @parent = parent
12
- end
13
-
14
- def self.name
15
- "Context"
12
+ @parent = Context.new(args.second) if args.second
16
13
  end
17
14
 
18
15
  def lookup!(identifier)
@@ -21,12 +18,12 @@ class Code
21
18
  elsif parent?
22
19
  parent.lookup!(identifier)
23
20
  else
24
- raise Code::Error::Undefined, "#{identifier} is not defined"
21
+ raise Error::Undefined, "#{identifier} is not defined"
25
22
  end
26
23
  end
27
24
 
28
25
  def merge(other)
29
- Context.new(raw.merge(other.raw), parent: parent || other.parent)
26
+ Context.new(raw.merge(other.raw), parent || other.parent)
30
27
  end
31
28
 
32
29
  def parent?
@@ -3,15 +3,11 @@
3
3
  class Code
4
4
  class Object
5
5
  class Date < Object
6
- attr_reader :raw
7
-
8
- def initialize(date)
9
- date = date.raw if date.is_a?(Date)
10
- @raw = date.to_date
11
- end
12
-
13
- def self.name
14
- "Date"
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.map(&:to_s).join("-").presence || ::Date.current.to_s
8
+ @raw = ::Date.parse(raw)
9
+ rescue ::Date::Error
10
+ raise Error, "#{raw.inspect} is an invalid date"
15
11
  end
16
12
 
17
13
  def self.call(**args)
@@ -21,26 +17,38 @@ class Code
21
17
  when "tomorrow"
22
18
  sig(args)
23
19
  code_tomorrow
20
+ when "yesterday"
21
+ sig(args)
22
+ code_yesterday
23
+ when "today"
24
+ sig(args)
25
+ code_today
26
+ when "now"
27
+ sig(args)
28
+ code_now
24
29
  else
25
30
  super
26
31
  end
27
32
  end
28
33
 
29
- def self.code_tomorrow
34
+ def self.code_now
30
35
  ::Time.zone ||= Time::DEFAULT_ZONE
31
- new(::Time.zone.tomorrow)
36
+ new(::Time.zone.now.beginning_of_day)
32
37
  end
33
38
 
34
- def inspect
35
- to_s
39
+ def self.code_today
40
+ ::Time.zone ||= Time::DEFAULT_ZONE
41
+ new(::Time.zone.now.beginning_of_day)
36
42
  end
37
43
 
38
- def to_s
39
- raw.to_s
44
+ def self.code_tomorrow
45
+ ::Time.zone ||= Time::DEFAULT_ZONE
46
+ new(::Time.zone.tomorrow.beginning_of_day)
40
47
  end
41
48
 
42
- def as_json(...)
43
- raw.as_json(...)
49
+ def self.code_yesterday
50
+ ::Time.zone ||= Time::DEFAULT_ZONE
51
+ new(::Time.zone.yesterday.beginning_of_day)
44
52
  end
45
53
  end
46
54
  end