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 +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +2 -2
- data/README.md +120 -50
- data/docker-compose.yml +8 -0
- data/ikea.jpg +0 -0
- data/lib/storexplore/testing/api_shared_examples.rb +3 -3
- data/lib/storexplore/version.rb +2 -2
- data/samples/ikea.rb +84 -0
- data/spec/lib/storexplore/testing/memory_usage_spec.rb +2 -1
- data/spec/lib/storexplore/walker_page_spec.rb +2 -2
- data/spec/spec_helper.rb +3 -4
- data/storexplore.gemspec +1 -1
- metadata +31 -49
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17cba9cf042f031c9d29a00f36ddc74bd1a55bde
|
4
|
+
data.tar.gz: 5e4f2f3c4e5ee403527e1c2e0beb188c9536498b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a88009b403a3b8505104c25b020e01d246cd592140fa2ab43a4641143278588785391d6b33d74fb66f2c3efe12e48c743b3df4c1eed5c829fd4d746511107933
|
7
|
+
data.tar.gz: 0efe5547f14b84d8c17b91cca614a6f2577733240b38f191815b405ce50c1e6cf94f629c86e0052433c88d8b8ba476214893cfe026fe24efcf651d3a9de2234e
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -2,12 +2,32 @@
|
|
2
2
|
|
3
3
|
# Storexplore
|
4
4
|
|
5
|
-
|
5
|
+
Transform online stores into APIs !
|
6
6
|
|
7
|
-
##
|
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
|
-
|
10
|
-
|
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
|
-
|
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
|
-
|
36
|
-
selectors (css or xpath).
|
47
|
+
## Usage
|
37
48
|
|
38
|
-
|
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::
|
91
|
+
Storexplore::Api.define 'ikea.com/us' do
|
42
92
|
|
43
|
-
categories 'a
|
93
|
+
categories '.departmentLinkBlock a' do
|
44
94
|
attributes do
|
45
|
-
{ :name => page.get_one("
|
95
|
+
{ :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
|
46
96
|
end
|
47
97
|
|
48
|
-
categories 'a
|
98
|
+
categories '.departmentLinks a' do
|
49
99
|
attributes do
|
50
|
-
{ :name => page.get_one("
|
100
|
+
{ :name => page.get_one("#breadCrumbNew .activeLink a").content.strip }
|
51
101
|
end
|
52
102
|
|
53
|
-
|
103
|
+
categories 'a.categoryName' do
|
54
104
|
attributes do
|
55
|
-
{
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
70
|
-
|
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.
|
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.
|
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
|
-
|
89
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
###
|
206
|
+
### Testing Your Own Scrapper
|
136
207
|
|
137
|
-
Storexplore also ships with an rspec shared examples macro. It
|
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
|
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'
|
data/docker-compose.yml
ADDED
data/ikea.jpg
ADDED
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
|
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
|
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
|
data/lib/storexplore/version.rb
CHANGED
@@ -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.
|
23
|
+
VERSION = "0.5.0"
|
24
24
|
end
|
data/samples/ikea.rb
ADDED
@@ -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-
|
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
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -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 '
|
23
|
-
|
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
|
|
data/storexplore.gemspec
CHANGED
@@ -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
|
+
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:
|
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:
|
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:
|
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.
|
198
|
+
rubygems_version: 2.6.8
|
217
199
|
signing_key:
|
218
200
|
specification_version: 4
|
219
201
|
summary: Online store scraping library
|
checksums.yaml.gz.sig
DELETED
Binary file
|
data.tar.gz.sig
DELETED
Binary file
|
metadata.gz.sig
DELETED
Binary file
|