holiday_list 0.0.1
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 +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +46 -0
- data/Rakefile +47 -0
- data/holiday_list.gemspec +33 -0
- data/lib/holiday_list.rb +61 -0
- data/lib/holiday_list/configuration.rb +11 -0
- data/lib/holiday_list/google_calendar_request_string.rb +39 -0
- data/lib/holiday_list/params.rb +60 -0
- data/lib/holiday_list/request_exception.rb +12 -0
- data/lib/holiday_list/version.rb +3 -0
- data/spec/holiday_list/configuration_spec.rb +40 -0
- data/spec/holiday_list/google_calendar_request_string_spec.rb +47 -0
- data/spec/holiday_list/params_spec.rb +107 -0
- data/spec/holiday_list/request_exception_spec.rb +41 -0
- data/spec/holiday_list_spec.rb +83 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/vcr/cassettes/01_29_2014_list.yml +640 -0
- data/spec/vcr/cassettes/bad_google_access_key.yml +59 -0
- metadata +227 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a4897c6155de7143716fe7b0d4d6745fe3c8aef5
|
4
|
+
data.tar.gz: e4664e1f521f868dda8ad81a9b5bf319a8c4e649
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 11209b133401cb0ec369a83500ea0cb44bca517f307082bf8092afcbb93dcf9ca71b98127f0a8117a14d036f1999d5366100a7e8b0e2e0175b709031391ee361
|
7
|
+
data.tar.gz: b7f35acc8298d84e5d57043f48d66d0028361a7f273902de7ba18ee7fcb0d2d2f77c8cb4cbc60becc78d4b522531806da9e1251f0164e3aeda00bd54cca7392c
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
- 2.1.0
|
6
|
+
- jruby-19mode
|
7
|
+
- ruby-head
|
8
|
+
- jruby-head
|
9
|
+
matrix:
|
10
|
+
fast_finish: true
|
11
|
+
allow_failures:
|
12
|
+
- rvm: jruby-head
|
13
|
+
# uncomment this line if your project needs to run something other than `rake`:
|
14
|
+
# script: bundle exec rspec spec
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ben Hicks
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Holiday::List
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'holiday_list'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install holiday_list
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
30
|
+
|
31
|
+
## Todo
|
32
|
+
|
33
|
+
- initializer
|
34
|
+
- Travis ci build
|
35
|
+
- Code complete
|
36
|
+
- Test coverage
|
37
|
+
- rename?
|
38
|
+
- clean up readme
|
39
|
+
- ~~replace httparty with faraday~~
|
40
|
+
|
41
|
+
### Its nice to want things
|
42
|
+
|
43
|
+
- connect to more google public calendars
|
44
|
+
- connect to private google calendars
|
45
|
+
- connect to non google calendars
|
46
|
+
- store data in redis
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core"
|
3
|
+
require "rspec/core/rake_task"
|
4
|
+
require "dotenv"
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
task :test => :spec
|
10
|
+
|
11
|
+
desc 'Launch irb with holiday_list required'
|
12
|
+
task :console do
|
13
|
+
require 'irb'
|
14
|
+
require 'irb/completion'
|
15
|
+
require 'holiday_list'
|
16
|
+
ARGV.clear
|
17
|
+
IRB.start
|
18
|
+
end
|
19
|
+
|
20
|
+
namespace :spec do
|
21
|
+
desc 'Run RSpec, re-recording VCR cassettes'
|
22
|
+
task :rerecord do
|
23
|
+
Dotenv.load
|
24
|
+
|
25
|
+
ENV['RERECORD'] = 'true'
|
26
|
+
Rake::Task['spec'].execute
|
27
|
+
Rake::Task['spec:scrub'].execute
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Scrub access key tokens'
|
31
|
+
task :scrub do
|
32
|
+
Dotenv.load
|
33
|
+
|
34
|
+
FileList.new('spec/vcr/cassettes/*.yml').each do |file|
|
35
|
+
next unless key = ENV['GOOGLE_ACCESS_KEY']
|
36
|
+
|
37
|
+
modified_file = File.open(file).read.gsub(/#{key}/, 'A_GOOD_KEY')
|
38
|
+
|
39
|
+
File.open(file, 'w') do |out|
|
40
|
+
out << modified_file
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# TODO: add git pre-commit hook to prevent users from checking in
|
47
|
+
# GOOGLE_ACCESS_KEY in VCR cassettes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'holiday_list/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "holiday_list"
|
8
|
+
spec.version = HolidayList::VERSION
|
9
|
+
spec.authors = ["Ben Hicks"]
|
10
|
+
spec.email = ["benkhicks@gmail.com"]
|
11
|
+
spec.description = %q{HolidayList}
|
12
|
+
spec.summary = %q{Connects to google calendar and retrieves holidays}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "faraday"
|
22
|
+
spec.add_runtime_dependency "activesupport"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "vcr"
|
28
|
+
spec.add_development_dependency "webmock", "~> 1.15.0"
|
29
|
+
spec.add_development_dependency "timecop"
|
30
|
+
spec.add_development_dependency "rubocop"
|
31
|
+
spec.add_development_dependency "dotenv"
|
32
|
+
spec.add_development_dependency "pry"
|
33
|
+
end
|
data/lib/holiday_list.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'holiday_list/version'
|
2
|
+
require 'holiday_list/configuration'
|
3
|
+
require 'holiday_list/google_calendar_request_string'
|
4
|
+
require 'holiday_list/request_exception'
|
5
|
+
require 'faraday'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
# MyList:
|
9
|
+
# Used to generate a list of upcoming holidays
|
10
|
+
class HolidayList
|
11
|
+
include RequestException
|
12
|
+
|
13
|
+
def self.list
|
14
|
+
new.to_a
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.configure
|
18
|
+
yield configuration
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.configuration
|
22
|
+
@configuration ||= Configuration.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@request_string = GoogleCalendarRequestString.new self.class.configuration
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_a
|
30
|
+
argument_error! if invalid_request?
|
31
|
+
|
32
|
+
json_response['items'].map do |item|
|
33
|
+
{
|
34
|
+
summary: item['summary'],
|
35
|
+
start_date: Date.parse(item['start']['date']),
|
36
|
+
etag: item['etag']
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# TODO: methods below are only used in #to_a, and are prime candidates for an extract class refactoring
|
44
|
+
def invalid_request?
|
45
|
+
return false unless response_error
|
46
|
+
response_error['code'] == 400
|
47
|
+
end
|
48
|
+
|
49
|
+
def response
|
50
|
+
conn = Faraday.new url: GoogleCalendarRequestString.url_base
|
51
|
+
conn.get @request_string.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def json_response
|
55
|
+
@json_response ||= JSON.parse(response.body)
|
56
|
+
end
|
57
|
+
|
58
|
+
def response_error
|
59
|
+
json_response['error']
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'holiday_list/params'
|
2
|
+
require 'holiday_list/request_exception'
|
3
|
+
|
4
|
+
class HolidayList
|
5
|
+
# GoogleCalendarRequestString:
|
6
|
+
# Generates the google calendar api request string
|
7
|
+
class GoogleCalendarRequestString
|
8
|
+
include RequestException
|
9
|
+
|
10
|
+
# TODO: address these items:
|
11
|
+
# - make class more extensible
|
12
|
+
# - rename class, redundat String, and is it really a 'Request'?
|
13
|
+
# - don't think 'to_str' is working. should work like:
|
14
|
+
# gcrs = GoogleCalendarRequestString.new(configuration)
|
15
|
+
# conn.get gcrs # '/calendar/v3/calendars/12345/events?time_min=yesterday'
|
16
|
+
def self.url_base
|
17
|
+
'https://www.googleapis.com'
|
18
|
+
end
|
19
|
+
|
20
|
+
def url_path
|
21
|
+
'/calendar/v3/calendars'
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :id, :params
|
25
|
+
|
26
|
+
def initialize(configuration)
|
27
|
+
argument_error! unless configuration.configured?
|
28
|
+
|
29
|
+
key = configuration.key
|
30
|
+
@id = configuration.id
|
31
|
+
|
32
|
+
@params = Params.new(key)
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
"#{url_path}/#{id}/events?#{params}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'active_support/core_ext/object/to_query'
|
2
|
+
require 'active_support/core_ext/date_time/calculations'
|
3
|
+
|
4
|
+
class HolidayList
|
5
|
+
# Params:
|
6
|
+
# Munges google calendar api request parameters
|
7
|
+
class Params
|
8
|
+
attr_reader :key
|
9
|
+
|
10
|
+
def initialize(key, time_options = {})
|
11
|
+
@key = key
|
12
|
+
@options = time_options
|
13
|
+
|
14
|
+
validate_options!
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
params_hash.to_query
|
19
|
+
end
|
20
|
+
|
21
|
+
def params_hash
|
22
|
+
{
|
23
|
+
key: key,
|
24
|
+
orderBy: order_by,
|
25
|
+
singleEvents: single_events,
|
26
|
+
timeMin: time_min,
|
27
|
+
timeMax: time_max
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def time_min
|
34
|
+
@time_min ||= @options.fetch('start') { DateTime.now.new_offset(0) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def time_max
|
38
|
+
@time_max ||= @options.fetch('stop') { DateTime.now.next_year.new_offset(0) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def order_by
|
42
|
+
'startTime'
|
43
|
+
end
|
44
|
+
|
45
|
+
def single_events
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_options!
|
50
|
+
message = 'Start and end dates must be valid DateTime objects that'\
|
51
|
+
' occur sequentially'
|
52
|
+
|
53
|
+
fail ArgumentError, message if [time_min, time_max].any? do |time|
|
54
|
+
time.class != DateTime
|
55
|
+
end
|
56
|
+
|
57
|
+
fail ArgumentError, message if time_min > time_max
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class HolidayList
|
2
|
+
# RequestException
|
3
|
+
# Provides convenience methods for common exceptions
|
4
|
+
module RequestException
|
5
|
+
private
|
6
|
+
|
7
|
+
def argument_error!(message = nil)
|
8
|
+
message ||= 'A valid google access key is required'
|
9
|
+
fail ArgumentError, message
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HolidayList::Configuration do
|
4
|
+
subject { HolidayList::Configuration.new }
|
5
|
+
|
6
|
+
describe '#configured?' do
|
7
|
+
shared_examples 'failing configuration' do
|
8
|
+
it 'is false' do
|
9
|
+
expect(subject.configured?).to be false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'without a key' do
|
14
|
+
before { subject.id = 'id' }
|
15
|
+
|
16
|
+
it_behaves_like 'failing configuration'
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'without an id' do
|
20
|
+
before { subject.key = 'key' }
|
21
|
+
|
22
|
+
it_behaves_like 'failing configuration'
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'without a key or id' do
|
26
|
+
it_behaves_like 'failing configuration'
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with a key and id' do
|
30
|
+
before do
|
31
|
+
subject.key = 'key'
|
32
|
+
subject.id = 'id'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'is true' do
|
36
|
+
expect(subject.configured?).to be true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HolidayList::GoogleCalendarRequestString do
|
4
|
+
let(:configuration) do
|
5
|
+
double('Configuration', configured?: true).as_null_object
|
6
|
+
end
|
7
|
+
|
8
|
+
subject { HolidayList::GoogleCalendarRequestString.new(configuration) }
|
9
|
+
|
10
|
+
describe '#new' do
|
11
|
+
context 'configured' do
|
12
|
+
before do
|
13
|
+
HolidayList::GoogleCalendarRequestString
|
14
|
+
.any_instance.should_not_receive(:argument_error!)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'creates a new object' do
|
18
|
+
subject
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'not configured' do
|
23
|
+
before do
|
24
|
+
configuration.stub(:configured?).and_return(false)
|
25
|
+
HolidayList::GoogleCalendarRequestString
|
26
|
+
.any_instance.should_receive(:argument_error!)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'calls argument_error!' do
|
30
|
+
subject
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#to_s' do
|
36
|
+
let(:params) { double('Params') }
|
37
|
+
|
38
|
+
before do
|
39
|
+
HolidayList::Params.stub(:new).and_return(params)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'uses Params' do
|
43
|
+
params.should_receive(:to_s)
|
44
|
+
subject.to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|