code-ruby 3.0.2 → 3.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b61a40e84c1815a9437f6127c4db28d7327982671aa1a602e11ccc85e467861f
4
- data.tar.gz: 796e46b1fbd2443799bd4cba9fcd7513c462bc9b605d31d17a2d1197ee7d6fd1
3
+ metadata.gz: 4adfeb34ead1c64815b7c1441fe958bdb800124060f85fe34e3e069d84471bf9
4
+ data.tar.gz: 47d16a2b78dfa78f09c3a85ceb96bec36462e5370c46c6da5bfa6cbeccb16704
5
5
  SHA512:
6
- metadata.gz: 4d131863a968fa7e02711182c37840bd7743770d32da91f031bdc8e6ccd42aedea8312c1521c1095205eca46ed87f2b663a0622cc97706beb6383b5998bba097
7
- data.tar.gz: 9b17fa0e159d1472929fd284020e538937ed1465cfeb0e36dce1f079044e657920edfd2d000aedee61a2e2a9f5eaabdf3ac3503833d162d3693efcccc594ffbd
6
+ metadata.gz: f3282f6775597df25231b0aef32f5d0a8a11d7cee0f33abdb0989c843fff87a16f908a01998c1269d81bebe507c5023cf56095a8037624be68066a6e82c15443
7
+ data.tar.gz: 49e847ebb8e89dad0b072b25e3116718d3cbb3de2c4b0252cb8e2d7ae0462e93992554dadbf1665f91cb821fd9fe05f0a1769b3a06ab8d1632d4d1a268b828bb
data/Gemfile.lock CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- code-ruby (3.0.2)
4
+ code-ruby (3.0.3)
5
5
  activesupport
6
6
  base64
7
7
  bigdecimal
8
8
  did-you-mean
9
9
  dorian-arguments
10
+ icalendar
10
11
  json
11
12
  language-ruby
12
13
  mail
@@ -95,6 +96,12 @@ GEM
95
96
  strscan (>= 3.1.2)
96
97
  i18n (1.14.8)
97
98
  concurrent-ruby (~> 1.0)
99
+ icalendar (2.12.2)
100
+ base64
101
+ ice_cube (~> 0.16)
102
+ logger
103
+ ostruct
104
+ ice_cube (0.17.0)
98
105
  json (2.18.1)
99
106
  json-schema (6.1.0)
100
107
  addressable (~> 2.8)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.2
1
+ 3.0.3
data/code-ruby.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.add_dependency "bigdecimal"
19
19
  s.add_dependency "did-you-mean"
20
20
  s.add_dependency "dorian-arguments"
21
+ s.add_dependency "icalendar"
21
22
  s.add_dependency "json"
22
23
  s.add_dependency "language-ruby"
23
24
  s.add_dependency "mail"
@@ -167,6 +167,9 @@ class Code
167
167
  when "Json"
168
168
  sig(args) { Object.repeat }
169
169
  code_arguments.any? ? Json.new(*code_arguments.raw) : Class.new(Json)
170
+ when "Ics"
171
+ sig(args) { Object.repeat }
172
+ code_arguments.any? ? Ics.new(*code_arguments.raw) : Class.new(Ics)
170
173
  when "evaluate"
171
174
  sig(args) { Object }
172
175
  Code.code_evaluate(code_value.code_to_string, **globals)
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Code
4
+ class Object
5
+ class Ics < Object
6
+ EVENT_ATTRIBUTES = %i[
7
+ uid
8
+ summary
9
+ description
10
+ location
11
+ url
12
+ status
13
+ organizer
14
+ categories
15
+ attendees
16
+ geo
17
+ ].freeze
18
+
19
+ def self.call(**args)
20
+ code_operator = args.fetch(:operator, nil).to_code
21
+ code_arguments = args.fetch(:arguments, []).to_code
22
+ code_value = code_arguments.code_first
23
+
24
+ case code_operator.to_s
25
+ when "parse"
26
+ sig(args) { String }
27
+ code_parse(code_value)
28
+ else
29
+ super
30
+ end
31
+ end
32
+
33
+ def self.code_parse(value)
34
+ source = value.to_code.raw
35
+ calendars = ::Icalendar::Calendar.parse(source)
36
+ calendars
37
+ .flat_map(&:events)
38
+ .map { |event| serialize_event(event) }
39
+ .to_code
40
+ rescue StandardError
41
+ [].to_code
42
+ end
43
+
44
+ def self.serialize_event(event)
45
+ EVENT_ATTRIBUTES.each_with_object({}) do |attribute, result|
46
+ next unless event.respond_to?(attribute)
47
+
48
+ serialized = serialize_value(event.public_send(attribute))
49
+ serialized = serialized.flatten(1) if attribute == :categories && serialized.is_a?(::Array)
50
+ result[attribute] = serialized unless serialized.nil?
51
+ end.merge(
52
+ timestamp: serialize_value(event.dtstamp),
53
+ starts_at: serialize_value(event.dtstart),
54
+ ends_at: serialize_value(event.dtend),
55
+ all_day: !!serialize_date_like(event.dtstart).is_a?(::Date)
56
+ ).compact
57
+ end
58
+
59
+ def self.serialize_value(value)
60
+ case value
61
+ when nil
62
+ nil
63
+ when ::String, ::Symbol, ::Integer, ::Float, ::BigDecimal, true, false
64
+ value
65
+ when ::Array
66
+ value.map { |item| serialize_value(item) }
67
+ when ::Hash
68
+ value.transform_values { |item| serialize_value(item) }
69
+ else
70
+ serialized_date = serialize_date_like(value)
71
+ return serialized_date unless serialized_date.nil?
72
+
73
+ if value.respond_to?(:value)
74
+ serialize_value(value.value)
75
+ elsif value.respond_to?(:to_ical)
76
+ value.to_ical
77
+ else
78
+ value.to_s
79
+ end
80
+ end
81
+ end
82
+
83
+ def self.serialize_date_like(value)
84
+ case value
85
+ when ::Time, ::Date, ::ActiveSupport::TimeWithZone
86
+ value
87
+ when ::DateTime
88
+ value.to_time
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
data/lib/code-ruby.rb CHANGED
@@ -7,6 +7,7 @@ require "bigdecimal/util"
7
7
  require "date"
