├── .gitignore ├── .travis.yml ├── Appraisals ├── CHANGELOG.md ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── carmen-rails.gemspec ├── gemfiles ├── rails_3.gemfile ├── rails_3.gemfile.lock ├── rails_4.gemfile └── rails_4.gemfile.lock ├── lib ├── carmen-rails.rb ├── carmen │ └── rails │ │ ├── action_view │ │ └── form_helper.rb │ │ └── version.rb └── tasks │ └── carmen-rails_tasks.rake └── test ├── carmen └── action_view │ └── helpers │ └── form_helper_test.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | Gemfile.lock 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 1.9.2 3 | - 1.9.3 4 | - 2.0.0 5 | env: 6 | - "RAILS_VERSION=3.1.0" 7 | - "RAILS_VERSION=3.2.0" 8 | - "RAILS_VERSION=4.0.0" 9 | matrix: 10 | exclude: 11 | - rvm: 1.9.2 12 | env: "RAILS_VERSION=4.0.0" 13 | branches: 14 | only: 15 | - master 16 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise "rails-3" do 2 | gem "rails", "~> 3.2" 3 | end 4 | 5 | appraise "rails-4" do 6 | gem "rails", "~> 4.0" 7 | end 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 1.0.1 2 | 3 | * Rails 4 compatibility. 4 | 5 | ### 1.0.0 6 | 7 | Updates 8 | 9 | * Push from beta to 1.0.0 final. 10 | 11 | ### 1.0.0.beta 3 12 | 13 | Bug Fixes 14 | 15 | * Removed some 1.9 syntax taht prevented the gem from running on Ruby 1.8 16 | 17 | Enhancements 18 | 19 | * Region select options are now sorted (lukast-akra) 20 | 21 | API Changes 22 | 23 | * region_options_for_select now takes priority region codes in an options hash 24 | under the key 'priority'. 25 | * The API for region_options_for_select now expects a collection of Carmen::Regions 26 | as its second argument instead of a parent region. This makes it simple to provide 27 | a custom collection of regions to build a select from. 28 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem 'appraisal', "1.0.0.beta3" 6 | gem "debugger" 7 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012 Jim Benton and contributors 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. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOT ACTIVELY MAINTAINED 2 | 3 | I haven't time in over a year to properly support this project. 4 | 5 | # carmen-rails 6 | 7 | carmen-rails is a Rails 3 plugin that supplies two new form helper methods: 8 | `country_select` and `subregion_select`. It uses 9 | [carmen](http://github.com/jim/carmen) as its source of geographic data. 10 | 11 | ## Requirements 12 | 13 | carmen-rails requires Ruby 1.9.2 or greater. 14 | 15 | ## Installation 16 | 17 | Just add carmen-rails to your Gemfile: 18 | 19 | ```ruby 20 | gem 'carmen-rails', '~> 1.0.0' 21 | ``` 22 | ## Usage 23 | 24 | ```erb 25 | <%= form_for(@order) do |f| %> 26 |
27 | <%= f.label :country_code %>
28 | <%= f.country_select :country_code, {priority: %w(US CA), prompt: 'Please select a country'} %> 29 |
30 | <% end %> 31 | ``` 32 | 33 | #### SimpleForm 34 | Pass the object to the country_select helper. This ensures the persisted country is selected when the form is rendered. 35 | 36 | ```erb 37 | <%= simple_form_for @user do |f| %> 38 | <%= f.input :country_code do %> 39 | <%= f.country_select :country_code, {object: f.object, prompt: 'Country'} %> 40 | <% end %> 41 | <% end %> 42 | ``` 43 | 44 | Passing the object is necessary when using nested form fields with Formtastic. 45 | 46 | ## How do I only display a subset of countries/regions? 47 | 48 | Carmen had a concept of excluded countries in the old days, where you could 49 | specify certain countries or regions to not include in a select. 50 | 51 | The new (and much more flexible) way to handle this is to write a helper method 52 | that returns the subset of regions you want to provide: 53 | 54 | ``` ruby 55 | def only_us_and_canada 56 | Carmen::Country.all.select{|c| %w{US CA}.include?(c.code)} 57 | end 58 | ``` 59 | 60 | And then in your form something like this: 61 | 62 | ``` erb 63 | <%= f.select :country, region_options_for_select(only_us_and_canada) %> 64 | ``` 65 | 66 | More docs coming soon. In the meantime, all of the public methods in 67 | carmen-rails [have been thoroughly TomDoc'ed](https://github.com/jim/carmen-rails/blob/master/lib/carmen/rails/action_view/form_helper.rb). 68 | 69 | ### Demo app 70 | 71 | There is a [live demo app](http://carmen-rails-demo.herokuapp.com) that shows 72 | carmen-rails in action, and includes a [step-by-step setup guide](https://github.com/jim/carmen-demo-app#readme). 73 | 74 | ## Configuration 75 | 76 | Using this library will automatically set Carmen to use [Rails' built-in I18n functionality](http://guides.rubyonrails.org/i18n.html). This means that changing 77 | some configuration should be done through Rails and not Carmen. For example, adding paths for additional locale files 78 | should be done inside `config/application.rb`: 79 | 80 | ``` ruby 81 | config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 82 | ``` 83 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "rubygems" 2 | require 'bundler/setup' 3 | 4 | require 'rake' 5 | require 'rake/testtask' 6 | require 'rdoc/task' 7 | 8 | Bundler::GemHelper.install_tasks 9 | 10 | Rake::TestTask.new(:test) do |t| 11 | t.libs << 'lib' 12 | t.libs << 'test' 13 | t.pattern = 'test/**/*_test.rb' 14 | t.verbose = true 15 | end 16 | 17 | desc 'Default: run unit tests.' 18 | task :default => :test 19 | -------------------------------------------------------------------------------- /carmen-rails.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | require "carmen/rails/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "carmen-rails" 7 | s.version = Carmen::Rails::VERSION 8 | s.authors = ["Jim Benton"] 9 | s.email = ["jim@autonomousmachine.com"] 10 | s.homepage = "http://github.com/jim/carmen-rails" 11 | s.summary = "Rails adapter for Carmen" 12 | s.description = "Provides country_select and subregion_select form helpers." 13 | 14 | s.files = Dir["{lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.md"] 15 | s.test_files = Dir["spec/**/*"] 16 | 17 | s.add_dependency "rails" 18 | s.add_dependency "carmen", "~> 1.0.0" 19 | 20 | s.add_development_dependency "minitest" 21 | end 22 | -------------------------------------------------------------------------------- /gemfiles/rails_3.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "appraisal", "1.0.0.beta3" 6 | gem "debugger" 7 | gem "rails", "~> 3.2" 8 | 9 | gemspec :path=>".././" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_3.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .././ 3 | specs: 4 | carmen-rails (1.0.0) 5 | carmen (~> 1.0.0) 6 | rails 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actionmailer (3.2.17) 12 | actionpack (= 3.2.17) 13 | mail (~> 2.5.4) 14 | actionpack (3.2.17) 15 | activemodel (= 3.2.17) 16 | activesupport (= 3.2.17) 17 | builder (~> 3.0.0) 18 | erubis (~> 2.7.0) 19 | journey (~> 1.0.4) 20 | rack (~> 1.4.5) 21 | rack-cache (~> 1.2) 22 | rack-test (~> 0.6.1) 23 | sprockets (~> 2.2.1) 24 | activemodel (3.2.17) 25 | activesupport (= 3.2.17) 26 | builder (~> 3.0.0) 27 | activerecord (3.2.17) 28 | activemodel (= 3.2.17) 29 | activesupport (= 3.2.17) 30 | arel (~> 3.0.2) 31 | tzinfo (~> 0.3.29) 32 | activeresource (3.2.17) 33 | activemodel (= 3.2.17) 34 | activesupport (= 3.2.17) 35 | activesupport (3.2.17) 36 | i18n (~> 0.6, >= 0.6.4) 37 | multi_json (~> 1.0) 38 | appraisal (1.0.0.beta3) 39 | bundler 40 | rake 41 | thor (>= 0.14.0) 42 | arel (3.0.3) 43 | builder (3.0.4) 44 | carmen (1.0.1) 45 | unicode_utils (~> 1.4.0) 46 | columnize (0.3.6) 47 | debugger (1.6.6) 48 | columnize (>= 0.3.1) 49 | debugger-linecache (~> 1.2.0) 50 | debugger-ruby_core_source (~> 1.3.2) 51 | debugger-linecache (1.2.0) 52 | debugger-ruby_core_source (1.3.2) 53 | erubis (2.7.0) 54 | hike (1.2.3) 55 | i18n (0.6.9) 56 | journey (1.0.4) 57 | json (1.8.1) 58 | mail (2.5.4) 59 | mime-types (~> 1.16) 60 | treetop (~> 1.4.8) 61 | mime-types (1.25.1) 62 | minitest (5.3.0) 63 | multi_json (1.9.0) 64 | polyglot (0.3.4) 65 | rack (1.4.5) 66 | rack-cache (1.2) 67 | rack (>= 0.4) 68 | rack-ssl (1.3.3) 69 | rack 70 | rack-test (0.6.2) 71 | rack (>= 1.0) 72 | rails (3.2.17) 73 | actionmailer (= 3.2.17) 74 | actionpack (= 3.2.17) 75 | activerecord (= 3.2.17) 76 | activeresource (= 3.2.17) 77 | activesupport (= 3.2.17) 78 | bundler (~> 1.0) 79 | railties (= 3.2.17) 80 | railties (3.2.17) 81 | actionpack (= 3.2.17) 82 | activesupport (= 3.2.17) 83 | rack-ssl (~> 1.3.2) 84 | rake (>= 0.8.7) 85 | rdoc (~> 3.4) 86 | thor (>= 0.14.6, < 2.0) 87 | rake (10.1.1) 88 | rdoc (3.12.2) 89 | json (~> 1.4) 90 | sprockets (2.2.2) 91 | hike (~> 1.2) 92 | multi_json (~> 1.0) 93 | rack (~> 1.0) 94 | tilt (~> 1.1, != 1.3.0) 95 | thor (0.18.1) 96 | tilt (1.4.1) 97 | treetop (1.4.15) 98 | polyglot 99 | polyglot (>= 0.3.1) 100 | tzinfo (0.3.38) 101 | unicode_utils (1.4.0) 102 | 103 | PLATFORMS 104 | ruby 105 | 106 | DEPENDENCIES 107 | appraisal (= 1.0.0.beta3) 108 | carmen-rails! 109 | debugger 110 | minitest 111 | rails (~> 3.2) 112 | -------------------------------------------------------------------------------- /gemfiles/rails_4.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "appraisal", "1.0.0.beta3" 6 | gem "debugger" 7 | gem "rails", "~> 4.0" 8 | 9 | gemspec :path=>".././" 10 | -------------------------------------------------------------------------------- /gemfiles/rails_4.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .././ 3 | specs: 4 | carmen-rails (1.0.0) 5 | carmen (~> 1.0.0) 6 | rails 7 | 8 | GEM 9 | remote: http://rubygems.org/ 10 | specs: 11 | actionmailer (4.0.3) 12 | actionpack (= 4.0.3) 13 | mail (~> 2.5.4) 14 | actionpack (4.0.3) 15 | activesupport (= 4.0.3) 16 | builder (~> 3.1.0) 17 | erubis (~> 2.7.0) 18 | rack (~> 1.5.2) 19 | rack-test (~> 0.6.2) 20 | activemodel (4.0.3) 21 | activesupport (= 4.0.3) 22 | builder (~> 3.1.0) 23 | activerecord (4.0.3) 24 | activemodel (= 4.0.3) 25 | activerecord-deprecated_finders (~> 1.0.2) 26 | activesupport (= 4.0.3) 27 | arel (~> 4.0.0) 28 | activerecord-deprecated_finders (1.0.3) 29 | activesupport (4.0.3) 30 | i18n (~> 0.6, >= 0.6.4) 31 | minitest (~> 4.2) 32 | multi_json (~> 1.3) 33 | thread_safe (~> 0.1) 34 | tzinfo (~> 0.3.37) 35 | appraisal (1.0.0.beta3) 36 | bundler 37 | rake 38 | thor (>= 0.14.0) 39 | arel (4.0.2) 40 | atomic (1.1.15) 41 | builder (3.1.4) 42 | carmen (1.0.1) 43 | unicode_utils (~> 1.4.0) 44 | columnize (0.3.6) 45 | debugger (1.6.6) 46 | columnize (>= 0.3.1) 47 | debugger-linecache (~> 1.2.0) 48 | debugger-ruby_core_source (~> 1.3.2) 49 | debugger-linecache (1.2.0) 50 | debugger-ruby_core_source (1.3.2) 51 | erubis (2.7.0) 52 | hike (1.2.3) 53 | i18n (0.6.9) 54 | mail (2.5.4) 55 | mime-types (~> 1.16) 56 | treetop (~> 1.4.8) 57 | mime-types (1.25.1) 58 | minitest (4.7.5) 59 | multi_json (1.9.0) 60 | polyglot (0.3.4) 61 | rack (1.5.2) 62 | rack-test (0.6.2) 63 | rack (>= 1.0) 64 | rails (4.0.3) 65 | actionmailer (= 4.0.3) 66 | actionpack (= 4.0.3) 67 | activerecord (= 4.0.3) 68 | activesupport (= 4.0.3) 69 | bundler (>= 1.3.0, < 2.0) 70 | railties (= 4.0.3) 71 | sprockets-rails (~> 2.0.0) 72 | railties (4.0.3) 73 | actionpack (= 4.0.3) 74 | activesupport (= 4.0.3) 75 | rake (>= 0.8.7) 76 | thor (>= 0.18.1, < 2.0) 77 | rake (10.1.1) 78 | sprockets (2.11.0) 79 | hike (~> 1.2) 80 | multi_json (~> 1.0) 81 | rack (~> 1.0) 82 | tilt (~> 1.1, != 1.3.0) 83 | sprockets-rails (2.0.1) 84 | actionpack (>= 3.0) 85 | activesupport (>= 3.0) 86 | sprockets (~> 2.8) 87 | thor (0.18.1) 88 | thread_safe (0.2.0) 89 | atomic (>= 1.1.7, < 2) 90 | tilt (1.4.1) 91 | treetop (1.4.15) 92 | polyglot 93 | polyglot (>= 0.3.1) 94 | tzinfo (0.3.38) 95 | unicode_utils (1.4.0) 96 | 97 | PLATFORMS 98 | ruby 99 | 100 | DEPENDENCIES 101 | appraisal (= 1.0.0.beta3) 102 | carmen-rails! 103 | debugger 104 | minitest 105 | rails (~> 4.0) 106 | -------------------------------------------------------------------------------- /lib/carmen-rails.rb: -------------------------------------------------------------------------------- 1 | require 'carmen' 2 | require 'carmen/rails/action_view/form_helper' 3 | require 'carmen/rails/version' 4 | 5 | module Carmen 6 | module Rails 7 | class Railtie < ::Rails::Railtie 8 | # Add Carmen's locale paths to the Rails backend 9 | paths = Carmen.i18n_backend.locale_paths.map { |path| 10 | Dir[path + '**/*.yml'] 11 | }.flatten.compact 12 | Carmen.i18n_backend = ::I18n 13 | config.i18n.load_path += paths 14 | 15 | # Enable fallbacks so that missing translations use the default locale 16 | config.i18n.fallbacks = true 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/carmen/rails/action_view/form_helper.rb: -------------------------------------------------------------------------------- 1 | module ActionView 2 | module Helpers 3 | module FormOptionsHelper 4 | 5 | # Generate select and subregion option tags for the given object and method. A 6 | # common use of this would be to allow users to select a state subregion within 7 | # a given country. 8 | # 9 | # object - The model object to generate the select for 10 | # method - The attribute on the object 11 | # parent_region_or_code - An instance of Carmen::Region or a 2-character 12 | # country code. 13 | # options - Other options pertaining to option tag generation. See 14 | # `region_options_for_select`. 15 | # html_options - Options to use when generating the select tag- class, 16 | # id, etc. 17 | # 18 | # Uses region_options_for_select to generate the list of option tags. 19 | # 20 | # Example: 21 | # 22 | # subregion_select(@object, :region, {priority: ['US', 'CA']}, class: 'region') 23 | # 24 | # Returns an `html_safe` string containing the HTML for a select element. 25 | def subregion_select(object, method, parent_region_or_code, options={}, html_options={}) 26 | parent_region = determine_parent(parent_region_or_code) 27 | tag = instance_tag(object, method, self, options) 28 | tag.to_region_select_tag(parent_region, options, html_options) 29 | end 30 | 31 | # Generate select and country option tags for the given object and method. A 32 | # common use of this would be to allow users to select a state subregion within 33 | # a given country. 34 | # 35 | # object - The model object to generate the select for 36 | # method - The attribute on the object 37 | # options - Other options pertaining to option tag generation. See 38 | # `region_options_for_select`. 39 | # html_options - Options to use when generating the select tag- class, 40 | # id, etc. 41 | # 42 | # Uses region_options_or_select to generate the list of option tags. 43 | # 44 | # Example: 45 | # 46 | # country_select(@object, :region, {priority: ['US', 'CA']}, class: 'region') 47 | # 48 | # Note that in order to preserve compatibility with various existing 49 | # libraries, an alternative API is supported but not recommended: 50 | # 51 | # country_select(@object, :region, ['US', 'CA'], class: region) 52 | # 53 | # Returns an `html_safe` string containing the HTML for a select element. 54 | def country_select(object, method, priorities_or_options = {}, options_or_html_options = {}, html_options = {}) 55 | if priorities_or_options.is_a? Array 56 | options = options_or_html_options 57 | options[:priority] = priorities_or_options 58 | else 59 | options = priorities_or_options 60 | html_options = options_or_html_options 61 | end 62 | 63 | tag = instance_tag(object, method, self, options) 64 | tag.to_region_select_tag(Carmen::World.instance, options, html_options) 65 | end 66 | 67 | # Generate option tags for a collection of regions. 68 | # 69 | # regions - An array or Carmen::RegionCollection containing Carmen::Regions 70 | # selected - the code of the region that should be selected 71 | # options - The hash of options used to customize the output (default: {}): 72 | # 73 | # To use priority regions (which are included in a special section at the 74 | # top of the list), provide an array of region codes at the :priority 75 | # option: 76 | # 77 | # region_options_for_select(@region.subregions, 'US', priority: ['US', 'CA']) 78 | # 79 | # Returns an `html_safe` string containing option tags. 80 | def region_options_for_select(regions, selected=nil, options={}) 81 | options.stringify_keys! 82 | priority_region_codes = options['priority'] || [] 83 | region_options = "" 84 | 85 | unless priority_region_codes.empty? 86 | unless regions.respond_to?(:coded) 87 | regions = Carmen::RegionCollection.new(regions) 88 | end 89 | 90 | priority_regions = priority_region_codes.map do |code| 91 | region = regions.coded(code) 92 | [region.name, region.code] if region 93 | end.compact 94 | unless priority_regions.empty? 95 | region_options += options_for_select(priority_regions, selected) 96 | region_options += "" 97 | 98 | # If a priority region is selected, don't select it again in the main list. 99 | # This prevents some browsers from selecting the second occurance of this region, 100 | # which makes it difficult to select an alternative priority region. 101 | selected = nil if priority_region_codes.include?(selected) 102 | end 103 | end 104 | 105 | main_options = regions.map { |r| [r.name, r.code] } 106 | main_options.sort!{|a, b| a.first.to_s <=> b.first.to_s} 107 | main_options.unshift [options['prompt'], ''] if options['prompt'] 108 | 109 | region_options += options_for_select(main_options, selected) 110 | region_options.html_safe 111 | end 112 | 113 | # Generate select and country option tags with the provided name. A 114 | # common use of this would be to allow users to select a country name 115 | # inside a web form. 116 | # 117 | # name - The name attribute for the select element. 118 | # options - Other options pertaining to option tag generation. See 119 | # `region_options_for_select`. 120 | # html_options - Options to use when generating the select tag- class, 121 | # id, etc. 122 | # 123 | # Uses region_options_or_select to generate the list of option tags. 124 | # 125 | # Example: 126 | # 127 | # country_select_tag('country_code', {priority: ['US', 'CA']}, class: 'region') 128 | # 129 | # Returns an `html_safe` string containing the HTML for a select element. 130 | def country_select_tag(name, value, options={}) 131 | subregion_select_tag(name, value, Carmen::World.instance, options) 132 | end 133 | 134 | # Generate select and subregion option tags for the given object and method. A 135 | # common use of this would be to allow users to select a state subregion within 136 | # a given country. 137 | # 138 | # name - The name attribute for the select element. 139 | # parent_region_or_code - An instance of Carmen::Region or a 2-character 140 | # country code. 141 | # options - Other options pertaining to option tag generation. See 142 | # `region_options_for_select`. 143 | # html_options - Options to use when generating the select tag- class, 144 | # id, etc. 145 | # 146 | # Uses region_options_or_select to generate the list of option tags. 147 | # 148 | # Example: 149 | # 150 | # subregion_select_tag('state_code', 'US', {priority: ['US', 'CA']}, class: 'region') 151 | # 152 | # Returns an `html_safe` string containing the HTML for a select element. 153 | def subregion_select_tag(name, value, parent_region_or_code, options = {}, html_options = {}) 154 | options.stringify_keys! 155 | parent_region = determine_parent(parent_region_or_code) 156 | opts = region_options_for_select(parent_region.subregions, value, options) 157 | html_options = {"name" => name, 158 | "id" => sanitize_to_id(name)}.update(html_options.stringify_keys) 159 | content_tag(:select, opts, html_options) 160 | end 161 | 162 | private 163 | 164 | def instance_tag(object_name, method_name, template_object, options = {}) 165 | if Rails::VERSION::MAJOR == 3 166 | InstanceTag.new(object_name, method_name, template_object, options.delete(:object)) 167 | else 168 | ActionView::Helpers::Tags::Base.new(object_name, method_name, template_object, options || {}) 169 | end 170 | end 171 | 172 | 173 | def determine_parent(parent_region_or_code) 174 | case parent_region_or_code 175 | when String 176 | Carmen::Country.coded(parent_region_or_code) 177 | when Array 178 | parent_region_or_code.inject(Carmen::World.instance) { |parent, next_code| 179 | parent.subregions.coded(next_code) 180 | } 181 | else 182 | parent_region_or_code 183 | end 184 | end 185 | end 186 | 187 | if Rails::VERSION::MAJOR == 3 188 | class InstanceTag 189 | def to_region_select_tag(parent_region, options = {}, html_options = {}) 190 | html_options = html_options.stringify_keys 191 | add_default_name_and_id(html_options) 192 | priority_regions = options[:priority] || [] 193 | value = options[:selected] ? options[:selected] : value(object) 194 | opts = add_options(region_options_for_select(parent_region.subregions, value, :priority => priority_regions), options, value) 195 | content_tag("select", opts, html_options) 196 | end 197 | end 198 | end 199 | 200 | if Rails::VERSION::MAJOR == 4 201 | module Tags 202 | class Base 203 | def to_region_select_tag(parent_region, options = {}, html_options = {}) 204 | html_options = html_options.stringify_keys 205 | add_default_name_and_id(html_options) 206 | options[:include_blank] ||= true unless options[:prompt] || select_not_required?(html_options) 207 | 208 | value = options[:selected] ? options[:selected] : value(object) 209 | priority_regions = options[:priority] || [] 210 | opts = add_options(region_options_for_select(parent_region.subregions, value, 211 | :priority => priority_regions), 212 | options, value) 213 | select = content_tag("select", opts, html_options) 214 | if html_options["multiple"] && options.fetch(:include_hidden, true) 215 | tag("input", :disabled => html_options["disabled"], :name => html_options["name"], 216 | :type => "hidden", :value => "") + select 217 | else 218 | select 219 | end 220 | end 221 | end 222 | end 223 | end 224 | 225 | class FormBuilder 226 | # Generate select and country option tags with the provided name. A 227 | # common use of this would be to allow users to select a country name inside a 228 | # web form. 229 | # 230 | # See `FormOptionsHelper::country_select` for more information. 231 | def country_select(method, priorities_or_options = {}, options_or_html_options = {}, html_options = {}) 232 | if priorities_or_options.is_a? Array 233 | options = options_or_html_options 234 | options[:priority] = priorities_or_options 235 | else 236 | options = priorities_or_options 237 | html_options = options_or_html_options 238 | end 239 | 240 | @template.country_select(@object_name, method, objectify_options(options), @default_options.merge(html_options)) 241 | end 242 | 243 | # Generate select and subregion option tags with the provided name. A 244 | # common use of this would be to allow users to select a state subregion within 245 | # a given country. 246 | # 247 | # See `FormOptionsHelper::subregion_select` for more information. 248 | def subregion_select(method, parent_region_or_code, options = {}, html_options = {}) 249 | @template.subregion_select(@object_name, method, parent_region_or_code, objectify_options(options), @default_options.merge(html_options)) 250 | end 251 | end 252 | 253 | end 254 | end 255 | -------------------------------------------------------------------------------- /lib/carmen/rails/version.rb: -------------------------------------------------------------------------------- 1 | module Carmen 2 | module Rails 3 | VERSION = "1.0.1" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/tasks/carmen-rails_tasks.rake: -------------------------------------------------------------------------------- 1 | # desc "Explaining what the task does" 2 | # task :carmen-rails do 3 | # # Task goes here 4 | # end 5 | -------------------------------------------------------------------------------- /test/carmen/action_view/helpers/form_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class CarmenViewHelperTest < MiniTest::Unit::TestCase 4 | include ActionView::Helpers::FormOptionsHelper 5 | include ActionView::Helpers::FormTagHelper 6 | include ActionDispatch::Assertions::SelectorAssertions 7 | 8 | def setup 9 | @object = OpenStruct.new 10 | def @object.to_s; 'object'; end 11 | end 12 | 13 | def response_from_page 14 | HTML::Document.new(@html).root 15 | end 16 | 17 | def test_basic_country_select 18 | html = country_select(:object, :country_code) 19 | expected = <<-HTML 20 | 25 | HTML 26 | 27 | assert_equal_markup(expected, html) 28 | end 29 | 30 | def test_country_selected_value 31 | @html = country_select(:object, :country_code, :selected => 'OC') 32 | assert_select('option[selected="selected"][value="OC"]') 33 | end 34 | 35 | def test_country_selected_object_option 36 | @object.country_code = 'OC' 37 | override_object = OpenStruct.new(:country_code => 'ES') 38 | @html = country_select(@object, :country_code, {:object => override_object}) 39 | 40 | assert_select('option[selected="selected"][value="ES"]') 41 | end 42 | 43 | def test_basic_country_select_tag 44 | html = country_select_tag('attribute_name', nil) 45 | expected = <<-HTML 46 | 51 | HTML 52 | 53 | assert_equal_markup(expected, html) 54 | end 55 | 56 | def test_country_select_tag_with_prompt 57 | html = country_select_tag('attribute_name', nil, :prompt => 'Please Select') 58 | expected = <<-HTML 59 | 65 | HTML 66 | 67 | assert_equal_markup(expected, html) 68 | end 69 | def test_country_tag_selected_value 70 | @html = country_select_tag(:country_code, 'OC') 71 | assert_select('option[selected="selected"][value="OC"]') 72 | end 73 | 74 | def test_priority_country_select 75 | html = country_select(:object, :country_code, :priority => ['ES']) 76 | expected = <<-HTML 77 | 84 | HTML 85 | 86 | assert_equal_markup(expected, html) 87 | end 88 | 89 | def test_priority_country_select_deprecated_api 90 | html = country_select(:object, :country_code, ['ES'], {}) 91 | expected = <<-HTML 92 | 99 | HTML 100 | 101 | assert_equal_markup(expected, html) 102 | end 103 | 104 | def test_country_select_selected_priority_region_not_selected_twice 105 | @object.country_code = 'ES' 106 | 107 | html = country_select(@object, :country_code, :priority => ['ES']) 108 | expected = <<-HTML 109 | 116 | HTML 117 | 118 | assert_equal_markup(expected, html) 119 | end 120 | 121 | def test_basic_subregion_select 122 | oceania = Carmen::Country.coded('OC') 123 | expected = <<-HTML 124 | 127 | HTML 128 | 129 | html = subregion_select(:object, :subregion_code, oceania) 130 | 131 | assert_equal_markup(expected, html) 132 | end 133 | 134 | def test_subregion_select_using_parent_code 135 | expected = <<-HTML 136 | 139 | HTML 140 | 141 | html = subregion_select(:object, :subregion_code, 'OC') 142 | 143 | assert_equal_markup(expected, html) 144 | end 145 | 146 | def test_subregion_select_using_parent_code_array 147 | expected = <<-HTML 148 | 151 | HTML 152 | 153 | html = subregion_select(:object, :subregion_code, ['OC', 'AO']) 154 | 155 | assert_equal_markup(expected, html) 156 | end 157 | 158 | def test_subregion_selected_value 159 | oceania = Carmen::Country.coded('OC') 160 | 161 | @html = subregion_select(:object, :subregion_code, oceania, :selected => 'AO') 162 | assert_select('option[selected="selected"][value="AO"]') 163 | end 164 | 165 | def test_subregion_selected_value_with_priority_and_selected_options 166 | oceania = Carmen::Country.coded('OC') 167 | @html = subregion_select(:object, :subregion_code, oceania, { priority: ['AO'], selected: 'AO' }) 168 | 169 | assert_select('option[selected="selected"][value="AO"]') 170 | end 171 | 172 | def test_html_options_for_selected_value_with_priority_and_selected_options 173 | oceania = Carmen::Country.coded('OC') 174 | @html = subregion_select(:object, :subregion_code, oceania, { priority: ['AO'], selected: 'AO' }, { class: :test_html_options}) 175 | 176 | assert_select('.test_html_options') 177 | end 178 | 179 | def test_basic_subregion_select_tag 180 | oceania = Carmen::Country.coded('OC') 181 | expected = <<-HTML 182 | 185 | HTML 186 | 187 | html = subregion_select_tag(:subregion_code, nil, oceania) 188 | 189 | assert_equal_markup(expected, html) 190 | end 191 | 192 | def test_subregion_select_tag_with_priority 193 | oceania = Carmen::Country.coded('OC') 194 | expected = <<-HTML 195 | 200 | HTML 201 | 202 | html = subregion_select_tag(:subregion_code, nil, oceania, :priority => ['AO']) 203 | 204 | assert_equal_markup(expected, html) 205 | end 206 | 207 | def test_subregion_select_tag_with_prompt 208 | oceania = Carmen::Country.coded('OC') 209 | expected = <<-HTML 210 | 214 | HTML 215 | 216 | html = subregion_select_tag(:subregion_code, nil, oceania, :prompt => 'Please select') 217 | 218 | assert_equal_markup(expected, html) 219 | end 220 | 221 | def test_region_options_for_select 222 | regions = Carmen::Country.all 223 | if Rails::VERSION::MAJOR == 3 224 | expected = <<-HTML 225 | 226 | 227 | 228 | HTML 229 | else 230 | expected = <<-HTML 231 | 232 | 233 | 234 | HTML 235 | end 236 | html = region_options_for_select(regions, 'OC') 237 | 238 | assert_equal_markup(expected, html) 239 | end 240 | 241 | def test_region_options_for_select_with_array_of_regions_and_priority 242 | regions = [Carmen::Country.coded('ES'), Carmen::Country.coded('EU')] 243 | expected = <<-HTML 244 | 245 | 246 | 247 | 248 | HTML 249 | html = region_options_for_select(regions, nil, :priority => ['ES']) 250 | 251 | assert_equal_markup(expected, html) 252 | end 253 | 254 | def test_form_builder_country_select 255 | form = ActionView::Helpers::FormBuilder.new(:object, @object, self, {}, lambda{}) 256 | 257 | html = form.country_select('attribute_name') 258 | expected = <<-HTML 259 | 264 | HTML 265 | 266 | assert_equal_markup(expected, html) 267 | end 268 | 269 | def test_form_builder_selected_country 270 | @object.country_code = 'OC' 271 | form = ActionView::Helpers::FormBuilder.new(:object, @object, self, {}, lambda{}) 272 | @html = form.country_select('country_code') 273 | 274 | assert_select('option[selected="selected"][value="OC"]') 275 | end 276 | 277 | def test_form_builder_country_select_deprecated_api 278 | form = ActionView::Helpers::FormBuilder.new(:object, @object, self, {}, lambda{}) 279 | 280 | html = form.country_select('attribute_name', ['ES']) 281 | expected = <<-HTML 282 | 289 | HTML 290 | 291 | assert_equal_markup(expected, html) 292 | end 293 | 294 | def test_form_builder_subregion_select 295 | form = ActionView::Helpers::FormBuilder.new(:object, @object, self, {}, lambda{}) 296 | html = form.subregion_select(:subregion_code, 'OC') 297 | expected = <<-HTML 298 | 301 | HTML 302 | 303 | assert_equal_markup(expected, html) 304 | end 305 | 306 | def test_form_builder_selected_subregion 307 | @object.subregion_code = 'AO' 308 | form = ActionView::Helpers::FormBuilder.new(:object, @object, self, {}, lambda{}) 309 | @html = form.subregion_select(:subregion_code, 'OC') 310 | 311 | assert_select('option[selected="selected"][value="AO"]') 312 | end 313 | end 314 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | lib_path = File.expand_path('../../lib', __FILE__) 2 | $LOAD_PATH.unshift(lib_path) 3 | 4 | require 'minitest/autorun' 5 | require 'minitest/spec' 6 | 7 | require 'action_view/test_case' 8 | 9 | require 'rails' 10 | require 'carmen-rails' 11 | require 'ostruct' 12 | require 'debugger' 13 | 14 | MiniTest::Spec.register_spec_type(/.*/, ActionView::TestCase) 15 | 16 | Carmen.clear_data_paths 17 | 18 | carmen_path = File.expand_path('../../../carmen', __FILE__) 19 | 20 | Carmen.append_data_path(carmen_path + '/spec_data/data') 21 | 22 | locale_path = carmen_path + '/spec_data/locale' 23 | Carmen.i18n_backend = Carmen::I18n::Simple.new(locale_path) 24 | 25 | class MiniTest::Unit::TestCase 26 | def assert_equal_markup(expected, actual, message=nil) 27 | assert_equal(clean_markup(expected), clean_markup(actual), message) 28 | end 29 | 30 | private 31 | 32 | def clean_markup(markup) 33 | clean_whitespace(markup).gsub(/( [a-zA-Z_]*="[^"]*")+/) do |match| 34 | ' ' + match.strip!.split(' ').sort.join(' ') 35 | end 36 | end 37 | 38 | def clean_whitespace(markup) 39 | markup. 40 | gsub(/\s+/, ' '). # cleanup whitespace 41 | gsub(/>\s/, '>'). # kill space after tags 42 | gsub(/\s/, '/>'). # space inside self-closing tags 44 | strip 45 | end 46 | end 47 | --------------------------------------------------------------------------------