zip_search 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/zip_search/init.js +16 -0
  6. data/app/assets/javascripts/zip_search/jquery.inputmask.bundle.js +2145 -0
  7. data/app/assets/javascripts/zip_search/locations.coffee +69 -0
  8. data/app/assets/stylesheets/zip_search/application.css +15 -0
  9. data/app/assets/stylesheets/zip_search/locations.css +4 -0
  10. data/app/assets/stylesheets/zip_search/typeahead.scss +72 -0
  11. data/app/controllers/zip_search/application_controller.rb +4 -0
  12. data/app/controllers/zip_search/locations_controller.rb +43 -0
  13. data/app/helpers/zip_search/application_helper.rb +4 -0
  14. data/app/helpers/zip_search/locations_helper.rb +4 -0
  15. data/app/models/zip_search/location.rb +9 -0
  16. data/app/views/layouts/zip_search/application.html.erb +14 -0
  17. data/app/views/zip_search/_simple_fields.html.erb +4 -0
  18. data/app/views/zip_search/locations/_search_field.html.erb +19 -0
  19. data/config/routes.rb +4 -0
  20. data/config/spring.rb +1 -0
  21. data/db/migrate/20150914014727_create_zip_search_locations.rb +17 -0
  22. data/db/migrate/20150920034901_add_zs_association_name_to_zip_search_locations.rb +7 -0
  23. data/lib/generators/zip_search/install/install_generator.rb +22 -0
  24. data/lib/tasks/zip_search_tasks.rake +4 -0
  25. data/lib/zip_search/acts_as_location.rb +61 -0
  26. data/lib/zip_search/capybara_helpers.rb +9 -0
  27. data/lib/zip_search/controller_helpers.rb +79 -0
  28. data/lib/zip_search/engine.rb +38 -0
  29. data/lib/zip_search/has_locations.rb +87 -0
  30. data/lib/zip_search/model_helpers.rb +29 -0
  31. data/lib/zip_search/railtie.rb +18 -0
  32. data/lib/zip_search/simple_form_helper.rb +50 -0
  33. data/lib/zip_search/strong_params_helper.rb +17 -0
  34. data/lib/zip_search/version.rb +3 -0
  35. data/lib/zip_search/view_helpers.rb +31 -0
  36. data/lib/zip_search.rb +62 -0
  37. data/spec/factories/travelers.rb +40 -0
  38. data/spec/features/travelers_spec.rb +68 -0
  39. data/spec/models/traveler_spec.rb +38 -0
  40. data/spec/models/zip_search/location_spec.rb +7 -0
  41. data/spec/spec_helper.rb +134 -0
  42. metadata +383 -0
