rubbish_collection 0.0.3 → 0.0.4

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.
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