simple_calendar 1.1.10 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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