storexplore 0.4.0 → 0.5.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: 10fe4669a7509cd1b7ff06f47fd12fc3269894ff
4
- data.tar.gz: 2d3f18b217666c80219922f49de9488fad98b03a
3
+ metadata.gz: 17cba9cf042f031c9d29a00f36ddc74bd1a55bde
4
+ data.tar.gz: 5e4f2f3c4e5ee403527e1c2e0beb188c9536498b
5
5
  SHA512:
6
- metadata.gz: 39223a9ac42ce39c6e35394723464b87a192235f92b9d1e398022426b92a5c8a93a0e1ea955003d1cef71edc9f117f7bfdc7a1062c729ee9de2f1be6cf04e8a1
7
- data.tar.gz: 93e31befe06656e2ff8f71590b78b06780eaba677b963bc86adff83bc963480502a7441576dffda5a48a3453742f3f6ddd77dd96710696af3ab179f8fb81e240
6
+ metadata.gz: a88009b403a3b8505104c25b020e01d246cd592140fa2ab43a4641143278588785391d6b33d74fb66f2c3efe12e48c743b3df4c1eed5c829fd4d746511107933
7
+ data.tar.gz: 0efe5547f14b84d8c17b91cca614a6f2577733240b38f191815b405ce50c1e6cf94f629c86e0052433c88d8b8ba476214893cfe026fe24efcf651d3a9de2234e
data/.gitignore CHANGED
@@ -24,3 +24,6 @@ doc/
24
24
  *~
25
25
  *#
26
26
  .#*
27
+
28
+ # vagrant files
29
+ .vagrant
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.1
4
- - 2.0.0
3
+ - 2.3.1
4
+ - 2.2.5
5
5
  script: bundle exec rake
6
6
 
7
7
  addons:
data/README.md CHANGED
@@ -2,12 +2,32 @@
2
2
 
3
3
  # Storexplore
4
4
 
5
- A declarative scrapping DSL that lets one define directory like apis to an online store
5
+ Transform online stores into APIs !
6
6
 
7
- ## Installation
7
+ ## Why
8
+ Once upon a time, I wanted to create online groceries with great user experience ! That's how I started [mes-courses.fr](https://github.com/philou/mes-courses). Unfortunately, most online groceries don't have APIs, so I resorted to scrapping. Scrapping comes with its (long) list of problems aswell !
8
9
 
