almanack 0.0.1.alpha3 → 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -13
  3. data/almanac.gemspec +2 -1
  4. data/bin/almanack +3 -0
  5. data/example.ru +18 -14
  6. data/lib/almanack.rb +16 -13
  7. data/lib/almanack/calendar.rb +35 -3
  8. data/lib/almanack/cli.rb +131 -0
  9. data/lib/almanack/configuration.rb +20 -4
  10. data/lib/almanack/event.rb +26 -1
  11. data/lib/almanack/event_source/ical_feed.rb +62 -0
  12. data/lib/almanack/event_source/meetup_group.rb +98 -0
  13. data/lib/almanack/event_source/static.rb +23 -0
  14. data/lib/almanack/server.rb +75 -4
  15. data/lib/almanack/themes/legacy/stylesheets/calendar.scss +168 -0
  16. data/lib/almanack/themes/legacy/views/error.erb +13 -0
  17. data/lib/almanack/themes/legacy/views/events.erb +4 -2
  18. data/lib/almanack/themes/legacy/views/layout.erb +9 -6
  19. data/lib/almanack/themes/starter/javascripts/calendar.js +5 -0
  20. data/lib/almanack/themes/starter/stylesheets/calendar.scss +27 -0
  21. data/lib/almanack/themes/starter/views/error.erb +13 -0
  22. data/lib/almanack/themes/starter/views/events.erb +31 -0
  23. data/lib/almanack/themes/starter/views/layout.erb +32 -0
  24. data/lib/almanack/version.rb +4 -1
  25. data/spec/almanack_spec.rb +8 -0
  26. data/spec/calendar_spec.rb +29 -25
  27. data/spec/configuration_spec.rb +19 -3
  28. data/spec/{ical_feed_spec.rb → event_source/ical_feed_spec.rb} +4 -4
  29. data/spec/{meetup_group_spec.rb → event_source/meetup_group_spec.rb} +4 -4
  30. data/spec/event_source/static_spec.rb +23 -0
  31. data/spec/event_spec.rb +24 -4
  32. data/spec/features/calendar_feature_spec.rb +7 -5
  33. data/spec/features/subscription_feature_spec.rb +60 -0
  34. data/spec/spec_helper.rb +2 -1
  35. data/spec/support/server_support.rb +2 -1
  36. data/spec/support/time_comparison_matchers.rb +14 -0
  37. data/templates/gitignore +2 -0
  38. data/templates/new/Gemfile +3 -0
  39. data/templates/new/config.ru.tt +24 -0
  40. metadata +45 -13
  41. data/lib/almanack/ical_feed.rb +0 -60
  42. data/lib/almanack/meetup_group.rb +0 -96
  43. data/lib/almanack/simple_event_collection.rb +0 -11
  44. data/lib/almanack/themes/legacy/views/stylesheets/legacy.css.sass +0 -119
  45. data/spec/simple_event_collection_spec.rb +0 -23
@@ -0,0 +1,13 @@
1
+ <% title 'Something went wrong' %>
2
+
3
+ <div id="error">
4
+ <h1>Oops.</h1>
5
+
6
+ <p>Something went wrong.</p>
7
+
8
+ <% if request.path == '/' %>
9
+ <p>Sorry about that. Check back later!</p>
10
+ <% else %>
11
+ <p><a href="/">Return home</a></p>
12
+ <% end %>
13
+ </div>
@@ -1,5 +1,7 @@
1
+ <% title 'Upcoming events' %>
2
+
1
3
  <div class="events">
2
- <% @calendar.events.each do |event| %>
4
+ <% calendar.events.each do |event| %>
3
5
  <div class="event">
4
6
  <div class="date">
5
7
  <div class="month"><%= event.start_date.strftime('%a') %></div>
@@ -21,7 +23,7 @@
21
23
  <% end %>
22
24
 
23
25
  <dt>When</dt>
24
- <dd><%= event.start_date.strftime('%l:%M%P, %-d %b %Y') %></dd>
26
+ <dd><%= event.formatted_date %></dd>
25
27
  </dl>
