location 0.0.1

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +23 -0
  4. data/app/assets/javascripts/location/application.js +13 -0
  5. data/app/assets/stylesheets/location/application.css +13 -0
  6. data/app/controllers/location/application_controller.rb +4 -0
  7. data/app/controllers/location/finder_controller.rb +11 -0
  8. data/app/helpers/location/application_helper.rb +4 -0
  9. data/app/models/location/address.rb +38 -0
  10. data/app/models/location/address_form.rb +145 -0
  11. data/app/models/location/city.rb +8 -0
  12. data/app/models/location/district.rb +8 -0
  13. data/app/models/location/form.rb +55 -0
  14. data/app/models/location/state.rb +9 -0
  15. data/app/views/layouts/location/application.html.erb +14 -0
  16. data/app/views/location/finder/show.js.coffee +6 -0
  17. data/config/routes.rb +3 -0
  18. data/db/migrate/20131209160000_create_location_cities.rb +9 -0
  19. data/db/migrate/20131209160035_create_location_districts.rb +9 -0
  20. data/db/migrate/20131209160111_create_location_states.rb +10 -0
  21. data/db/migrate/20131209160523_create_location_addresses.rb +21 -0
  22. data/db/migrate/20131209165654_remove_city_and_state_from_address.rb +6 -0
  23. data/db/migrate/20131209171214_add_city_to_district.rb +5 -0
  24. data/db/migrate/20131209172128_add_state_to_city.rb +5 -0
  25. data/db/migrate/20140112163948_add_type_to_address.rb +5 -0
  26. data/db/migrate/20140129154554_add_normalized_to_states.rb +5 -0
  27. data/db/migrate/20140129154726_add_normalized_to_cities.rb +5 -0
  28. data/db/migrate/20140129154734_add_normalized_to_districts.rb +5 -0
  29. data/lib/location.rb +32 -0
  30. data/lib/location/engine.rb +10 -0
  31. data/lib/location/finder.rb +66 -0
  32. data/lib/location/services/errors.rb +6 -0
  33. data/lib/location/services/failed_service.rb +9 -0
  34. data/lib/location/services/null_service.rb +8 -0
  35. data/lib/location/services/republica.rb +8 -0
  36. data/lib/location/services/stubbed_service.rb +26 -0
  37. data/lib/location/services/uni5.rb +66 -0
  38. data/lib/location/version.rb +3 -0
  39. data/lib/tasks/location_tasks.rake +4 -0
  40. metadata +258 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d5e6cb904c7136f83a2944efe05be72b4da98191
