playwhe 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -16
- data/Gemfile +1 -2
- data/LICENSE +17 -18
- data/README.md +98 -89
- data/Rakefile +9 -2
- data/bin/playwhe +99 -74
- data/lib/playwhe.rb +76 -133
- data/lib/playwhe/fetcher.rb +25 -0
- data/lib/playwhe/get.rb +214 -0
- data/lib/playwhe/http.rb +39 -0
- data/lib/playwhe/parser.rb +15 -0
- data/lib/playwhe/result.rb +119 -0
- data/lib/playwhe/settings.rb +15 -0
- data/lib/playwhe/util.rb +11 -0
- data/lib/playwhe/version.rb +1 -1
- data/playwhe.gemspec +32 -24
- data/test/playwhe/fetcher_test.rb +72 -0
- data/test/playwhe/get_test.rb +187 -0
- data/test/playwhe/http/adapter_test.rb +46 -0
- data/test/playwhe/http/response_test.rb +39 -0
- data/test/playwhe/parser_test.rb +34 -0
- data/test/playwhe/result_test.rb +158 -0
- data/test/playwhe/settings_test.rb +13 -0
- data/test/playwhe/util_test.rb +37 -0
- data/test/test_helper.rb +6 -0
- metadata +97 -45
- data/data/playwhe.db +0 -0
- data/lib/playwhe/storage.rb +0 -109
- data/lib/playwhe/storage/models.rb +0 -92
data/lib/playwhe/http.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "http"
|
2
|
+
|
3
|
+
module PlayWhe
|
4
|
+
module HTTP
|
5
|
+
class Response
|
6
|
+
attr_reader :response
|
7
|
+
|
8
|
+
def initialize(response)
|
9
|
+
@response = response
|
10
|
+
end
|
11
|
+
|
12
|
+
def status
|
13
|
+
response.status
|
14
|
+
end
|
15
|
+
|
16
|
+
def body
|
17
|
+
response.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def ok?
|
21
|
+
status == 200
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Adapter
|
26
|
+
attr_reader :http_client
|
27
|
+
|
28
|
+
def initialize(http_client)
|
29
|
+
@http_client = http_client
|
30
|
+
end
|
31
|
+
|
32
|
+
def post(url, data)
|
33
|
+
Response.new http_client.post(url, form: data)
|
34
|
+
rescue ::HTTP::Error
|
35
|
+
raise PlayWhe::NetworkError
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PlayWhe
|
2
|
+
module Parser
|
3
|
+
PATTERN = /Draw #: <\/strong>(?<draw>\d+).*?Date: <\/strong>(?<day>\d{1,2})-(?<month>[A-Z]{3})-(?<year>\d{2}).*?Mark Drawn: <\/strong>(?<mark>\d+).*?Drawn at: <\/strong>(?<period>[A-Z]{2})/i
|
4
|
+
|
5
|
+
def self.parse(html_results)
|
6
|
+
html_results.to_enum(:scan, PATTERN).map do
|
7
|
+
m = $~
|
8
|
+
date = "#{m[:day]}-#{m[:month]}-#{m[:year]}"
|
9
|
+
|
10
|
+
Result.new \
|
11
|
+
draw: m[:draw], date: date, mark: m[:mark], period: m[:period]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "date"
|
2
|
+
|
3
|
+
module PlayWhe
|
4
|
+
class Result
|
5
|
+
attr_reader :draw, :date, :mark, :period
|
6
|
+
attr_reader :errors
|
7
|
+
|
8
|
+
def initialize(draw:, date:, mark:, period:)
|
9
|
+
@draw = draw
|
10
|
+
@date = date
|
11
|
+
@mark = mark
|
12
|
+
@period = period
|
13
|
+
clean
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
return true if other.equal?(self)
|
18
|
+
return false unless other.instance_of?(self.class)
|
19
|
+
draw == other.draw &&
|
20
|
+
date == other.date &&
|
21
|
+
mark == other.mark &&
|
22
|
+
period == other.period
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"#{draw},#{date ? date.strftime('%Y-%m-%d') : '-'},#{mark},#{period}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def is_valid?(context = nil)
|
30
|
+
validate(context)
|
31
|
+
no_errors?
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :context
|
37
|
+
|
38
|
+
def clean
|
39
|
+
clean_draw
|
40
|
+
clean_date
|
41
|
+
clean_mark
|
42
|
+
clean_period
|
43
|
+
end
|
44
|
+
|
45
|
+
def clean_draw
|
46
|
+
@draw = draw.to_i
|
47
|
+
end
|
48
|
+
|
49
|
+
def clean_date
|
50
|
+
@date = Date.parse(date.to_s) unless date.is_a?(Date)
|
51
|
+
rescue ArgumentError
|
52
|
+
@date = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def clean_mark
|
56
|
+
@mark = mark.to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
def clean_period
|
60
|
+
@period = period.to_s.upcase
|
61
|
+
end
|
62
|
+
|
63
|
+
def validate(context)
|
64
|
+
init(context)
|
65
|
+
validate_draw
|
66
|
+
validate_date
|
67
|
+
validate_mark
|
68
|
+
validate_period
|
69
|
+
end
|
70
|
+
|
71
|
+
def init(context)
|
72
|
+
@context = context
|
73
|
+
@errors = {}
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_error(name, message)
|
77
|
+
@errors[name] ||= []
|
78
|
+
@errors[name] << message
|
79
|
+
end
|
80
|
+
|
81
|
+
def no_errors?
|
82
|
+
errors.empty?
|
83
|
+
end
|
84
|
+
|
85
|
+
def validate_draw
|
86
|
+
add_error(:draw, "must be a positive integer") unless draw >= 1
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate_date
|
90
|
+
if date.nil?
|
91
|
+
add_error(:date, "must be a date")
|
92
|
+
else
|
93
|
+
if date < BIRTHDAY
|
94
|
+
add_error(:date, "must be greater than Play Whe's birthday")
|
95
|
+
end
|
96
|
+
|
97
|
+
if context && context.year && date.year != context.year
|
98
|
+
add_error(:date, "must be for the correct year (#{context.year})")
|
99
|
+
end
|
100
|
+
|
101
|
+
if context && context.month && date.month != context.month
|
102
|
+
add_error(:date, "must be for the correct month (#{context.month})")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def validate_mark
|
108
|
+
if mark < LOWEST_MARK || mark > HIGHEST_MARK
|
109
|
+
add_error(:mark, "must be between #{LOWEST_MARK} and #{HIGHEST_MARK} inclusive")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def validate_period
|
114
|
+
unless PERIODS.include?(period)
|
115
|
+
add_error(:period, "must be one of #{PERIODS.join(', ')}")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "dry-configurable"
|
2
|
+
|
3
|
+
module PlayWhe
|
4
|
+
class Settings
|
5
|
+
extend Dry::Configurable
|
6
|
+
|
7
|
+
setting :http do
|
8
|
+
setting :read_timeout, 5
|
9
|
+
setting :write_timeout, 5
|
10
|
+
setting :connect_timeout, 5
|
11
|
+
end
|
12
|
+
|
13
|
+
setting :url, "http://nlcb.co.tt/app/index.php/pwresults/playwhemonthsum"
|
14
|
+
end
|
15
|
+
end
|
data/lib/playwhe/util.rb
ADDED
data/lib/playwhe/version.rb
CHANGED
data/playwhe.gemspec
CHANGED
@@ -1,25 +1,33 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
require_relative "lib/playwhe/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.author = "Dwayne Crooks"
|
5
|
+
s.email = "dwayne@playwhesmarter.com"
|
6
|
+
|
7
|
+
s.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
|
8
|
+
A Ruby library for retrieving Play Whe results from the
|
9
|
+
National Lotteries Control Board (NLCB) website.
|
10
|
+
DESCRIPTION
|
11
|
+
|
12
|
+
s.summary = "Play Whe results should be easy to get"
|
13
|
+
s.homepage = "https://rubygems.org/gems/playwhe"
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
|
20
|
+
s.name = "playwhe"
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
s.version = PlayWhe::VERSION
|
23
|
+
|
24
|
+
s.required_ruby_version = ">= 2.0"
|
25
|
+
|
26
|
+
s.add_runtime_dependency "http", "~> 2.0", ">= 2.0.2"
|
27
|
+
s.add_runtime_dependency "dry-configurable", "~> 0"
|
28
|
+
|
29
|
+
s.add_development_dependency "bundler", "~> 1.0"
|
30
|
+
s.add_development_dependency "minitest", "~> 5.9"
|
31
|
+
s.add_development_dependency "pry-byebug", "~> 0"
|
32
|
+
s.add_development_dependency "rake", "~> 0"
|
25
33
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe PlayWhe::Fetcher do
|
4
|
+
let(:url) { "http://example.com" }
|
5
|
+
let(:year) { 2016 }
|
6
|
+
let(:month) { 1 }
|
7
|
+
|
8
|
+
describe "#get" do
|
9
|
+
it "makes a POST request" do
|
10
|
+
good_response = Object.new
|
11
|
+
def good_response.ok?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
def good_response.body
|
15
|
+
""
|
16
|
+
end
|
17
|
+
|
18
|
+
http_adapter = Minitest::Mock.new
|
19
|
+
http_adapter.expect \
|
20
|
+
:post, good_response, [url, { year: "16", month: "Jan" }]
|
21
|
+
|
22
|
+
fetcher = PlayWhe::Fetcher.new(http_adapter, url)
|
23
|
+
fetcher.get(year: year, month: month)
|
24
|
+
|
25
|
+
expect(http_adapter.verify).must_equal true
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "when the response is good" do
|
29
|
+
it "returns the body of the response" do
|
30
|
+
http_adapter = Object.new
|
31
|
+
def http_adapter.post(*args)
|
32
|
+
good_response = Object.new
|
33
|
+
def good_response.ok?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
def good_response.body
|
37
|
+
"results"
|
38
|
+
end
|
39
|
+
good_response
|
40
|
+
end
|
41
|
+
|
42
|
+
fetcher = PlayWhe::Fetcher.new(http_adapter, url)
|
43
|
+
|
44
|
+
expect(fetcher.get(year: year, month: month)).must_equal "results"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "when the response is bad" do
|
49
|
+
it "raises PlayWhe::BadResponseError" do
|
50
|
+
http_adapter = Object.new
|
51
|
+
def http_adapter.post(*args)
|
52
|
+
bad_response = Object.new
|
53
|
+
def bad_response.ok?
|
54
|
+
false
|
55
|
+
end
|
56
|
+
def bad_response.status
|
57
|
+
400
|
58
|
+
end
|
59
|
+
def bad_response.body
|
60
|
+
""
|
61
|
+
end
|
62
|
+
bad_response
|
63
|
+
end
|
64
|
+
|
65
|
+
fetcher = PlayWhe::Fetcher.new(http_adapter, url)
|
66
|
+
|
67
|
+
expect { fetcher.get(year: year, month: month) }.must_raise \
|
68
|
+
PlayWhe::BadResponseError
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class FakeFetcher
|
4
|
+
def initialize(start_year, years: 1, days: 1)
|
5
|
+
@results = []
|
6
|
+
|
7
|
+
draw = 1
|
8
|
+
end_year = start_year + years - 1
|
9
|
+
(start_year..end_year).each do |year|
|
10
|
+
(1..12).each do |month|
|
11
|
+
(1..days).each do |day|
|
12
|
+
date = Date.new(year, month, day)
|
13
|
+
|
14
|
+
PlayWhe::PERIODS.each do |period|
|
15
|
+
@results << make_result(draw, date, period)
|
16
|
+
draw += 1
|
17
|
+
end
|
18
|
+
|
19
|
+
# One bad result per day
|
20
|
+
@results << make_result(draw, date, "XM")
|
21
|
+
draw += 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@results.shuffle!
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(year:, month: nil)
|
30
|
+
results.select do |r|
|
31
|
+
if month.nil?
|
32
|
+
r[:date].year == year
|
33
|
+
else
|
34
|
+
r[:date].year == year && r[:date].month == month
|
35
|
+
end
|
36
|
+
end
|
37
|
+
.map { |r| as_html(r) }
|
38
|
+
.join
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :results
|
44
|
+
|
45
|
+
def as_html(result)
|
46
|
+
draw = result[:draw]
|
47
|
+
date = result[:date].strftime("%d-%b-%y")
|
48
|
+
mark = result[:mark]
|
49
|
+
period = result[:period]
|
50
|
+
|
51
|
+
"<strong> Draw #: </strong>#{draw}<br><strong> Date: </strong>#{date}<br><strong> Mark Drawn: </strong>#{mark}<br><strong> Drawn at: </strong>#{period}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def make_result(draw, date, period)
|
55
|
+
mark = (PlayWhe::LOWEST_MARK..PlayWhe::HIGHEST_MARK).to_a.shuffle.first
|
56
|
+
{ draw: draw, date: date, mark: mark, period: period }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe PlayWhe::Get do
|
61
|
+
let(:parser) { PlayWhe::Parser }
|
62
|
+
|
63
|
+
describe "#results_for_year" do
|
64
|
+
it "returns the results for the year of the given date in ascending order" do
|
65
|
+
fetcher = FakeFetcher.new(2014, years: 3) # 2014, 2015, 2016
|
66
|
+
get = PlayWhe::Get.new(fetcher: fetcher, parser: parser)
|
67
|
+
|
68
|
+
good_results, bad_results = get.results_for_year(Date.new(2015))
|
69
|
+
|
70
|
+
expect(good_results.length).must_equal(12 * 1 * 4)
|
71
|
+
|
72
|
+
expect(good_results.first.date).must_equal(Date.new(2015, 1, 1))
|
73
|
+
expect(good_results.first.period).must_equal("EM")
|
74
|
+
|
75
|
+
expect(good_results.last.date).must_equal(Date.new(2015, 12, 1))
|
76
|
+
expect(good_results.last.period).must_equal("PM")
|
77
|
+
|
78
|
+
expect(bad_results.length).must_equal(12 * 1)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#results_for_month" do
|
83
|
+
it "returns the results for the year/month of the given date in ascending order" do
|
84
|
+
fetcher = FakeFetcher.new(2015, days: 10)
|
85
|
+
get = PlayWhe::Get.new(fetcher: fetcher, parser: parser)
|
86
|
+
|
87
|
+
good_results, bad_results = get.results_for_month(Date.new(2015, 4))
|
88
|
+
|
89
|
+
expect(good_results.length).must_equal(10 * 4)
|
90
|
+
|
91
|
+
expect(good_results.first.date).must_equal(Date.new(2015, 4, 1))
|
92
|
+
expect(good_results.first.period).must_equal("EM")
|
93
|
+
|
94
|
+
expect(good_results.last.date).must_equal(Date.new(2015, 4, 10))
|
95
|
+
expect(good_results.last.period).must_equal("PM")
|
96
|
+
|
97
|
+
expect(bad_results.length).must_equal(10)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#results_for_day" do
|
102
|
+
it "returns the results for the year/month/day of the given date in ascending order" do
|
103
|
+
fetcher = FakeFetcher.new(2015, days: 10)
|
104
|
+
get = PlayWhe::Get.new(fetcher: fetcher, parser: parser)
|
105
|
+
|
106
|
+
good_results, bad_results = get.results_for_day(Date.new(2015, 10, 10))
|
107
|
+
|
108
|
+
expect(good_results.length).must_equal(4)
|
109
|
+
|
110
|
+
expect(good_results[0].date).must_equal(Date.new(2015, 10, 10))
|
111
|
+
expect(good_results[0].period).must_equal("EM")
|
112
|
+
|
113
|
+
expect(good_results[1].date).must_equal(Date.new(2015, 10, 10))
|
114
|
+
expect(good_results[1].period).must_equal("AM")
|
115
|
+
|
116
|
+
expect(good_results[2].date).must_equal(Date.new(2015, 10, 10))
|
117
|
+
expect(good_results[2].period).must_equal("AN")
|
118
|
+
|
119
|
+
expect(good_results[3].date).must_equal(Date.new(2015, 10, 10))
|
120
|
+
expect(good_results[3].period).must_equal("PM")
|
121
|
+
|
122
|
+
expect(bad_results.length).must_equal(1)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#most_recent" do
|
127
|
+
describe "when limit is a positive integer" do
|
128
|
+
it "returns limit results in most recent to least recent order" do
|
129
|
+
fetcher = FakeFetcher.new(2015)
|
130
|
+
get = PlayWhe::Get.new(fetcher: fetcher, parser: parser)
|
131
|
+
|
132
|
+
good_results, bad_results = get.most_recent(limit: 6)
|
133
|
+
|
134
|
+
expect(good_results.length).must_equal(4)
|
135
|
+
|
136
|
+
expect(good_results[0].date).must_equal(Date.new(2015, 12, 1))
|
137
|
+
expect(good_results[0].period).must_equal("PM")
|
138
|
+
|
139
|
+
expect(good_results[1].date).must_equal(Date.new(2015, 12, 1))
|
140
|
+
expect(good_results[1].period).must_equal("AN")
|
141
|
+
|
142
|
+
expect(good_results[2].date).must_equal(Date.new(2015, 12, 1))
|
143
|
+
expect(good_results[2].period).must_equal("AM")
|
144
|
+
|
145
|
+
expect(good_results[3].date).must_equal(Date.new(2015, 12, 1))
|
146
|
+
expect(good_results[3].period).must_equal("EM")
|
147
|
+
|
148
|
+
expect(bad_results.length).must_equal(2)
|
149
|
+
|
150
|
+
expect(bad_results[0].date).must_equal(Date.new(2015, 12, 1))
|
151
|
+
expect(bad_results[1].date).must_equal(Date.new(2015, 11, 1))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "#least_recent" do
|
157
|
+
describe "when limit is a positive integer" do
|
158
|
+
it "returns limit results in least recent to most recent order" do
|
159
|
+
fetcher = FakeFetcher.new(2015)
|
160
|
+
get = PlayWhe::Get.new(fetcher: fetcher, parser: parser)
|
161
|
+
|
162
|
+
good_results, bad_results = get.least_recent(limit: 6)
|
163
|
+
|
164
|
+
expect(good_results.length).must_equal(5)
|
165
|
+
|
166
|
+
expect(good_results[0].date).must_equal(Date.new(2015, 1, 1))
|
167
|
+
expect(good_results[0].period).must_equal("EM")
|
168
|
+
|
169
|
+
expect(good_results[1].date).must_equal(Date.new(2015, 1, 1))
|
170
|
+
expect(good_results[1].period).must_equal("AM")
|
171
|
+
|
172
|
+
expect(good_results[2].date).must_equal(Date.new(2015, 1, 1))
|
173
|
+
expect(good_results[2].period).must_equal("AN")
|
174
|
+
|
175
|
+
expect(good_results[3].date).must_equal(Date.new(2015, 1, 1))
|
176
|
+
expect(good_results[3].period).must_equal("PM")
|
177
|
+
|
178
|
+
expect(good_results[4].date).must_equal(Date.new(2015, 2, 1))
|
179
|
+
expect(good_results[4].period).must_equal("EM")
|
180
|
+
|
181
|
+
expect(bad_results.length).must_equal(1)
|
182
|
+
|
183
|
+
expect(bad_results[0].date).must_equal(Date.new(2015, 1, 1))
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|