vrbo 1.1.0 → 2.0.1

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: 1e7a1740a7b58843bfc500c961fc306a65062547
4
- data.tar.gz: fb2f0f9d024bd079b6e70105c84d304eff56737a
3
+ metadata.gz: 292464634aa7ba985ef18252adaf0cfc66554524
4
+ data.tar.gz: b3bd501182bb1ea02ac9d35bee0778013c2a3a74
5
5
  SHA512:
6
- metadata.gz: ef04241e73ebb3c63bd1ce2010317a5842d83c33d69a1ff619ac244a5b2bf7a9d79d933bc2e5ba5b6ec27876c1a99641e5426a1de0a2f6f3187886d12d749d97
7
- data.tar.gz: b57dba1d7a5c60a32a62f591ce33a6c3536849dbc49cc556cec460031649075cf65fc0a2ed9b49de653f914c92e11f3bce3dc7ea6e7564ee4d359f79b1bd6c30
6
+ metadata.gz: 4815b659820d192c4f4ef80d05bb3c87b5afdc5ace663ec6fd4449dace169b4862462d6ec7a22aa9179e54488e5644d99274eb582e1ade9b840340b7fee01df6
7
+ data.tar.gz: df2a0fee297894982bcb946fb6cbc12579eb12014cb1e0fb21a709f486efdf2ffa0fb62085fe737c9407cc14d1653593874a723180c5ed332d389c0b2428d173
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/README.md CHANGED
@@ -5,37 +5,28 @@ scrape this calendar: [http://www.vrbo.com/293021/calendar](http://www.vrbo.com/
5
5
 
6
6
  ## Installation
7
7
 
8
- Add this line to your application's Gemfile:
9
-
10
- gem 'vrbo'
11
-
12
- And then execute:
13
-
14
- $ bundle
15
-
16
- Or install it yourself as:
17
-
18
8
  $ gem install vrbo
19
9
 
20
10
  ## Usage
21
11
 
22
12
  If you're just working with one calendar, then you can specify the VRBO calendar id in an initializer:
23
13
 
24
- # config/initializers/vrbo_calendar.rb
25
-
26
- VRBO.configure do |config|
27
- config.calendar_id = 293021
28
- end
14
+ ```ruby
15
+ # config/initializers/vrbo.rb
16
+ VRBO.configure do |config|
17
+ config.calendar_id = 293021
18
+ end
19
+ ```
29
20
 
30
21
  Then to lookup available dates and see if a date range is available:
31
22
 
32
- calendar = VRBO::Calendar.new
33
- calendar.find_available_dates
34
- calendar.available?(Date.today, Date.tomorrow)
35
- #=> true/false
36
-
37
- These two methods are also available as class methods, however `available?` will then need an array of dates
38
- as the third parameter.
23
+ ```ruby
24
+ calendar = VRBO::Calendar.new
25
+ calendar.available?(Date.today, Date.today + 5)
26
+ #=> true/false
27
+ calendar.available_dates
28
+ #=> ["2015-11-03", "2015-11-04", "2015-11-05", ...]
29
+ ```
39
30
 
40
31
  ## Contributing
41
32
 
data/Rakefile CHANGED
@@ -1,9 +1,8 @@
1
- require 'bundler/gem_tasks'
2
- require 'rake'
3
- require 'rake/testtask'
1
+ require 'rspec/core/rake_task'
4
2
 
5
- task default: :test
6
-
7
- Rake::TestTask.new do |t|
8
- t.pattern = 'test/**/*_test.rb'
3
+ RSpec::Core::RakeTask.new(:spec) do |spec|
4
+ spec.pattern = 'spec/**/*_spec.rb'
9
5
  end
6
+
7
+ desc 'Run specs'
8
+ task default: :spec
data/lib/vrbo.rb CHANGED
@@ -2,14 +2,10 @@ require 'date'
2
2
  require 'uri'
3
3
  require 'net/https'
4
4
  require 'mechanize'
5
-
6
5
  require 'vrbo/version'
7
- require 'vrbo/configuration'
8
- require 'vrbo/availability'
9
- require 'vrbo/calendar'
10
6
 
11
7
  module VRBO
12
- extend self
8
+ module_function
13
9
 
14
10
  def configure
15
11
  yield config
@@ -23,4 +19,7 @@ module VRBO
23
19
  @config = nil
24
20
  end
25
21
 
26
- end
22
+ autoload :Configuration, 'vrbo/configuration'
23
+ autoload :Availability, 'vrbo/availability'
24
+ autoload :Calendar, 'vrbo/calendar'
25
+ end
@@ -28,4 +28,4 @@ module VRBO
28
28
  count
29
29
  end
30
30
  end
31
- end
31
+ end
data/lib/vrbo/calendar.rb CHANGED
@@ -1,19 +1,21 @@
1
- require 'vrbo/class_methods'
2
-
3
1
  module VRBO
4
2
  class Calendar
5
- extend ClassMethods
6
3
 
7
- attr_accessor :id, :available_dates, :days
4
+ attr_accessor :id, :days
8
5
 
9
6
  def initialize(calendar_id = nil)
10
7
  @id = calendar_id || VRBO.config.calendar_id
11
8
  @days = {}
12
- @available_dates = []
9
+ @available_dates = nil
10
+ end
11
+
12
+ def available_dates
13
+ @available_dates ||= Date.today.upto(Date.today + 365).map { |date| date_if_available(date) }.compact
13
14
  end
14
15
 
15
- def available?(arrival, depart, my_dates = nil)
16
- dates = my_dates || available_dates
16
+ # @description exclusive, drops day from departure because bookings usually go on per nightly
17
+ def available?(arrival, depart, dates = nil)
18
+ dates = dates || available_dates
17
19
  available = dates.any?
18
20
  arrival.upto(depart - 1).each do |date|
19
21
  available = false unless dates.include?(date.to_s)
@@ -21,22 +23,17 @@ module VRBO
21
23
  available
22
24
  end
23
25
 
24
- def find_available_dates
25
- today = Date.today
26
- @available_dates = today.upto(today + 365).map { |date| date_if_available(date) }.compact
27
- end
28
-
29
26
  def url(protocol = 'http')
30
27
  if id
31
28
  "#{protocol}://www.vrbo.com/#{id}/calendar"
32
29
  else
33
- raise ArgumentError, 'You must provide a calendar id'
30
+ fail ArgumentError, 'calendar_id is required! You can initialize with a calendar_id or configure the module VRBO'
34
31
  end
35
32
  end
36
33
 
37
- alias :find_all_available_dates :find_available_dates
38
-
39
- private
34
+ #
35
+ # Private
36
+ #
40
37
 
41
38
  def date_if_available(date)
42
39
  m = date.month.to_s
@@ -45,24 +42,28 @@ module VRBO
45
42
  end
46
43
 
47
44
  def collect_days_for_month(date)
48
- scrape_table_for(date).map { |cell| cell.children.to_s.strip }
45
+ table = calendar.search('.cal-month').at("//b[contains(text(), '#{date.strftime('%B %Y')}')]/following-sibling::table")
46
+ table.search('td:not(.strike)').map { |cell| cell.children.to_s.strip }
47
+ rescue => e
48
+ puts e.class
49
+ puts e.message
50
+ puts e.backtrace
51
+ puts calendar: calendar
49
52
  end
50
53
 
51
- def scrape_table_for(date)
52
- calendar.search('.cal-month').at(table_xpath(date)).search('td:not(.strike)')
53
- end
54
+ # , retries: 10
55
+ # collect_days_for_month(date, retries: retries - 1) if table.nil? && retries > 0
54
56
 
55
57
  def calendar
56
- @calendar ||= agent.get(url)
57
- end
58
-
59
- def agent
60
- @agent ||= Mechanize.new
61
- end
62
-
63
- # e.g. March 2014
64
- def table_xpath(date)
65
- "//b[contains(text(), '#{date.strftime('%B %Y')}')]/following-sibling::table"
58
+ @calendar ||= Mechanize.start do |agent|
59
+ agent.open_timeout = 10
60
+ agent.read_timeout = 10
61
+ agent.follow_meta_refresh = true
62
+ agent.keep_alive = true
63
+ agent.max_history = 1
64
+ agent.user_agent_alias = 'Mac Safari'
65
+ agent.get(url).parser
66
+ end
66
67
  end
67
68
  end
68
- end
69
+ end
@@ -2,4 +2,4 @@ module VRBO
2
2
  class Configuration
3
3
  attr_accessor :calendar_id
4
4
  end
5
- end
5
+ end
data/lib/vrbo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module VRBO
2
- VERSION = '1.1.0'
2
+ VERSION = '2.0.1'
3
3
  end
@@ -0,0 +1,247 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://www.vrbo.com/293021/calendar
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip,deflate,identity
12
+ Accept:
13
+ - '*/*'
14
+ User-Agent:
15
+ - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML,
16
+ like Gecko) Version/5.1.1 Safari/534.51.22
17
+ Accept-Charset:
18
+ - ISO-8859-1,utf-8;q=0.7,*;q=0.7
19
+ Accept-Language:
20
+ - en-us,en;q=0.5
21
+ Host:
22
+ - www.vrbo.com
23
+ Connection:
24
+ - keep-alive
25
+ Keep-Alive:
26
+ - 300
27
+ response:
28
+ status:
29
+ code: 200
30
+ message: OK
31
+ headers:
32
+ Server:
33
+ - nginx
34
+ Date:
35
+ - Wed, 04 Nov 2015 02:44:58 GMT
36
+ Content-Type:
37
+ - text/html; charset=utf-8
38
+ Transfer-Encoding:
39
+ - chunked
40
+ Connection:
41
+ - keep-alive
42
+ Vary:
43
+ - Accept-Encoding
44
+ Cache-Control:
45
+ - private
46
+ Set-Cookie:
47
+ - PpcCampaign=; path=/
48
+ - __RequestVerificationToken=GUOOk32Gm_UNUeaktYp8m1TJSb_b-wgIv-Q_7yYiK_ZzqQmjAt95jnYg6hOTlPsTJ92AUeoQbt7M5tWC_s9cH6IeO7g1;
49
+ path=/; HttpOnly
50
+ - hal=ga=0&si=1&ui=0&vi=1&pr=1; expires=Thu, 05-Nov-2015 02:44:58 GMT; path=/
51
+ - has=311c654d-3316-44e4-8a17-854a00afc4a8; expires=Thu, 05-Nov-2015 02:44:58
52
+ GMT; path=/
53
+ - hav=196004f3-753a-410d-96df-7dde37be9bf0; expires=Sat, 04-Nov-2017 01:44:58
54
+ GMT; path=/
55
+ - pr_buckets=buckets=vbr%3a1%2cvbq%3a0%2cvbp%3a1%2cvbl%3a1%2cvbz%3a0%2cvbw%3a1%2cvbaa%3a0%2cvbv%3a1%2cvbu%3a0%2cvrbobceheader%3a0%2cvba%3a1%2cvbc%3a1%2cvbg%3a0%2cvbi%3a0%2cvbk%3a0;
56
+ expires=Wed, 04-Nov-2015 02:49:58 GMT; path=/
57
+ - pr_groups=forceGroups=; expires=Fri, 04-Dec-2015 02:44:58 GMT; path=/
58
+ X-Powered-By:
59
+ - ASP.NET
60
+ Content-Encoding:
61
+ - gzip
62
+ body:
63
+ encoding: ASCII-8BIT
64
+ string: !binary |-
65
+ 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
245
+ http_version:
246
+ recorded_at: Wed, 04 Nov 2015 02:44:59 GMT
247
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,105 @@
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
+ require 'vcr'
18
+ require 'rspec/its'
19
+
20
+ VCR.configure do |config|
21
+ config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
22
+ config.hook_into :webmock
23
+ end
24
+
25
+ require 'vrbo'
26
+
27
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
28
+ RSpec.configure do |config|
29
+ # rspec-expectations config goes here. You can use an alternate
30
+ # assertion/expectation library such as wrong or the stdlib/minitest
31
+ # assertions if you prefer.
32
+ config.expect_with :rspec do |expectations|
33
+ # This option will default to `true` in RSpec 4. It makes the `description`
34
+ # and `failure_message` of custom matchers include text for helper methods
35
+ # defined using `chain`, e.g.:
36
+ # be_bigger_than(2).and_smaller_than(4).description
37
+ # # => "be bigger than 2 and smaller than 4"
38
+ # ...rather than:
39
+ # # => "be bigger than 2"
40
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
41
+ end
42
+
43
+ # rspec-mocks config goes here. You can use an alternate test double
44
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
45
+ config.mock_with :rspec do |mocks|
46
+ # Prevents you from mocking or stubbing a method that does not exist on
47
+ # a real object. This is generally recommended, and will default to
48
+ # `true` in RSpec 4.
49
+ mocks.verify_partial_doubles = true
50
+ end
51
+
52
+ # The settings below are suggested to provide a good initial experience
53
+ # with RSpec, but feel free to customize to your heart's content.
54
+ =begin
55
+ # These two settings work together to allow you to limit a spec run
56
+ # to individual examples or groups you care about by tagging them with
57
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
58
+ # get run.
59
+ config.filter_run :focus
60
+ config.run_all_when_everything_filtered = true
61
+
62
+ # Allows RSpec to persist some state between runs in order to support
63
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
64
+ # you configure your source control system to ignore this file.
65
+ config.example_status_persistence_file_path = "spec/examples.txt"
66
+
67
+ # Limits the available syntax to the non-monkey patched syntax that is
68
+ # recommended. For more details, see:
69
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
70
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
71
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
72
+ config.disable_monkey_patching!
73
+
74
+ # This setting enables warnings. It's recommended, but in some cases may
75
+ # be too noisy due to issues in dependencies.
76
+ config.warnings = true
77
+
78
+ # Many RSpec users commonly either run the entire suite or an individual
79
+ # file, and it's useful to allow more verbose output when running an
80
+ # individual spec file.
81
+ if config.files_to_run.one?
82
+ # Use the documentation formatter for detailed output,
83
+ # unless a formatter has already been configured
84
+ # (e.g. via a command-line flag).
85
+ config.default_formatter = 'doc'
86
+ end
87
+
88
+ # Print the 10 slowest examples and example groups at the
89
+ # end of the spec run, to help surface which specs are running
90
+ # particularly slow.
91
+ config.profile_examples = 10
92
+
93
+ # Run specs in random order to surface order dependencies. If you find an
94
+ # order dependency and want to debug it, you can fix the order by providing
95
+ # the seed, which is printed after each run.
96
+ # --seed 1234
97
+ config.order = :random
98
+
99
+ # Seed global randomization in this process using the `--seed` CLI option.
100
+ # Setting this allows you to use `--seed` to deterministically reproduce
101
+ # test failures related to randomization by passing the same `--seed` value
102
+ # as the one that triggered the failure.
103
+ Kernel.srand config.seed
104
+ =end
105
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe VRBO::Availability do
4
+ let(:dates) { %w[2015-12-13 2015-12-14 2015-12-15 2015-12-16 2015-12-17 2015-12-20] }
5
+
6
+ subject { described_class.new(dates) }
7
+
8
+ describe '#initialize' do
9
+ context 'when given an array of dates strings' do
10
+ it 'assigns @start_at to the date parsed first item' do
11
+ expect(subject.start_at).to eq Date.parse('2015-12-13')
12
+ end
13
+
14
+ it 'removes the first item from the array (mutation)' do
15
+ expect {
16
+ subject.start_at
17
+ }.to change(dates, :length).from(6).to(5)
18
+ end
19
+
20
+ it 'assigns the all but the first items in -dates- to @dates' do
21
+ expect(subject.dates).to eq %w[2015-12-14 2015-12-15 2015-12-16 2015-12-17 2015-12-20]
22
+ end
23
+ end
24
+
25
+ context 'when given nil' do
26
+ let(:dates) { nil }
27
+
28
+ it 'assigns @start_at to today' do
29
+ expect(subject.start_at).to eq Date.today
30
+ end
31
+ end
32
+ end
33
+
34
+ describe '#duration' do
35
+ context 'when given a list of dates in ascending order' do
36
+ it 'returns the length of the first sequence' do
37
+ expect(subject.duration).to eq 5
38
+ end
39
+
40
+ context 'when dates are sequential' do
41
+ let(:dates) { %w[2015-12-05 2015-12-07 2015-12-10] }
42
+
43
+ it 'returns one' do
44
+ expect(subject.duration).to eq 1
45
+ end
46
+ end
47
+ end
48
+
49
+ context 'when no dates are given' do
50
+ let(:dates) { [] }
51
+
52
+ it 'returns one' do
53
+ expect(subject.duration).to eq 1
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+
3
+ describe VRBO::Calendar do
4
+ let(:calendar_id) { '293021' }
5
+
6
+ subject { described_class.new calendar_id }
7
+
8
+ describe '#initialize' do
9
+ its(:id) { should == calendar_id }
10
+ its(:days) { should == {} }
11
+
12
+ context 'when no -calendar_id given' do
13
+ let(:calendar_id) { nil }
14
+
15
+ before do
16
+ VRBO.configure do |config|
17
+ config.calendar_id = calendar_id
18
+ end
19
+ end
20
+
21
+ it 'uses the configuration value' do
22
+ expect(subject.id).to eq calendar_id
23
+ end
24
+
25
+ after do
26
+ VRBO.reset_config
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#available_dates' do
32
+ it 'returns the available dates for the next year' do
33
+ VCR.use_cassette(calendar_id) do
34
+ expect(subject.available_dates.length).to eq 284
35
+ expect(subject.available_dates).to eq %w[2015-11-08 2015-11-09 2015-11-22 2015-11-23 2015-11-24 2015-11-25 2015-11-26 2015-11-29 2015-11-30 2015-12-10 2015-12-13 2015-12-14 2015-12-15 2015-12-16 2015-12-17 2015-12-18 2015-12-22 2015-12-23 2015-12-24 2015-12-31 2016-01-01 2016-01-05 2016-01-06 2016-01-07 2016-01-08 2016-01-11 2016-01-12 2016-01-19 2016-01-20 2016-01-21 2016-01-22 2016-01-23 2016-01-24 2016-01-25 2016-01-26 2016-01-27 2016-01-28 2016-01-29 2016-01-30 2016-01-31 2016-02-01 2016-02-06 2016-02-07 2016-02-08 2016-02-09 2016-02-10 2016-02-11 2016-02-20 2016-02-21 2016-02-25 2016-03-02 2016-03-03 2016-03-04 2016-03-05 2016-03-06 2016-03-07 2016-03-08 2016-03-09 2016-03-10 2016-03-11 2016-03-16 2016-03-17 2016-03-18 2016-03-19 2016-03-20 2016-03-21 2016-03-26 2016-03-27 2016-03-28 2016-03-29 2016-03-30 2016-03-31 2016-04-01 2016-04-02 2016-04-03 2016-04-04 2016-04-05 2016-04-06 2016-04-07 2016-04-08 2016-04-09 2016-04-10 2016-04-11 2016-04-12 2016-04-13 2016-04-14 2016-04-15 2016-04-16 2016-04-17 2016-04-18 2016-04-19 2016-04-20 2016-04-21 2016-04-22 2016-04-23 2016-04-24 2016-04-25 2016-04-26 2016-04-27 2016-04-28 2016-04-29 2016-04-30 2016-05-01 2016-05-02 2016-05-03 2016-05-04 2016-05-05 2016-05-06 2016-05-07 2016-05-08 2016-05-09 2016-05-10 2016-05-11 2016-05-12 2016-05-13 2016-05-14 2016-05-15 2016-05-16 2016-05-17 2016-05-18 2016-05-19 2016-05-20 2016-05-21 2016-05-22 2016-05-23 2016-05-24 2016-05-25 2016-05-26 2016-05-27 2016-05-28 2016-05-29 2016-05-30 2016-05-31 2016-06-01 2016-06-02 2016-06-03 2016-06-04 2016-06-05 2016-06-06 2016-06-07 2016-06-08 2016-06-09 2016-06-10 2016-06-11 2016-06-12 2016-06-13 2016-06-14 2016-06-15 2016-06-16 2016-06-17 2016-06-18 2016-06-19 2016-06-20 2016-06-21 2016-06-22 2016-06-23 2016-06-24 2016-06-27 2016-06-28 2016-06-29 2016-06-30 2016-07-01 2016-07-02 2016-07-03 2016-07-04 2016-07-05 2016-07-06 2016-07-07 2016-07-08 2016-07-09 2016-07-10 2016-07-11 2016-07-12 2016-07-13 2016-07-14 2016-07-15 2016-07-16 2016-07-17 2016-07-18 2016-07-19 2016-07-20 2016-07-21 2016-07-22 2016-07-23 2016-07-24 2016-07-25 2016-07-26 2016-07-27 2016-07-28 2016-07-29 2016-07-30 2016-07-31 2016-08-01 2016-08-02 2016-08-03 2016-08-04 2016-08-05 2016-08-06 2016-08-07 2016-08-08 2016-08-09 2016-08-10 2016-08-11 2016-08-12 2016-08-13 2016-08-14 2016-08-15 2016-08-16 2016-08-17 2016-08-18 2016-08-19 2016-08-20 2016-08-21 2016-08-22 2016-08-23 2016-08-24 2016-08-25 2016-08-26 2016-08-27 2016-08-28 2016-08-29 2016-08-30 2016-08-31 2016-09-01 2016-09-02 2016-09-03 2016-09-04 2016-09-05 2016-09-06 2016-09-07 2016-09-08 2016-09-09 2016-09-10 2016-09-11 2016-09-12 2016-09-13 2016-09-14 2016-09-15 2016-09-16 2016-09-17 2016-09-18 2016-09-19 2016-09-20 2016-09-21 2016-09-22 2016-09-23 2016-09-24 2016-09-25 2016-09-26 2016-09-27 2016-09-28 2016-09-29 2016-09-30 2016-10-01 2016-10-02 2016-10-03 2016-10-04 2016-10-05 2016-10-06 2016-10-07 2016-10-08 2016-10-09 2016-10-10 2016-10-11 2016-10-12 2016-10-13 2016-10-14 2016-10-15 2016-10-16 2016-10-17 2016-10-18 2016-10-19 2016-10-20 2016-10-21 2016-10-22 2016-10-23 2016-10-24 2016-10-25 2016-10-26 2016-10-27 2016-10-28 2016-10-29 2016-10-30 2016-10-31]
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '#available?' do
41
+ let(:arrival) { Date.new(2015, 11, 8) }
42
+ let(:departure) { Date.new(2015, 11, 9) }
43
+
44
+ context 'when the requested dates are available' do
45
+ context 'when range is two days (1 night)' do
46
+ it 'returns true' do
47
+ VCR.use_cassette(calendar_id) do
48
+ expect(subject.available?(arrival, departure)).to eq true
49
+ end
50
+ end
51
+ end
52
+
53
+ context 'when range is three days (2 nights)' do
54
+ let(:departure) { Date.new(2015, 11, 10) }
55
+
56
+ it 'returns true' do
57
+ VCR.use_cassette(calendar_id) do
58
+ expect(subject.available?(arrival, departure)).to eq true
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'when the requested dates are unavailable' do
65
+ let(:arrival) { Date.new(2015, 11, 22) }
66
+ let(:departure) { Date.new(2015, 11, 28) }
67
+
68
+ it 'returns false' do
69
+ VCR.use_cassette(calendar_id) do
70
+ expect(subject.available?(arrival, departure)).to eq false
71
+ end
72
+ end
73
+ end
74
+
75
+ context 'when -dates- is empty' do
76
+ it 'returns false' do
77
+ VCR.use_cassette(calendar_id) do
78
+ expect(subject).to receive(:available_dates).and_return []
79
+ expect(subject.available?(arrival, departure)).to eq false
80
+ end
81
+ end
82
+ end
83
+
84
+ context 'when the third argument -dates- is given' do
85
+ let(:dates) { %w[2015-12-13 2015-12-14 2015-12-15 2015-12-16 2015-12-17 2015-12-18] }
86
+
87
+ it 'does not call +available_dates+' do
88
+ VCR.use_cassette(calendar_id) do
89
+ expect(subject).to_not receive(:available_dates)
90
+ subject.available?(arrival, departure, dates)
91
+ end
92
+ end
93
+
94
+ context 'when the requested dates are available' do
95
+ let(:arrival) { Date.new(2015, 12, 14) }
96
+ let(:departure) { Date.new(2015, 12, 19) }
97
+
98
+ it 'returns true' do
99
+ VCR.use_cassette(calendar_id) do
100
+ expect(subject.available?(arrival, departure, dates)).to be true
101
+ end
102
+ end
103
+ end
104
+
105
+ context 'when the requested dates are unavailable' do
106
+ it 'returns false' do
107
+ VCR.use_cassette(calendar_id) do
108
+ expect(subject.available?(arrival, departure, dates)).to be false
109
+ end
110
+ end
111
+ end
112
+
113
+ context 'when -dates- are empty' do
114
+ let(:dates) { [] }
115
+
116
+ it 'returns false' do
117
+ VCR.use_cassette(calendar_id) do
118
+ expect(subject).to_not receive(:available_dates)
119
+ expect(subject.available?(arrival, departure, dates)).to be false
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ describe '#url' do
127
+ context 'when @id is present' do
128
+ context 'when -protocol- is given' do
129
+ it 'returns the url using the given protocol' do
130
+ expect(subject.url('https')).to eq "https://www.vrbo.com/#{calendar_id}/calendar"
131
+ end
132
+ end
133
+
134
+ context 'when -protocol- is given' do
135
+ it 'returns the url using the default "http" protocol' do
136
+ expect(subject.url).to eq "http://www.vrbo.com/#{calendar_id}/calendar"
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'when @id is missing' do
142
+ let(:calendar_id) { nil }
143
+
144
+ it 'raises an argument error' do
145
+ expect {
146
+ subject.url
147
+ }.to raise_error(ArgumentError, /calendar_id is required/)
148
+ end
149
+ end
150
+ end
151
+ end
data/vrbo.gemspec CHANGED
@@ -23,4 +23,8 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
  spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "vcr", '~> 2.9'