4
+ data.tar.gz: a9288f769f3f4ee55dc8f89fb5dcf6e5942b5060
5
+ SHA512:
6
+ metadata.gz: 171da40227393a64a0624aa167b4e1b46ec2fb03443074267e049e273c1fcd6d9d43c5f8e8f113222f455f460636b9e22cadfa9e7aef82384010e206b82db20a
7
+ data.tar.gz: f76b33b5e2c321898165a6ae01287a91c029c9ae7ee61da0fe8803e79232240d7dd9fa399e3920810e6e713b296e4da290b98aac4d0899d67a4bc5c5d3b1c729
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Location'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ module Location
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,11 @@
1
+ module Location
2
+ class FinderController < ActionController::Base
3
+ respond_to :js
4
+
5
+ def show
6
+ Finder.find params[:postal_code] do |f|
7
+ @address = f.address.to_json
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module Location
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,38 @@
1
+ module Location
2
+ class Address < ActiveRecord::Base
3
+ belongs_to :district
4
+ belongs_to :addressable, polymorphic: true
5
+ has_one :city, through: :district
6
+ has_one :state, through: :city
7
+
8
+ before_save :format_postal_code
9
+
10
+ validates :address, length: { maximum: 150 }
11
+ validates :number, length: { maximum: 20 }
12
+ validates :complement, length: { maximum: 40 }
13
+ validates :latitude, :longitude, numericality: true, allow_blank: true
14
+
15
+ scope :full, ->{ eager_load(:district).eager_load(:city).eager_load(:state) }
16
+ default_scope { full }
17
+
18
+ def to_hash
19
+ {
20
+ postal_code: self.postal_code,
21
+ address: self.address,
22
+ number: self.number,
23
+ complement: self.complement,
24
+ district: self.district.try(:name),
25
+ city: self.city.try(:name),
26
+ state: self.state.try(:name)
27
+ }
28
+ end
29
+
30
+ private
31
+
32
+ def format_postal_code
33
+ postal_code.gsub!(/[^0-9]/, '') if postal_code.present?
34
+ end
35
+ end
36
+ end
37
+
38
+
@@ -0,0 +1,145 @@
1
+ module Location
2
+ class AddressForm
3
+ include Form
4
+
5
+ def self.normalizable_attributes
6
+ %i{state city district}
7
+ end
8
+
9
+ def self.default_presence_attributes
10
+ %i{postal_code address district city state}
11
+ end
12
+
13
+ def self.string_attributes
14
+ %i{postal_code address number complement district city state}
15
+ end
16
+
17
+ def self.float_attributes
18
+ %i{latitude longitude}
19
+ end
20
+
21
+ string_attributes.each { |attr| attribute attr, String }
22
+ float_attributes.each { |attr| attribute attr, Float }
23
+
24
+ (string_attributes + float_attributes).each do |attr|
25
+ validates attr, presence: true, if: ->(a){ a.presence[attr] }
26
+ end
27
+
28
+ before_validation :build_finder
29
+ validate :ensure_find_address
30
+ before_save :normalize_attributes!
31
+
32
+ attr_accessor :model
33
+
34
+ def presence
35
+ @presence || validate_presence_of(AddressForm.default_presence_attributes)
36
+ end
37
+
38
+ def address_attributes
39
+ attributes = %w{postal_code address number complement latitude longitude}
40
+ values_for_attributes(attributes)
41
+ end
42
+
43
+ def normalized_attributes=(attributes)
44
+ @normalized_attributes = Array(attributes)
45
+ ensure_valid_normalized_attributes!
46
+ end
47
+
48
+ def normalized_attributes
49
+ @normalized_attributes ||= Location.configuration.normalized_fields
50
+ ensure_valid_normalized_attributes!
51
+ @normalized_attributes
52
+ end
53
+
54
+ def ensure_valid_normalized_attributes!
55
+ unless valid_normalized_attributes?
56
+ raise ::StandardError.new, "Invalid normalizable attributes"
57
+ end
58
+ end
59
+
60
+ def attribute_normalized?(attr)
61
+ normalized_attributes.include?(attr)
62
+ end
63
+
64
+ def validate_presence_of(attributes)
65
+ attributes = Array(attributes)
66
+ @presence = self.attributes.keys.inject({}) do |hash, attr|
67
+ hash[attr] = attributes.include?(attr)
68
+ hash
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def valid_normalized_attributes?
75
+ valid = self.class.normalizable_attributes.slice(0, @normalized_attributes.count)
76
+ valid == @normalized_attributes || valid.reverse == @normalized_attributes
77
+ end
78
+
79
+ def persist!
80
+ State.transaction(requires_new: true) do
81
+ if @model.try(:persisted?)
82
+ update
83
+ else
84
+ create
85
+ end
86
+ end
87
+ end
88
+
89
+ def create
90
+ state = create_attribute(:state, State)
91
+ city = create_attribute(:city, state.cities)
92
+ district = create_attribute(:district, city.districts)
93
+
94
+ @model = district.addresses.create!(address_attributes)
95
+ end
96
+
97
+ def update
98
+ @model.update(address_attributes)
99
+
100
+ district = update_attribute(@model, :district)
101
+ city = update_attribute(district, :city)
102
+ state = update_attribute(city, :state)
103
+ end
104
+
105
+ def update_attribute(parent, attr)
106
+ child = parent.send(attr) || parent.send("build_#{attr.to_s}")
107
+ child.update(attributes_for(attr))
108
+ child
109
+ end
110
+
111
+ def attributes_for(attr)
112
+ { name: send(attr), normalized: attribute_normalized?(attr) }
113
+ end
114
+
115
+ def create_attribute(attr, klass)
116
+ attrs = attributes_for(attr)
117
+ method = attrs[:normalized] ? "first_or_create!" : "create!"
118
+ klass.send(method, attrs)
119
+ end
120
+
121
+ def build_finder
122
+ @finder = Finder.build(postal_code)
123
+ end
124
+
125
+ def ensure_find_address
126
+ @finder.find do |f|
127
+ unless f.successful?
128
+ errors.add :postal_code, %{Can't find address for #{postal_code}}
129
+ end
130
+ end
131
+ end
132
+
133
+ def normalize_attributes!
134
+ normalized_attributes.each do |f|
135
+ send("#{f}=", @finder.address.send(f))
136
+ end
137
+ end
138
+
139
+ def values_for_attributes(attributes)
140
+ attributes.each_with_object({}) do |attr, hash|
141
+ hash[attr] = send(attr)
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,8 @@
1
+ module Location
2
+ class City < ActiveRecord::Base
3
+ has_many :districts
4
+ belongs_to :state, dependent: :destroy
5
+
6
+ validates :name, length: { maximum: 150 }
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Location
2
+ class District < ActiveRecord::Base
3
+ has_many :addresses
4
+ belongs_to :city
5
+
6
+ validates :name, length: { maximum: 150 }
7
+ end
8
+ end
@@ -0,0 +1,55 @@
1
+ require 'virtus'
2
+
3
+ module Location
4
+ module Form
5
+ def self.included(klass)
6
+ virtus = @virtus_options ?
7
+ Virtus.model(@virtus_options) :
8
+ Virtus.model
9
+
10
+ klass.include virtus
11
+ klass.include ActiveModel::Conversion
12
+ klass.include ActiveModel::Validations
13
+ klass.extend ActiveModel::Naming
14
+ klass.extend ActiveModel::Callbacks
15
+
16
+ add_callbacks(klass)
17
+
18
+ @virtus_options = nil
19
+ end
20
+
21
+ def self.add_callbacks(klass)
22
+ klass.class_eval do
23
+ alias_method :ar_valid?, :valid?
24
+
25
+ def valid?
26
+ run_callbacks :validation do
27
+ ar_valid?
28
+ end
29
+ end
30
+
31
+ define_model_callbacks :validation, :save
32
+ end
33
+ end
34
+
35
+ def self.base(virtus_options = {})
36
+ @virtus_options = virtus_options
37
+ Form
38
+ end
39
+
40
+ def persisted?
41
+ false
42
+ end
43
+
44
+ def save
45
+ if valid?
46
+ run_callbacks :save do
47
+ persist!
48
+ end
49
+ true
50
+ else
51
+ false
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,9 @@
1
+ module Location
2
+ class State < ActiveRecord::Base
3
+ has_many :cities, dependent: :destroy
4
+ has_many :districts, through: :cities
5
+ has_many :addresses, through: :districts
6
+
7
+ validates :name, length: { maximum: 150 }
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Location</title>
5
+ <%= stylesheet_link_tag "location/application", media: "all" %>
6
+ <%= javascript_include_tag "location/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,6 @@
1
+ address = jQuery.parseJSON('<%= raw @address %>')
2
+ postal_code_id = '#<%= params[:postal_code_id] %>'
3
+ prefix = postal_code_id.replace /postal_code$/, ''
4
+
5
+ for attr, value of address
6
+ $("#{prefix}#{attr}").val(value) if value
@@ -0,0 +1,3 @@
1
+ Location::Engine.routes.draw do
2
+ post '/finder', to: 'finder#show', as: 'location_finder'
3
+ end
@@ -0,0 +1,9 @@
1
+ class CreateLocationCities < ActiveRecord::Migration
2
+ def change
3
+ create_table :location_cities do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class CreateLocationDistricts < ActiveRecord::Migration
2
+ def change
3
+ create_table :location_districts do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class CreateLocationStates < ActiveRecord::Migration
2
+ def change
3
+ create_table :location_states do |t|
4
+ t.string :name
5
+ t.string :abbr
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ class CreateLocationAddresses < ActiveRecord::Migration
2
+ def change
3
+ create_table :location_addresses do |t|
4
+ t.string :postal_code
5
+ t.string :address
6
+ t.string :number
7
+ t.string :complement
8
+ t.references :district, index: true
9
+ t.references :city, index: true
10
+ t.references :state, index: true
11
+ t.decimal :latitude
12
+ t.decimal :longitude
13
+ t.references :addressable, polymorphic: true
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :location_addresses, [:addressable_type, :addressable_id],
19
+ name: 'index_location_addressable_id_and_type'
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ class RemoveCityAndStateFromAddress < ActiveRecord::Migration
2
+ def change
3
+ remove_column :location_addresses, :city_id
4
+ remove_column :location_addresses, :state_id
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddCityToDistrict < ActiveRecord::Migration
2
+ def change
3
+ add_reference :location_districts, :city, index: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddStateToCity < ActiveRecord::Migration
2
+ def change
3
+ add_reference :location_cities, :state, index: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddTypeToAddress < ActiveRecord::Migration
2
+ def change
3
+ add_column :location_addresses, :type, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddNormalizedToStates < ActiveRecord::Migration
2
+ def change
3
+ add_column :location_states, :normalized, :boolean, default: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddNormalizedToCities < ActiveRecord::Migration
2
+ def change
3
+ add_column :location_cities, :normalized, :boolean, default: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddNormalizedToDistricts < ActiveRecord::Migration
2
+ def change
3
+ add_column :location_districts, :normalized, :boolean, default: true
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ require 'location/engine' if defined?(Rails)
2
+ require 'location/finder'
3
+
4
+ Dir[File.dirname(__FILE__) + '/location/services/**/*.rb'].each { |f| require f }
5
+
6
+ module Location
7
+ class << self
8
+ attr_accessor :configuration
9
+ end
10
+
11
+ def self.configuration
12
+ @configuration ||= Configuration.new
13
+ end
14
+
15
+ def self.configure
16
+ yield configuration
17
+ end
18
+
19
+ class Configuration
20
+ attr_accessor :default_service
21
+ attr_accessor :service_options
22
+ attr_accessor :concat_type_to_address
23
+ attr_accessor :normalized_fields
24
+
25
+ def initialize
26
+ @default_service = Services::Republica
27
+ @service_options = {}
28
+ @concat_type_to_address = false
29
+ @normalized_fields = %i{state city}
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ module Location
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Location
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec, view_specs: false
7
+ g.fixture_replacement :factory_girl, dir: 'spec/support/factories'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,66 @@
1
+ module Location
2
+ class Finder
3
+ attr_accessor :postal_code, :service
4
+ attr_reader :address, :error
5
+
6
+ def self.build(postal_code)
7
+ new(postal_code, Location.configuration.default_service.new)
8
+ end
9
+
10
+ def self.find(postal_code, &block)
11
+ build(postal_code).find(&block)
12
+ end
13
+
14
+ def initialize(postal_code, service)
15
+ @postal_code = postal_code
16
+ @service = service
17
+ @address = Address.new
18
+ end
19
+
20
+ def find
21
+ service.fetch(postal_code, address)
22
+ @success = true
23
+ rescue Services::Error => error
24
+ @error = error.message
25
+ @success = false
26
+ ensure
27
+ @address.freeze
28
+ yield self if block_given?
29
+ end
30
+
31
+ def successful?
32
+ @success
33
+ end
34
+
35
+ class Address
36
+ attr_accessor :type, :postal_code
37
+ attr_accessor :address, :number, :complement
38
+ attr_accessor :district, :city, :state
39
+
40
+ def type=(type)
41
+ @type = type
42
+ concat_type_to_address
43
+ end
44
+
45
+ def address=(address)
46
+ @address = address
47
+ concat_type_to_address
48
+ end
49
+
50
+ private
51
+
52
+ def concat_type_to_address
53
+ concat_type_to_address! if concat_type_to_address?
54
+ end
55
+
56
+ def concat_type_to_address?
57
+ Location.configuration.concat_type_to_address &&
58
+ !type.nil? && !address.nil?
59
+ end
60
+
61
+ def concat_type_to_address!
62
+ @address = "#{type} #{address}"
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,6 @@
1
+ module Location
2
+ module Services
3
+ class Error < ::StandardError; end
4
+ class OptionsError < StandardError; end
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module Location
2
+ module Services
3
+ class FailedService
4
+ def fetch(postal_code, address)
5
+ raise Error.new
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Location
2
+ module Services
3
+ class NullService
4
+ def fetch(postal_code, address)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Location
2
+ module Services
3
+ class Republica
4
+ def fetch(postal_code, address)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ module Location
2
+ module Services
3
+ class StubbedService
4
+ class << self
5
+ attr_writer :attributes
6
+ end
7
+
8
+ def self.attributes
9
+ @attributes || {
10
+ address: 'R. Barata Ribeiro',
11
+ number: '1981',
12
+ complement: '',
13
+ district: 'Copacabana',
14
+ city: 'Rio de Janeiro',
15
+ state: 'RJ'
16
+ }
17
+ end
18
+
19
+ def fetch(postal_code, address)
20
+ StubbedService.attributes.each do |k, v|
21
+ address.send("#{k}=", v)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module Location
5
+ module Services
6
+ class Uni5
7
+ FULL_ADDRESS = '1'
8
+ ONLY_CITY_AND_UF = '2'
9
+
10
+ def fetch(postal_code, address)
11
+ @postal_code = postal_code
12
+
13
+ http_request do |res|
14
+ address.state = res['uf']
15
+ address.city = res['cidade']
16
+ address.district = res['bairro']
17
+ address.type = res['tipo_logradouro']
18
+ address.address = res['logradouro']
19
+ end
20
+ end
21
+
22
+ def options
23
+ required = { formato: 'json' }
24
+ required[:cep] = @postal_code if defined?(@postal_code)
25
+
26
+ Location.configuration.service_options.merge(required).tap do |o|
27
+ raise OptionsError, 'Missing auth option' unless o.has_key? :auth
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def http_request
34
+ response = Net::HTTP.get_response(uri)
35
+
36
+ unless response.code == '200'
37
+ raise Error.new, "Got response #{response.code} for #{@postal_code}"
38
+ end
39
+
40
+ yield eval_result(response.body)
41
+ rescue Net::HTTPBadResponse => e
42
+ raise Error.new, 'Got a bad response'
43
+ end
44
+
45
+ def eval_result(json)
46
+ result = JSON.parse(json)
47
+
48
+ unless success? result['resultado']
49
+ raise Error.new, "Couldn't find address for #{@postal_code}"
50
+ end
51
+
52
+ result
53
+ end
54
+
55
+ def success?(result)
56
+ [FULL_ADDRESS, ONLY_CITY_AND_UF].include? result
57
+ end
58
+
59
+ def uri
60
+ URI('http://webservice.uni5.net/web_cep.php').tap do |uri|
61
+ uri.query = URI.encode_www_form(options)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ module Location
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :location do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,258 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: location
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Thiago A. Silva
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 4.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 4.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: sqlite3
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '='
38
+ - !ruby/object:Gem::Version
39
+ version: 1.3.8
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '='
45
+ - !ruby/object:Gem::Version
46
+ version: 1.3.8
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec-rails
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 2.14.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '='
59
+ - !ruby/object:Gem::Version
60
+ version: 2.14.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: capybara
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '='
66
+ - !ruby/object:Gem::Version
67
+ version: 2.2.0
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '='
73
+ - !ruby/object:Gem::Version
74
+ version: 2.2.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: shoulda-matchers
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '='
80
+ - !ruby/object:Gem::Version
81
+ version: 2.4.0
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '='
87
+ - !ruby/object:Gem::Version
88
+ version: 2.4.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: factory_girl_rails
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '='
94
+ - !ruby/object:Gem::Version
95
+ version: 4.3.0
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '='
101
+ - !ruby/object:Gem::Version
102
+ version: 4.3.0
103
+ - !ruby/object:Gem::Dependency
104
+ name: guard-rspec
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - '='
108
+ - !ruby/object:Gem::Version
109
+ version: 4.2.0
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - '='
115
+ - !ruby/object:Gem::Version
116
+ version: 4.2.0
117
+ - !ruby/object:Gem::Dependency
118
+ name: webmock
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '='
122
+ - !ruby/object:Gem::Version
123
+ version: 1.16.1
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '='
129
+ - !ruby/object:Gem::Version
130
+ version: 1.16.1
131
+ - !ruby/object:Gem::Dependency
132
+ name: virtus
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - '='
136
+ - !ruby/object:Gem::Version
137
+ version: 1.0.1
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - '='
143
+ - !ruby/object:Gem::Version
144
+ version: 1.0.1
145
+ - !ruby/object:Gem::Dependency
146
+ name: pry-rails
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - '='
150
+ - !ruby/object:Gem::Version
151
+ version: 0.3.2
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - '='
157
+ - !ruby/object:Gem::Version
158
+ version: 0.3.2
159
+ - !ruby/object:Gem::Dependency
160
+ name: thor
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - '='
164
+ - !ruby/object:Gem::Version
165
+ version: 0.18.1
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - '='
171
+ - !ruby/object:Gem::Version
172
+ version: 0.18.1
173
+ - !ruby/object:Gem::Dependency
174
+ name: simplecov
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - '='
178
+ - !ruby/object:Gem::Version
179
+ version: 0.8.2
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - '='
185
+ - !ruby/object:Gem::Version
186
+ version: 0.8.2
187
+ description: Polymorphic address models, address normalization, address web services,
188
+ address autocomplete, maps
189
+ email:
190
+ - thiagoaraujos@gmail.com
191
+ executables: []
192
+ extensions: []
193
+ extra_rdoc_files: []
194
+ files:
195
+ - MIT-LICENSE
196
+ - Rakefile
197
+ - app/assets/javascripts/location/application.js
198
+ - app/assets/stylesheets/location/application.css
199
+ - app/controllers/location/application_controller.rb
200
+ - app/controllers/location/finder_controller.rb
201
+ - app/helpers/location/application_helper.rb
202
+ - app/models/location/address.rb
203
+ - app/models/location/address_form.rb
204
+ - app/models/location/city.rb
205
+ - app/models/location/district.rb
206
+ - app/models/location/form.rb
207
+ - app/models/location/state.rb
208
+ - app/views/layouts/location/application.html.erb
209
+ - app/views/location/finder/show.js.coffee
210
+ - config/routes.rb
211
+ - db/migrate/20131209160000_create_location_cities.rb
212
+ - db/migrate/20131209160035_create_location_districts.rb
213
+ - db/migrate/20131209160111_create_location_states.rb
214
+ - db/migrate/20131209160523_create_location_addresses.rb
215
+ - db/migrate/20131209165654_remove_city_and_state_from_address.rb
216
+ - db/migrate/20131209171214_add_city_to_district.rb
217
+ - db/migrate/20131209172128_add_state_to_city.rb
218
+ - db/migrate/20140112163948_add_type_to_address.rb
219
+ - db/migrate/20140129154554_add_normalized_to_states.rb
220
+ - db/migrate/20140129154726_add_normalized_to_cities.rb
221
+ - db/migrate/20140129154734_add_normalized_to_districts.rb
222
+ - lib/location.rb
223
+ - lib/location/engine.rb
224
+ - lib/location/finder.rb
225
+ - lib/location/services/errors.rb
226
+ - lib/location/services/failed_service.rb
227
+ - lib/location/services/null_service.rb
228
+ - lib/location/services/republica.rb
229
+ - lib/location/services/stubbed_service.rb
230
+ - lib/location/services/uni5.rb
231
+ - lib/location/version.rb
232
+ - lib/tasks/location_tasks.rake
233
+ homepage: http://github.com/thiagoa/location
234
+ licenses:
235
+ - MIT
236
+ metadata: {}
237
+ post_install_message:
238
+ rdoc_options: []
239
+ require_paths:
240
+ - lib
241
+ required_ruby_version: !ruby/object:Gem::Requirement
242
+ requirements:
243
+ - - ">="
244
+ - !ruby/object:Gem::Version
245
+ version: '0'
246
+ required_rubygems_version: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ requirements: []
252
+ rubyforge_project:
253
+ rubygems_version: 2.2.0
254
+ signing_key:
255
+ specification_version: 4
256
+ summary: Location and address related utilities
257
+ test_files: []
258
+ has_rdoc: