code-ruby 3.1.2 → 4.0.0

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/code +97 -20
  4. data/lib/code/concerns/shared.rb +331 -15
  5. data/lib/code/format.rb +15 -1
  6. data/lib/code/network.rb +87 -0
  7. data/lib/code/node/call.rb +79 -2
  8. data/lib/code/node/call_argument.rb +14 -0
  9. data/lib/code/node/code.rb +5 -4
  10. data/lib/code/node/function_parameter.rb +7 -4
  11. data/lib/code/node/list.rb +29 -1
  12. data/lib/code/object/base_64.rb +132 -6
  13. data/lib/code/object/boolean.rb +60 -0
  14. data/lib/code/object/class.rb +138 -2
  15. data/lib/code/object/code.rb +111 -3
  16. data/lib/code/object/context.rb +57 -1
  17. data/lib/code/object/cryptography.rb +63 -0
  18. data/lib/code/object/date.rb +13339 -462
  19. data/lib/code/object/decimal.rb +1725 -0
  20. data/lib/code/object/dictionary.rb +1790 -11
  21. data/lib/code/object/duration.rb +28 -0
  22. data/lib/code/object/function.rb +261 -23
  23. data/lib/code/object/global.rb +534 -1
  24. data/lib/code/object/html.rb +179 -7
  25. data/lib/code/object/http.rb +244 -14
  26. data/lib/code/object/ics.rb +75 -13
  27. data/lib/code/object/identifier_list.rb +17 -2
  28. data/lib/code/object/integer.rb +1937 -2
  29. data/lib/code/object/json.rb +75 -1
  30. data/lib/code/object/list.rb +3383 -10
  31. data/lib/code/object/nothing.rb +53 -0
  32. data/lib/code/object/number.rb +110 -0
  33. data/lib/code/object/parameter.rb +140 -0
  34. data/lib/code/object/range.rb +576 -14
  35. data/lib/code/object/smtp.rb +95 -12
  36. data/lib/code/object/string.rb +944 -3
  37. data/lib/code/object/super.rb +10 -1
  38. data/lib/code/object/time.rb +13358 -498
  39. data/lib/code/object/url.rb +65 -0
  40. data/lib/code/object.rb +543 -0
  41. data/lib/code/parser.rb +161 -24
  42. data/lib/code-ruby.rb +3 -0
  43. data/lib/code.rb +30 -3
  44. metadata +135 -84
  45. data/.github/dependabot.yml +0 -15
  46. data/.github/workflows/ci.yml +0 -38
  47. data/.gitignore +0 -30
  48. data/.node-version +0 -1
  49. data/.npm-version +0 -1
  50. data/.prettierignore +0 -2
  51. data/.rspec +0 -1
  52. data/.rubocop.yml +0 -140
  53. data/.ruby-version +0 -1
  54. data/.tool-versions +0 -3
  55. data/AGENTS.md +0 -43
  56. data/Gemfile +0 -22
  57. data/Gemfile.lock +0 -292
  58. data/Rakefile +0 -5
  59. data/bin/bundle +0 -123
  60. data/bin/bundle-audit +0 -31
  61. data/bin/bundler-audit +0 -31
  62. data/bin/dorian +0 -31
  63. data/bin/rspec +0 -31
  64. data/bin/rubocop +0 -31
  65. data/bin/test +0 -5
  66. data/code-ruby.gemspec +0 -34
  67. data/docs/precedence.txt +0 -36
  68. data/package-lock.json +0 -14
  69. data/package.json +0 -7
  70. data/spec/bin/code_spec.rb +0 -48
  71. data/spec/code/format_spec.rb +0 -153
  72. data/spec/code/node/call_spec.rb +0 -11
  73. data/spec/code/object/boolean_spec.rb +0 -18
  74. data/spec/code/object/cryptography_spec.rb +0 -25
  75. data/spec/code/object/decimal_spec.rb +0 -50
  76. data/spec/code/object/dictionary_spec.rb +0 -98
  77. data/spec/code/object/function_spec.rb +0 -268
  78. data/spec/code/object/http_spec.rb +0 -33
  79. data/spec/code/object/ics_spec.rb +0 -50
  80. data/spec/code/object/integer_spec.rb +0 -42
  81. data/spec/code/object/list_spec.rb +0 -22
  82. data/spec/code/object/nothing_spec.rb +0 -14
  83. data/spec/code/object/range_spec.rb +0 -23
  84. data/spec/code/object/string_spec.rb +0 -26
  85. data/spec/code/parser/boolean_spec.rb +0 -11
  86. data/spec/code/parser/chained_call_spec.rb +0 -16
  87. data/spec/code/parser/dictionary_spec.rb +0 -18
  88. data/spec/code/parser/function_spec.rb +0 -16
  89. data/spec/code/parser/group_spec.rb +0 -11
  90. data/spec/code/parser/if_modifier_spec.rb +0 -18
  91. data/spec/code/parser/list_spec.rb +0 -17
  92. data/spec/code/parser/number_spec.rb +0 -11
  93. data/spec/code/parser/string_spec.rb +0 -20
  94. data/spec/code/parser_spec.rb +0 -52
  95. data/spec/code/type_spec.rb +0 -21
  96. data/spec/code_spec.rb +0 -717
  97. data/spec/spec_helper.rb +0 -21
  98. data/spec/zeitwerk/loader_spec.rb +0 -7