8
8
  require "did_you_mean"
9
9
  require "digest"
10
+ require "icalendar"
10
11
  require "json"
11
12
  require "mail"
12
13
  require "net/http"
data/spec/code_spec.rb CHANGED
@@ -151,6 +151,7 @@ RSpec.describe Code do
151
151
  Json.parse('[]')
152
152
  Json.parse('{}')
153
153
  Json.parse('random-string')
154
+ Ics.parse("BEGIN:VCALENDAR\nEND:VCALENDAR")
154
155
  {}["".to_string]
155
156
  ] + ["Time.hour >= 6 and Time.hour <= 23"]
156
157
  ).each do |input|
@@ -557,4 +558,51 @@ RSpec.describe Code do
557
558
  described_class.evaluate("UnknownConstant.zone = 1")
558
559
  end.to raise_error(Code::Error, /UnknownConstant is not defined/)
559
560
  end
561
+
562
+ it "parses ics events into dictionaries" do
563
+ result = described_class.evaluate(<<~CODE)
564
+ events = Ics.parse("BEGIN:VCALENDAR
565
+ VERSION:2.0
566
+ PRODID:-//code-ruby//EN
567
+ BEGIN:VEVENT
568
+ UID:event-1
569
+ DTSTART:20260327T120000Z
570
+ DTEND:20260327T133000Z
571
+ SUMMARY:Lunch
572
+ DESCRIPTION:Team lunch
573
+ LOCATION:Paris
574
+ URL:https://example.com/events/1
575
+ CATEGORIES:food,team
576
+ END:VEVENT
577
+ END:VCALENDAR")
578
+
579
+ {
580
+ size: events.size,
581
+ summary: events.first.summary,
582
+ location: events.first.location,
583
+ uid: events.first.uid,
584
+ categories: events.first.categories,
585
+ starts_at: events.first.starts_at.to_string,
586
+ ends_at: events.first.ends_at.to_string,
587
+ all_day: events.first.all_day
588
+ }
589
+ CODE
590
+
591
+ expect(result).to eq(
592
+ {
593
+ size: 1,
594
+ summary: "Lunch",
595
+ location: "Paris",
596
+ uid: "event-1",
597
+ categories: ["food", "team"],
598
+ starts_at: "2026-03-27 12:00:00 UTC",
599
+ ends_at: "2026-03-27 13:30:00 UTC",
600
+ all_day: false
601
+ }.to_code
602
+ )
603
+ end
604
+
605
+ it "returns an empty list for invalid ics" do
606
+ expect(described_class.evaluate('Ics.parse("not an ics file")')).to eq([].to_code)
607
+ end
560
608
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 3.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
@@ -79,6 +79,20 @@ dependencies:
79
79
  - - ">="
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: icalendar
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
82
96
  - !ruby/object:Gem::Dependency
83
97
  name: json
84
98
  requirement: !ruby/object:Gem::Requirement
@@ -275,6 +289,7 @@ files:
275
289
  - lib/code/object/global.rb
276
290
  - lib/code/object/html.rb
277
291
  - lib/code/object/http.rb
292
+ - lib/code/object/ics.rb
278
293
  - lib/code/object/identifier_list.rb
279
294
  - lib/code/object/integer.rb
280
295
  - lib/code/object/json.rb