rubbish_collection 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -20,6 +20,15 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ require 'ostruct'
24
+
25
+ address = OpenStruct.new :house_number => "43",
26
+ :street_name => "Redcross Way", :postcode => "SE1 1EY"
27
+ collection_times = RubbishCollection.times_at_address address
28
+ collection_times.each do |t|
29
+ puts t.to_s
30
+ end
31
+
23
32
  address = OpenStruct.new :house_number => "2",
24
33
  :street_name => "Beech Road", :postcode => "GU14 8EU"
25
34
  collection_times = RubbishCollection.times_at_address address
@@ -1,7 +1,12 @@
1
1
  require "rubbish_collection/version"
2
2
  require 'local_authority'
3
+ require 'runt'
3
4
 
4
5
  module RubbishCollection
6
+ DOMESTIC_RUBBISH = 'Domestic Rubbish'.freeze
7
+ DOMESTIC_RECYCLING = 'Domestic Recycling'.freeze
8
+ COMMUNAL_RECYCLING = 'Communal Recycling'.freeze
9
+
5
10
  class UnknownAdapter
6
11
  attr_accessor :local_authority
7
12
  private :local_authority=, :local_authority
@@ -15,64 +20,190 @@ module RubbishCollection
15
20
  end
16
21
  end
17
22
 
18
- class CollectionTimes
19
- attr_accessor :times
20
- private :times=, :times
23
+ class Collections
24
+ attr_accessor :collections
25
+ private :collections=, :collections
21
26
 
22
27
  def initialize
23
- self.times = []
28
+ self.collections = []
29
+ end
30
+
31
+ def << collection
32
+ collections << collection
24
33
  end
25
34
 
26
35
  def each
27
- times.each { |t| yield t }
36
+ upto(Time.now + (86400 * 31)).each { |t| yield t }
28
37
  end
29
- include Enumerable
38
+ include Comparable
30
39
 
31
- def << time
32
- times << time
40
+ def upto until_date
41
+ now = Time.now
42
+ collections.map { |c| c.realise now, until_date }.flatten.sort
33
43
  end
34
44
  end
35
45
 
36
- class CollectionTime
46
+ class Resolution
47
+ attr_accessor :name
48
+ private :name=
49
+
50
+ attr_accessor :step
51
+ private :step=
52
+
53
+ def initialize name, step
54
+ self.name = name
55
+ self.step = step
56
+ end
57
+
58
+ def <=> other
59
+ other.step <=> step
60
+ end
61
+ include Comparable
62
+
63
+ def match_resolution time
64
+ args = [ time.year, time.month, time.day, time.hour, time.min, time.sec, time.usec ]
65
+ case step
66
+ when 1
67
+ Runt::PDate.sec *args
68
+ when 60
69
+ Runt::PDate.min *args
70
+ when 3600
71
+ Runt::PDate.hour *args
72
+ when 86400
73
+ Runt::PDate.day *args
74
+ else
75
+ raise "Don't know how to represent a time with resolution of #{step}"
76
+ end
77
+ end
78
+
79
+ SECOND = new "Second", 1
80
+ MINUTE = new "Minute", 60
81
+ HOUR = new "Hour", 3600
82
+ DAY = new "Day", 86400
83
+ end
84
+
85
+ class Schedule
86
+ attr_accessor :condition
87
+ private :condition=, :condition
88
+
89
+ attr_accessor :resolution
90
+ private :resolution=
91
+
92
+ def initialize resolution
93
+ self.resolution = resolution
94
+ end
95
+
96
+ def self.day_of_week day_name
97
+ normalised_name = day_name[0,1].upcase + day_name[1..-1].downcase
98
+ day_const = Runt.const_get normalised_name
99
+ Runt::DIWeek.new day_const
100
+ end
101
+
102
+ def self.hour hour
103
+ Runt::REDay.new hour, 0, hour, 59, true
104
+ end
105
+
106
+ def add_rule rule
107
+ if condition.nil?
108
+ self.condition = rule
109
+ return
110
+ end
111
+ self.condition = condition & rule
112
+ end
113
+
114
+ def include? time
115
+ time_with_resolution = resolution.match_resolution time
116
+ condition.include? time_with_resolution
117
+ end
37
118
 
38
- attr_accessor :day
39
- private :day=, :day
119
+ def to_s
120
+ condition.to_s
121
+ end
122
+ end
123
+
124
+ class Collection
125
+ attr_accessor :pickup_type
126
+ private :pickup_type=
127
+
128
+ attr_accessor :schedule
129
+ private :schedule=, :schedule
130
+
131
+ def initialize pickup_type, schedule
132
+ self.pickup_type = pickup_type
133
+ self.schedule = schedule
134
+ end
135
+
136
+ def realise from, to
137
+ times = []
138
+ now = from
139
+ resolution = schedule.resolution
140
+ rem = now.to_i % resolution.step
141
+ diff = resolution.step - rem
142
+ now += diff
143
+ while now < to
144
+ if schedule.include? now
145
+ time = CollectionTime.new pickup_type, now, resolution
146
+ times << time
147
+ end
148
+ now += resolution.step
149
+ end
150
+ times
151
+ end
152
+
153
+ def to_s
154
+ [ pickup_type, schedule.to_s ].join ' - '
155
+ end
156
+ end
40
157
 
158
+ class CollectionTime
41
159
  attr_accessor :time
42
160
  private :time=, :time
43
161
 
162
+ attr_accessor :resolution
163
+ private :resolution=, :resolution
164
+
44
165
  attr_accessor :pickup_type
45
166
  private :pickup_type=, :pickup_type
46
167
 
47
- def initialize day, time = :unknown, pickup_type = :domestic_refuse
48
- self.day = day
168
+ def initialize pickup_type, time, resolution
49
169
  self.time = time
