From c7e2cefaa1f6b573bf777259fbc687ed71c9a889 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:05:25 -0400 Subject: [PATCH 01/32] Add bin/setup script --- bin/setup | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 bin/setup diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here From b67a302672291edeec3778a5d640ebf41fb5dcec Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:05:44 -0400 Subject: [PATCH 02/32] Remove travis config --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8e1084c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: ruby -cache: bundler -sudo: false -rvm: - - 2.0.0 - - 2.1 - - 2.2.5 - - 2.3.1 -script: bundle exec rspec spec From 8f5f34e87d754955f9825a81e3e76d2a958f50f3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:05:57 -0400 Subject: [PATCH 03/32] Remove Guardfile --- Guardfile | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 Guardfile diff --git a/Guardfile b/Guardfile deleted file mode 100644 index 135f0e6..0000000 --- a/Guardfile +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env ruby - -guard 'rspec', :cli => "-fd", :version => 2 do - watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}) { "spec" } - watch('spec/spec_helper.rb') { "spec" } -end - From a0c49c54d447cf24442d6ffca99b0a56e74b8c83 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:06:02 -0400 Subject: [PATCH 04/32] Remove cucumber tests --- cucumber.yml | 2 - features/rails_integration.feature | 29 ---------- features/steps/rails.rb | 37 ------------ features/support/rails_driver.rb | 93 ------------------------------ 4 files changed, 161 deletions(-) delete mode 100644 cucumber.yml delete mode 100644 features/rails_integration.feature delete mode 100644 features/steps/rails.rb delete mode 100644 features/support/rails_driver.rb diff --git a/cucumber.yml b/cucumber.yml deleted file mode 100644 index 0c12ef1..0000000 --- a/cucumber.yml +++ /dev/null @@ -1,2 +0,0 @@ -default: --format progress --strict --tags ~@wip -wip: --format pretty --wip --tags @wip diff --git a/features/rails_integration.feature b/features/rails_integration.feature deleted file mode 100644 index 99d8433..0000000 --- a/features/rails_integration.feature +++ /dev/null @@ -1,29 +0,0 @@ -@rails -Feature: Rails Integration - - To use http_accept_language inside a Rails application, just add it to your - Gemfile and run `bundle install`. - - It is automatically added to your middleware. - - Scenario: Installing - When I generate a new Rails app - And I add http_accept_language to my Gemfile - And I run `rake middleware` - Then the output should contain "use HttpAcceptLanguage::Middleware" - - Scenario: Using - Given I have installed http_accept_language - When I generate the following controller: - """ - class LanguagesController < ApplicationController - - def index - languages = http_accept_language.user_preferred_languages - render :text => "Languages: #{languages.join(' : ')}" - end - - end - """ - When I access that action with the HTTP_ACCEPT_LANGUAGE header "en-us,en-gb;q=0.8,en;q=0.6,es-419" - Then the response should contain "Languages: en-US : es-419 : en-GB : en" diff --git a/features/steps/rails.rb b/features/steps/rails.rb deleted file mode 100644 index bba48fc..0000000 --- a/features/steps/rails.rb +++ /dev/null @@ -1,37 +0,0 @@ -Before "@rails" do - @rails = RailsDriver.new -end - -When /^I generate a new Rails app$/ do - @rails.generate_rails -end - -When /^I add http_accept_language to my Gemfile$/ do - @rails.append_gemfile -end - -Given /^I have installed http_accept_language$/ do - @rails.install_gem -end - -When /^I generate the following controller:$/ do |string| - @rails.generate_controller "languages", string -end - -When /^I access that action with the HTTP_ACCEPT_LANGUAGE header "(.*?)"$/ do |header| - @rails.with_rails_running do - @rails.request_with_http_accept_language_header(header, "/languages") - end -end - -Then /^the response should contain "(.*?)"$/ do |output| - @rails.output_should_contain(output) -end - -When /^I run `rake middleware`$/ do - @rails.bundle_exec("rake middleware") -end - -Then /^the output should contain "(.*?)"$/ do |expected| - @rails.assert_partial_output(expected, @rails.all_output) -end diff --git a/features/support/rails_driver.rb b/features/support/rails_driver.rb deleted file mode 100644 index eaf2b37..0000000 --- a/features/support/rails_driver.rb +++ /dev/null @@ -1,93 +0,0 @@ -require 'aruba/api' - -class RailsDriver - include Aruba::Api - - def initialize - @aruba_io_wait_seconds = 10 - # @announce_stdout = true - # @announce_stderr = true - # @announce_cmd = true - # @announce_dir = true - # @announce_env = true - end - - def app_name - "foobar" - end - - def install_gem - if app_exists? - cd app_name - else - generate_rails - append_gemfile - end - end - - def app_exists? - in_current_dir do - File.exist?("#{app_name}/Gemfile") - end - end - - def bundle_exec(cmd) - run_simple "bundle exec #{cmd}" - end - - def generate_rails - # install rails with as few things as possible, for speed! - bundle_exec "rails new #{app_name} --force --skip-git --skip-active-record --skip-sprockets --skip-javascript --skip-test-unit --old-style-hash" - cd app_name - end - - def append_gemfile - # Specifiy a path so cucumber will use the unreleased version of the gem - append_to_file "Gemfile", "gem 'http_accept_language', :path => '#{gem_path}'" - end - - def gem_path - File.expand_path('../../../', __FILE__) - end - - def generate_controller(name, content) - bundle_exec "rails generate resource #{name} --force" - write_file "app/controllers/#{name}_controller.rb", content - end - - def request_with_http_accept_language_header(header, path) - run_simple "curl --retry 10 -H 'Accept-language: #{header}' #{File.join(host, path)} -o #{response}" - run_simple "cat out.html" - end - - def host - "http://localhost:13000" - end - - def with_rails_running - start_rails - yield - ensure - stop_rails - end - - def start_rails - bundle_exec "rails server -p 13000 -d" - end - - def stop_rails - in_current_dir do - `cat tmp/pids/server.pid | xargs kill -9` - end - end - - def response - File.expand_path(File.join(current_dir, 'out.html')) - end - - def output_should_contain(expected) - actual = File.open(response, 'r:utf-8').read - actual.should include expected - end - -end From 6747f8cf1c1744ea4f52ab3f6c2f6626cc8d8293 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:06:27 -0400 Subject: [PATCH 05/32] Require spec helper --- .rspec | 1 + 1 file changed, 1 insertion(+) diff --git a/.rspec b/.rspec index 5f16476..2559e39 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,3 @@ --color --format progress +--require spec_helper From a99f5ff3acff5f9faa5dd57e73cfa7cdc3d2062d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:06:48 -0400 Subject: [PATCH 06/32] Remove cucumber from Rakefile --- Rakefile | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Rakefile b/Rakefile index 1b92817..c5c746e 100644 --- a/Rakefile +++ b/Rakefile @@ -1,13 +1,6 @@ require "bundler/gem_tasks" -require 'rspec/core/rake_task' +require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) -require 'cucumber/rake/task' -Cucumber::Rake::Task.new(:cucumber) - -Cucumber::Rake::Task.new(:wip, "Run features tagged with @wip") do |t| - t.profile = "wip" -end - -task :default => [:spec, :cucumber, :wip] +task default: [:spec] From 12bd4017cb654228605d70d5d8ea53dbef58f6d6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:07:24 -0400 Subject: [PATCH 07/32] Formatting once over on lib/ --- lib/http_accept_language.rb | 8 +++---- lib/http_accept_language/auto_locale.rb | 8 ++----- lib/http_accept_language/middleware.rb | 4 ++-- lib/http_accept_language/parser.rb | 30 ++++++++++++------------- lib/http_accept_language/version.rb | 2 +- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/lib/http_accept_language.rb b/lib/http_accept_language.rb index 0e8a0a6..a91f21a 100644 --- a/lib/http_accept_language.rb +++ b/lib/http_accept_language.rb @@ -1,4 +1,4 @@ -require 'http_accept_language/auto_locale' -require 'http_accept_language/parser' -require 'http_accept_language/middleware' -require 'http_accept_language/railtie' if defined?(Rails::Railtie) +require "http_accept_language/auto_locale" +require "http_accept_language/parser" +require "http_accept_language/middleware" +require "http_accept_language/railtie" if defined?(Rails::Railtie) diff --git a/lib/http_accept_language/auto_locale.rb b/lib/http_accept_language/auto_locale.rb index 82490eb..73cf45c 100644 --- a/lib/http_accept_language/auto_locale.rb +++ b/lib/http_accept_language/auto_locale.rb @@ -1,15 +1,11 @@ -require 'active_support/concern' +require "active_support/concern" module HttpAcceptLanguage module AutoLocale extend ActiveSupport::Concern included do - if respond_to?(:prepend_before_action) - prepend_before_action :set_locale - else - prepend_before_filter :set_locale - end + prepend_before_action :set_locale end private diff --git a/lib/http_accept_language/middleware.rb b/lib/http_accept_language/middleware.rb index 6f42e1a..3998bf8 100644 --- a/lib/http_accept_language/middleware.rb +++ b/lib/http_accept_language/middleware.rb @@ -6,11 +6,11 @@ def initialize(app) def call(env) env["http_accept_language.parser"] = Parser.new(env["HTTP_ACCEPT_LANGUAGE"]) - + def env.http_accept_language self["http_accept_language.parser"] end - + @app.call(env) end end diff --git a/lib/http_accept_language/parser.rb b/lib/http_accept_language/parser.rb index f7e4086..bc02ef9 100644 --- a/lib/http_accept_language/parser.rb +++ b/lib/http_accept_language/parser.rb @@ -16,12 +16,12 @@ def initialize(header) # def user_preferred_languages @user_preferred_languages ||= begin - header.to_s.gsub(/\s+/, '').split(',').map do |language| - locale, quality = language.split(';q=') - raise ArgumentError, 'Not correctly formatted' unless locale =~ /^[a-z\-0-9]+|\*$/i + header.to_s.gsub(/\s+/, "").split(",").map do |language| + locale, quality = language.split(";q=") + raise ArgumentError, "Not correctly formatted" unless /^[a-z\-0-9]+|\*$/i.match?(locale) - locale = locale.downcase.gsub(/-[a-z0-9]+$/i, &:upcase) # Uppercase territory - locale = nil if locale == '*' # Ignore wildcards + locale = locale.downcase.gsub(/-[a-z0-9]+$/i, &:upcase) # Uppercase territory + locale = nil if locale == "*" # Ignore wildcards quality = quality ? quality.to_f : 1.0 @@ -36,9 +36,7 @@ def user_preferred_languages # Sets the user languages preference, overriding the browser # - def user_preferred_languages=(languages) - @user_preferred_languages = languages - end + attr_writer :user_preferred_languages # Finds the locale specifically requested by the browser. # @@ -59,13 +57,13 @@ def preferred_language_from(array) # request.compatible_language_from I18n.available_locales # def compatible_language_from(available_languages) - user_preferred_languages.map do |preferred| #en-US + user_preferred_languages.map do |preferred| # en-US preferred = preferred.downcase - preferred_language = preferred.split('-', 2).first + preferred_language = preferred.split("-", 2).first available_languages.find do |available| # en available = available.to_s.downcase - preferred == available || preferred_language == available.split('-', 2).first + preferred == available || preferred_language == available.split("-", 2).first end end.compact.first end @@ -93,15 +91,15 @@ def sanitize_available_locales(available_languages) # def language_region_compatible_from(available_languages) available_languages = sanitize_available_locales(available_languages) - user_preferred_languages.map do |preferred| #en-US + user_preferred_languages.map do |preferred| # en-US preferred = preferred.downcase - preferred_language = preferred.split('-', 2).first + preferred_language = preferred.split("-", 2).first lang_group = available_languages.select do |available| # en - preferred_language == available.downcase.split('-', 2).first + preferred_language == available.downcase.split("-", 2).first end - - lang_group.find { |lang| lang.downcase == preferred } || lang_group.first #en-US, en-UK + + lang_group.find { |lang| lang.downcase == preferred } || lang_group.first # en-US, en-UK end.compact.first end end diff --git a/lib/http_accept_language/version.rb b/lib/http_accept_language/version.rb index 36a2f9b..805da0b 100644 --- a/lib/http_accept_language/version.rb +++ b/lib/http_accept_language/version.rb @@ -1,3 +1,3 @@ module HttpAcceptLanguage - VERSION = '2.1.1' + VERSION = "2.1.1" end From 97a53de262a8054cbc6f8664469c6c549c834c43 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:07:47 -0400 Subject: [PATCH 08/32] Ignore rspec status and coverage files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index b8479b7..87a5af7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,8 @@ pkg/* .rvmrc log/*.log tmp/ + +# rspec failure tracking +.rspec_status + +/coverage/ From 6be2c78d333f653ca5d2a1a12513f6724daf065f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:08:27 -0400 Subject: [PATCH 09/32] Inherit from AC::Base in auto locale spec --- spec/auto_locale_spec.rb | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/spec/auto_locale_spec.rb b/spec/auto_locale_spec.rb index 8679f25..ee0f306 100644 --- a/spec/auto_locale_spec.rb +++ b/spec/auto_locale_spec.rb @@ -1,24 +1,11 @@ -require 'i18n' -require 'http_accept_language/auto_locale' -require 'http_accept_language/parser' -require 'http_accept_language/middleware' - -describe HttpAcceptLanguage::AutoLocale do +RSpec.describe HttpAcceptLanguage::AutoLocale do let(:controller_class) do - Class.new do + Class.new(ActionController::Base) do def initialize(header = nil) super() @header = header end - def self.prepend_before_action(dummy) - # dummy method - end - - def self.prepend_before_filter(dummy) - # dummy method - end - def http_accept_language @http_accept_language ||= HttpAcceptLanguage::Parser.new(@header) end @@ -54,7 +41,7 @@ def http_accept_language end end - let(:no_accept_language_controller) { controller_class.new() } + let(:no_accept_language_controller) { controller_class.new } context "default locale is ja" do before do From 69364f17adc5ea955873f790b2ec6497c49c2c54 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:09:02 -0400 Subject: [PATCH 10/32] Add GH Actions config --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..00fbf13 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: Ruby + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - name: Run specs + run: | + bin/rspec + + - name: Lint with standard + run: | + bin/standardrb From 161a588abd2bb6dc4d0d631bd2c769082745f006 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:09:13 -0400 Subject: [PATCH 11/32] Add standard and rspec binstub --- bin/rspec | 27 +++++++++++++++++++++++++++ bin/standardrb | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100755 bin/rspec create mode 100755 bin/standardrb diff --git a/bin/rspec b/bin/rspec new file mode 100755 index 0000000..cb53ebe --- /dev/null +++ b/bin/rspec @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rspec' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rspec-core", "rspec") diff --git a/bin/standardrb b/bin/standardrb new file mode 100755 index 0000000..b329561 --- /dev/null +++ b/bin/standardrb @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'standardrb' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("standard", "standardrb") From b77769af76ed46d3cbbb94061c1a66ff6d4dde4f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:09:50 -0400 Subject: [PATCH 12/32] Formatting once over on spec --- spec/middleware_spec.rb | 35 ++++++++++++++--------------------- spec/parser_spec.rb | 36 ++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/spec/middleware_spec.rb b/spec/middleware_spec.rb index 931de7c..aaefbe6 100644 --- a/spec/middleware_spec.rb +++ b/spec/middleware_spec.rb @@ -1,24 +1,18 @@ -require 'http_accept_language' -require 'rack/test' -require 'json' - class TestRackApp - def call(env) request = Rack::Request.new(env) http_accept_language = env.http_accept_language result = { - :user_preferred_languages => http_accept_language.user_preferred_languages, + user_preferred_languages: http_accept_language.user_preferred_languages } - if request.params['preferred'] - result[:preferred_language_from] = http_accept_language.preferred_language_from(request.params['preferred']) + if request.params["preferred"] + result[:preferred_language_from] = http_accept_language.preferred_language_from(request.params["preferred"]) end - [ 200, {}, [ JSON.generate(result) ]] + [200, {}, [JSON.generate(result)]] end - end -describe "Rack integration" do +RSpec.describe "Rack integration" do include Rack::Test::Methods def app @@ -29,32 +23,31 @@ def app end it "handles reuse of the env instance" do - env = { "HTTP_ACCEPT_LANGUAGE" => "en" } + env = {"HTTP_ACCEPT_LANGUAGE" => "en"} app = lambda { |env| env } middleware = HttpAcceptLanguage::Middleware.new(app) middleware.call(env) - expect(env.http_accept_language.user_preferred_languages).to eq %w{en} + expect(env.http_accept_language.user_preferred_languages).to eq %w[en] env["HTTP_ACCEPT_LANGUAGE"] = "de" middleware.call(env) - expect(env.http_accept_language.user_preferred_languages).to eq %w{de} + expect(env.http_accept_language.user_preferred_languages).to eq %w[de] end it "decodes the HTTP_ACCEPT_LANGUAGE header" do - request_with_header 'en-us,en-gb;q=0.8,en;q=0.6,es-419' - expect(r['user_preferred_languages']).to eq %w{en-US es-419 en-GB en} + request_with_header "en-us,en-gb;q=0.8,en;q=0.6,es-419" + expect(body_as_json["user_preferred_languages"]).to eq %w[en-US es-419 en-GB en] end it "finds the first available language" do - request_with_header 'en-us,en-gb;q=0.8,en;q=0.6,es-419', :preferred => %w(en en-GB) - expect(r['preferred_language_from']).to eq 'en-GB' + request_with_header "en-us,en-gb;q=0.8,en;q=0.6,es-419", preferred: %w[en en-GB] + expect(body_as_json["preferred_language_from"]).to eq "en-GB" end def request_with_header(header, params = {}) - get "/", params, 'HTTP_ACCEPT_LANGUAGE' => header + get "/", params, "HTTP_ACCEPT_LANGUAGE" => header end - def r + def body_as_json JSON.parse(last_response.body) end - end diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 15677e2..0ed638c 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -1,9 +1,6 @@ -require 'http_accept_language/parser' - -describe HttpAcceptLanguage::Parser do - +RSpec.describe HttpAcceptLanguage::Parser do def parser - @parser ||= HttpAcceptLanguage::Parser.new('en-us,en-gb;q=0.8,en;q=0.6,es-419') + @parser ||= HttpAcceptLanguage::Parser.new("en-us,en-gb;q=0.8,en;q=0.6,es-419") end it "should return empty array" do @@ -12,45 +9,45 @@ def parser end it "should properly split" do - expect(parser.user_preferred_languages).to eq %w{en-US es-419 en-GB en} + expect(parser.user_preferred_languages).to eq %w[en-US es-419 en-GB en] end it "should ignore jambled header" do - parser.header = 'odkhjf89fioma098jq .,.,' + parser.header = "odkhjf89fioma098jq .,.," expect(parser.user_preferred_languages).to eq [] end it "should properly respect whitespace" do - parser.header = 'en-us, en-gb; q=0.8,en;q = 0.6,es-419' - expect(parser.user_preferred_languages).to eq %w{en-US es-419 en-GB en} + parser.header = "en-us, en-gb; q=0.8,en;q = 0.6,es-419" + expect(parser.user_preferred_languages).to eq %w[en-US es-419 en-GB en] end it "should find first available language" do - expect(parser.preferred_language_from(%w{en en-GB})).to eq "en-GB" + expect(parser.preferred_language_from(%w[en en-GB])).to eq "en-GB" end it "should find first compatible language" do - expect(parser.compatible_language_from(%w{en-hk})).to eq "en-hk" - expect(parser.compatible_language_from(%w{en})).to eq "en" + expect(parser.compatible_language_from(%w[en-hk])).to eq "en-hk" + expect(parser.compatible_language_from(%w[en])).to eq "en" end it "should find first compatible from user preferred" do - parser.header = 'en-us,de-de' - expect(parser.compatible_language_from(%w{de en})).to eq 'en' + parser.header = "en-us,de-de" + expect(parser.compatible_language_from(%w[de en])).to eq "en" end it "should accept symbols as available languages" do - parser.header = 'en-us' + parser.header = "en-us" expect(parser.compatible_language_from([:"en-HK"])).to eq :"en-HK" end it "should accept and ignore wildcards" do - parser.header = 'en-US,en,*' + parser.header = "en-US,en,*" expect(parser.compatible_language_from([:"en-US"])).to eq :"en-US" end it "should sanitize available language names" do - expect(parser.sanitize_available_locales(%w{en_UK-x3 en-US-x1 ja_JP-x2 pt-BR-x5 es-419-x4})).to eq ["en-UK", "en-US", "ja-JP", "pt-BR", "es-419"] + expect(parser.sanitize_available_locales(%w[en_UK-x3 en-US-x1 ja_JP-x2 pt-BR-x5 es-419-x4])).to eq ["en-UK", "en-US", "ja-JP", "pt-BR", "es-419"] end it "should accept available language names as symbols and return them as strings" do @@ -58,8 +55,7 @@ def parser end it "should find most compatible language from user preferred" do - parser.header = 'ja,en-gb,en-us,fr-fr' - expect(parser.language_region_compatible_from(%w{en-UK en-US ja-JP})).to eq "ja-JP" + parser.header = "ja,en-gb,en-us,fr-fr" + expect(parser.language_region_compatible_from(%w[en-UK en-US ja-JP])).to eq "ja-JP" end - end From 31a2f61195ae6c170eeca8f18805cd1a861b122d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:11:41 -0400 Subject: [PATCH 13/32] Once over on gemspec --- http_accept_language.gemspec | 49 +++++++++++++++++------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index 5885f8a..185f67a 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -1,30 +1,27 @@ -# -*- encoding: utf-8 -*- -$:.push File.expand_path("../lib", __FILE__) -require "http_accept_language/version" +require_relative "lib/http_accept_language/version" -Gem::Specification.new do |s| - s.name = "http_accept_language" - s.version = HttpAcceptLanguage::VERSION - s.authors = ["iain"] - s.email = ["iain@iain.nl"] - s.homepage = "https://github.com/iain/http_accept_language" - s.summary = %q{Find out which locale the user preferes by reading the languages they specified in their browser} - s.description = %q{Find out which locale the user preferes by reading the languages they specified in their browser} - s.license = "MIT" +Gem::Specification.new do |spec| + spec.authors = ["iain"] + spec.email = ["iain@iain.nl"] + spec.homepage = "https://github.com/iain/http_accept_language" + spec.license = "MIT" + spec.name = "http_accept_language" + spec.required_ruby_version = ">= 3.0" + spec.summary = "Find out which locale the user prefers by reading the languages they specified in their browser." + spec.version = HttpAcceptLanguage::VERSION - s.rubyforge_project = "http_accept_language" + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject do |f| + (File.expand_path(f) == __FILE__) || + f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - s.require_paths = ["lib"] - - s.add_development_dependency 'rake' - s.add_development_dependency 'rspec' - s.add_development_dependency 'rack-test' - s.add_development_dependency 'guard-rspec' - s.add_development_dependency 'listen', '< 3.1.0' if RUBY_VERSION < '2.2.5' - s.add_development_dependency 'rails', ['>= 3.2.6', *('< 5' if RUBY_VERSION < '2.2.2')] - s.add_development_dependency 'cucumber' - s.add_development_dependency 'aruba' + spec.add_dependency "i18n" + spec.add_dependency "rack" end From aba65d30ee59d7c5744e2f954f64e131bf54cf0f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:11:54 -0400 Subject: [PATCH 14/32] Use combustion for rails integration specs --- Gemfile | 11 ++++++++ config.ru | 9 +++++++ .../app/controllers/application_controller.rb | 2 ++ .../app/controllers/languages_controller.rb | 11 ++++++++ spec/internal/config/routes.rb | 5 ++++ spec/internal/log/.gitignore | 1 + spec/rails_integration_spec.rb | 19 +++++++++++++ spec/spec_helper.rb | 27 +++++++++++++++++++ 8 files changed, 85 insertions(+) create mode 100644 config.ru create mode 100644 spec/internal/app/controllers/application_controller.rb create mode 100644 spec/internal/app/controllers/languages_controller.rb create mode 100644 spec/internal/config/routes.rb create mode 100644 spec/internal/log/.gitignore create mode 100644 spec/rails_integration_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/Gemfile b/Gemfile index b4e2a20..0afa518 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,14 @@ source "https://rubygems.org" gemspec + +gem "combustion" +gem "listen" +gem "rack-test" +gem "rails", "> 6" +gem "rake" +gem "rspec-rails" +gem "rspec" +gem "simplecov", require: false +gem "sqlite3", "< 2" +gem "standard" diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..1265db9 --- /dev/null +++ b/config.ru @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "rubygems" +require "bundler" + +Bundler.require :default, :development + +Combustion.initialize! :all +run Combustion::Application diff --git a/spec/internal/app/controllers/application_controller.rb b/spec/internal/app/controllers/application_controller.rb new file mode 100644 index 0000000..09705d1 --- /dev/null +++ b/spec/internal/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < ActionController::Base +end diff --git a/spec/internal/app/controllers/languages_controller.rb b/spec/internal/app/controllers/languages_controller.rb new file mode 100644 index 0000000..d909cde --- /dev/null +++ b/spec/internal/app/controllers/languages_controller.rb @@ -0,0 +1,11 @@ +class LanguagesController < ApplicationController + def index + render plain: "Languages: #{languages.join(" : ")}" + end + + private + + def languages + http_accept_language.user_preferred_languages + end +end diff --git a/spec/internal/config/routes.rb b/spec/internal/config/routes.rb new file mode 100644 index 0000000..1502766 --- /dev/null +++ b/spec/internal/config/routes.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +Rails.application.routes.draw do + root to: "languages#index" +end diff --git a/spec/internal/log/.gitignore b/spec/internal/log/.gitignore new file mode 100644 index 0000000..bf0824e --- /dev/null +++ b/spec/internal/log/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/spec/rails_integration_spec.rb b/spec/rails_integration_spec.rb new file mode 100644 index 0000000..7de2552 --- /dev/null +++ b/spec/rails_integration_spec.rb @@ -0,0 +1,19 @@ +RSpec.describe "Rails integration" do + describe "Controller Helper", type: :request do + it "returns correct language values from header" do + headers = {"HTTP_ACCEPT_LANGUAGE" => "en-us,en-gb;q=0.8,en;q=0.6,es-419"} + + get root_path, headers: headers + + expect(response.body) + .to include("Languages: en-US : es-419 : en-GB : en") + end + end + + describe "Middleware" do + it "inserts middleware into the Rails application" do + expect(Rails.application.middleware.middlewares) + .to include(HttpAcceptLanguage::Middleware) + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..37ae8f0 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,27 @@ +if ENV.fetch("COVERAGE", false) + require "simplecov" + SimpleCov.start do + load_profile "test_frameworks" + end +end + +require "action_controller/railtie" + +Bundler.require :default, :development + +Combustion.initialize! :action_controller do + config.load_defaults Rails::VERSION::STRING.to_f +end + +require "rspec/rails" + +RSpec.configure do |config| + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + config.infer_spec_type_from_file_location! + config.use_transactional_fixtures = true + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! +end From e299778c77be214d97bfaf1c50482214866a06dd Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:20:42 -0400 Subject: [PATCH 15/32] Remove travis badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c5103d3..f632d77 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# HttpAcceptLanguage [![Build Status](https://travis-ci.org/iain/http_accept_language.svg?branch=master)](https://travis-ci.org/iain/http_accept_language) +# HttpAcceptLanguage A gem which helps you detect the users preferred language, as sent by the "Accept-Language" HTTP header. From b65b587ad60857d0c919d0c7e007fc3ed342daa4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:26:26 -0400 Subject: [PATCH 16/32] Once over on README --- README.md | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index f632d77..497af28 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,15 @@ # HttpAcceptLanguage -A gem which helps you detect the users preferred language, as sent by the "Accept-Language" HTTP header. +A gem which helps you detect the users preferred language, as sent by the +"Accept-Language" HTTP header. -The algorithm is based on [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html), with one exception: -when a user requests "en-US" and "en" is an available language, "en" is deemed compatible with "en-US". -The RFC specifies that the requested language must either exactly match the available language or must exactly match a prefix of the available language. This means that when the user requests "en" and "en-US" is available, "en-US" would be compatible, but not the other way around. This is usually not what you're looking for. +The algorithm is based on [RFC 2616], with one exception: when a user requests +`en-US` and `en` is an available language, `en` is deemed compatible with +`en-US`. The RFC specifies that the requested language must either exactly match +the available language or must exactly match a prefix of the available language. +This means that when the user requests `en` and `en-US` is available, `en-US` +would be compatible, but not the other way around. This is usually not what +you're looking for. Since version 2.0, this gem is Rack middleware. @@ -30,11 +35,11 @@ class SomeController < ApplicationController end ``` -You can easily set the locale used for i18n in a before-filter: +You can easily set the locale used for i18n with a callback: ```ruby class SomeController < ApplicationController - before_filter :set_locale + before_action :set_locale private def set_locale @@ -43,12 +48,11 @@ class SomeController < ApplicationController end ``` -If you want to enable this behavior by default in your controllers, you can just include the provided concern: +To enable this behavior by default, include the provided concern: ```ruby class ApplicationController < ActionController::Base include HttpAcceptLanguage::AutoLocale - #... end ``` @@ -88,21 +92,21 @@ end ## Available methods -* **user_preferred_languages**: - Returns a sorted array based on user preference in HTTP_ACCEPT_LANGUAGE, sanitized and all. -* **preferred_language_from(languages)**: - Finds the locale specifically requested by the browser -* **compatible_language_from(languages)**: - Returns the first of the user_preferred_languages that is compatible with the available locales. +* **user_preferred_languages**: Returns a sorted array based on user preference + in `HTTP_ACCEPT_LANGUAGE`, sanitized and all. +* **preferred_language_from(languages)**: Finds the locale specifically + requested by the browser. +* **compatible_language_from(languages)**: Returns the first of the + `user_preferred_languages` that is compatible with the available locales. Ignores region. -* **sanitize_available_locales(languages)**: - Returns a supplied list of available locals without any extra application info - that may be attached to the locale for storage in the application. -* **language_region_compatible_from(languages)**: - 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. +* **sanitize_available_locales(languages)**: Returns a supplied list of + available locales without any extra application info that may be attached to + the locale for storage in the application. +* **language_region_compatible_from(languages)**: 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. ## Installation @@ -122,4 +126,6 @@ Run `bundle install` to install it. --- -Released under the MIT license +Released under the MIT license. + +[RFC 2616]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html \ No newline at end of file From 3d3eafccd6b971879d8e8d39aa5e148db0470fa3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:48:53 -0400 Subject: [PATCH 17/32] Allow ruby 2.7+ --- http_accept_language.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index 185f67a..0c819cb 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |spec| spec.homepage = "https://github.com/iain/http_accept_language" spec.license = "MIT" spec.name = "http_accept_language" - spec.required_ruby_version = ">= 3.0" + spec.required_ruby_version = ">= 2.7.0" spec.summary = "Find out which locale the user prefers by reading the languages they specified in their browser." spec.version = HttpAcceptLanguage::VERSION From e5a14e5513aa0f050a70d021237f12d4cf1cb5af Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:52:30 -0400 Subject: [PATCH 18/32] I18n will come in via rails --- http_accept_language.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index 0c819cb..9dea391 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -22,6 +22,5 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.add_dependency "i18n" spec.add_dependency "rack" end From b3ce7e223e35eb7041eda8fb23dab72829320fec Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 10:53:02 -0400 Subject: [PATCH 19/32] rack will come in via rails --- http_accept_language.gemspec | 2 -- 1 file changed, 2 deletions(-) diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index 9dea391..52b98a4 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -21,6 +21,4 @@ Gem::Specification.new do |spec| spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - - spec.add_dependency "rack" end From 4eecef05b06f7e8781222af2d9a28c3662586314 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 11:04:32 -0400 Subject: [PATCH 20/32] Add license copy --- LICENSE.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..10f2327 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From b54cb8b65cf5375b19bb3fbcf6f385ed7df5b8ad Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 11:04:41 -0400 Subject: [PATCH 21/32] Improve gemspec files listing --- http_accept_language.gemspec | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index 52b98a4..d04b011 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -10,14 +10,13 @@ Gem::Specification.new do |spec| spec.summary = "Find out which locale the user prefers by reading the languages they specified in their browser." spec.version = HttpAcceptLanguage::VERSION - # Specify which files should be added to the gem when it is released. - # The `git ls-files -z` loads the files in the RubyGem that have been added into git. - spec.files = Dir.chdir(__dir__) do - `git ls-files -z`.split("\x0").reject do |f| - (File.expand_path(f) == __FILE__) || - f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile]) - end - end + spec.files = Dir[ + "lib/**/*", + "README.md", + "LICENSE", + "http_accept_language.gemspec" + ] + spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] From 8fbfcba29646c9687a54d0eba49ebd70d2c8a35a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 11:05:52 -0400 Subject: [PATCH 22/32] Improve gemspec files listing --- http_accept_language.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index d04b011..7370b86 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |spec| spec.files = Dir[ "lib/**/*", "README.md", - "LICENSE", + "LICENSE.txt", "http_accept_language.gemspec" ] From d206bd08ef388b78b091c842b3e0fe88a2e8014f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 11:25:47 -0400 Subject: [PATCH 23/32] Improve gemspec files listing --- http_accept_language.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index 7370b86..75e9e87 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -14,7 +14,6 @@ Gem::Specification.new do |spec| "lib/**/*", "README.md", "LICENSE.txt", - "http_accept_language.gemspec" ] spec.bindir = "exe" From 6d330371c72765753b91bc10c80a3710175837b8 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 17:01:03 -0400 Subject: [PATCH 24/32] Terminology correction --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 497af28..f5de189 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ class SomeController < ApplicationController end ``` -You can easily set the locale used for i18n with a callback: +You can easily set the locale used for i18n with a filter: ```ruby class SomeController < ApplicationController From fc722ab1cbffc8a86719cb2da5ebc5f625729fa1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 17:13:37 -0400 Subject: [PATCH 25/32] Add CI matrix for ruby versions --- .github/workflows/ci.yml | 9 +++++++++ http_accept_language.gemspec | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00fbf13..c87090f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,12 +10,21 @@ jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: + - '3.0' + - '3.1' + - '3.2' + - '3.3' + steps: - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: + ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - name: Run specs diff --git a/http_accept_language.gemspec b/http_accept_language.gemspec index 75e9e87..d777008 100644 --- a/http_accept_language.gemspec +++ b/http_accept_language.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |spec| spec.homepage = "https://github.com/iain/http_accept_language" spec.license = "MIT" spec.name = "http_accept_language" - spec.required_ruby_version = ">= 2.7.0" + spec.required_ruby_version = ">= 3.0.0" spec.summary = "Find out which locale the user prefers by reading the languages they specified in their browser." spec.version = HttpAcceptLanguage::VERSION From 4596485bb805fdb4225443a003f2bfdab0dd10f6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 17:15:22 -0400 Subject: [PATCH 26/32] Remove sqllite3 (no db in specs) --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index 0afa518..629db10 100644 --- a/Gemfile +++ b/Gemfile @@ -10,5 +10,4 @@ gem "rake" gem "rspec-rails" gem "rspec" gem "simplecov", require: false -gem "sqlite3", "< 2" gem "standard" From 784524dd3c23fb569d54c56d808261a4ee194b0a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 17:18:34 -0400 Subject: [PATCH 27/32] Remove listen gem --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index 629db10..60001ee 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,6 @@ source "https://rubygems.org" gemspec gem "combustion" -gem "listen" gem "rack-test" gem "rails", "> 6" gem "rake" From 396bce074fdf9d0954880655785b92c741ef83bf Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 17:29:24 -0400 Subject: [PATCH 28/32] Move valid locale format to constant in parser --- lib/http_accept_language/parser.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/http_accept_language/parser.rb b/lib/http_accept_language/parser.rb index bc02ef9..a85d8a4 100644 --- a/lib/http_accept_language/parser.rb +++ b/lib/http_accept_language/parser.rb @@ -1,5 +1,7 @@ module HttpAcceptLanguage class Parser + LOCALE_FORMAT = /^[a-z\-0-9]+|\*$/i + attr_accessor :header def initialize(header) @@ -18,7 +20,7 @@ def user_preferred_languages @user_preferred_languages ||= begin header.to_s.gsub(/\s+/, "").split(",").map do |language| locale, quality = language.split(";q=") - raise ArgumentError, "Not correctly formatted" unless /^[a-z\-0-9]+|\*$/i.match?(locale) + raise ArgumentError, "Not correctly formatted" unless LOCALE_FORMAT.match?(locale) locale = locale.downcase.gsub(/-[a-z0-9]+$/i, &:upcase) # Uppercase territory locale = nil if locale == "*" # Ignore wildcards From a4bd41553b20f7f107ea394560697d964c349e8d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 17:31:05 -0400 Subject: [PATCH 29/32] Extract `languages_from_header` private method in `Parser` --- lib/http_accept_language/parser.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/http_accept_language/parser.rb b/lib/http_accept_language/parser.rb index a85d8a4..baa2a21 100644 --- a/lib/http_accept_language/parser.rb +++ b/lib/http_accept_language/parser.rb @@ -18,7 +18,7 @@ def initialize(header) # def user_preferred_languages @user_preferred_languages ||= begin - header.to_s.gsub(/\s+/, "").split(",").map do |language| + languages_from_header.map do |language| locale, quality = language.split(";q=") raise ArgumentError, "Not correctly formatted" unless LOCALE_FORMAT.match?(locale) @@ -104,5 +104,14 @@ def language_region_compatible_from(available_languages) lang_group.find { |lang| lang.downcase == preferred } || lang_group.first # en-US, en-UK end.compact.first end + + private + + def languages_from_header + header + .to_s + .gsub(/\s+/, "") + .split(",") + end end end From f30b8d9be2647c7f17e1a05479b34103d14bb14d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 17:33:47 -0400 Subject: [PATCH 30/32] Extract constant for default language quality in Parser --- lib/http_accept_language/parser.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/http_accept_language/parser.rb b/lib/http_accept_language/parser.rb index baa2a21..b16d96e 100644 --- a/lib/http_accept_language/parser.rb +++ b/lib/http_accept_language/parser.rb @@ -1,5 +1,6 @@ module HttpAcceptLanguage class Parser + DEFAULT_QUALITY = 1.0 LOCALE_FORMAT = /^[a-z\-0-9]+|\*$/i attr_accessor :header @@ -25,7 +26,7 @@ def user_preferred_languages locale = locale.downcase.gsub(/-[a-z0-9]+$/i, &:upcase) # Uppercase territory locale = nil if locale == "*" # Ignore wildcards - quality = quality ? quality.to_f : 1.0 + quality = quality ? quality.to_f : DEFAULT_QUALITY [locale, quality] end.sort do |(_, left), (_, right)| From 701f747fee8aa09a425a5ab1cf12902ce00fe7e8 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 18:01:27 -0400 Subject: [PATCH 31/32] Parser comments --- lib/http_accept_language/parser.rb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/http_accept_language/parser.rb b/lib/http_accept_language/parser.rb index b16d96e..ecb67bf 100644 --- a/lib/http_accept_language/parser.rb +++ b/lib/http_accept_language/parser.rb @@ -10,7 +10,6 @@ def initialize(header) 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: # @@ -32,7 +31,7 @@ def user_preferred_languages end.sort do |(_, left), (_, right)| right <=> left end.map(&:first).compact - rescue ArgumentError # Just rescue anything if the browser messed up badly. + rescue ArgumentError # Rescue from malformed language strings. [] end end @@ -41,7 +40,7 @@ def user_preferred_languages # attr_writer :user_preferred_languages - # Finds the locale specifically requested by the browser. + # Finds the first locale specifically requested by the browser. # # Example: # @@ -71,11 +70,11 @@ def compatible_language_from(available_languages) 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. + # Returns a supplied list of available locales 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] + # 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 |available| @@ -83,10 +82,10 @@ def sanitize_available_locales(available_languages) 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. + # 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 then on region. If no matching region is found, return the first + # language in the group matching that primary language. # # Example: # From 3df65dcacc7591e2bb8f5b1a986a6237b2adaee6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 20 Jun 2024 18:03:42 -0400 Subject: [PATCH 32/32] Rspec config --- spec/spec_helper.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 37ae8f0..74eedce 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,12 +16,8 @@ require "rspec/rails" RSpec.configure do |config| - # Enable flags like --only-failures and --next-failure + config.disable_monkey_patching! config.example_status_persistence_file_path = ".rspec_status" - config.infer_spec_type_from_file_location! config.use_transactional_fixtures = true - - # Disable RSpec exposing methods globally on `Module` and `main` - config.disable_monkey_patching! end