27
+ spec.add_development_dependency "webmock", '~> 1.21'
28
+ spec.add_development_dependency "rspec", '~> 3.3'
29
+ spec.add_development_dependency "rspec-its", '~> 1.2'
26
30
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vrbo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Buckley
@@ -66,6 +66,62 @@ dependencies:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: vcr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '2.9'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '2.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '1.21'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '1.21'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '3.3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '3.3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-its
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '1.2'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: '1.2'
69
125
  description: Scrapes a VRBO calendar using Mechanize and returns available dates
70
126
  email:
71
127
  - arebuckley@gmail.com
@@ -74,6 +130,7 @@ extensions: []
74
130
  extra_rdoc_files: []
75
131
  files:
76
132
  - .gitignore
133
+ - .rspec
77
134
  - .ruby-gemset
78
135
  - .ruby-version
79
136
  - Gemfile
@@ -83,12 +140,12 @@ files:
83
140
  - lib/vrbo.rb
84
141
  - lib/vrbo/availability.rb
85
142
  - lib/vrbo/calendar.rb
86
- - lib/vrbo/class_methods.rb
87
143
  - lib/vrbo/configuration.rb
88
144
  - lib/vrbo/version.rb
89
- - test/support/calendar_dates.rb
90
- - test/vrbo/availability_test.rb
91
- - test/vrbo/calendar_test.rb
145
+ - spec/fixtures/vcr_cassettes/293021.yml
146
+ - spec/spec_helper.rb
147
+ - spec/vrbo/availability_spec.rb
148
+ - spec/vrbo/calendar_spec.rb
92
149
  - vrbo.gemspec