26
28
  </div>
27
29
  </div>
@@ -2,22 +2,25 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Upcoming events</title>
6
- <link rel="stylesheet" type="text/css" href="/stylesheets/legacy.css">
5
+ <title><%= page_title %></title>
6
+ <link rel="stylesheet" type="text/css" href="/stylesheets/calendar.css">
7
7
  </head>
8
8
  <body>
9
9
 
10
10
  <header>
11
- <h1><%= @calendar.title %></h1>
12
- <h2>The Next <%= @calendar.days_lookahead %> Days</h2>
11
+ <h1><a href="/"><%= calendar.title %></a></h1>
12
+ <h2>The Next <%= calendar.days_lookahead %> Days</h2>
13
13
  </header>
14
14
 
15
15
  <%= yield %>
16
16
 
17
17
  <footer>
18
+ <div class="subscribe">
19
+ <a href="<%= feed_url %>">Subscribe to Calendar</a>
20
+ </div>
21
+
18
22
  <div class="fork">
19
- Powered by <a href="http://github.com/Aupajo/sinatra-gcal">Almanack</a>.
20
- <a href="http://github.com/Aupajo/sinatra-gcal/issues">Bugs? Features?</a>
23
+ Powered by <a href="<%= almanack_project_url %>">Almanack</a>.
21
24
  </div>
22
25
  </footer>
23
26
 
