simple_calendar 1.1.10 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b1bdcbd6d655fbc158f0cf7d66e3895da990d2bd
4
- data.tar.gz: c9eae626c02312bf24d10416f0e7fdae69718e9e
3
+ metadata.gz: 8dfc97c340a63812f227e879a6756c2802c50488
4
+ data.tar.gz: ebf3dad29eae132666ecc41060996ca812e59d9c
5
5
  SHA512:
6
- metadata.gz: e18cb18051aa312839aff84a6236302319accd44d208e3c5166e32af5bbe32409ab10149e8d8081f0117a6703ba23eb7e846f843899c64e6d04ec150044d5d9a
7
- data.tar.gz: 2c82eaaa511a7c86c95b7e4555528789e84a5a64df3b4c2c6de7cdb0aec8cdad05802ca8360f332664a18e7c0d939f13fcceaa85f32dc64a5b7aa8b3ce1826c3
6
+ metadata.gz: c7fcff14b9f734bd872120d693bd3b71434cf82d439d92a11767c3cc6fbc862a05d2b297b7937b3704b5c5adf5d0dee6a2390b1bbb0a58a0d9003ad53d0fa9d8
7
+ data.tar.gz: 32501ddee6d5535fd55a1af0487b66ba9a3b23c3e464e48181e1bb7956de0efacc599decff45c131b9f8ba9f7b4865eb81ea0b8bf7a9256a66d022894332942f
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ - 2.1.6
5
+ - 2.0.0
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ ![travis ci](https://travis-ci.org/excid3/simple_calendar.svg?branch=2.0)
2
+
1
3
  Simple Calendar
2
4
  ===============
3
5
 
@@ -19,12 +21,12 @@ Installation
19
21
 
20
22
  Just add this into your Gemfile followed by a bundle install:
21
23
 
22
- gem "simple_calendar", "~> 1.1.0"
24
+ gem "simple_calendar", "~> 2.0"
23
25
 
24
26
  Usage
25
27
  -----
26
28
 
27
- Generating calendars is extremely simple with simple_calendar in version 1.1.
29
+ Generating calendars is extremely simple with simple_calendar.
28
30
 
29
31
  The first parameter is a symbol that looks up the current date in
30
32
  `params`. If no date is found, it will use the current date.
@@ -77,26 +79,26 @@ model called Meeting, but you can add this to any model or Ruby object.
77
79
  Here's an example model:
78
80
 
79
81
  ```bash
80
- rails g scaffold Meeting name starts_at:datetime
82
+ rails g scaffold Meeting name start_time:datetime
81
83
  ```
82
84
 
83
- We use the `has_calendar` method to tell simple_calendar how to filter
84
- and sort the meetings on the different calendar days. This should be the
85
- start date/time of your meeting. By default it uses `starts_at` as the
86
- attribute name.
85
+ By default it uses `start_time` as the attribute name.
87
86
 
88
- ```ruby
89
- class Meeting < ActiveRecord::Base
90
- extend SimpleCalendar
91
- has_calendar
87
+ **If you'd like to use another attribute other than start_time, just
88
+ pass it in as the `attribute` option**
92
89
 
93
- # Or set a custom attribute for simple_calendar to sort by
94
- # has_calendar :attribute => :your_starting_time_column_name
95
- end
90
+ ```erb
91
+ <%= month_calendar(attribute: :starts_at) do |date| %>
92
+ <%= day %>
93
+ <% end %>
96
94
  ```
97
95
 
98
96
  In your controller, query for these meetings and store them in an instance
99
- variable. We'll just load up all the meetings for this example.
97
+ variable. Normally you'll want to search for the ones that only show up
98
+ inside the calendar view (for example, you may only want to grab the events for
99
+ the current month).
100
+
101
+ We'll just load up all the meetings for this example.
100
102
 
101
103
  ```ruby
102
104
  def index
@@ -125,13 +127,23 @@ do custom filtering however you want.
125
127
 
126
128
  ## Customizing The Calendar
127
129
 
128
- You can change a couple of global options that will affect how the
129
- calendars are generated:
130
+ There are a handful of configuration options that you can use in
131
+ simple_calendar.
130
132
 
131
- ```ruby
132
- Time.zone = "Central Time (US & Canada)"
133
+ ### Customizing Views
134
+
135
+ You can customize the layouts for each of the calendars by running the
136
+ generators for simple_calendar:
137
+
138
+ ```bash
139
+ rails g simple_calendar:views
133
140
  ```
134
141
 
142
+ This will generate a folder in app/views called simple_calendar that you
143
+ edit to your heart's desire.
144
+
145
+ ### Time Zones
146
+
135
147
  Setting `Time.zone` will make sure the calendar start days are correctly computed
136
148
  in the right timezone. You can set this globally in your `application.rb` file or
137
149
  if you have a User model with a time_zone attribute, you can set it on every request by using
@@ -153,12 +165,6 @@ class ApplicationController < ActionController::Base
153
165
  end
154
166
  end
155
167
  ```
156
- On the other hand, you can always pass a ``ActiveSupport::TimeZone`` object as an option to avoid possible timezone pollution:
157
-
158
- ```erb
159
- <%= calendar timezone: ActiveSupport::TimeZone.new('Taipei') do |date, events| %>
160
- <% end %>
161
- ```
162
168
 
163
169
  If you want to set the time zone globally, you can set the following in
164
170
  `config/application.rb`:
@@ -167,6 +173,8 @@ If you want to set the time zone globally, you can set the following in
167
173
  config.time_zone = 'Central Time (US & Canada)'
168
174
  ```
169
175
 
176
+ ### Beginning Of Week
177
+
170
178
  You can also change the beginning day of the week by setting
171
179
  `Date.beginning_of_week` in a `before_filter` just like in the previous
172
180
  example. If you want to set this globally, you can put this line in
@@ -176,188 +184,142 @@ example. If you want to set this globally, you can put this line in
176
184
  config.beginning_of_week = :sunday
177
185
  ```
178
186
 
187
+ ### Custom CSS Classes
188
+
179
189
  Setting classes on the table and elements are pretty easy.
180
190
 
181
- Each of the options are passed directly to the
182
- the `content_tag` method so each of them **must** be a hash.
191
+ You can simply run the following command to install the calendar views
192
+ and then add your own helpers to the table, rows, headers, and days.
183
193
 
184
- ```ruby
194
+ simple_calendar comes with a handful of useful classes for each day in
195
+ the calendar that you can use:
185
196
 
186
- <%= calendar table: {class: "table table-bordered"}, tr: {class: "calendar-row"}, td: {class: "day"}, do |date| %>
187
- <% end %>
188
- ```
197
+ ```scss
198
+ .simple-calendar {
199
+ .day {}
189
200
 
190
- This will set the class of `table table-bordered` on the `table` HTML
191
- element.
201
+ .wday-0 {}
202
+ .wday-1 {}
203
+ .wday-2 {}
204
+ .wday-3 {}
205
+ .wday-4 {}
206
+ .wday-5 {}
207
+ .wday-6 {}
192
208
 
193
- ### Custom Day Classes
209
+ .today {}
210
+ .past {}
211
+ .future {}
194
212
 
195
- `td` is an option for setting the options on the td content tag that is
196
- generated. By default, simple_calendar renders the following classes for
197
- any given day in a calendar:
213
+ .start-date {}
198
214
 
215
+ .prev-month {}
216
+ .next-month { }
217
+ .current-month {}
199
218
 
200
- ```ruby
201
- td_class = ["day"]
202
- td_class << "today" if today == current_calendar_date
203
- td_class << "past" if today > current_calendar_date
204
- td_class << "future" if today < current_calendar_date
205
- td_class << "prev-month" if start_date.month != current_calendar_date.month && current_calendar_date < start_date
206
- td_class << "next-month" if start_date.month != current_calendar_date.month && current_calendar_date > start_date
207
- td_class << "current-month" if start_date.month == current_calendar_date.month
208
- td_class << "wday-#{current_calendar_date.wday.to_s}"
219
+ .has-events {}
220
+ }
209
221
  ```
210
222
 
211
- You can set your CSS styles based upon these if you want to highlight
212
- specific days or types of days. If you wish to override this
213
- functionality, just set the `tr` option to a lambda that accepts two
214
- dates and returns a hash. The hash will be passed in directly to the
215
- content_tag options. If you wish to set a class or data attributes, just
216
- set them as you normally would in a content_tag call.
223
+ Just paste this into a CSS file and add your styles and they will be
224
+ applied to the calendar. All of these classes are inside of the
225
+ simple-calendar class so you can scope your own classes with similar
226
+ names.
217
227
 
218
- ```erb
219
- <%= month_calendar td: ->(start_date, current_calendar_date) { {class: "calendar-date", data: {day: current_calendar_date}} } do |day| %>
220
- <% end %>
221
- ```
222
-
223
- This generate each day in the calendar like this:
228
+ ### Custom Header Title And Links
224
229
 
225
- ```html
226
- <td class="calendar-date" data-day="2014-05-11">
227
- </td>
228
- ```
230
+ Header and title links are easily adjusted by generating views and
231
+ modifying them inside your application.
229
232
 
230
- Instead of writing the lambdas inline, a cleaner approach is to write a
231
- helper that returns a lambda. You can duplicate the following example by
232
- adding this to one of your helpers:
233
+ For example, if you'd like to use abbreviated month names, you can modify
234
+ the views from this:
233
235
 
234
- ```ruby
235
- def month_calendar_td_options
236
- ->(start_date, current_calendar_date) {
237
- {class: "calendar-date", data: {day: current_calendar_date}}
238
- }
239
- end
236
+ ```erb
237
+ <%= I18n.t("date.month_names")[start_date.month] %> <%= start_date.year %>
240
238
  ```
