playwhe 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,11 @@
1
+ module PlayWhe::Util
2
+ module_function
3
+
4
+ def normalize_year(year)
5
+ "%02d" % (year.to_i % 100)
6
+ end
7
+
8
+ def normalize_month(month)
9
+ Date::ABBR_MONTHNAMES[month.to_i]
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module PlayWhe
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,25 +1,33 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/playwhe/version', __FILE__)
3
-
4
- Gem::Specification.new do |gem|
5
- gem.authors = ["Dwayne R. Crooks"]
6
- gem.email = ["me@dwaynecrooks.com"]
7
- gem.description = %q{A ruby gem for retrieving and storing Play Whe results.
8
-
9
- The gem provides a ruby API and script for retrieving and storing Play Whe
10
- results from the National Lotteries Control Board (NLCB) website at
11
- http://www.nlcb.co.tt/.}
12
- gem.summary = %q{A ruby gem for retrieving and storing Play Whe results.}
13
- gem.homepage = "http://rubygems.org/gems/playwhe"
14
-
15
- gem.add_dependency('data_mapper', '~> 1.2.0')
16
- gem.add_dependency('dm-sqlite-adapter', '~> 1.2.0')
17
- gem.add_dependency('trollop', '~> 1.16.2')
18
-
19
- gem.files = `git ls-files`.split($\)
20
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
- gem.name = "playwhe"
23
- gem.require_paths = ["lib"]
24
- gem.version = PlayWhe::VERSION
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