jekyll-ical-tag 1.4.0 → 1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,169 +0,0 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- require "jekyll"
5
- require "jekyll-ical-tag/version"
6
-
7
- module Jekyll
8
- class IcalTag < Liquid::Block
9
- require_relative "jekyll-ical-tag/calendar_feed_coordinator"
10
- require_relative "jekyll-ical-tag/calendar_fetcher"
11
- require_relative "jekyll-ical-tag/calendar_limiter"
12
- require_relative "jekyll-ical-tag/calendar_parser"
13
- require_relative "jekyll-ical-tag/event"
14
-
15
- include Convertible
16
-
17
- def initialize(tag_name, markup, parse_context)
18
- super
19
- @markup = markup
20
- @attributes = {}
21
-
22
- scan_attributes!
23
- set_limit!
24
- set_reverse!
25
- set_url!
26
- set_only!
27
- end
28
-
29
- def render(context)
30
- context.registers[:ical] ||= Hash.new(0)
31
-
32
- result = []
33
-
34
- context.stack do
35
- url = get_dereferenced_url(context) || @url
36
- before_date = before_date_from(context)
37
- after_date = after_date_from(context)
38
-
39
- calendar_feed_coordinator = CalendarFeedCoordinator.new(
40
- url: url, only: @only, reverse: @reverse,
41
- before_date: before_date, after_date: after_date,
42
- limit: @limit
43
- )
44
- events = calendar_feed_coordinator.events
45
- event_count = events.length
46
-
47
- events.each_with_index do |event, index|
48
- # Init
49
- context["event"] = {}
50
-
51
- # Jekyll helper variables
52
- context["event"]["index"] = index
53
-
54
- # RFC 5545 conformant and custom properties.
55
- context["event"].merge!(event.all_properties)
56
-
57
- # Supported but non-standard attributes.
58
- context["event"]["attendees"] = event.attendees
59
- context["event"]["simple_html_description"] = event.simple_html_description
60
-
61
- # Overridden values
62
- context["event"]["url"] ||= event.description_urls.first
63
-
64
- # Deprecated attribute names.
65
- context["event"]["end_time"] = context["event"]["dtend"]
66
- context["event"]["start_time"] = context["event"]["dtstart"]
67
-
68
- context["forloop"] = {
69
- "name" => "ical",
70
- "length" => event_count,
71
- "index" => index + 1,
72
- "index0" => index,
73
- "rindex" => event_count - index,
74
- "rindex0" => event_count - index - 1,
75
- "first" => (index == 0),
76
- "last" => (index == event_count - 1),
77
- }
78
-
79
- result << nodelist.map do |n|
80
- if n.respond_to? :render
81
- n.render(context)
82
- else
83
- n
84
- end
85
- end.join
86
- end
87
- end
88
-
89
- result
90
- end
91
-
92
- private
93
-
94
- def get_dereferenced_url(context)
95
- return unless context.key?(@url)
96
-
97
- context[@url]
98
- end
99
-
100
- def after_date_from(context)
101
- safely_cast_to_time(
102
- dereferenced_liquid_val(context, "after_date")
103
- ).tap { |v| pp v }
104
- end
105
-
106
- def before_date_from(context)
107
-
108
- safely_cast_to_time(
109
- dereferenced_liquid_val(context, "before_date")
110
- ).tap { |v| pp v }
111
- end
112
-
113
- def safely_cast_to_time(val)
114
- case val
115
- when String
116
- Time.parse(val)
117
- when Date, DateTime, Time
118
- val
119
- when NilClass
120
- # Do nothing
121
- else
122
- raise "Cannot cast to Time: #{val}"
123
- end
124
- end
125
-
126
- def dereferenced_liquid_val(context, variable_name)
127
- raw_value = @attributes[variable_name]
128
-
129
- context.key?(raw_value) ? context[raw_value] : raw_value
130
- end
131
-
132
- def scan_attributes!
133
- @markup.scan(Liquid::TagAttributes) do |key, value|
134
- @attributes[key] = value
135
- end
136
- end
137
-
138
- def set_limit!
139
- @limit = nil
140
- @limit = @attributes["limit"].to_i if @attributes["limit"]
141
- end
142
-
143
- def set_reverse!
144
- @reverse = @attributes["reverse"] == "true"
145
- end
146
-
147
- def set_url!
148
- @url = @attributes["url"]
149
- end
150
-
151
- def set_only!
152
- only_future = @attributes["only_future"] == "true"
153
- only_past = @attributes["only_past"] == "true"
154
-
155
- raise "Set only_future OR only_past, not both" if only_future && only_past
156
-
157
- @only =
158
- if only_future
159
- :future
160
- elsif only_past
161
- :past
162
- else
163
- :all
164
- end
165
- end
166
- end
167
- end
168
-
169
- Liquid::Template.register_tag("ical", Jekyll::IcalTag)
@@ -1,219 +0,0 @@
1
- require "spec_helper"
2
-
3
- EXAMPLE_RAW_FEEDS = {
4
- empty: "",
5
- basic: File.read("spec/support/basic.ics"),
6
- italian: File.read("spec/support/italian.ics"),
7
- sesh: File.read("spec/support/sesh.ics")
8
- }
9
-
10
- RSpec.describe Jekyll::IcalTag::CalendarFeedCoordinator do
11
- context "happy path" do
12
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: "https://space.floern.com/launch.ics") }
13
-
14
- it "should not raise error" do
15
- expect { coordinator.events }.to_not raise_error
16
- end
17
-
18
- it "should return accurate event count" do
19
- expect(coordinator.events.count).to be > 0
20
- end
21
-
22
- it "should be able to parse all parse of each event" do
23
- coordinator.events.each do |event|
24
- expect { event.all_properties }.to_not raise_error
25
- expect { event.simple_html_description }.to_not raise_error
26
- expect { event.attendees }.to_not raise_error
27
- expect { event.description_urls }.to_not raise_error
28
- end
29
- end
30
- end
31
-
32
- context "with empty feed" do
33
- let(:fake_url) { "https://www.calendarfeed.com/feed.ics"}
34
- let(:mock_feed) { double(:mock_feed, fetch: EXAMPLE_RAW_FEEDS[:empty])}
35
-
36
- before do
37
- allow(Jekyll::IcalTag::CalendarFetcher).to receive(:new).and_return(mock_feed)
38
- end
39
-
40
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url) }
41
-
42
- it "should not raise error" do
43
- expect { coordinator.events }.to_not raise_error
44
- end
45
-
46
- it "should return accurate event count" do
47
- expect(coordinator.events.count).to eq(0)
48
- end
49
- end
50
-
51
- context "with basic feed" do
52
- let(:fake_url) { "https://www.calendarfeed.com/feed.ics"}
53
- let(:mock_feed) { double(:mock_feed, fetch: EXAMPLE_RAW_FEEDS[:basic])}
54
- before { allow(Jekyll::IcalTag::CalendarFetcher).to receive(:new).and_return(mock_feed) }
55
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url) }
56
-
57
- it "should not raise error" do
58
- expect {
59
- coordinator.events
60
- }.to_not raise_error
61
- end
62
-
63
- it "should return accurate event count" do
64
- expect(coordinator.events.count).to eq(66)
65
- end
66
-
67
- it "should be able to parse all parse of each event" do
68
- coordinator.events.each do |event|
69
- expect { event.all_properties }.to_not raise_error
70
- expect { event.simple_html_description }.to_not raise_error
71
- expect { event.attendees }.to_not raise_error
72
- expect { event.description_urls }.to_not raise_error
73
- end
74
- end
75
-
76
- it "should return dates from oldest to newest first" do
77
- first_date = coordinator.events.first.dtstart.to_date
78
- last_date = coordinator.events.last.dtstart.to_date
79
-
80
- expect(first_date).to be < last_date
81
- end
82
-
83
- describe "limit" do
84
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, limit: 5) }
85
-
86
- it "should return accurate event count" do
87
- expect(coordinator.events.count).to eq(5)
88
- end
89
- end
90
-
91
- describe "only future" do
92
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, only: :future) }
93
-
94
- it "should return accurate event count" do
95
- expect(coordinator.events.count).to eq(1)
96
- end
97
- end
98
-
99
- describe "only past" do
100
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, only: :past) }
101
-
102
- it "should return accurate event count" do
103
- expect(coordinator.events.count).to eq(65)
104
- end
105
- end
106
-
107
- describe "only all" do
108
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, only: :all) }
109
-
110
- it "should return accurate event count" do
111
- expect(coordinator.events.count).to eq(66)
112
- end
113
- end
114
-
115
- describe "before date" do
116
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, before_date: Date.parse("1/1/2020")) }
117
-
118
- it "should return accurate event count" do
119
- expect(coordinator.events.count).to eq(55)
120
- end
121
- end
122
-
123
- describe "after date" do
124
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, after_date: Date.parse("1/1/2020")) }
125
-
126
- it "should return accurate event count" do
127
- expect(coordinator.events.count).to eq(11)
128
- end
129
- end
130
-
131
- describe "reverse" do
132
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, reverse: true) }
133
-
134
- it "should return dates from oldest to newest first" do
135
- first_date = coordinator.events.first.dtstart.to_date
136
- last_date = coordinator.events.last.dtstart.to_date
137
-
138
- expect(first_date).to be > last_date
139
- end
140
- end
141
- end
142
-
143
- context "with italian feed" do
144
- let(:fake_url) { "https://www.calendarfeed.com/feed.ics"}
145
- let(:mock_feed) { double(:mock_feed, fetch: EXAMPLE_RAW_FEEDS[:italian])}
146
- before { allow(Jekyll::IcalTag::CalendarFetcher).to receive(:new).and_return(mock_feed) }
147
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url) }
148
-
149
- it "should not raise error" do
150
- expect {
151
- coordinator.events
152
- }.to_not raise_error
153
- end
154
-
155
- it "should return accurate event count" do
156
- expect(coordinator.events.count).to eq(10)
157
- end
158
-
159
- it "should be able to parse all parse of each event" do
160
- coordinator.events.each do |event|
161
- expect { event.all_properties }.to_not raise_error
162
- expect { event.simple_html_description }.to_not raise_error
163
- expect { event.attendees }.to_not raise_error
164
- expect { event.description_urls }.to_not raise_error
165
- end
166
- end
167
-
168
- it "selected outputs should always be strings" do
169
- coordinator.events.each do |event|
170
- expect(event.simple_html_description.to_s).to be_a String
171
- expect(event.description.to_s).to be_a String
172
- event.all_properties.each do |property, value|
173
- expect(value).to be_a(Time)
174
- .or be_a(Date)
175
- .or be_a(String)
176
- .or be_a(NilClass)
177
- end
178
- end
179
- end
180
- end
181
-
182
-
183
- context "with sesh feed" do
184
- let(:fake_url) { "https://www.calendarfeed.com/feed.ics"}
185
- let(:mock_feed) { double(:mock_feed, fetch: EXAMPLE_RAW_FEEDS[:sesh])}
186
- before { allow(Jekyll::IcalTag::CalendarFetcher).to receive(:new).and_return(mock_feed) }
187
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url) }
188
-
189
- it "should return accurate event count" do
190
- expect(coordinator.events.count).to eq(3)
191
- end
192
-
193
- describe "reverse" do
194
- let(:coordinator) { Jekyll::IcalTag::CalendarFeedCoordinator.new(url: fake_url, reverse: reverse) }
195
-
196
- context "when reversed" do
197
- let(:reverse) { true }
198
-
199
- it "should return dates from oldest to newest first" do
200
- first_date = coordinator.events.first.dtstart.to_date
201
- last_date = coordinator.events.last.dtstart.to_date
202
-
203
- expect(first_date).to be > last_date
204
- end
205
- end
206
-
207
- context "when not reversed" do
208
- let(:reverse) { false }
209
-
210
- it "should return dates from oldest to newest first" do
211
- first_date = coordinator.events.first.dtstart.to_date
212
- last_date = coordinator.events.last.dtstart.to_date
213
-
214
- expect(first_date).to be < last_date
215
- end
216
- end
217
- end
218
- end
219
- end
@@ -1,85 +0,0 @@
1
- require "rspec"
2
-
3
- require "./lib/jekyll-ical-tag"
4
-
5
- RSpec.configure do |config|
6
- # rspec-expectations config goes here. You can use an alternate
7
- # assertion/expectation library such as wrong or the stdlib/minitest
8
- # assertions if you prefer.
9
- config.expect_with :rspec do |expectations|
10
- # This option will default to `true` in RSpec 4. It makes the `description`
11
- # and `failure_message` of custom matchers include text for helper methods
12
- # defined using `chain`, e.g.:
13
- # be_bigger_than(2).and_smaller_than(4).description
14
- # # => "be bigger than 2 and smaller than 4"
15
- # ...rather than:
16
- # # => "be bigger than 2"
17
- expectations.include_chain_clauses_in_custom_matcher_descriptions = true
18
- end
19
-
20
- # rspec-mocks config goes here. You can use an alternate test double
21
- # library (such as bogus or mocha) by changing the `mock_with` option here.
22
- config.mock_with :rspec do |mocks|
23
- # Prevents you from mocking or stubbing a method that does not exist on
24
- # a real object. This is generally recommended, and will default to
25
- # `true` in RSpec 4.
26
- mocks.verify_partial_doubles = true
27
- end
28
-
29
- # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
30
- # have no way to turn it off -- the option exists only for backwards
31
- # compatibility in RSpec 3). It causes shared context metadata to be
32
- # inherited by the metadata hash of host groups and examples, rather than
33
- # triggering implicit auto-inclusion in groups with matching metadata.
34
- config.shared_context_metadata_behavior = :apply_to_host_groups
35
-
36
- # This allows you to limit a spec run to individual examples or groups
37
- # you care about by tagging them with `:focus` metadata. When nothing
38
- # is tagged with `:focus`, all examples get run. RSpec also provides
39
- # aliases for `it`, `describe`, and `context` that include `:focus`
40
- # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
41
- config.filter_run_when_matching :focus
42
-
43
- # Allows RSpec to persist some state between runs in order to support
44
- # the `--only-failures` and `--next-failure` CLI options. We recommend
45
- # you configure your source control system to ignore this file.
46
- config.example_status_persistence_file_path = "spec/examples.txt"
47
-
48
- # Limits the available syntax to the non-monkey patched syntax that is
49
- # recommended. For more details, see:
50
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
51
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
52
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
53
- config.disable_monkey_patching!
54
-
55
- # This setting enables warnings. It"s recommended, but in some cases may
56
- # be too noisy due to issues in dependencies.
57
- # config.warnings = true
58
-
59
- # Many RSpec users commonly either run the entire suite or an individual
60
- # file, and it"s useful to allow more verbose output when running an
61
- # individual spec file.
62
- if config.files_to_run.one?
63
- # Use the documentation formatter for detailed output,
64
- # unless a formatter has already been configured
65
- # (e.g. via a command-line flag).
66
- config.default_formatter = "doc"
67
- end
68
-
69
- # Print the 10 slowest examples and example groups at the
70
- # end of the spec run, to help surface which specs are running
71
- # particularly slow.
72
- config.profile_examples = 10
73
-
74
- # Run specs in random order to surface order dependencies. If you find an
75
- # order dependency and want to debug it, you can fix the order by providing
76
- # the seed, which is printed after each run.
77
- # --seed 1234
78
- config.order = :random
79
-
80
- # Seed global randomization in this process using the `--seed` CLI option.
81
- # Setting this allows you to use `--seed` to deterministically reproduce
82
- # test failures related to randomization by passing the same `--seed` value
83
- # as the one that triggered the failure.
84
- Kernel.srand config.seed
85
- end