Permalink
Browse files

Split up responsibilities

  • Loading branch information...
1 parent 0503fc8 commit 3977c5b4e09280d2e449c904d20e993b87e6c78f @iain committed Jul 13, 2012
View
10 Rakefile
@@ -1,10 +1,6 @@
require "bundler/gem_tasks"
-require 'rake/testtask'
-desc 'Test the http_accept_language plugin.'
-Rake::TestTask.new(:test) do |t|
- t.pattern = 'test/**/*_test.rb'
-end
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec)
-desc 'Default: run unit tests.'
-task :default => :test
+task :default => :spec
View
97 lib/http_accept_language.rb
@@ -1,96 +1,3 @@
-module HttpAcceptLanguage
-
- # Returns a sorted array based on user preference in HTTP_ACCEPT_LANGUAGE.
- # Browsers send this HTTP header, so don't think this is holy.
- #
- # Example:
- #
- # request.user_preferred_languages
- # # => [ 'nl-NL', 'nl-BE', 'nl', 'en-US', 'en' ]
- #
- def user_preferred_languages
- @user_preferred_languages ||= env['HTTP_ACCEPT_LANGUAGE'].split(/\s*,\s*/).collect do |l|
- l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/
- l.split(';q=')
- end.sort do |x,y|
- raise "Not correctly formatted" unless x.first =~ /^[a-z\-0-9]+$/i
- y.last.to_f <=> x.last.to_f
- end.collect do |l|
- l.first.downcase.gsub(/-[a-z0-9]+$/i) { |x| x.upcase }
- end
- rescue # Just rescue anything if the browser messed up badly.
- []
- end
-
- # Sets the user languages preference, overiding the browser
- #
- def user_preferred_languages=(languages)
- @user_preferred_languages = languages
- end
-
- # Finds the locale specifically requested by the browser.
- #
- # Example:
- #
- # request.preferred_language_from I18n.available_locales
- # # => 'nl'
- #
- def preferred_language_from(array)
- (user_preferred_languages & array.collect { |i| i.to_s }).first
- end
-
- # Returns the first of the user_preferred_languages that is compatible
- # with the available locales. Ignores region.
- #
- # Example:
- #
- # request.compatible_language_from I18n.available_locales
- #
- def compatible_language_from(available_languages)
- user_preferred_languages.map do |x| #en-US
- available_languages.find do |y| # en
- y = y.to_s
- x == y || x.split('-', 2).first == y.split('-', 2).first
- end
- end.compact.first
- end
-
- # Returns a supplied list of available locals without any extra application info
- # that may be attached to the locale for storage in the application.
- #
- # Example:
- # [ja_JP-x1, en-US-x4, en_UK-x5, fr-FR-x3] => [ja-JP, en-US, en-UK, fr-FR]
- #
- def sanitize_available_locales(available_languages)
- available_languages.map do |avail|
- split_locale = avail.split(/[_-]/)
-
- split_locale.map do |e|
- e unless e.match(/x|[0-9*]/)
- end.compact.join("-")
- end
- end
-
- # Returns the first of the user preferred languages that is
- # also found in available languages. Finds best fit by matching on
- # primary language first and secondarily on region. If no matching region is
- # found, return the first language in the group matching that primary language.
- #
- # Example:
- #
- # request.language_region_compatible(available_languages)
- #
- def language_region_compatible_from(available_languages)
- available_languages = sanitize_available_locales(available_languages)
- user_preferred_languages.map do |x| #en-US
- lang_group = available_languages.select do |y| # en
- y = y.to_s
- x.split('-', 2).first == y.split('-', 2).first
- end
- lang_group.find{|l| l == x} || lang_group.first #en-US, en-UK
- end.compact.first
- end
-
-end
-
+require 'http_accept_language/parser'
+require 'http_accept_language/rack'
require 'http_accept_language/rails' if defined?(ActionPack)
View
104 lib/http_accept_language/parser.rb
@@ -0,0 +1,104 @@
+module HttpAcceptLanguage
+
+ class Parser
+
+ attr_reader :env
+
+ def initialize(env)
+ @env = env
+ end
+
+ # Returns a sorted array based on user preference in HTTP_ACCEPT_LANGUAGE.
+ # Browsers send this HTTP header, so don't think this is holy.
+ #
+ # Example:
+ #
+ # request.user_preferred_languages
+ # # => [ 'nl-NL', 'nl-BE', 'nl', 'en-US', 'en' ]
+ #
+ def user_preferred_languages
+ @user_preferred_languages ||= env['HTTP_ACCEPT_LANGUAGE'].split(/\s*,\s*/).collect do |l|
+ l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/
+ l.split(';q=')
+ end.sort do |x,y|
+ raise "Not correctly formatted" unless x.first =~ /^[a-z\-0-9]+$/i
+ y.last.to_f <=> x.last.to_f
+ end.collect do |l|
+ l.first.downcase.gsub(/-[a-z0-9]+$/i) { |x| x.upcase }
+ end
+ rescue # Just rescue anything if the browser messed up badly.
+ []
+ end
+
+ # Sets the user languages preference, overiding the browser
+ #
+ def user_preferred_languages=(languages)
+ @user_preferred_languages = languages
+ end
+
+ # Finds the locale specifically requested by the browser.
+ #
+ # Example:
+ #
+ # request.preferred_language_from I18n.available_locales
+ # # => 'nl'
+ #
+ def preferred_language_from(array)
+ (user_preferred_languages & array.collect { |i| i.to_s }).first
+ end
+
+ # Returns the first of the user_preferred_languages that is compatible
+ # with the available locales. Ignores region.
+ #
+ # Example:
+ #
+ # request.compatible_language_from I18n.available_locales
+ #
+ def compatible_language_from(available_languages)
+ user_preferred_languages.map do |x| #en-US
+ available_languages.find do |y| # en
+ y = y.to_s
+ x == y || x.split('-', 2).first == y.split('-', 2).first
+ end
+ end.compact.first
+ end
+
+ # Returns a supplied list of available locals without any extra application info
+ # that may be attached to the locale for storage in the application.
+ #
+ # Example:
+ # [ja_JP-x1, en-US-x4, en_UK-x5, fr-FR-x3] => [ja-JP, en-US, en-UK, fr-FR]
+ #
+ def sanitize_available_locales(available_languages)
+ available_languages.map do |avail|
+ split_locale = avail.split(/[_-]/)
+
+ split_locale.map do |e|
+ e unless e.match(/x|[0-9*]/)
+ end.compact.join("-")
+ end
+ end
+
+ # Returns the first of the user preferred languages that is
+ # also found in available languages. Finds best fit by matching on
+ # primary language first and secondarily on region. If no matching region is
+ # found, return the first language in the group matching that primary language.
+ #
+ # Example:
+ #
+ # request.language_region_compatible(available_languages)
+ #
+ def language_region_compatible_from(available_languages)
+ available_languages = sanitize_available_locales(available_languages)
+ user_preferred_languages.map do |x| #en-US
+ lang_group = available_languages.select do |y| # en
+ y = y.to_s
+ x.split('-', 2).first == y.split('-', 2).first
+ end
+ lang_group.find{|l| l == x} || lang_group.first #en-US, en-UK
+ end.compact.first
+ end
+
+ end
+
+end
View
16 lib/http_accept_language/rack.rb
@@ -1,5 +1,3 @@
-require 'http_accept_language'
-
module HttpAcceptLanguage
class Rack
@@ -9,22 +7,10 @@ def initialize(app)
def call(env)
def env.http_accept_language
- @http_accept_language ||= HttpAcceptLanguage.new(self)
+ @http_accept_language ||= Parser.new(self)
end
@app.call(env)
end
- class HttpAcceptLanguage
- include ::HttpAcceptLanguage
-
- attr_reader :env
-
- def initialize(env)
- @env = env
- end
-
- end
-
end
end
-
View
22 lib/http_accept_language/rails.rb
@@ -1,7 +1,27 @@
+require 'forwardable'
+
+module HttpAcceptLanguage
+ module Rails
+
+ extend Forwardable
+
+ def http_accept_language_parser
+ @http_accept_language_parser ||= Parser.new(env)
+ end
+
+ def_delegators :http_accept_language_parser,
+ :user_preferred_languages, :user_preferred_languages=,
+ :preferred_language_from, :compatible_language_from,
+ :sanitize_available_locales, :language_region_compatible_from
+
+ end
+
+end
+
classes = if ActionPack::VERSION::MAJOR == 2
[ActionController::Request, ActionController::CgiRequest]
else
[ActionDispatch::Request]
end
-classes.each { |c| c.send :include, HttpAcceptLanguage }
+classes.each { |c| c.send :include, HttpAcceptLanguage::Rails }
View
58 spec/http_accept_language_spec.rb
@@ -1,58 +0,0 @@
-require 'http_accept_language'
-
-class MockedCgiRequest
- include HttpAcceptLanguage
- def env
- @env ||= {'HTTP_ACCEPT_LANGUAGE' => 'en-us,en-gb;q=0.8,en;q=0.6,es-419'}
- end
-end
-
-describe HttpAcceptLanguage do
-
- it "should return empty array" do
- request.env['HTTP_ACCEPT_LANGUAGE'] = nil
- request.user_preferred_languages.should eq []
- end
-
- it "should properly split" do
- request.user_preferred_languages.should eq %w{en-US es-419 en-GB en}
- end
-
- it "should ignore jambled header" do
- request.env['HTTP_ACCEPT_LANGUAGE'] = 'odkhjf89fioma098jq .,.,'
- request.user_preferred_languages.should eq []
- end
-
- it "should find first available language" do
- request.preferred_language_from(%w{en en-GB}).should eq "en-GB"
- end
-
- it "should find first compatible language" do
- request.compatible_language_from(%w{en-hk}).should eq "en-hk"
- request.compatible_language_from(%w{en}).should eq "en"
- end
-
- it "should find first compatible from user preferred" do
- request.env['HTTP_ACCEPT_LANGUAGE'] = 'en-us,de-de'
- request.compatible_language_from(%w{de en}).should eq 'en'
- end
-
- it "should accept symbols as available languages" do
- request.env['HTTP_ACCEPT_LANGUAGE'] = 'en-us'
- request.compatible_language_from([:"en-HK"]).should eq :"en-HK"
- end
-
- it "should sanitize available language names" do
- request.sanitize_available_locales(%w{en_UK-x3 en-US-x1 ja_JP-x2 pt-BR-x5}).should eq ["en-UK", "en-US", "ja-JP", "pt-BR"]
- end
-
- it "should find most compatible language from user preferred" do
- request.env['HTTP_ACCEPT_LANGUAGE'] = 'ja,en-gb,en-us,fr-fr'
- request.language_region_compatible_from(%w{en-UK en-US ja-JP}).should eq "ja-JP"
- end
-
- def request
- @request ||= MockedCgiRequest.new
- end
-
-end
View
51 spec/parser_spec.rb
@@ -0,0 +1,51 @@
+require 'http_accept_language/parser'
+
+describe HttpAcceptLanguage::Parser do
+
+ def parser
+ @parser ||= HttpAcceptLanguage::Parser.new('HTTP_ACCEPT_LANGUAGE' => 'en-us,en-gb;q=0.8,en;q=0.6,es-419')
+ end
+
+ it "should return empty array" do
+ parser.env['HTTP_ACCEPT_LANGUAGE'] = nil
+ parser.user_preferred_languages.should eq []
+ end
+
+ it "should properly split" do
+ parser.user_preferred_languages.should eq %w{en-US es-419 en-GB en}
+ end
+
+ it "should ignore jambled header" do
+ parser.env['HTTP_ACCEPT_LANGUAGE'] = 'odkhjf89fioma098jq .,.,'
+ parser.user_preferred_languages.should eq []
+ end
+
+ it "should find first available language" do
+ parser.preferred_language_from(%w{en en-GB}).should eq "en-GB"
+ end
+
+ it "should find first compatible language" do
+ parser.compatible_language_from(%w{en-hk}).should eq "en-hk"
+ parser.compatible_language_from(%w{en}).should eq "en"
+ end
+
+ it "should find first compatible from user preferred" do
+ parser.env['HTTP_ACCEPT_LANGUAGE'] = 'en-us,de-de'
+ parser.compatible_language_from(%w{de en}).should eq 'en'
+ end
+
+ it "should accept symbols as available languages" do
+ parser.env['HTTP_ACCEPT_LANGUAGE'] = 'en-us'
+ parser.compatible_language_from([:"en-HK"]).should eq :"en-HK"
+ end
+
+ it "should sanitize available language names" do
+ parser.sanitize_available_locales(%w{en_UK-x3 en-US-x1 ja_JP-x2 pt-BR-x5}).should eq ["en-UK", "en-US", "ja-JP", "pt-BR"]
+ end
+
+ it "should find most compatible language from user preferred" do
+ parser.env['HTTP_ACCEPT_LANGUAGE'] = 'ja,en-gb,en-us,fr-fr'
+ parser.language_region_compatible_from(%w{en-UK en-US ja-JP}).should eq "ja-JP"
+ end
+
+end
View
2 spec/rack_spec.rb
@@ -1,4 +1,4 @@
-require 'http_accept_language/rack'
+require 'http_accept_language'
require 'rack/test'
require 'json'
View
21 spec/rails_spec.rb
@@ -21,28 +21,17 @@ class Request
describe "Rails integration" do
it "should be included into actionpack v2" do
- silence_warnings do
- ActionPack::VERSION.const_set(:MAJOR, 2)
- end
+ stub_const("ActionPack::VERSION::MAJOR", 2)
load "http_accept_language/rails.rb"
- ActionController::Request.ancestors.should include HttpAcceptLanguage
- ActionController::CgiRequest.ancestors.should include HttpAcceptLanguage
+ ActionController::Request.ancestors.should include HttpAcceptLanguage::Rails
+ ActionController::CgiRequest.ancestors.should include HttpAcceptLanguage::Rails
end
it "should be included into actionpack v3" do
- silence_warnings do
- ActionPack::VERSION.const_set(:MAJOR, 3)
- end
+ stub_const("ActionPack::VERSION::MAJOR", 3)
load "http_accept_language/rails.rb"
- ActionDispatch::Request.ancestors.should include HttpAcceptLanguage
- end
-
- def silence_warnings
- old_verbose, $VERBOSE = $VERBOSE, nil
- yield
- ensure
- $VERBOSE = old_verbose
+ ActionDispatch::Request.ancestors.should include HttpAcceptLanguage::Rails
end
end

0 comments on commit 3977c5b

Please sign in to comment.