holiday_list 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .env
@@ -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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in holiday_list.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -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
@@ -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,11 @@
1
+ class HolidayList
2
+ # Configuration:
3
+ # Used to persist access token configurations
4
+ class Configuration
5
+ attr_accessor :id, :key
6
+
7
+ def configured?
8
+ !id.nil? && !key.nil?
9
+ end
10
+ end
11
+ 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,3 @@
1
+ class HolidayList # rubocop:disable Documentation
2
+ VERSION = '0.0.1'
3
+ 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