241
239
 
242
- And then your view would use `month_calendar_td_options` as the value.
240
+ To
243
241
 
244
242
  ```erb
245
- <%= month_calendar td: month_calendar_td_options do |date| %>
246
- <% end %>
243
+ <%= I18n.t("date.abbr_month_names")[start_date.month] %> <%= start_date.year %>
247
244
  ```
248
245
 
249
- ### Custom Header Title And Links
246
+ Your calendar will now display "Sep 2015" instead of "September 2015" at
247
+ the top! :)
250
248
 
251
- Each of the calendar methods will generate a header with links to the
252
- previous and next views. The `month_calendar` also includes a header
253
- with a title that tells you the current month and year that you are viewing.
254
-
255
- To change these, you can pass in the `previous_link`, `title`, and
256
- `next_link` options into the calendar methods.
249
+ ### AJAX Calendars
257
250
 
258
- **Use a method in your helpers to return a lambda instead of writing
259
- them inline like these examples so your views are cleaner.**
251
+ Rendering calendars that update with AJAX is pretty simple. You'll need
252
+ to wrap your calendar in a div, overwrite the `next_link` and `previous_link` options, and setup your
253
+ controller to respond to JS requests. The response can simply replace
254
+ the HTML of the div with the newly rendered calendar.
260
255
 
