auspost 0.8.5

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.
@@ -0,0 +1,18 @@
1
+ # The list of files that should be ignored by Mr Bones.
2
+ # Lines that start with '#' are comments.
3
+ #
4
+ # A .gitignore file can be used instead by setting it as the ignore
5
+ # file in your Rakefile:
6
+ #
7
+ # Bones {
8
+ # ignore_file '.gitignore'
9
+ # }
10
+ #
11
+ # For a project with a C extension, the following would be a good set of
12
+ # exclude patterns (uncomment them if you want to use them):
13
+ # *.[oa]
14
+ # *~
15
+ announcement.txt
16
+ coverage
17
+ doc
18
+ pkg
@@ -0,0 +1,4 @@
1
+ == 1.0.0 / 2009-12-26
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
@@ -0,0 +1,73 @@
1
+ auspost
2
+ by Cameron Barrie
3
+ http://wiki.github.com/whalec/auspost
4
+
5
+ == DESCRIPTION:
6
+
7
+ Give you the ability to search the Australia Post Web site with either Suburb or Postcode, and return an array of Locations.
8
+ Also add's validation methods to ActiveRecord Objects to allow you to validate that A Postcode + State + Suburb is correct
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ ActiveRecord Validations - validates_location
13
+
14
+
15
+ == SYNOPSIS:
16
+
17
+ class Foo < ActiveRecord::Base
18
+ include Auspost::Postie
19
+
20
+ before_save :check_address
21
+
22
+ def check_address
23
+ location?(:postcode => 2038, :suburb => "Annandale", :state => "NSW")
24
+ end
25
+ end
26
+
27
+ or
28
+
29
+ require 'auspost/active_record'
30
+ class Foo < ActiveRecord::Base
31
+
32
+ validate_location
33
+
34
+ end
35
+
36
+ == REQUIREMENTS:
37
+
38
+ Nokogiri - For teh XML parsing.
39
+
40
+ == INSTALL:
41
+
42
+ sudo gem install auspost
43
+
44
+ == TODO:
45
+
46
+ Validations for Active Record should take more options, including mapping the suburb, postcode and state to other columns
47
+
48
+ validate_location :suburb => :home, :state => "state.name", :on => [:create, :change], :if => lambda { !home.blank? && !postcode.blank? }
49
+
50
+ == LICENSE:
51
+
52
+ (The MIT License)
53
+
54
+ Copyright (c) 2009
55
+
56
+ Permission is hereby granted, free of charge, to any person obtaining
57
+ a copy of this software and associated documentation files (the
58
+ 'Software'), to deal in the Software without restriction, including
59
+ without limitation the rights to use, copy, modify, merge, publish,
60
+ distribute, sublicense, and/or sell copies of the Software, and to
61
+ permit persons to whom the Software is furnished to do so, subject to
62
+ the following conditions:
63
+
64
+ The above copyright notice and this permission notice shall be
65
+ included in all copies or substantial portions of the Software.
66
+
67
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
68
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
69
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
70
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
71
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
72
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
73
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ begin
2
+ require 'bones'
3
+ rescue LoadError
4
+ abort '### Please install the "bones" gem ###'
5
+ end
6
+
7
+ ensure_in_path 'lib'
8
+ require 'auspost'
9
+
10
+ task :default => 'test:run'
11
+ task 'gem:release' => 'test:run'
12
+
13
+ Bones {
14
+ name 'auspost'
15
+ authors 'Cameron Barrie'
16
+ email 'camwritescode@gmail.com'
17
+ dependencies ['nokogiri', "memcache-client"]
18
+ url 'http://www.camwritescode.com/auspost'
19
+ version Auspost::VERSION
20
+ }
21
+
22
+ # EOF
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib auspost]))
5
+
6
+ # Put your code here
7
+
@@ -0,0 +1,48 @@
1
+ module Auspost
2
+
3
+ # :stopdoc:
4
+ VERSION = '0.8.5'
5
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
+ # :startdoc:
8
+
9
+ # Returns the version string for the library.
10
+ #
11
+ def self.version
12
+ VERSION
13
+ end
14
+
15
+ # Returns the library path for the module. If any arguments are given,
16
+ # they will be joined to the end of the libray path using
17
+ # <tt>File.join</tt>.
18
+ #
19
+ def self.libpath( *args )
20
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
21
+ end
22
+
23
+ # Returns the lpath for the module. If any arguments are given,
24
+ # they will be joined to the end of the path using
25
+ # <tt>File.join</tt>.
26
+ #
27
+ def self.path( *args )
28
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
29
+ end
30
+
31
+ # Utility method used to require all files ending in .rb that lie in the
32
+ # directory below this file that has the same name as the filename passed
33
+ # in. Optionally, a specific _directory_ name can be passed in such that
34
+ # the _filename_ does not have to be equivalent to the directory.
35
+ #
36
+ def self.require_all_libs_relative_to( fname, dir = nil )
37
+ dir ||= ::File.basename(fname, '.*')
38
+ search_me = ::File.expand_path(
39
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
40
+
41
+ Dir.glob(search_me).sort.each {|rb| require rb}
42
+ end
43
+
44
+ end # module Auspost
45
+ require 'open-uri'
46
+ require 'nokogiri'
47
+ require 'memcache'
48
+ require 'auspost/postie'
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), 'active_record/validations')
2
+ ActiveRecord::Base.class_eval do
3
+ include Auspost::Postie::ActiveRecord::Validations
4
+ include Auspost::Postie
5
+ end
@@ -0,0 +1,82 @@
1
+ module Auspost
2
+ module Postie
3
+
4
+ module ActiveRecord
5
+ module Validations
6
+
7
+ @@valid_attributes = {
8
+ :state => {:accessor => :state, :message => ["%s is not found in the %s postcode", :state, :postcode] },
9
+ :postcode => {:accessor => :postcode, :message => ["%s cannot be found", :postcode] },
10
+ :suburb => {:accessor => :suburb, :message => ["%s is not found in the %s postcode", :suburb, :postcode] },
11
+ }
12
+
13
+ def self.included(base)
14
+ base.extend ClassMethods
15
+ end
16
+
17
+
18
+ def validate_location
19
+ result = location?(map_attributes)
20
+ if result && !result.status
21
+ result.errors.each do |error|
22
+ message = @@valid_attributes[error.accessor][:message]
23
+ if message.is_a?(String)
24
+ errors.add(error.accessor, message)
25
+ else
26
+ mappings = message[1..-1].map do |x|
27
+ if x.to_s.include?(".")
28
+ methods = x.split(".")
29
+ send(methods.first).send(methods.last).to_s.upcase
30
+ else
31
+ send(x).to_s.upcase
32
+ end
33
+ end
34
+ errors.add(error.accessor, message.first % mappings)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def valid_attributes
41
+ @@valid_attributes
42
+ end
43
+
44
+ protected
45
+
46
+ def map_attributes
47
+ {
48
+ :state => get_column(:state),
49
+ :postcode => get_column(:postcode),
50
+ :suburb => get_column(:suburb)
51
+ }
52
+ end
53
+
54
+ def get_column(column)
55
+ if @@valid_attributes[column][:accessor].nil?
56
+ column
57
+ elsif @@valid_attributes[column][:accessor].is_a?(String) && @@valid_attributes[column][:accessor].include?(".")
58
+ association = @@valid_attributes[column][:accessor].split(".")
59
+ self.send(association.first.to_sym).send(association.last.to_sym)
60
+ else
61
+ self.send(@@valid_attributes[column][:accessor]) || column
62
+ end
63
+ end
64
+
65
+
66
+ module ClassMethods
67
+
68
+ include Validations
69
+
70
+ # I'll add some validations here...
71
+ def validate_location(*args)
72
+ valid_attributes.update(args.extract_options!)
73
+ validate :validate_location, valid_attributes
74
+ end
75
+
76
+
77
+ end
78
+ end
79
+ end #ActiveRecord
80
+
81
+ end
82
+ end
@@ -0,0 +1,172 @@
1
+ require 'cgi'
2
+ module Auspost
3
+
4
+ module Postie
5
+
6
+ class Cache
7
+
8
+ # Over ride these two class variables to change your memcache settings
9
+ @@memcache_host = "localhost"
10
+ @@memcache_port = "11211"
11
+
12
+ def initialize
13
+ if Object.const_defined? :Rails
14
+ Rails.cache
15
+ else
16
+ @cache = MemCache.new "#{@@memcache_host}:#{@@memcache_port}", :namespace => 'auspost'
17
+ end
18
+ end
19
+
20
+ def write(key, object)
21
+ if @cache
22
+ @cache.add(key, object) if @cache.servers.map{|s| s.alive?}.include?(true)
23
+ else
24
+ Rails.cache.write(key, object)
25
+ end
26
+ end
27
+
28
+ def read(key)
29
+ if @cache
30
+ @cache.get(key) if @cache.servers.map{|s| s.alive?}.include?(true)
31
+ else
32
+ Rails.cache.read(key)
33
+ end
34
+ end
35
+ end
36
+
37
+ class Suburb
38
+ def initialize(attrs)
39
+ @suburb = attrs[:suburb].downcase
40
+ @postcode = attrs[:postcode].to_i
41
+ @state = attrs[:state].downcase
42
+ end
43
+
44
+ def suburb?(attrs)
45
+ attrs[:suburb].downcase == @suburb
46
+ end
47
+
48
+ def state?(attrs)
49
+ attrs[:state].downcase == @state.downcase
50
+ end
51
+
52
+ def postcode?(attrs)
53
+ attrs[:postcode].to_i == @postcode
54
+ end
55
+
56
+ def eql?(attrs)
57
+ suburb?(attrs) && postcode?(attrs) && state?(attrs)
58
+ end
59
+
60
+ def to_i(attrs)
61
+ (suburb?(attrs) ? 1 : 0) +
62
+ (state?(attrs) ? 1 : 0) +
63
+ (postcode?(attrs) ? 1 : 0)
64
+ end
65
+ end
66
+
67
+ class Result
68
+
69
+ attr_reader :status, :errors
70
+
71
+ def initialize(status)
72
+ @status = status
73
+ @errors = [] if !@status
74
+ end
75
+
76
+ end
77
+
78
+ class Error
79
+
80
+ attr_reader :accessor
81
+
82
+ def initialize(accessor)
83
+ @accessor = accessor
84
+ end
85
+
86
+ end
87
+
88
+
89
+ # This is the method that returns whether a location is correct or not.
90
+ # It requires three attributes
91
+ # :postcode, :suburb & :state such as
92
+ # location?(:postcode => 2038, :suburb => "Annandale", :state => "NSW") #=> Result#status => true
93
+ # location?(:postcode => 2010, :suburb => "Annandale", :state => "NSW") #=> Result#status => false
94
+ # Result#errors => Error#accessor => :suburb && Error#message => "Annandale does not match 2010 postcode"
95
+ # The results of a request to a given postcode is cached in memcached if available or in
96
+ # your Rails.cache store if you're in a Rails project.
97
+ def location?(attrs = {})
98
+ map_attributes!(attrs)
99
+ url = "http://www1.auspost.com.au/postcodes/index.asp?Locality=&sub=1&State=&Postcode=#{CGI::escape(@postcode)}&submit1=Search"
100
+ @content = get(url)
101
+ check_results(attrs)
102
+ end
103
+
104
+
105
+ protected
106
+
107
+ def cache
108
+ @cache ||= set_cache
109
+ end
110
+
111
+ def set_cache
112
+ @cache = Cache.new
113
+ end
114
+
115
+ def get(url)
116
+ @results = check_cache || get_and_cache(url)
117
+ end
118
+
119
+ def check_cache
120
+ cache.read(@postcode)
121
+ end
122
+
123
+ def get_and_cache(url)
124
+ object = open(url)
125
+ @table = Nokogiri::HTML(object).xpath('//table[3]/tr/td[2]/table/tr/td/font/table/tr[2]/td/table/tr')
126
+ content = map_results
127
+ content.delete_if{|x| x.nil?}
128
+ cache.write(@postcode, content)
129
+ content
130
+ end
131
+
132
+ def map_attributes!(attrs)
133
+ raise ArgumentError, "You must supply a suburb" if attrs[:suburb].nil?
134
+ raise ArgumentError, "You must supply a state" if attrs[:state].nil?
135
+ raise ArgumentError, "You must supply a postcode" if attrs[:postcode].nil?
136
+ attrs.values.map!{|value| value.to_s.downcase! }
137
+ @postcode = attrs[:postcode].to_s
138
+ end
139
+
140
+ def map_results
141
+ @table.map do |row|
142
+ content = row.content.strip if row.content.include?("LOCATION:")
143
+ if content
144
+ s = content.index("LOCATION: ")
145
+ e = content.index(",")
146
+ suburb = content[s..e-1].split(" ").last
147
+ state = content[e+2..e+4]
148
+ final = Suburb.new(:suburb => suburb, :state => state, :postcode => @postcode)
149
+ end
150
+ end
151
+ end
152
+
153
+ def check_results(attrs)
154
+ if @results.map{|suburb| suburb.eql?(attrs)}.include?(true)
155
+ Result.new(true)
156
+ else
157
+ generate_result_with_errors(attrs)
158
+ end
159
+ end
160
+
161
+ def generate_result_with_errors(attrs)
162
+ result = Result.new(false)
163
+ error_count = @results.map{|r| r.to_i(attrs) }
164
+ main_error = @results[error_count.index(error_count.sort.last)]
165
+ result.errors << Error.new(:suburb) if !main_error.suburb?(attrs)
166
+ result.errors << Error.new(:state) if !main_error.state?(attrs)
167
+ result
168
+ end
169
+
170
+ end
171
+
172
+ end
@@ -0,0 +1,72 @@
1
+ require File.join(File.dirname(__FILE__), "../../spec_helper")
2
+ require File.join(File.dirname(__FILE__), "../../fixtures/postal_worker")
3
+
4
+ describe PostalWorker, "without auspost/active_record required" do
5
+
6
+ it "should not respond to a method validate_location" do
7
+ PostalWorker.should_not respond_to(:validate_location)
8
+ end
9
+
10
+ end
11
+
12
+
13
+ describe PostalWorker, "with auspost/active_record required" do
14
+
15
+ # require needs to be in the before block, otherwise it's called when the file is required or the describe blocks are called.
16
+ # causing failure to the above spec
17
+ before(:all) do
18
+ require 'auspost/active_record'
19
+ PostalWorker.validate_location
20
+ end
21
+
22
+ before do
23
+ @valid_attributes = {:address => "William St", :suburb => "Annandale", :postcode => "2038", :state => "NSW"}
24
+ @invalid_attributes = {:address => "William St", :suburb => "Annandale", :postcode => "2000", :state => "VIC"}
25
+ end
26
+
27
+ it "should have a method validate_location" do
28
+ PostalWorker.should respond_to(:validate_location)
29
+ end
30
+
31
+ it "should not be valid" do
32
+ @worker = PostalWorker.new(@invalid_attributes)
33
+ @worker.should_not be_valid
34
+ end
35
+
36
+ it "should validate an address" do
37
+ @worker = PostalWorker.new({:suburb => "Rozelle", :postcode => "2039", :state => "NSW"})
38
+ @worker.should be_valid
39
+ end
40
+
41
+ it "should return a useful error message on the state" do
42
+ @worker = PostalWorker.new(@invalid_attributes)
43
+ @worker.should_not be_valid
44
+ @worker.errors.on(:state).should eql("VIC is not found in the 2000 postcode")
45
+ @worker.errors.on(:suburb).should eql("ANNANDALE is not found in the 2000 postcode")
46
+ end
47
+
48
+ it "should return a useful error message on the suburb" do
49
+ @worker = PostalWorker.new(@valid_attributes.merge(:suburb => "Rozelle"))
50
+ @worker.should_not be_valid
51
+ @worker.errors.on(:suburb).should eql("ROZELLE is not found in the 2038 postcode")
52
+ @worker.errors.on(:state).should be_nil
53
+ end
54
+ end
55
+
56
+
57
+ describe MashedPostalWorker, "with options set on the validation" do
58
+ before(:all) do
59
+ require 'auspost/active_record'
60
+ MashedPostalWorker.validate_location :suburb => {:accessor => :city, :message => "That doesn't match up!"},
61
+ :postcode => {:accessor => :zipcode, :message => ["Postcode %s cannot be found", :zipcode]},
62
+ :state => {:accessor => "state.name", :message => ["%s is such a better state anyway *ducks*", "state.name"]}
63
+ end
64
+
65
+ it "should have a custom message on the suburb" do
66
+ @worker = MashedPostalWorker.new({:city => "Annandale", :zipcode => 3001, :state => State.new(:name => "NSW")})
67
+ @worker.should_not be_valid
68
+ @worker.errors.on(:suburb).should eql("That doesn't match up!")
69
+ @worker.errors.on(:state).should eql("NSW is such a better state anyway *ducks*")
70
+ end
71
+
72
+ end
@@ -0,0 +1,55 @@
1
+ require File.join(File.dirname(__FILE__), "../spec_helper")
2
+ include Auspost
3
+
4
+ describe Postie do
5
+ include Postie
6
+
7
+ it "should find Annandale and return true" do
8
+ location?({:postcode => "2038", :suburb => "Annandale", :state => "NSW"}).status.should eql(true)
9
+ end
10
+
11
+ it "shouldn't find that Surry Hills is in the 2000 postcode" do
12
+ location?({:postcode => "2000", :suburb => "Surry Hills", :state => "QLD"}).status.should_not eql(true)
13
+ end
14
+
15
+ # Testing this to ensure sub-strings don't pass as true
16
+ it "shoudn't find dale in 2038" do
17
+ location?({:postcode => "2038", :suburb => "dale", :state => "NSW"}).status.should_not eql(true)
18
+ end
19
+
20
+ it "shouldn't substring search" do
21
+ location?(:postcode => "2038", :suburb => "Annandale", :state => "N").status.should_not eql(true)
22
+ end
23
+
24
+ it "should raise if there's not a postcode" do
25
+ lambda { location?(:suburb => "Surry Hills", :state => "FOO") }.should raise_error(ArgumentError)
26
+ end
27
+
28
+ it "should raise if there's not a suburb" do
29
+ lambda { location?(:postcode => 2038, :state => "FOO") }.should raise_error(ArgumentError)
30
+ end
31
+
32
+ it "should raise if there's not a state" do
33
+ lambda { location?(:suburb => "Surry Hills", :postcode => 2038) }.should raise_error(ArgumentError)
34
+ end
35
+
36
+ it "should accept an Integer for the postcode" do
37
+ location?({:postcode => 2038, :suburb => "Annandale", :state => "NSW"}).status.should eql(true)
38
+ end
39
+
40
+ end
41
+
42
+ describe Postie, " with cached" do
43
+ include Postie
44
+
45
+ it "should cache a result" do
46
+ @io = mock(IO)
47
+ @string = mock(String)
48
+ @array = mock(Array)
49
+ Postie::Cache.should_receive(:new).and_return(@io)
50
+ @io.should_receive(:read).with("2038").and_return(@string)
51
+ @string.should_receive(:map).at_least(:once).and_return(@array)
52
+ @array.should_receive(:include?).with(true).and_return(true)
53
+ location?({:postcode => "2038", :suburb => "Annandale", :state => "NSW"}).status.should eql(true)
54
+ end
55
+ end
@@ -0,0 +1,187 @@
1
+
2
+ <html>
3
+ <head>
4
+ <link rel="stylesheet" href="/include/stylesheet/miniapps.css" type="text/css">
5
+ <link rel="stylesheet" href="/include/stylesheet/mainstyle.css" type="text/css">
6
+ <title>Australia Post - Postcode Search</title>
7
+
8
+ <META NAME='ROBOTS' CONTENT='ALL'>
9
+ <META NAME='description' CONTENT='Search for Australian Postcode locations online'>
10
+ <META NAME='keywords' CONTENT='Australia Post Postcode Search Find locations'>
11
+
12
+ </head>
13
+ <script type="text/JavaScript">
14
+ <!--
15
+ function MM_preloadImages() { //v3.0
16
+ var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
17
+ var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
18
+ if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
19
+ }
20
+
21
+ function MM_swapImgRestore() { //v3.0
22
+ var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
23
+ }
24
+
25
+ function MM_findObj(n, d) { //v4.01
26
+ var p,i,x; if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
27
+ d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
28
+ if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
29
+ for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
30
+ if(!x && d.getElementById) x=d.getElementById(n); return x;
31
+ }
32
+
33
+ function MM_swapImage() { //v3.0
34
+ var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
35
+ if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
36
+ }
37
+ function cmdGo_Click() {
38
+ window.document.queryForm.submit(); }
39
+ //-->
40
+ </script>
41
+ <table width="780" border="0" cellspacing="0" cellpadding="0">
42
+ <tr class="top-header">
43
+ <td width="210"><a href="http://www.auspost.com.au"><img src="/auspost/images/display/logo.jpg" alt="Australia Post Home" width="182" height="45" border="0" /></a></td>
44
+ <td><img src="/auspost/images/display/b_arrow.gif" alt="Arrow" id="contact-arrow" width="13" height="14" />&nbsp;&nbsp;<a class="white-title" href="http://www.auspost.com.au/BCP/0,1080,CH3988%257EMO19,00.html">Jobs @ Post</a>&nbsp;&nbsp;&nbsp;<img src="/auspost/images/display/b_arrow.gif" alt="Arrow" id="contact-arrow" width="13" height="14" />&nbsp;&nbsp;&nbsp;<a class="white-title" href="http://www.auspost.com.au/CUP/0,,CHNONE%257EMO19,00.html">Contact Us</a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="search-title">Search Site :</span>&nbsp;<form id="queryForm" name="queryForm" action="http://search.auspost.com.au/cse/auspost/default.asp" method="get"><input id="queryBox" name="q" value="" size="20" />&nbsp;&nbsp;<a href="javascript:onClick=cmdGo_Click();" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('btngosearch','','/auspost/images/display/br_submit.gif',1)"><img name="btngosearch" id="btngosearch" src="/auspost/images/display/b_submit.gif" alt="submit" width="62" height="22" border="0" /></form></td>
45
+ </tr>
46
+ </table>
47
+ <table width="780" border="0" cellspacing="0" cellpadding="0">
48
+ <tr class="tabs-row">
49
+ <td width="19">&nbsp;</td>
50
+ <td width="101"><a href="http://www.auspost.com.au"><img src="/auspost/images/display/b_Home.gif" alt="Home" name="Image2" width="82" height="29" border="0" id="Image2" onmouseover="MM_swapImage('Image2','','/auspost/images/display/br_Home.gif',1)" onmouseout="MM_swapImgRestore()" /></a></td>
51
+ <td width="139"><a href="http://www.auspost.com.au/CAP/0,,CH2002%257EMO19,00.html"><img src="/auspost/images/display/b_GenServices.gif" alt="General Services" width="122" height="29" border="0" id="Image3" onmouseover="MM_swapImage('Image3','','/auspost/images/display/br_GenServices.gif',1)" onmouseout="MM_swapImgRestore()" /></a></td>
52
+ <td width="199"><a href="http://www.auspost.com.au/CAP/0,,CH2006%257EMO19,00.html"><img src="/auspost/images/display/b_Billing.gif" alt="Billing &amp; Financial" width="180" height="29" border="0" id="Image4" onmouseover="MM_swapImage('Image4','','/auspost/images/display/br_Billing.gif',1)" onmouseout="MM_swapImgRestore()" /></a></td>
53
+ <td width="154"><a href="http://www.auspost.com.au/CAP/0,,CH2005%257EMO19,00.html"><img src="/auspost/images/display/b_BusSolutions.gif" alt="Business Solutions" width="138" height="29" border="0" id="Image5" onmouseover="MM_swapImage('Image5','','/auspost/images/display/br_BusSolutions.gif',1)" onmouseout="MM_swapImgRestore()" /></a></td>
54
+ <td><a href="http://www.auspost.com.au/CAP/0,,CH2007%257EMO19,00.html"><img src="/auspost/images/display/b_AboutUs.gif" alt="About Us" width="85" height="29" border="0" id="Image6" onmouseover="MM_swapImage('Image6','','/auspost/images/display/br_AboutUs.gif',1)" onmouseout="MM_swapImgRestore()" /></a></td>
55
+ <td width="50"><div align="right"><img src="/auspost/images/display/cnr_btm_r.gif" alt="corner" width="39" height="29" /></div></td>
56
+ </tr>
57
+ <tr>
58
+ <td colspan="7"><img src="/auspost/images/display/transparent 3x3.gif" alt="Blank" width="8" height="8" /></td>
59
+ </tr>
60
+ </table>
61
+ <table border="0" cellpadding="0" cellspacing="0" width="780">
62
+ <tr>
63
+ <td valign="top" id="td-site-app">
64
+
65
+ <ul id="site-apps" style="padding-right: 5px;">
66
+ <li><img src="/auspost/images/display/h_Useful_Tools.gif" alt="Useful Tools" width="113" height="29" /></li>
67
+ <li><img src="/auspost/images/display/i_FindPostcode.gif" alt="Find a postcode" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www1.auspost.com.au/postcodes/">Find a postcode</a></li>
68
+ <li><img src="/auspost/images/display/i_CalcPostageRates.gif" alt="Calculate postage rates" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www1.auspost.com.au/pac/">Calculate postage rates</a></li>
69
+ <li><img src="/auspost/images/display/i_ExpressPostPlatTrackg.gif" alt="Australia post delivery tracking" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www.auspost.com.au/track">Track my item</a></li>
70
+ <li><img src="/auspost/images/display/i_FindPostalOutlet.gif" alt="Find a postal outlet" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www.auspost.com.au/pol/">Find a postal outlet</a></li>
71
+ <li><img src="/auspost/images/display/i_FindPostalBox.gif" alt="Find a street posting box" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www.auspost.com.au/pol/">Find a street posting box</a></li>
72
+ <li><img src="/auspost/images/display/i_PayBillsOnline.gif" alt="Pay bills online" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www.postbillpay.com.au/">Pay bills online</a></li>
73
+ <li><img src="/auspost/images/display/i_IntnlPostageDetails.gif" alt="International Postage Details" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www1.auspost.com.au/international/">International postage details</a></li>
74
+ <li><img src="/auspost/images/display/i_PostGuides.gif" alt="Post guides" width="22" height="22" />&nbsp;&nbsp;<a class="min-apps" href="http://www.auspost.com.au/BCP/0,,CH3851%257EMO19,00.html">Post guides</a></li>
75
+ </ul>
76
+
77
+ </td>
78
+ <td valign="top">
79
+ <table width="600" border="0" cellpadding="0" cellspacing="10">
80
+ <tr valign="top">
81
+ <td width="493" align="center" valign="top"><font face="verdana,Helv,Arial" size="2">
82
+
83
+
84
+ <table border="0" cellpadding="0" cellspacing="0" width="490">
85
+ <tr>
86
+ <!-- banner header -->
87
+ <td colspan="2" bgcolor="#B9E3DE"><img src="../images_new/postcode_search/funct_postcodesearch.gif" alt="Postcode Search" width="327" height="32"></td>
88
+ </tr>
89
+ <tr>
90
+ <!-- Results row -->
91
+ <td width="330" valign="top"><table width="330" border="0" cellpadding="5" cellspacing="0">
92
+
93
+ <tr>
94
+ <td valign="top" width="7" bgcolor="#ff0000"><font face="verdana, arial, helv" size="2" color="#ffffff"><strong>1.</strong></td>
95
+ <td><font face="arial, helv" size="2"> <strong>LOCATION:</strong> ANNANDALE, NSW<br />
96
+
97
+ <strong>POSTCODE:</strong> 2038<br />
98
+
99
+ <strong>CATEGORY:</strong> Delivery Area<br />
100
+
101
+ </td>
102
+ </tr>
103
+ <tr>
104
+ <td colspan="2"><hr noshade size="1">
105
+ </td>
106
+ </tr>
107
+
108
+ </table></td>
109
+ <td width="150" valign="top" bgcolor="#B9E3DE"><table width="150" border="0" cellpadding="5" cellspacing="0">
110
+ <!-- Results summary table -->
111
+ <tr>
112
+ <!-- Show results for each state -->
113
+ <td width="150" style="background-color: #B9E3DE; font-size:100%"><a href="index.asp">Search Again</a>
114
+ <hr noshade size="1">
115
+ <strong>Returned Matches:</strong> 1
116
+ <hr noshade size="1">
117
+
118
+ <strong>Breakdown</strong>
119
+ <br />New South Wales: 1
120
+ </td>
121
+ </tr>
122
+
123
+ </table></td>
124
+ </tr>
125
+ </table>
126
+
127
+ </td>
128
+ </tr>
129
+ </table>
130
+ </td>
131
+ </tr>
132
+ </table>
133
+
134
+ <table width="780" border="0" cellspacing="0" cellpadding="0">
135
+ <!---------- SPACER ------------------------------------------------------------------->
136
+ <tr>
137
+ <td valign="top" height="20">
138
+ </td>
139
+ </tr>
140
+ <!---------- end SPACER --------------------------------------------------------------->
141
+
142
+ <!---------- FIRST LEVEL NAVIGATION ------------------------------------------------------>
143
+ <tr>
144
+ <td id="td-foot">
145
+ <br />
146
+ <ul id="footer-list">
147
+ <li><img src="/auspost/images/display/a_right.gif" alt="Arrow" width="4" height="7" /> <a class="footer" href="http://www.auspost.com.au/APC/CDA/Sitemap/APC_CDA_Sitemap/0,1084,CHNONE%257EMO19,00.html">Site map</a>&nbsp;&nbsp;&nbsp;&nbsp;</li>
148
+ <li><img src="/auspost/images/display/a_right.gif" alt="Arrow" width="4" height="7" /> <a class="footer" href="http://www.auspost.com.au/CUP/0,1050,CHNONE%257EMO19,00.html">Contact Us</a>&nbsp;&nbsp;&nbsp;&nbsp;</li>
149
+ <li><img src="/auspost/images/display/a_right.gif" alt="Arrow" width="4" height="7" /> <a class="footer" href="http://www.auspost.com.au/APC/CDA/Site_Governance/APC_CDA_Privacy_Policy/">Privacy</a>&nbsp;&nbsp;&nbsp;&nbsp;</li>
150
+ <li><img src="/auspost/images/display/a_right.gif" alt="Arrow" width="4" height="7" /> <a class="footer" href="http://www.auspost.com.au/APC/CDA/Site_Governance/APC_CDA_Terms_Conditions/">Terms &amp; Conditions </a></li>
151
+ </ul>
152
+
153
+
154
+ <!-- Track File Downloads with Google -->
155
+ <script language="javascript" type="text/javascript" src="/APC/CDA/CSS/gatag.js" ></script>
156
+
157
+ <!--Google tracking -->
158
+ <script type="text/javascript">
159
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
160
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
161
+ </script>
162
+
163
+ <script type="text/javascript">
164
+ <!-- Auspost roll up account -->
165
+ try {
166
+ var APTracker = _gat._getTracker("UA-2225711-5");
167
+ APTracker._setDomainName(".auspost.com.au");
168
+ APTracker._trackPageview("WWW1" + document.location.pathname);
169
+ } catch(err) {}
170
+
171
+ <!-- Auspost account -->
172
+ try {
173
+ var pageTracker = _gat._getTracker("UA-2225711-1");
174
+ pageTracker._setDomainName(".auspost.com.au");
175
+ pageTracker._trackPageview();
176
+ } catch(err) {}
177
+
178
+ <!-- WWW1 account -->
179
+ try {
180
+ var pageTracker = _gat._getTracker("UA-2225711-3");
181
+ pageTracker._setDomainName(".auspost.com.au");
182
+ pageTracker._trackPageview();
183
+ } catch(err) {}
184
+ </script>
185
+
186
+ </body>
187
+ </html>
@@ -0,0 +1,39 @@
1
+ gem 'sqlite3-ruby'
2
+ require 'sqlite3'
3
+ require 'active_record'
4
+
5
+ ActiveRecord::Base.establish_connection(
6
+ :adapter => "sqlite3",
7
+ :database => ":memory:"
8
+ )
9
+ ActiveRecord::Base.connection.create_table(:postal_workers) do |t|
10
+ t.string :address
11
+ t.string :postcode
12
+ t.string :suburb
13
+ t.string :state
14
+ end
15
+
16
+
17
+ ActiveRecord::Base.connection.create_table(:mashed_postal_workers) do |t|
18
+ t.string :addr
19
+ t.string :zipcode
20
+ t.string :city
21
+ t.integer :state_id
22
+ end
23
+
24
+ ActiveRecord::Base.connection.create_table(:states) do |t|
25
+ t.string :name
26
+ end
27
+
28
+
29
+ class PostalWorker < ActiveRecord::Base;end
30
+
31
+ class MashedPostalWorker < ActiveRecord::Base
32
+
33
+ belongs_to :state
34
+
35
+ end
36
+
37
+ class State < ActiveRecord::Base
38
+ has_many :mashed_postal_workers
39
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib auspost]))
4
+
5
+ Spec::Runner.configure do |config|
6
+ # == Mock Framework
7
+ #
8
+ # RSpec uses it's own mocking framework by default. If you prefer to
9
+ # use mocha, flexmock or RR, uncomment the appropriate line:
10
+ #
11
+ # config.mock_with :mocha
12
+ # config.mock_with :flexmock
13
+ # config.mock_with :rr
14
+ end
15
+
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: auspost
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.5
5
+ platform: ruby
6
+ authors:
7
+ - Cameron Barrie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-02 00:00:00 +11:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bones
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 3.2.0
24
+ version:
25
+ description: |-
26
+ Give you the ability to search the Australia Post Web site with either Suburb or Postcode, and return an array of Locations.
27
+ Also add's validation methods to ActiveRecord Objects to allow you to validate that A Postcode + State + Suburb is correct
28
+ email: camwritescode@gmail.com
29
+ executables:
30
+ - auspost
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - History.txt
35
+ - README.txt
36
+ - bin/auspost
37
+ files:
38
+ - .bnsignore
39
+ - History.txt
40
+ - README.txt
41
+ - Rakefile
42
+ - bin/auspost
43
+ - lib/auspost.rb
44
+ - lib/auspost/active_record.rb
45
+ - lib/auspost/active_record/validations.rb
46
+ - lib/auspost/postie.rb
47
+ - spec/auspost/active_record/validations_spec.rb
48
+ - spec/auspost/postie_spec.rb
49
+ - spec/fixtures/auspost.html
50
+ - spec/fixtures/postal_worker.rb
51
+ - spec/spec_helper.rb
52
+ has_rdoc: true
53
+ homepage: http://www.camwritescode.com/auspost
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --main
59
+ - README.txt
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project: auspost
77
+ rubygems_version: 1.3.5
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Give you the ability to search the Australia Post Web site with either Suburb or Postcode, and return an array of Locations
81
+ test_files:
82
+ - spec/auspost/active_record/validations_spec.rb
83
+ - spec/auspost/postie_spec.rb