@@ -0,0 +1,5 @@
1
+ // If you need jQuery, see views/layout.erb for an example of how to include it.
2
+ //
3
+ // CoffeeScript can also be added by adding `gem "coffee_script"` to your
4
+ // calendar's Gemfile and running `bundle install`. Name your CoffeeScript files
5
+ // with a .coffee extension.
@@ -0,0 +1,27 @@
1
+ // SCSS or regular CSS supported.
2
+ // http://sass-lang.com/
3
+
4
+ body {
5
+ font: 12pt/1.6em "Helvetica Neue", Arial, sans-serif;
6
+ margin: 4em;
7
+ }
8
+
9
+ header {
10
+ border-bottom: 2px solid;
11
+ }
12
+
13
+ footer {
14
+ border-top: 2px solid;
15
+ }
16
+
17
+ .event {
18
+ border-bottom: 1px solid #ccc;
19
+ padding: 2em 0;
20
+
21
+ .date {
22
+ .month, .day {
23
+ display: inline;
24
+ font-weight: bold;
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,13 @@
1
+ <% title 'Something went wrong' %>
2
+
3
+ <div id="error">
4
+ <h1>Oops.</h1>
5
+
6
+ <p>Something went wrong.</p>
7
+
8
+ <% if request.path == '/' %>
9
+ <p>Sorry about that. Check back later!</p>
10
+ <% else %>
11
+ <p><a href="/">Return home</a></p>
12
+ <% end %>
13
+ </div>
@@ -0,0 +1,31 @@
1
+ <% title 'Upcoming events' %>
2
+
3
+ <div class="events">
4
+ <% calendar.events.each do |event| %>
5
+ <div class="event">
6
+ <div class="date">
7
+ <div class="month"><%= event.start_date.strftime('%a') %></div>
8
+ <div class="day"><%= event.start_date.strftime('%d') %></div>
9
+ </div>
10
+ <div class="details">
11
+ <h3 class="title"><%= event.title %></h3>
12
+
13
+ <% if event.description %>
14
+ <div class="description">
15
+ <%= event.description %>
16
+ </div>
17
+ <% end %>
18
+
19
+ <dl>
20
+ <% if event.location %>
21
+ <dt>Where</dt>
22
+ <dd><%= event.location %></dd>
23
+ <% end %>
24
+
25
+ <dt>When</dt>
26
+ <dd><%= event.formatted_date %></dd>
27
+ </dl>
28
+ </div>
29
+ </div>
30
+ <% end %>
31
+ </div>
@@ -0,0 +1,32 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title><%= page_title %></title>
6
+ <link rel="stylesheet" type="text/css" href="/stylesheets/calendar.css">
7
+ </head>
8
+ <body>
9
+
10
+ <header>
11
+ <h1><a href="/"><%= calendar.title %></a></h1>
12
+ <h2>The Next <%= calendar.days_lookahead %> Days</h2>
13
+ </header>
14
+
15
+ <%= yield %>
16
+
17
+ <footer>
18
+ <div class="subscribe">
19
+ <a href="<%= feed_url %>">Subscribe to Calendar</a>
20
+ </div>
21
+
22
+ <div class="fork">
23
+ <!-- Don't feel any obligation to keep this link if you don't want to -->
24
+ Powered by <a href="<%= almanack_project_url %>">Almanack</a>.
25
+ </div>
26
+ </footer>
27
+
28
+ <!-- Uncomment the following like to include jQuery -->
29
+ <!-- <script src="//code.jquery.com/jquery-1.11.0.min.js"></script> -->
30
+ <script src="/javascripts/calendar.js"></script>
31
+ </body>
32
+ </html>
@@ -1,3 +1,6 @@
1
1
  module Almanack
2
- VERSION = "0.0.1.alpha3"
2
+ CODENAME = "Garlick"
3
+ VERSION = "1.0.0.pre"
4
+ HOMEPAGE = "https://github.com/Aupajo/sinatra-gcal"
5
+ ISSUES = "https://github.com/Aupajo/sinatra-gcal/issues"
3
6
  end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Almanack do
4
+ describe "#config" do
5
+ specify { expect(Almanack.config).to be_an_instance_of(Almanack::Configuration) }
6
+ specify { expect { |probe| Almanack.config(&probe) }.to yield_control }
7
+ end
8
+ end
@@ -13,39 +13,43 @@ module Almanack
13
13
  end
14
14
 
15
15
  describe "#events" do
16
- describe "with simple events" do
17
- it "returns the events" do
18
- config = Configuration.new
19
- config.add_events [
20
- { title: "Hogswatch" }
21
- ]
16
+ it "calls events_between with now and the days lookahead" do
17
+ config = Configuration.new
18
+ calendar = Calendar.new(config)
22
19
 
23
- calendar = Calendar.new(config)
20
+ now = Time.now
21
+ lookahead = 42
22
+ future = now + lookahead * 24 * 60 * 60
24
23
 
25
- expect(calendar.events.size).to eq(1)
26
- expect(calendar.events.first.title).to eq('Hogswatch')
24
+ Timecop.freeze(now) do
25
+ expect(calendar).to receive(:days_lookahead) { lookahead }
26
+ expect(calendar).to receive(:events_between) do |date_range|
27
+ expect(date_range.min).to eq_time(now)
28
+ expect(date_range.max).to eq_time(future)
29
+ :results
30
+ end
31
+
32
+ expect(calendar.events).to eq(:results)
27
33
  end
28
34
  end
35
+ end
29
36
 
30
- describe "with an iCal feed" do
31
- it "returns the event occurrences" do
32
- config = Configuration.new
33
- config.add_ical_feed "https://www.google.com/calendar/ical/61s2re9bfk01abmla4d17tojuo%40group.calendar.google.com/public/basic.ics"
34
-
35
- calendar = Calendar.new(config)
37
+ describe "#events_between" do
38
+ it "collects the event sources' events between two dates" do
39
+ today = Time.now
40
+ yesterday = today - 1
41
+ tomorrow = today + 1
36
42
 
37
- events = nil
43
+ config = Configuration.new
44
+ config.add_events [
45
+ { title: 'Today', start_date: today },
46
+ { title: 'Yesterday', start_date: yesterday },
47
+ { title: 'Tomorrow', start_date: tomorrow },
48
+ ]
38
49
 
39
- Timecop.freeze(2014, 4, 3) do
40
- VCR.use_cassette('google_calendar') do
41
- events = calendar.events
42
- end
43
- end
50
+ calendar = Calendar.new(config)
44
51
 
45
- expect(events.size).to eq(15)
46
- expect(events).to all_have_properties(:title, :start_date)
47
- expect(events).to be_in_order
48
- end
52
+ expect(calendar.events_between(today..tomorrow).map(&:title)).to eq(%w( Today Tomorrow ))
49
53
  end
50
54
  end
51
55
 
@@ -11,6 +11,22 @@ module Almanack
11
11
  end
12
12
  end
13
13
 
14
+ describe "#theme" do
15
+ it "can be set and accessed" do
16
+ config = Configuration.new
17
+ config.theme = "custom"
18
+ expect(config.theme).to eq("custom")
19
+ end
20
+ end
21
+
22
+ describe "#theme_root" do
23
+ specify "it raises an error if no theme can be found" do
24
+ config = Configuration.new
25
+ config.theme = "nonexistent"
26
+ expect { config.theme_root }.to raise_error(Configuration::ThemeNotFound)
27
+ end
28
+ end
29
+
14
30
  describe "#add_events" do
15
31
  it "adds a simple event collection event source" do
16
32
  config = Configuration.new
@@ -21,7 +37,7 @@ module Almanack
21
37
  ]
22
38
 
23
39
  expect(config.event_sources.size).to eq(1)
24
- expect(config.event_sources.first).to be_an_instance_of(SimpleEventCollection)
40
+ expect(config.event_sources.first).to be_an_instance_of(EventSource::Static)
25
41
  end
26
42
  end
27
43
 
@@ -33,7 +49,7 @@ module Almanack
33
49
  config.add_ical_feed "https://www.google.com/calendar/ical/61s2re9bfk01abmla4d17tojuo%40group.calendar.google.com/public/basic.ics"
34
50
 
35
51
  expect(config.event_sources.size).to eq(1)
36
- expect(config.event_sources.first).to be_an_instance_of(IcalFeed)
52
+ expect(config.event_sources.first).to be_an_instance_of(EventSource::IcalFeed)
37
53
  end
38
54
  end
39
55
 
@@ -45,7 +61,7 @@ module Almanack
45
61
  config.add_meetup_group(group_urlname: "CHC-JS", key: "secrettoken")
46
62
 
47
63
  expect(config.event_sources.size).to eq(1)
48
- expect(config.event_sources.first).to be_an_instance_of(MeetupGroup)
64
+ expect(config.event_sources.first).to be_an_instance_of(EventSource::MeetupGroup)
49
65
  end
50
66
  end
51
67
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module Almanack
3
+ module Almanack::EventSource
4
4
  describe IcalFeed do
5
5
  it "accepts a URL" do
6
6
  IcalFeed.new("http://example.org/ical.ics")
@@ -13,8 +13,8 @@ module Almanack
13
13
 
14
14
  Timecop.freeze(2014, 4, 3) do
15
15
  VCR.use_cassette('google_calendar') do
16
- from = DateTime.now
17
- to = from + 30
16
+ from = Time.now
17
+ to = from + 30 * 24 * 60 * 60
18
18
  events = feed.events_between(from..to)
19
19
  end
20
20
  end
@@ -27,4 +27,4 @@ module Almanack
27
27
  end
28
28
 
29
29
  end
30
- end
30
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module Almanack
3
+ module Almanack::EventSource
4
4
  describe MeetupGroup do
5
5
  describe "#events_between" do
6
6
  it "returns a list of events" do
@@ -9,8 +9,8 @@ module Almanack
9
9
 
10
10
  Timecop.freeze(2014, 5, 24) do
11
11
  VCR.use_cassette('meetup') do
12
- from = DateTime.now
13
- to = from + 30
12
+ from = Time.now
13
+ to = from + 30 * 24 * 60 * 60
14
14
  events = feed.events_between(from..to)
15
15
  end
16
16
  end
@@ -23,4 +23,4 @@ module Almanack
23
23
  end
24
24
 
25
25
  end
26
- end
26
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ module Almanack::EventSource
4
+ describe Static do
5
+ describe "#events_between" do
6
+ it "returns events between two dates" do
7
+ now = Time.now
8
+ yesterday = now - 1
9
+ tomorrow = now + 1
10
+
11
+ source = Static.new [
12
+ { title: 'Yesterday', start_date: yesterday },
13
+ { title: 'Today', start_date: now },
14
+ { title: 'Tomorrow', start_date: tomorrow }
15
+ ]
16
+
17
+ expect(source.events_between(yesterday..tomorrow).map(&:title)).to eq(%w( Yesterday Today Tomorrow ))
18
+ expect(source.events_between(now..tomorrow).map(&:title)).to eq(%w( Today Tomorrow ))
19
+ expect(source.events_between(yesterday..now).map(&:title)).to eq(%w( Yesterday Today ))
20
+ end
21
+ end
22
+ end
23
+ end
data/spec/event_spec.rb CHANGED
@@ -9,13 +9,13 @@ module Almanack
9
9
  end
10
10
 
11
11
  it "has a start date" do
12
- event = Event.new(start_date: DateTime.new(2014, 01, 01))
13
- expect(event.start_date).to eq(DateTime.new(2014, 01, 01))
12
+ event = Event.new(start_date: Time.new(2014, 01, 01))
13
+ expect(event.start_date).to eq_time(Time.new(2014, 01, 01))
14
14
  end
15
15
 
16
16
  it "has a end date" do
17
- event = Event.new(end_date: DateTime.new(2014, 01, 02))
18
- expect(event.end_date).to eq(DateTime.new(2014, 01, 02))
17
+ event = Event.new(end_date: Time.new(2014, 01, 02))
18
+ expect(event.end_date).to eq_time(Time.new(2014, 01, 02))
19
19
  end
20
20
 
21
21
  it "has a location" do
@@ -28,5 +28,25 @@ module Almanack
28
28
  expect(event.description).to eq("Be there or be a rectangular thynge.")
29
29
  end
30
30
 
31
+ describe "#formatted_date" do
32
+ it "handles events without an end date" do
33
+ event = Event.new(start_date: Time.parse("2014-07-06 06:24:00 UTC"))
34
+ expect(event.formatted_date).to eq("July 6 2014 at 6:24am")
35
+ end
36
+
37
+ it "handles events with an end date on the same day" do
38
+ event = Event.new(start_date: Time.parse("2014-07-06 06:24:00 UTC"),
39
+ end_date: Time.parse("2014-07-06 13:20:00 UTC"))
40
+ expect(event.formatted_date).to eq("July 6 2014 at 6:24am to 1:20pm")
41
+ end
42
+
43
+ it "handles events with an end date on a different day" do
44
+ event = Event.new(start_date: Time.parse("2014-07-06 06:00:00 UTC"),
45
+ end_date: Time.parse("2014-08-07 10:00:00 UTC"))
46
+ expect(event.formatted_date).to eq("July 6 2014 at 6:00am to August 7 2014 at 10:00am")
47
+ end
48
+ end
49
+
50
+
31
51
  end
32
52
  end
@@ -4,15 +4,17 @@ describe "Viewing a calendar", :feature do
4
4
  before { Almanack.reset! }
5
5
 
6
6
  it "displays all upcoming events" do
7
- today = DateTime.now
7
+ now = Time.now
8
8
 
9
9
  Almanack.config.add_events [
10
- { title: "Hogswatch", start_date: today },
11
- { title: "Soul Cake Tuesday", start_date: today + 10 },
12
- { title: "Eve of Small Gods", start_date: today + 30 },
10
+ { title: "Hogswatch", start_date: now },
11
+ { title: "Soul Cake Tuesday", start_date: now + 10 * 24 * 60 * 60 },
12
+ { title: "Eve of Small Gods", start_date: now + 30 * 24 * 60 * 60 },
13
13
  ]
14
14
 
15
- get "/"
15
+ Timecop.freeze(now) do
16
+ get "/"
17
+ end
16
18
 
17
19
  expect(last_response).to have_event_on_page("Hogswatch")
18
20
  expect(last_response).to have_event_on_page("Soul Cake Tuesday")