reckless 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 86f695a892834cf350aa6981ef710d7f9ad8cb14
4
+ data.tar.gz: b82ca334df61c7de41cc3db026f460beabe1e853
5
+ SHA512:
6
+ metadata.gz: 2ceeeb085d34c513e223aa5361eaea13809b113d97983ad7e6ea94737c876abe3e55c70deed8ca1b34c0c69541229d615feec0e874e5de3f3794601da0006c7c
7
+ data.tar.gz: ebb4f7980ad86c54b00f3bad118a498a164eeb3f91ae23ece37356307af360d6b3e1cd798e36ad0278cc8d434445dbc1efc9087f912795a54c6e082d251a7315
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ reckless (0.1.0)
5
+ faraday (~> 0.7)
6
+ json (~> 1.8)
7
+ nokogiri (~> 1.5)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ diff-lcs (1.2.5)
13
+ docile (1.1.0)
14
+ faraday (0.8.9)
15
+ multipart-post (~> 1.2.0)
16
+ json (1.8.1)
17
+ mini_portile (0.5.1)
18
+ multi_json (1.8.2)
19
+ multipart-post (1.2.0)
20
+ nokogiri (1.6.0)
21
+ mini_portile (~> 0.5.0)
22
+ rake (10.1.1)
23
+ rspec (2.14.1)
24
+ rspec-core (~> 2.14.0)
25
+ rspec-expectations (~> 2.14.0)
26
+ rspec-mocks (~> 2.14.0)
27
+ rspec-core (2.14.7)
28
+ rspec-expectations (2.14.4)
29
+ diff-lcs (>= 1.1.3, < 2.0)
30
+ rspec-mocks (2.14.4)
31
+ simplecov (0.8.2)
32
+ docile (~> 1.1.0)
33
+ multi_json
34
+ simplecov-html (~> 0.8.0)
35
+ simplecov-html (0.8.0)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ rake
42
+ reckless!
43
+ rspec (~> 2.13)
44
+ simplecov (~> 0.7)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Dan Sosedoff, <dan.sosedoff@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Reckless
2
+
3
+ Ruby client to Chicago's records store Reckless.com
4
+
5
+ ## Installation
6
+
7
+ Add it to your Gemfile:
8
+
9
+ ```
10
+ gem "reckless"
11
+ ```
12
+
13
+ Or install it manually:
14
+
15
+ ```
16
+ gem install reckless
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ See examples:
22
+
23
+ ```ruby
24
+ require "reckless"
25
+
26
+ # Search for records
27
+ search = Reckless.search("Nirvana")
28
+ search = Reckless.recent_arrivals
29
+
30
+ # Get search details
31
+ search.url # http://www.reckless.com/index.phpkeywords=&format=&cond=&store=&is_search=true&srch=Search
32
+ search.total_pages # 15
33
+ search.total_results # 450
34
+ search.page # 1
35
+ search.results # returns an array of results
36
+ ```
37
+
38
+ Each search result is a simple hash:
39
+
40
+ ```ruby
41
+ {
42
+ :artist => "13th Floor Elevators",
43
+ :title => "Easter Everywhere (180g, Reissue)",
44
+ :label => "International Artist",
45
+ :price => 11.99,
46
+ :type => "New LP",
47
+ :condition => "Good Condition",
48
+ :store => "Milwaukee Ave"
49
+ }
50
+ ```
51
+
52
+ ### Search options
53
+
54
+ - `page` - Specify a page to fetch. Defaults to `1`
55
+ - `format` - Choose record format: `LP`, `CD`, `DVD`. Defaults to `LP`
56
+ - `store` - Choose store: `Broadway`, `Milwaukee` or `Loop`. Does not have a default.
57
+
58
+ ## Testing
59
+
60
+ Execute test suite:
61
+
62
+ ```
63
+ bundle exec rake test
64
+ ```
65
+
66
+ ### License
67
+
68
+ The MIT License (MIT)
69
+
70
+ Copyright (c) 2014 Dan Sosedoff, <dan.sosedoff@gmail.com>
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:test) do |t|
6
+ t.pattern = "spec/**/*_spec.rb"
7
+ t.verbose = false
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,38 @@
1
+ module Reckless
2
+ class Client
3
+ BASE_URL = "http://www.reckless.com"
4
+
5
+ def search(keywords = "", options = {})
6
+ url = "#{BASE_URL}/index.php"
7
+
8
+ params = search_options(options).merge(
9
+ keywords: keywords,
10
+ is_search: true
11
+ )
12
+
13
+ Reckless::Search.new(url, params)
14
+ end
15
+
16
+ def recent_arrivals(options = {})
17
+ url = "#{BASE_URL}/new_arrivals.php"
18
+
19
+ params = search_options(options).merge(
20
+ period: options[:period] || 1,
21
+ style: options[:style] || 0
22
+ )
23
+
24
+ Reckless::Search.new(url, params)
25
+ end
26
+
27
+ private
28
+
29
+ def search_options(options)
30
+ {
31
+ page: options[:page] || 1,
32
+ format: options[:format] || "LP",
33
+ cond: options[:cond] || "",
34
+ store: options[:store] || ""
35
+ }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ module Reckless
2
+ module Normalizer
3
+ #
4
+ # Transform text from all caps to normal capitalized words
5
+ # Example: SOME GREAT BAND => Some Great Band
6
+ #
7
+ def normalize_text(text)
8
+ text.downcase.split.map(&:capitalize).join(" ")
9
+ end
10
+
11
+ #
12
+ # Transform artist name to normal representation
13
+ # Example: Beck, Jeff => Jeff Beck
14
+ #
15
+ def normalize_artist(text)
16
+ if text =~ /[\d]+,[\d]+/
17
+ text
18
+ else
19
+ text.gsub(/(([\w]+),\s?([\w]+))/) do |m|
20
+ m = "#{$3} #{$2}"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,61 @@
1
+ module Reckless
2
+ class ResultsParser
3
+ include Reckless::Normalizer
4
+
5
+ def initialize(body)
6
+ @document = Nokogiri::HTML(body)
7
+ end
8
+
9
+ def parse
10
+ find_result_elements.map do |node|
11
+ {
12
+ artist: normalize_artist(fetch_text(node, "artist")),
13
+ title: fetch_text(node, "title"),
14
+ label: fetch_text(node, "label"),
15
+ price: fetch_price(node.css("td").last),
16
+ type: fetch_type(node),
17
+ condition: fetch_condition(node),
18
+ store: fetch_store(node)
19
+ }
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def find_result_elements
26
+ @document.css("table.item")
27
+ end
28
+
29
+ def fetch_price(node)
30
+ node.to_s.scan(/\$([\d\.]+)/).flatten.first.to_f
31
+ end
32
+
33
+ def fetch_text(node, name)
34
+ element = node.css("span.#{name}").first
35
+ element ? normalize_text(element.children.first.text.strip) : ""
36
+ end
37
+
38
+ def fetch_type(node)
39
+ element = node.css("tr:last-child td b").first
40
+
41
+ if element
42
+ text = element.children.first.text.strip
43
+ text.scan(/^([\w]+ [\w]+)/).flatten.first
44
+ end
45
+ end
46
+
47
+ def fetch_condition(node)
48
+ element = node.css("tr:last-child td b").first
49
+
50
+ if element
51
+ text = element.children.first.text.gsub("Condition", "")
52
+ text.scan(/\(([\w\s]+)\)/).flatten.first.to_s.strip
53
+ end
54
+ end
55
+
56
+ def fetch_store(node)
57
+ match = node.to_s.scan(/<span style="color:#a33; font-weight: bold;">([\w\s]+).<\/span>/)
58
+ match.flatten.first
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,48 @@
1
+ module Reckless
2
+ class Search
3
+ attr_reader :url, :params
4
+ attr_reader :page, :total_results, :total_pages
5
+ attr_reader :results
6
+
7
+ def initialize(url, params = {})
8
+ @url = url
9
+ @params = params
10
+ @page = params[:page] || 1
11
+ @total_results = 0
12
+ @total_pages = 0
13
+ @results = []
14
+
15
+ fetch_page_contents
16
+ parse_results_count
17
+ parse_pagination
18
+ parse_results
19
+ end
20
+
21
+ private
22
+
23
+ def fetch_page_contents
24
+ @body = Faraday.get(@url, @params).body
25
+ end
26
+
27
+ def parse_results_count
28
+ matches = @body.scan(/<b>([\d]+) found.<\/b>/).flatten
29
+
30
+ unless matches.empty?
31
+ @total_results = matches.first.to_i
32
+ end
33
+ end
34
+
35
+ def parse_pagination
36
+ matches = @body.scan(/This is page ([\d]+) of ([\d]+)/).flatten
37
+
38
+ unless matches.empty?
39
+ @page = matches[0].to_i
40
+ @total_pages = matches[1].to_i
41
+ end
42
+ end
43
+
44
+ def parse_results
45
+ @results = Reckless::ResultsParser.new(@body).parse
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module Reckless
2
+ VERSION = "0.1.0"
3
+ end
data/lib/reckless.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "nokogiri"
2
+ require "faraday"
3
+
4
+ require "reckless/client"
5
+ require "reckless/search"
6
+ require "reckless/normalizer"
7
+ require "reckless/results_parser"
8
+ require "reckless/version"
9
+
10
+ module Reckless
11
+ def self.search(keywords = "", options = {})
12
+ Reckless::Client.new.search(keywords, options)
13
+ end
14
+
15
+ def self.recent_arrivals(options = {})
16
+ Reckless::Client.new.recent_arrivals(options)
17
+ end
18
+ end
data/reckless.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ require File.expand_path("../lib/reckless/version", __FILE__)
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "reckless"
5
+ spec.version = Reckless::VERSION
6
+ spec.summary = "Client for Reckless.com site"
7
+ spec.description = "Client for Reckless.com site"
8
+ spec.homepage = "http://github.com/sosedoff/reckless"
9
+ spec.authors = ["Dan Sosedoff"]
10
+ spec.email = ["dan.sosedoff@gmail.com"]
11
+
12
+ spec.add_dependency "json", "~> 1.8"
13
+ spec.add_dependency "faraday", "~> 0.7"
14
+ spec.add_dependency "nokogiri", "~> 1.5"
15
+
16
+ spec.add_development_dependency "rake"
17
+ spec.add_development_dependency "rspec", "~> 2.13"
18
+ spec.add_development_dependency "simplecov", "~> 0.7"
19
+
20
+ spec.files = `git ls-files`.split("\n")
21
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
23
+ spec.require_paths = ["lib"]
24
+ end