watchmob 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/watchmob +30 -0
- data/lib/watchmob.rb +10 -0
- data/lib/watchmob/aukro_page.rb +57 -0
- data/lib/watchmob/error.rb +6 -0
- data/lib/watchmob/gsmarena_page.rb +86 -0
- data/lib/watchmob/gsmarena_search_page.rb +33 -0
- data/lib/watchmob/heureka_page.rb +69 -0
- data/lib/watchmob/heureka_search_page.rb +31 -0
- data/lib/watchmob/log.rb +36 -0
- data/lib/watchmob/page.rb +17 -0
- data/lib/watchmob/smartphone.rb +112 -0
- data/lib/watchmob/view_helpers.rb +15 -0
- data/lib/watchmob/watchlist.haml +63 -0
- data/lib/watchmob/watchlist.rb +47 -0
- metadata +118 -0
data/bin/watchmob
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
|
3
|
+
require 'json'
|
4
|
+
require 'watchmob'
|
5
|
+
|
6
|
+
if ARGV.size >= 1
|
7
|
+
json = JSON.parse(File.read(ARGV[0]))
|
8
|
+
else
|
9
|
+
STDERR.puts "Use: #$0 input.json <output.html>"
|
10
|
+
exit 1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Watchmob::Log.output = STDERR
|
15
|
+
watchlist = Watchmob::Watchlist.new(json)
|
16
|
+
watchlist.sort_by! :battery_capacity
|
17
|
+
|
18
|
+
if ARGV.size >= 2
|
19
|
+
output = File.open(ARGV[1], "w")
|
20
|
+
else
|
21
|
+
output = STDOUT
|
22
|
+
end
|
23
|
+
|
24
|
+
output.write(watchlist.to_html)
|
25
|
+
rescue Watchmob::WatchmobError => e
|
26
|
+
Watchmob::Log.error(e)
|
27
|
+
exit 2
|
28
|
+
ensure
|
29
|
+
output.close if output
|
30
|
+
end
|
data/lib/watchmob.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'watchmob/log'
|
2
|
+
require 'watchmob/error'
|
3
|
+
require 'watchmob/watchlist'
|
4
|
+
require 'watchmob/page'
|
5
|
+
require 'watchmob/smartphone'
|
6
|
+
require 'watchmob/aukro_page'
|
7
|
+
require 'watchmob/heureka_page'
|
8
|
+
require 'watchmob/heureka_search_page'
|
9
|
+
require 'watchmob/gsmarena_page'
|
10
|
+
require 'watchmob/gsmarena_search_page'
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Watchmob
|
3
|
+
class AukroPage < Page
|
4
|
+
def finished?
|
5
|
+
not document.at_css("#itemFinishBox2").nil?
|
6
|
+
end
|
7
|
+
|
8
|
+
def price
|
9
|
+
if finished?
|
10
|
+
e = document.at_css("#itemFinishBox2 .left:first-child strong")
|
11
|
+
else
|
12
|
+
e = document.at_css(".price")
|
13
|
+
end
|
14
|
+
e.inner_text.gsub(/\s+/, "").gsub(",", ".").to_f
|
15
|
+
end
|
16
|
+
|
17
|
+
def deadline
|
18
|
+
document.at_css(".timeInfo").inner_text.match(
|
19
|
+
/\(([[:alpha:]]+),\s+(\d+)\s+([[:alpha:]]+),\s+(\d+):(\d+):(\d+)/
|
20
|
+
) do |md|
|
21
|
+
text, weekday_name, month_day, month_name, hours, minutes, seconds = *md.to_a
|
22
|
+
DateTime.new(
|
23
|
+
Time.now.year,
|
24
|
+
month_name_to_number(month_name),
|
25
|
+
month_day.to_i,
|
26
|
+
hours.to_i,
|
27
|
+
minutes.to_i,
|
28
|
+
seconds.to_i,
|
29
|
+
'+1'
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def month_name_to_number(month_name)
|
35
|
+
case month_name
|
36
|
+
when "ledna" then 1
|
37
|
+
when "února" then 2
|
38
|
+
when "března" then 3
|
39
|
+
when "dubna" then 4
|
40
|
+
when "května" then 5
|
41
|
+
when "června" then 6
|
42
|
+
when "července" then 7
|
43
|
+
when "srpna" then 8
|
44
|
+
when "září" then 9
|
45
|
+
when "října" then 10
|
46
|
+
when "listopadu" then 11
|
47
|
+
when "prosince" then 12
|
48
|
+
else
|
49
|
+
require 'pry'
|
50
|
+
pry binding
|
51
|
+
raise AukroDateError, "Unknown month name #{month_name.inspect}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'andand'
|
2
|
+
require 'watchmob/page'
|
3
|
+
|
4
|
+
module Watchmob
|
5
|
+
class GSMArenaPage < Page
|
6
|
+
def self.find(phrase)
|
7
|
+
search = GSMArenaSearchPage.search(phrase)
|
8
|
+
uri = search.first_result_uri
|
9
|
+
new(uri)
|
10
|
+
end
|
11
|
+
|
12
|
+
def title
|
13
|
+
"GSMArena"
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
document.at_css("h1").andand.inner_text
|
18
|
+
end
|
19
|
+
|
20
|
+
def mass
|
21
|
+
property "Weight" do |text|
|
22
|
+
text.match /(\d+)\s*g/ do |md|
|
23
|
+
return md[1].to_f
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def battery_capacity
|
29
|
+
property "Battery" do |text|
|
30
|
+
text.match /(\d+)\s*mAh/i do |md|
|
31
|
+
return md[1].to_f
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def stand_by
|
37
|
+
property "Stand-by" do |text|
|
38
|
+
average_time text
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def talk_time
|
43
|
+
property "Talk time" do |text|
|
44
|
+
average_time text
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def average_time(text)
|
49
|
+
minutes = text.scan(/(\d+)\s*h\s*(\d+\s*min)?/).map do |hours, mins=0|
|
50
|
+
hours.to_f * 60 + mins.to_f
|
51
|
+
end
|
52
|
+
|
53
|
+
unless minutes.empty?
|
54
|
+
sum = minutes.inject :+
|
55
|
+
return sum.to_f / minutes.size
|
56
|
+
end
|
57
|
+
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def autofocus
|
62
|
+
property "Primary" do |text|
|
63
|
+
!!(text =~ /autofocus/)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def property(name)
|
68
|
+
found = nil
|
69
|
+
document.css("#specs-list tr").each do |tr|
|
70
|
+
cells = [tr.at_css("th"), tr.at_css(".ttl")]
|
71
|
+
if cells.any? { |c| c.andand.inner_text.to_s.strip == name }
|
72
|
+
value = tr.at_css(".nfo").inner_text
|
73
|
+
|
74
|
+
unless value.nil?
|
75
|
+
raise PropertyError, "Property named #{name} has been matched " +
|
76
|
+
"more than once on GSM arena page #{uri}" if found
|
77
|
+
found = yield value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
found
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'watchmob/page'
|
2
|
+
|
3
|
+
module Watchmob
|
4
|
+
class GSMArenaSearchPage < Page
|
5
|
+
def self.search(phrase)
|
6
|
+
encoded_phrase = URI.encode_www_form_component(phrase)
|
7
|
+
new("http://www.gsmarena.com/results.php3?sQuickSearch=no&sName=#{encoded_phrase}", phrase)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(uri, phrase = nil)
|
11
|
+
super(uri)
|
12
|
+
@phrase = phrase
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :phrase
|
16
|
+
|
17
|
+
def first_result_uri
|
18
|
+
if document.at_css("#specs-list")
|
19
|
+
uri
|
20
|
+
else
|
21
|
+
path = document.css("#mid-col .makers li a").
|
22
|
+
map { |a| a.attr("href") }.
|
23
|
+
first
|
24
|
+
|
25
|
+
if path
|
26
|
+
URI.parse("http://www.gsmarena.com/#{path}")
|
27
|
+
else
|
28
|
+
raise NotFoundError, "There were no phones for #{phrase.inspect} on GSM arena"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'andand'
|
2
|
+
require 'watchmob/page'
|
3
|
+
|
4
|
+
module Watchmob
|
5
|
+
class HeurekaPage < Page
|
6
|
+
def self.find(name)
|
7
|
+
search = HeurekaSearchPage.search(name)
|
8
|
+
uri = search.first_result_uri
|
9
|
+
uri.path += "/specifikace/"
|
10
|
+
new(uri)
|
11
|
+
end
|
12
|
+
|
13
|
+
def title
|
14
|
+
"Heureka"
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
document.at_css(".main-info h2").andand.inner_text
|
19
|
+
end
|
20
|
+
|
21
|
+
def mass
|
22
|
+
param_value(1607).andand.to_f
|
23
|
+
end
|
24
|
+
|
25
|
+
def battery_capacity
|
26
|
+
capacity = param_value(1615).andand.to_f
|
27
|
+
if !capacity.nil? and capacity <= 10
|
28
|
+
# this is a common mistake in Heureka specs (1.3 mAh instead of 1300 mAh)
|
29
|
+
capacity * 1000
|
30
|
+
else
|
31
|
+
capacity
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def stand_by
|
36
|
+
param_value_to_min(1616).andand.to_f
|
37
|
+
end
|
38
|
+
|
39
|
+
def talk_time
|
40
|
+
param_value_to_min(1617).andand.to_f
|
41
|
+
end
|
42
|
+
|
43
|
+
def autofocus
|
44
|
+
param_value(3688).andand.eql? "ano"
|
45
|
+
end
|
46
|
+
|
47
|
+
def param_value_to_min(param)
|
48
|
+
value = param_value(param).andand.to_f
|
49
|
+
case unit = param_unit(param)
|
50
|
+
when /hodin/
|
51
|
+
value * 60
|
52
|
+
when /min/
|
53
|
+
value
|
54
|
+
when nil
|
55
|
+
nil
|
56
|
+
else
|
57
|
+
raise RuntimeError, "Unknown unit #{unit}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def param_value(param)
|
62
|
+
document.at_css("#param-value-#{param}").andand.inner_text
|
63
|
+
end
|
64
|
+
|
65
|
+
def param_unit(param)
|
66
|
+
document.at_css("#param-unit-#{param}").andand.inner_text
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'watchmob/page'
|
3
|
+
|
4
|
+
module Watchmob
|
5
|
+
class HeurekaSearchPage < Page
|
6
|
+
def self.search(phrase)
|
7
|
+
encoded_phrase = URI.encode_www_form_component(phrase)
|
8
|
+
new("http://mobilni-telefony.heureka.cz/f:q:#{encoded_phrase}", phrase)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(uri, phrase = nil)
|
12
|
+
super(uri)
|
13
|
+
@phrase = phrase
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :phrase
|
17
|
+
|
18
|
+
def first_result_uri
|
19
|
+
if document.at_css("#product-container")
|
20
|
+
found_uri = document.css("#product-container .p").
|
21
|
+
map { |search_result| URI.parse(search_result.at_css("h2 a").attr("href")) }.
|
22
|
+
first
|
23
|
+
|
24
|
+
return found_uri unless found_uri.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
raise NotFoundError, "There were no smartphones for #{phrase.inspect} on Heureka"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
data/lib/watchmob/log.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Watchmob
|
2
|
+
module Log
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def error(msg)
|
6
|
+
show msg
|
7
|
+
end
|
8
|
+
|
9
|
+
def info(msg)
|
10
|
+
show msg
|
11
|
+
end
|
12
|
+
|
13
|
+
def waiting(msg)
|
14
|
+
show "#{msg}..."
|
15
|
+
begin
|
16
|
+
yield
|
17
|
+
rescue Exception => e
|
18
|
+
show " #{msg} -> #{e.class.to_s}"
|
19
|
+
raise
|
20
|
+
else
|
21
|
+
show " #{msg} -> OK"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_accessor :output
|
26
|
+
|
27
|
+
@output = STDERR
|
28
|
+
@print_mutex = Mutex.new
|
29
|
+
|
30
|
+
def show(msg)
|
31
|
+
@print_mutex.synchronize do
|
32
|
+
output.puts(msg)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'uri'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
module Watchmob
|
6
|
+
class Page
|
7
|
+
def initialize(uri)
|
8
|
+
@uri = uri
|
9
|
+
Log.waiting("get #@uri") do
|
10
|
+
@document = Nokogiri::HTML.parse(open(uri))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :uri
|
15
|
+
attr_reader :document
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'watchmob/gsmarena_page'
|
3
|
+
require 'watchmob/heureka_page'
|
4
|
+
|
5
|
+
module Watchmob
|
6
|
+
class Smartphone
|
7
|
+
|
8
|
+
SPEC_PAGES = [HeurekaPage, GSMArenaPage]
|
9
|
+
|
10
|
+
def self.find(params)
|
11
|
+
unless params["aukro"] and params["phone"]
|
12
|
+
raise ArgumentError, "I want parameters 'aukro' and 'phone', got #{params.inspect}"
|
13
|
+
end
|
14
|
+
|
15
|
+
aukro_page = AukroPage.new(URI.parse(params["aukro"]))
|
16
|
+
spec_pages = SPEC_PAGES.map { |spec_page|
|
17
|
+
begin
|
18
|
+
spec_page.find(params["phone"])
|
19
|
+
rescue NotFoundError
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
}.select { |s| !s.nil? }
|
23
|
+
|
24
|
+
unless spec_pages.empty?
|
25
|
+
new(aukro_page, spec_pages)
|
26
|
+
else
|
27
|
+
raise NotFoundError, "Smartphone #{params["phone"]} <#{params["aukro"]}> was not found anywhere"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(aukro_page, spec_pages)
|
32
|
+
@aukro_page = aukro_page
|
33
|
+
@spec_pages = spec_pages
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :aukro_page
|
37
|
+
attr_reader :spec_pages
|
38
|
+
|
39
|
+
def name
|
40
|
+
@spec_pages.first.name
|
41
|
+
end
|
42
|
+
|
43
|
+
def aukro_finished?
|
44
|
+
@aukro_page.finished?
|
45
|
+
end
|
46
|
+
|
47
|
+
def aukro_price
|
48
|
+
@aukro_page.price
|
49
|
+
end
|
50
|
+
|
51
|
+
def aukro_deadline
|
52
|
+
@aukro_page.deadline
|
53
|
+
end
|
54
|
+
|
55
|
+
def aukro_uri
|
56
|
+
@aukro_page.uri
|
57
|
+
end
|
58
|
+
|
59
|
+
def mass
|
60
|
+
average :mass
|
61
|
+
end
|
62
|
+
|
63
|
+
def battery_capacity
|
64
|
+
average :battery_capacity
|
65
|
+
end
|
66
|
+
|
67
|
+
def stand_by
|
68
|
+
average :stand_by
|
69
|
+
end
|
70
|
+
|
71
|
+
def talk_time
|
72
|
+
average :talk_time
|
73
|
+
end
|
74
|
+
|
75
|
+
def autofocus
|
76
|
+
boolean :autofocus
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def average(property)
|
82
|
+
values = property_values(property)
|
83
|
+
unless values.empty?
|
84
|
+
sum = values.inject(0) { |a,b| a + b }
|
85
|
+
sum / values.length.to_f
|
86
|
+
else
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def boolean(property)
|
92
|
+
values = property_values(property)
|
93
|
+
unless values.empty?
|
94
|
+
if values.all? { |v| !!v }
|
95
|
+
true
|
96
|
+
elsif values.all? { |v| !v }
|
97
|
+
false
|
98
|
+
else
|
99
|
+
raise PropertyError, "Property #{property} of #{name} has values #{values.inspect}"
|
100
|
+
+ ", expected all true or all false"
|
101
|
+
end
|
102
|
+
else
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def property_values(property)
|
108
|
+
@spec_pages.map(&property).select { |v| !v.nil? }
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Watchmob
|
2
|
+
module ViewHelpers
|
3
|
+
def format_datetime(time)
|
4
|
+
time.strftime("%Y-%m-%d %H:%M:%S")
|
5
|
+
end
|
6
|
+
|
7
|
+
def format_time_interval(seconds)
|
8
|
+
if seconds > 2*24*60*60
|
9
|
+
"#{(seconds / (24*60*60)).round} days"
|
10
|
+
else
|
11
|
+
"#{(seconds / (60*60)).round} hours"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%meta{:charset => "utf-8"}
|
5
|
+
%meta{:"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"}
|
6
|
+
%title Aukro smartphones comparsion
|
7
|
+
%style
|
8
|
+
:sass
|
9
|
+
table#phones
|
10
|
+
border-collapse: collapse
|
11
|
+
tbody tr:hover
|
12
|
+
background-color: #ddd
|
13
|
+
tbody tr.finished
|
14
|
+
font-style: italic
|
15
|
+
th
|
16
|
+
font-weight: bold
|
17
|
+
text-align: left
|
18
|
+
padding-left: 1em
|
19
|
+
td
|
20
|
+
text-align: right
|
21
|
+
padding-right: 1em
|
22
|
+
&.name
|
23
|
+
text-align: left
|
24
|
+
font-weight: bold
|
25
|
+
|
26
|
+
|
27
|
+
%body
|
28
|
+
%h1 Aukro smartphones comparsion
|
29
|
+
|
30
|
+
%table#phones
|
31
|
+
%thead
|
32
|
+
%tr
|
33
|
+
%th.name Name
|
34
|
+
%th.price Price
|
35
|
+
%th.mass Mass
|
36
|
+
%th.battery Battery
|
37
|
+
%th.talk-time Talk time
|
38
|
+
%th.stand-by Stand by
|
39
|
+
%th.autofocus Autofocus
|
40
|
+
%th.remaining-time Time
|
41
|
+
%th.deadline Deadline
|
42
|
+
%th.spec Spec
|
43
|
+
|
44
|
+
%tbody
|
45
|
+
- phones.each do |phone|
|
46
|
+
%tr{:class => phone.aukro_finished? ? "finished" : nil}
|
47
|
+
%td.name
|
48
|
+
%a{:href => phone.aukro_uri.to_s} #{phone.name}
|
49
|
+
%td #{phone.aukro_price} CZK
|
50
|
+
%td #{phone.mass} g
|
51
|
+
%td #{phone.battery_capacity} mAh
|
52
|
+
%td #{phone.talk_time} min
|
53
|
+
%td #{phone.stand_by / 60} h
|
54
|
+
%td #{phone.autofocus.nil? ? "" : (phone.autofocus ? "yes" : "no")}
|
55
|
+
%td #{format_time_interval(phone.aukro_deadline.to_time - Time.now)}
|
56
|
+
%td #{format_datetime(phone.aukro_deadline.to_time)}
|
57
|
+
%td
|
58
|
+
- phone.spec_pages.each do |spec|
|
59
|
+
%a{:href => spec.uri} #{spec.title}
|
60
|
+
|
61
|
+
#generated-at
|
62
|
+
Generated at #{format_datetime(Time.now)}
|
63
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'sass'
|
3
|
+
require 'haml'
|
4
|
+
|
5
|
+
require 'watchmob/view_helpers'
|
6
|
+
|
7
|
+
module Watchmob
|
8
|
+
class Watchlist
|
9
|
+
include ViewHelpers
|
10
|
+
|
11
|
+
HAML_TEMPLATE = File.expand_path("../watchlist.haml", __FILE__)
|
12
|
+
PHONE_TIMEOUT = 15.0
|
13
|
+
|
14
|
+
def initialize(json)
|
15
|
+
@phones = []
|
16
|
+
|
17
|
+
phone_threads = json.map do |phone_json|
|
18
|
+
params = if phone_json.is_a? Array
|
19
|
+
{"aukro" => phone_json[0], "phone" => phone_json[1]}
|
20
|
+
else
|
21
|
+
phone_json
|
22
|
+
end
|
23
|
+
|
24
|
+
Thread.new do
|
25
|
+
Thread.current.abort_on_exception = true
|
26
|
+
@phones << Smartphone.find(params)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Timeout.timeout(PHONE_TIMEOUT) do
|
31
|
+
phone_threads.each(&:join)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :phones
|
36
|
+
|
37
|
+
def sort_by!(property)
|
38
|
+
@phones.sort_by! { |phone| phone.aukro_page.uri.to_s }
|
39
|
+
@phones.sort_by! { |phone| phone.__send__(property) or 0 }
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_html
|
43
|
+
engine = Haml::Engine.new(File.read(HAML_TEMPLATE), :filename => HAML_TEMPLATE)
|
44
|
+
engine.render(self)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: watchmob
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jan Špaček
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: andand
|
16
|
+
requirement: &68961290 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *68961290
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: haml
|
27
|
+
requirement: &68960590 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.1'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *68960590
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: json
|
38
|
+
requirement: &68960200 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.6'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *68960200
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: nokogiri
|
49
|
+
requirement: &68959790 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.5'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *68959790
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: sass
|
60
|
+
requirement: &68958990 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '3.1'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *68958990
|
69
|
+
description: ! " Reads a simple JSON watchlist, loads auction information and\n phone
|
70
|
+
specifications from multiple web resources and displays\n the smartphones in clear
|
71
|
+
HTML file.\n"
|
72
|
+
email: patek.mail@gmail.com
|
73
|
+
executables:
|
74
|
+
- watchmob
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- ./lib/watchmob/aukro_page.rb
|
79
|
+
- ./lib/watchmob/heureka_page.rb
|
80
|
+
- ./lib/watchmob/smartphone.rb
|
81
|
+
- ./lib/watchmob/page.rb
|
82
|
+
- ./lib/watchmob/gsmarena_search_page.rb
|
83
|
+
- ./lib/watchmob/watchlist.haml
|
84
|
+
- ./lib/watchmob/log.rb
|
85
|
+
- ./lib/watchmob/view_helpers.rb
|
86
|
+
- ./lib/watchmob/error.rb
|
87
|
+
- ./lib/watchmob/gsmarena_page.rb
|
88
|
+
- ./lib/watchmob/heureka_search_page.rb
|
89
|
+
- ./lib/watchmob/watchlist.rb
|
90
|
+
- ./lib/watchmob.rb
|
91
|
+
- !binary |-
|
92
|
+
YmluL3dhdGNobW9i
|
93
|
+
homepage: http://github.com/honzasp/watchmob
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.8.17
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Watch smartphones on Aukro.cz and compare them
|
118
|
+
test_files: []
|