9
- In order to be able to enumerate all items of a store in constant memory,
10
- Storexplore requires Matz Ruby 2.0 for its lazy enumerators.
10
+ * Scrapping code is a mess
11
+ * The scrapped html can change at any time
12
+ * Scrappers are difficult to test
13
+
14
+ Refactoring by refactoring, I extracted this libary which defines scrappers for any online store in a straightforward way (check [auchandirect-scrAPI](https://github.com/philou/auchandirect-scrAPI) for my real world usage). A scrapper definition consists of :
15
+
16
+ * a scrapper definition file
17
+ * the selectors for the links
18
+ * the selectors for the content you want to capture
19
+
20
+ As a result of using storexplore for mes-courses, the scrapping code was split between the storexplore gem and my special scrapper definition :
21
+
22
+ * This made the whole overall code cleaner
23
+ * I could write simple and reliable tests
24
+ * Most importantly, I could easily keep pace with the changes in the online store html
25
+
26
+ ## Tutorial
27
+
28
+ [![How to define an API on ikea.us in 10 minutes using storexplore](https://raw.githubusercontent.com/philou/storexplore/master/ikea.jpg)](http://www.youtube.com/watch?v=O30xReGgdVU)
29
+
30
+ ## Installation
11
31
 
12
32
  Add this line to your application's Gemfile:
13
33
 
@@ -21,44 +41,81 @@ Or install it yourself as:
21
41
 
22
42
  $ gem install storexplore
23
43
 
24
- ## Usage
25
-
26
- The library builds hierarchical APIs on online stores. Stores are typicaly
27
- organized in the following way :
28
-
29
- Store > Categories > ... > Sub Categories > Items
30
-
31
- The store is like a root category. Any category, at any depth level can have
32
- both children categories and items. Items cannot have children of any kind.
33
- Both categories and items can have attributes.
44
+ In order to be able to enumerate all items of a store in constant memory,
45
+ Storexplore requires ruby 2.0 for its lazy enumerators.
34
46
 
35
- All searching of children and attributes is done through mechanize/nokogiri
36
- selectors (css or xpath).
47
+ ## Usage
37
48
 
38
- Here is a sample store api declaration :
49
+ Online stores are typicaly organized as hierarchies. For example [Ikea (US)](http://www.ikea.com/us/en) is organized as follows :
50
+
51
+ Ikea
52
+ |-> Living room
53
+ | |-> Sofas & armchairs
54
+ | | |-> Fabric Sofas
55
+ | | | |-> Norsborg Sofa
56
+ | | | |-> Norborg Loveseat
57
+ | | | |-> ...
58
+ | | | |-> Pöang Footstool cushion
59
+ | | |-> Leather Sofas
60
+ | | |-> ...
61
+ | | |-> Armchairs
62
+ | |-> TV & media funiture
63
+ | |-> ...
64
+ | |-> Living room textiles & rugs
65
+ |-> Bedroom
66
+ |-> ...
67
+ |-> Dining
68
+
69
+ Storexplore builds hierarchical APIs on the following pattern :
70
+
71
+ Store
72
+ |-> Category 1
73
+ | |-> Sub Category 1
74
+ | | |-> Item 1
75
+ | | |-> ...
76
+ | | |-> Item n
77
+ | |-> Sub Category 2
78
+ | |-> ...
79
+ | |-> Sub Category n
80
+ |-> Category 2
81
+ |-> ...
82
+ |-> Category n
83
+
84
+ The store is like a root category. Any level of depth is allowed. Any category, at any depth level can have both children categories and items. Items cannot have children of any kind. Both categories and items can have attributes.
85
+
86
+ All searching of children and attributes is done through mechanize/nokogiri selectors (css or xpath).
87
+
88
+ Here is a sample store api declaration for [Ikea](http://www.ikea.com/us/en) again:
39
89
 
40
90
  ```ruby
41
- Storexplore::define_api 'dummy-store.com' do
91
+ Storexplore::Api.define 'ikea.com/us' do
42
92
 
43
- categories 'a.category' do
93
+ categories '.departmentLinkBlock a' do
44
94
  attributes do
45
- { :name => page.get_one("h1").content }
95
+ { :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
46
96
  end
47
97
 
48
- categories 'a.category' do
98
+ categories '.departmentLinks a' do
49
99
  attributes do
50
- { :name => page.get_one("h1").content }
100
+ { :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
51
101
  end
52
102
 
53
- items 'a.item' do
103
+ categories 'a.categoryName' do
54
104
  attributes do
55
- {
56
- :name => page.get_one('h1').content,
57
- :brand => page.get_one('#brand').content,
58
- :price => page.get_one('#price').content.to_f,
59
- :image => page.get_one('#image').content,
60
- :remote_id => page.get_one('#remote_id').content
61
- }
105
+ { :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
106
+ end
107
+
108
+ items '.productDetails > a' do
109
+ attributes do
110
+ {
111
+ :name => page.get_one('#name').content.strip,
112
+ :type => page.get_one('#type').content.strip,
113
+ :price => page.get_one('#price1').content.strip.sub('$','').to_f,
114
+ :salesArgs => page.get_one('#salesArg').content.strip,
115
+ :image => page.get_one('#productImg').attributes['src'].content,
116
+ :ikea_id => page.uri.to_s.match("^.*\/([0-9]+)\/?$").captures.first
117
+ }
118
+ end
62
119
  end
63
120
  end
64
121
  end
@@ -66,41 +123,55 @@ Storexplore::define_api 'dummy-store.com' do
66
123
  end
67
124
  ```
68
125
 
69
- This build a hierarchical API on the 'dummy-store.com' online store. This
70
- registers a new api definition that will be used to browse any store which
71
- uri contains 'dummy-store.com'.
126
+ This defines a hierarchical API on the IKEA store that will be used to browse any store which
127
+ uri contains 'ikea.com/us'.
72
128
 
73
129
  Now here is how this API can be accessed to pretty print all its content:
74
130
 
75
131
  ```ruby
76
- Api.browse('http://www.dummy-store.com').categories.each do |category|
132
+ Storexplore::Api.browse('http://www.ikea.com/us/en').categories.each do |category|
77
133
 
78
- puts "category: #{category.title}"
134
+ puts "category: #{category.title.strip}"
79
135
  puts "attributes: #{category.attributes}"
80
136
 
81
137
  category.categories.each do |sub_category|
82
138
 
83
- puts " category: #{sub_category.title}"
139
+ puts " category: #{sub_category.title.strip}"
84
140
  puts " attributes: #{sub_category.attributes}"
85
141
 
86
- sub_category.items.each do |item|
142
+ sub_category.categories.each do |sub_sub_category|
143
+
144
+ puts " category: #{sub_sub_category.title.strip}"
145
+ puts " attributes: #{sub_sub_category.attributes}"
146
+
147
+ sub_sub_category.items.each do |item|
87
148
 
88
- puts " item: #{item.title}"
89
- puts " attributes: #{item.attributes}"
149
+ puts " item: #{item.title.strip}"
150
+ puts " attributes: #{item.attributes}"
90
151
 
152
+ end
91
153
  end
92
154
  end
93
155
  end
94
156
  ```
95
157
 
96
- ### Testing
158
+ (This sample can be found in samples/ikea.rb)
159
+
160
+ ## Testing
161
+
162
+ NOTE : please keep in mind that these testing utilities have been extracted from my first real use case ([auchandirect-scrAPI](https://github.com/philou/auchandirect-scrAPI)) and might still rely on assumptions coming from there. Any help cleaning this up is welcome.
163
+
164
+ ### Testing Code Relying On A Scrapped Thirdparty
165
+
166
+ This can be quite a challenge. Storeexplore can help you with that :
167
+
168
+ * it provides a customizable offline (disk) dummy store generator
169
+ * it provides an API for this store
170
+ * As long as your dummy store provides the same attributes than the real store, you can use it in your tests
97
171
 
98
- Storexplore ships with some dummy store generation utilities. Dummy stores can
99
- be generated to the file system using the Storexplore::Testing::DummyStore and
100
- Storexplore::Testing::DummyStoreGenerator classes. This is particularly useful
101
- while testing.
172
+ Dummy stores can be generated to the file system using the Storexplore::Testing::DummyStore and Storexplore::Testing::DummyStoreGenerator classes.
102
173
 
103
- To use it, add the following, to your spec_helper.rb for example :
174
+ To use it, add the following to your spec_helper.rb for example :
104
175
 
105
176
  ```ruby
106
177
  require 'storexplore/testing'
@@ -118,7 +189,7 @@ DummyStore.wipe_out_store(store_name)
118
189
  @store_generator.generate(3).categories.and(3).categories.and(item_count).items
119
190
  ```
120
191
 
121
- It is also possibe to add elements with explicit values :
192
+ You can add custom elements with explicit values :
122
193
 
123
194
  ```ruby
124
195
  @store_generator.
@@ -132,10 +203,9 @@ Storexplore provides an api definition for dummy stores in
132
203
  'storexplore/testing/dummy_store_api'. It can be required independently if
133
204
  needed.
134
205
 
135
- ### RSpec shared examples
206
+ ### Testing Your Own Scrapper
136
207
 
137
- Storexplore also ships with an rspec shared examples macro. It can be used for
138
- any custom store API definition.
208
+ Storexplore also ships with an rspec shared examples macro. It guarantees basic scrapper well behaviour such as the presence of many categories, of item names and prices
139
209
 
140
210
  ```ruby
141
211
  require 'storexplore/testing'
@@ -150,7 +220,7 @@ describe "MyStoreApi" do
150
220
  end
151
221
  ```
152
222
 
153
- ### Testing files to require
223
+ ### Summary Testing Files To Require
154
224
 
155
225
  * To only get the api definition for a previously generated dummy store, it is enough to require 'storexplore/testing/dummy_store_api'
156
226
  * To be able to generate and scrap dummy stores, it's needed to require 'storexplore/testing/dummy_store_generator'
@@ -0,0 +1,8 @@
1
+ storexplore:
2
+ image: ruby:2.3.1
3
+ command: bash
4
+ working_dir: /usr/src/app
5
+ environment:
6
+ BUNDLE_PATH: 'vendor/bundle'
7
+ volumes:
8
+ - '.:/usr/src/app'
Binary file
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # api_shared_examples.rb
4
4
  #
5
- # Copyright (c) 2010-2014 by Philippe Bourgau. All rights reserved.
5
+ # Copyright (c) 2010-2014, 2016 by Philippe Bourgau. All rights reserved.
6
6
  #
7
7
  # This library is free software; you can redistribute it and/or
8
8
  # modify it under the terms of the GNU Lesser General Public
@@ -51,7 +51,7 @@ module Storexplore
51
51
  end
52
52
 
53
53
  it "should have items with a price" do
54
- expect(sample_items_attributes).to all_ { have_key(:price) }
54
+ expect(sample_items_attributes).to all(have_key(:price))
55
55
  end
56
56
 
57
57
  it "should mostly have items with an image" do
@@ -63,7 +63,7 @@ module Storexplore
63
63
  end
64
64
 
65
65
  it "should have items with unique remote id" do
66
- expect(sample_items_attributes).to all_ { have_unique(:remote_id).in(sample_items_attributes) }
66
+ expect(sample_items_attributes).to all(have_unique(:remote_id).in(sample_items_attributes))
67
67
  end
68
68
 
69
69
  it "should have items with unique uris" do
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # version.rb
4
4
  #
5
- # Copyright (c) 2010-2014 by Philippe Bourgau. All rights reserved.
5
+ # Copyright (c) 2010-2014, 2016 by Philippe Bourgau. All rights reserved.
6
6
  #
7
7
  # This library is free software; you can redistribute it and/or
8
8
  # modify it under the terms of the GNU Lesser General Public
@@ -20,5 +20,5 @@
20
20
  # MA 02110-1301 USA
21
21
 
22
22
  module Storexplore
23
- VERSION = "0.4.0"
23
+ VERSION = "0.5.0"
24
24
  end
@@ -0,0 +1,84 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # ikea.rb
4
+ #
5
+ # Copyright (c) 2015 by Philippe Bourgau. All rights reserved.
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation; either
10
+ # version 3.0 of the License, or (at your option) any later version.
11
+ #
12
+ # This library is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public
18
+ # License along with this library; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ # MA 02110-1301 USA
21
+
22
+ # Please note that I don't intend to maintain this scrapper definition :)
23
+
24
+ require_relative "../lib/storexplore"
25
+
26
+ Storexplore::Api.define 'ikea.com/us' do
27
+
28
+ categories '.departmentLinkBlock a' do
29
+ attributes do
30
+ { :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
31
+ end
32
+
33
+ categories '.departmentLinks a' do
34
+ attributes do
35
+ { :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
36
+ end
37
+
38
+ categories 'a.categoryName' do
39
+ attributes do
40
+ { :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
41
+ end
42
+
43
+ items '.productDetails > a' do
44
+ attributes do
45
+ {
46
+ :name => page.get_one('#name').content.strip,
47
+ :type => page.get_one('#type').content.strip,
48
+ :price => page.get_one('#price1').content.strip.sub('$','').to_f,
49
+ :salesArgs => page.get_one('#salesArg').content.strip,
50
+ :image => page.get_one('#productImg').attributes['src'].content,
51
+ :ikea_id => page.uri.to_s.match("^.*\/([0-9]+)\/?$").captures.first
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+
61
+ Storexplore::Api.browse('http://www.ikea.com/us/en').categories.take(1).each do |category|
62
+
63
+ puts "category: #{category.title.strip}"
64
+ puts "attributes: #{category.attributes}"
65
+
66
+ category.categories.take(2).each do |sub_category|
67
+
68
+ puts " category: #{sub_category.title.strip}"
69
+ puts " attributes: #{sub_category.attributes}"
70
+
71
+ sub_category.categories.take(3).each do |sub_sub_category|
72
+
73
+ puts " category: #{sub_sub_category.title.strip}"
74
+ puts " attributes: #{sub_sub_category.attributes}"
75
+
76
+ sub_sub_category.items.take(4).each do |item|
77
+
78
+ puts " item: #{item.title.strip}"
79
+ puts " attributes: #{item.attributes}"
80
+
81
+ end
82
+ end
83
+ end
84
+ end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # memory_usage_spec.rb
4
4
  #
5
- # Copyright (c) 2011-2014 by Philippe Bourgau. All rights reserved.
5
+ # Copyright (c) 2011-2015 by Philippe Bourgau. All rights reserved.
6
6
  #
7
7
  # This library is free software; you can redistribute it and/or
8
8
  # modify it under the terms of the GNU Lesser General Public
@@ -89,6 +89,7 @@ module Storexplore
89
89
  end
90
90
 
91
91
  def current_living_objects
92
+ GC.start
92
93
  object_counts = ObjectSpace.count_objects
93
94
  object_counts[:TOTAL] - object_counts[:FREE]
94
95
  end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # walker_page_spec.rb
4
4
  #
5
- # Copyright (c) 2011-2014 by Philippe Bourgau. All rights reserved.
5
+ # Copyright (c) 2011-2014, 2016 by Philippe Bourgau. All rights reserved.
6
6
  #
7
7
  # This library is free software; you can redistribute it and/or
8
8
  # modify it under the terms of the GNU Lesser General Public
@@ -97,7 +97,7 @@ module Storexplore
97
97
  end
98
98
 
99
99
  it "links to other instances of WalkerPage" do
100
- expect(@page.search_links("#myself").map { |link| link.get }).to all_ {be_instance_of(WalkerPage)}
100
+ expect(@page.search_links("#myself").map { |link| link.get }).to all(be_instance_of(WalkerPage))
101
101
  end
102
102
 
103
103
  it "knows the text of the links" do
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # spec_helper.rb
4
4
  #
5
- # Copyright (c) 2013-2014 by Philippe Bourgau. All rights reserved.
5
+ # Copyright (c) 2013-2014, 2016 by Philippe Bourgau. All rights reserved.
6
6
  #
7
7
  # This library is free software; you can redistribute it and/or
8
8
  # modify it under the terms of the GNU Lesser General Public
@@ -19,12 +19,11 @@
19
19
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
20
  # MA 02110-1301 USA
21
21
 
22
- require 'codeclimate-test-reporter'
23
- CodeClimate::TestReporter.start
22
+ require 'simplecov'
23
+ SimpleCov.start
24
24
 
25
25
  require 'fakeweb'
26
26
  require 'rspec/collection_matchers'
27
- require 'spec_combos'
28
27
  require 'storexplore'
29
28
  require 'storexplore/testing'
30
29
 
@@ -23,8 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler"
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "guard-rspec"
26
- spec.add_development_dependency "spec_combos"
27
26
  spec.add_development_dependency "fakeweb"
28
27
  spec.add_development_dependency "rspec-collection_matchers"
28
+ spec.add_development_dependency "simplecov"
29
29
  spec.add_development_dependency "codeclimate-test-reporter"
30
30
  end
metadata CHANGED
@@ -1,146 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: storexplore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philou
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain:
11
- - |
12
- -----BEGIN CERTIFICATE-----
13
- MIIDQjCCAiqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBHMRkwFwYDVQQDDBBwaGls
14
- aXBwZS5ib3VyZ2F1MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/Is
15
- ZAEZFgNjb20wHhcNMTQxMTA0MDUwNTA4WhcNMTUxMTA0MDUwNTA4WjBHMRkwFwYD
16
- VQQDDBBwaGlsaXBwZS5ib3VyZ2F1MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzAR
17
- BgoJkiaJk/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
18
- AQC8CpoqZwEbzXr55EUxdSplgn0MYZ9xPGO/XmRa8bD63n+JYWF0AS+mj452ZY18
19
- rwM+yKrKhtsA+aJJdlOafgIUnY5SrZOr7v7kgc6T2YNoUj+M00Um2jv+shQbOtV6
20
- qGp0Jw1HfPNUMVa+3pXZyAGCecN6rTnsZJIuW6KNaJUq6lEMVXanoTHgAKrH5aHd
21
- Y6ofwQL86d6LDkC1S4p86iMUWvF34w8h5ItVo+JKlPRR22rzsK/ZKgNH3lfjbS6i
22
- JWqPva70rL2xz5kCVn6DL7XhNZtqnAO4kvCQyQeWezvcoGXEnbHacKky7B+/WKec
23
- OIWEwedl6j+X0OD5OYki3QaTAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQD
24
- AgSwMB0GA1UdDgQWBBSZy8+NDp7v3X6S0oqVORYE8uli5jANBgkqhkiG9w0BAQUF
25
- AAOCAQEAjTpuKjUclY0kNioKIcwD9nEkAwxeGiMNrY2zc7FfabSVhNKa0GafjHiz
26
- 6STN4S4j03wgmD8YMnA6uqQBSCgb3mcySr9sfglxub4sC9c3Ma+A3G7JEE+KPeLE
27
- gcVYqRPSgVV5naFYaFu4HK0o8ZY8smY30BM3uFmW3cQ9cTKNtaqgUQ177fMmXuYa
28
- QOTMg5o5t1YFdpg/RwQNoUX5DyAC8gWJY8vlVJbiIKvvB0z4+o7d5nEuuE3jvKQr
29
- LKjGZUoe+A3/FKYHWLPZAArCXrXLhpjAfopLBNmOAju0e30ObcjPQDWcj7z5jfJl
30
- ILiFgo6hdHrp/tFaDv14PiMRm6sZaQ==
31
- -----END CERTIFICATE-----
32
- date: 2014-11-05 00:00:00.000000000 Z
10
+ cert_chain: []
11
+ date: 2016-12-17 00:00:00.000000000 Z
33
12
  dependencies:
34
13
  - !ruby/object:Gem::Dependency
35
14
  name: mechanize
36
15
  requirement: !ruby/object:Gem::Requirement
37
16
  requirements:
38
- - - ~>
17
+ - - "~>"
39
18
  - !ruby/object:Gem::Version
40
19
  version: '2.0'
41
20
  type: :runtime
42
21
  prerelease: false
43
22
  version_requirements: !ruby/object:Gem::Requirement
44
23
  requirements:
45
- - - ~>
24
+ - - "~>"
46
25
  - !ruby/object:Gem::Version
47
26
  version: '2.0'
48
27
  - !ruby/object:Gem::Dependency
49
28
  name: bundler
50
29
  requirement: !ruby/object:Gem::Requirement
51
30
  requirements:
52
- - - '>='
31
+ - - ">="
53
32
  - !ruby/object:Gem::Version
54
33
  version: '0'
55
34
  type: :development
56
35
  prerelease: false
57
36
  version_requirements: !ruby/object:Gem::Requirement
58
37
  requirements:
59
- - - '>='
38
+ - - ">="
60
39
  - !ruby/object:Gem::Version
61
40
  version: '0'
62
41
  - !ruby/object:Gem::Dependency
63
42
  name: rake
64
43
  requirement: !ruby/object:Gem::Requirement
65
44
  requirements:
66
- - - '>='
45
+ - - ">="
67
46
  - !ruby/object:Gem::Version
68
47
  version: '0'
69
48
  type: :development
70
49
  prerelease: false
71
50
  version_requirements: !ruby/object:Gem::Requirement
72
51
  requirements:
73
- - - '>='
52
+ - - ">="
74
53
  - !ruby/object:Gem::Version
75
54
  version: '0'
76
55
  - !ruby/object:Gem::Dependency
77
56
  name: guard-rspec
78
57
  requirement: !ruby/object:Gem::Requirement
79
58
  requirements:
80
- - - '>='
59
+ - - ">="
81
60
  - !ruby/object:Gem::Version
82
61
  version: '0'
83
62
  type: :development
84
63
  prerelease: false
85
64
  version_requirements: !ruby/object:Gem::Requirement
86
65
  requirements:
87
- - - '>='
66
+ - - ">="
88
67
  - !ruby/object:Gem::Version
89
68
  version: '0'
90
69
  - !ruby/object:Gem::Dependency
91
- name: spec_combos
70
+ name: fakeweb
92
71
  requirement: !ruby/object:Gem::Requirement
93
72
  requirements:
94
- - - '>='
73
+ - - ">="
95
74
  - !ruby/object:Gem::Version
96
75
  version: '0'
97
76
  type: :development
98
77
  prerelease: false
99
78
  version_requirements: !ruby/object:Gem::Requirement
100
79
  requirements:
101
- - - '>='
80
+ - - ">="
102
81
  - !ruby/object:Gem::Version
103
82
  version: '0'
104
83
  - !ruby/object:Gem::Dependency
105
- name: fakeweb
84
+ name: rspec-collection_matchers
106
85
  requirement: !ruby/object:Gem::Requirement
107
86
  requirements:
108
- - - '>='
87
+ - - ">="
109
88
  - !ruby/object:Gem::Version
110
89
  version: '0'
111
90
  type: :development
112
91
  prerelease: false
113
92
  version_requirements: !ruby/object:Gem::Requirement
114
93
  requirements:
115
- - - '>='
94
+ - - ">="
116
95
  - !ruby/object:Gem::Version
117
96
  version: '0'
118
97
  - !ruby/object:Gem::Dependency
119
- name: rspec-collection_matchers
98
+ name: simplecov
120
99
  requirement: !ruby/object:Gem::Requirement
121
100
  requirements:
122
- - - '>='
101
+ - - ">="
123
102
  - !ruby/object:Gem::Version
124
103
  version: '0'
125
104
  type: :development
126
105
  prerelease: false
127
106
  version_requirements: !ruby/object:Gem::Requirement
128
107
  requirements:
129
- - - '>='
108
+ - - ">="
130
109
  - !ruby/object:Gem::Version
131
110
  version: '0'
132
111
  - !ruby/object:Gem::Dependency
133
112
  name: codeclimate-test-reporter
134
113
  requirement: !ruby/object:Gem::Requirement
135
114
  requirements:
136
- - - '>='
115
+ - - ">="
137
116
  - !ruby/object:Gem::Version
138
117
  version: '0'
139
118
  type: :development
140
119
  prerelease: false
141
120
  version_requirements: !ruby/object:Gem::Requirement
142
121
  requirements:
143
- - - '>='
122
+ - - ">="
144
123
  - !ruby/object:Gem::Version
145
124
  version: '0'
146
125
  description: A declarative scrapping DSL that lets one define directory like apis
@@ -151,14 +130,16 @@ executables: []
151
130
  extensions: []
152
131
  extra_rdoc_files: []
153
132
  files:
154
- - .gitignore
155
- - .rspec
156
- - .travis.yml
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".travis.yml"
157
136
  - Gemfile
158
137
  - Guardfile
159
138
  - LICENSE
160
139
  - README.md
161
140
  - Rakefile
141
+ - docker-compose.yml
142
+ - ikea.jpg
162
143
  - lib/storexplore.rb
163
144
  - lib/storexplore/api.rb
164
145
  - lib/storexplore/array_utils.rb
@@ -183,6 +164,7 @@ files:
183
164
  - lib/storexplore/walker.rb
184
165
  - lib/storexplore/walker_page.rb
185
166
  - lib/storexplore/walker_page_error.rb
167
+ - samples/ikea.rb
186
168
  - spec/lib/storexplore/api_spec.rb
187
169
  - spec/lib/storexplore/dsl_spec.rb
188
170
  - spec/lib/storexplore/store_walker_page_spec_fixture.html
@@ -203,17 +185,17 @@ require_paths:
203
185
  - lib
204
186
  required_ruby_version: !ruby/object:Gem::Requirement
205
187
  requirements:
206
- - - '>='
188
+ - - ">="
207
189
  - !ruby/object:Gem::Version
208
190
  version: '0'
209
191
  required_rubygems_version: !ruby/object:Gem::Requirement
210
192
  requirements:
211
- - - '>='
193
+ - - ">="
212
194
  - !ruby/object:Gem::Version
213
195
  version: '0'
214
196
  requirements: []
215
197
  rubyforge_project:
216
- rubygems_version: 2.0.3
198
+ rubygems_version: 2.6.8
217
199
  signing_key:
218
200
  specification_version: 4
219
201
  summary: Online store scraping library
Binary file
data.tar.gz.sig DELETED
Binary file
metadata.gz.sig DELETED
Binary file