auchandirect-scrAPI 0.0.1 → 0.1.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: d467fe59e8fbdaec06eac26018e63a1f35144ee6
4
- data.tar.gz: 0e6fa119d92864dda09e498dbcee4f388c70b1b7
3
+ metadata.gz: cc35cb08d3c9467fe51c720cd6d154286627d478
4
+ data.tar.gz: f13f7199fa84e7f6093d4fac3d97772108ac52f6
5
5
  SHA512:
6
- metadata.gz: 6d5dcb57103f62abc269e1ba4c73e09d3db88c5df6e654eb590dbff2fc3d2d600b06d30a429b9a85ee71b05dca6bd945d066621856cfdf6ee520945540221f95
7
- data.tar.gz: 866b9b4bff3e1819ddb3a63b816e466a381ab37469f60825d54ec91929914c7df4a1968a0a590553830d13116030d1be0af0acd81963199783dad02c7bc0254e
6
+ metadata.gz: cec302e8fbaf7f1ad245f94cf0f8a483c2f712328e6ba512a49438cfc88be7b154e20f5d00b38dcc9b5b82e146ad264c3fd7dbf8cdc55eada15a3c8ead3e9c8b
7
+ data.tar.gz: c924a934ffda7b7b4d3040fcb123c9f5fa590e473b974c072870db8a7d8d904eb166dd50e915baa04314cab4531dd1edff533b2c90eaf1b046e31e4b6495c605
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - ruby-head
4
- - 2.1.0
4
+ - 2.1.1
5
5
  - 2.0.0
6
6
  - jruby-head
7
7
  - jruby-21mode
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Auchandirect::ScrAPI
2
2
 
3
- A ruby gem providing, through scrapping, an API to the french www.auchandirect.com online grocery
3
+ A ruby gem providing, through scrapping, an API to the french www.auchandirect.fr online grocery
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,9 +16,61 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install auchandirect-scrAPI
18
18
 