93
150
  homepage: ''
94
151
  licenses:
@@ -115,6 +172,7 @@ signing_key:
115
172
  specification_version: 4
116
173
  summary: Scrapes a VRBO calendar using Mechanize
117
174
  test_files:
118
- - test/support/calendar_dates.rb
119
- - test/vrbo/availability_test.rb
120
- - test/vrbo/calendar_test.rb
175
+ - spec/fixtures/vcr_cassettes/293021.yml
176
+ - spec/spec_helper.rb
177
+ - spec/vrbo/availability_spec.rb
178
+ - spec/vrbo/calendar_spec.rb
@@ -1,14 +0,0 @@
1
- module VRBO
2
- module ClassMethods
3
-
4
- def method_missing(method_name, *arguments)
5
- inst = new
6
- if inst.respond_to?(method_name)
7
- inst.send(method_name, *arguments)
8
- else
9
- super
10
- end
11
- end
12
-
13
- end
14
- end
@@ -1,47 +0,0 @@
1
- module CalendarDates
2
-
3
- def available?(list, a = today, b = tomorrow)
4
- vrbo_calendar.available?(a, b, list)
5
- end
6
-
7
- def all
8
- prep [today, tomorrow]
9
- end
10
-
11
- def random
12
- prep all.shuffle
13
- end
14
-
15
- def arrival_only
16
- prep [today]
17
- end
18
-
19
- def depart_only
20
- prep [tomorrow]
21
- end
22
-
23
- def prep(list)
24
- list.map(&:to_s)
25
- end
26
-
27
- def today
28
- @today ||= Date.today
29
- end
30
-
31
- def tomorrow
32
- @tomorrow ||= today + 1
33
- end
34
-
35
- def vrbo_calendar
36
- @vrbo_calendar ||= begin
37
- calendar = VRBO::Calendar.new
38
-
39
- def calendar.collect_days_for_month(date)
40
- dates = date.upto(date.next_month).to_a
41
- dates.map(&:day).map(&:to_s).take(3)
42
- end
43
-
44
- calendar
45
- end
46
- end
47
- end
@@ -1,21 +0,0 @@
1
- $: << 'test'
2
- require 'minitest/autorun'
3
- require 'vrbo'
4
- require 'support/calendar_dates'
5
-
6
- class AvailabilityTest < MiniTest::Unit::TestCase
7
- include CalendarDates
8
-
9
- def test_new_with_params
10
- availability = VRBO::Availability.new(all << (tomorrow + 2).to_s)
11
- assert_equal today, availability.start_at
12
- assert_equal 2, availability.duration
13
- end
14
-
15
- def test_new_without_params
16
- availability = VRBO::Availability.new
17
- assert_equal today, availability.start_at
18
- assert_equal 1, availability.duration
19
- end
20
-
21
- end
@@ -1,70 +0,0 @@
1
- $: << 'test'
2
- require 'minitest/autorun'
3
- require 'vrbo'
4
- require 'support/calendar_dates'
5
-
6
- class CalendarTest < MiniTest::Unit::TestCase
7
- include CalendarDates
8
-
9
- def calendar_id
10
- 212121
11
- end
12
-
13
- def test_available_with_all
14
- assert_equal true, available?(all)
15
- end
16
-
17
- def test_available_with_random
18
- assert_equal true, available?(random)
19
- end
20
-
21
- def test_available_with_arrival
22
- assert_equal true, available?(arrival_only)
23
- end
24
-
25
- def test_available_with_depart
26
- assert_equal false, available?(depart_only)
27
- end
28
-
29
- def test_available_with_empty
30
- assert_equal false, available?([])
31
- end
32
-
33
- def test_available_with_edge
34
- assert_equal true, available?(all, today, tomorrow + 1)
35
- end
36
-
37
- def test_available_with_exceeding
38
- assert_equal false, available?(all, today, tomorrow + 2)
39
- end
40
-
41
- def test_find_all_available_dates
42
- # 3 days taken for each month (36)
43
- assert_equal 36, vrbo_calendar.find_available_dates.length
44
- assert_equal 12, vrbo_calendar.days.length
45
- assert_equal today.to_s, vrbo_calendar.available_dates.first
46
- end
47
-
48
- def test_passing_calendar_id
49
- calendar = VRBO::Calendar.new(calendar_id)
50
- assert_equal calendar_id, calendar.id
51
- assert_equal "http://www.vrbo.com/#{calendar_id}/calendar", calendar.url
52
- assert_equal "https://www.vrbo.com/#{calendar_id}/calendar", calendar.url('https')
53
- end
54
-
55
- def test_no_calendar_id_given
56
- assert_raises ArgumentError do
57
- VRBO::Calendar.new.url
58
- end
59
- end
60
-
61
- def test_calendar_id_from_config
62
- VRBO.configure do |config|
63
- config.calendar_id = calendar_id
64
- end
65
- calendar = VRBO::Calendar.new
66
- VRBO.reset_config
67
- assert_equal calendar_id, calendar.id
68
- assert_equal "http://www.vrbo.com/#{calendar_id}/calendar", calendar.url
69
- end
70
- end