@@ -3,6 +3,33 @@
3
3
  class Code
4
4
  class Object
5
5
  class Ics < Object
6
+ CLASS_DOCUMENTATION = {
7
+ name: "Ics",
8
+ description: "parses icalendar text and exposes events as dictionaries.",
9
+ examples: [
10
+ "Ics.parse(\"BEGIN:VCALENDAR\\nBEGIN:VEVENT\\nSUMMARY:meet\\nEND:VEVENT\\nEND:VCALENDAR\")",
11
+ "Ics.parse(\"BEGIN:VCALENDAR\\nVERSION:2.0\\nEND:VCALENDAR\")",
12
+ "Ics.parse(\"\")"
13
+ ]
14
+ }.freeze
15
+ CLASS_FUNCTIONS = {
16
+ "parse" => {
17
+ name: "parse",
18
+ description: "returns event dictionaries parsed from icalendar text.",
19
+ examples: [
20
+ "Ics.parse(\"BEGIN:VCALENDAR\\nBEGIN:VEVENT\\nUID:1\\nSUMMARY:demo\\nEND:VEVENT\\nEND:VCALENDAR\")",
21
+ "Ics.parse(\"BEGIN:VCALENDAR\\nEND:VCALENDAR\")",
22
+ "Ics.parse(\"not calendar data\")"
23
+ ]
24
+ }
25
+ }.freeze
26
+
27
+ def self.function_documentation(scope)
28
+ return CLASS_FUNCTIONS if scope == :class
29
+
30
+ {}
31
+ end
32
+
6
33
  EVENT_ATTRIBUTES = %i[
7
34
  uid
8
35
  summary
@@ -15,6 +42,9 @@ class Code
15
42
  attendees
16
43
  geo
17
44
  ].freeze
45
+ MISSING_ATTRIBUTE = Object.new.freeze
46
+ MAX_EVENTS = 10_000
47
+ MAX_NESTING = 50
18
48
 
19
49
  def self.call(**args)
20
50
  code_operator = args.fetch(:operator, nil).to_code
@@ -32,11 +62,14 @@ class Code
32
62
 
33
63
  def self.code_parse(value)
34
64
  source = value.to_code.raw
65
+ ::Code.ensure_input_size!(source, label: "ics")
35
66
  calendars = ::Icalendar::Calendar.parse(source)
36
- calendars
37
- .flat_map(&:events)
38
- .map { |event| serialize_event(event) }
39
- .to_code
67
+ events = calendars.flat_map(&:events)
68
+ raise Error, "ics has too many events" if events.size > MAX_EVENTS
69
+
70
+ events.map { |event| serialize_event(event) }.to_code
71
+ rescue ::Code::Error
72
+ raise
40
73
  rescue StandardError
41
74
  [].to_code
42
75
  end
@@ -44,9 +77,9 @@ class Code
44
77
  def self.serialize_event(event)