19
+ ## Status
20
+
21
+ This library should be production ready.
22
+ * It is automaticaly tested through Travis[https://travis-ci.org/philou/auchandirect-scrAPI]
23
+ * It should be daily tested through TravisCron[http://traviscron.pythonanywhere.com/] to quickly detect modification at auchandirect.fr
24
+
19
25
  ## Usage
20
26
 
21
- TODO: Write usage instructions here
27
+ This API has 2 main features :
28
+ * walking the store to collect all the different items in the different subsections
29
+ * Connecting with a user account in order to fill his cart
30
+
31
+ It is not currently possible to pay and validate an order through this API. In order to do so, a user must :
32
+ 1. first disconnect from the API
33
+ 2. only then reconnect with his account through a browser, and order his pre-filled cart
34
+
35
+ ### Sample usage
36
+
37
+ Suppose you'd want to fill your cart with all the pizzas available on the store, this is how you would do it :
38
+
39
+ ```ruby
40
+ cart = Auchandirect::ScrAPI::Cart.login('buyer@mail.org', 'password')
41
+
42
+ begin
43
+
44
+ Storexplore::Api.browse('http://www.auchandirect.fr').categories.each do |cat|
45
+ cat.categories.each do |s_cat|
46
+ s_cat.categories.each do |ss_cat|
47
+ ss_cat.items.each do |item|
48
+
49
+ if item.attributes[:name] =~ /pizza/i
50
+
51
+ cart.add_to_cart(item.attributes[:remote_id])
52
+
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ ensure
60
+
61
+ ensure cart.logout
62
+
63
+ end
64
+
65
+ ```
66
+
67
+ ### Client side usage
68
+
69
+ In order to make it possible for a web browser to automaticaly connect to auchandirect.fr (for example in an iframe, to pay for a cart that was previously filled with this gem on the server), the cart The Auchandirect::ScrAPI::Cart classes exposes enough information to generate the html that makes this possible. You can have a look at spec/lib/auchandirect/scrAPI/client_cart_shared_examples.rb for more details. /This whole thing remains tricky and subject to failures though./
70
+
71
+ ### Testing
72
+
73
+ In order to run quicker and offline tests for the rest of your app, you can use Auchandirect::ScrAPI::DummyCart in place of a real cart. This cart is compatible with Storexplore's dummy store generators [https://github.com/philou/storexplore].
22
74
 
23
75
  ## Contributing
24
76
 
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Auchandirect::ScrAPI::VERSION
9
9
  spec.authors = ["Philou"]
10
10
  spec.email = ["philippe.bourgau@gmail.com"]
11
- spec.description = %q{Through scrapping, an API to the french www.auchandirect.com online grocery}
11
+ spec.description = %q{Through scrapping, an API to the french www.auchandirect.fr online grocery}
12
12
  spec.summary = %q{auchandirect.com grocery API}
13
13
  spec.homepage = "https://github.com/philou/auchandirect-scrAPI"
14
14
  spec.license = "LGPL v3"
@@ -22,19 +22,21 @@
22
22
  module Auchandirect
23
23
  module ScrAPI
24
24
 
25
- # Objects providing an api like access to third party online stores
25
+ # Base class for objects providing an api like access to third party online stores
26
26
  class BaseCart
27
27
 
28
+ # :login is a synonym for :new
28
29
  class << self
29
30
  alias :login :new
30
31
  end
31
32
 
32
- # main url of the store
33
- # def self.url
33
+ # Main url of the store
34
34
  def url
35
35
  self.class.url
36
36
  end
37
37
 
38
+ # def self.url
39
+
38
40
  # url at which a client browser can login
39
41
  # def self.login_url
40
42
 
@@ -24,10 +24,10 @@ require 'json'
24
24
  module Auchandirect
25
25
  module ScrAPI
26
26
 
27
- # Store API for AuchanDirect store
27
+ # Cart API for AuchanDirect store
28
28
  class Cart < BaseCart
29
29
 
30
- # main url of the store
30
+ # Main url of the store
31
31
  def self.url
32
32
  "http://www.auchandirect.fr"
33
33
  end
@@ -39,11 +39,11 @@ module Auchandirect
39
39
  raise InvalidAccountError unless logged_in?
40
40
  end
41
41
 
42
- # url at which a client browser can login
42
+ # Url at which a client browser can login
43
43
  def self.login_url
44
44
  url + login_path
45
45
  end
46
- # parameters for a client side login
46
+ # Parameters for a client side login
47
47
  def self.login_parameters(login, password)
48
48
  default_params = post_parameters.map {|name, value| {'name' => name, 'value' => value, 'type' => 'hidden'}}
49
49
  user_params = [{'name' => FORMDATA_PARAMETER, 'value' => login_form_data(Mechanize.new), 'type' => 'hidden'},
@@ -53,42 +53,57 @@ module Auchandirect
53
53
  default_params + user_params
54
54
  end
55
55
 
56
- # login and password parameters names
56
+ # Client side 'login' parameter name
57
57
  def self.login_parameter
58
58
  LOGIN_PARAMETER
59
59
  end
60
+ # Client side 'password' parameter name
60
61
  def self.password_parameter
61
62
  PASSWORD_PARAMETER
62
63
  end
63
64
 
64
- # url at which a client browser can logout
65
+ # Url at which a client browser can logout
65
66
  def self.logout_url
66
67
  url + logout_path
67
68
  end
68
69
 
69
- # logs out from the store
70
+ # Logs out from the store
70
71
  def logout
71
72
  get(self.class.logout_path)
72
73
  end
73
74
 
74
- # total value of the remote cart
75
+ # Total value of the remote cart
75
76
  def cart_value
76
77
  cart_page = get("/monpanier")
77
78
  cart_page.search("span.prix-total").first.content.gsub(/€$/,"").to_f
78
79
  end
79
80
 
80
- # empties the cart of the current user
81
+ # Empties the cart of the current user
81
82
  def empty_the_cart
82
83
  post("/boutiques.blockzones.popuphandler.cleanbasketpopup.cleanbasket")
83
84
  end
84
85
 
85
- # adds items to the cart of the current user
86
+ # Adds items to the cart of the current user
86
87
  def add_to_cart(quantity, item_remote_id)
87
88
  quantity.times do
88
89
  post("/boutiques.mozaique.thumbnailproduct.addproducttobasket/#{item_remote_id}")
89
90
  end
90
91
  end
91
92
 
93
+ # Missing methods can be forwarded to the class
94
+ def method_missing(method_sym, *arguments, &block)
95
+ if delegate_to_class?(method_sym)
96
+ self.class.send(method_sym, *arguments, &block)
97
+ else
98
+ super
99
+ end
100
+ end
101
+
102
+ # It can respond to messages that the class can handle
103
+ def respond_to?(method_sym)
104
+ super or delegate_to_class?(method_sym)
105
+ end
106
+
92
107
  private
93
108
 
94
109
  def do_login(login,password)
@@ -150,17 +165,6 @@ module Auchandirect
150
165
  {'t:ac' => "Accueil", 't:cp' => 'gabarit/generated'}
151
166
  end
152
167
 
153
- def method_missing(method_sym, *arguments, &block)
154
- if delegate_to_class?(method_sym)
155
- self.class.send(method_sym, *arguments, &block)
156
- else
157
- super
158
- end
159
- end
160
-
161
- def respond_to?(method_sym)
162
- super or delegate_to_class?(method_sym)
163
- end
164
168
  def delegate_to_class?(method_sym)
165
169
  self.class.respond_to?(method_sym)
166
170
  end
@@ -22,15 +22,18 @@
22
22
  module Auchandirect
23
23
  module ScrAPI
24
24
 
25
- # Logger mock api
25
+ # A mock for Auchandirect::ScrAPI::Cart
26
+ # It provides a call log as a way of testing
26
27
  class DummyCart < BaseCart
27
28
 
28
29
  def self.url
29
30
  "http://www.#{Storexplore::Testing::DummyStoreConstants::NAME}.com"
30
31
  end
32
+ # The valid login to log into this dummy store
31
33
  def self.valid_email
32
34
  "valid@mail.com"
33
35
  end
36
+ # The valid password to log into this dummy store
34
37
  def self.valid_password
35
38
  "valid-password"
36
39
  end
@@ -53,20 +56,25 @@ module Auchandirect
53
56
  'password'
54
57
  end
55
58
 
59
+ # Accessors to the login and passwords used to login
60
+ # And to the received messages log
56
61
  attr_reader :login, :password, :log
57
62
 
63
+ # As the real store, the remote cart outlives the sessions
64
+ @@content = Hash.new(0)
65
+
58
66
  def initialize(login = nil, password = nil)
59
67
  @log = []
60
68
  @login = ""
61
69
  @password = ""
62
70
  @unavailable_items = {}
63
- @content = Hash.new(0)
64
71
 
65
72
  if !login.nil? || !password.nil?
66
73
  relog(login, password)
67
74
  end
68
75
  end
69
76
 
77
+ # Resets the session as if a new one was started
70
78
  def relog(login, password)
71
79
  if login != DummyCart.valid_email
72
80
  raise InvalidAccountError.new
@@ -83,18 +91,18 @@ module Auchandirect
83
91
 
84
92
  def empty_the_cart
85
93
  @log.push(:empty_the_cart)
86
- @content.clear
94
+ @@content.clear
87
95
  end
88
96
 
89
97
  def add_to_cart(quantity, item)
90
98
  if available?(item)
91
99
  @log.push(:add_to_cart)
92
- @content[item] += quantity
100
+ @@content[item] += quantity
93
101
  end
94
102
  end
95
103
 
96
104
  def cart_value
97
- @content.to_a.inject(0.0) do |amount,id_and_quantity|
105
+ @@content.to_a.inject(0.0) do |amount,id_and_quantity|
98
106
  item = id_and_quantity.first
99
107
  quantity = id_and_quantity.last
100
108
 
@@ -104,21 +112,27 @@ module Auchandirect
104
112
  end
105
113
  end
106
114
 
115
+ # Collection of all the different items in the cart
107
116
  def content
108
- @content.keys
117
+ @@content.keys
109
118
  end
110
119
 
120
+ # Is the cart empty ?
111
121
  def empty?
112
- @content.empty?
122
+ @@content.empty?
113
123
  end
114
124
 
125
+ # Does the cart contain the specified quantity of this item ?
115
126
  def containing?(item, quantity)
116
- @content[item] == quantity
127
+ @@content[item] == quantity
117
128
  end
118
129
 
130
+ # Makes an item temporarily unavailable
119
131
  def add_unavailable_item(item)
120
132
  @unavailable_items[item] = true
121
133
  end
134
+
135
+ # Is the given item available at this moment ?
122
136
  def available?(item)
123
137
  !@unavailable_items[item]
124
138
  end
@@ -21,6 +21,7 @@
21
21
 
22
22
  module Auchandirect
23
23
  module ScrAPI
24
+ # Error thrown when one tries to login with invalid credentials
24
25
  class InvalidAccountError < RuntimeError
25
26
  end
26
27
  end
@@ -22,6 +22,20 @@
22
22
  module Auchandirect
23
23
  module ScrAPI
24
24
 
25
+ # Storexplore api definition to browse all the items available
26
+ # at auchandirect.com
27
+ # See[https://github.com/philou/storexplore/blob/master/README.md]
28
+ #
29
+ # The store has 3 depths of categories.
30
+ # The only attribute the categories have is their name
31
+ # The items are all child of the bottom categories, here are
32
+ # their attributes
33
+ # * brand
34
+ # * name
35
+ # * price
36
+ # * image (url of the link to the image)
37
+ # * remote_id (the id of this item in the auchandirect database)
38
+
25
39
  module Items
26
40
  NAMES_SEPARATOR = ', '
27
41
  end
@@ -21,7 +21,7 @@
21
21
 
22
22
  module Auchandirect
23
23
  module ScrAPI
24
- VERSION = "0.0.1"
24
+ VERSION = "0.1.0"
25
25
  end
26
26
  end
27
27
 
@@ -24,6 +24,7 @@ require 'spec_helper'
24
24
  shared_examples_for "Any Cart" do |store_cart_class, store_url|
25
25
 
26
26
  before :all do
27
+ @store_cart_class = store_cart_class
27
28
  @store_url = store_url
28
29
  end
29
30
 
@@ -63,7 +64,7 @@ shared_examples_for "Any Cart" do |store_cart_class, store_url|
63
64
  attr_reader :sample_item_id, :another_item_id, :store_cart_api
64
65
 
65
66
  before(:all) do
66
- @api = store_cart_class.login(store_cart_class.valid_email, store_cart_class.valid_password)
67
+ @session = new_session
67
68
 
68
69
  sample_items = extract_sample_items
69
70
  sample_item = sample_items.next
@@ -71,38 +72,38 @@ shared_examples_for "Any Cart" do |store_cart_class, store_url|
71
72
  @another_item_id = extract_another_item_id(sample_items, sample_item)
72
73
  end
73
74
  before(:each) do
74
- @api.empty_the_cart
75
+ @session.empty_the_cart
75
76
  end
76
77
 
77
78
  after(:all) do
78
- @api.logout
79
+ @session.logout
79
80
  end
80
81
 
81
82
  # Some tests are redudant with what is item extractions, but the followings
82
83
  # are clearer about what is expected from the cart
83
84
 
84
85
  it "should set the cart value to 0 when emptying the cart" do
85
- @api.add_to_cart(1, sample_item_id)
86
+ @session.add_to_cart(1, sample_item_id)
86
87
 
87
- @api.empty_the_cart
88
- expect(@api.cart_value).to eq 0
88
+ @session.empty_the_cart
89
+ expect(@session.cart_value).to eq 0
89
90
  end
90
91
 
91
92
  it "should set the cart value to something greater than 0 when adding items to the cart" do
92
- @api.empty_the_cart
93
+ @session.empty_the_cart
93
94
 
94
- @api.add_to_cart(1, sample_item_id)
95
- expect(@api.cart_value).to be > 0
95
+ @session.add_to_cart(1, sample_item_id)
96
+ expect(@session.cart_value).to be > 0
96
97
  end
97
98
 
98
99
  it "should set the cart value to 2 times that of one item when adding 2 items" do
99
- @api.empty_the_cart
100
+ @session.empty_the_cart
100
101
 
101
- @api.add_to_cart(1, sample_item_id)
102
- item_price = @api.cart_value
102
+ @session.add_to_cart(1, sample_item_id)
103
+ item_price = @session.cart_value
103
104
 
104
- @api.add_to_cart(1, sample_item_id)
105
- expect(@api.cart_value).to eq 2*item_price
105
+ @session.add_to_cart(1, sample_item_id)
106
+ expect(@session.cart_value).to eq 2*item_price
106
107
  end
107
108
 
108
109
  it "should set different cart values with different items" do
@@ -112,24 +113,41 @@ shared_examples_for "Any Cart" do |store_cart_class, store_url|
112
113
  expect(sample_item_cart_value).not_to eq another_item_cart_value
113
114
  end
114
115
 
115
- it "should synchronize different sessions with logout login" do
116
- @api.add_to_cart(1, sample_item_id)
116
+ it "should save the cart between sessions" do
117
+ @session.add_to_cart(1, sample_item_id)
118
+ @session.logout
117
119
 
118
- api2 = store_cart_class.login(store_cart_class.valid_email, store_cart_class.valid_password)
119
- begin
120
- api2.empty_the_cart
121
- ensure
122
- api2.logout
123
- end
120
+ @session = new_session
124
121
 
125
- @api.logout
126
- @api = store_cart_class.login(store_cart_class.valid_email, store_cart_class.valid_password)
122
+ expect(@session.cart_value).not_to eq 0
123
+ end
124
+
125
+ it "should save the cart between sessions, even while another session" do
126
+ background_session = @session
127
+
128
+ run_session do |session|
129
+ session.add_to_cart(1, sample_item_id)
130
+ end
127
131
 
128
- expect(@api.cart_value).to eq 0
132
+ run_session do |session|
133
+ expect(session.cart_value).not_to eq 0
134
+ end
129
135
  end
130
136
 
131
137
  private
132
138
 
139
+ def run_session
140
+ session = new_session
141
+ begin
142
+ yield session
143
+ ensure
144
+ session.logout
145
+ end
146
+ end
147
+
148
+ def new_session
149
+ @store_cart_class.login(@store_cart_class.valid_email, @store_cart_class.valid_password)
150
+ end
133
151
  def extract_another_item_id(sample_items, sample_item)
134
152
  another_item = sample_item
135
153
  while sample_item.attributes[:price] == another_item.attributes[:price]
@@ -158,13 +176,13 @@ shared_examples_for "Any Cart" do |store_cart_class, store_url|
158
176
  end
159
177
 
160
178
  def item_available?(item_id)
161
- @api.empty_the_cart
162
- @api.add_to_cart(1, item_id)
163
- item_price = @api.cart_value
179
+ @session.empty_the_cart
180
+ @session.add_to_cart(1, item_id)
181
+ item_price = @session.cart_value
164
182
  return false if 0 == item_price
165
183
 
166
- @api.add_to_cart(1, item_id)
167
- return @api.cart_value == item_price * 2
184
+ @session.add_to_cart(1, item_id)
185
+ return @session.cart_value == item_price * 2
168
186
  end
169
187
 
170
188
  def nationaly_available_first(elements)
@@ -181,9 +199,9 @@ shared_examples_for "Any Cart" do |store_cart_class, store_url|
181
199
  end
182
200
 
183
201
  def cart_value_with_item(item_id)
184
- @api.empty_the_cart
185
- @api.add_to_cart(1, item_id)
186
- @api.cart_value
202
+ @session.empty_the_cart
203
+ @session.add_to_cart(1, item_id)
204
+ @session.cart_value
187
205
  end
188
206
  end
189
207
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: auchandirect-scrAPI
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philou
@@ -31,102 +31,102 @@ cert_chain:
31
31
  yLcl1cmm5ALtJ/+Bkkmp0i4amXeTDMvq9r8PBsVsQwxYOYJBP+Umxz3PX6HjFHrQ
32
32
  XdkXx3oZ
33
33
  -----END CERTIFICATE-----
34
- date: 2014-03-17 00:00:00.000000000 Z
34
+ date: 2014-03-21 00:00:00.000000000 Z
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: storexplore
38
38
  requirement: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - ~>
40
+ - - "~>"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0.2'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ~>
47
+ - - "~>"
48
48
  - !ruby/object:Gem::Version
49
49
  version: '0.2'
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: bundler
52
52
  requirement: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - ~>
54
+ - - "~>"
55
55
  - !ruby/object:Gem::Version
56
56
  version: '1.3'
57
57
  type: :development
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - ~>
61
+ - - "~>"
62
62
  - !ruby/object:Gem::Version
63
63
  version: '1.3'
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: rake
66
66
  requirement: !ruby/object:Gem::Requirement
67
67
  requirements:
68
- - - ~>
68
+ - - "~>"
69
69
  - !ruby/object:Gem::Version
70
70
  version: '10.1'
71
71
  type: :development
72
72
  prerelease: false
73
73
  version_requirements: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - ~>
75
+ - - "~>"
76
76
  - !ruby/object:Gem::Version
77
77
  version: '10.1'
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: guard-rspec
80
80
  requirement: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - ~>
82
+ - - "~>"
83
83
  - !ruby/object:Gem::Version
84
84
  version: '4.0'
85
85
  type: :development
86
86
  prerelease: false
87
87
  version_requirements: !ruby/object:Gem::Requirement
88
88
  requirements:
89
- - - ~>
89
+ - - "~>"
90
90
  - !ruby/object:Gem::Version
91
91
  version: '4.0'
92
92
  - !ruby/object:Gem::Dependency
93
93
  name: net-ping
94
94
  requirement: !ruby/object:Gem::Requirement
95
95
  requirements:
96
- - - ~>
96
+ - - "~>"
97
97
  - !ruby/object:Gem::Version
98
98
  version: '1.7'
99
99
  type: :development
100
100
  prerelease: false
101
101
  version_requirements: !ruby/object:Gem::Requirement
102
102
  requirements:
103
- - - ~>
103
+ - - "~>"
104
104
  - !ruby/object:Gem::Version
105
105
  version: '1.7'
106
106
  - !ruby/object:Gem::Dependency
107
107
  name: spec_combos
108
108
  requirement: !ruby/object:Gem::Requirement
109
109
  requirements:
110
- - - ~>
110
+ - - "~>"
111
111
  - !ruby/object:Gem::Version
112
112
  version: '0.2'
113
113
  type: :development
114
114
  prerelease: false
115
115
  version_requirements: !ruby/object:Gem::Requirement
116
116
  requirements:
117
- - - ~>
117
+ - - "~>"
118
118
  - !ruby/object:Gem::Version
119
119
  version: '0.2'
120
- description: Through scrapping, an API to the french www.auchandirect.com online grocery
120
+ description: Through scrapping, an API to the french www.auchandirect.fr online grocery
121
121
  email:
122
122
  - philippe.bourgau@gmail.com
123
123
  executables: []
124
124
  extensions: []
125
125
  extra_rdoc_files: []
126
126
  files:
127
- - .gitignore
128
- - .rspec
129
- - .travis.yml
127
+ - ".gitignore"
128
+ - ".rspec"
129
+ - ".travis.yml"
130
130
  - Gemfile
131
131
  - Guardfile
132
132
  - LICENSE
@@ -161,17 +161,17 @@ require_paths:
161
161
  - lib
162
162
  required_ruby_version: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - '>='
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  required_rubygems_version: !ruby/object:Gem::Requirement
168
168
  requirements:
169
- - - '>='
169
+ - - ">="
170
170
  - !ruby/object:Gem::Version
171
171
  version: '0'
172
172
  requirements: []
173
173
  rubyforge_project:
174
- rubygems_version: 2.0.3
174
+ rubygems_version: 2.2.2
175
175
  signing_key:
176
176
  specification_version: 4
177
177
  summary: auchandirect.com grocery API
metadata.gz.sig CHANGED
Binary file