170
+ self.resolution = resolution
50
171
  self.pickup_type = pickup_type
51
172
  end
52
173
 
53
- def human_day
54
- Date::DAYNAMES[day]
174
+ def human_time
175
+ return unless resolution > Resolution::DAY
176
+ start_time = time
177
+ end_time = time + resolution.step
178
+
179
+ [ start_time, end_time ].map { |t| t.strftime('%l.%M%P').strip }.join(' to ')
55
180
  end
56
181
 
57
- def human_time
58
- return if time == :unknown
59
- t = time.to_s.rjust 4, '0'
60
- t[0..1] + ':' + t[2..3]
182
+ def human_date
183
+ time.strftime '%A %d %B %Y'
61
184
  end
62
185
 
63
186
  def human_type
64
- pickup_type.to_s.split(/_/).join(' ')
187
+ pickup_type
188
+ end
189
+
190
+ def <=> other
191
+ sort_key <=> other.sort_key
192
+ end
193
+
194
+ def sort_key
195
+ [ time, resolution, pickup_type ]
65
196
  end
66
197
 
67
198
  def to_s
68
- [ human_day, human_time ].compact.join(' ') + " - #{human_type}"
199
+ [ human_date, human_time ].compact.join(' from ') + " - #{human_type}"
69
200
  end
70
201
  end
71
202
 
72
203
  def self.times_at_address address
73
204
  pc = address.postcode
74
205
  local_authority = LocalAuthority::LocalAuthority.find_by_postcode pc
75
- times = CollectionTimes.new
206
+ times = Collections.new
76
207
  return times if local_authority.nil?
77
208
  adaptor = adapter_for local_authority
78
209
  adaptor.collection_times_at(address).each do |t|
@@ -21,9 +21,11 @@ module RubbishCollection
21
21
  hour = hour.to_i
22
22
  hour += 12 if modifier == "pm"
23
23
  time = hour * 100
24
- day = info.xpath ".//*[@class='day']/text()"
25
- day_index = DAYS.index day.to_s.strip
26
- [ CollectionTime.new(day_index, time) ]
24
+ day_name = info.xpath(".//*[@class='day']/text()").to_s
25
+ s = Schedule.new Resolution::HOUR
26
+ s.add_rule Schedule.day_of_week day_name
27
+ s.add_rule Schedule.hour hour
28
+ [ Collection.new(DOMESTIC_RUBBISH, s) ]
27
29
  end
28
30
  end
29
31
  end
@@ -24,17 +24,22 @@ module RubbishCollection
24
24
  times = []
25
25
  container.xpath("p").each do |rubbish_div|
26
26
  lines = rubbish_div.text.split("\n")
27
- collection_type = case lines[1]
28
- when /rubbish bin collection/
29
- :domestic_refuse
30
- # In Rushmoor, recycling comes every two weeks, CollectionTime doesn't really support this
31
- # when /recycling collection/
32
- # :domestic_recycling
33
- else
34
- next
27
+ day_name = lines[2].to_s.strip.split(" ")[0]
28
+ s = Schedule.new Resolution::DAY
29
+ collection = case lines[1]
30
+ when /rubbish bin collection/
31
+ s.add_rule Schedule.day_of_week day_name
32
+ Collection.new DOMESTIC_RUBBISH, s
33
+ when /recycling collection/
34
+ nc = Time.parse lines[2]
35
+ start_date = Runt::PDate.day nc.year, nc.month, nc.day
36
+ s.add_rule Runt::EveryTE.new(start_date, 2, Runt::DPrecision::WEEK)
37
+ s.add_rule Schedule.day_of_week day_name
38
+ Collection.new DOMESTIC_RECYCLING, s
39
+ else
40
+ next
35
41
  end
36
- day_index = Date::DAYNAMES.index(lines[2].strip.split(" ")[0])
37
- times << CollectionTime.new(day_index, :unknown, collection_type)
42
+ times << collection
38
43
  end
39
44
  times
40
45
  end
@@ -25,20 +25,22 @@ module RubbishCollection
25
25
  link_text = link.inner_text.to_s.strip
26
26
  collection_type = case link_text
27
27
  when /refuse bin/
28
- :domestic_refuse
28
+ DOMESTIC_RUBBISH
29
29
  when /communal recycling bins/
30
- :communal_recycling
30
+ COMMUNAL_RECYCLING
31
31
  when /mixed recycling bag/
32
- :mixed_recycling_bag
32
+ DOMESTIC_RECYCLING
33
33
  else
34
- link_text.to_sym
34
+ next
35
35
  end
36
36
  DAYS.inject([]) { |a,e|
37
- a << DAYS.index(e) if fragment =~ /#{e}/i
37
+ a << e if fragment =~ /#{e}/i
38
38
  a
39
39
  }.each do |d|
40
- t = CollectionTime.new d, :unknown, collection_type
41
- times << t
40
+ s = Schedule.new Resolution::DAY
41
+ s.add_rule Schedule.day_of_week(d)
42
+ c = Collection.new collection_type, s
43
+ times << c
42
44
  end
43
45
  end
44
46
  times
@@ -1,3 +1,3 @@
1
1
  module RubbishCollection
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -17,4 +17,5 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_runtime_dependency 'local_authority', '~> 0.0.5'
19
19
  gem.add_runtime_dependency 'nokogiri'
20
+ gem.add_runtime_dependency 'runt19', '~> 0.7.7'
20
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubbish_collection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-14 00:00:00.000000000 Z
12
+ date: 2012-10-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: local_authority
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: runt19
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.7.7
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.7.7
46
62
  description: When is my rubbish collected?
47
63
  email:
48
64
  - craig@barkingiguana.com