45
78
  EVENT_ATTRIBUTES
46
79
  .each_with_object({}) do |attribute, result|
47
- next unless event.respond_to?(attribute)
80
+ serialized = serialize_value(event_attribute(event, attribute))
81
+ next if serialized == MISSING_ATTRIBUTE
48
82
 
49
- serialized = serialize_value(event.public_send(attribute))
50
83
  serialized =
51
84
  if attribute == :categories && serialized.is_a?(::Array)
52
85
  serialized.flatten(1)
@@ -67,7 +100,36 @@ class Code
67
100
  .compact
68
101
  end
69
102
 
70
- def self.serialize_value(value)
103
+ def self.event_attribute(event, attribute)
104
+ case attribute
105
+ when :uid
106
+ event.uid
107
+ when :summary
108
+ event.summary
109
+ when :description
110
+ event.description
111
+ when :location
112
+ event.location
113
+ when :url
114
+ event.url
115
+ when :status
116
+ event.status
117
+ when :organizer
118
+ event.organizer
119
+ when :categories
120
+ event.categories
121
+ when :attendees
122
+ event.attendees
123
+ when :geo
124
+ event.geo
125
+ end
126
+ rescue NoMethodError
127
+ MISSING_ATTRIBUTE
128
+ end
129
+
130
+ def self.serialize_value(value, depth: 0)
131
+ raise Error, "ics is too deeply nested" if depth > MAX_NESTING
132
+
71
133
  case value
72
134
  when nil
73
135
  nil
@@ -76,17 +138,17 @@ class Code
76
138
  when ::Symbol, ::Integer, ::Float, ::BigDecimal, true, false
77
139
  value
78
140
  when ::Array
79
- value.map { |item| serialize_value(item) }
141
+ value.map { |item| serialize_value(item, depth: depth + 1) }
80
142
  when ::Hash
81
- value.transform_values { |item| serialize_value(item) }
143
+ value.transform_values do |item|
144
+ serialize_value(item, depth: depth + 1)
145
+ end
82
146
  else
83
147
  serialized_date = serialize_date_like(value)
84
148
  return serialized_date unless serialized_date.nil?
85
149
 
86
- if value.respond_to?(:value)
87
- serialize_value(value.value)
88
- elsif value.respond_to?(:to_ical)
89
- normalize_string(value.to_ical)
150
+ if value.is_a?(::Icalendar::Value)
151
+ serialize_value(value.value, depth: depth + 1)
90
152
  else
91
153
  normalize_string(value.to_s)
92
154
  end
@@ -3,6 +3,15 @@
3
3
  class Code
4
4
  class Object
5
5
  class IdentifierList < List
6
+ CLASS_DOCUMENTATION = {
7
+ name: "IdentifierList",
8
+ description: "stores ordered identifier names used to assign nested values.",
9
+ examples: [
10
+ "IdentifierList",
11
+ "IdentifierList.new([:user, :name]).first",
12
+ "IdentifierList.new([:user, :name]).join(\".\")"
13
+ ]
14
+ }.freeze
6
15
  def call(**args)
7
16
  code_operator = args.fetch(:operator, nil).to_code
8
17
  code_arguments = args.fetch(:arguments, []).to_code
@@ -87,7 +96,7 @@ class Code
87
96
  **args,
88
97
  operator: "#{raw.last}=",
89
98
  arguments: Object::List.new([code_value])
90
- )
99
+ ).tap { persist_class_receiver(receiver, args.fetch(:context)) }
91
100
  else
92
101
  next_value =
93
102
  receiver.call(
@@ -104,9 +113,15 @@ class Code
104
113
  **args,
105
114
  operator: "#{raw.last}=",
106
115
  arguments: Object::List.new([next_value])
107
- )
116
+ ).tap { persist_class_receiver(receiver, args.fetch(:context)) }
108
117
  end
109
118
  end
119
+
120
+ def persist_class_receiver(receiver, context)
121
+ return unless receiver.is_a?(Object::Class)
122
+
123
+ context.code_set(raw.first, receiver)
124
+ end
110
125
  end
111
126
  end
112
127
  end