261
- * `title` option is a lambda that shows at the top of the calendar. For
262
- month calendars, this is the Month and Year (May 2014)
256
+ Take a look at **[excid3/simple_calendar-ajax-example](https://github.com/excid3/simple_calendar-ajax-example)** to see how it is done.
263
257
 
264
- ```erb
265
- <%= calendar title: ->(start_date) { content_tag :span, "#{I18n.t("date.month_names")[start_date.month]} #{start_date.year}", class: "calendar-title" } do |date, events| %>
266
- <% end %>
267
- ```
268
258
 
269
- * `previous_link` option is a standard `link_to` that is a left arrow and
270
- with the current url having `?start_date=2014-04-30` appended to it as
271
- a date in the previous view of the calendar.
259
+ ## Custom Calendars
272
260
 
273
- ```erb
274
- <%= month_calendar previous_link: ->(param, date_range) { link_to raw("&laquo;"), {param => date_range.first - 1.day} } do |date, events| %>
275
- <% end %>
276
- ```
261
+ The three main calendars available should take care of most of your
262
+ needs, but simple_calendar makes it easy to create completely custom
263
+ calendars (like maybe you only want business weeks).
277
264
 
278
- * `next_link` option is a standard `link_to` that is a right arrow and
279
- with the current url having `?start_date=2014-06-01` appended to it as
280
- a date in the next view of the calendar.
265
+ If you'd like to make a completely custom calendar, you can create a new
266
+ class that inherits from `SimpleCalendar::Calendar`. The name you give
267
+ it will correspond to the name of the template it will try to render.
281
268
 
282
- ```erb
283
- <%= calendar next_link: ->(param, date_range) { link_to raw("&raquo;"), {param => date_range.last + 1.day} } do |date, events| %>
284
- <% end %>
285
- ```
286
269
 
287
- * `header` lets you add options to the header tag
270
+ The main method you'll need to implement is the `date_range` so that
271
+ your calendar can have a custom length.
288
272
 
289
- ```erb
290
- <%= calendar header: {class: "calendar-header"} do |date, events| %>
291
- <% end %>
292
273
  ```
274
+ class SimpleCalendar::BusinessWeekCalendar
275
+ private
293
276
 
294
- * `thead` allows you to customize the table headers. These are the
295
- abbreviated day names by default (Sun Mon Tue Wed).
277
+ def date_range
278
+ beginning = start_date.beginning_of_week + 1.day
279
+ ending = start_date.end_of_week - 1.day
280
+ (beginning..ending)
281
+ end
282
+ end
283
+ ```
296
284
 
297
- You can disable the `thead` line if you like by passing in `false`.
285
+ To render this in the view, you can do:
298
286
 
299
287
  ```erb
300
- <%= calendar thead: false do |date, events| %>
288
+ <%= SimpleCalendar::BusinessWeekCalendar.new(self).render do |date| %>
289
+ <%= day %>
301
290
  <% end %>
302
291
  ```
303
292
 
304
- * `day_names` lets you customize the day names in the `thead` row.
293
+ And this will render the
294
+ `app/views/simple_calendar/_business_week_calendar.html.erb` partial.
305
295
 
306
- If you want to use full day names instead of the abbreviated ones in the
307
- table header, you can pass in the `day_names` option which points to a
308
- validate I18n array.
296
+ You can copy one of the existing templates to use for the partial for
297
+ your new calendar.
309
298
 
310
- ```erb
311
- <%= calendar day_names: "date.day_names" do |date, events| %>
312
- <% end %>
313
- ```
314
-
315
- Which renders:
316
-
317
- ```html
318
- <thead>
319
- <tr>
320
- <th>Sunday</th>
321
- <th>Monday</th>
322
- <th>Tuesday</th>
323
- <th>Wednesday</th>
324
- </tr>
325
- </thead>
326
- ```
299
+ ## View Specs and Tests
327
300
 
328
- By default we use the `date.abbr_day_names` translation to have shorter
329
- header names.
301
+ If you're running view specs against views with calendars, you may run into route generation errors like the following:
330
302
 
331
- ```erb
332
- <%= calendar day_names: "date.abbr_day_names" do |date, events| %>
333
- <% end %>
334
303
  ```
335
-
336
- This renders:
337
-
338
- ```html
339
- <thead>
340
- <tr>
341
- <th>Sun</th>
342
- <th>Mon</th>
343
- <th>Tue</th>
344
- <th>Wed</th>
345
- </tr>
346
- </thead>
304
+ Failure/Error: render
305
+ ActionView::Template::Error:
306
+ No route matches {:action=>"show", :controller=>"controller_name", :start_date=>Sun, 29 Mar 2015}
347
307
  ```
348
308
 
349
- ### AJAX Calendars
309
+ If so, you can stub out the appropriate method like so (rspec 3 and up):
350
310
 
351
- Rendering calendars that update with AJAX is pretty simple. You'll need
352
- to wrap your calendar in a div, overwrite the `next_link` and `previous_link` options, and setup your
353
- controller to respond to JS requests. The response can simply replace
354
- the HTML of the div with the newly rendered calendar.
311
+ ```
312
+ expect_any_instance_of(SimpleCalendar::Calendar).to receive(:link_to).at_least(:once).and_return("")
313
+ ```
355
314
 
356
- Take a look at **[excid3/simple_calendar-ajax-example](https://github.com/excid3/simple_calendar-ajax-example)** to see how it is done.
315
+ With modifications as appropriate.
357
316
 
358
317
  ## TODO
359
318
 
360
- - Multi-day events?
319
+ - Multi-day events
320
+ - Rspec tests for Calendar
321
+ - Rspec tests for MonthCalendar
322
+ - Rspec tests for WeekCalendar
361
323
 
362
324
  ## Author
363
325
 
@@ -366,3 +328,7 @@ Chris Oliver <chris@gorails.com>
366
328
  [https://gorails.com](https://gorails.com)
367
329
 
368
330
  [@excid3](https://twitter.com/excid3)
331
+
332
+ ## Support
333
+
334
+ Need help
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task default: :spec
7
+ rescue LoadError
8
+ end
@@ -0,0 +1,27 @@
1
+ <div class="simple-calendar">
2
+ <%= link_to "Previous", start_date: date_range.first - 1.day %>
3
+ <%= I18n.t("date.month_names")[start_date.month] %> <%= start_date.year %>
4
+ <%= link_to "Next", start_date: date_range.last + 1.day %>
5
+
6
+ <table class="table table-striped">
7
+ <thead>
8
+ <tr>
9
+ <% date_range.slice(0, 7).each do |day| %>
10
+ <th><%= I18n.t("date.abbr_day_names")[day.wday] %></th>
11
+ <% end %>
12
+ </tr>
13
+ </thead>
14
+
15
+ <tbody>
16
+ <% date_range.each_slice(7) do |week| %>
17
+ <tr>
18
+ <% week.each do |day| %>
19
+ <%= content_tag :td, class: calendar.td_classes_for(day) do %>
20
+ <%= block.call day, sorted_events.fetch(day, []) %>
21
+ <% end %>
22
+ <% end %>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
27
+ </div>
@@ -0,0 +1,27 @@
1
+ <div class="simple-calendar">
2
+ <%= link_to "Previous", start_date: date_range.first - 1.day %>
3
+ <%= I18n.t("date.month_names")[start_date.month] %> <%= start_date.year %>
4
+ <%= link_to "Next", start_date: date_range.last + 1.day %>
5
+
6
+ <table class="table table-striped">
7
+ <thead>
8
+ <tr>
9
+ <% date_range.slice(0, 7).each do |day| %>
10
+ <th><%= I18n.t("date.abbr_day_names")[day.wday] %></th>
11
+ <% end %>
12
+ </tr>
13
+ </thead>
14
+
15
+ <tbody>
16
+ <% date_range.each_slice(7) do |week| %>
17
+ <tr>
18
+ <% week.each do |day| %>
19
+ <%= content_tag :td, class: calendar.td_classes_for(day) do %>
20
+ <%= block.call day, sorted_events.fetch(day, []) %>
21
+ <% end %>
22
+ <% end %>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
27
+ </div>
@@ -0,0 +1,27 @@
1
+ <div class="simple-calendar">
2
+ <%= link_to "Previous", start_date: date_range.first - 1.day %>
3
+ Week <%= start_date.strftime("%U").to_i %>
4
+ <%= link_to "Next", start_date: date_range.last + 1.day %>
5
+
6
+ <table class="table table-striped">
7
+ <thead>
8
+ <tr>
9
+ <% date_range.slice(0, 7).each do |day| %>
10
+ <th><%= I18n.t("date.abbr_day_names")[day.wday] %></th>
11
+ <% end %>
12
+ </tr>
13
+ </thead>
14
+
15
+ <tbody>
16
+ <% date_range.each_slice(7) do |week| %>
17
+ <tr>
18
+ <% week.each do |day| %>
19
+ <%= content_tag :td, class: calendar.td_classes_for(day) do %>
20
+ <%= block.call day, sorted_events.fetch(day, []) %>
21
+ <% end %>
22
+ <% end %>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
27
+ </div>
data/bin/console ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'rails'
5
+ require 'simple_calendar'
6
+
7
+ require 'irb'
8
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+
3
+ module SimpleCalendar
4
+ module Generators
5
+ class ViewsGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../../../..", __FILE__)
7
+
8
+ def copy_views
9
+ directory 'app/views/simple_calendar', 'app/views/simple_calendar'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,17 +1,7 @@
1
1
  require "simple_calendar/calendar"
2
2
  require "simple_calendar/month_calendar"
3
3
  require "simple_calendar/week_calendar"
4
- require "simple_calendar/model_additions"
5
4
  require "simple_calendar/railtie"
6
5
  require "simple_calendar/version"
7
6
  require "simple_calendar/view_helpers"
8
7
 
9
- module SimpleCalendar
10
- def self.extended(model_class)
11
- return if model_class.respond_to? :has_calendar
12
-
13
- model_class.class_eval do
14
- extend ModelAdditions
15
- end
16
- end
17
- end
@@ -1,147 +1,83 @@
1
+ require 'rails'
2
+
1
3
  module SimpleCalendar
2
4
  class Calendar
3
- delegate :capture, :concat, :content_tag, :link_to, :params, :raw, :safe_join, to: :view_context
4
-
5
- attr_reader :block, :events, :options, :view_context
5
+ attr_accessor :view_context, :options
6
6
 
7
7
  def initialize(view_context, opts={})
8
8
  @view_context = view_context
9
- @events = opts.delete(:events) { [] }
10
- @timezone = opts.fetch(:timezone, Time.zone)
11
-
12
- opts.reverse_merge!(
13
- header: {class: "calendar-header"},
14
- previous_link: default_previous_link,
15
- title: default_title,
16
- next_link: default_next_link,
17
- td: default_td_classes,
18
- thead: default_thead,
9
+ @options = opts
10
+ end
11
+
12
+ def render(&block)
13
+ view_context.render(
14
+ partial: partial_name,
15
+ locals: {
16
+ block: block,
17
+ calendar: self,
18
+ date_range: date_range,
19
+ start_date: start_date,
20
+ sorted_events: sorted_events
21
+ }
19
22
  )
20
-
21
- @options = opts
22
23
  end
23
24
 
24
- def render(block)
25
- @block = block
25
+ def td_classes_for(day)
26
+ today = Time.zone.now.to_date
26
27
 
27
- capture do
28
- concat render_header
29
- concat render_table
30
- end
31
- end
28
+ td_class = ["day"]
29
+ td_class << "wday-#{day.wday.to_s}"
30
+ td_class << "today" if today == day
31
+ td_class << "past" if today > day
32
+ td_class << "future" if today < day
33
+ td_class << 'start-date' if day.to_date == start_date.to_date
34
+ td_class << "prev-month" if start_date.month != day.month && day < start_date
35
+ td_class << "next-month" if start_date.month != day.month && day > start_date
36
+ td_class << "current-month" if start_date.month == day.month
37
+ td_class << "has-events" if sorted_events.fetch(day, []).any?
32
38
 
33
- def render_header
34
- capture do
35
- content_tag :header, get_option(:header) do
36
- concat get_option(:previous_link, param_name, date_range)
37
- concat get_option(:title, start_date)
38
- concat get_option(:next_link, param_name, date_range)
39
- end
40
- end
39
+ td_class
41
40
  end
42
41
 
43
- def render_table
44
- content_tag :table, get_option(:table) do
45
- capture do
46
- concat get_option(:thead, date_range.to_a.slice(0, 7))
47
- concat content_tag(:tbody, render_weeks, get_option(:tbody))
48
- end
49
- end
50
- end
51
-
52
- def render_weeks
53
- capture do
54
- date_range.each_slice(7) do |week|
55
- concat content_tag(:tr, render_week(week), get_option(:tr, week))
56
- end
57
- end
58
- end
42
+ private
59
43
 
60
- def render_week(week)
61
- results = week.map do |day|
62
- content_tag :td, get_option(:td, start_date, day) do
63
- block.call(day, events_for_date(day))
64
- end
44
+ def partial_name
45
+ self.class.name.underscore
65
46
  end
66
- safe_join results
67
- end
68
-
69
- def param_name
70
- @param_name ||= options.fetch(:param_name, :start_date)
71
- end
72
47
 
73
- def events_for_date(current_date)
74
- if events.any? && events.first.respond_to?(:simple_calendar_start_time)
75
- events.select do |e|
76
- current_date == e.send(:simple_calendar_start_time).in_time_zone(@timezone).to_date
77
- end.sort_by(&:simple_calendar_start_time)
78
- else
79
- events
48
+ def attribute
49
+ options.fetch(:attribute, :start_time).to_sym
80
50
  end
81
- end
82
51
 
83
- def default_previous_link
84
- ->(param, date_range) { link_to raw("&laquo;"), param => date_range.first - 1.day }
85
- end
86
-
87
- def default_title
88
- ->(start_date) { }
89
- end
90
-
91
- def default_next_link
92
- ->(param, date_range) { link_to raw("&raquo;"), param => date_range.last + 1.day }
93
- end
94
-
95
- def default_thead
96
- ->(dates) {
97
- content_tag(:thead) do
98
- content_tag(:tr) do
99
- capture do
100
- dates.each do |date|
101
- concat content_tag(:th, I18n.t(options.fetch(:day_names, "date.abbr_day_names"))[date.wday])
102
- end
103
- end
52
+ def sorted_events
53
+ events = options.fetch(:events, [])
54
+ sorted = {}
55
+
56
+ events.each do |event|
57
+ start_time = event.send(attribute)
58
+ if start_time.present?
59
+ date = start_time.to_date
60
+ sorted[date] ||= []
61
+ sorted[date] << event
62
+ sorted[date] = sorted[date].sort_by(&attribute)
104
63
  end
105
64
  end
106
- }
107
- end
108
65
 
109
- def start_date
110
- @start_date ||= (get_option(:start_date) || params[param_name] || Time.zone.now).to_date
111
- end
66
+ # TODO: move sorting by start_time to after the event loop
112
67
 
113
- def date_range
114
- @date_range ||= begin
115
- number_of_days = options.fetch(:number_of_days, 4) - 1
116
- start_date..(start_date + number_of_days.days)
117
- end
118
- end
68
+ sorted
69
+ end
119
70
 
120
- def default_td_classes
121
- ->(start_date, current_calendar_date) {
122
- today = Time.zone.now.to_date
123
- td_class = ["day"]
124
- td_class << "today" if today == current_calendar_date
125
- td_class << "past" if today > current_calendar_date
126
- td_class << "future" if today < current_calendar_date
127
- td_class << "prev-month" if start_date.month != current_calendar_date.month && current_calendar_date < start_date
128
- td_class << "next-month" if start_date.month != current_calendar_date.month && current_calendar_date > start_date
129
- td_class << "current-month" if start_date.month == current_calendar_date.month
130
- td_class << "wday-#{current_calendar_date.wday.to_s}"
131
- td_class << "has-events" if events_for_date(current_calendar_date).any?
132
-
133
- { class: td_class.join(" ") }
134
- }
135
- end
71
+ def start_date
72
+ view_context.params.fetch(:start_date, Date.today).to_date
73
+ end
136
74
 
137
- def get_option(name, *params)
138
- option = options[name]
139
- case option
140
- when Hash
141
- option
142
- else
143
- option.respond_to?(:call) ? option.call(*params) : option
75
+ def date_range
76
+ (start_date..(start_date + additional_days.days)).to_a
77
+ end
78
+
79
+ def additional_days
80
+ options.fetch(:number_of_days, 4) - 1
144
81
  end
145
- end
146
82
  end
147
83
  end
@@ -1,16 +1,10 @@
1
1
  module SimpleCalendar
2
- class MonthCalendar < Calendar
3
- def date_range
4
- @date_range ||= start_date.beginning_of_month.beginning_of_week..start_date.end_of_month.end_of_week
5
- end
2
+ class MonthCalendar < SimpleCalendar::Calendar
3
+ private
6
4
 
7
- def default_title
8
- ->(start_date) { content_tag :span, month_name(start_date) }
9
- end
10
-
11
- def month_name(start_date)
12
- "#{I18n.t("date.month_names")[start_date.month]} #{start_date.year}"
13
- end
5
+ def date_range
6
+ (start_date.beginning_of_month.beginning_of_week..start_date.end_of_month.end_of_week).to_a
7
+ end
14
8
  end
15
9
  end
16
10
 
@@ -1,5 +1,5 @@
1
1
  module SimpleCalendar
2
- class Railtie < Rails::Railtie
2
+ class Engine < Rails::Engine
3
3
  initializer "simple_calendar.view_helpers" do
4
4
  ActionView::Base.send :include, ViewHelpers
5
5
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleCalendar
2
- VERSION = "1.1.10"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -2,17 +2,17 @@ module SimpleCalendar
2
2
  module ViewHelpers
3
3
  def calendar(options={}, &block)
4
4
  raise 'calendar requires a block' unless block_given?
5
- SimpleCalendar::Calendar.new(self, options).render(block)
5
+ SimpleCalendar::Calendar.new(self, options).render(&block)
6
6
  end
7
7
 
8
8
  def month_calendar(options={}, &block)
9
9
  raise 'month_calendar requires a block' unless block_given?
10
- SimpleCalendar::MonthCalendar.new(self, options).render(block)
10
+ SimpleCalendar::MonthCalendar.new(self, options).render(&block)
11
11
  end
12
12
 
13
13
  def week_calendar(options={}, &block)
14
14
  raise 'week_calendar requires a block' unless block_given?
15
- SimpleCalendar::WeekCalendar.new(self, options).render(block)
15
+ SimpleCalendar::WeekCalendar.new(self, options).render(&block)
16
16
  end
17
17
  end
18
18
  end
@@ -1,44 +1,16 @@
1
1
  module SimpleCalendar
2
- class WeekCalendar < Calendar
3
- def date_range
4
- @date_range ||= begin
5
- number_of_weeks = options.fetch(:number_of_weeks, 1)
6
- number_of_days = (number_of_weeks * 7) - 1
7
- starting_day = start_date.beginning_of_week.to_date
8
- ending_day = starting_day + number_of_days.days
9
- starting_day..ending_day
10
- end
11
- end
2
+ class WeekCalendar < SimpleCalendar::Calendar
3
+ private
12
4
 
13
- def default_title
14
- ->(start_date) { content_tag :span,
15
- if month_name(@date_range.last) == month_name(start_date)
16
- month_name(start_date) .
17
- concat year_number(start_date)
18
- else
19
- month_name(start_date) .
20
- concat " into " .
21
- concat month_name(@date_range.last) .
22
- concat year_number @date_range.last
23
- end
24
- }
25
- end
5
+ def date_range
6
+ starting = start_date.beginning_of_week
7
+ ending = (starting + (number_of_weeks - 1).weeks).end_of_week
26
8
 
27
- def default_previous_link
28
- ->(param, date_range) { link_to raw("&laquo;"), param => date_range.first - (((options.fetch(:number_of_weeks, 1) - 1) * 7) + 1).days }
29
- end
9
+ (starting..ending).to_a
10
+ end
30
11
 
31
- def default_next_link
32
- ->(param, date_range) { link_to raw("&raquo;"), param => date_range.last + 1.day }
33
- end
34
-
35
- def month_name(date)
36
- "#{I18n.t("date.month_names")[date.month]}"
37
- end
38
-
39
- def year_number(date)
40
- " #{date.year}"
41
- end
12
+ def number_of_weeks
13
+ options.fetch(:number_of_weeks, 1)
14
+ end
42
15
  end
43
16
  end
44
-
@@ -19,4 +19,5 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  s.add_dependency 'rails', '>= 3.0'
22
+ s.add_development_dependency 'rspec'
22
23
  end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+ require 'simple_calendar/calendar'
3
+
4
+ class ViewContext
5
+ attr_accessor :start_date
6
+
7
+ def initialize(start_date=nil)
8
+ @start_date = start_date
9
+ end
10
+
11
+ def params
12
+ if @start_date.present?
13
+ {start_date: @start_date}
14
+ else
15
+ {}
16
+ end
17
+ end
18
+ end
19
+
20
+ describe SimpleCalendar::Calendar do
21
+ let(:calendar) { SimpleCalendar::Calendar.new(nil) }
22
+
23
+ it 'renders a partial with the same name as the class' do
24
+ expect(calendar.send(:partial_name)).to eq("simple_calendar/calendar")
25
+ end
26
+
27
+ context 'event sorting attribute' do
28
+ it 'has start_time as the default attribute' do
29
+ expect(calendar.send(:attribute)).to eq(:start_time)
30
+ end
31
+
32
+ it 'allows you to override the default attribute' do
33
+ expect(SimpleCalendar::Calendar.new(nil, attribute: :starts_at).send(:attribute)).to eq(:starts_at)
34
+ end
35
+ end
36
+
37
+ describe "#sorted_events" do
38
+ it 'converts an array of events to a hash sorted by days'
39
+ end
40
+
41
+ describe "#start_date" do
42
+ it "defaults to today's date" do
43
+ view_context = ViewContext.new()
44
+ calendar = SimpleCalendar::Calendar.new(view_context)
45
+ expect(calendar.send(:start_date)).to eq(Date.today)
46
+ end
47
+
48
+ it "uses the params start_date to override" do
49
+ view_context = ViewContext.new(Date.yesterday)
50
+ calendar = SimpleCalendar::Calendar.new(view_context)
51
+ expect(calendar.send(:start_date)).to eq(Date.yesterday)
52
+ end
53
+ end
54
+
55
+ it 'has a param that determines the start date of the calendar'
56
+ it 'generates a default date if no start date is present'
57
+ it 'has a range of dates'
58
+
59
+ it 'can split the range of dates into weeks'
60
+ it 'has a title'
61
+ it 'has a next view link'
62
+ it 'has a previous view link'
63
+
64
+ it 'accepts an array of events'
65
+ it 'sorts the events'
66
+ it 'yields the events for each day'
67
+
68
+ it "doesn't crash when an event has a nil start_time"
69
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+ require 'simple_calendar/month_calendar'
3
+
4
+ describe SimpleCalendar::MonthCalendar do
5
+ it 'renders a full calendar month'
6
+ it 'render the days of next and previous months on the edges of the calendar'
7
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'rails'
3
+
4
+ describe SimpleCalendar do
5
+ it 'has a version number' do
6
+ expect(SimpleCalendar::VERSION).not_to be nil
7
+ end
8
+ end
@@ -0,0 +1,96 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ RSpec.configure do |config|
20
+ # rspec-expectations config goes here. You can use an alternate
21
+ # assertion/expectation library such as wrong or the stdlib/minitest
22
+ # assertions if you prefer.
23
+ config.expect_with :rspec do |expectations|
24
+ # This option will default to `true` in RSpec 4. It makes the `description`
25
+ # and `failure_message` of custom matchers include text for helper methods
26
+ # defined using `chain`, e.g.:
27
+ # be_bigger_than(2).and_smaller_than(4).description
28
+ # # => "be bigger than 2 and smaller than 4"
29
+ # ...rather than:
30
+ # # => "be bigger than 2"
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ # rspec-mocks config goes here. You can use an alternate test double
35
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended, and will default to
39
+ # `true` in RSpec 4.
40
+ mocks.verify_partial_doubles = true
41
+ end
42
+
43
+ # The settings below are suggested to provide a good initial experience
44
+ # with RSpec, but feel free to customize to your heart's content.
45
+ =begin
46
+ # These two settings work together to allow you to limit a spec run
47
+ # to individual examples or groups you care about by tagging them with
48
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
49
+ # get run.
50
+ config.filter_run :focus
51
+ config.run_all_when_everything_filtered = true
52
+
53
+ # Allows RSpec to persist some state between runs in order to support
54
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
55
+ # you configure your source control system to ignore this file.
56
+ config.example_status_persistence_file_path = "spec/examples.txt"
57
+
58
+ # Limits the available syntax to the non-monkey patched syntax that is
59
+ # recommended. For more details, see:
60
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
61
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
62
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
63
+ config.disable_monkey_patching!
64
+
65
+ # This setting enables warnings. It's recommended, but in some cases may
66
+ # be too noisy due to issues in dependencies.
67
+ config.warnings = true
68
+
69
+ # Many RSpec users commonly either run the entire suite or an individual
70
+ # file, and it's useful to allow more verbose output when running an
71
+ # individual spec file.
72
+ if config.files_to_run.one?
73
+ # Use the documentation formatter for detailed output,
74
+ # unless a formatter has already been configured
75
+ # (e.g. via a command-line flag).
76
+ config.default_formatter = 'doc'
77
+ end
78
+
79
+ # Print the 10 slowest examples and example groups at the
80
+ # end of the spec run, to help surface which specs are running
81
+ # particularly slow.
82
+ config.profile_examples = 10
83
+
84
+ # Run specs in random order to surface order dependencies. If you find an
85
+ # order dependency and want to debug it, you can fix the order by providing
86
+ # the seed, which is printed after each run.
87
+ # --seed 1234
88
+ config.order = :random
89
+
90
+ # Seed global randomization in this process using the `--seed` CLI option.
91
+ # Setting this allows you to use `--seed` to deterministically reproduce
92
+ # test failures related to randomization by passing the same `--seed` value
93
+ # as the one that triggered the failure.
94
+ Kernel.srand config.seed
95
+ =end
96
+ end
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+ require "generators/simple_calendar/views_generator"
3
+
4
+ describe SimpleCalendar::Generators::ViewsGenerator do
5
+ it 'copies the files to app/views/simple_calendar'
6
+ it 'verifies the content'
7
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_calendar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.10
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-06 00:00:00.000000000 Z
11
+ date: 2015-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,27 +24,54 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  description: A simple Rails 3 and Rails 4 calendar
28
42
  email:
29
43
  - excid3@gmail.com
30
- executables: []
44
+ executables:
45
+ - console
46
+ - setup
31
47
  extensions: []
32
48
  extra_rdoc_files: []
33
49
  files:
34
50
  - ".gitignore"
35
51
  - ".rspec"
52
+ - ".travis.yml"
36
53
  - Gemfile
37
54
  - README.md
38
55
  - Rakefile
56
+ - app/views/simple_calendar/_calendar.html.erb
57
+ - app/views/simple_calendar/_month_calendar.html.erb
58
+ - app/views/simple_calendar/_week_calendar.html.erb
59
+ - bin/console
60
+ - bin/setup
61
+ - lib/generators/simple_calendar/views_generator.rb
39
62
  - lib/simple_calendar.rb
40
63
  - lib/simple_calendar/calendar.rb
41
- - lib/simple_calendar/model_additions.rb
42
64
  - lib/simple_calendar/month_calendar.rb
43
65
  - lib/simple_calendar/railtie.rb
44
66
  - lib/simple_calendar/version.rb
45
67
  - lib/simple_calendar/view_helpers.rb
46
68
  - lib/simple_calendar/week_calendar.rb
47
69
  - simple_calendar.gemspec
70
+ - spec/calendar_spec.rb
71
+ - spec/calendars/month_calendar_spec.rb
72
+ - spec/simple_calendar_spec.rb
73
+ - spec/spec_helper.rb
74
+ - spec/views_generators_spec.rb
48
75
  homepage: https://github.com/excid3/simple_calendar
49
76
  licenses: []
50
77
  metadata: {}
@@ -64,8 +91,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
91
  version: '0'
65
92
  requirements: []
66
93
  rubyforge_project: simple_calendar
67
- rubygems_version: 2.2.2
94
+ rubygems_version: 2.4.5.1
68
95
  signing_key:
69
96
  specification_version: 4
70
97
  summary: A simple Rails 3 and Rails 4 calendar
71
- test_files: []
98
+ test_files:
99
+ - spec/calendar_spec.rb
100
+ - spec/calendars/month_calendar_spec.rb
101
+ - spec/simple_calendar_spec.rb
102
+ - spec/spec_helper.rb
103
+ - spec/views_generators_spec.rb
@@ -1,16 +0,0 @@
1
- module SimpleCalendar
2
- module ModelAdditions
3
- def has_calendar(options={})
4
- config = { :attribute => :starts_at }
5
-
6
- # Override default config
7
- config.update(options) if options.is_a?(Hash)
8
-
9
- class_eval <<-EOV
10
- def simple_calendar_start_time
11
- #{config[:attribute]}
12
- end
13
- EOV
14
- end
15
- end
16
- end