@@ -0,0 +1,50 @@
1
+ require 'zip_search'
2
+
3
+ module ZipSearch
4
+ module SimpleFormHelper
5
+ METHODS_TO_EXPORT = ZipSearch::ASSOCIATION_MODES.map{|m| :"simple_fields_for_#{m}" }
6
+
7
+ def self.simple_fields_for_location(fb, title=:location, *args, &block)
8
+ wrap_zs_fields fb.simple_fields_for(title, *args, &block)
9
+ end
10
+ def self.simple_fields_for_locations(fb, title=:locations, *args, &block)
11
+ wrap_zs_fields fb.simple_fields_for(title, *args, &block)
12
+ end
13
+ def self.simple_fields_for_current_location(fb, title=:current_location, *args, &block)
14
+ wrap_zs_fields fb.simple_fields_for(title, *args, &block)
15
+ end
16
+ def self.simple_fields_for_location_history(fb, title=:location_history, *args, &block)
17
+ wrap_zs_fields fb.simple_fields_for(title, *args, &block)
18
+ end
19
+
20
+ def simple_fields_for_location(*args, &block)
21
+ new_block = block_given? ? block : ->(fb2) {
22
+ render partial: 'zip_search/simple_fields',
23
+ locals: { title: :location, f: fb2 } }
24
+ SimpleFormHelper.simple_fields_for_location(*args, &new_block)
25
+ end
26
+ def simple_fields_for_locations(*args, &block)
27
+ new_block = block_given? ? block : ->(fb2) {
28
+ render partial: 'zip_search/simple_fields',
29
+ locals: { title: :locations, f: fb2 } }
30
+ SimpleFormHelper.simple_fields_for_locations(*args, &new_block)
31
+ end
32
+ def simple_fields_for_current_location(*args, &block)
33
+ new_block = block_given? ? block : ->(fb2) {
34
+ render partial: 'zip_search/simple_fields',
35
+ locals: { title: :current_location, f: fb2 } }
36
+ SimpleFormHelper.simple_fields_for_current_location(*args, &new_block)
37
+ end
38
+ def simple_fields_for_location_history(*args, &block)
39
+ new_block = block_given? ? block : ->(fb2) {
40
+ render partial: 'zip_search/simple_fields',
41
+ locals: { title: :location, f: fb2 } }
42
+ SimpleFormHelper.simple_fields_for_location_history(*args, &new_block)
43
+ end
44
+
45
+ def self.wrap_zs_fields(fields_content)
46
+ "<div class='zs-location-fields'>#{fields_content}</div>".html_safe
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ require 'zip_search'
2
+
3
+ module ZipSearch
4
+ module StrongParamsHelper
5
+ ZipSearch::ASSOCIATION_MODES.each do |am|
6
+ define_method :"#{am}_params" do |title=am|
7
+ rclass = begin params[:controller].classify.constantize
8
+ rescue NameError; nil end
9
+ aclass = if rclass && rclass.has_zipsearch_association?(title)
10
+ rclass.zipsearch_association(title).klass
11
+ else Location end
12
+ { :"#{title}_attributes" => aclass.nested_params }
13
+ end
14
+ end
15
+ extend self
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module ZipSearch
2
+ VERSION = '0.1.3'
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'zip_search'
2
+
3
+ module ZipSearch
4
+ module ViewHelpers
5
+ extend ActiveSupport::Concern
6
+
7
+ def location_search_field(options={})
8
+ settings = {
9
+ field: {
10
+ placeholder: 'Filter by location...',
11
+ class: ''
12
+ },
13
+ form: {
14
+ url: request.url,
15
+ method: :get,
16
+ html: {
17
+ class: '',
18
+ style: ''
19
+ } } }.deep_merge(options)
20
+ if params.key?(:location_search) && params[:location_search].key?(:q)
21
+ settings[:field][:class] << ' zipsearch-typeahead'
22
+ settings[:field][:value] ||= params[:location_search][:q]
23
+ end
24
+ settings[:form][:html][:class] << ' location-search-form pull-left'
25
+ # form_style = "margin:10px 6px 0 0;#{settings[:form][:html][:style]}"
26
+ # settings[:form][:html][:style] = form_style
27
+ render 'zip_search/locations/search_field', settings: settings
28
+ end
29
+
30
+ end
31
+ end
data/lib/zip_search.rb ADDED
@@ -0,0 +1,62 @@
1
+ module ZipSearch
2
+ ASSOCIATION_MODES = %i( location locations location_history current_location )
3
+ def self.association_modes; ASSOCIATION_MODES end
4
+
5
+ US_BOUNDS = [[-124.7844079, 24.7433195], [-66.9513812, 49.3457868]]
6
+ US_STATES = [
7
+ ['Alabama', 'AL'],
8
+ ['Alaska', 'AK'],
9
+ ['Arizona', 'AZ'],
10
+ ['Arkansas', 'AR'],
11
+ ['California', 'CA'],
12
+ ['Colorado', 'CO'],
13
+ ['Connecticut', 'CT'],
14
+ ['Delaware', 'DE'],
15
+ ['District of Columbia', 'DC'],
16
+ ['Florida', 'FL'],
17
+ ['Georgia', 'GA'],
18
+ ['Hawaii', 'HI'],
19
+ ['Idaho', 'ID'],
20
+ ['Illinois', 'IL'],
21
+ ['Indiana', 'IN'],
22
+ ['Iowa', 'IA'],
23
+ ['Kansas', 'KS'],
24
+ ['Kentucky', 'KY'],
25
+ ['Louisiana', 'LA'],
26
+ ['Maine', 'ME'],
27
+ ['Maryland', 'MD'],
28
+ ['Massachusetts', 'MA'],
29
+ ['Michigan', 'MI'],
30
+ ['Minnesota', 'MN'],
31
+ ['Mississippi', 'MS'],
32
+ ['Missouri', 'MO'],
33
+ ['Montana', 'MT'],
34
+ ['Nebraska', 'NE'],
35
+ ['Nevada', 'NV'],
36
+ ['New Hampshire', 'NH'],
37
+ ['New Jersey', 'NJ'],
38
+ ['New Mexico', 'NM'],
39
+ ['New York', 'NY'],
40
+ ['North Carolina', 'NC'],
41
+ ['North Dakota', 'ND'],
42
+ ['Ohio', 'OH'],
43
+ ['Oklahoma', 'OK'],
44
+ ['Oregon', 'OR'],
45
+ ['Pennsylvania', 'PA'],
46
+ ['Puerto Rico', 'PR'],
47
+ ['Rhode Island', 'RI'],
48
+ ['South Carolina', 'SC'],
49
+ ['South Dakota', 'SD'],
50
+ ['Tennessee', 'TN'],
51
+ ['Texas', 'TX'],
52
+ ['Utah', 'UT'],
53
+ ['Vermont', 'VT'],
54
+ ['Virginia', 'VA'],
55
+ ['Washington', 'WA'],
56
+ ['West Virginia', 'WV'],
57
+ ['Wisconsin', 'WI'],
58
+ ['Wyoming', 'WY'] ]
59
+
60
+ end
61
+
62
+ require 'zip_search/engine' if defined? Rails
@@ -0,0 +1,40 @@
1
+ FactoryGirl.define do
2
+ # to_create do |instance|
3
+ # raise "Save failed for #{instance.class} (#{instance.errors.full_messages.inspect})" if !instance.save
4
+ # end
5
+
6
+ factory :traveler do
7
+ name { MFaker::Name.name }
8
+
9
+ %i(location current_location).each{|lm|
10
+ trait(:"with_#{lm}") {
11
+ send(:"#{lm}_attributes") { { zip: random_zip } } } }
12
+ %i(locations location_history).each{|lm|
13
+ trait(:"with_#{lm}") {
14
+ with_current_location if lm == :location_history
15
+ send(:"#{lm}_attributes") { [ { zip: random_zip } ] } } }
16
+
17
+ # trait :with_photo do
18
+ # gallery_attributes {
19
+ # attributes_for :polygallery_gallery, :with_photo }
20
+ # end
21
+ #
22
+ # trait :with_photos do
23
+ # gallery_attributes {
24
+ # attributes_for :polygallery_gallery, :with_photos }
25
+ # end
26
+ #
27
+ # trait :with_custom_photo do
28
+ # custom_gallery_attributes {
29
+ # attributes_for :polygallery_gallery,
30
+ # :with_photo, :title => 'custom_gallery' }
31
+ # end
32
+ #
33
+ # trait :with_custom_photos do
34
+ # custom_gallery_attributes {
35
+ # attributes_for :polygallery_gallery,
36
+ # :with_photos, title: 'custom_gallery' }
37
+ # end
38
+
39
+ end
40
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ feature 'Traveler Management', js: true do
3
+ let(:traveler_attrs) { attributes_for :traveler }
4
+ let(:new_traveler) { build :traveler }
5
+ let(:existing_traveler) { create :traveler }
6
+
7
+ feature 'Adding travelers' do
8
+ def complete_the_form(attrs=nil)
9
+ attrs ||= traveler_attrs
10
+ form_selector = if current_path =~ /edit$/ then 'form.edit_traveler'
11
+ else 'form.new_traveler' end
12
+ within form_selector do
13
+ fill_in 'Name', with: attrs[:name]
14
+ yield(attrs) if block_given?
15
+ click_button ' Traveler'
16
+ end
17
+ end
18
+ def expect_success
19
+ expect(page).to have_content 'Traveler was successfully '
20
+ end
21
+
22
+ it 'basically works' do
23
+ visit new_traveler_path
24
+ expect {
25
+ complete_the_form
26
+ expect_success
27
+ }.to change { Traveler.count }.by 1
28
+ t = Traveler.last
29
+ expect(t.current_location.id).to be_nil
30
+ expect(t.location_history.any?).to be false
31
+ end
32
+
33
+ it 'adds a current location when a zip code is supplied' do
34
+ visit new_traveler_path
35
+ expect {
36
+ complete_the_form {
37
+ fill_in 'traveler_current_location_attributes_zip', with: rand(10000..99999).to_s
38
+ sleep 1 }
39
+ expect_success
40
+ }.to change { Traveler.count }.by 1
41
+ t = Traveler.last
42
+ expect(t.current_location.id).not_to be_nil
43
+ expect(t.location_history.any?).to be false
44
+ end
45
+
46
+ it 'moves old current_location to location history when new one added' do
47
+ visit new_traveler_path
48
+ expect {
49
+ complete_the_form {
50
+ fill_in 'traveler_current_location_attributes_zip', with: rand(10000..99999).to_s
51
+ sleep 1 }
52
+ expect_success
53
+ }.to change { Traveler.count }.by 1
54
+ t = Traveler.last
55
+ expect(t.current_location.id).not_to be_nil
56
+ expect(t.location_history.count).to eq 0
57
+ visit edit_traveler_path(t)
58
+ expect {
59
+ complete_the_form {
60
+ fill_in 'traveler_current_location_attributes_zip', with: rand(10000..99999).to_s
61
+ sleep 1 }
62
+ expect_success
63
+ }.to change { t.reload.current_location.zip }
64
+ expect(t.location_history.count).to eq 1
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Traveler do
4
+ let(:new_traveler) { build :traveler }
5
+ let(:traveler_with_location) { create :traveler, :with_current_location }
6
+ let(:traveler_with_history) { create :traveler, :with_location_history }
7
+
8
+ it 'has a valid factory' do
9
+ expect(new_traveler).to be_valid
10
+ %i(current_location location_history).each{|trait|
11
+ expect(build(:traveler, :"with_#{trait}")).to be_valid }
12
+ end
13
+
14
+ it 'sets the current location when provided with attributes for it' do
15
+ expect(traveler_with_location.current_location.id).not_to be_nil
16
+ end
17
+ it 'sets location history when provided with attributes for it' do
18
+ expect(traveler_with_history.current_location.id).not_to be_nil
19
+ expect(traveler_with_history.location_history.any?).to be true
20
+ end
21
+
22
+ it 'moves old traveler locations into the history association' do
23
+ expect(traveler_with_location.location_history.count).to eq 0
24
+ expect {
25
+ traveler_with_location.current_location.zip = rand(10000..99999).to_s
26
+ traveler_with_location.save
27
+ }.to change { traveler_with_location.reload.location_history.count }.by 1
28
+ expect( traveler_with_location.current_location.id ).not_to be_nil
29
+ expect( traveler_with_location.location_history.any?).to be true
30
+ expect( traveler_with_location.location_history ).not_to include(
31
+ traveler_with_location.current_location )
32
+ end
33
+
34
+ it 'to_sentence returns "Location unavailable" if location_blank? is true' do
35
+ expect(new_traveler.current_location.to_sentence).to eq 'Location unavailable'
36
+ end
37
+
38
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe ZipSearch::Location do
4
+ it 'has a valid factory' do
5
+ puts 'HI!'
6
+ end
7
+ end
@@ -0,0 +1,134 @@
1
+ # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+
20
+ ENV["RAILS_ENV"] = 'test'
21
+ require File.expand_path('../../test/dummy/config/environment', __FILE__)
22
+ require 'rspec/rails'
23
+ require 'selenium-webdriver'
24
+ require 'capybara/rails'
25
+ require 'capybara/dsl'
26
+ require 'factory_girl_rails'
27
+ require 'database_cleaner'
28
+ require 'ffaker'
29
+ require 'byebug'
30
+ require 'zip_search/capybara_helpers'
31
+
32
+ Capybara.app_host = 'http://localhost:3003'
33
+ Capybara.server_port = 3003
34
+ Capybara.default_max_wait_time = 15
35
+ Capybara.register_driver :chrome do |app|
36
+ Capybara::Selenium::Driver.new(app, browser: :chrome)
37
+ end
38
+ Capybara.javascript_driver = :chrome
39
+
40
+ # Requires supporting ruby files with custom matchers and macros, etc,
41
+ # in spec/support/ and its subdirectories.
42
+ # Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
43
+
44
+ # Checks for pending migrations before tests are run.
45
+ # If you are not using ActiveRecord, you can remove this line.
46
+ ActiveRecord::Migration.maintain_test_schema!
47
+
48
+ RSpec.configure do |config|
49
+ # rspec-expectations config goes here. You can use an alternate
50
+ # assertion/expectation library such as wrong or the stdlib/minitest
51
+ # assertions if you prefer.
52
+ config.expect_with :rspec do |expectations|
53
+ # This option will default to `true` in RSpec 4. It makes the `description`
54
+ # and `failure_message` of custom matchers include text for helper methods
55
+ # defined using `chain`, e.g.:
56
+ # be_bigger_than(2).and_smaller_than(4).description
57
+ # # => "be bigger than 2 and smaller than 4"
58
+ # ...rather than:
59
+ # # => "be bigger than 2"
60
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
61
+ end
62
+
63
+ # rspec-mocks config goes here. You can use an alternate test double
64
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
65
+ config.mock_with :rspec do |mocks|
66
+ # Prevents you from mocking or stubbing a method that does not exist on
67
+ # a real object. This is generally recommended, and will default to
68
+ # `true` in RSpec 4.
69
+ mocks.verify_partial_doubles = true
70
+ end
71
+
72
+ config.order = 'random'
73
+
74
+ config.include FactoryGirl::Syntax::Methods
75
+ config.include ZipSearch::CapybaraHelpers, type: 'feature'
76
+
77
+ config.infer_spec_type_from_file_location!
78
+
79
+ config.use_transactional_fixtures = false
80
+
81
+ config.before(:suite) do
82
+ DatabaseCleaner.strategy = :truncation
83
+ DatabaseCleaner.clean_with :truncation
84
+ end
85
+ config.around(:each) {|e| DatabaseCleaner.cleaning { e.run } }
86
+ config.after(:suite) {
87
+ FileUtils.rm_rf Dir["#{Rails.root}/public/system/test/"] }
88
+
89
+
90
+ # The settings below are suggested to provide a good initial experience
91
+ # with RSpec, but feel free to customize to your heart's content.
92
+ =begin
93
+ # These two settings work together to allow you to limit a spec run
94
+ # to individual examples or groups you care about by tagging them with
95
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
96
+ # get run.
97
+ config.filter_run :focus
98
+ config.run_all_when_everything_filtered = true
99
+
100
+ # Limits the available syntax to the non-monkey patched syntax that is
101
+ # recommended. For more details, see:
102
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
103
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
104
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
105
+ config.disable_monkey_patching!
106
+
107
+ # Many RSpec users commonly either run the entire suite or an individual
108
+ # file, and it's useful to allow more verbose output when running an
109
+ # individual spec file.
110
+ if config.files_to_run.one?
111
+ # Use the documentation formatter for detailed output,
112
+ # unless a formatter has already been configured
113
+ # (e.g. via a command-line flag).
114
+ config.default_formatter = 'doc'
115
+ end
116
+
117
+ # Print the 10 slowest examples and example groups at the
118
+ # end of the spec run, to help surface which specs are running
119
+ # particularly slow.
120
+ config.profile_examples = 10
121
+
122
+ # Run specs in random order to surface order dependencies. If you find an
123
+ # order dependency and want to debug it, you can fix the order by providing
124
+ # the seed, which is printed after each run.
125
+ # --seed 1234
126
+ config.order = :random
127
+
128
+ # Seed global randomization in this process using the `--seed` CLI option.
129
+ # Setting this allows you to use `--seed` to deterministically reproduce
130
+ # test failures related to randomization by passing the same `--seed` value
131
+ # as the one that triggered the failure.
132
+ Kernel.srand config.seed
133
+ =end
134
+ end