diff options
1970 files changed, 52066 insertions, 52515 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml index 877c67873d..17fcaa4360 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -7,20 +7,6 @@ ratings: - "**.rb" exclude_paths: - - actioncable/lib/rails/generators/ - - actioncable/test/ - - actionmailer/lib/rails/generators/ - - actionmailer/test/ - - actionpack/test/ - - actionview/test/ - - activejob/lib/rails/generators/ - - activejob/test/ - - activemodel/test/ - - activerecord/lib/rails/generators/ - - activerecord/test/ - - activesupport/test/ - - railties/lib/rails/generators/ - - railties/test/ - ci/ - guides/ - tasks/ diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 48f7b0e214..214d63740c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,6 +11,9 @@ If there's anything else that's important and relevant to your pull request, mention that information here. This could include benchmarks, or other information. +If you are updating any of the CHANGELOG files or are asked to update the +CHANGELOG files by reviewers, please add the CHANGELOG entry at the top of the file. + Finally, if your pull request affects documentation or any non-code changes, guidelines for those changes are [available here](http://guides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation) diff --git a/.rubocop.yml b/.rubocop.yml index dd8db6af3a..985a036556 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,27 +1,98 @@ AllCops: - TargetRubyVersion: 2.3 + TargetRubyVersion: 2.2 + # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop + # to ignore them, so only the ones explicitly set in this file are enabled. DisabledByDefault: true + Exclude: + - '**/templates/**/*' + - '**/vendor/**/*' + +# Prefer &&/|| over and/or. +Style/AndOr: + Enabled: true + +# Do not use braces for hash literals when they are the last argument of a +# method call. +Style/BracesAroundHashParameters: + Enabled: true + +# Align `when` with `case`. +Style/CaseIndentation: + Enabled: true + +# Align comments with method definitions. +Style/CommentIndentation: + Enabled: true + +# No extra empty lines. +Style/EmptyLines: + Enabled: true + +# In a regular class definition, no empty lines around the body. +Style/EmptyLinesAroundClassBody: + Enabled: true + +# In a regular module definition, no empty lines around the body. +Style/EmptyLinesAroundModuleBody: + Enabled: true + +# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }. +Style/HashSyntax: + Enabled: true + +# Method definitions after `private` or `protected` isolated calls need one +# extra level of indentation. +Style/IndentationConsistency: + Enabled: true + EnforcedStyle: rails # Two spaces, no tabs (for indentation). Style/IndentationWidth: - enabled: true + Enabled: true -# No trailing whitespace. -Style/TrailingWhitespace: - enabled: true +# Defining a method with parameters needs parentheses. +Style/MethodDefParentheses: + Enabled: true + +# Use `foo {}` not `foo{}`. +Style/SpaceBeforeBlockBraces: + Enabled: true + +# Use `foo { bar }` not `foo {bar}`. +Style/SpaceInsideBlockBraces: + Enabled: true + +# Use `{ a: 1 }` not `{a:1}`. +Style/SpaceInsideHashLiteralBraces: + Enabled: true + +# Check quotes usage according to lint rule below. +Style/StringLiterals: + Enabled: true + EnforcedStyle: double_quotes + +# Detect hard tabs, no hard tabs. +Style/Tab: + Enabled: true # Blank lines should not have any spaces. Style/TrailingBlankLines: - enabled: true + Enabled: true -# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }. -Style/HashSyntax: - enabled: true +# No trailing whitespace. +Style/TrailingWhitespace: + Enabled: true -# Prefer &&/|| over and/or. -Style/AndOr: - enabled: true +# Use quotes for string literals when they are enough. +Style/UnneededPercentQ: + Enabled: true + +# Align `end` with the matching keyword or starting expression except for +# assignments, where it should be aligned with the LHS. +Lint/EndAlignment: + Enabled: true + AlignWith: variable # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg. Lint/RequireParentheses: - enabled: true + Enabled: true diff --git a/.travis.yml b/.travis.yml index 461bd172c1..d29ef1702a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,12 +16,9 @@ addons: postgresql: "9.4" bundler_args: --without test --jobs 3 --retry 3 -#FIXME: Remove bundler uninstall on Travis when https://github.com/bundler/bundler/issues/4493 is fixed. before_install: - - rvm @global do gem uninstall bundler --all --ignore-dependencies --executables - - rvm @global do gem install bundler -v '1.11.2' - - bundle --version - "rm ${BUNDLE_GEMFILE}.lock" + - "gem update bundler" - "[ -f /tmp/beanstalkd-1.10/Makefile ] || (curl -L https://github.com/kr/beanstalkd/archive/v1.10.tar.gz | tar xz -C /tmp)" - "pushd /tmp/beanstalkd-1.10 && make && (./beanstalkd &); popd" @@ -40,9 +37,7 @@ env: - "GEM=railties" - "GEM=ap" - "GEM=ac" - - "GEM=ac FAYE=1" - "GEM=ac:integration" - - "GEM=ac:integration FAYE=1" - "GEM=am,amo,as,av,aj" - "GEM=as PRESERVE_TIMEZONES=1" - "GEM=ar:mysql2" @@ -72,8 +67,6 @@ matrix: allow_failures: - rvm: ruby-head - rvm: jruby-9.0.5.0 - - env: "GEM=ac:integration" - - env: "GEM=ac:integration FAYE=1" fast_finish: true notifications: @@ -88,6 +81,3 @@ notifications: on_failure: always rooms: - secure: "YA1alef1ESHWGFNVwvmVGCkMe4cUy4j+UcNvMUESraceiAfVyRMAovlQBGs6\n9kBRm7DHYBUXYC2ABQoJbQRLDr/1B5JPf/M8+Qd7BKu8tcDC03U01SMHFLpO\naOs/HLXcDxtnnpL07tGVsm0zhMc5N8tq4/L3SHxK7Vi+TacwQzI=" - -git: - depth: 1 @@ -1,75 +1,81 @@ -source 'https://rubygems.org' +source "https://rubygems.org" + +git_source(:github) do |repo_name| + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + "https://github.com/#{repo_name}.git" +end gemspec # We need a newish Rake since Active Job sets its test tasks' descriptions. -gem 'rake', '>= 11.1' +gem "rake", ">= 11.1" # This needs to be with require false to ensure correct loading order, as it has to # be loaded after loading the test library. -gem 'mocha', '~> 0.14', require: false +gem "mocha", "~> 0.14", require: false -gem 'rack-cache', '~> 1.2' -gem 'jquery-rails' -gem 'coffee-rails', github: 'rails/coffee-rails' -gem 'turbolinks', github: 'turbolinks/turbolinks-rails' +gem "rack-cache", "~> 1.2" +gem "jquery-rails" +gem "coffee-rails" +gem "sass-rails" +gem "turbolinks", "~> 5" # require: false so bcrypt is loaded only when has_secure_password is used. # This is to avoid Active Model (and by extension the entire framework) # being dependent on a binary library. -gem 'bcrypt', '~> 3.1.11', require: false +gem "bcrypt", "~> 3.1.11", require: false # This needs to be with require false to avoid it being automatically loaded by # sprockets. -gem 'uglifier', '>= 1.3.0', require: false +gem "uglifier", ">= 1.3.0", require: false # Track stable branch of sass because it doesn't have circular require warnings. -gem 'sass', github: 'sass/sass', branch: 'stable', require: false +gem "sass", github: "sass/sass", branch: "stable", require: false + +# FIXME: Remove this fork after https://github.com/nex3/rb-inotify/pull/49 is fixed. +gem "rb-inotify", github: "matthewd/rb-inotify", branch: "close-handling", require: false group :doc do - gem 'sdoc', '~> 0.4.0' - gem 'redcarpet', '~> 3.2.3', platforms: :ruby - gem 'w3c_validators' - gem 'kindlerb', '0.1.1' + gem "sdoc", "1.0.0.beta2" + gem "redcarpet", "~> 3.2.3", platforms: :ruby + gem "w3c_validators" + gem "kindlerb", ">= 1.0.1" end # Active Support. -gem 'dalli', '>= 2.2.1' -gem 'listen', '~> 3.0.5', require: false +gem "dalli", ">= 2.2.1" +gem "listen", ">= 3.0.5", "< 3.2", require: false # Active Job. group :job do - gem 'resque', '< 1.26', require: false - gem 'resque-scheduler', require: false - gem 'sidekiq', require: false - gem 'sucker_punch', require: false - gem 'delayed_job', require: false, github: 'collectiveidea/delayed_job' - gem 'queue_classic', github: "QueueClassic/queue_classic", branch: 'master', require: false, platforms: :ruby - gem 'sneakers', require: false - gem 'que', require: false - gem 'backburner', require: false + gem "resque", github: "resque/resque", require: false + gem "resque-scheduler", require: false + gem "sidekiq", require: false + gem "sucker_punch", require: false + gem "delayed_job", require: false, github: "collectiveidea/delayed_job" + gem "queue_classic", github: "QueueClassic/queue_classic", branch: "master", require: false, platforms: :ruby + gem "sneakers", require: false + gem "que", require: false + gem "backburner", require: false #TODO: add qu after it support Rails 5.1 # gem 'qu-rails', github: "bkeepers/qu", branch: "master", require: false - gem 'qu-redis', require: false - gem 'delayed_job_active_record', require: false, github: 'collectiveidea/delayed_job_active_record' - gem 'sequel', require: false + gem "qu-redis", require: false + gem "delayed_job_active_record", require: false, github: "collectiveidea/delayed_job_active_record" + gem "sequel", require: false end # Action Cable group :cable do - gem 'puma', require: false - - gem 'em-hiredis', require: false - gem 'hiredis', require: false - gem 'redis', require: false + gem "puma", require: false - gem 'faye-websocket', require: false + gem "em-hiredis", require: false + gem "hiredis", require: false + gem "redis", require: false - # Lock to 1.1.1 until the fix for https://github.com/faye/faye/issues/394 is released - gem 'faye', '1.1.1', require: false + gem "websocket-client-simple", github: "matthewd/websocket-client-simple", branch: "close-race", require: false - gem 'blade', require: false - gem 'blade-sauce_labs_plugin', require: false + gem "blade", require: false, platforms: [:ruby] + gem "blade-sauce_labs_plugin", require: false, platforms: [:ruby] end # Add your own local bundler stuff. @@ -78,43 +84,43 @@ instance_eval File.read local_gemfile if File.exist? local_gemfile group :test do # FIX: Our test suite isn't ready to run in random order yet. - gem 'minitest', '< 5.3.4' + gem "minitest", "< 5.3.4" platforms :mri do - gem 'stackprof' - gem 'byebug' + gem "stackprof" + gem "byebug" end - gem 'benchmark-ips' + gem "benchmark-ips" end platforms :ruby, :mswin, :mswin64, :mingw, :x64_mingw do - gem 'nokogiri', '>= 1.6.8' + gem "nokogiri", ">= 1.6.8" # Needed for compiling the ActionDispatch::Journey parser. - gem 'racc', '>=1.4.6', require: false + gem "racc", ">=1.4.6", require: false # Active Record. - gem 'sqlite3', '~> 1.3.6' + gem "sqlite3", "~> 1.3.6" group :db do - gem 'pg', '>= 0.18.0' - gem 'mysql2', '>= 0.4.4' + gem "pg", ">= 0.18.0" + gem "mysql2", ">= 0.4.4" end end platforms :jruby do - if ENV['AR_JDBC'] - gem 'activerecord-jdbcsqlite3-adapter', github: 'jruby/activerecord-jdbc-adapter', branch: 'master' + if ENV["AR_JDBC"] + gem "activerecord-jdbcsqlite3-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master" group :db do - gem 'activerecord-jdbcmysql-adapter', github: 'jruby/activerecord-jdbc-adapter', branch: 'master' - gem 'activerecord-jdbcpostgresql-adapter', github: 'jruby/activerecord-jdbc-adapter', branch: 'master' + gem "activerecord-jdbcmysql-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master" + gem "activerecord-jdbcpostgresql-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master" end else - gem 'activerecord-jdbcsqlite3-adapter', '>= 1.3.0' + gem "activerecord-jdbcsqlite3-adapter", ">= 1.3.0" group :db do - gem 'activerecord-jdbcmysql-adapter', '>= 1.3.0' - gem 'activerecord-jdbcpostgresql-adapter', '>= 1.3.0' + gem "activerecord-jdbcmysql-adapter", ">= 1.3.0" + gem "activerecord-jdbcpostgresql-adapter", ">= 1.3.0" end end end @@ -122,18 +128,18 @@ end platforms :rbx do # The rubysl-yaml gem doesn't ship with Psych by default as it needs # libyaml that isn't always available. - gem 'psych', '~> 2.0' + gem "psych", "~> 2.0" end # Gems that are necessary for Active Record tests with Oracle. -if ENV['ORACLE_ENHANCED'] +if ENV["ORACLE_ENHANCED"] platforms :ruby do - gem 'ruby-oci8', '~> 2.2' + gem "ruby-oci8", "~> 2.2" end - gem 'activerecord-oracle_enhanced-adapter', github: 'rsim/oracle-enhanced', branch: 'master' + gem "activerecord-oracle_enhanced-adapter", github: "rsim/oracle-enhanced", branch: "master" end # A gem necessary for Active Record tests with IBM DB. -gem 'ibm_db' if ENV['IBM_DB'] -gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] -gem 'wdm', '>= 0.1.0', platforms: [:mingw, :mswin, :x64_mingw, :mswin64] +gem "ibm_db" if ENV["IBM_DB"] +gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] +gem "wdm", ">= 0.1.0", platforms: [:mingw, :mswin, :x64_mingw, :mswin64] diff --git a/Gemfile.lock b/Gemfile.lock index 71f4302a5b..4257685c46 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,47 +1,60 @@ GIT - remote: git://github.com/QueueClassic/queue_classic.git - revision: c26f2c9f6f6133b946fbcdd7b7ec905a4aca9f94 + remote: https://github.com/QueueClassic/queue_classic.git + revision: 51d56ca6fa2fdf1eeffdffd702ae1cc0940b5156 branch: master specs: queue_classic (3.2.0.RC1) - pg (>= 0.17, < 0.19) + pg (>= 0.17, < 0.20) GIT - remote: git://github.com/collectiveidea/delayed_job.git - revision: 71f1d5faf934d3057abca942f0d410327bc69087 + remote: https://github.com/collectiveidea/delayed_job.git + revision: e3772d4f0c8470d0fcba00c86ca3bc4f5e876830 specs: - delayed_job (4.1.1) + delayed_job (4.1.2) activesupport (>= 3.0, < 5.1) GIT - remote: git://github.com/collectiveidea/delayed_job_active_record.git - revision: 61e688e03b2ef4004b08de6d1e0a123fda8fffad + remote: https://github.com/collectiveidea/delayed_job_active_record.git + revision: 36f434c4fd660e8f11ce932be117e9c71dde7212 specs: - delayed_job_active_record (4.1.0) + delayed_job_active_record (4.1.1) activerecord (>= 3.0, < 5.1) delayed_job (>= 3.0, < 5) GIT - remote: git://github.com/rails/coffee-rails.git - revision: aa2e623cbda4f3c789a0a15d1f707239e68f5736 + remote: https://github.com/matthewd/rb-inotify.git + revision: 90553518d1fb79aedc98a3036c59bd2b6731ac40 + branch: close-handling specs: - coffee-rails (4.1.1) - coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.2.x) + rb-inotify (0.9.7) + ffi (>= 0.5.0) GIT - remote: git://github.com/sass/sass.git - revision: 3fda1cbe70d615e7ef96e28db4fd1f8a3ebb5505 - branch: stable + remote: https://github.com/matthewd/websocket-client-simple.git + revision: e161305f1a466b9398d86df3b1731b03362da91b + branch: close-race specs: - sass (3.4.22) + websocket-client-simple (0.3.0) + event_emitter + websocket + +GIT + remote: https://github.com/resque/resque.git + revision: 20d885065ac19e7f7d7a982f4ed1296083db0300 + specs: + resque (1.27.0) + mono_logger (~> 1.0) + multi_json (~> 1.0) + redis-namespace (~> 1.3) + sinatra (>= 0.9.2) + vegas (~> 0.1.2) GIT - remote: git://github.com/turbolinks/turbolinks-rails.git - revision: 65884729016dbb4d032f12bb01b7e7c1ddeb68ac + remote: https://github.com/sass/sass.git + revision: 7716e67f3507c6f65878c69aa49ec358ebf675c7 + branch: stable specs: - turbolinks (5.0.0.beta2) - turbolinks-source + sass (3.4.22) PATH remote: . @@ -59,7 +72,7 @@ PATH actionpack (5.1.0.alpha) actionview (= 5.1.0.alpha) activesupport (= 5.1.0.alpha) - rack (~> 2.x) + rack (~> 2.0) rack-test (~> 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) @@ -107,15 +120,16 @@ GEM specs: addressable (2.4.0) amq-protocol (2.0.1) - arel (7.0.0) - backburner (1.3.0) + arel (7.1.2) + backburner (1.3.1) beaneater (~> 1.0) + concurrent-ruby (~> 1.0.1) dante (> 0.1.5) bcrypt (3.1.11) bcrypt (3.1.11-x64-mingw32) bcrypt (3.1.11-x86-mingw32) beaneater (1.0.0) - benchmark-ips (2.6.1) + benchmark-ips (2.7.2) blade (0.5.6) activesupport (>= 3.0.0) blade-qunit_adapter (~> 1.20.0) @@ -130,46 +144,50 @@ GEM thor (~> 0.19.1) useragent (~> 0.16.7) blade-qunit_adapter (1.20.0) - blade-sauce_labs_plugin (0.5.2) + blade-sauce_labs_plugin (0.5.3) childprocess faraday selenium-webdriver builder (3.2.2) bunny (2.2.2) amq-protocol (>= 2.0.1) - byebug (8.2.5) + byebug (9.0.6) childprocess (0.5.9) ffi (~> 1.0, >= 1.0.11) + coffee-rails (4.2.1) + coffee-script (>= 2.2.0) + railties (>= 4.0.0, < 5.2.x) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.10.0) concurrent-ruby (1.0.2) connection_pool (2.2.0) - cookiejar (0.3.0) + cookiejar (0.3.3) curses (1.0.2) - daemons (1.2.3) + daemons (1.2.4) dalli (2.7.6) dante (0.2.0) em-hiredis (0.3.1) eventmachine (~> 1.0) hiredis (~> 0.6.0) - em-http-request (1.1.3) + em-http-request (1.1.5) addressable (>= 2.3.4) - cookiejar (<= 0.3.0) + cookiejar (!= 0.3.1) em-socksify (>= 0.3) eventmachine (>= 1.0.3) http_parser.rb (>= 0.6.0) em-socksify (0.3.1) eventmachine (>= 1.0.0.beta.4) erubis (2.7.0) + event_emitter (0.2.5) eventmachine (1.2.0.1) eventmachine (1.2.0.1-x64-mingw32) eventmachine (1.2.0.1-x86-mingw32) execjs (2.7.0) faraday (0.9.2) multipart-post (>= 1.2, < 3) - faye (1.1.1) + faye (1.2.2) cookiejar (>= 0.3.0) em-http-request (>= 0.3.0) eventmachine (>= 0.12.0) @@ -180,34 +198,35 @@ GEM faye-websocket (0.10.4) eventmachine (>= 0.12.0) websocket-driver (>= 0.5.1) - ffi (1.9.10) - ffi (1.9.10-x64-mingw32) - ffi (1.9.10-x86-mingw32) - globalid (0.3.6) + ffi (1.9.14) + ffi (1.9.14-x64-mingw32) + ffi (1.9.14-x86-mingw32) + globalid (0.3.7) activesupport (>= 4.1.0) hiredis (0.6.1) http_parser.rb (0.6.0) i18n (0.7.0) - jquery-rails (4.1.1) + jquery-rails (4.2.1) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.3) - kindlerb (0.1.1) + json (2.0.2) + kindlerb (1.0.1) mustache nokogiri - listen (3.0.7) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9.7) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) loofah (2.0.3) nokogiri (>= 1.5.9) mail (2.6.4) mime-types (>= 1.16, < 4) metaclass (0.0.4) method_source (0.8.2) - mime-types (3.0) + mime-types (3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0221) + mime-types-data (3.2016.0521) mini_portile2 (2.1.0) minitest (5.3.3) mocha (0.14.0) @@ -216,80 +235,75 @@ GEM multi_json (1.12.1) multipart-post (2.0.0) mustache (1.0.3) - mysql2 (0.4.4) - mysql2 (0.4.4-x64-mingw32) - mysql2 (0.4.4-x86-mingw32) + mysql2 (0.4.5) + mysql2 (0.4.5-x64-mingw32) + mysql2 (0.4.5-x86-mingw32) nio4r (1.2.1) - nokogiri (1.6.8) + nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) - pkg-config (~> 1.1.7) - nokogiri (1.6.8-x64-mingw32) + nokogiri (1.6.8.1-x64-mingw32) mini_portile2 (~> 2.1.0) - pkg-config (~> 1.1.7) - nokogiri (1.6.8-x86-mingw32) + nokogiri (1.6.8.1-x86-mingw32) mini_portile2 (~> 2.1.0) - pkg-config (~> 1.1.7) - pg (0.18.4) - pg (0.18.4-x64-mingw32) - pg (0.18.4-x86-mingw32) - pkg-config (1.1.7) - psych (2.0.17) - puma (3.4.0) + pg (0.19.0) + pg (0.19.0-x64-mingw32) + pg (0.19.0-x86-mingw32) + psych (2.1.1) + puma (3.6.0) qu (0.2.0) multi_json qu-redis (0.2.0) qu (= 0.2.0) redis-namespace simple_uuid - que (0.11.4) + que (0.12.0) racc (1.4.14) - rack (2.0.0.rc1) - json + rack (2.0.1) rack-cache (1.6.1) rack (>= 0.4) + rack-protection (1.5.3) + rack rack-test (0.6.3) rack (>= 1.0) - rails-dom-testing (2.0.0) + rails-dom-testing (2.0.1) activesupport (>= 4.2.0, < 6.0) nokogiri (~> 1.6.0) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - rake (11.1.2) + rake (11.3.0) rb-fsevent (0.9.7) - rb-inotify (0.9.7) - ffi (>= 0.5.0) - rdoc (4.2.2) - json (~> 1.4) + rdoc (5.0.0.beta2) redcarpet (3.2.3) - redis (3.3.0) + redis (3.3.1) redis-namespace (1.5.2) redis (~> 3.0, >= 3.0.4) - resque (1.25.2) - mono_logger (~> 1.0) - multi_json (~> 1.0) - redis-namespace (~> 1.3) - sinatra (>= 0.9.2) - vegas (~> 0.1.2) - resque-scheduler (4.2.0) + resque-scheduler (4.3.0) mono_logger (~> 1.0) - redis (~> 3.0) - resque (~> 1.25) + redis (~> 3.3) + resque (~> 1.26) rufus-scheduler (~> 3.2) + ruby_dep (1.4.0) rubyzip (1.2.0) - rufus-scheduler (3.2.1) - sdoc (0.4.1) - json (~> 1.7, >= 1.7.7) - rdoc (~> 4.0) - selenium-webdriver (2.53.0) + rufus-scheduler (3.2.2) + sass-rails (5.0.6) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + sdoc (1.0.0.beta2) + rdoc (= 5.0.0.beta2) + selenium-webdriver (2.53.4) childprocess (~> 0.5) rubyzip (~> 1.0) websocket (~> 1.0) - sequel (4.34.0) + sequel (4.39.0) serverengine (1.5.11) sigdump (~> 0.2.2) - sidekiq (4.1.2) + sidekiq (4.2.2) concurrent-ruby (~> 1.0) connection_pool (~> 2.2, >= 2.2.0) + rack-protection (~> 1.5) redis (~> 3.2, >= 3.2.1) sigdump (0.2.4) simple_uuid (0.4.0) @@ -300,18 +314,18 @@ GEM serverengine (~> 1.5.11) thor thread (~> 0.1.7) - sprockets (3.6.1) + sprockets (3.7.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-export (0.9.1) - sprockets-rails (3.0.4) + sprockets-rails (3.2.0) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.3.11) sqlite3 (1.3.11-x64-mingw32) sqlite3 (1.3.11-x86-mingw32) - stackprof (0.2.9) + stackprof (0.2.10) sucker_punch (2.0.2) concurrent-ruby (~> 1.0.0) thin (1.7.0) @@ -321,14 +335,17 @@ GEM thor (0.19.1) thread (0.1.7) thread_safe (0.3.5) - turbolinks-source (5.0.0.beta4) + tilt (2.0.5) + turbolinks (5.0.1) + turbolinks-source (~> 5) + turbolinks-source (5.0.0) tzinfo (1.2.2) thread_safe (~> 0.1) - tzinfo-data (1.2016.4) + tzinfo-data (1.2016.7) tzinfo (>= 1.0.0) - uglifier (3.0.0) + uglifier (3.0.2) execjs (>= 0.3.0, < 3) - useragent (0.16.7) + useragent (0.16.8) vegas (0.1.11) rack (>= 1.0.0) w3c_validators (1.2) @@ -355,17 +372,15 @@ DEPENDENCIES blade blade-sauce_labs_plugin byebug - coffee-rails! + coffee-rails dalli (>= 2.2.1) delayed_job! delayed_job_active_record! em-hiredis - faye (= 1.1.1) - faye-websocket hiredis jquery-rails - kindlerb (= 0.1.1) - listen (~> 3.0.5) + kindlerb (>= 1.0.1) + listen (>= 3.0.5, < 3.2) minitest (< 5.3.4) mocha (~> 0.14) mysql2 (>= 0.4.4) @@ -380,23 +395,26 @@ DEPENDENCIES rack-cache (~> 1.2) rails! rake (>= 11.1) + rb-inotify! redcarpet (~> 3.2.3) redis - resque (< 1.26) + resque! resque-scheduler sass! - sdoc (~> 0.4.0) + sass-rails + sdoc (= 1.0.0.beta2) sequel sidekiq sneakers sqlite3 (~> 1.3.6) stackprof sucker_punch - turbolinks! + turbolinks (~> 5) tzinfo-data uglifier (>= 1.3.0) w3c_validators wdm (>= 0.1.0) + websocket-client-simple! BUNDLED WITH - 1.11.2 + 1.13.6 diff --git a/MIT-LICENSE b/MIT-LICENSE new file mode 100644 index 0000000000..40235833ba --- /dev/null +++ b/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2005-2016 David Heinemeier Hansson + +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. @@ -1,20 +1,20 @@ -require 'net/http' +require "net/http" -$:.unshift File.expand_path('..', __FILE__) +$:.unshift File.expand_path("..", __FILE__) require "tasks/release" -require 'railties/lib/rails/api/task' +require "railties/lib/rails/api/task" desc "Build gem files for all projects" -task :build => "all:build" +task build: "all:build" desc "Prepare the release" -task :prep_release => "all:prep_release" +task prep_release: "all:prep_release" desc "Release all gems to rubygems and create a tag" -task :release => "all:release" +task release: "all:release" -desc 'Run all tests by default' -task :default => %w(test test:isolated) +desc "Run all tests by default" +task default: %w(test test:isolated) %w(test test:isolated package gem).each do |task_name| desc "Run #{task_name} task for all projects" @@ -23,9 +23,6 @@ task :default => %w(test test:isolated) FRAMEWORKS.each do |project| system(%(cd #{project} && #{$0} #{task_name} --trace)) || errors << project end - if task_name =~ /test/ - system(%(cd actioncable && env FAYE=1 #{$0} #{task_name} --trace)) || errors << 'actioncable-faye' - end fail("Errors in #{errors.join(', ')}") unless errors.empty? end end @@ -36,21 +33,20 @@ task :smoke do system %(cd #{project} && #{$0} test:isolated --trace) end system %(cd activerecord && #{$0} sqlite3:isolated_test --trace) - system %(cd actioncable && env FAYE=1 #{$0} test:isolated --trace) end desc "Install gems for all projects." -task :install => "all:install" +task install: "all:install" desc "Generate documentation for the Rails framework" -if ENV['EDGE'] - Rails::API::EdgeTask.new('rdoc') +if ENV["EDGE"] + Rails::API::EdgeTask.new("rdoc") else - Rails::API::StableTask.new('rdoc') + Rails::API::StableTask.new("rdoc") end -desc 'Bump all versions to match RAILS_VERSION' -task :update_versions => "all:update_versions" +desc "Bump all versions to match RAILS_VERSION" +task update_versions: "all:update_versions" # We have a webhook configured in GitHub that gets invoked after pushes. # This hook triggers the following tasks: @@ -61,10 +57,10 @@ task :update_versions => "all:update_versions" # * if there's a new stable tag, generates and publishes stable docs # # Everything is automated and you do NOT need to run this task normally. -desc 'Publishes docs, run this AFTER a new stable tag has been pushed' +desc "Publishes docs, run this AFTER a new stable tag has been pushed" task :publish_docs do - Net::HTTP.new('api.rubyonrails.org', 8080).start do |http| - request = Net::HTTP::Post.new('/rails-master-hook') + Net::HTTP.new("api.rubyonrails.org", 8080).start do |http| + request = Net::HTTP::Post.new("/rails-master-hook") response = http.request(request) puts response.body end diff --git a/actioncable/CHANGELOG.md b/actioncable/CHANGELOG.md index a767857607..d70d32ce07 100644 --- a/actioncable/CHANGELOG.md +++ b/actioncable/CHANGELOG.md @@ -1,2 +1,37 @@ +* Permit same-origin connections by default. + + New option `config.action_cable.allow_same_origin_as_host = false` + to disable. + + *Dávid Halász*, *Matthew Draper* + +* Prevent race where the client could receive and act upon a + subscription confirmation before the channel's `subscribed` method + completed. + + Fixes #25381. + + *Vladimir Dementyev* + +* Buffer writes to websocket connections, to avoid blocking threads + that could be doing more useful things. + + *Matthew Draper*, *Tinco Andringa* + +* Protect against concurrent writes to a websocket connection from + multiple threads; the underlying OS write is not always threadsafe. + + *Tinco Andringa* + +* Add ActiveSupport::Notifications hook to Broadcaster#broadcast. + + *Matthew Wear* + +* Close hijacked socket when connection is shut down. + + Fixes #25613. + + *Tinco Andringa* + Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/actioncable/CHANGELOG.md) for previous changes. diff --git a/actioncable/README.md b/actioncable/README.md index 58d23d2834..8ad9aeb1f1 100644 --- a/actioncable/README.md +++ b/actioncable/README.md @@ -167,7 +167,7 @@ App.cable.subscriptions.create "AppearanceChannel", buttonSelector = "[data-behavior~=appear_away]" install: -> - $(document).on "page:change.appearance", => + $(document).on "turbolinks:load.appearance", => @appear() $(document).on "click.appearance", buttonSelector, => @@ -299,15 +299,242 @@ The rebroadcast will be received by all connected clients, _including_ the clien See the [rails/actioncable-examples](https://github.com/rails/actioncable-examples) repository for a full example of how to setup Action Cable in a Rails app, and how to add channels. -## Download and installation +## Configuration -The latest version of Action Cable can be installed with RubyGems: +Action Cable has three required configurations: a subscription adapter, allowed request origins, and the cable server URL (which can optionally be set on the client side). - $ gem install actioncable +### Redis -Source code can be downloaded as part of the Rails project on GitHub +By default, `ActionCable::Server::Base` will look for a configuration file in `Rails.root.join('config/cable.yml')`. +This file must specify an adapter and a URL for each Rails environment. It may use the following format: -* https://github.com/rails/rails/tree/master/actioncable +```yaml +production: &production + adapter: redis + url: redis://10.10.3.153:6381 +development: &development + adapter: redis + url: redis://localhost:6379 +test: *development +``` + +You can also change the location of the Action Cable config file in a Rails initializer with something like: + +```ruby +Rails.application.paths.add "config/cable", with: "somewhere/else/cable.yml" +``` + +### Allowed Request Origins + +Action Cable will only accept requests from specific origins. + +By default, only an origin matching the cable server itself will be permitted. +Additional origins can be specified using strings or regular expressions, provided in an array. + +```ruby +Rails.application.config.action_cable.allowed_request_origins = ['http://rubyonrails.com', /http:\/\/ruby.*/] +``` + +When running in the development environment, this defaults to "http://localhost:3000". + +To disable protection and allow requests from any origin: + +```ruby +Rails.application.config.action_cable.disable_request_forgery_protection = true +``` + +To disable automatic access for same-origin requests, and strictly allow +only the configured origins: + +```ruby +Rails.application.config.action_cable.allow_same_origin_as_host = false +``` + +### Consumer Configuration + +Once you have decided how to run your cable server (see below), you must provide the server URL (or path) to your client-side setup. +There are two ways you can do this. + +The first is to simply pass it in when creating your consumer. For a standalone server, +this would be something like: `App.cable = ActionCable.createConsumer("ws://example.com:28080")`, and for an in-app server, +something like: `App.cable = ActionCable.createConsumer("/cable")`. + +The second option is to pass the server URL through the `action_cable_meta_tag` in your layout. +This uses a URL or path typically set via `config.action_cable.url` in the environment configuration files, or defaults to "/cable". + +This method is especially useful if your WebSocket URL might change between environments. If you host your production server via https, you will need to use the wss scheme +for your Action Cable server, but development might remain http and use the ws scheme. You might use localhost in development and your +domain in production. + +In any case, to vary the WebSocket URL between environments, add the following configuration to each environment: + +```ruby +config.action_cable.url = "ws://example.com:28080" +``` + +Then add the following line to your layout before your JavaScript tag: + +```erb +<%= action_cable_meta_tag %> +``` + +And finally, create your consumer like so: + +```coffeescript +App.cable = ActionCable.createConsumer() +``` + +### Other Configurations + +The other common option to configure is the log tags applied to the per-connection logger. Here's an example that uses the user account id if available, else "no-account" while tagging: + +```ruby +config.action_cable.log_tags = [ + -> request { request.env['user_account_id'] || "no-account" }, + :action_cable, + -> request { request.uuid } +] +``` + +For a full list of all configuration options, see the `ActionCable::Server::Configuration` class. + +Also note that your server must provide at least the same number of database connections as you have workers. The default worker pool is set to 4, so that means you have to make at least that available. You can change that in `config/database.yml` through the `pool` attribute. + + +## Running the cable server + +### Standalone +The cable server(s) is separated from your normal application server. It's still a Rack application, but it is its own Rack +application. The recommended basic setup is as follows: + +```ruby +# cable/config.ru +require ::File.expand_path('../../config/environment', __FILE__) +Rails.application.eager_load! + +run ActionCable.server +``` + +Then you start the server using a binstub in bin/cable ala: +```sh +#!/bin/bash +bundle exec puma -p 28080 cable/config.ru +``` + +The above will start a cable server on port 28080. + +### In app + +If you are using a server that supports the [Rack socket hijacking API](http://www.rubydoc.info/github/rack/rack/file/SPEC#Hijacking), Action Cable can run alongside your Rails application. For example, to listen for WebSocket requests on `/websocket`, specify that path to `config.action_cable.mount_path`: + +```ruby +# config/application.rb +class Application < Rails::Application + config.action_cable.mount_path = '/websocket' +end +``` + +For every instance of your server you create and for every worker your server spawns, you will also have a new instance of Action Cable, but the use of Redis keeps messages synced across connections. + +### Notes + +Beware that currently, the cable server will _not_ auto-reload any changes in the framework. As we've discussed, long-running cable connections mean long-running objects. We don't yet have a way of reloading the classes of those objects in a safe manner. So when you change your channels, or the model your channels use, you must restart the cable server. + +We'll get all this abstracted properly when the framework is integrated into Rails. + +The WebSocket server doesn't have access to the session, but it has access to the cookies. This can be used when you need to handle authentication. You can see one way of doing that with Devise in this [article](http://www.rubytutorial.io/actioncable-devise-authentication). + +## Dependencies + +Action Cable provides a subscription adapter interface to process its pubsub internals. By default, asynchronous, inline, PostgreSQL, evented Redis, and non-evented Redis adapters are included. The default adapter in new Rails applications is the asynchronous (`async`) adapter. To create your own adapter, you can look at `ActionCable::SubscriptionAdapter::Base` for all methods that must be implemented, and any of the adapters included within Action Cable as example implementations. + +The Ruby side of things is built on top of [websocket-driver](https://github.com/faye/websocket-driver-ruby), [nio4r](https://github.com/celluloid/nio4r), and [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby). + + +## Deployment + +Action Cable is powered by a combination of WebSockets and threads. All of the +connection management is handled internally by utilizing Ruby’s native thread +support, which means you can use all your regular Rails models with no problems +as long as you haven’t committed any thread-safety sins. + +The Action Cable server does _not_ need to be a multi-threaded application server. +This is because Action Cable uses the [Rack socket hijacking API](http://www.rubydoc.info/github/rack/rack/file/SPEC#Hijacking) +to take over control of connections from the application server. Action Cable +then manages connections internally, in a multithreaded manner, regardless of +whether the application server is multi-threaded or not. So Action Cable works +with all the popular application servers -- Unicorn, Puma and Passenger. + +Action Cable does not work with WEBrick, because WEBrick does not support the +Rack socket hijacking API. + +## Frontend assets + +Action Cable's frontend assets are distributed through two channels: the +official gem and npm package, both titled `actioncable`. + +### Gem usage + +Through the `actioncable` gem, Action Cable's frontend assets are +available through the Rails Asset Pipeline. Create a `cable.js` or +`cable.coffee` file (this is automatically done for you with Rails +generators), and then simply require the assets: + +In JavaScript... + +```javascript +//= require action_cable +``` + +... and in CoffeeScript: + +```coffeescript +#= require action_cable +``` + +### npm usage + +In addition to being available through the `actioncable` gem, Action Cable's +frontend JS assets are also bundled in an officially supported npm module, +intended for usage in standalone frontend applications that communicate with a +Rails application. A common use case for this could be if you have a decoupled +frontend application written in React, Ember.js, etc. and want to add real-time +WebSocket functionality. + +### Installation + +``` +npm install actioncable --save +``` + +### Usage + +The `ActionCable` constant is available as a `require`-able module, so +you only have to require the package to gain access to the API that is +provided. + +In JavaScript... + +```javascript +ActionCable = require('actioncable') + +var cable = ActionCable.createConsumer('wss://RAILS-API-PATH.com/cable') + +cable.subscriptions.create('AppearanceChannel', { + // normal channel code goes here... +}); +``` + +and in CoffeeScript... + +```coffeescript +ActionCable = require('actioncable') + +cable = ActionCable.createConsumer('wss://RAILS-API-PATH.com/cable') + +cable.subscriptions.create 'AppearanceChannel', + # normal channel code goes here... +``` ## License diff --git a/actioncable/Rakefile b/actioncable/Rakefile index a72142deb5..87d443919c 100644 --- a/actioncable/Rakefile +++ b/actioncable/Rakefile @@ -1,13 +1,12 @@ -require 'rake/testtask' -require 'pathname' -require 'action_cable' -require 'blade' +require "rake/testtask" +require "pathname" +require "action_cable" dir = File.dirname(__FILE__) -task :default => :test +task default: :test -task :package => "assets:compile" +task package: "assets:compile" Rake::TestTask.new do |t| t.libs << "test" @@ -20,12 +19,13 @@ end namespace :test do task :isolated do Dir.glob("test/**/*_test.rb").all? do |file| - sh(Gem.ruby, '-w', '-Ilib:test', file) - end or raise "Failures" + sh(Gem.ruby, "-w", "-Ilib:test", file) + end || raise("Failures") end task :integration do - if ENV['CI'] + require "blade" + if ENV["CI"] Blade.start(interface: :ci) else Blade.start(interface: :runner) @@ -36,6 +36,7 @@ end namespace :assets do desc "Compile Action Cable assets" task :compile do + require "blade" Blade.build end end diff --git a/actioncable/actioncable.gemspec b/actioncable/actioncable.gemspec index c65ff7871f..e7f91d0e34 100644 --- a/actioncable/actioncable.gemspec +++ b/actioncable/actioncable.gemspec @@ -1,25 +1,25 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'actioncable' + s.name = "actioncable" s.version = version - s.summary = 'WebSocket framework for Rails.' - s.description = 'Structure many real-time application concerns into channels over a single WebSocket connection.' + s.summary = "WebSocket framework for Rails." + s.description = "Structure many real-time application concerns into channels over a single WebSocket connection." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = ['Pratik Naik', 'David Heinemeier Hansson'] - s.email = ['pratiknaik@gmail.com', 'david@loudthinking.com'] - s.homepage = 'http://rubyonrails.org' + s.author = ["Pratik Naik", "David Heinemeier Hansson"] + s.email = ["pratiknaik@gmail.com", "david@loudthinking.com"] + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.md', 'lib/**/*'] - s.require_path = 'lib' + s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.md", "lib/**/*"] + s.require_path = "lib" - s.add_dependency 'actionpack', version + s.add_dependency "actionpack", version - s.add_dependency 'nio4r', '~> 1.2' - s.add_dependency 'websocket-driver', '~> 0.6.1' + s.add_dependency "nio4r", "~> 1.2" + s.add_dependency "websocket-driver", "~> 0.6.1" end diff --git a/actioncable/lib/action_cable.rb b/actioncable/lib/action_cable.rb index b6d2842867..d353716636 100644 --- a/actioncable/lib/action_cable.rb +++ b/actioncable/lib/action_cable.rb @@ -21,21 +21,21 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'active_support' -require 'active_support/rails' -require 'action_cable/version' +require "active_support" +require "active_support/rails" +require "action_cable/version" module ActionCable extend ActiveSupport::Autoload INTERNAL = { message_types: { - welcome: 'welcome'.freeze, - ping: 'ping'.freeze, - confirmation: 'confirm_subscription'.freeze, - rejection: 'reject_subscription'.freeze + welcome: "welcome".freeze, + ping: "ping".freeze, + confirmation: "confirm_subscription".freeze, + rejection: "reject_subscription".freeze }, - default_mount_path: '/cable'.freeze, + default_mount_path: "/cable".freeze, protocols: ["actioncable-v1-json".freeze, "actioncable-unsupported".freeze].freeze } diff --git a/actioncable/lib/action_cable/channel/base.rb b/actioncable/lib/action_cable/channel/base.rb index 845b747fc5..a866044f95 100644 --- a/actioncable/lib/action_cable/channel/base.rb +++ b/actioncable/lib/action_cable/channel/base.rb @@ -1,4 +1,4 @@ -require 'set' +require "set" module ActionCable module Channel @@ -144,13 +144,14 @@ module ActionCable # When a channel is streaming via pubsub, we want to delay the confirmation # transmission until pubsub subscription is confirmed. - @defer_subscription_confirmation = false + # + # The counter starts at 1 because it's awaiting a call to #subscribe_to_channel + @defer_subscription_confirmation_counter = Concurrent::AtomicFixnum.new(1) @reject_subscription = nil @subscription_confirmation_sent = nil delegate_connection_identifiers - subscribe_to_channel end # Extract the action name from the passed data and process it via the channel. The process will ensure @@ -169,6 +170,17 @@ module ActionCable end end + # This method is called after subscription has been added to the connection + # and confirms or rejects the subscription. + def subscribe_to_channel + run_callbacks :subscribe do + subscribed + end + + reject_subscription if subscription_rejected? + ensure_confirmation_sent + end + # Called by the cable connection when it's cut, so the channel has a chance to cleanup with callbacks. # This method is not intended to be called directly by the user. Instead, overwrite the #unsubscribed callback. def unsubscribe_from_channel # :nodoc: @@ -177,7 +189,6 @@ module ActionCable end end - protected # Called once a consumer has become a subscriber of the channel. Usually the place to setup any streams # you want this channel to be sending to the subscriber. @@ -202,12 +213,18 @@ module ActionCable end end + def ensure_confirmation_sent + return if subscription_rejected? + @defer_subscription_confirmation_counter.decrement + transmit_subscription_confirmation unless defer_subscription_confirmation? + end + def defer_subscription_confirmation! - @defer_subscription_confirmation = true + @defer_subscription_confirmation_counter.increment end def defer_subscription_confirmation? - @defer_subscription_confirmation + @defer_subscription_confirmation_counter.value > 0 end def subscription_confirmation_sent? @@ -231,24 +248,12 @@ module ActionCable end end - def subscribe_to_channel - run_callbacks :subscribe do - subscribed - end - - if subscription_rejected? - reject_subscription - else - transmit_subscription_confirmation unless defer_subscription_confirmation? - end - end - def extract_action(data) - (data['action'].presence || :receive).to_sym + (data["action"].presence || :receive).to_sym end def processable_action?(action) - self.class.action_methods.include?(action.to_s) + self.class.action_methods.include?(action.to_s) unless subscription_rejected? end def dispatch_action(action, data) @@ -263,7 +268,7 @@ module ActionCable def action_signature(action, data) "#{self.class.name}##{action}".tap do |signature| - if (arguments = data.except('action')).any? + if (arguments = data.except("action")).any? signature << "(#{arguments.inspect})" end end diff --git a/actioncable/lib/action_cable/channel/broadcasting.rb b/actioncable/lib/action_cable/channel/broadcasting.rb index afc23d7d1a..23ed4ec943 100644 --- a/actioncable/lib/action_cable/channel/broadcasting.rb +++ b/actioncable/lib/action_cable/channel/broadcasting.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/to_param' +require "active_support/core_ext/object/to_param" module ActionCable module Channel @@ -16,7 +16,7 @@ module ActionCable def broadcasting_for(model) #:nodoc: case when model.is_a?(Array) - model.map { |m| broadcasting_for(m) }.join(':') + model.map { |m| broadcasting_for(m) }.join(":") when model.respond_to?(:to_gid_param) model.to_gid_param else diff --git a/actioncable/lib/action_cable/channel/callbacks.rb b/actioncable/lib/action_cable/channel/callbacks.rb index 295d750e86..c740132c94 100644 --- a/actioncable/lib/action_cable/channel/callbacks.rb +++ b/actioncable/lib/action_cable/channel/callbacks.rb @@ -1,4 +1,4 @@ -require 'active_support/callbacks' +require "active_support/callbacks" module ActionCable module Channel diff --git a/actioncable/lib/action_cable/channel/naming.rb b/actioncable/lib/action_cable/channel/naming.rb index 8e1b2a4af0..b7e88bf73d 100644 --- a/actioncable/lib/action_cable/channel/naming.rb +++ b/actioncable/lib/action_cable/channel/naming.rb @@ -12,7 +12,7 @@ module ActionCable # Chats::AppearancesChannel.channel_name # => 'chats:appearances' # FooChats::BarAppearancesChannel.channel_name # => 'foo_chats:bar_appearances' def channel_name - @channel_name ||= name.sub(/Channel$/, '').gsub('::',':').underscore + @channel_name ||= name.sub(/Channel$/, "").gsub("::",":").underscore end end diff --git a/actioncable/lib/action_cable/channel/periodic_timers.rb b/actioncable/lib/action_cable/channel/periodic_timers.rb index dab604440f..c9daa0bcd3 100644 --- a/actioncable/lib/action_cable/channel/periodic_timers.rb +++ b/actioncable/lib/action_cable/channel/periodic_timers.rb @@ -30,7 +30,7 @@ module ActionCable def periodically(callback_or_method_name = nil, every:, &block) callback = if block_given? - raise ArgumentError, 'Pass a block or provide a callback arg, not both' if callback_or_method_name + raise ArgumentError, "Pass a block or provide a callback arg, not both" if callback_or_method_name block else case callback_or_method_name @@ -64,9 +64,7 @@ module ActionCable def start_periodic_timer(callback, every:) connection.server.event_loop.timer every do - connection.worker_pool.async_invoke connection do - instance_exec(&callback) - end + connection.worker_pool.async_exec self, connection: connection, &callback end end diff --git a/actioncable/lib/action_cable/channel/streams.rb b/actioncable/lib/action_cable/channel/streams.rb index 561750d713..dbba333353 100644 --- a/actioncable/lib/action_cable/channel/streams.rb +++ b/actioncable/lib/action_cable/channel/streams.rb @@ -69,8 +69,8 @@ module ActionCable # Start streaming from the named <tt>broadcasting</tt> pubsub queue. Optionally, you can pass a <tt>callback</tt> that'll be used # instead of the default of just transmitting the updates straight to the subscriber. - # Pass `coder: ActiveSupport::JSON` to decode messages as JSON before passing to the callback. - # Defaults to `coder: nil` which does no decoding, passes raw messages. + # Pass <tt>coder: ActiveSupport::JSON</tt> to decode messages as JSON before passing to the callback. + # Defaults to <tt>coder: nil</tt> which does no decoding, passes raw messages. def stream_from(broadcasting, callback = nil, coder: nil, &block) broadcasting = String(broadcasting) @@ -84,7 +84,7 @@ module ActionCable connection.server.event_loop.post do pubsub.subscribe(broadcasting, handler, lambda do - transmit_subscription_confirmation + ensure_confirmation_sent logger.info "#{self.class.name} is streaming from #{broadcasting}" end) end @@ -94,8 +94,8 @@ module ActionCable # <tt>callback</tt> that'll be used instead of the default of just transmitting the updates straight # to the subscriber. # - # Pass `coder: ActiveSupport::JSON` to decode messages as JSON before passing to the callback. - # Defaults to `coder: nil` which does no decoding, passes raw messages. + # Pass <tt>coder: ActiveSupport::JSON</tt> to decode messages as JSON before passing to the callback. + # Defaults to <tt>coder: nil</tt> which does no decoding, passes raw messages. def stream_for(model, callback = nil, coder: nil, &block) stream_from(broadcasting_for([ channel_name, model ]), callback || block, coder: coder) end diff --git a/actioncable/lib/action_cable/connection.rb b/actioncable/lib/action_cable/connection.rb index 5f813cf8e0..902efb07e2 100644 --- a/actioncable/lib/action_cable/connection.rb +++ b/actioncable/lib/action_cable/connection.rb @@ -8,8 +8,6 @@ module ActionCable autoload :ClientSocket autoload :Identification autoload :InternalChannel - autoload :FayeClientSocket - autoload :FayeEventLoop autoload :MessageBuffer autoload :Stream autoload :StreamEventLoop diff --git a/actioncable/lib/action_cable/connection/authorization.rb b/actioncable/lib/action_cable/connection/authorization.rb index 070a70e4e2..85df206445 100644 --- a/actioncable/lib/action_cable/connection/authorization.rb +++ b/actioncable/lib/action_cable/connection/authorization.rb @@ -10,4 +10,4 @@ module ActionCable end end end -end
\ No newline at end of file +end diff --git a/actioncable/lib/action_cable/connection/base.rb b/actioncable/lib/action_cable/connection/base.rb index 75c1299e36..dfee123ea2 100644 --- a/actioncable/lib/action_cable/connection/base.rb +++ b/actioncable/lib/action_cable/connection/base.rb @@ -1,4 +1,4 @@ -require 'action_dispatch' +require "action_dispatch" module ActionCable module Connection @@ -57,7 +57,7 @@ module ActionCable @worker_pool = server.worker_pool @logger = new_tagged_logger - @websocket = ActionCable::Connection::WebSocket.new(env, self, event_loop, server.config.client_socket_class) + @websocket = ActionCable::Connection::WebSocket.new(env, self, event_loop) @subscriptions = ActionCable::Connection::Subscriptions.new(self) @message_buffer = ActionCable::Connection::MessageBuffer.new(self) @@ -105,14 +105,14 @@ module ActionCable worker_pool.async_invoke(self, method, *arguments) end - # Return a basic hash of statistics for the connection keyed with `identifier`, `started_at`, and `subscriptions`. + # Return a basic hash of statistics for the connection keyed with <tt>identifier</tt>, <tt>started_at</tt>, <tt>subscriptions</tt>, and <tt>request_id</tt>. # This can be returned by a health check against the connection. def statistics { identifier: connection_identifier, started_at: @started_at, subscriptions: subscriptions.identifiers, - request_id: @env['action_dispatch.request_id'] + request_id: @env["action_dispatch.request_id"] } end @@ -195,7 +195,10 @@ module ActionCable def allow_request_origin? return true if server.config.disable_request_forgery_protection - if Array(server.config.allowed_request_origins).any? { |allowed_origin| allowed_origin === env['HTTP_ORIGIN'] } + proto = Rack::Request.new(env).ssl? ? "https" : "http" + if server.config.allow_same_origin_as_host && env["HTTP_ORIGIN"] == "#{proto}://#{env['HTTP_HOST']}" + true + elsif Array(server.config.allowed_request_origins).any? { |allowed_origin| allowed_origin === env["HTTP_ORIGIN"] } true else logger.error("Request origin not allowed: #{env['HTTP_ORIGIN']}") @@ -213,7 +216,7 @@ module ActionCable logger.error invalid_request_message logger.info finished_request_message - [ 404, { 'Content-Type' => 'text/plain' }, [ 'Page not found' ] ] + [ 404, { "Content-Type" => "text/plain" }, [ "Page not found" ] ] end # Tags are declared in the server but computed in the connection. This allows us per-connection tailored tags. @@ -226,7 +229,7 @@ module ActionCable 'Started %s "%s"%s for %s at %s' % [ request.request_method, request.filtered_path, - websocket.possible? ? ' [WebSocket]' : '[non-WebSocket]', + websocket.possible? ? " [WebSocket]" : "[non-WebSocket]", request.ip, Time.now.to_s ] end @@ -234,19 +237,19 @@ module ActionCable def finished_request_message 'Finished "%s"%s for %s at %s' % [ request.filtered_path, - websocket.possible? ? ' [WebSocket]' : '[non-WebSocket]', + websocket.possible? ? " [WebSocket]" : "[non-WebSocket]", request.ip, Time.now.to_s ] end def invalid_request_message - 'Failed to upgrade to WebSocket (REQUEST_METHOD: %s, HTTP_CONNECTION: %s, HTTP_UPGRADE: %s)' % [ + "Failed to upgrade to WebSocket (REQUEST_METHOD: %s, HTTP_CONNECTION: %s, HTTP_UPGRADE: %s)" % [ env["REQUEST_METHOD"], env["HTTP_CONNECTION"], env["HTTP_UPGRADE"] ] end def successful_request_message - 'Successfully upgraded to WebSocket (REQUEST_METHOD: %s, HTTP_CONNECTION: %s, HTTP_UPGRADE: %s)' % [ + "Successfully upgraded to WebSocket (REQUEST_METHOD: %s, HTTP_CONNECTION: %s, HTTP_UPGRADE: %s)" % [ env["REQUEST_METHOD"], env["HTTP_CONNECTION"], env["HTTP_UPGRADE"] ] end diff --git a/actioncable/lib/action_cable/connection/client_socket.rb b/actioncable/lib/action_cable/connection/client_socket.rb index 6f29f32ea9..70a2bbecb1 100644 --- a/actioncable/lib/action_cable/connection/client_socket.rb +++ b/actioncable/lib/action_cable/connection/client_socket.rb @@ -1,4 +1,4 @@ -require 'websocket/driver' +require "websocket/driver" module ActionCable module Connection @@ -8,16 +8,16 @@ module ActionCable # Copyright (c) 2010-2015 James Coglan class ClientSocket # :nodoc: def self.determine_url(env) - scheme = secure_request?(env) ? 'wss:' : 'ws:' + scheme = secure_request?(env) ? "wss:" : "ws:" "#{ scheme }//#{ env['HTTP_HOST'] }#{ env['REQUEST_URI'] }" end def self.secure_request?(env) - return true if env['HTTPS'] == 'on' - return true if env['HTTP_X_FORWARDED_SSL'] == 'on' - return true if env['HTTP_X_FORWARDED_SCHEME'] == 'https' - return true if env['HTTP_X_FORWARDED_PROTO'] == 'https' - return true if env['rack.url_scheme'] == 'https' + return true if env["HTTPS"] == "on" + return true if env["HTTP_X_FORWARDED_SSL"] == "on" + return true if env["HTTP_X_FORWARDED_SCHEME"] == "https" + return true if env["HTTP_X_FORWARDED_PROTO"] == "https" + return true if env["rack.url_scheme"] == "https" return false end @@ -37,7 +37,7 @@ module ActionCable @url = ClientSocket.determine_url(@env) @driver = @driver_started = nil - @close_params = ['', 1006] + @close_params = ["", 1006] @ready_state = CONNECTING @@ -56,7 +56,7 @@ module ActionCable return if @driver.nil? || @driver_started @stream.hijack_rack_socket - if callback = @env['async.callback'] + if callback = @env["async.callback"] callback.call([101, {}, @stream]) end @@ -78,18 +78,18 @@ module ActionCable def transmit(message) return false if @ready_state > OPEN case message - when Numeric then @driver.text(message.to_s) - when String then @driver.text(message) - when Array then @driver.binary(message) + when Numeric then @driver.text(message.to_s) + when String then @driver.text(message) + when Array then @driver.binary(message) else false end end def close(code = nil, reason = nil) code ||= 1000 - reason ||= '' + reason ||= "" - unless code == 1000 or (code >= 3000 and code <= 4999) + unless code == 1000 || (code >= 3000 && code <= 4999) raise ArgumentError, "Failed to execute 'close' on WebSocket: " + "The code must be either 1000, or between 3000 and 4999. " + "#{code} is neither." diff --git a/actioncable/lib/action_cable/connection/faye_client_socket.rb b/actioncable/lib/action_cable/connection/faye_client_socket.rb deleted file mode 100644 index a4bfe7db17..0000000000 --- a/actioncable/lib/action_cable/connection/faye_client_socket.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'faye/websocket' - -module ActionCable - module Connection - class FayeClientSocket - def initialize(env, event_target, stream_event_loop, protocols) - @env = env - @event_target = event_target - @protocols = protocols - - @faye = nil - end - - def alive? - @faye && @faye.ready_state == Faye::WebSocket::API::OPEN - end - - def transmit(data) - connect - @faye.send data - end - - def close - @faye && @faye.close - end - - def protocol - @faye && @faye.protocol - end - - def rack_response - connect - @faye.rack_response - end - - private - def connect - return if @faye - @faye = Faye::WebSocket.new(@env, @protocols) - - @faye.on(:open) { |event| @event_target.on_open } - @faye.on(:message) { |event| @event_target.on_message(event.data) } - @faye.on(:close) { |event| @event_target.on_close(event.reason, event.code) } - @faye.on(:error) { |event| @event_target.on_error(event.message) } - end - end - end -end diff --git a/actioncable/lib/action_cable/connection/faye_event_loop.rb b/actioncable/lib/action_cable/connection/faye_event_loop.rb deleted file mode 100644 index 9c44b38bc3..0000000000 --- a/actioncable/lib/action_cable/connection/faye_event_loop.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'thread' - -require 'eventmachine' -EventMachine.epoll if EventMachine.epoll? -EventMachine.kqueue if EventMachine.kqueue? - -module ActionCable - module Connection - class FayeEventLoop - @@mutex = Mutex.new - - def timer(interval, &block) - ensure_reactor_running - EMTimer.new(::EM::PeriodicTimer.new(interval, &block)) - end - - def post(task = nil, &block) - task ||= block - - ensure_reactor_running - ::EM.next_tick(&task) - end - - private - def ensure_reactor_running - return if EventMachine.reactor_running? - @@mutex.synchronize do - Thread.new { EventMachine.run } unless EventMachine.reactor_running? - Thread.pass until EventMachine.reactor_running? - end - end - - class EMTimer - def initialize(inner) - @inner = inner - end - - def shutdown - @inner.cancel - end - end - end - end -end diff --git a/actioncable/lib/action_cable/connection/identification.rb b/actioncable/lib/action_cable/connection/identification.rb index 4a54044aff..c91a1d1fd7 100644 --- a/actioncable/lib/action_cable/connection/identification.rb +++ b/actioncable/lib/action_cable/connection/identification.rb @@ -1,4 +1,4 @@ -require 'set' +require "set" module ActionCable module Connection diff --git a/actioncable/lib/action_cable/connection/internal_channel.rb b/actioncable/lib/action_cable/connection/internal_channel.rb index f70d52f99b..8f0ec766c3 100644 --- a/actioncable/lib/action_cable/connection/internal_channel.rb +++ b/actioncable/lib/action_cable/connection/internal_channel.rb @@ -27,8 +27,8 @@ module ActionCable end def process_internal_message(message) - case message['type'] - when 'disconnect' + case message["type"] + when "disconnect" logger.info "Removing connection (#{connection_identifier})" websocket.close end diff --git a/actioncable/lib/action_cable/connection/stream.rb b/actioncable/lib/action_cable/connection/stream.rb index 0cf59091bc..e620b93845 100644 --- a/actioncable/lib/action_cable/connection/stream.rb +++ b/actioncable/lib/action_cable/connection/stream.rb @@ -1,3 +1,5 @@ +require "thread" + module ActionCable module Connection #-- @@ -8,9 +10,13 @@ module ActionCable def initialize(event_loop, socket) @event_loop = event_loop @socket_object = socket - @stream_send = socket.env['stream.send'] + @stream_send = socket.env["stream.send"] @rack_hijack_io = nil + @write_lock = Mutex.new + + @write_head = nil + @write_buffer = Queue.new end def each(&callback) @@ -27,21 +33,71 @@ module ActionCable end def write(data) - return @rack_hijack_io.write(data) if @rack_hijack_io - return @stream_send.call(data) if @stream_send + if @stream_send + return @stream_send.call(data) + end + + if @write_lock.try_lock + begin + if @write_head.nil? && @write_buffer.empty? + written = @rack_hijack_io.write_nonblock(data, exception: false) + + case written + when :wait_writable + # proceed below + when data.bytesize + return data.bytesize + else + @write_head = data.byteslice(written, data.bytesize) + @event_loop.writes_pending @rack_hijack_io + + return data.bytesize + end + end + ensure + @write_lock.unlock + end + end + + @write_buffer << data + @event_loop.writes_pending @rack_hijack_io + + data.bytesize rescue EOFError, Errno::ECONNRESET @socket_object.client_gone end + def flush_write_buffer + @write_lock.synchronize do + loop do + if @write_head.nil? + return true if @write_buffer.empty? + @write_head = @write_buffer.pop + end + + written = @rack_hijack_io.write_nonblock(@write_head, exception: false) + case written + when :wait_writable + return false + when @write_head.bytesize + @write_head = nil + else + @write_head = @write_head.byteslice(written, @write_head.bytesize) + return false + end + end + end + end + def receive(data) @socket_object.parse(data) end def hijack_rack_socket - return unless @socket_object.env['rack.hijack'] + return unless @socket_object.env["rack.hijack"] - @socket_object.env['rack.hijack'].call - @rack_hijack_io = @socket_object.env['rack.hijack_io'] + @socket_object.env["rack.hijack"].call + @rack_hijack_io = @socket_object.env["rack.hijack_io"] @event_loop.attach(@rack_hijack_io, self) end diff --git a/actioncable/lib/action_cable/connection/stream_event_loop.rb b/actioncable/lib/action_cable/connection/stream_event_loop.rb index 2abad09c03..2d1af0ff9f 100644 --- a/actioncable/lib/action_cable/connection/stream_event_loop.rb +++ b/actioncable/lib/action_cable/connection/stream_event_loop.rb @@ -1,11 +1,11 @@ -require 'nio' -require 'thread' +require "nio" +require "thread" module ActionCable module Connection class StreamEventLoop def initialize - @nio = @thread = nil + @nio = @executor = @thread = nil @map = {} @stopping = false @todo = Queue.new @@ -20,13 +20,14 @@ module ActionCable def post(task = nil, &block) task ||= block - Concurrent.global_io_executor << task + spawn + @executor << task end def attach(io, stream) @todo << lambda do - @map[io] = stream - @nio.register(io, :r) + @map[io] = @nio.register(io, :r) + @map[io].value = stream end wakeup end @@ -35,6 +36,16 @@ module ActionCable @todo << lambda do @nio.deregister io @map.delete io + io.close + end + wakeup + end + + def writes_pending(io) + @todo << lambda do + if monitor = @map[io] + monitor.interests = :rw + end end wakeup end @@ -52,6 +63,13 @@ module ActionCable return if @thread && @thread.status @nio ||= NIO::Selector.new + + @executor ||= Concurrent::ThreadPoolExecutor.new( + min_threads: 1, + max_threads: 10, + max_queue: 0, + ) + @thread = Thread.new { run } return true @@ -77,12 +95,25 @@ module ActionCable monitors.each do |monitor| io = monitor.io - stream = @map[io] + stream = monitor.value begin - stream.receive io.read_nonblock(4096) - rescue IO::WaitReadable - next + if monitor.writable? + if stream.flush_write_buffer + monitor.interests = :r + end + next unless monitor.readable? + end + + incoming = io.read_nonblock(4096, exception: false) + case incoming + when :wait_readable + next + when nil + stream.close + else + stream.receive incoming + end rescue # We expect one of EOFError or Errno::ECONNRESET in # normal operation (when the client goes away). But if diff --git a/actioncable/lib/action_cable/connection/subscriptions.rb b/actioncable/lib/action_cable/connection/subscriptions.rb index 6051818bfb..00511aead5 100644 --- a/actioncable/lib/action_cable/connection/subscriptions.rb +++ b/actioncable/lib/action_cable/connection/subscriptions.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/indifferent_access' +require "active_support/core_ext/hash/indifferent_access" module ActionCable module Connection @@ -11,10 +11,10 @@ module ActionCable end def execute_command(data) - case data['command'] - when 'subscribe' then add data - when 'unsubscribe' then remove data - when 'message' then perform_action data + case data["command"] + when "subscribe" then add data + when "unsubscribe" then remove data + when "message" then perform_action data else logger.error "Received unrecognized command in #{data.inspect}" end @@ -23,13 +23,17 @@ module ActionCable end def add(data) - id_key = data['identifier'] + id_key = data["identifier"] id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access + return if subscriptions.key?(id_key) + subscription_klass = id_options[:channel].safe_constantize if subscription_klass && ActionCable::Channel::Base >= subscription_klass - subscriptions[id_key] ||= subscription_klass.new(connection, id_key, id_options) + subscription = subscription_klass.new(connection, id_key, id_options) + subscriptions[id_key] = subscription + subscription.subscribe_to_channel else logger.error "Subscription class not found: #{id_options[:channel].inspect}" end @@ -37,7 +41,7 @@ module ActionCable def remove(data) logger.info "Unsubscribing from channel: #{data['identifier']}" - remove_subscription subscriptions[data['identifier']] + remove_subscription subscriptions[data["identifier"]] end def remove_subscription(subscription) @@ -46,7 +50,7 @@ module ActionCable end def perform_action(data) - find(data).perform_action ActiveSupport::JSON.decode(data['data']) + find(data).perform_action ActiveSupport::JSON.decode(data["data"]) end def identifiers @@ -64,7 +68,7 @@ module ActionCable delegate :logger, to: :connection def find(data) - if subscription = subscriptions[data['identifier']] + if subscription = subscriptions[data["identifier"]] subscription else raise "Unable to find subscription with identifier: #{data['identifier']}" diff --git a/actioncable/lib/action_cable/connection/web_socket.rb b/actioncable/lib/action_cable/connection/web_socket.rb index 11f28c37e8..382141b89f 100644 --- a/actioncable/lib/action_cable/connection/web_socket.rb +++ b/actioncable/lib/action_cable/connection/web_socket.rb @@ -1,11 +1,11 @@ -require 'websocket/driver' +require "websocket/driver" module ActionCable module Connection # Wrap the real socket to minimize the externally-presented API class WebSocket - def initialize(env, event_target, event_loop, client_socket_class, protocols: ActionCable::INTERNAL[:protocols]) - @websocket = ::WebSocket::Driver.websocket?(env) ? client_socket_class.new(env, event_target, event_loop, protocols) : nil + def initialize(env, event_target, event_loop, protocols: ActionCable::INTERNAL[:protocols]) + @websocket = ::WebSocket::Driver.websocket?(env) ? ClientSocket.new(env, event_target, event_loop, protocols) : nil end def possible? diff --git a/actioncable/lib/action_cable/engine.rb b/actioncable/lib/action_cable/engine.rb index 34f9952c71..4c5c975cd8 100644 --- a/actioncable/lib/action_cable/engine.rb +++ b/actioncable/lib/action_cable/engine.rb @@ -32,7 +32,7 @@ module ActionCable end previous_connection_class = self.connection_class - self.connection_class = -> { 'ApplicationCable::Connection'.safe_constantize || previous_connection_class.call } + self.connection_class = -> { "ApplicationCable::Connection".safe_constantize || previous_connection_class.call } options.each { |k,v| send("#{k}=", v) } end diff --git a/actioncable/lib/action_cable/remote_connections.rb b/actioncable/lib/action_cable/remote_connections.rb index a528024427..720ba52d19 100644 --- a/actioncable/lib/action_cable/remote_connections.rb +++ b/actioncable/lib/action_cable/remote_connections.rb @@ -41,7 +41,7 @@ module ActionCable # Uses the internal channel to disconnect the connection. def disconnect - server.broadcast internal_channel, type: 'disconnect' + server.broadcast internal_channel, type: "disconnect" end # Returns all the identifiers that were applied to this connection. diff --git a/actioncable/lib/action_cable/server.rb b/actioncable/lib/action_cable/server.rb index bd6a3826a3..22f9353825 100644 --- a/actioncable/lib/action_cable/server.rb +++ b/actioncable/lib/action_cable/server.rb @@ -9,7 +9,7 @@ module ActionCable autoload :Configuration autoload :Worker - autoload :ActiveRecordConnectionManagement, 'action_cable/server/worker/active_record_connection_management' + autoload :ActiveRecordConnectionManagement, "action_cable/server/worker/active_record_connection_management" end end end diff --git a/actioncable/lib/action_cable/server/base.rb b/actioncable/lib/action_cable/server/base.rb index 0ad1e408a9..419eccd73c 100644 --- a/actioncable/lib/action_cable/server/base.rb +++ b/actioncable/lib/action_cable/server/base.rb @@ -1,4 +1,4 @@ -require 'monitor' +require "monitor" module ActionCable module Server @@ -37,9 +37,13 @@ module ActionCable connections.each(&:close) @mutex.synchronize do - worker_pool.halt if @worker_pool - + # Shutdown the worker pool + @worker_pool.halt if @worker_pool @worker_pool = nil + + # Shutdown the pub/sub adapter + @pubsub.shutdown if @pubsub + @pubsub = nil end end @@ -49,12 +53,12 @@ module ActionCable end def event_loop - @event_loop || @mutex.synchronize { @event_loop ||= config.event_loop_class.new } + @event_loop || @mutex.synchronize { @event_loop ||= ActionCable::Connection::StreamEventLoop.new } end # The worker pool is where we run connection callbacks and channel actions. We do as little as possible on the server's main thread. # The worker pool is an executor service that's backed by a pool of threads working from a task queue. The thread pool size maxes out - # at 4 worker threads by default. Tune the size yourself with `config.action_cable.worker_pool_size`. + # at 4 worker threads by default. Tune the size yourself with <tt>config.action_cable.worker_pool_size</tt>. # # Using Active Record, Redis, etc within your channel actions means you'll get a separate connection from each thread in the worker pool. # Plan your deployment accordingly: 5 servers each running 5 Puma workers each running an 8-thread worker pool means at least 200 database diff --git a/actioncable/lib/action_cable/server/broadcasting.rb b/actioncable/lib/action_cable/server/broadcasting.rb index 8f93564113..1fc58baa3e 100644 --- a/actioncable/lib/action_cable/server/broadcasting.rb +++ b/actioncable/lib/action_cable/server/broadcasting.rb @@ -39,8 +39,12 @@ module ActionCable def broadcast(message) server.logger.info "[ActionCable] Broadcasting to #{broadcasting}: #{message.inspect}" - encoded = coder ? coder.encode(message) : message - server.pubsub.broadcast broadcasting, encoded + + payload = { broadcasting: broadcasting, message: message, coder: coder } + ActiveSupport::Notifications.instrument("broadcast.action_cable", payload) do + encoded = coder ? coder.encode(message) : message + server.pubsub.broadcast broadcasting, encoded + end end end end diff --git a/actioncable/lib/action_cable/server/configuration.rb b/actioncable/lib/action_cable/server/configuration.rb index ada1ac22cc..17e0dee064 100644 --- a/actioncable/lib/action_cable/server/configuration.rb +++ b/actioncable/lib/action_cable/server/configuration.rb @@ -4,8 +4,8 @@ module ActionCable # in a Rails config initializer. class Configuration attr_accessor :logger, :log_tags - attr_accessor :use_faye, :connection_class, :worker_pool_size - attr_accessor :disable_request_forgery_protection, :allowed_request_origins + attr_accessor :connection_class, :worker_pool_size + attr_accessor :disable_request_forgery_protection, :allowed_request_origins, :allow_same_origin_as_host attr_accessor :cable, :url, :mount_path def initialize @@ -15,13 +15,14 @@ module ActionCable @worker_pool_size = 4 @disable_request_forgery_protection = false + @allow_same_origin_as_host = true end # Returns constant of subscription adapter specified in config/cable.yml. # If the adapter cannot be found, this will default to the Redis adapter. # Also makes sure proper dependencies are required. def pubsub_adapter - adapter = (cable.fetch('adapter') { 'redis' }) + adapter = (cable.fetch("adapter") { "redis" }) path_to_adapter = "action_cable/subscription_adapter/#{adapter}" begin require path_to_adapter @@ -32,25 +33,9 @@ module ActionCable end adapter = adapter.camelize - adapter = 'PostgreSQL' if adapter == 'Postgresql' + adapter = "PostgreSQL" if adapter == "Postgresql" "ActionCable::SubscriptionAdapter::#{adapter}".constantize end - - def event_loop_class - if use_faye - ActionCable::Connection::FayeEventLoop - else - ActionCable::Connection::StreamEventLoop - end - end - - def client_socket_class - if use_faye - ActionCable::Connection::FayeClientSocket - else - ActionCable::Connection::ClientSocket - end - end end end end diff --git a/actioncable/lib/action_cable/server/worker.rb b/actioncable/lib/action_cable/server/worker.rb index a638ff72e7..43639c27af 100644 --- a/actioncable/lib/action_cable/server/worker.rb +++ b/actioncable/lib/action_cable/server/worker.rb @@ -1,6 +1,6 @@ -require 'active_support/callbacks' -require 'active_support/core_ext/module/attribute_accessors_per_thread' -require 'concurrent' +require "active_support/callbacks" +require "active_support/core_ext/module/attribute_accessors_per_thread" +require "concurrent" module ActionCable module Server @@ -25,7 +25,7 @@ module ActionCable # Stop processing work: any work that has not already started # running will be discarded from the queue def halt - @executor.kill + @executor.shutdown end def stopping? @@ -42,16 +42,20 @@ module ActionCable self.connection = nil end - def async_invoke(receiver, method, *args, connection: receiver) + def async_exec(receiver, *args, connection:, &block) + async_invoke receiver, :instance_exec, *args, connection: connection, &block + end + + def async_invoke(receiver, method, *args, connection: receiver, &block) @executor.post do - invoke(receiver, method, *args, connection: connection) + invoke(receiver, method, *args, connection: connection, &block) end end - def invoke(receiver, method, *args, connection:) + def invoke(receiver, method, *args, connection:, &block) work(connection) do begin - receiver.send method, *args + receiver.send method, *args, &block rescue Exception => e logger.error "There was an exception - #{e.class}(#{e.message})" logger.error e.backtrace.join("\n") diff --git a/actioncable/lib/action_cable/subscription_adapter/async.rb b/actioncable/lib/action_cable/subscription_adapter/async.rb index 10b3ac8cd8..46819dbfec 100644 --- a/actioncable/lib/action_cable/subscription_adapter/async.rb +++ b/actioncable/lib/action_cable/subscription_adapter/async.rb @@ -1,4 +1,4 @@ -require 'action_cable/subscription_adapter/inline' +require "action_cable/subscription_adapter/inline" module ActionCable module SubscriptionAdapter diff --git a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb index 4735a4bfa8..bcd46d2a0e 100644 --- a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb +++ b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb @@ -1,9 +1,9 @@ -require 'thread' +require "thread" -gem 'em-hiredis', '~> 0.3.0' -gem 'redis', '~> 3.0' -require 'em-hiredis' -require 'redis' +gem "em-hiredis", "~> 0.3.0" +gem "redis", "~> 3.0" +require "em-hiredis" +require "redis" EventMachine.epoll if EventMachine.epoll? EventMachine.kqueue if EventMachine.kqueue? diff --git a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb index 66c7852f6e..bdab5205ec 100644 --- a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb +++ b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb @@ -1,6 +1,6 @@ -gem 'pg', '~> 0.18' -require 'pg' -require 'thread' +gem "pg", "~> 0.18" +require "pg" +require "thread" module ActionCable module SubscriptionAdapter @@ -33,7 +33,7 @@ module ActionCable pg_conn = ar_conn.raw_connection unless pg_conn.is_a?(PG::Connection) - raise 'ActiveRecord database must be Postgres in order to use the Postgres ActionCable storage adapter' + raise "The Active Record database must be PostgreSQL in order to use the PostgreSQL Action Cable storage adapter" end yield pg_conn diff --git a/actioncable/lib/action_cable/subscription_adapter/redis.rb b/actioncable/lib/action_cable/subscription_adapter/redis.rb index 65434f7107..62bd284a6b 100644 --- a/actioncable/lib/action_cable/subscription_adapter/redis.rb +++ b/actioncable/lib/action_cable/subscription_adapter/redis.rb @@ -1,7 +1,7 @@ -require 'thread' +require "thread" -gem 'redis', '~> 3.0' -require 'redis' +gem "redis", "~> 3.0" +require "redis" module ActionCable module SubscriptionAdapter @@ -72,7 +72,7 @@ module ActionCable conn.without_reconnect do original_client = conn.client - conn.subscribe('_action_cable_internal') do |on| + conn.subscribe("_action_cable_internal") do |on| on.subscribe do |chan, count| @subscription_lock.synchronize do if count == 1 @@ -111,7 +111,7 @@ module ActionCable return if @thread.nil? when_connected do - send_command('unsubscribe') + send_command("unsubscribe") @raw_client = nil end end @@ -123,13 +123,13 @@ module ActionCable @subscription_lock.synchronize do ensure_listener_running @subscribe_callbacks[channel] << on_success - when_connected { send_command('subscribe', channel) } + when_connected { send_command("subscribe", channel) } end end def remove_channel(channel) @subscription_lock.synchronize do - when_connected { send_command('unsubscribe', channel) } + when_connected { send_command("unsubscribe", channel) } end end diff --git a/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb b/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb index 37eed09793..4ec513e3ba 100644 --- a/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb +++ b/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb @@ -32,7 +32,11 @@ module ActionCable end def broadcast(channel, message) - list = @sync.synchronize { @subscribers[channel].dup } + list = @sync.synchronize do + return if !@subscribers.key?(channel) + @subscribers[channel].dup + end + list.each do |subscriber| invoke_callback(subscriber, message) end diff --git a/actioncable/lib/action_cable/version.rb b/actioncable/lib/action_cable/version.rb index e17877202b..d6081409f0 100644 --- a/actioncable/lib/action_cable/version.rb +++ b/actioncable/lib/action_cable/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActionCable # Returns the version of the currently loaded Action Cable as a <tt>Gem::Version</tt> diff --git a/actioncable/lib/rails/generators/channel/channel_generator.rb b/actioncable/lib/rails/generators/channel/channel_generator.rb index 47232252e3..20d807c033 100644 --- a/actioncable/lib/rails/generators/channel/channel_generator.rb +++ b/actioncable/lib/rails/generators/channel/channel_generator.rb @@ -10,14 +10,14 @@ module Rails check_class_collision suffix: "Channel" def create_channel_file - template "channel.rb", File.join('app/channels', class_path, "#{file_name}_channel.rb") + template "channel.rb", File.join("app/channels", class_path, "#{file_name}_channel.rb") if options[:assets] if self.behavior == :invoke template "assets/cable.js", "app/assets/javascripts/cable.js" end - js_template "assets/channel", File.join('app/assets/javascripts/channels', class_path, "#{file_name}") + js_template "assets/channel", File.join("app/assets/javascripts/channels", class_path, "#{file_name}") end generate_application_cable_files @@ -25,7 +25,7 @@ module Rails protected def file_name - @_file_name ||= super.gsub(/_channel/i, '') + @_file_name ||= super.gsub(/_channel/i, "") end # FIXME: Change these files to symlinks once RubyGems 2.5.0 is required. @@ -33,12 +33,12 @@ module Rails return if self.behavior != :invoke files = [ - 'application_cable/channel.rb', - 'application_cable/connection.rb' + "application_cable/channel.rb", + "application_cable/connection.rb" ] files.each do |name| - path = File.join('app/channels/', name) + path = File.join("app/channels/", name) template(name, path) if !File.exist?(path) end end diff --git a/actioncable/lib/rails/generators/channel/templates/application_cable/channel.rb b/actioncable/lib/rails/generators/channel/templates/application_cable/channel.rb index 17a85f60f9..d672697283 100644 --- a/actioncable/lib/rails/generators/channel/templates/application_cable/channel.rb +++ b/actioncable/lib/rails/generators/channel/templates/application_cable/channel.rb @@ -1,5 +1,3 @@ -# Be sure to restart your server when you modify this file. Action Cable runs in -# a loop that does not support auto reloading. module ApplicationCable class Channel < ActionCable::Channel::Base end diff --git a/actioncable/lib/rails/generators/channel/templates/application_cable/connection.rb b/actioncable/lib/rails/generators/channel/templates/application_cable/connection.rb index 93f28c4306..0ff5442f47 100644 --- a/actioncable/lib/rails/generators/channel/templates/application_cable/connection.rb +++ b/actioncable/lib/rails/generators/channel/templates/application_cable/connection.rb @@ -1,5 +1,3 @@ -# Be sure to restart your server when you modify this file. Action Cable runs in -# a loop that does not support auto reloading. module ApplicationCable class Connection < ActionCable::Connection::Base end diff --git a/actioncable/lib/rails/generators/channel/templates/assets/cable.js b/actioncable/lib/rails/generators/channel/templates/assets/cable.js index 71ee1e66de..739aa5f022 100644 --- a/actioncable/lib/rails/generators/channel/templates/assets/cable.js +++ b/actioncable/lib/rails/generators/channel/templates/assets/cable.js @@ -1,5 +1,5 @@ // Action Cable provides the framework to deal with WebSockets in Rails. -// You can generate new channels where WebSocket features live using the rails generate channel command. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. // //= require action_cable //= require_self diff --git a/actioncable/lib/rails/generators/channel/templates/channel.rb b/actioncable/lib/rails/generators/channel/templates/channel.rb index 7bff3341c1..4bcfb2be4d 100644 --- a/actioncable/lib/rails/generators/channel/templates/channel.rb +++ b/actioncable/lib/rails/generators/channel/templates/channel.rb @@ -1,4 +1,3 @@ -# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading. <% module_namespacing do -%> class <%= class_name %>Channel < ApplicationCable::Channel def subscribed diff --git a/actioncable/test/channel/base_test.rb b/actioncable/test/channel/base_test.rb index daa782eeb3..9a3a3581e6 100644 --- a/actioncable/test/channel/base_test.rb +++ b/actioncable/test/channel/base_test.rb @@ -1,6 +1,6 @@ -require 'test_helper' -require 'stubs/test_connection' -require 'stubs/room' +require "test_helper" +require "stubs/test_connection" +require "stubs/room" class ActionCable::Channel::BaseTest < ActiveSupport::TestCase class ActionCable::Channel::Base @@ -58,7 +58,7 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase end def get_latest - transmit data: 'latest' + transmit data: "latest" end def receive @@ -74,14 +74,16 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase setup do @user = User.new "lifo" @connection = TestConnection.new(@user) - @channel = ChatChannel.new @connection, "{id: 1}", { id: 1 } + @channel = ChatChannel.new @connection, "{id: 1}", id: 1 end - test "should subscribe to a channel on initialize" do + test "should subscribe to a channel" do + @channel.subscribe_to_channel assert_equal 1, @channel.room.id end test "on subscribe callbacks" do + @channel.subscribe_to_channel assert @channel.subscribed end @@ -90,6 +92,8 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase end test "unsubscribing from a channel" do + @channel.subscribe_to_channel + assert @channel.room assert @channel.subscribed? @@ -104,54 +108,59 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase end test "callable action without any argument" do - @channel.perform_action 'action' => :leave + @channel.perform_action "action" => :leave assert_equal [ :leave ], @channel.last_action end test "callable action with arguments" do - data = { 'action' => :speak, 'content' => "Hello World" } + data = { "action" => :speak, "content" => "Hello World" } @channel.perform_action data assert_equal [ :speak, data ], @channel.last_action end test "should not dispatch a private method" do - @channel.perform_action 'action' => :rm_rf + @channel.perform_action "action" => :rm_rf assert_nil @channel.last_action end test "should not dispatch a public method defined on Base" do - @channel.perform_action 'action' => :kick + @channel.perform_action "action" => :kick assert_nil @channel.last_action end test "should dispatch a public method defined on Base and redefined on channel" do - data = { 'action' => :topic, 'content' => "This is Sparta!" } + data = { "action" => :topic, "content" => "This is Sparta!" } @channel.perform_action data assert_equal [ :topic, data ], @channel.last_action end test "should dispatch calling a public method defined in an ancestor" do - @channel.perform_action 'action' => :chatters + @channel.perform_action "action" => :chatters assert_equal [ :chatters ], @channel.last_action end test "should dispatch receive action when perform_action is called with empty action" do - data = { 'content' => 'hello' } + data = { "content" => "hello" } @channel.perform_action data assert_equal [ :receive ], @channel.last_action end test "transmitting data" do - @channel.perform_action 'action' => :get_latest + @channel.perform_action "action" => :get_latest - expected = { "identifier" => "{id: 1}", "message" => { "data" => "latest" }} + expected = { "identifier" => "{id: 1}", "message" => { "data" => "latest" } } assert_equal expected, @connection.last_transmission end - test "subscription confirmation" do + test "do not send subscription confirmation on initialize" do + assert_nil @connection.last_transmission + end + + test "subscription confirmation on subscribe_to_channel" do expected = { "identifier" => "{id: 1}", "type" => "confirm_subscription" } + @channel.subscribe_to_channel assert_equal expected, @connection.last_transmission end @@ -162,7 +171,7 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase test "invalid action on Channel" do assert_logged("Unable to process ActionCable::Channel::BaseTest::ChatChannel#invalid_action") do - @channel.perform_action 'action' => :invalid_action + @channel.perform_action "action" => :invalid_action end end @@ -173,12 +182,12 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase events << ActiveSupport::Notifications::Event.new(*args) end - data = {'action' => :speak, 'content' => 'hello'} + data = { "action" => :speak, "content" => "hello" } @channel.perform_action data assert_equal 1, events.length - assert_equal 'perform_action.action_cable', events[0].name - assert_equal 'ActionCable::Channel::BaseTest::ChatChannel', events[0].payload[:channel_class] + assert_equal "perform_action.action_cable", events[0].name + assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class] assert_equal :speak, events[0].payload[:action] assert_equal data, events[0].payload[:data] ensure @@ -189,27 +198,29 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase test "notification for transmit" do begin events = [] - ActiveSupport::Notifications.subscribe 'transmit.action_cable' do |*args| + ActiveSupport::Notifications.subscribe "transmit.action_cable" do |*args| events << ActiveSupport::Notifications::Event.new(*args) end - @channel.perform_action 'action' => :get_latest - expected_data = {data: 'latest'} + @channel.perform_action "action" => :get_latest + expected_data = { data: "latest" } assert_equal 1, events.length - assert_equal 'transmit.action_cable', events[0].name - assert_equal 'ActionCable::Channel::BaseTest::ChatChannel', events[0].payload[:channel_class] + assert_equal "transmit.action_cable", events[0].name + assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class] assert_equal expected_data, events[0].payload[:data] assert_nil events[0].payload[:via] ensure - ActiveSupport::Notifications.unsubscribe 'transmit.action_cable' + ActiveSupport::Notifications.unsubscribe "transmit.action_cable" end end test "notification for transmit_subscription_confirmation" do begin + @channel.subscribe_to_channel + events = [] - ActiveSupport::Notifications.subscribe 'transmit_subscription_confirmation.action_cable' do |*args| + ActiveSupport::Notifications.subscribe "transmit_subscription_confirmation.action_cable" do |*args| events << ActiveSupport::Notifications::Event.new(*args) end @@ -217,27 +228,27 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase @channel.send(:transmit_subscription_confirmation) assert_equal 1, events.length - assert_equal 'transmit_subscription_confirmation.action_cable', events[0].name - assert_equal 'ActionCable::Channel::BaseTest::ChatChannel', events[0].payload[:channel_class] + assert_equal "transmit_subscription_confirmation.action_cable", events[0].name + assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class] ensure - ActiveSupport::Notifications.unsubscribe 'transmit_subscription_confirmation.action_cable' + ActiveSupport::Notifications.unsubscribe "transmit_subscription_confirmation.action_cable" end end test "notification for transmit_subscription_rejection" do begin events = [] - ActiveSupport::Notifications.subscribe 'transmit_subscription_rejection.action_cable' do |*args| + ActiveSupport::Notifications.subscribe "transmit_subscription_rejection.action_cable" do |*args| events << ActiveSupport::Notifications::Event.new(*args) end @channel.send(:transmit_subscription_rejection) assert_equal 1, events.length - assert_equal 'transmit_subscription_rejection.action_cable', events[0].name - assert_equal 'ActionCable::Channel::BaseTest::ChatChannel', events[0].payload[:channel_class] + assert_equal "transmit_subscription_rejection.action_cable", events[0].name + assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class] ensure - ActiveSupport::Notifications.unsubscribe 'transmit_subscription_rejection.action_cable' + ActiveSupport::Notifications.unsubscribe "transmit_subscription_rejection.action_cable" end end diff --git a/actioncable/test/channel/broadcasting_test.rb b/actioncable/test/channel/broadcasting_test.rb index 1de04243e5..3476c1db31 100644 --- a/actioncable/test/channel/broadcasting_test.rb +++ b/actioncable/test/channel/broadcasting_test.rb @@ -1,6 +1,6 @@ -require 'test_helper' -require 'stubs/test_connection' -require 'stubs/room' +require "test_helper" +require "stubs/test_connection" +require "stubs/room" class ActionCable::Channel::BroadcastingTest < ActiveSupport::TestCase class ChatChannel < ActionCable::Channel::Base @@ -11,7 +11,7 @@ class ActionCable::Channel::BroadcastingTest < ActiveSupport::TestCase end test "broadcasts_to" do - ActionCable.stubs(:server).returns mock().tap { |m| m.expects(:broadcast).with('action_cable:channel:broadcasting_test:chat:Room#1-Campfire', "Hello World") } + ActionCable.stubs(:server).returns mock().tap { |m| m.expects(:broadcast).with("action_cable:channel:broadcasting_test:chat:Room#1-Campfire", "Hello World") } ChatChannel.broadcast_to(Room.new(1), "Hello World") end diff --git a/actioncable/test/channel/naming_test.rb b/actioncable/test/channel/naming_test.rb index 89ef6ad8b0..08f0e7be48 100644 --- a/actioncable/test/channel/naming_test.rb +++ b/actioncable/test/channel/naming_test.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require "test_helper" class ActionCable::Channel::NamingTest < ActiveSupport::TestCase class ChatChannel < ActionCable::Channel::Base diff --git a/actioncable/test/channel/periodic_timers_test.rb b/actioncable/test/channel/periodic_timers_test.rb index 03464003cf..2ee711fd29 100644 --- a/actioncable/test/channel/periodic_timers_test.rb +++ b/actioncable/test/channel/periodic_timers_test.rb @@ -1,7 +1,7 @@ -require 'test_helper' -require 'stubs/test_connection' -require 'stubs/room' -require 'active_support/time' +require "test_helper" +require "stubs/test_connection" +require "stubs/room" +require "active_support/time" class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase class ChatChannel < ActionCable::Channel::Base @@ -36,22 +36,22 @@ class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase end end - test 'disallow negative and zero periods' do - [ 0, 0.0, 0.seconds, -1, -1.seconds, 'foo', :foo, Object.new ].each do |invalid| + test "disallow negative and zero periods" do + [ 0, 0.0, 0.seconds, -1, -1.seconds, "foo", :foo, Object.new ].each do |invalid| assert_raise ArgumentError, /Expected every:/ do ChatChannel.periodically :send_updates, every: invalid end end end - test 'disallow block and arg together' do + test "disallow block and arg together" do assert_raise ArgumentError, /not both/ do ChatChannel.periodically(:send_updates, every: 1) { ping } end end - test 'disallow unknown args' do - [ 'send_updates', Object.new, nil ].each do |invalid| + test "disallow unknown args" do + [ "send_updates", Object.new, nil ].each do |invalid| assert_raise ArgumentError, /Expected a Symbol/ do ChatChannel.periodically invalid, every: 1 end @@ -60,8 +60,9 @@ class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase test "timer start and stop" do @connection.server.event_loop.expects(:timer).times(3).returns(stub(shutdown: nil)) - channel = ChatChannel.new @connection, "{id: 1}", { id: 1 } + channel = ChatChannel.new @connection, "{id: 1}", id: 1 + channel.subscribe_to_channel channel.unsubscribe_from_channel assert_equal [], channel.send(:active_periodic_timers) end diff --git a/actioncable/test/channel/rejection_test.rb b/actioncable/test/channel/rejection_test.rb index 15db57d6ba..99c4a7603a 100644 --- a/actioncable/test/channel/rejection_test.rb +++ b/actioncable/test/channel/rejection_test.rb @@ -1,12 +1,15 @@ -require 'test_helper' -require 'stubs/test_connection' -require 'stubs/room' +require "test_helper" +require "stubs/test_connection" +require "stubs/room" class ActionCable::Channel::RejectionTest < ActiveSupport::TestCase class SecretChannel < ActionCable::Channel::Base def subscribed reject if params[:id] > 0 end + + def secret_action + end end setup do @@ -16,10 +19,23 @@ class ActionCable::Channel::RejectionTest < ActiveSupport::TestCase test "subscription rejection" do @connection.expects(:subscriptions).returns mock().tap { |m| m.expects(:remove_subscription).with instance_of(SecretChannel) } - @channel = SecretChannel.new @connection, "{id: 1}", { id: 1 } + @channel = SecretChannel.new @connection, "{id: 1}", id: 1 + @channel.subscribe_to_channel expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" } assert_equal expected, @connection.last_transmission end + test "does not execute action if subscription is rejected" do + @connection.expects(:subscriptions).returns mock().tap { |m| m.expects(:remove_subscription).with instance_of(SecretChannel) } + @channel = SecretChannel.new @connection, "{id: 1}", id: 1 + @channel.subscribe_to_channel + + expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" } + assert_equal expected, @connection.last_transmission + assert_equal 1, @connection.transmissions.size + + @channel.perform_action("action" => :secret_action) + assert_equal 1, @connection.transmissions.size + end end diff --git a/actioncable/test/channel/stream_test.rb b/actioncable/test/channel/stream_test.rb index 38543920d3..31dcde2e29 100644 --- a/actioncable/test/channel/stream_test.rb +++ b/actioncable/test/channel/stream_test.rb @@ -1,6 +1,6 @@ -require 'test_helper' -require 'stubs/test_connection' -require 'stubs/room' +require "test_helper" +require "stubs/test_connection" +require "stubs/room" module ActionCable::StreamTests class Connection < ActionCable::Connection::Base @@ -25,11 +25,11 @@ module ActionCable::StreamTests private def pick_coder(coder) case coder - when nil, 'json' + when nil, "json" ActiveSupport::JSON - when 'custom' + when "custom" DummyEncoder - when 'none' + when "none" nil end end @@ -38,7 +38,7 @@ module ActionCable::StreamTests module DummyEncoder extend self def encode(*) '{ "foo": "encoded" }' end - def decode(*) { foo: 'decoded' } end + def decode(*) { foo: "decoded" } end end class SymbolChannel < ActionCable::Channel::Base @@ -52,7 +52,8 @@ module ActionCable::StreamTests run_in_eventmachine do connection = TestConnection.new connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("test_room_1", kind_of(Proc), kind_of(Proc)).returns stub_everything(:pubsub) } - channel = ChatChannel.new connection, "{id: 1}", { id: 1 } + channel = ChatChannel.new connection, "{id: 1}", id: 1 + channel.subscribe_to_channel connection.expects(:pubsub).returns mock().tap { |m| m.expects(:unsubscribe) } channel.unsubscribe_from_channel @@ -64,6 +65,7 @@ module ActionCable::StreamTests connection = TestConnection.new connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("channel", kind_of(Proc), kind_of(Proc)).returns stub_everything(:pubsub) } channel = SymbolChannel.new connection, "" + channel.subscribe_to_channel connection.expects(:pubsub).returns mock().tap { |m| m.expects(:unsubscribe) } channel.unsubscribe_from_channel @@ -76,6 +78,7 @@ module ActionCable::StreamTests connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("action_cable:stream_tests:chat:Room#1-Campfire", kind_of(Proc), kind_of(Proc)).returns stub_everything(:pubsub) } channel = ChatChannel.new connection, "" + channel.subscribe_to_channel channel.stream_for Room.new(1) end end @@ -84,7 +87,9 @@ module ActionCable::StreamTests run_in_eventmachine do connection = TestConnection.new - ChatChannel.new connection, "{id: 1}", { id: 1 } + channel = ChatChannel.new connection, "{id: 1}", id: 1 + channel.subscribe_to_channel + assert_nil connection.last_transmission wait_for_async @@ -114,7 +119,7 @@ module ActionCable::StreamTests end end - require 'action_cable/subscription_adapter/inline' + require "action_cable/subscription_adapter/async" class UserCallbackChannel < ActionCable::Channel::Base def subscribed @@ -124,19 +129,26 @@ module ActionCable::StreamTests end end - class StreamEncodingTest < ActionCable::TestCase + class MultiChatChannel < ActionCable::Channel::Base + def subscribed + stream_from "main_room" + stream_from "test_all_rooms" + end + end + + class StreamFromTest < ActionCable::TestCase setup do - @server = TestServer.new(subscription_adapter: ActionCable::SubscriptionAdapter::Inline) + @server = TestServer.new(subscription_adapter: ActionCable::SubscriptionAdapter::Async) @server.config.allowed_request_origins = %w( http://rubyonrails.com ) end - test 'custom encoder' do + test "custom encoder" do run_in_eventmachine do connection = open_connection subscribe_to connection, identifiers: { id: 1 } connection.websocket.expects(:transmit) - @server.broadcast 'test_room_1', { foo: 'bar' }, coder: DummyEncoder + @server.broadcast "test_room_1", { foo: "bar" }, coder: DummyEncoder wait_for_async wait_for_executor connection.server.worker_pool.executor end @@ -145,21 +157,32 @@ module ActionCable::StreamTests test "user supplied callbacks are run through the worker pool" do run_in_eventmachine do connection = open_connection - receive(connection, command: 'subscribe', channel: UserCallbackChannel.name, identifiers: { id: 1 }) + receive(connection, command: "subscribe", channel: UserCallbackChannel.name, identifiers: { id: 1 }) - @server.broadcast 'channel', {} + @server.broadcast "channel", {} wait_for_async refute Thread.current[:ran_callback], "User callback was not run through the worker pool" end end + test "subscription confirmation should only be sent out once with muptiple stream_from" do + run_in_eventmachine do + connection = open_connection + expected = { "identifier" => { "channel" => MultiChatChannel.name }.to_json, "type" => "confirm_subscription" } + connection.websocket.expects(:transmit).with(expected.to_json) + receive(connection, command: "subscribe", channel: MultiChatChannel.name, identifiers: {}) + + wait_for_async + end + end + private def subscribe_to(connection, identifiers:) - receive connection, command: 'subscribe', identifiers: identifiers + receive connection, command: "subscribe", identifiers: identifiers end def open_connection - env = Rack::MockRequest.env_for '/test', 'HTTP_HOST' => 'localhost', 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket', 'HTTP_ORIGIN' => 'http://rubyonrails.com' + env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", "HTTP_ORIGIN" => "http://rubyonrails.com" Connection.new(@server, env).tap do |connection| connection.process @@ -170,7 +193,7 @@ module ActionCable::StreamTests end end - def receive(connection, command:, identifiers:, channel: 'ActionCable::StreamTests::ChatChannel') + def receive(connection, command:, identifiers:, channel: "ActionCable::StreamTests::ChatChannel") identifier = JSON.generate(channel: channel, **identifiers) connection.dispatch_websocket_message JSON.generate(command: command, identifier: identifier) wait_for_async diff --git a/actioncable/test/client_test.rb b/actioncable/test/client_test.rb index f4b4a53aea..db10a7ad16 100644 --- a/actioncable/test/client_test.rb +++ b/actioncable/test/client_test.rb @@ -1,14 +1,31 @@ -require 'test_helper' -require 'concurrent' +require "test_helper" +require "concurrent" -require 'active_support/core_ext/hash/indifferent_access' -require 'pathname' +require "websocket-client-simple" +require "json" -require 'faye/websocket' -require 'json' +require "active_support/hash_with_indifferent_access" + +#### +# 😷 Warning suppression 😷 +WebSocket::Frame::Handler::Handler03.prepend Module.new { + def initialize(*) + @application_data_buffer = nil + super + end +} + +WebSocket::Frame::Data.prepend Module.new { + def initialize(*) + @masking_key = nil + super + end +} +# +#### class ClientTest < ActionCable::TestCase - WAIT_WHEN_EXPECTING_EVENT = 8 + WAIT_WHEN_EXPECTING_EVENT = 2 WAIT_WHEN_NOT_EXPECTING_EVENT = 0.5 class EchoChannel < ActionCable::Channel::Base @@ -17,20 +34,20 @@ class ClientTest < ActionCable::TestCase end def unsubscribed - 'Goodbye from EchoChannel!' + "Goodbye from EchoChannel!" end def ding(data) - transmit(dong: data['message']) + transmit(dong: data["message"]) end def delay(data) sleep 1 - transmit(dong: data['message']) + transmit(dong: data["message"]) end def bulk(data) - ActionCable.server.broadcast "global", wide: data['message'] + ActionCable.server.broadcast "global", wide: data["message"] end end @@ -39,26 +56,15 @@ class ClientTest < ActionCable::TestCase server = ActionCable.server server.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN } - server.config.cable = { adapter: 'async' }.with_indifferent_access - server.config.use_faye = ENV['FAYE'].present? + server.config.cable = ActiveSupport::HashWithIndifferentAccess.new(adapter: "async") # and now the "real" setup for our test: server.config.disable_request_forgery_protection = true - - Thread.new { EventMachine.run } unless EventMachine.reactor_running? - Thread.pass until EventMachine.reactor_running? - - # faye-websocket is warning-rich - @previous_verbose, $VERBOSE = $VERBOSE, nil - end - - def teardown - $VERBOSE = @previous_verbose end def with_puma_server(rack_app = ActionCable.server, port = 3099) server = ::Puma::Server.new(rack_app, ::Puma::Events.strings) - server.add_tcp_listener '127.0.0.1', port + server.add_tcp_listener "127.0.0.1", port server.min_threads = 1 server.max_threads = 4 @@ -74,44 +80,49 @@ class ClientTest < ActionCable::TestCase attr_reader :pings def initialize(port) - @ws = Faye::WebSocket::Client.new("ws://127.0.0.1:#{port}/") - @messages = Queue.new - @closed = Concurrent::Event.new - @has_messages = Concurrent::Semaphore.new(0) - @pings = 0 - - open = Concurrent::Event.new - error = nil - - @ws.on(:error) do |event| - if open.set? - @messages << RuntimeError.new(event.message) - else - error = event.message - open.set + messages = @messages = Queue.new + closed = @closed = Concurrent::Event.new + has_messages = @has_messages = Concurrent::Semaphore.new(0) + pings = @pings = Concurrent::AtomicFixnum.new(0) + + open = Concurrent::Promise.new + + @ws = WebSocket::Client::Simple.connect("ws://127.0.0.1:#{port}/") do |ws| + ws.on(:error) do |event| + event = RuntimeError.new(event.message) unless event.is_a?(Exception) + + if open.pending? + open.fail(event) + else + messages << event + has_messages.release + end end - end - @ws.on(:open) do |event| - open.set - end + ws.on(:open) do |event| + open.set(true) + end - @ws.on(:message) do |event| - message = JSON.parse(event.data) - if message['type'] == 'ping' - @pings += 1 - else - @messages << message - @has_messages.release + ws.on(:message) do |event| + if event.type == :close + closed.set + else + message = JSON.parse(event.data) + if message["type"] == "ping" + pings.increment + else + messages << message + has_messages.release + end + end end - end - @ws.on(:close) do |event| - @closed.set + ws.on(:close) do |event| + closed.set + end end - open.wait(WAIT_WHEN_EXPECTING_EVENT) - raise error if error + open.wait!(WAIT_WHEN_EXPECTING_EVENT) end def read_message @@ -162,76 +173,80 @@ class ClientTest < ActionCable::TestCase end end - def faye_client(port) + def websocket_client(port) SyncClient.new(port) end + def concurrently(enum) + enum.map { |*x| Concurrent::Future.execute { yield(*x) } }.map(&:value!) + end + def test_single_client with_puma_server do |port| - c = faye_client(port) - assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack - c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel') - assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message) - c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello') - assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "message"=>{"dong"=>"hello"}}, c.read_message) + c = websocket_client(port) + assert_equal({ "type" => "welcome" }, c.read_message) # pop the first welcome message off the stack + c.send_message command: "subscribe", identifier: JSON.generate(channel: "ClientTest::EchoChannel") + assert_equal({ "identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription" }, c.read_message) + c.send_message command: "message", identifier: JSON.generate(channel: "ClientTest::EchoChannel"), data: JSON.generate(action: "ding", message: "hello") + assert_equal({ "identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "message"=>{ "dong"=>"hello" } }, c.read_message) c.close end end def test_interacting_clients with_puma_server do |port| - clients = 10.times.map { faye_client(port) } + clients = concurrently(10.times) { websocket_client(port) } barrier_1 = Concurrent::CyclicBarrier.new(clients.size) barrier_2 = Concurrent::CyclicBarrier.new(clients.size) - clients.map {|c| Concurrent::Future.execute { - assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack - c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel') - assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "type"=>"confirm_subscription"}, c.read_message) - c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello') - assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message) + concurrently(clients) do |c| + assert_equal({ "type" => "welcome" }, c.read_message) # pop the first welcome message off the stack + c.send_message command: "subscribe", identifier: JSON.generate(channel: "ClientTest::EchoChannel") + assert_equal({ "identifier"=>'{"channel":"ClientTest::EchoChannel"}', "type"=>"confirm_subscription" }, c.read_message) + c.send_message command: "message", identifier: JSON.generate(channel: "ClientTest::EchoChannel"), data: JSON.generate(action: "ding", message: "hello") + assert_equal({ "identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{ "dong"=>"hello" } }, c.read_message) barrier_1.wait WAIT_WHEN_EXPECTING_EVENT - c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'bulk', message: 'hello') + c.send_message command: "message", identifier: JSON.generate(channel: "ClientTest::EchoChannel"), data: JSON.generate(action: "bulk", message: "hello") barrier_2.wait WAIT_WHEN_EXPECTING_EVENT assert_equal clients.size, c.read_messages(clients.size).size - } }.each(&:wait!) + end - clients.map {|c| Concurrent::Future.execute { c.close } }.each(&:wait!) + concurrently(clients, &:close) end end def test_many_clients with_puma_server do |port| - clients = 100.times.map { faye_client(port) } - - clients.map {|c| Concurrent::Future.execute { - assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack - c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel') - assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "type"=>"confirm_subscription"}, c.read_message) - c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello') - assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message) - } }.each(&:wait!) + clients = concurrently(100.times) { websocket_client(port) } + + concurrently(clients) do |c| + assert_equal({ "type" => "welcome" }, c.read_message) # pop the first welcome message off the stack + c.send_message command: "subscribe", identifier: JSON.generate(channel: "ClientTest::EchoChannel") + assert_equal({ "identifier"=>'{"channel":"ClientTest::EchoChannel"}', "type"=>"confirm_subscription" }, c.read_message) + c.send_message command: "message", identifier: JSON.generate(channel: "ClientTest::EchoChannel"), data: JSON.generate(action: "ding", message: "hello") + assert_equal({ "identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{ "dong"=>"hello" } }, c.read_message) + end - clients.map {|c| Concurrent::Future.execute { c.close } }.each(&:wait!) + concurrently(clients, &:close) end end def test_disappearing_client with_puma_server do |port| - c = faye_client(port) - assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack - c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel') - assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message) - c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'delay', message: 'hello') + c = websocket_client(port) + assert_equal({ "type" => "welcome" }, c.read_message) # pop the first welcome message off the stack + c.send_message command: "subscribe", identifier: JSON.generate(channel: "ClientTest::EchoChannel") + assert_equal({ "identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription" }, c.read_message) + c.send_message command: "message", identifier: JSON.generate(channel: "ClientTest::EchoChannel"), data: JSON.generate(action: "delay", message: "hello") c.close # disappear before write - c = faye_client(port) - assert_equal({"type" => "welcome"}, c.read_message) # pop the first welcome message off the stack - c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel') - assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message) - c.send_message command: 'message', identifier: JSON.generate(channel: 'ClientTest::EchoChannel'), data: JSON.generate(action: 'ding', message: 'hello') - assert_equal({"identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{"dong"=>"hello"}}, c.read_message) + c = websocket_client(port) + assert_equal({ "type" => "welcome" }, c.read_message) # pop the first welcome message off the stack + c.send_message command: "subscribe", identifier: JSON.generate(channel: "ClientTest::EchoChannel") + assert_equal({ "identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription" }, c.read_message) + c.send_message command: "message", identifier: JSON.generate(channel: "ClientTest::EchoChannel"), data: JSON.generate(action: "ding", message: "hello") + assert_equal({ "identifier"=>'{"channel":"ClientTest::EchoChannel"}', "message"=>{ "dong"=>"hello" } }, c.read_message) c.close # disappear before read end end @@ -239,17 +254,17 @@ class ClientTest < ActionCable::TestCase def test_unsubscribe_client with_puma_server do |port| app = ActionCable.server - identifier = JSON.generate(channel: 'ClientTest::EchoChannel') + identifier = JSON.generate(channel: "ClientTest::EchoChannel") - c = faye_client(port) - assert_equal({"type" => "welcome"}, c.read_message) - c.send_message command: 'subscribe', identifier: identifier - assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message) + c = websocket_client(port) + assert_equal({ "type" => "welcome" }, c.read_message) + c.send_message command: "subscribe", identifier: identifier + assert_equal({ "identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription" }, c.read_message) assert_equal(1, app.connections.count) assert(app.remote_connections.where(identifier: identifier)) subscriptions = app.connections.first.subscriptions.send(:subscriptions) - assert_not_equal 0, subscriptions.size, 'Missing EchoChannel subscription' + assert_not_equal 0, subscriptions.size, "Missing EchoChannel subscription" channel = subscriptions.first[1] channel.expects(:unsubscribed) c.close @@ -262,10 +277,10 @@ class ClientTest < ActionCable::TestCase def test_server_restart with_puma_server do |port| - c = faye_client(port) - assert_equal({"type" => "welcome"}, c.read_message) - c.send_message command: 'subscribe', identifier: JSON.generate(channel: 'ClientTest::EchoChannel') - assert_equal({"identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription"}, c.read_message) + c = websocket_client(port) + assert_equal({ "type" => "welcome" }, c.read_message) + c.send_message command: "subscribe", identifier: JSON.generate(channel: "ClientTest::EchoChannel") + assert_equal({ "identifier"=>"{\"channel\":\"ClientTest::EchoChannel\"}", "type"=>"confirm_subscription" }, c.read_message) ActionCable.server.restart c.wait_for_close diff --git a/actioncable/test/connection/authorization_test.rb b/actioncable/test/connection/authorization_test.rb index a0506cb9c0..dcdbe9c1d1 100644 --- a/actioncable/test/connection/authorization_test.rb +++ b/actioncable/test/connection/authorization_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require 'stubs/test_server' +require "test_helper" +require "stubs/test_server" class ActionCable::Connection::AuthorizationTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -19,8 +19,8 @@ class ActionCable::Connection::AuthorizationTest < ActionCable::TestCase server = TestServer.new server.config.allowed_request_origins = %w( http://rubyonrails.com ) - env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket', - 'HTTP_HOST' => 'localhost', 'HTTP_ORIGIN' => 'http://rubyonrails.com' + env = Rack::MockRequest.env_for "/test", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", + "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.com" connection = Connection.new(server, env) connection.websocket.expects(:close) diff --git a/actioncable/test/connection/base_test.rb b/actioncable/test/connection/base_test.rb index d7e1041e68..9bcd0700cf 100644 --- a/actioncable/test/connection/base_test.rb +++ b/actioncable/test/connection/base_test.rb @@ -1,6 +1,6 @@ -require 'test_helper' -require 'stubs/test_server' -require 'active_support/core_ext/object/json' +require "test_helper" +require "stubs/test_server" +require "active_support/core_ext/object/json" class ActionCable::Connection::BaseTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -113,14 +113,14 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase run_in_eventmachine do class CallMeMaybe def call(*) - raise 'Do not call me!' + raise "Do not call me!" end end env = Rack::MockRequest.env_for( "/test", - { 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket', - 'HTTP_HOST' => 'localhost', 'HTTP_ORIGIN' => 'http://rubyonrails.org', 'rack.hijack' => CallMeMaybe.new } + "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", + "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.org", "rack.hijack" => CallMeMaybe.new ) connection = ActionCable::Connection::Base.new(@server, env) @@ -131,8 +131,8 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase private def open_connection - env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket', - 'HTTP_HOST' => 'localhost', 'HTTP_ORIGIN' => 'http://rubyonrails.com' + env = Rack::MockRequest.env_for "/test", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", + "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.com" Connection.new(@server, env) end diff --git a/actioncable/test/connection/client_socket_test.rb b/actioncable/test/connection/client_socket_test.rb index 4af071b4da..bc3ff6a3d7 100644 --- a/actioncable/test/connection/client_socket_test.rb +++ b/actioncable/test/connection/client_socket_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require 'stubs/test_server' +require "test_helper" +require "stubs/test_server" class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -32,28 +32,46 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase @server.config.allowed_request_origins = %w( http://rubyonrails.com ) end - test 'delegate socket errors to on_error handler' do - skip if ENV['FAYE'].present? - + test "delegate socket errors to on_error handler" do run_in_eventmachine do connection = open_connection # Internal hax = :( client = connection.websocket.send(:websocket) - client.instance_variable_get('@stream').expects(:write).raises('foo') + client.instance_variable_get("@stream").expects(:write).raises("foo") client.expects(:client_gone).never - client.write('boo') + client.write("boo") assert_equal %w[ foo ], connection.errors end end + test "closes hijacked i/o socket at shutdown" do + run_in_eventmachine do + connection = open_connection + + client = connection.websocket.send(:websocket) + event = Concurrent::Event.new + client.instance_variable_get("@stream") + .instance_variable_get("@rack_hijack_io") + .define_singleton_method(:close) { event.set } + connection.close + event.wait + end + end + private def open_connection - env = Rack::MockRequest.env_for '/test', - 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket', - 'HTTP_HOST' => 'localhost', 'HTTP_ORIGIN' => 'http://rubyonrails.com' - env['rack.hijack'] = -> { env['rack.hijack_io'] = StringIO.new } + env = Rack::MockRequest.env_for "/test", + "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", + "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.com" + io = \ + begin + Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM, 0).first + rescue + StringIO.new + end + env["rack.hijack"] = -> { env["rack.hijack_io"] = io } Connection.new(@server, env).tap do |connection| connection.process diff --git a/actioncable/test/connection/cross_site_forgery_test.rb b/actioncable/test/connection/cross_site_forgery_test.rb index 2d516b0533..37bedfd734 100644 --- a/actioncable/test/connection/cross_site_forgery_test.rb +++ b/actioncable/test/connection/cross_site_forgery_test.rb @@ -1,8 +1,8 @@ -require 'test_helper' -require 'stubs/test_server' +require "test_helper" +require "stubs/test_server" class ActionCable::Connection::CrossSiteForgeryTest < ActionCable::TestCase - HOST = 'rubyonrails.com' + HOST = "rubyonrails.com" class Connection < ActionCable::Connection::Base def send_async(method, *args) @@ -13,44 +13,53 @@ class ActionCable::Connection::CrossSiteForgeryTest < ActionCable::TestCase setup do @server = TestServer.new @server.config.allowed_request_origins = %w( http://rubyonrails.com ) + @server.config.allow_same_origin_as_host = false end teardown do @server.config.disable_request_forgery_protection = false @server.config.allowed_request_origins = [] + @server.config.allow_same_origin_as_host = true end test "disable forgery protection" do @server.config.disable_request_forgery_protection = true - assert_origin_allowed 'http://rubyonrails.com' - assert_origin_allowed 'http://hax.com' + assert_origin_allowed "http://rubyonrails.com" + assert_origin_allowed "http://hax.com" end test "explicitly specified a single allowed origin" do - @server.config.allowed_request_origins = 'http://hax.com' - assert_origin_not_allowed 'http://rubyonrails.com' - assert_origin_allowed 'http://hax.com' + @server.config.allowed_request_origins = "http://hax.com" + assert_origin_not_allowed "http://rubyonrails.com" + assert_origin_allowed "http://hax.com" end test "explicitly specified multiple allowed origins" do @server.config.allowed_request_origins = %w( http://rubyonrails.com http://www.rubyonrails.com ) - assert_origin_allowed 'http://rubyonrails.com' - assert_origin_allowed 'http://www.rubyonrails.com' - assert_origin_not_allowed 'http://hax.com' + assert_origin_allowed "http://rubyonrails.com" + assert_origin_allowed "http://www.rubyonrails.com" + assert_origin_not_allowed "http://hax.com" end test "explicitly specified a single regexp allowed origin" do @server.config.allowed_request_origins = /.*ha.*/ - assert_origin_not_allowed 'http://rubyonrails.com' - assert_origin_allowed 'http://hax.com' + assert_origin_not_allowed "http://rubyonrails.com" + assert_origin_allowed "http://hax.com" end test "explicitly specified multiple regexp allowed origins" do - @server.config.allowed_request_origins = [/http:\/\/ruby.*/, /.*rai.s.*com/, 'string' ] - assert_origin_allowed 'http://rubyonrails.com' - assert_origin_allowed 'http://www.rubyonrails.com' - assert_origin_not_allowed 'http://hax.com' - assert_origin_not_allowed 'http://rails.co.uk' + @server.config.allowed_request_origins = [/http:\/\/ruby.*/, /.*rai.s.*com/, "string" ] + assert_origin_allowed "http://rubyonrails.com" + assert_origin_allowed "http://www.rubyonrails.com" + assert_origin_not_allowed "http://hax.com" + assert_origin_not_allowed "http://rails.co.uk" + end + + test "allow same origin as host" do + @server.config.allow_same_origin_as_host = true + assert_origin_allowed "http://#{HOST}" + assert_origin_not_allowed "http://hax.com" + assert_origin_not_allowed "http://rails.co.uk" end private @@ -75,7 +84,7 @@ class ActionCable::Connection::CrossSiteForgeryTest < ActionCable::TestCase end def env_for_origin(origin) - Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket', 'SERVER_NAME' => HOST, - 'HTTP_HOST' => HOST, 'HTTP_ORIGIN' => origin + Rack::MockRequest.env_for "/test", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", "SERVER_NAME" => HOST, + "HTTP_HOST" => HOST, "HTTP_ORIGIN" => origin end end diff --git a/actioncable/test/connection/identifier_test.rb b/actioncable/test/connection/identifier_test.rb index b48d9af809..a4dfcc06f0 100644 --- a/actioncable/test/connection/identifier_test.rb +++ b/actioncable/test/connection/identifier_test.rb @@ -1,6 +1,6 @@ -require 'test_helper' -require 'stubs/test_server' -require 'stubs/user' +require "test_helper" +require "stubs/test_server" +require "stubs/user" class ActionCable::Connection::IdentifierTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -23,9 +23,9 @@ class ActionCable::Connection::IdentifierTest < ActionCable::TestCase test "should subscribe to internal channel on open and unsubscribe on close" do run_in_eventmachine do - pubsub = mock('pubsub_adapter') - pubsub.expects(:subscribe).with('action_cable/User#lifo', kind_of(Proc)) - pubsub.expects(:unsubscribe).with('action_cable/User#lifo', kind_of(Proc)) + pubsub = mock("pubsub_adapter") + pubsub.expects(:subscribe).with("action_cable/User#lifo", kind_of(Proc)) + pubsub.expects(:unsubscribe).with("action_cable/User#lifo", kind_of(Proc)) server = TestServer.new server.stubs(:pubsub).returns(pubsub) @@ -40,7 +40,7 @@ class ActionCable::Connection::IdentifierTest < ActionCable::TestCase open_connection_with_stubbed_pubsub @connection.websocket.expects(:close) - @connection.process_internal_message 'type' => 'disconnect' + @connection.process_internal_message "type" => "disconnect" end end @@ -49,20 +49,20 @@ class ActionCable::Connection::IdentifierTest < ActionCable::TestCase open_connection_with_stubbed_pubsub @connection.websocket.expects(:close).never - @connection.process_internal_message 'type' => 'unknown' + @connection.process_internal_message "type" => "unknown" end end protected def open_connection_with_stubbed_pubsub server = TestServer.new - server.stubs(:adapter).returns(stub_everything('adapter')) + server.stubs(:adapter).returns(stub_everything("adapter")) open_connection server: server end def open_connection(server:) - env = Rack::MockRequest.env_for "/test", 'HTTP_HOST' => 'localhost', 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket' + env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket" @connection = Connection.new(server, env) @connection.process diff --git a/actioncable/test/connection/multiple_identifiers_test.rb b/actioncable/test/connection/multiple_identifiers_test.rb index 484e73bb30..67e68355c5 100644 --- a/actioncable/test/connection/multiple_identifiers_test.rb +++ b/actioncable/test/connection/multiple_identifiers_test.rb @@ -1,6 +1,6 @@ -require 'test_helper' -require 'stubs/test_server' -require 'stubs/user' +require "test_helper" +require "stubs/test_server" +require "stubs/user" class ActionCable::Connection::MultipleIdentifiersTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -22,13 +22,13 @@ class ActionCable::Connection::MultipleIdentifiersTest < ActionCable::TestCase protected def open_connection_with_stubbed_pubsub server = TestServer.new - server.stubs(:pubsub).returns(stub_everything('pubsub')) + server.stubs(:pubsub).returns(stub_everything("pubsub")) open_connection server: server end def open_connection(server:) - env = Rack::MockRequest.env_for "/test", 'HTTP_HOST' => 'localhost', 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket' + env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket" @connection = Connection.new(server, env) @connection.process diff --git a/actioncable/test/connection/stream_test.rb b/actioncable/test/connection/stream_test.rb index a7a61d8d6f..36e1d3c095 100644 --- a/actioncable/test/connection/stream_test.rb +++ b/actioncable/test/connection/stream_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require 'stubs/test_server' +require "test_helper" +require "stubs/test_server" class ActionCable::Connection::StreamTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -34,17 +34,15 @@ class ActionCable::Connection::StreamTest < ActionCable::TestCase [ EOFError, Errno::ECONNRESET ].each do |closed_exception| test "closes socket on #{closed_exception}" do - skip if ENV['FAYE'].present? - run_in_eventmachine do connection = open_connection # Internal hax = :( client = connection.websocket.send(:websocket) - client.instance_variable_get('@stream').instance_variable_get('@rack_hijack_io').expects(:write).raises(closed_exception, 'foo') + client.instance_variable_get("@stream").instance_variable_get("@rack_hijack_io").expects(:write).raises(closed_exception, "foo") client.expects(:client_gone) - client.write('boo') + client.write("boo") assert_equal [], connection.errors end end @@ -52,10 +50,10 @@ class ActionCable::Connection::StreamTest < ActionCable::TestCase private def open_connection - env = Rack::MockRequest.env_for '/test', - 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket', - 'HTTP_HOST' => 'localhost', 'HTTP_ORIGIN' => 'http://rubyonrails.com' - env['rack.hijack'] = -> { env['rack.hijack_io'] = StringIO.new } + env = Rack::MockRequest.env_for "/test", + "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", + "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.com" + env["rack.hijack"] = -> { env["rack.hijack_io"] = StringIO.new } Connection.new(@server, env).tap do |connection| connection.process diff --git a/actioncable/test/connection/string_identifier_test.rb b/actioncable/test/connection/string_identifier_test.rb index eca0c31060..87484765e5 100644 --- a/actioncable/test/connection/string_identifier_test.rb +++ b/actioncable/test/connection/string_identifier_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require 'stubs/test_server' +require "test_helper" +require "stubs/test_server" class ActionCable::Connection::StringIdentifierTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -24,13 +24,13 @@ class ActionCable::Connection::StringIdentifierTest < ActionCable::TestCase protected def open_connection_with_stubbed_pubsub @server = TestServer.new - @server.stubs(:pubsub).returns(stub_everything('pubsub')) + @server.stubs(:pubsub).returns(stub_everything("pubsub")) open_connection end def open_connection - env = Rack::MockRequest.env_for "/test", 'HTTP_HOST' => 'localhost', 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket' + env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket" @connection = Connection.new(@server, env) @connection.process diff --git a/actioncable/test/connection/subscriptions_test.rb b/actioncable/test/connection/subscriptions_test.rb index a5b1e5dcf3..a1c8a4613c 100644 --- a/actioncable/test/connection/subscriptions_test.rb +++ b/actioncable/test/connection/subscriptions_test.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require "test_helper" class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase class Connection < ActionCable::Connection::Base @@ -25,7 +25,7 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase setup do @server = TestServer.new - @chat_identifier = ActiveSupport::JSON.encode(id: 1, channel: 'ActionCable::Connection::SubscriptionsTest::ChatChannel') + @chat_identifier = ActiveSupport::JSON.encode(id: 1, channel: "ActionCable::Connection::SubscriptionsTest::ChatChannel") end test "subscribe command" do @@ -42,7 +42,7 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase run_in_eventmachine do setup_connection - @subscriptions.execute_command 'command' => 'subscribe' + @subscriptions.execute_command "command" => "subscribe" assert @subscriptions.identifiers.empty? end end @@ -55,7 +55,7 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase channel = subscribe_to_chat_channel channel.expects(:unsubscribe_from_channel) - @subscriptions.execute_command 'command' => 'unsubscribe', 'identifier' => @chat_identifier + @subscriptions.execute_command "command" => "unsubscribe", "identifier" => @chat_identifier assert @subscriptions.identifiers.empty? end end @@ -64,7 +64,7 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase run_in_eventmachine do setup_connection - @subscriptions.execute_command 'command' => 'unsubscribe' + @subscriptions.execute_command "command" => "unsubscribe" assert @subscriptions.identifiers.empty? end end @@ -74,8 +74,8 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase setup_connection channel = subscribe_to_chat_channel - data = { 'content' => 'Hello World!', 'action' => 'speak' } - @subscriptions.execute_command 'command' => 'message', 'identifier' => @chat_identifier, 'data' => ActiveSupport::JSON.encode(data) + data = { "content" => "Hello World!", "action" => "speak" } + @subscriptions.execute_command "command" => "message", "identifier" => @chat_identifier, "data" => ActiveSupport::JSON.encode(data) assert_equal [ data ], channel.lines end @@ -87,7 +87,7 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase channel1 = subscribe_to_chat_channel - channel2_id = ActiveSupport::JSON.encode(id: 2, channel: 'ActionCable::Connection::SubscriptionsTest::ChatChannel') + channel2_id = ActiveSupport::JSON.encode(id: 2, channel: "ActionCable::Connection::SubscriptionsTest::ChatChannel") channel2 = subscribe_to_chat_channel(channel2_id) channel1.expects(:unsubscribe_from_channel) @@ -99,14 +99,14 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase private def subscribe_to_chat_channel(identifier = @chat_identifier) - @subscriptions.execute_command 'command' => 'subscribe', 'identifier' => identifier + @subscriptions.execute_command "command" => "subscribe", "identifier" => identifier assert_equal identifier, @subscriptions.identifiers.last - @subscriptions.send :find, 'identifier' => identifier + @subscriptions.send :find, "identifier" => identifier end def setup_connection - env = Rack::MockRequest.env_for "/test", 'HTTP_HOST' => 'localhost', 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket' + env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket" @connection = Connection.new(@server, env) @subscriptions = ActionCable::Connection::Subscriptions.new(@connection) diff --git a/actioncable/test/server/base_test.rb b/actioncable/test/server/base_test.rb new file mode 100644 index 0000000000..f0a51c5a7d --- /dev/null +++ b/actioncable/test/server/base_test.rb @@ -0,0 +1,33 @@ +require "test_helper" +require "stubs/test_server" +require "active_support/core_ext/hash/indifferent_access" + +class BaseTest < ActiveSupport::TestCase + def setup + @server = ActionCable::Server::Base.new + @server.config.cable = { adapter: "async" }.with_indifferent_access + end + + class FakeConnection + def close + end + end + + test "#restart closes all open connections" do + conn = FakeConnection.new + @server.add_connection(conn) + + conn.expects(:close) + @server.restart + end + + test "#restart shuts down worker pool" do + @server.worker_pool.expects(:halt) + @server.restart + end + + test "#restart shuts down pub/sub adapter" do + @server.pubsub.expects(:shutdown) + @server.restart + end +end diff --git a/actioncable/test/server/broadcasting_test.rb b/actioncable/test/server/broadcasting_test.rb index 3b4a7eaf90..ed377b7d5d 100644 --- a/actioncable/test/server/broadcasting_test.rb +++ b/actioncable/test/server/broadcasting_test.rb @@ -1,10 +1,7 @@ require "test_helper" +require "stubs/test_server" class BroadcastingTest < ActiveSupport::TestCase - class TestServer - include ActionCable::Server::Broadcasting - end - test "fetching a broadcaster converts the broadcasting queue to a string" do broadcasting = :test_queue server = TestServer.new @@ -12,4 +9,52 @@ class BroadcastingTest < ActiveSupport::TestCase assert_equal "test_queue", broadcaster.broadcasting end + + test "broadcast generates notification" do + begin + server = TestServer.new + + events = [] + ActiveSupport::Notifications.subscribe "broadcast.action_cable" do |*args| + events << ActiveSupport::Notifications::Event.new(*args) + end + + broadcasting = "test_queue" + message = { body: "test message" } + server.broadcast(broadcasting, message) + + assert_equal 1, events.length + assert_equal "broadcast.action_cable", events[0].name + assert_equal broadcasting, events[0].payload[:broadcasting] + assert_equal message, events[0].payload[:message] + assert_equal ActiveSupport::JSON, events[0].payload[:coder] + ensure + ActiveSupport::Notifications.unsubscribe "broadcast.action_cable" + end + end + + test "broadcaster from broadcaster_for generates notification" do + begin + server = TestServer.new + + events = [] + ActiveSupport::Notifications.subscribe "broadcast.action_cable" do |*args| + events << ActiveSupport::Notifications::Event.new(*args) + end + + broadcasting = "test_queue" + message = { body: "test message" } + + broadcaster = server.broadcaster_for(broadcasting) + broadcaster.broadcast(message) + + assert_equal 1, events.length + assert_equal "broadcast.action_cable", events[0].name + assert_equal broadcasting, events[0].payload[:broadcasting] + assert_equal message, events[0].payload[:message] + assert_equal ActiveSupport::JSON, events[0].payload[:coder] + ensure + ActiveSupport::Notifications.unsubscribe "broadcast.action_cable" + end + end end diff --git a/actioncable/test/stubs/room.rb b/actioncable/test/stubs/room.rb index cd66a0b687..9e521cf3a6 100644 --- a/actioncable/test/stubs/room.rb +++ b/actioncable/test/stubs/room.rb @@ -1,7 +1,7 @@ class Room attr_reader :id, :name - def initialize(id, name='Campfire') + def initialize(id, name="Campfire") @id = id @name = name end diff --git a/actioncable/test/stubs/test_connection.rb b/actioncable/test/stubs/test_connection.rb index 885450dda6..cd2e219d88 100644 --- a/actioncable/test/stubs/test_connection.rb +++ b/actioncable/test/stubs/test_connection.rb @@ -1,4 +1,4 @@ -require 'stubs/user' +require "stubs/user" class TestConnection attr_reader :identifiers, :logger, :current_user, :server, :transmissions diff --git a/actioncable/test/stubs/test_server.rb b/actioncable/test/stubs/test_server.rb index b86f422a13..5bf2a151dc 100644 --- a/actioncable/test/stubs/test_server.rb +++ b/actioncable/test/stubs/test_server.rb @@ -1,4 +1,4 @@ -require 'ostruct' +require "ostruct" class TestServer include ActionCable::Server::Connections @@ -10,14 +10,8 @@ class TestServer @logger = ActiveSupport::TaggedLogging.new ActiveSupport::Logger.new(StringIO.new) @config = OpenStruct.new(log_tags: [], subscription_adapter: subscription_adapter) - @config.use_faye = ENV['FAYE'].present? - @config.client_socket_class = if @config.use_faye - ActionCable::Connection::FayeClientSocket - else - ActionCable::Connection::ClientSocket - end - - @mutex = Monitor.new + + @mutex = Monitor.new end def pubsub @@ -25,11 +19,9 @@ class TestServer end def event_loop - @event_loop ||= if @config.use_faye - ActionCable::Connection::FayeEventLoop.new - else - ActionCable::Connection::StreamEventLoop.new - end + @event_loop ||= ActionCable::Connection::StreamEventLoop.new.tap do |loop| + loop.instance_variable_set(:@executor, Concurrent.global_io_executor) + end end def worker_pool diff --git a/actioncable/test/subscription_adapter/async_test.rb b/actioncable/test/subscription_adapter/async_test.rb index 8f413f14c2..7bc2e55d40 100644 --- a/actioncable/test/subscription_adapter/async_test.rb +++ b/actioncable/test/subscription_adapter/async_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require_relative './common' +require "test_helper" +require_relative "./common" class AsyncAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest @@ -12,6 +12,6 @@ class AsyncAdapterTest < ActionCable::TestCase end def cable_config - { adapter: 'async' } + { adapter: "async" } end end diff --git a/actioncable/test/subscription_adapter/base_test.rb b/actioncable/test/subscription_adapter/base_test.rb index 256dce673f..212ea49d2f 100644 --- a/actioncable/test/subscription_adapter/base_test.rb +++ b/actioncable/test/subscription_adapter/base_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require 'stubs/test_server' +require "test_helper" +require "stubs/test_server" class ActionCable::SubscriptionAdapter::BaseTest < ActionCable::TestCase ## TEST THAT ERRORS ARE RETURNED FOR INHERITORS THAT DON'T OVERRIDE METHODS @@ -15,31 +15,31 @@ class ActionCable::SubscriptionAdapter::BaseTest < ActionCable::TestCase test "#broadcast returns NotImplementedError by default" do assert_raises NotImplementedError do - BrokenAdapter.new(@server).broadcast('channel', 'payload') + BrokenAdapter.new(@server).broadcast("channel", "payload") end end test "#subscribe returns NotImplementedError by default" do - callback = lambda { puts 'callback' } - success_callback = lambda { puts 'success' } + callback = lambda { puts "callback" } + success_callback = lambda { puts "success" } assert_raises NotImplementedError do - BrokenAdapter.new(@server).subscribe('channel', callback, success_callback) + BrokenAdapter.new(@server).subscribe("channel", callback, success_callback) end end test "#unsubscribe returns NotImplementedError by default" do - callback = lambda { puts 'callback' } + callback = lambda { puts "callback" } assert_raises NotImplementedError do - BrokenAdapter.new(@server).unsubscribe('channel', callback) + BrokenAdapter.new(@server).unsubscribe("channel", callback) end end # TEST METHODS THAT ARE REQUIRED OF THE ADAPTER'S BACKEND STORAGE OBJECT test "#broadcast is implemented" do - broadcast = SuccessAdapter.new(@server).broadcast('channel', 'payload') + broadcast = SuccessAdapter.new(@server).broadcast("channel", "payload") assert_respond_to(SuccessAdapter.new(@server), :broadcast) @@ -49,9 +49,9 @@ class ActionCable::SubscriptionAdapter::BaseTest < ActionCable::TestCase end test "#subscribe is implemented" do - callback = lambda { puts 'callback' } - success_callback = lambda { puts 'success' } - subscribe = SuccessAdapter.new(@server).subscribe('channel', callback, success_callback) + callback = lambda { puts "callback" } + success_callback = lambda { puts "success" } + subscribe = SuccessAdapter.new(@server).subscribe("channel", callback, success_callback) assert_respond_to(SuccessAdapter.new(@server), :subscribe) @@ -61,8 +61,8 @@ class ActionCable::SubscriptionAdapter::BaseTest < ActionCable::TestCase end test "#unsubscribe is implemented" do - callback = lambda { puts 'callback' } - unsubscribe = SuccessAdapter.new(@server).unsubscribe('channel', callback) + callback = lambda { puts "callback" } + unsubscribe = SuccessAdapter.new(@server).unsubscribe("channel", callback) assert_respond_to(SuccessAdapter.new(@server), :unsubscribe) diff --git a/actioncable/test/subscription_adapter/common.rb b/actioncable/test/subscription_adapter/common.rb index 285c690df0..3aa88c2caa 100644 --- a/actioncable/test/subscription_adapter/common.rb +++ b/actioncable/test/subscription_adapter/common.rb @@ -1,8 +1,8 @@ -require 'test_helper' -require 'concurrent' +require "test_helper" +require "concurrent" -require 'active_support/core_ext/hash/indifferent_access' -require 'pathname' +require "active_support/core_ext/hash/indifferent_access" +require "pathname" module CommonSubscriptionAdapterTest WAIT_WHEN_EXPECTING_EVENT = 3 @@ -11,7 +11,7 @@ module CommonSubscriptionAdapterTest def setup server = ActionCable::Server::Base.new server.config.cable = cable_config.with_indifferent_access - server.config.use_faye = ENV['FAYE'].present? + server.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN } adapter_klass = server.config.pubsub_adapter @@ -20,10 +20,9 @@ module CommonSubscriptionAdapterTest end def teardown - [@rx_adapter, @tx_adapter].uniq.each(&:shutdown) + [@rx_adapter, @tx_adapter].uniq.compact.each(&:shutdown) end - def subscribe_as_queue(channel, adapter = @rx_adapter) queue = Queue.new @@ -41,77 +40,76 @@ module CommonSubscriptionAdapterTest adapter.unsubscribe(channel, callback) if subscribed.set? end - def test_subscribe_and_unsubscribe - subscribe_as_queue('channel') do |queue| + subscribe_as_queue("channel") do |queue| end end def test_basic_broadcast - subscribe_as_queue('channel') do |queue| - @tx_adapter.broadcast('channel', 'hello world') + subscribe_as_queue("channel") do |queue| + @tx_adapter.broadcast("channel", "hello world") - assert_equal 'hello world', queue.pop + assert_equal "hello world", queue.pop end end def test_broadcast_after_unsubscribe keep_queue = nil - subscribe_as_queue('channel') do |queue| + subscribe_as_queue("channel") do |queue| keep_queue = queue - @tx_adapter.broadcast('channel', 'hello world') + @tx_adapter.broadcast("channel", "hello world") - assert_equal 'hello world', queue.pop + assert_equal "hello world", queue.pop end - @tx_adapter.broadcast('channel', 'hello void') + @tx_adapter.broadcast("channel", "hello void") sleep WAIT_WHEN_NOT_EXPECTING_EVENT assert_empty keep_queue end def test_multiple_broadcast - subscribe_as_queue('channel') do |queue| - @tx_adapter.broadcast('channel', 'bananas') - @tx_adapter.broadcast('channel', 'apples') + subscribe_as_queue("channel") do |queue| + @tx_adapter.broadcast("channel", "bananas") + @tx_adapter.broadcast("channel", "apples") received = [] 2.times { received << queue.pop } - assert_equal ['apples', 'bananas'], received.sort + assert_equal ["apples", "bananas"], received.sort end end def test_identical_subscriptions - subscribe_as_queue('channel') do |queue| - subscribe_as_queue('channel') do |queue_2| - @tx_adapter.broadcast('channel', 'hello') + subscribe_as_queue("channel") do |queue| + subscribe_as_queue("channel") do |queue_2| + @tx_adapter.broadcast("channel", "hello") - assert_equal 'hello', queue_2.pop + assert_equal "hello", queue_2.pop end - assert_equal 'hello', queue.pop + assert_equal "hello", queue.pop end end def test_simultaneous_subscriptions - subscribe_as_queue('channel') do |queue| - subscribe_as_queue('other channel') do |queue_2| - @tx_adapter.broadcast('channel', 'apples') - @tx_adapter.broadcast('other channel', 'oranges') + subscribe_as_queue("channel") do |queue| + subscribe_as_queue("other channel") do |queue_2| + @tx_adapter.broadcast("channel", "apples") + @tx_adapter.broadcast("other channel", "oranges") - assert_equal 'apples', queue.pop - assert_equal 'oranges', queue_2.pop + assert_equal "apples", queue.pop + assert_equal "oranges", queue_2.pop end end end def test_channel_filtered_broadcast - subscribe_as_queue('channel') do |queue| - @tx_adapter.broadcast('other channel', 'one') - @tx_adapter.broadcast('channel', 'two') + subscribe_as_queue("channel") do |queue| + @tx_adapter.broadcast("other channel", "one") + @tx_adapter.broadcast("channel", "two") - assert_equal 'two', queue.pop + assert_equal "two", queue.pop end end end diff --git a/actioncable/test/subscription_adapter/evented_redis_test.rb b/actioncable/test/subscription_adapter/evented_redis_test.rb index 6d20e6ed78..f316bc46ef 100644 --- a/actioncable/test/subscription_adapter/evented_redis_test.rb +++ b/actioncable/test/subscription_adapter/evented_redis_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require_relative './common' +require "test_helper" +require_relative "./common" class EventedRedisAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest @@ -12,10 +12,18 @@ class EventedRedisAdapterTest < ActionCable::TestCase end def teardown + super + + # Ensure EM is shut down before we re-enable warnings + EventMachine.reactor_thread.tap do |thread| + EventMachine.stop + thread.join + end + $VERBOSE = @previous_verbose end def cable_config - { adapter: 'evented_redis', url: 'redis://127.0.0.1:6379/12' } + { adapter: "evented_redis", url: "redis://127.0.0.1:6379/12" } end end diff --git a/actioncable/test/subscription_adapter/inline_test.rb b/actioncable/test/subscription_adapter/inline_test.rb index 75ea51e6b3..52bfa00aba 100644 --- a/actioncable/test/subscription_adapter/inline_test.rb +++ b/actioncable/test/subscription_adapter/inline_test.rb @@ -1,5 +1,5 @@ -require 'test_helper' -require_relative './common' +require "test_helper" +require_relative "./common" class InlineAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest @@ -12,6 +12,6 @@ class InlineAdapterTest < ActionCable::TestCase end def cable_config - { adapter: 'inline' } + { adapter: "inline" } end end diff --git a/actioncable/test/subscription_adapter/postgresql_test.rb b/actioncable/test/subscription_adapter/postgresql_test.rb index 214352a0b2..beb6efab28 100644 --- a/actioncable/test/subscription_adapter/postgresql_test.rb +++ b/actioncable/test/subscription_adapter/postgresql_test.rb @@ -1,18 +1,18 @@ -require 'test_helper' -require_relative './common' +require "test_helper" +require_relative "./common" -require 'active_record' +require "active_record" class PostgresqlAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest def setup - database_config = { 'adapter' => 'postgresql', 'database' => 'activerecord_unittest' } - ar_tests = File.expand_path('../../../activerecord/test', __dir__) + database_config = { "adapter" => "postgresql", "database" => "activerecord_unittest" } + ar_tests = File.expand_path("../../../activerecord/test", __dir__) if Dir.exist?(ar_tests) - require File.join(ar_tests, 'config') - require File.join(ar_tests, 'support/config') - local_config = ARTest.config['arunit'] + require File.join(ar_tests, "config") + require File.join(ar_tests, "support/config") + local_config = ARTest.config["arunit"] database_config.update local_config if local_config end @@ -35,6 +35,6 @@ class PostgresqlAdapterTest < ActionCable::TestCase end def cable_config - { adapter: 'postgresql' } + { adapter: "postgresql" } end end diff --git a/actioncable/test/subscription_adapter/redis_test.rb b/actioncable/test/subscription_adapter/redis_test.rb index 4f34dd86c9..2ba5636656 100644 --- a/actioncable/test/subscription_adapter/redis_test.rb +++ b/actioncable/test/subscription_adapter/redis_test.rb @@ -1,16 +1,16 @@ -require 'test_helper' -require_relative './common' +require "test_helper" +require_relative "./common" class RedisAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest def cable_config - { adapter: 'redis', driver: 'ruby', url: 'redis://127.0.0.1:6379/12' } + { adapter: "redis", driver: "ruby", url: "redis://127.0.0.1:6379/12" } end end class RedisAdapterTest::Hiredis < RedisAdapterTest def cable_config - super.merge(driver: 'hiredis') + super.merge(driver: "hiredis") end end diff --git a/actioncable/test/subscription_adapter/subscriber_map_test.rb b/actioncable/test/subscription_adapter/subscriber_map_test.rb new file mode 100644 index 0000000000..76b984c849 --- /dev/null +++ b/actioncable/test/subscription_adapter/subscriber_map_test.rb @@ -0,0 +1,17 @@ +require "test_helper" + +class SubscriberMapTest < ActionCable::TestCase + test "broadcast should not change subscribers" do + setup_subscription_map + origin = @subscription_map.instance_variable_get(:@subscribers).dup + + @subscription_map.broadcast("not_exist_channel", "") + + assert_equal origin, @subscription_map.instance_variable_get(:@subscribers) + end + + private + def setup_subscription_map + @subscription_map = ActionCable::SubscriptionAdapter::SubscriberMap.new + end +end diff --git a/actioncable/test/test_helper.rb b/actioncable/test/test_helper.rb index 0a9ee7ce77..a47032753b 100644 --- a/actioncable/test/test_helper.rb +++ b/actioncable/test/test_helper.rb @@ -1,53 +1,19 @@ -require 'action_cable' -require 'active_support/testing/autorun' +require "action_cable" +require "active_support/testing/autorun" -require 'puma' -require 'mocha/setup' -require 'rack/mock' +require "puma" +require "mocha/setup" +require "rack/mock" begin - require 'byebug' + require "byebug" rescue LoadError end # Require all the stubs and models -Dir[File.dirname(__FILE__) + '/stubs/*.rb'].each {|file| require file } +Dir[File.dirname(__FILE__) + "/stubs/*.rb"].each { |file| require file } -if ENV['FAYE'].present? - require 'faye/websocket' - class << Faye::WebSocket - remove_method :ensure_reactor_running - - # We don't want Faye to start the EM reactor in tests because it makes testing much harder. - # We want to be able to start and stop EM loop in tests to make things simpler. - def ensure_reactor_running - # no-op - end - end -end - -module EventMachineConcurrencyHelpers - def wait_for_async - EM.run_deferred_callbacks - end - - def run_in_eventmachine - failure = nil - EM.run do - begin - yield - rescue => ex - failure = ex - ensure - wait_for_async - EM.stop if EM.reactor_running? - end - end - raise failure if failure - end -end - -module ConcurrentRubyConcurrencyHelpers +class ActionCable::TestCase < ActiveSupport::TestCase def wait_for_async wait_for_executor Concurrent.global_io_executor end @@ -56,18 +22,14 @@ module ConcurrentRubyConcurrencyHelpers yield wait_for_async end -end - -class ActionCable::TestCase < ActiveSupport::TestCase - if ENV['FAYE'].present? - include EventMachineConcurrencyHelpers - else - include ConcurrentRubyConcurrencyHelpers - end def wait_for_executor(executor) + # do not wait forever, wait 2s + timeout = 2 until executor.completed_task_count == executor.scheduled_task_count sleep 0.1 + timeout -= 0.1 + raise "Executor could not complete all tasks in 2 seconds" unless timeout > 0 end end end diff --git a/actioncable/test/worker_test.rb b/actioncable/test/worker_test.rb index e2c81fe312..63dc453840 100644 --- a/actioncable/test/worker_test.rb +++ b/actioncable/test/worker_test.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require "test_helper" class WorkerTest < ActiveSupport::TestCase class Receiver diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index 416c9ee33a..6f05d236d9 100644 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -1,4 +1,4 @@ -require 'rake/testtask' +require "rake/testtask" desc "Default Task" task default: [ :test ] @@ -8,7 +8,7 @@ task :package # Run the unit tests Rake::TestTask.new { |t| t.libs << "test" - t.pattern = 'test/**/*_test.rb' + t.pattern = "test/**/*_test.rb" t.warning = true t.verbose = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) @@ -17,7 +17,7 @@ Rake::TestTask.new { |t| namespace :test do task :isolated do Dir.glob("test/**/*_test.rb").all? do |file| - sh(Gem.ruby, '-w', '-Ilib:test', file) - end or raise "Failures" + sh(Gem.ruby, "-w", "-Ilib:test", file) + end || raise("Failures") end end diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 25e3bcb2e9..e75dae6cf9 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -1,28 +1,28 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'actionmailer' + s.name = "actionmailer" s.version = version - s.summary = 'Email composition, delivery, and receiving framework (part of Rails).' - s.description = 'Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.' + s.summary = "Email composition, delivery, and receiving framework (part of Rails)." + s.description = "Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*'] - s.require_path = 'lib' - s.requirements << 'none' + s.files = Dir["CHANGELOG.md", "README.rdoc", "MIT-LICENSE", "lib/**/*"] + s.require_path = "lib" + s.requirements << "none" - s.add_dependency 'actionpack', version - s.add_dependency 'actionview', version - s.add_dependency 'activejob', version + s.add_dependency "actionpack", version + s.add_dependency "actionview", version + s.add_dependency "activejob", version - s.add_dependency 'mail', ['~> 2.5', '>= 2.5.4'] - s.add_dependency 'rails-dom-testing', '~> 2.0' + s.add_dependency "mail", ["~> 2.5", ">= 2.5.4"] + s.add_dependency "rails-dom-testing", "~> 2.0" end diff --git a/actionmailer/bin/test b/actionmailer/bin/test index 404cabba51..84a05bba08 100755 --- a/actionmailer/bin/test +++ b/actionmailer/bin/test @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -COMPONENT_ROOT = File.expand_path("../../", __FILE__) + +COMPONENT_ROOT = File.expand_path("..", __dir__) require File.expand_path("../tools/test", COMPONENT_ROOT) + exit Minitest.run(ARGV) diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index 55c017e338..668bc99435 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -21,15 +21,15 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'abstract_controller' -require 'action_mailer/version' +require "abstract_controller" +require "action_mailer/version" # Common Active Support usage in Action Mailer -require 'active_support/rails' -require 'active_support/core_ext/class' -require 'active_support/core_ext/module/attr_internal' -require 'active_support/core_ext/string/inflections' -require 'active_support/lazy_load_hooks' +require "active_support/rails" +require "active_support/core_ext/class" +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/string/inflections" +require "active_support/lazy_load_hooks" module ActionMailer extend ::ActiveSupport::Autoload @@ -43,14 +43,14 @@ module ActionMailer autoload :InlinePreviewInterceptor autoload :MailHelper autoload :Preview - autoload :Previews, 'action_mailer/preview' + autoload :Previews, "action_mailer/preview" autoload :TestCase autoload :TestHelper autoload :MessageDelivery autoload :DeliveryJob end -autoload :Mime, 'action_dispatch/http/mime_type' +autoload :Mime, "action_dispatch/http/mime_type" ActiveSupport.on_load(:action_view) do ActionView::Base.default_formats ||= Mime::SET.symbols diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index e766221008..e9966c7ff5 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,11 +1,11 @@ -require 'mail' -require 'action_mailer/collector' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/module/anonymous' +require "mail" +require "action_mailer/collector" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/module/anonymous" -require 'action_mailer/log_subscriber' -require 'action_mailer/rescuable' +require "action_mailer/log_subscriber" +require "action_mailer/rescuable" module ActionMailer # Action Mailer allows you to send email from your application using a mailer model and views. @@ -396,7 +396,7 @@ module ActionMailer # # * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method. # * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>. - # * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i -t</tt> with <tt>-f sender@address</tt> + # * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i</tt> with <tt>-f sender@address</tt> # added automatically before the message is sent. # # * <tt>file_settings</tt> - Allows you to override options for the <tt>:file</tt> delivery method. @@ -598,7 +598,7 @@ module ActionMailer end class NullMail #:nodoc: - def body; '' end + def body; "" end def header; {} end def respond_to?(string, include_all=false) @@ -832,136 +832,136 @@ module ActionMailer protected - # Used by #mail to set the content type of the message. - # - # It will use the given +user_content_type+, or multipart if the mail - # message has any attachments. If the attachments are inline, the content - # type will be "multipart/related", otherwise "multipart/mixed". - # - # If there is no content type passed in via headers, and there are no - # attachments, or the message is multipart, then the default content type is - # used. - def set_content_type(m, user_content_type, class_default) - params = m.content_type_parameters || {} - case - when user_content_type.present? - user_content_type - when m.has_attachments? - if m.attachments.detect(&:inline?) - ["multipart", "related", params] + # Used by #mail to set the content type of the message. + # + # It will use the given +user_content_type+, or multipart if the mail + # message has any attachments. If the attachments are inline, the content + # type will be "multipart/related", otherwise "multipart/mixed". + # + # If there is no content type passed in via headers, and there are no + # attachments, or the message is multipart, then the default content type is + # used. + def set_content_type(m, user_content_type, class_default) + params = m.content_type_parameters || {} + case + when user_content_type.present? + user_content_type + when m.has_attachments? + if m.attachments.detect(&:inline?) + ["multipart", "related", params] + else + ["multipart", "mixed", params] + end + when m.multipart? + ["multipart", "alternative", params] else - ["multipart", "mixed", params] + m.content_type || class_default end - when m.multipart? - ["multipart", "alternative", params] - else - m.content_type || class_default end - end - # Translates the +subject+ using Rails I18n class under <tt>[mailer_scope, action_name]</tt> scope. - # If it does not find a translation for the +subject+ under the specified scope it will default to a - # humanized version of the <tt>action_name</tt>. - # If the subject has interpolations, you can pass them through the +interpolations+ parameter. - def default_i18n_subject(interpolations = {}) - mailer_scope = self.class.mailer_name.tr('/', '.') - I18n.t(:subject, interpolations.merge(scope: [mailer_scope, action_name], default: action_name.humanize)) - end + # Translates the +subject+ using Rails I18n class under <tt>[mailer_scope, action_name]</tt> scope. + # If it does not find a translation for the +subject+ under the specified scope it will default to a + # humanized version of the <tt>action_name</tt>. + # If the subject has interpolations, you can pass them through the +interpolations+ parameter. + def default_i18n_subject(interpolations = {}) + mailer_scope = self.class.mailer_name.tr("/", ".") + I18n.t(:subject, interpolations.merge(scope: [mailer_scope, action_name], default: action_name.humanize)) + end - # Emails do not support relative path links. - def self.supports_path? - false - end + # Emails do not support relative path links. + def self.supports_path? + false + end private - def apply_defaults(headers) - default_values = self.class.default.map do |key, value| - [ - key, - value.is_a?(Proc) ? instance_eval(&value) : value - ] - end.to_h - - headers_with_defaults = headers.reverse_merge(default_values) - headers_with_defaults[:subject] ||= default_i18n_subject - headers_with_defaults - end + def apply_defaults(headers) + default_values = self.class.default.map do |key, value| + [ + key, + value.is_a?(Proc) ? instance_eval(&value) : value + ] + end.to_h + + headers_with_defaults = headers.reverse_merge(default_values) + headers_with_defaults[:subject] ||= default_i18n_subject + headers_with_defaults + end - def assign_headers_to_message(message, headers) - assignable = headers.except(:parts_order, :content_type, :body, :template_name, - :template_path, :delivery_method, :delivery_method_options) - assignable.each { |k, v| message[k] = v } - end + def assign_headers_to_message(message, headers) + assignable = headers.except(:parts_order, :content_type, :body, :template_name, + :template_path, :delivery_method, :delivery_method_options) + assignable.each { |k, v| message[k] = v } + end - def collect_responses(headers) - if block_given? - collector = ActionMailer::Collector.new(lookup_context) { render(action_name) } - yield(collector) - collector.responses - elsif headers[:body] - [{ - body: headers.delete(:body), - content_type: self.class.default[:content_type] || "text/plain" - }] - else - collect_responses_from_templates(headers) + def collect_responses(headers) + if block_given? + collector = ActionMailer::Collector.new(lookup_context) { render(action_name) } + yield(collector) + collector.responses + elsif headers[:body] + [{ + body: headers.delete(:body), + content_type: self.class.default[:content_type] || "text/plain" + }] + else + collect_responses_from_templates(headers) + end end - end - def collect_responses_from_templates(headers) - templates_path = headers[:template_path] || self.class.mailer_name - templates_name = headers[:template_name] || action_name + def collect_responses_from_templates(headers) + templates_path = headers[:template_path] || self.class.mailer_name + templates_name = headers[:template_name] || action_name - each_template(Array(templates_path), templates_name).map do |template| - self.formats = template.formats - { - body: render(template: template), - content_type: template.type.to_s - } + each_template(Array(templates_path), templates_name).map do |template| + self.formats = template.formats + { + body: render(template: template), + content_type: template.type.to_s + } + end end - end - def each_template(paths, name, &block) - templates = lookup_context.find_all(name, paths) - if templates.empty? - raise ActionView::MissingTemplate.new(paths, name, paths, false, 'mailer') - else - templates.uniq(&:formats).each(&block) + def each_template(paths, name, &block) + templates = lookup_context.find_all(name, paths) + if templates.empty? + raise ActionView::MissingTemplate.new(paths, name, paths, false, "mailer") + else + templates.uniq(&:formats).each(&block) + end end - end - def create_parts_from_responses(m, responses) - if responses.size == 1 && !m.has_attachments? - responses[0].each { |k,v| m[k] = v } - elsif responses.size > 1 && m.has_attachments? - container = Mail::Part.new - container.content_type = "multipart/alternative" - responses.each { |r| insert_part(container, r, m.charset) } - m.add_part(container) - else - responses.each { |r| insert_part(m, r, m.charset) } + def create_parts_from_responses(m, responses) + if responses.size == 1 && !m.has_attachments? + responses[0].each { |k,v| m[k] = v } + elsif responses.size > 1 && m.has_attachments? + container = Mail::Part.new + container.content_type = "multipart/alternative" + responses.each { |r| insert_part(container, r, m.charset) } + m.add_part(container) + else + responses.each { |r| insert_part(m, r, m.charset) } + end end - end - def insert_part(container, response, charset) - response[:charset] ||= charset - part = Mail::Part.new(response) - container.add_part(part) - end + def insert_part(container, response, charset) + response[:charset] ||= charset + part = Mail::Part.new(response) + container.add_part(part) + end - # This and #instrument_name is for caching instrument - def instrument_payload(key) - { - mailer: mailer_name, - key: key - } - end + # This and #instrument_name is for caching instrument + def instrument_payload(key) + { + mailer: mailer_name, + key: key + } + end - def instrument_name - "action_mailer" - end + def instrument_name + "action_mailer" + end - ActiveSupport.run_load_hooks(:action_mailer, self) + ActiveSupport.run_load_hooks(:action_mailer, self) end end diff --git a/actionmailer/lib/action_mailer/collector.rb b/actionmailer/lib/action_mailer/collector.rb index e8883a8235..d97a73d65a 100644 --- a/actionmailer/lib/action_mailer/collector.rb +++ b/actionmailer/lib/action_mailer/collector.rb @@ -1,6 +1,6 @@ -require 'abstract_controller/collector' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/array/extract_options' +require "abstract_controller/collector" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/array/extract_options" module ActionMailer class Collector diff --git a/actionmailer/lib/action_mailer/delivery_job.rb b/actionmailer/lib/action_mailer/delivery_job.rb index d371c1b61a..a617daa87e 100644 --- a/actionmailer/lib/action_mailer/delivery_job.rb +++ b/actionmailer/lib/action_mailer/delivery_job.rb @@ -1,4 +1,4 @@ -require 'active_job' +require "active_job" module ActionMailer # The <tt>ActionMailer::DeliveryJob</tt> class is used when you diff --git a/actionmailer/lib/action_mailer/delivery_methods.rb b/actionmailer/lib/action_mailer/delivery_methods.rb index 571c8e7d2a..6be2c91da6 100644 --- a/actionmailer/lib/action_mailer/delivery_methods.rb +++ b/actionmailer/lib/action_mailer/delivery_methods.rb @@ -1,4 +1,4 @@ -require 'tmpdir' +require "tmpdir" module ActionMailer # This module handles everything related to mail delivery, from registering @@ -25,7 +25,7 @@ module ActionMailer add_delivery_method :smtp, Mail::SMTP, address: "localhost", port: 25, - domain: 'localhost.localdomain', + domain: "localhost.localdomain", user_name: nil, password: nil, authentication: nil, @@ -35,8 +35,8 @@ module ActionMailer location: defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails" add_delivery_method :sendmail, Mail::Sendmail, - location: '/usr/sbin/sendmail', - arguments: '-i' + location: "/usr/sbin/sendmail", + arguments: "-i" add_delivery_method :test, Mail::TestMailer end @@ -51,7 +51,7 @@ module ActionMailer # # add_delivery_method :sendmail, Mail::Sendmail, # location: '/usr/sbin/sendmail', - # arguments: '-i -t' + # arguments: '-i' def add_delivery_method(symbol, klass, default_options={}) class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings") send(:"#{symbol}_settings=", default_options) diff --git a/actionmailer/lib/action_mailer/inline_preview_interceptor.rb b/actionmailer/lib/action_mailer/inline_preview_interceptor.rb index 419d6c7b93..b7318f0092 100644 --- a/actionmailer/lib/action_mailer/inline_preview_interceptor.rb +++ b/actionmailer/lib/action_mailer/inline_preview_interceptor.rb @@ -1,4 +1,4 @@ -require 'base64' +require "base64" module ActionMailer # Implements a mailer preview interceptor that converts image tag src attributes @@ -55,7 +55,7 @@ module ActionMailer end def find_part(cid) - message.all_parts.find{ |p| p.attachment? && p.cid == cid } + message.all_parts.find { |p| p.attachment? && p.cid == cid } end end end diff --git a/actionmailer/lib/action_mailer/log_subscriber.rb b/actionmailer/lib/action_mailer/log_subscriber.rb index 2867bf90fb..2c058ccf66 100644 --- a/actionmailer/lib/action_mailer/log_subscriber.rb +++ b/actionmailer/lib/action_mailer/log_subscriber.rb @@ -1,4 +1,4 @@ -require 'active_support/log_subscriber' +require "active_support/log_subscriber" module ActionMailer # Implements the ActiveSupport::LogSubscriber for logging notifications when @@ -7,7 +7,7 @@ module ActionMailer # An email was delivered. def deliver(event) info do - recipients = Array(event.payload[:to]).join(', ') + recipients = Array(event.payload[:to]).join(", ") "Sent mail to #{recipients} (#{event.duration.round(1)}ms)" end diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb index 239974e7b1..e04fc08866 100644 --- a/actionmailer/lib/action_mailer/mail_helper.rb +++ b/actionmailer/lib/action_mailer/mail_helper.rb @@ -54,7 +54,7 @@ module ActionMailer sentences = [[]] text.split.each do |word| - if sentences.first.present? && (sentences.last + [word]).join(' ').length > len + if sentences.first.present? && (sentences.last + [word]).join(" ").length > len sentences << [word] else sentences.last << word diff --git a/actionmailer/lib/action_mailer/message_delivery.rb b/actionmailer/lib/action_mailer/message_delivery.rb index c5ba5f9f1d..994d297768 100644 --- a/actionmailer/lib/action_mailer/message_delivery.rb +++ b/actionmailer/lib/action_mailer/message_delivery.rb @@ -1,4 +1,4 @@ -require 'delegate' +require "delegate" module ActionMailer # The <tt>ActionMailer::MessageDelivery</tt> class is used by diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb index aab92fe8db..93a11453bf 100644 --- a/actionmailer/lib/action_mailer/preview.rb +++ b/actionmailer/lib/action_mailer/preview.rb @@ -1,4 +1,4 @@ -require 'active_support/descendants_tracker' +require "active_support/descendants_tracker" module ActionMailer module Previews #:nodoc: @@ -34,7 +34,8 @@ module ActionMailer # Either a class or a string can be passed in as the Interceptor. If a # string is passed in it will be <tt>constantize</tt>d. def register_preview_interceptor(interceptor) - preview_interceptor = case interceptor + preview_interceptor = \ + case interceptor when String, Symbol interceptor.to_s.camelize.constantize else @@ -80,23 +81,23 @@ module ActionMailer # Returns true if the preview exists. def exists?(preview) - all.any?{ |p| p.preview_name == preview } + all.any? { |p| p.preview_name == preview } end # Find a mailer preview by its underscored class name. def find(preview) - all.find{ |p| p.preview_name == preview } + all.find { |p| p.preview_name == preview } end # Returns the underscored name of the mailer preview without the suffix. def preview_name - name.sub(/Preview$/, '').underscore + name.sub(/Preview$/, "").underscore end protected def load_previews #:nodoc: if preview_path - Dir["#{preview_path}/**/*_preview.rb"].each{ |file| require_dependency file } + Dir["#{preview_path}/**/*_preview.rb"].each { |file| require_dependency file } end end diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index a727ed38e9..c47d7781cc 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -1,4 +1,4 @@ -require 'active_job/railtie' +require "active_job/railtie" require "action_mailer" require "rails" require "abstract_controller/railties/routes_helpers" @@ -18,7 +18,7 @@ module ActionMailer if app.config.force_ssl options.default_url_options ||= {} - options.default_url_options[:protocol] ||= 'https' + options.default_url_options[:protocol] ||= "https" end options.assets_dir ||= paths["public"].first @@ -61,8 +61,8 @@ module ActionMailer if options.show_previews app.routes.prepend do - get '/rails/mailers' => "rails/mailers#index", internal: true - get '/rails/mailers/*path' => "rails/mailers#preview", internal: true + get "/rails/mailers" => "rails/mailers#index", internal: true + get "/rails/mailers/*path" => "rails/mailers#preview", internal: true end if options.preview_path diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb index b045e883ad..1d09a4ee96 100644 --- a/actionmailer/lib/action_mailer/test_case.rb +++ b/actionmailer/lib/action_mailer/test_case.rb @@ -1,5 +1,5 @@ -require 'active_support/test_case' -require 'rails-dom-testing' +require "active_support/test_case" +require "rails-dom-testing" module ActionMailer class NonInferrableMailerError < ::StandardError @@ -21,11 +21,11 @@ module ActionMailer private - def clear_test_deliveries - if ActionMailer::Base.delivery_method == :test - ActionMailer::Base.deliveries.clear + def clear_test_deliveries + if ActionMailer::Base.delivery_method == :test + ActionMailer::Base.deliveries.clear + end end - end end module Behavior @@ -41,6 +41,7 @@ module ActionMailer setup :initialize_test_deliveries setup :set_expected_mail teardown :restore_test_deliveries + ActiveSupport.run_load_hooks(:action_mailer_test_case, self) end module ClassMethods @@ -99,7 +100,7 @@ module ActionMailer def set_expected_mail # :nodoc: @expected = Mail.new @expected.content_type ["text", "plain", { "charset" => charset }] - @expected.mime_version = '1.0' + @expected.mime_version = "1.0" end private @@ -113,7 +114,7 @@ module ActionMailer end def read_fixture(action) - IO.readlines(File.join(Rails.root, 'test', 'fixtures', self.class.mailer_class.name.underscore, action)) + IO.readlines(File.join(Rails.root, "test", "fixtures", self.class.mailer_class.name.underscore, action)) end end diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb index e423aac389..c17ecad4c6 100644 --- a/actionmailer/lib/action_mailer/test_helper.rb +++ b/actionmailer/lib/action_mailer/test_helper.rb @@ -1,4 +1,4 @@ -require 'active_job' +require "active_job" module ActionMailer # Provides helper methods for testing Action Mailer, including #assert_emails diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb index 06f80a8fdc..8452d6370e 100644 --- a/actionmailer/lib/action_mailer/version.rb +++ b/actionmailer/lib/action_mailer/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActionMailer # Returns the version of the currently loaded Action Mailer as a diff --git a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb index 01bdfb0685..9dd7ee7a27 100644 --- a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb +++ b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb @@ -8,11 +8,11 @@ module Rails check_class_collision suffix: "Mailer" def create_mailer_file - template "mailer.rb", File.join('app/mailers', class_path, "#{file_name}_mailer.rb") + template "mailer.rb", File.join("app/mailers", class_path, "#{file_name}_mailer.rb") in_root do if self.behavior == :invoke && !File.exist?(application_mailer_file_name) - template 'application_mailer.rb', application_mailer_file_name + template "application_mailer.rb", application_mailer_file_name end end end @@ -21,16 +21,16 @@ module Rails protected def file_name - @_file_name ||= super.gsub(/_mailer/i, '') + @_file_name ||= super.gsub(/_mailer/i, "") end private def application_mailer_file_name @_application_mailer_file_name ||= if mountable_engine? - "app/mailers/#{namespaced_path}/application_mailer.rb" - else - "app/mailers/application_mailer.rb" - end + "app/mailers/#{namespaced_path}/application_mailer.rb" + else + "app/mailers/application_mailer.rb" + end end end end diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index 8d740ac863..82f03f5cba 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/kernel/reporting' +require "active_support/core_ext/kernel/reporting" # These are the normal settings that will be set up by Railties # TODO: Have these tests support other combinations of these values @@ -9,17 +9,17 @@ end module Rails def self.root - File.expand_path('../', File.dirname(__FILE__)) + File.expand_path("../", File.dirname(__FILE__)) end end -require 'active_support/testing/autorun' -require 'active_support/testing/method_call_assertions' -require 'action_mailer' -require 'action_mailer/test_case' +require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" +require "action_mailer" +require "action_mailer/test_case" # Emulate AV railtie -require 'action_view' +require "action_view" ActionMailer::Base.include(ActionView::Layouts) # Show backtraces for deprecated behavior for quicker cleanup. @@ -28,15 +28,15 @@ ActiveSupport::Deprecation.debug = true # Disable available locale checks to avoid warnings running the test suite. I18n.enforce_available_locales = false -FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__)) +FIXTURE_LOAD_PATH = File.expand_path("fixtures", File.dirname(__FILE__)) ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH # Skips the current run on Rubinius using Minitest::Assertions#skip -def rubinius_skip(message = '') - skip message if RUBY_ENGINE == 'rbx' +def rubinius_skip(message = "") + skip message if RUBY_ENGINE == "rbx" end # Skips the current run on JRuby using Minitest::Assertions#skip -def jruby_skip(message = '') +def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end diff --git a/actionmailer/test/assert_select_email_test.rb b/actionmailer/test/assert_select_email_test.rb index cae2e20abd..bf14fe0853 100644 --- a/actionmailer/test/assert_select_email_test.rb +++ b/actionmailer/test/assert_select_email_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class AssertSelectEmailTest < ActionMailer::TestCase class AssertSelectMailer < ActionMailer::Base @@ -11,8 +11,8 @@ class AssertSelectEmailTest < ActionMailer::TestCase class AssertMultipartSelectMailer < ActionMailer::Base def test(options) mail subject: "Test e-mail", from: "test@test.host", to: "test <test@test.host>" do |format| - format.text { render text: options[:text] } - format.html { render text: options[:html] } + format.text { render plain: options[:text] } + format.html { render plain: options[:html] } end end end @@ -36,7 +36,7 @@ class AssertSelectEmailTest < ActionMailer::TestCase end def test_assert_select_email_multipart - AssertMultipartSelectMailer.test(html: "<div><p>foo</p><p>bar</p></div>", text: 'foo bar').deliver_now + AssertMultipartSelectMailer.test(html: "<div><p>foo</p><p>bar</p></div>", text: "foo bar").deliver_now assert_select_email do assert_select "div:root" do assert_select "p:first-child", "foo" diff --git a/actionmailer/test/asset_host_test.rb b/actionmailer/test/asset_host_test.rb index 10cfdcf693..812df01a34 100644 --- a/actionmailer/test/asset_host_test.rb +++ b/actionmailer/test/asset_host_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' -require 'action_controller' +require "abstract_unit" +require "action_controller" class AssetHostMailer < ActionMailer::Base def email_with_asset - mail to: 'test@localhost', - subject: 'testing email containing asset path while asset_host is set', - from: 'tester@example.com' + mail to: "test@localhost", + subject: "testing email containing asset path while asset_host is set", + from: "tester@example.com" end end @@ -22,16 +22,16 @@ class AssetHostTest < ActionMailer::TestCase def test_asset_host_as_string mail = AssetHostMailer.email_with_asset - assert_dom_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip + assert_dom_equal '<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />', mail.body.to_s.strip end def test_asset_host_as_one_argument_proc AssetHostMailer.config.asset_host = Proc.new { |source| - if source.starts_with?('/images') - 'http://images.example.com' + if source.starts_with?("/images") + "http://images.example.com" end } mail = AssetHostMailer.email_with_asset - assert_dom_equal %Q{<img alt="Somelogo" src="http://images.example.com/images/somelogo.png" />}, mail.body.to_s.strip + assert_dom_equal '<img alt="Somelogo" src="http://images.example.com/images/somelogo.png" />', mail.body.to_s.strip end end diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 50f2c71737..3bca69890d 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' -require 'set' +require "abstract_unit" +require "set" -require 'action_dispatch' -require 'active_support/time' +require "action_dispatch" +require "active_support/time" -require 'mailers/base_mailer' -require 'mailers/proc_mailer' -require 'mailers/asset_mailer' +require "mailers/base_mailer" +require "mailers/proc_mailer" +require "mailers/asset_mailer" class BaseTest < ActiveSupport::TestCase include Rails::Dom::Testing::Assertions::DomAssertions @@ -32,33 +32,33 @@ class BaseTest < ActiveSupport::TestCase # Basic mail usage without block test "mail() should set the headers of the mail message" do email = BaseMailer.welcome - assert_equal(['system@test.lindsaar.net'], email.to) - assert_equal(['jose@test.plataformatec.com'], email.from) - assert_equal('The first email on new API!', email.subject) + assert_equal(["system@test.lindsaar.net"], email.to) + assert_equal(["jose@test.plataformatec.com"], email.from) + assert_equal("The first email on new API!", email.subject) end test "mail() with from overwrites the class level default" do - email = BaseMailer.welcome(from: 'someone@example.com', - to: 'another@example.org') - assert_equal(['someone@example.com'], email.from) - assert_equal(['another@example.org'], email.to) + email = BaseMailer.welcome(from: "someone@example.com", + to: "another@example.org") + assert_equal(["someone@example.com"], email.from) + assert_equal(["another@example.org"], email.to) end test "mail() with bcc, cc, content_type, charset, mime_version, reply_to and date" do time = Time.now.beginning_of_day.to_datetime - email = BaseMailer.welcome(bcc: 'bcc@test.lindsaar.net', - cc: 'cc@test.lindsaar.net', - content_type: 'multipart/mixed', - charset: 'iso-8559-1', - mime_version: '2.0', - reply_to: 'reply-to@test.lindsaar.net', + email = BaseMailer.welcome(bcc: "bcc@test.lindsaar.net", + cc: "cc@test.lindsaar.net", + content_type: "multipart/mixed", + charset: "iso-8559-1", + mime_version: "2.0", + reply_to: "reply-to@test.lindsaar.net", date: time) - assert_equal(['bcc@test.lindsaar.net'], email.bcc) - assert_equal(['cc@test.lindsaar.net'], email.cc) - assert_equal('multipart/mixed; charset=iso-8559-1', email.content_type) - assert_equal('iso-8559-1', email.charset) - assert_equal('2.0', email.mime_version) - assert_equal(['reply-to@test.lindsaar.net'], email.reply_to) + assert_equal(["bcc@test.lindsaar.net"], email.bcc) + assert_equal(["cc@test.lindsaar.net"], email.cc) + assert_equal("multipart/mixed; charset=iso-8559-1", email.content_type) + assert_equal("iso-8559-1", email.charset) + assert_equal("2.0", email.mime_version) + assert_equal(["reply-to@test.lindsaar.net"], email.reply_to) assert_equal(time, email.date) end @@ -75,63 +75,63 @@ class BaseTest < ActiveSupport::TestCase test "should set template content type if mail has only one part" do mail = BaseMailer.html_only - assert_equal('text/html', mail.mime_type) + assert_equal("text/html", mail.mime_type) mail = BaseMailer.plain_text_only - assert_equal('text/plain', mail.mime_type) + assert_equal("text/plain", mail.mime_type) end # Custom headers test "custom headers" do email = BaseMailer.welcome - assert_equal("Not SPAM", email['X-SPAM'].decoded) + assert_equal("Not SPAM", email["X-SPAM"].decoded) end test "can pass random headers in as a hash to mail" do - hash = {'X-Special-Domain-Specific-Header' => "SecretValue", - 'In-Reply-To' => '1234@mikel.me.com' } + hash = { "X-Special-Domain-Specific-Header" => "SecretValue", + "In-Reply-To" => "1234@mikel.me.com" } mail = BaseMailer.welcome(hash) - assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded) - assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded) + assert_equal("SecretValue", mail["X-Special-Domain-Specific-Header"].decoded) + assert_equal("1234@mikel.me.com", mail["In-Reply-To"].decoded) end test "can pass random headers in as a hash to headers" do - hash = {'X-Special-Domain-Specific-Header' => "SecretValue", - 'In-Reply-To' => '1234@mikel.me.com' } + hash = { "X-Special-Domain-Specific-Header" => "SecretValue", + "In-Reply-To" => "1234@mikel.me.com" } mail = BaseMailer.welcome_with_headers(hash) - assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded) - assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded) + assert_equal("SecretValue", mail["X-Special-Domain-Specific-Header"].decoded) + assert_equal("1234@mikel.me.com", mail["In-Reply-To"].decoded) end # Attachments test "attachment with content" do email = BaseMailer.attachment_with_content assert_equal(1, email.attachments.length) - assert_equal('invoice.pdf', email.attachments[0].filename) - assert_equal('This is test File content', email.attachments['invoice.pdf'].decoded) + assert_equal("invoice.pdf", email.attachments[0].filename) + assert_equal("This is test File content", email.attachments["invoice.pdf"].decoded) end test "attachment gets content type from filename" do email = BaseMailer.attachment_with_content - assert_equal('invoice.pdf', email.attachments[0].filename) - assert_equal('application/pdf', email.attachments[0].mime_type) + assert_equal("invoice.pdf", email.attachments[0].filename) + assert_equal("application/pdf", email.attachments[0].mime_type) end test "attachment with hash" do email = BaseMailer.attachment_with_hash assert_equal(1, email.attachments.length) - assert_equal('invoice.jpg', email.attachments[0].filename) + assert_equal("invoice.jpg", email.attachments[0].filename) expected = "\312\213\254\232)b" expected.force_encoding(Encoding::BINARY) - assert_equal expected, email.attachments['invoice.jpg'].decoded + assert_equal expected, email.attachments["invoice.jpg"].decoded end test "attachment with hash using default mail encoding" do email = BaseMailer.attachment_with_hash_default_encoding assert_equal(1, email.attachments.length) - assert_equal('invoice.jpg', email.attachments[0].filename) + assert_equal("invoice.jpg", email.attachments[0].filename) expected = "\312\213\254\232)b" expected.force_encoding(Encoding::BINARY) - assert_equal expected, email.attachments['invoice.jpg'].decoded + assert_equal expected, email.attachments["invoice.jpg"].decoded end test "sets mime type to multipart/mixed when attachment is included" do @@ -215,24 +215,24 @@ class BaseTest < ActiveSupport::TestCase email = BaseMailer.welcome(subject: nil) assert_equal "Welcome", email.subject - with_translation 'en', base_mailer: {welcome: {subject: "New Subject!"}} do + with_translation "en", base_mailer: { welcome: { subject: "New Subject!" } } do email = BaseMailer.welcome(subject: nil) assert_equal "New Subject!", email.subject end end end - test 'default subject can have interpolations' do - with_translation 'en', base_mailer: {with_subject_interpolations: {subject: 'Will the real %{rapper_or_impersonator} please stand up?'}} do + test "default subject can have interpolations" do + with_translation "en", base_mailer: { with_subject_interpolations: { subject: "Will the real %{rapper_or_impersonator} please stand up?" } } do email = BaseMailer.with_subject_interpolations - assert_equal 'Will the real Slim Shady please stand up?', email.subject + assert_equal "Will the real Slim Shady please stand up?", email.subject end end test "translations are scoped properly" do - with_translation 'en', base_mailer: {email_with_translations: {greet_user: "Hello %{name}!"}} do + with_translation "en", base_mailer: { email_with_translations: { greet_user: "Hello %{name}!" } } do email = BaseMailer.email_with_translations - assert_equal 'Hello lifo!', email.body.encoded + assert_equal "Hello lifo!", email.body.encoded end end @@ -240,7 +240,7 @@ class BaseTest < ActiveSupport::TestCase class LateAttachmentMailer < ActionMailer::Base def welcome mail body: "yay", from: "welcome@example.com", to: "to@example.com" - attachments['invoice.pdf'] = 'This is test File content' + attachments["invoice.pdf"] = "This is test File content" end end @@ -252,7 +252,7 @@ class BaseTest < ActiveSupport::TestCase class LateInlineAttachmentMailer < ActionMailer::Base def welcome mail body: "yay", from: "welcome@example.com", to: "to@example.com" - attachments.inline['invoice.pdf'] = 'This is test File content' + attachments.inline["invoice.pdf"] = "This is test File content" end end @@ -271,13 +271,13 @@ class BaseTest < ActiveSupport::TestCase assert_nothing_raised { mail.message } assert_equal ["image/jpeg; filename=controller_attachments.jpg", - "image/jpeg; filename=attachments.jpg"], mail.attachments.inline.map {|a| a['Content-Type'].to_s } + "image/jpeg; filename=attachments.jpg"], mail.attachments.inline.map { |a| a["Content-Type"].to_s } end test "accessing attachments works after mail was called" do class LateAttachmentAccessorMailer < ActionMailer::Base def welcome - attachments['invoice.pdf'] = 'This is test File content' + attachments["invoice.pdf"] = "This is test File content" mail body: "yay", from: "welcome@example.com", to: "to@example.com" unless attachments.map(&:filename) == ["invoice.pdf"] @@ -366,7 +366,7 @@ class BaseTest < ActiveSupport::TestCase I18n.backend = fallback_backend.new I18n.fallbacks[:"de-AT"] = [:de] - swap I18n, locale: 'de-AT' do + swap I18n, locale: "de-AT" do email = BaseMailer.implicit_with_locale assert_equal(2, email.parts.size) assert_equal("multipart/alternative", email.mime_type) @@ -380,7 +380,6 @@ class BaseTest < ActiveSupport::TestCase end end - test "implicit multipart with several view paths uses the first one with template" do old = BaseMailer.view_paths begin @@ -449,7 +448,7 @@ class BaseTest < ActiveSupport::TestCase assert_equal("Format with any!", email.parts[1].body.encoded) end - test 'explicit without specifying format with format.any' do + test "explicit without specifying format with format.any" do error = assert_raises(ArgumentError) do BaseMailer.explicit_without_specifying_format_with_any.parts end @@ -508,13 +507,13 @@ class BaseTest < ActiveSupport::TestCase test "calling just the action should return the generated mail object" do email = BaseMailer.welcome assert_equal(0, BaseMailer.deliveries.length) - assert_equal('The first email on new API!', email.subject) + assert_equal("The first email on new API!", email.subject) end test "calling deliver on the action should deliver the mail object" do assert_called(BaseMailer, :deliver_mail) do mail = BaseMailer.welcome.deliver_now - assert_equal 'The first email on new API!', mail.subject + assert_equal "The first email on new API!", mail.subject end end @@ -534,35 +533,35 @@ class BaseTest < ActiveSupport::TestCase # Rendering test "you can specify a different template for implicit render" do - mail = BaseMailer.implicit_different_template('implicit_multipart').deliver_now + mail = BaseMailer.implicit_different_template("implicit_multipart").deliver_now assert_equal("HTML Implicit Multipart", mail.html_part.body.decoded) assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded) end test "should raise if missing template in implicit render" do assert_raises ActionView::MissingTemplate do - BaseMailer.implicit_different_template('missing_template').deliver_now + BaseMailer.implicit_different_template("missing_template").deliver_now end assert_equal(0, BaseMailer.deliveries.length) end test "you can specify a different template for explicit render" do - mail = BaseMailer.explicit_different_template('explicit_multipart_templates').deliver_now + mail = BaseMailer.explicit_different_template("explicit_multipart_templates").deliver_now assert_equal("HTML Explicit Multipart Templates", mail.html_part.body.decoded) assert_equal("TEXT Explicit Multipart Templates", mail.text_part.body.decoded) end test "you can specify a different layout" do - mail = BaseMailer.different_layout('different_layout').deliver_now + mail = BaseMailer.different_layout("different_layout").deliver_now assert_equal("HTML -- HTML", mail.html_part.body.decoded) assert_equal("PLAIN -- PLAIN", mail.text_part.body.decoded) end test "you can specify the template path for implicit lookup" do - mail = BaseMailer.welcome_from_another_path('another.path/base_mailer').deliver_now + mail = BaseMailer.welcome_from_another_path("another.path/base_mailer").deliver_now assert_equal("Welcome from another path", mail.body.encoded) - mail = BaseMailer.welcome_from_another_path(['unknown/invalid', 'another.path/base_mailer']).deliver_now + mail = BaseMailer.welcome_from_another_path(["unknown/invalid", "another.path/base_mailer"]).deliver_now assert_equal("Welcome from another path", mail.body.encoded) end @@ -589,15 +588,15 @@ class BaseTest < ActiveSupport::TestCase assert_dom_equal(%{<img alt="Dummy" src="http://local.com/images/dummy.png" />}, mail.body.to_s.strip) end - test 'the view is not rendered when mail was never called' do + test "the view is not rendered when mail was never called" do mail = BaseMailer.without_mail_call - assert_equal('', mail.body.to_s.strip) + assert_equal("", mail.body.to_s.strip) mail.deliver_now end - test 'the return value of mailer methods is not relevant' do + test "the return value of mailer methods is not relevant" do mail = BaseMailer.with_nil_as_return_value - assert_equal('Welcome', mail.body.to_s.strip) + assert_equal("Welcome", mail.body.to_s.strip) mail.deliver_now end @@ -708,16 +707,16 @@ class BaseTest < ActiveSupport::TestCase end test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do - mail1 = ProcMailer.welcome['X-Proc-Method'] + mail1 = ProcMailer.welcome["X-Proc-Method"] yesterday = 1.day.ago Time.stub(:now, yesterday) do - mail2 = ProcMailer.welcome['X-Proc-Method'] + mail2 = ProcMailer.welcome["X-Proc-Method"] assert(mail1.to_s.to_i > mail2.to_s.to_i) end end - test 'default values which have to_proc (e.g. symbols) should not be considered procs' do - assert(ProcMailer.welcome['x-has-to-proc'].to_s == 'symbol') + test "default values which have to_proc (e.g. symbols) should not be considered procs" do + assert(ProcMailer.welcome["x-has-to-proc"].to_s == "symbol") end test "we can call other defined methods on the class as needed" do @@ -732,12 +731,12 @@ class BaseTest < ActiveSupport::TestCase def welcome ; mail ; end private - def add_special_header! - headers('X-Special-Header' => 'Wow, so special') - end + def add_special_header! + headers("X-Special-Header" => "Wow, so special") + end end - assert_equal('Wow, so special', BeforeActionMailer.welcome['X-Special-Header'].to_s) + assert_equal("Wow, so special", BeforeActionMailer.welcome["X-Special-Header"].to_s) end test "modifying the mail message with an after_action" do @@ -747,12 +746,12 @@ class BaseTest < ActiveSupport::TestCase def welcome ; mail ; end private - def add_special_header! - headers('X-Special-Header' => 'Testing') - end + def add_special_header! + headers("X-Special-Header" => "Testing") + end end - assert_equal('Testing', AfterActionMailer.welcome['X-Special-Header'].to_s) + assert_equal("Testing", AfterActionMailer.welcome["X-Special-Header"].to_s) end test "adding an inline attachment using a before_action" do @@ -762,19 +761,19 @@ class BaseTest < ActiveSupport::TestCase def welcome ; mail ; end private - def add_inline_attachment! - attachments.inline["footer.jpg"] = 'hey there' - end + def add_inline_attachment! + attachments.inline["footer.jpg"] = "hey there" + end end mail = DefaultInlineAttachmentMailer.welcome - assert_equal('image/jpeg; filename=footer.jpg', mail.attachments.inline.first['Content-Type'].to_s) + assert_equal("image/jpeg; filename=footer.jpg", mail.attachments.inline.first["Content-Type"].to_s) end test "action methods should be refreshed after defining new method" do class FooMailer < ActionMailer::Base - # this triggers action_methods - self.respond_to?(:foo) + # This triggers action_methods. + respond_to?(:foo) def notify end @@ -798,8 +797,8 @@ class BaseTest < ActiveSupport::TestCase test "default_from can be set" do class DefaultFromMailer < ActionMailer::Base - default to: 'system@test.lindsaar.net' - self.default_options = {from: "robert.pankowecki@gmail.com"} + default to: "system@test.lindsaar.net" + self.default_options = { from: "robert.pankowecki@gmail.com" } def welcome mail(subject: "subject", body: "hello world") @@ -814,7 +813,7 @@ class BaseTest < ActiveSupport::TestCase after_action :a_callback def welcome - headers('X-Special-Header' => 'special indeed!') + headers("X-Special-Header" => "special indeed!") mail subject: "subject", body: "hello world", to: ["joe@example.com"] end diff --git a/actionmailer/test/caching_test.rb b/actionmailer/test/caching_test.rb index 22e1bdb5f1..cff49c8894 100644 --- a/actionmailer/test/caching_test.rb +++ b/actionmailer/test/caching_test.rb @@ -1,11 +1,11 @@ -require 'fileutils' -require 'abstract_unit' -require 'mailers/base_mailer' -require 'mailers/caching_mailer' +require "fileutils" +require "abstract_unit" +require "mailers/base_mailer" +require "mailers/caching_mailer" -CACHE_DIR = 'test_cache' +CACHE_DIR = "test_cache" # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed -FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR) +FILE_STORE_PATH = File.join(File.dirname(__FILE__), "/../temp/", CACHE_DIR) class FragmentCachingMailer < ActionMailer::Base abstract! @@ -23,89 +23,89 @@ class BaseCachingTest < ActiveSupport::TestCase end def test_fragment_cache_key - assert_equal 'views/what a key', @mailer.fragment_cache_key('what a key') + assert_equal "views/what a key", @mailer.fragment_cache_key("what a key") end end class FragmentCachingTest < BaseCachingTest def test_read_fragment_with_caching_enabled - @store.write('views/name', 'value') - assert_equal 'value', @mailer.read_fragment('name') + @store.write("views/name", "value") + assert_equal "value", @mailer.read_fragment("name") end def test_read_fragment_with_caching_disabled @mailer.perform_caching = false - @store.write('views/name', 'value') - assert_nil @mailer.read_fragment('name') + @store.write("views/name", "value") + assert_nil @mailer.read_fragment("name") end def test_fragment_exist_with_caching_enabled - @store.write('views/name', 'value') - assert @mailer.fragment_exist?('name') - assert !@mailer.fragment_exist?('other_name') + @store.write("views/name", "value") + assert @mailer.fragment_exist?("name") + assert !@mailer.fragment_exist?("other_name") end def test_fragment_exist_with_caching_disabled @mailer.perform_caching = false - @store.write('views/name', 'value') - assert !@mailer.fragment_exist?('name') - assert !@mailer.fragment_exist?('other_name') + @store.write("views/name", "value") + assert !@mailer.fragment_exist?("name") + assert !@mailer.fragment_exist?("other_name") end def test_write_fragment_with_caching_enabled - assert_nil @store.read('views/name') - assert_equal 'value', @mailer.write_fragment('name', 'value') - assert_equal 'value', @store.read('views/name') + assert_nil @store.read("views/name") + assert_equal "value", @mailer.write_fragment("name", "value") + assert_equal "value", @store.read("views/name") end def test_write_fragment_with_caching_disabled - assert_nil @store.read('views/name') + assert_nil @store.read("views/name") @mailer.perform_caching = false - assert_equal 'value', @mailer.write_fragment('name', 'value') - assert_nil @store.read('views/name') + assert_equal "value", @mailer.write_fragment("name", "value") + assert_nil @store.read("views/name") end def test_expire_fragment_with_simple_key - @store.write('views/name', 'value') - @mailer.expire_fragment 'name' - assert_nil @store.read('views/name') + @store.write("views/name", "value") + @mailer.expire_fragment "name" + assert_nil @store.read("views/name") end def test_expire_fragment_with_regexp - @store.write('views/name', 'value') - @store.write('views/another_name', 'another_value') - @store.write('views/primalgrasp', 'will not expire ;-)') + @store.write("views/name", "value") + @store.write("views/another_name", "another_value") + @store.write("views/primalgrasp", "will not expire ;-)") @mailer.expire_fragment(/name/) - assert_nil @store.read('views/name') - assert_nil @store.read('views/another_name') - assert_equal 'will not expire ;-)', @store.read('views/primalgrasp') + assert_nil @store.read("views/name") + assert_nil @store.read("views/another_name") + assert_equal "will not expire ;-)", @store.read("views/primalgrasp") end def test_fragment_for - @store.write('views/expensive', 'fragment content') + @store.write("views/expensive", "fragment content") fragment_computed = false view_context = @mailer.view_context - buffer = 'generated till now -> '.html_safe - buffer << view_context.send(:fragment_for, 'expensive') { fragment_computed = true } + buffer = "generated till now -> ".html_safe + buffer << view_context.send(:fragment_for, "expensive") { fragment_computed = true } assert !fragment_computed - assert_equal 'generated till now -> fragment content', buffer + assert_equal "generated till now -> fragment content", buffer end def test_html_safety - assert_nil @store.read('views/name') - content = 'value'.html_safe - assert_equal content, @mailer.write_fragment('name', content) + assert_nil @store.read("views/name") + content = "value".html_safe + assert_equal content, @mailer.write_fragment("name", content) - cached = @store.read('views/name') + cached = @store.read("views/name") assert_equal content, cached assert_equal String, cached.class - html_safe = @mailer.read_fragment('name') + html_safe = @mailer.read_fragment("name") assert_equal content, html_safe assert html_safe.html_safe? end @@ -131,7 +131,7 @@ class FunctionalFragmentCachingTest < BaseCachingTest def test_fragment_caching_in_partials email = @mailer.fragment_cache_in_partials - expected_body = 'Old fragment caching in a partial' + expected_body = "Old fragment caching in a partial" assert_match(expected_body, email.body.encoded) assert_match(expected_body, @@ -172,6 +172,7 @@ class FunctionalFragmentCachingTest < BaseCachingTest end def test_fragment_cache_instrumentation + @mailer.enable_fragment_cache_logging = true payload = nil subscriber = proc do |*args| @@ -185,6 +186,8 @@ class FunctionalFragmentCachingTest < BaseCachingTest assert_equal "caching_mailer", payload[:mailer] assert_equal "views/caching/#{template_digest("caching_mailer/fragment_cache")}", payload[:key] + ensure + @mailer.enable_fragment_cache_logging = true end private @@ -195,7 +198,6 @@ class FunctionalFragmentCachingTest < BaseCachingTest end class CacheHelperOutputBufferTest < BaseCachingTest - class MockController def read_fragment(name, options) return false @@ -224,7 +226,7 @@ class CacheHelperOutputBufferTest < BaseCachingTest cache_helper.stub :output_buffer, output_buffer do assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do assert_nothing_raised do - cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + cache_helper.send :fragment_for, "Test fragment name", "Test fragment", &Proc.new { nil } end end end @@ -245,7 +247,7 @@ class CacheHelperOutputBufferTest < BaseCachingTest cache_helper.stub :output_buffer, output_buffer do assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do assert_nothing_raised do - cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + cache_helper.send :fragment_for, "Test fragment name", "Test fragment", &Proc.new { nil } end end end diff --git a/actionmailer/test/delivery_methods_test.rb b/actionmailer/test/delivery_methods_test.rb index bcbd036f26..898d32c1e2 100644 --- a/actionmailer/test/delivery_methods_test.rb +++ b/actionmailer/test/delivery_methods_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class MyCustomDelivery end @@ -23,7 +23,7 @@ class DefaultsDeliveryMethodsTest < ActiveSupport::TestCase test "default smtp settings" do settings = { address: "localhost", port: 25, - domain: 'localhost.localdomain', + domain: "localhost.localdomain", user_name: nil, password: nil, authentication: nil, @@ -32,14 +32,14 @@ class DefaultsDeliveryMethodsTest < ActiveSupport::TestCase end test "default file delivery settings (with Rails.root)" do - settings = {location: "#{Rails.root}/tmp/mails"} + settings = { location: "#{Rails.root}/tmp/mails" } assert_equal settings, ActionMailer::Base.file_settings end test "default sendmail settings" do settings = { - location: '/usr/sbin/sendmail', - arguments: '-i' + location: "/usr/sbin/sendmail", + arguments: "-i" } assert_equal settings, ActionMailer::Base.sendmail_settings end @@ -83,8 +83,8 @@ end class MailDeliveryTest < ActiveSupport::TestCase class DeliveryMailer < ActionMailer::Base DEFAULT_HEADERS = { - to: 'mikel@test.lindsaar.net', - from: 'jose@test.plataformatec.com' + to: "mikel@test.lindsaar.net", + from: "jose@test.plataformatec.com" } def welcome(hash={}) @@ -127,16 +127,16 @@ class MailDeliveryTest < ActiveSupport::TestCase end test "delivery method options default to class level options" do - default_options = {a: "b"} + default_options = { a: "b" } ActionMailer::Base.add_delivery_method :optioned, MyOptionedDelivery, default_options mail_instance = DeliveryMailer.welcome(delivery_method: :optioned) assert_equal default_options, mail_instance.delivery_method.options end test "delivery method options can be overridden per mail instance" do - default_options = {a: "b"} + default_options = { a: "b" } ActionMailer::Base.add_delivery_method :optioned, MyOptionedDelivery, default_options - overridden_options = {a: "a"} + overridden_options = { a: "a" } mail_instance = DeliveryMailer.welcome(delivery_method: :optioned, delivery_method_options: overridden_options) assert_equal overridden_options, mail_instance.delivery_method.options end @@ -145,14 +145,14 @@ class MailDeliveryTest < ActiveSupport::TestCase settings = { address: "localhost", port: 25, - domain: 'localhost.localdomain', + domain: "localhost.localdomain", user_name: nil, password: nil, authentication: nil, enable_starttls_auto: true } assert_equal settings, ActionMailer::Base.smtp_settings - overridden_options = {user_name: "overridden", password: "somethingobtuse"} + overridden_options = { user_name: "overridden", password: "somethingobtuse" } mail_instance = DeliveryMailer.welcome(delivery_method_options: overridden_options) delivery_method_instance = mail_instance.delivery_method assert_equal "overridden", delivery_method_instance.settings[:user_name] diff --git a/actionmailer/test/i18n_with_controller_test.rb b/actionmailer/test/i18n_with_controller_test.rb index 50c4b74eb8..039685ffe5 100644 --- a/actionmailer/test/i18n_with_controller_test.rb +++ b/actionmailer/test/i18n_with_controller_test.rb @@ -1,10 +1,10 @@ -require 'abstract_unit' -require 'action_view' -require 'action_controller' +require "abstract_unit" +require "action_view" +require "action_controller" class I18nTestMailer < ActionMailer::Base configure do |c| - c.assets_dir = '' + c.assets_dir = "" end def mail_with_i18n_subject(recipient) @@ -18,7 +18,7 @@ end class TestController < ActionController::Base def send_mail email = I18nTestMailer.mail_with_i18n_subject("test@localhost").deliver_now - render text: "Mail sent - Subject: #{email.subject}" + render plain: "Mail sent - Subject: #{email.subject}" end end @@ -26,7 +26,7 @@ class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new Routes.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end @@ -56,9 +56,9 @@ class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest def test_send_mail stub_any_instance(Mail::SMTP, instance: Mail::SMTP.new({})) do |instance| assert_called(instance, :deliver!) do - with_translation 'de', email_subject: '[Anmeldung] Willkommen' do + with_translation "de", email_subject: "[Anmeldung] Willkommen" do ActiveSupport::Deprecation.silence do - get '/test/send_mail' + get "/test/send_mail" end assert_equal "Mail sent - Subject: [Anmeldung] Willkommen", @response.body end @@ -68,10 +68,10 @@ class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest protected - def with_translation(locale, data) - I18n.backend.store_translations(locale, data) - yield - ensure - I18n.backend.reload! - end + def with_translation(locale, data) + I18n.backend.store_translations(locale, data) + yield + ensure + I18n.backend.reload! + end end diff --git a/actionmailer/test/log_subscriber_test.rb b/actionmailer/test/log_subscriber_test.rb index 3871b16840..d864c3acca 100644 --- a/actionmailer/test/log_subscriber_test.rb +++ b/actionmailer/test/log_subscriber_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'mailers/base_mailer' -require 'active_support/log_subscriber/test_helper' -require 'action_mailer/log_subscriber' +require "abstract_unit" +require "mailers/base_mailer" +require "active_support/log_subscriber/test_helper" +require "action_mailer/log_subscriber" class AMLogSubscriberTest < ActionMailer::TestCase include ActiveSupport::LogSubscriber::TestHelper diff --git a/actionmailer/test/mail_helper_test.rb b/actionmailer/test/mail_helper_test.rb index ff6b25b0c7..972629e477 100644 --- a/actionmailer/test/mail_helper_test.rb +++ b/actionmailer/test/mail_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class HelperMailer < ActionMailer::Base def use_mail_helper @@ -67,10 +67,10 @@ The second protected - def mail_with_defaults(&block) - mail(to: "test@localhost", from: "tester@example.com", - subject: "using helpers", &block) - end + def mail_with_defaults(&block) + mail(to: "test@localhost", from: "tester@example.com", + subject: "using helpers", &block) + end end class MailerHelperTest < ActionMailer::TestCase diff --git a/actionmailer/test/mail_layout_test.rb b/actionmailer/test/mail_layout_test.rb index 166dd096d4..73059d782d 100644 --- a/actionmailer/test/mail_layout_test.rb +++ b/actionmailer/test/mail_layout_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' +require "abstract_unit" class AutoLayoutMailer < ActionMailer::Base - default to: 'test@localhost', + default to: "test@localhost", subject: "You have a mail", from: "tester@example.com" @@ -11,7 +11,7 @@ class AutoLayoutMailer < ActionMailer::Base def spam @world = "Earth" - mail(body: render(inline: "Hello, <%= @world %>", layout: 'spam')) + mail(body: render(inline: "Hello, <%= @world %>", layout: "spam")) end def nolayout @@ -28,9 +28,9 @@ class AutoLayoutMailer < ActionMailer::Base end class ExplicitLayoutMailer < ActionMailer::Base - layout 'spam', except: [:logout] + layout "spam", except: [:logout] - default to: 'test@localhost', + default to: "test@localhost", subject: "You have a mail", from: "tester@example.com" @@ -54,10 +54,10 @@ class LayoutMailerTest < ActiveSupport::TestCase assert_equal "multipart/alternative", mail.mime_type assert_equal 2, mail.parts.size - assert_equal 'text/plain', mail.parts.first.mime_type + assert_equal "text/plain", mail.parts.first.mime_type assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s - assert_equal 'text/html', mail.parts.last.mime_type + assert_equal "text/html", mail.parts.last.mime_type assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s end @@ -66,10 +66,10 @@ class LayoutMailerTest < ActiveSupport::TestCase assert_equal "multipart/mixed", mail.mime_type assert_equal 2, mail.parts.size - assert_equal 'text/plain', mail.parts.first.mime_type + assert_equal "text/plain", mail.parts.first.mime_type assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s - assert_equal 'text/html', mail.parts.last.mime_type + assert_equal "text/html", mail.parts.last.mime_type assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s end diff --git a/actionmailer/test/mailers/asset_mailer.rb b/actionmailer/test/mailers/asset_mailer.rb index f54a50d00d..1cf15128d2 100644 --- a/actionmailer/test/mailers/asset_mailer.rb +++ b/actionmailer/test/mailers/asset_mailer.rb @@ -2,6 +2,6 @@ class AssetMailer < ActionMailer::Base self.mailer_name = "asset_mailer" def welcome - mail + mail end end diff --git a/actionmailer/test/mailers/base_mailer.rb b/actionmailer/test/mailers/base_mailer.rb index 8c2225ce60..0d45376070 100644 --- a/actionmailer/test/mailers/base_mailer.rb +++ b/actionmailer/test/mailers/base_mailer.rb @@ -1,13 +1,13 @@ class BaseMailer < ActionMailer::Base self.mailer_name = "base_mailer" - default to: 'system@test.lindsaar.net', - from: 'jose@test.plataformatec.com', - reply_to: 'mikel@test.lindsaar.net' + default to: "system@test.lindsaar.net", + from: "jose@test.plataformatec.com", + reply_to: "mikel@test.lindsaar.net" def welcome(hash = {}) - headers['X-SPAM'] = "Not SPAM" - mail({subject: "The first email on new API!"}.merge!(hash)) + headers["X-SPAM"] = "Not SPAM" + mail({ subject: "The first email on new API!" }.merge!(hash)) end def welcome_with_headers(hash = {}) @@ -28,30 +28,30 @@ class BaseMailer < ActionMailer::Base end def inline_attachment - attachments.inline['logo.png'] = "\312\213\254\232" + attachments.inline["logo.png"] = "\312\213\254\232" mail end def attachment_with_content(hash = {}) - attachments['invoice.pdf'] = 'This is test File content' + attachments["invoice.pdf"] = "This is test File content" mail(hash) end def attachment_with_hash - attachments['invoice.jpg'] = { data: ::Base64.encode64("\312\213\254\232)b"), + attachments["invoice.jpg"] = { data: ::Base64.encode64("\312\213\254\232)b"), mime_type: "image/x-jpg", transfer_encoding: "base64" } mail end def attachment_with_hash_default_encoding - attachments['invoice.jpg'] = { data: "\312\213\254\232)b", + attachments["invoice.jpg"] = { data: "\312\213\254\232)b", mime_type: "image/x-jpg" } mail end def implicit_multipart(hash = {}) - attachments['invoice.pdf'] = 'This is test File content' if hash.delete(:attachments) + attachments["invoice.pdf"] = "This is test File content" if hash.delete(:attachments) mail(hash) end @@ -60,10 +60,10 @@ class BaseMailer < ActionMailer::Base end def explicit_multipart(hash = {}) - attachments['invoice.pdf'] = 'This is test File content' if hash.delete(:attachments) + attachments["invoice.pdf"] = "This is test File content" if hash.delete(:attachments) mail(hash) do |format| - format.text { render text: "TEXT Explicit Multipart" } - format.html { render text: "HTML Explicit Multipart" } + format.text { render plain: "TEXT Explicit Multipart" } + format.html { render plain: "HTML Explicit Multipart" } end end @@ -76,7 +76,7 @@ class BaseMailer < ActionMailer::Base def explicit_multipart_with_any(hash = {}) mail(hash) do |format| - format.any(:text, :html){ render text: "Format with any!" } + format.any(:text, :html) { render plain: "Format with any!" } end end @@ -88,8 +88,8 @@ class BaseMailer < ActionMailer::Base def explicit_multipart_with_options(include_html = false) mail do |format| - format.text(content_transfer_encoding: "base64"){ render "welcome" } - format.html{ render "welcome" } if include_html + format.text(content_transfer_encoding: "base64") { render "welcome" } + format.html { render "welcome" } if include_html end end @@ -100,18 +100,18 @@ class BaseMailer < ActionMailer::Base end end - def implicit_different_template(template_name='') + def implicit_different_template(template_name="") mail(template_name: template_name) end - def explicit_different_template(template_name='') + def explicit_different_template(template_name="") mail do |format| format.text { render template: "#{mailer_name}/#{template_name}" } format.html { render template: "#{mailer_name}/#{template_name}" } end end - def different_layout(layout_name='') + def different_layout(layout_name="") mail do |format| format.text { render layout: layout_name } format.html { render layout: layout_name } @@ -131,6 +131,6 @@ class BaseMailer < ActionMailer::Base end def with_subject_interpolations - mail(subject: default_i18n_subject(rapper_or_impersonator: 'Slim Shady'), body: '') + mail(subject: default_i18n_subject(rapper_or_impersonator: "Slim Shady"), body: "") end end diff --git a/actionmailer/test/mailers/delayed_mailer.rb b/actionmailer/test/mailers/delayed_mailer.rb index e6211ef028..cae4ec2f48 100644 --- a/actionmailer/test/mailers/delayed_mailer.rb +++ b/actionmailer/test/mailers/delayed_mailer.rb @@ -1,4 +1,4 @@ -require 'active_job/arguments' +require "active_job/arguments" class DelayedMailerError < StandardError; end @@ -17,10 +17,10 @@ class DelayedMailer < ActionMailer::Base end def test_message(*) - mail(from: 'test-sender@test.com', to: 'test-receiver@test.com', subject: 'Test Subject', body: 'Test Body') + mail(from: "test-sender@test.com", to: "test-receiver@test.com", subject: "Test Subject", body: "Test Body") end def test_raise(klass_name) - raise klass_name.constantize, 'boom' + raise klass_name.constantize, "boom" end end diff --git a/actionmailer/test/mailers/proc_mailer.rb b/actionmailer/test/mailers/proc_mailer.rb index 7e189d861f..2487db9eb9 100644 --- a/actionmailer/test/mailers/proc_mailer.rb +++ b/actionmailer/test/mailers/proc_mailer.rb @@ -1,8 +1,8 @@ class ProcMailer < ActionMailer::Base - default to: 'system@test.lindsaar.net', - 'X-Proc-Method' => Proc.new { Time.now.to_i.to_s }, + default to: "system@test.lindsaar.net", + "X-Proc-Method" => Proc.new { Time.now.to_i.to_s }, subject: Proc.new { give_a_greeting }, - 'x-has-to-proc' => :symbol + "x-has-to-proc" => :symbol def welcome mail @@ -10,8 +10,7 @@ class ProcMailer < ActionMailer::Base private - def give_a_greeting - "Thanks for signing up this afternoon" - end - + def give_a_greeting + "Thanks for signing up this afternoon" + end end diff --git a/actionmailer/test/message_delivery_test.rb b/actionmailer/test/message_delivery_test.rb index aaed94d519..0eb81a8496 100644 --- a/actionmailer/test/message_delivery_test.rb +++ b/actionmailer/test/message_delivery_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_job' -require 'mailers/delayed_mailer' +require "abstract_unit" +require "active_job" +require "mailers/delayed_mailer" class MessageDeliveryTest < ActiveSupport::TestCase include ActiveJob::TestHelper @@ -31,27 +31,27 @@ class MessageDeliveryTest < ActiveSupport::TestCase DelayedMailer.last_rescue_from_instance = nil end - test 'should have a message' do + test "should have a message" do assert @mail.message end - test 'its message should be a Mail::Message' do + test "its message should be a Mail::Message" do assert_equal Mail::Message , @mail.message.class end - test 'should respond to .deliver_later' do + test "should respond to .deliver_later" do assert_respond_to @mail, :deliver_later end - test 'should respond to .deliver_later!' do + test "should respond to .deliver_later!" do assert_respond_to @mail, :deliver_later! end - test 'should respond to .deliver_now' do + test "should respond to .deliver_now" do assert_respond_to @mail, :deliver_now end - test 'should respond to .deliver_now!' do + test "should respond to .deliver_now!" do assert_respond_to @mail, :deliver_now! end @@ -62,46 +62,46 @@ class MessageDeliveryTest < ActiveSupport::TestCase ActionMailer::Base.deliveries.clear end - test 'should enqueue the email with :deliver_now delivery method' do - assert_performed_with(job: ActionMailer::DeliveryJob, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3]) do + test "should enqueue the email with :deliver_now delivery method" do + assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", 1, 2, 3]) do @mail.deliver_later end end - test 'should enqueue the email with :deliver_now! delivery method' do - assert_performed_with(job: ActionMailer::DeliveryJob, args: ['DelayedMailer', 'test_message', 'deliver_now!', 1, 2, 3]) do + test "should enqueue the email with :deliver_now! delivery method" do + assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now!", 1, 2, 3]) do @mail.deliver_later! end end - test 'should enqueue a delivery with a delay' do + test "should enqueue a delivery with a delay" do travel_to Time.new(2004, 11, 24, 01, 04, 44) do - assert_performed_with(job: ActionMailer::DeliveryJob, at: Time.current.to_f+600.seconds, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3]) do + assert_performed_with(job: ActionMailer::DeliveryJob, at: Time.current.to_f+600.seconds, args: ["DelayedMailer", "test_message", "deliver_now", 1, 2, 3]) do @mail.deliver_later wait: 600.seconds end end end - test 'should enqueue a delivery at a specific time' do + test "should enqueue a delivery at a specific time" do later_time = Time.now.to_f + 3600 - assert_performed_with(job: ActionMailer::DeliveryJob, at: later_time, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3]) do + assert_performed_with(job: ActionMailer::DeliveryJob, at: later_time, args: ["DelayedMailer", "test_message", "deliver_now", 1, 2, 3]) do @mail.deliver_later wait_until: later_time end end - test 'should enqueue the job on the correct queue' do - assert_performed_with(job: ActionMailer::DeliveryJob, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3], queue: "test_queue") do + test "should enqueue the job on the correct queue" do + assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", 1, 2, 3], queue: "test_queue") do @mail.deliver_later end end - test 'can override the queue when enqueuing mail' do - assert_performed_with(job: ActionMailer::DeliveryJob, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3], queue: "another_queue") do + test "can override the queue when enqueuing mail" do + assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", 1, 2, 3], queue: "another_queue") do @mail.deliver_later(queue: :another_queue) end end - test 'deliver_later after accessing the message is disallowed' do + test "deliver_later after accessing the message is disallowed" do @mail.message # Load the message, which calls the mailer method. assert_raise RuntimeError do @@ -109,17 +109,17 @@ class MessageDeliveryTest < ActiveSupport::TestCase end end - test 'job delegates error handling to mailer' do + test "job delegates error handling to mailer" do # Superclass not rescued by mailer's rescue_from RuntimeError - message = DelayedMailer.test_raise('StandardError') + message = DelayedMailer.test_raise("StandardError") assert_raise(StandardError) { message.deliver_later } assert_nil DelayedMailer.last_error assert_nil DelayedMailer.last_rescue_from_instance # Rescued by mailer's rescue_from RuntimeError - message = DelayedMailer.test_raise('DelayedMailerError') + message = DelayedMailer.test_raise("DelayedMailerError") assert_nothing_raised { message.deliver_later } - assert_equal 'boom', DelayedMailer.last_error.message + assert_equal "boom", DelayedMailer.last_error.message assert_kind_of DelayedMailer, DelayedMailer.last_rescue_from_instance end @@ -127,7 +127,7 @@ class MessageDeliveryTest < ActiveSupport::TestCase include GlobalID::Identification def self.find(id) - raise 'boom, missing find' + raise "boom, missing find" end attr_reader :id @@ -136,11 +136,11 @@ class MessageDeliveryTest < ActiveSupport::TestCase end def to_global_id(options = {}) - super app: 'foo' + super app: "foo" end end - test 'job delegates deserialization errors to mailer class' do + test "job delegates deserialization errors to mailer class" do # Inject an argument that can't be deserialized. message = DelayedMailer.test_message(DeserializationErrorFixture.new) @@ -148,6 +148,6 @@ class MessageDeliveryTest < ActiveSupport::TestCase # on the mailer class. assert_nothing_raised { message.deliver_later } assert_equal DelayedMailer, DelayedMailer.last_rescue_from_instance - assert_equal 'Error while trying to deserialize arguments: boom, missing find', DelayedMailer.last_error.message + assert_equal "Error while trying to deserialize arguments: boom, missing find", DelayedMailer.last_error.message end end diff --git a/actionmailer/test/test_case_test.rb b/actionmailer/test/test_case_test.rb index 5d8d3c3b36..193d107b0a 100644 --- a/actionmailer/test/test_case_test.rb +++ b/actionmailer/test/test_case_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TestTestMailer < ActionMailer::Base end @@ -8,7 +8,7 @@ class ClearTestDeliveriesMixinTest < ActiveSupport::TestCase def before_setup ActionMailer::Base.delivery_method, @original_delivery_method = :test, ActionMailer::Base.delivery_method - ActionMailer::Base.deliveries << 'better clear me, setup' + ActionMailer::Base.deliveries << "better clear me, setup" super end @@ -20,13 +20,13 @@ class ClearTestDeliveriesMixinTest < ActiveSupport::TestCase def test_deliveries_are_cleared_on_setup_and_teardown assert_equal [], ActionMailer::Base.deliveries - ActionMailer::Base.deliveries << 'better clear me, teardown' + ActionMailer::Base.deliveries << "better clear me, teardown" end end class MailerDeliveriesClearingTest < ActionMailer::TestCase def before_setup - ActionMailer::Base.deliveries << 'better clear me, setup' + ActionMailer::Base.deliveries << "better clear me, setup" super end @@ -37,7 +37,7 @@ class MailerDeliveriesClearingTest < ActionMailer::TestCase def test_deliveries_are_cleared_on_setup_and_teardown assert_equal [], ActionMailer::Base.deliveries - ActionMailer::Base.deliveries << 'better clear me, teardown' + ActionMailer::Base.deliveries << "better clear me, teardown" end end @@ -58,7 +58,7 @@ class CrazySymbolNameMailerTest < ActionMailer::TestCase end class CrazyStringNameMailerTest < ActionMailer::TestCase - tests 'test_test_mailer' + tests "test_test_mailer" def test_set_mailer_class_manual_using_string assert_equal TestTestMailer, self.class.mailer_class diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb index 0a4bc75d3e..31ac5a5211 100644 --- a/actionmailer/test/test_helper_test.rb +++ b/actionmailer/test/test_helper_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/testing/stream' +require "abstract_unit" +require "active_support/testing/stream" class TestHelperMailer < ActionMailer::Base def test @@ -40,11 +40,11 @@ class TestHelperMailerTest < ActionMailer::TestCase end def test_encode - assert_equal '=?UTF-8?Q?This_is_=E3=81=82_string?=', encode('This is ã‚ string') + assert_equal "=?UTF-8?Q?This_is_=E3=81=82_string?=", encode("This is ã‚ string") end def test_read_fixture - assert_equal ['Welcome!'], read_fixture('welcome') + assert_equal ["Welcome!"], read_fixture("welcome") end def test_assert_emails @@ -198,6 +198,6 @@ class AnotherTestHelperMailerTest < ActionMailer::TestCase def test_setup_shouldnt_conflict_with_mailer_setup assert_kind_of Mail::Message, @expected - assert_equal 'a value', @test_var + assert_equal "a value", @test_var end end diff --git a/actionmailer/test/url_test.rb b/actionmailer/test/url_test.rb index 70bd05055f..27f6e8a491 100644 --- a/actionmailer/test/url_test.rb +++ b/actionmailer/test/url_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_controller' +require "abstract_unit" +require "action_controller" class WelcomeController < ActionController::Base end @@ -11,10 +11,10 @@ class ActionMailer::Base end class UrlTestMailer < ActionMailer::Base - default_url_options[:host] = 'www.basecamphq.com' + default_url_options[:host] = "www.basecamphq.com" configure do |c| - c.assets_dir = '' # To get the tests to pass + c.assets_dir = "" # To get the tests to pass end def signed_up_with_url(recipient) @@ -27,14 +27,14 @@ class UrlTestMailer < ActionMailer::Base def exercise_url_for(options) @options = options @url = url_for(@options) - mail(from: 'from@example.com', to: 'to@example.com', subject: 'subject') + mail(from: "from@example.com", to: "to@example.com", subject: "subject") end end class ActionMailerUrlTest < ActionMailer::TestCase class DummyModel def self.model_name - OpenStruct.new(route_key: 'dummy_model') + OpenStruct.new(route_key: "dummy_model") end def persisted? @@ -64,7 +64,7 @@ class ActionMailerUrlTest < ActionMailer::TestCase end def assert_url_for(expected, options, relative = false) - expected = "http://www.basecamphq.com#{expected}" if expected.start_with?('/') && !relative + expected = "http://www.basecamphq.com#{expected}" if expected.start_with?("/") && !relative urls = UrlTestMailer.exercise_url_for(options).body.to_s.chomp.split assert_equal expected, urls.first @@ -72,7 +72,7 @@ class ActionMailerUrlTest < ActionMailer::TestCase end def setup - @recipient = 'test@localhost' + @recipient = "test@localhost" end def test_url_for @@ -80,30 +80,30 @@ class ActionMailerUrlTest < ActionMailer::TestCase AppRoutes.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' - get '/welcome' => 'foo#bar', as: 'welcome' - get '/dummy_model' => 'foo#baz', as: 'dummy_model' + get ":controller(/:action(/:id))" + get "/welcome" => "foo#bar", as: "welcome" + get "/dummy_model" => "foo#baz", as: "dummy_model" end end # string - assert_url_for 'http://foo/', 'http://foo/' + assert_url_for "http://foo/", "http://foo/" # symbol - assert_url_for '/welcome', :welcome + assert_url_for "/welcome", :welcome # hash - assert_url_for '/a/b/c', controller: 'a', action: 'b', id: 'c' - assert_url_for '/a/b/c', {controller: 'a', action: 'b', id: 'c', only_path: true}, true + assert_url_for "/a/b/c", controller: "a", action: "b", id: "c" + assert_url_for "/a/b/c", { controller: "a", action: "b", id: "c", only_path: true }, true # model - assert_url_for '/dummy_model', DummyModel.new + assert_url_for "/dummy_model", DummyModel.new # class - assert_url_for '/dummy_model', DummyModel + assert_url_for "/dummy_model", DummyModel # array - assert_url_for '/dummy_model' , [DummyModel] + assert_url_for "/dummy_model" , [DummyModel] end def test_signed_up_with_url @@ -111,8 +111,8 @@ class ActionMailerUrlTest < ActionMailer::TestCase AppRoutes.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' - get '/welcome' => "foo#bar", as: "welcome" + get ":controller(/:action(/:id))" + get "/welcome" => "foo#bar", as: "welcome" end end @@ -128,15 +128,15 @@ class ActionMailerUrlTest < ActionMailer::TestCase assert_nothing_raised { created = UrlTestMailer.signed_up_with_url(@recipient) } assert_not_nil created - expected.message_id = '<123@456>' - created.message_id = '<123@456>' + expected.message_id = "<123@456>" + created.message_id = "<123@456>" assert_dom_equal expected.encoded, created.encoded assert_nothing_raised { UrlTestMailer.signed_up_with_url(@recipient).deliver_now } assert_not_nil ActionMailer::Base.deliveries.first delivered = ActionMailer::Base.deliveries.first - delivered.message_id = '<123@456>' + delivered.message_id = "<123@456>" assert_dom_equal expected.encoded, delivered.encoded end end diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index be911b147c..c9c347ea26 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,2 +1,265 @@ +* Allow keys not found in RACK_KEY_TRANSLATION for setting the environment when rendering + arbitrary templates. + + *Sammy Larbi* + +* Remove deprecated support to non-keyword arguments in `ActionDispatch::IntegrationTest#process`, + `#get`, `#post`, `#patch`, `#put`, `#delete`, and `#head`. + + *Rafael Mendonça França* + +* Remove deprecated `ActionDispatch::IntegrationTest#*_via_redirect`. + + *Rafael Mendonça França* + +* Remove deprecated `ActionDispatch::IntegrationTest#xml_http_request`. + + *Rafael Mendonça França* + +* Remove deprecated support for passing `:path` and route path as strings in `ActionDispatch::Routing::Mapper#match`. + + *Rafael Mendonça França* + +* Remove deprecated support for passing path as `nil` in `ActionDispatch::Routing::Mapper#match`. + + *Rafael Mendonça França* + +* Remove deprecated `cache_control` argument from `ActionDispatch::Static#initialize`. + + *Rafael Mendonça França* + +* Remove deprecated support to passing strings or symbols to the middleware stack. + + *Rafael Mendonça França* + +* Change HSTS subdomain to true. + + *Rafael Mendonça França* + +* Remove deprecated `host` and `port` ssl options. + + *Rafael Mendonça França* + +* Remove deprecated `const_error` argument in + `ActionDispatch::Session::SessionRestoreError#initialize`. + + *Rafael Mendonça França* + +* Remove deprecated `#original_exception` in `ActionDispatch::Session::SessionRestoreError`. + + *Rafael Mendonça França* + +* Deprecate `ActionDispatch::ParamsParser::ParseError` in favor of + `ActionDispatch::Http::Parameters::ParseError`. + + *Rafael Mendonça França* + +* Remove deprecated `ActionDispatch::ParamsParser`. + + *Rafael Mendonça França* + +* Remove deprecated `original_exception` and `message` arguments in + `ActionDispatch::ParamsParser::ParseError#initialize`. + + *Rafael Mendonça França* + +* Remove deprecated `#original_exception` in `ActionDispatch::ParamsParser::ParseError`. + + *Rafael Mendonça França* + +* Remove deprecated access to mime types through constants. + + *Rafael Mendonça França* + +* Remove deprecated support to non-keyword arguments in `ActionController::TestCase#process`, + `#get`, `#post`, `#patch`, `#put`, `#delete`, and `#head`. + + *Rafael Mendonça França* + +* Remove deprecated `xml_http_request` and `xhr` methods in `ActionController::TestCase`. + + *Rafael Mendonça França* + +* Remove deprecated methods in `ActionController::Parameters`. + + *Rafael Mendonça França* + +* Remove deprecated support to comparing a `ActionController::Parameters` + with a `Hash`. + + *Rafael Mendonça França* + +* Remove deprecated support to `:text` in `render`. + + *Rafael Mendonça França* + +* Remove deprecated support to `:nothing` in `render`. + + *Rafael Mendonça França* + +* Remove deprecated support to `:back` in `redirect_to`. + + *Rafael Mendonça França* + +* Remove deprecated support to passing status as option `head`. + + *Rafael Mendonça França* + +* Remove deprecated support to passing original exception to `ActionController::BadRequest` + and the `ActionController::BadRequest#original_exception` method. + + *Rafael Mendonça França* + +* Remove deprecated methods `skip_action_callback`, `skip_filter`, `before_filter`, + `prepend_before_filter`, `skip_before_filter`, `append_before_filter`, `around_filter` + `prepend_around_filter`, `skip_around_filter`, `append_around_filter`, `after_filter`, + `prepend_after_filter`, `skip_after_filter` and `append_after_filter`. + + *Rafael Mendonça França* + +* Show an "unmatched constraints" error when params fail to match constraints + on a matched route, rather than a "missing keys" error. + + Fixes #26470. + + *Chris Carter* + +* Fix adding implicitly rendered template digests to ETags. + + Fixes a case when modifying an implicitly rendered template for a + controller action using `fresh_when` or `stale?` would not result in a new + `ETag` value. + + *Javan Makhmali* + +* Make `fixture_file_upload` work in integration tests. + + *Yuji Yaginuma* + +* Add `to_param` to `ActionController::Parameters` deprecations. + + In the future `ActionController::Parameters` are discouraged from being used + in URLs without explicit whitelisting. Go through `to_h` to use `to_param`. + + *Kir Shatrov* + +* Fix nested multiple roots + + The PR #20940 enabled the use of multiple roots with different constraints + at the top level but unfortunately didn't work when those roots were inside + a namespace and also broke the use of root inside a namespace after a top + level root was defined because the check for the existence of the named route + used the global :root name and not the namespaced name. + + This is fixed by using the name_for_action method to expand the :root name to + the full namespaced name. We can pass nil for the second argument as we're not + dealing with resource definitions so don't need to handle the cases for edit + and new routes. + + Fixes #26148. + + *Ryo Hashimoto*, *Andrew White* + +* Include the content of the flash in the auto-generated etag. This solves the following problem: + + 1. POST /messages + 2. redirect_to messages_url, notice: 'Message was created' + 3. GET /messages/1 + 4. GET /messages + + Step 4 would before still include the flash message, even though it's no longer relevant, + because the etag cache was recorded with the flash in place and didn't change when it was gone. + + *DHH* + +* SSL: Changes redirect behavior for all non-GET and non-HEAD requests + (like POST/PUT/PATCH etc) to `http://` resources to redirect to `https://` + with a [307 status code](http://tools.ietf.org/html/rfc7231#section-6.4.7) instead of [301 status code](http://tools.ietf.org/html/rfc7231#section-6.4.2). + + 307 status code instructs the HTTP clients to preserve the original + request method while redirecting. It has been part of HTTP RFC since + 1999 and is implemented/recognized by most (if not all) user agents. + + # Before + POST http://example.com/articles (i.e. ArticlesContoller#create) + redirects to + GET https://example.com/articles (i.e. ArticlesContoller#index) + + # After + POST http://example.com/articles (i.e. ArticlesContoller#create) + redirects to + POST https://example.com/articles (i.e. ArticlesContoller#create) + + *Chirag Singhal* + +* Add `:as` option to `ActionController:TestCase#process` and related methods. + + Specifying `as: mime_type` allows the `CONTENT_TYPE` header to be specified + in controller tests without manually doing this through `@request.headers['CONTENT_TYPE']`. + + *Everest Stefan Munro-Zeisberger* + +* Show cache hits and misses when rendering partials. + + Partials using the `cache` helper will show whether a render hit or missed + the cache: + + ``` + Rendered messages/_message.html.erb in 1.2 ms [cache hit] + Rendered recordings/threads/_thread.html.erb in 1.5 ms [cache miss] + ``` + + This removes the need for the old fragment cache logging: + + ``` + Read fragment views/v1/2914079/v1/2914079/recordings/70182313-20160225015037000000/d0bdf2974e1ef6d31685c3b392ad0b74 (0.6ms) + Rendered messages/_message.html.erb in 1.2 ms [cache hit] + Write fragment views/v1/2914079/v1/2914079/recordings/70182313-20160225015037000000/3b4e249ac9d168c617e32e84b99218b5 (1.1ms) + Rendered recordings/threads/_thread.html.erb in 1.5 ms [cache miss] + ``` + + Though that full output can be reenabled with + `config.action_controller.enable_fragment_cache_logging = true`. + + *Stan Lo* + +* Don't override the `Accept` header in integration tests when called with `xhr: true`. + + Fixes #25859. + + *David Chen* + +* Fix `defaults` option for root route. + + A regression from some refactoring for the 5.0 release, this change + fixes the use of `defaults` (default parameters) in the `root` routing method. + + *Chris Arcand* + +* Check `request.path_parameters` encoding at the point they're set. + + Check for any non-UTF8 characters in path parameters at the point they're + set in `env`. Previously they were checked for when used to get a controller + class, but this meant routes that went directly to a Rack app, or skipped + controller instantiation for some other reason, had to defend against + non-UTF8 characters themselves. + + *Grey Baker* + +* Don't raise `ActionController::UnknownHttpMethod` from `ActionDispatch::Static`. + + Pass `Rack::Request` objects to `ActionDispatch::FileHandler` to avoid it + raising `ActionController::UnknownHttpMethod`. If an unknown method is + passed, it should pass exception higher in the stack instead, once we've had a + chance to define exception handling behaviour. + + *Grey Baker* + +* Handle `Rack::QueryParser` errors in `ActionDispatch::ExceptionWrapper`. + + Updated `ActionDispatch::ExceptionWrapper` to handle the Rack 2.0 namespace + for `ParameterTypeError` and `InvalidParameterError` errors. + + *Grey Baker* Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/actionpack/CHANGELOG.md) for previous changes. diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 4a05c067a9..31dd1865f9 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -1,15 +1,15 @@ -require 'rake/testtask' +require "rake/testtask" -test_files = Dir.glob('test/**/*_test.rb') +test_files = Dir.glob("test/**/*_test.rb") desc "Default Task" -task :default => :test +task default: :test task :package # Run the unit tests Rake::TestTask.new do |t| - t.libs << 'test' + t.libs << "test" t.test_files = test_files t.warning = true @@ -20,19 +20,19 @@ end namespace :test do task :isolated do test_files.all? do |file| - sh(Gem.ruby, '-w', '-Ilib:test', file) - end or raise "Failures" + sh(Gem.ruby, "-w", "-Ilib:test", file) + end || raise("Failures") end end task :lines do - load File.expand_path('..', File.dirname(__FILE__)) + '/tools/line_statistics' + load File.expand_path("..", File.dirname(__FILE__)) + "/tools/line_statistics" files = FileList["lib/**/*.rb"] CodeTools::LineStatistics.new(files).print_loc end -rule '.rb' => '.y' do |t| +rule ".rb" => ".y" do |t| sh "racc -l -o #{t.name} #{t.source}" end -task compile: 'lib/action_dispatch/journey/parser.rb' +task compile: "lib/action_dispatch/journey/parser.rb" diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 965fafff5f..2c24a54305 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -1,31 +1,31 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'actionpack' + s.name = "actionpack" s.version = version - s.summary = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).' - s.description = 'Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server.' + s.summary = "Web-flow and rendering framework putting the VC in MVC (part of Rails)." + s.description = "Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*'] - s.require_path = 'lib' - s.requirements << 'none' + s.files = Dir["CHANGELOG.md", "README.rdoc", "MIT-LICENSE", "lib/**/*"] + s.require_path = "lib" + s.requirements << "none" - s.add_dependency 'activesupport', version + s.add_dependency "activesupport", version - s.add_dependency 'rack', '~> 2.x' - s.add_dependency 'rack-test', '~> 0.6.3' - s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.2' - s.add_dependency 'rails-dom-testing', '~> 2.0' - s.add_dependency 'actionview', version + s.add_dependency "rack", "~> 2.0" + s.add_dependency "rack-test", "~> 0.6.3" + s.add_dependency "rails-html-sanitizer", "~> 1.0", ">= 1.0.2" + s.add_dependency "rails-dom-testing", "~> 2.0" + s.add_dependency "actionview", version - s.add_development_dependency 'activemodel', version + s.add_development_dependency "activemodel", version end diff --git a/actionpack/bin/test b/actionpack/bin/test index 404cabba51..84a05bba08 100755 --- a/actionpack/bin/test +++ b/actionpack/bin/test @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -COMPONENT_ROOT = File.expand_path("../../", __FILE__) + +COMPONENT_ROOT = File.expand_path("..", __dir__) require File.expand_path("../tools/test", COMPONENT_ROOT) + exit Minitest.run(ARGV) diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 1e57cbaac4..8bd965b198 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -1,6 +1,6 @@ -require 'action_pack' -require 'active_support/rails' -require 'active_support/i18n' +require "action_pack" +require "active_support/rails" +require "active_support/i18n" module AbstractController extend ActiveSupport::Autoload diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index aa06f70433..8e588812f8 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -1,9 +1,9 @@ -require 'erubis' -require 'abstract_controller/error' -require 'active_support/configurable' -require 'active_support/descendants_tracker' -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/module/attr_internal' +require "erubis" +require "abstract_controller/error" +require "active_support/configurable" +require "active_support/descendants_tracker" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/attr_internal" module AbstractController # Raised when a non-existing controller action is triggered. @@ -94,7 +94,7 @@ module AbstractController # ==== Returns # * <tt>String</tt> def controller_path - @controller_path ||= name.sub(/Controller$/, ''.freeze).underscore unless anonymous? + @controller_path ||= name.sub(/Controller$/, "".freeze).underscore unless anonymous? end # Refresh the cached action_methods when a new action_method is added. diff --git a/actionpack/lib/abstract_controller/caching.rb b/actionpack/lib/abstract_controller/caching.rb index 0dea50889a..d222880922 100644 --- a/actionpack/lib/abstract_controller/caching.rb +++ b/actionpack/lib/abstract_controller/caching.rb @@ -29,11 +29,14 @@ module AbstractController extend ConfigMethods config_accessor :default_static_extension - self.default_static_extension ||= '.html' + self.default_static_extension ||= ".html" config_accessor :perform_caching self.perform_caching = true if perform_caching.nil? + config_accessor :enable_fragment_cache_logging + self.enable_fragment_cache_logging = false + class_attribute :_view_cache_dependencies self._view_cache_dependencies = [] helper_method :view_cache_dependencies if respond_to?(:helper_method) diff --git a/actionpack/lib/abstract_controller/caching/fragments.rb b/actionpack/lib/abstract_controller/caching/fragments.rb index 3257a731ed..c85b4adba1 100644 --- a/actionpack/lib/abstract_controller/caching/fragments.rb +++ b/actionpack/lib/abstract_controller/caching/fragments.rb @@ -51,7 +51,7 @@ module AbstractController # end # end def fragment_cache_key(value = nil, &key) - self.fragment_cache_keys += [key || ->{ value }] + self.fragment_cache_keys += [key || -> { value }] end end diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 3ef8da86fa..ce4ecf17cc 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -49,30 +49,11 @@ module AbstractController def _normalize_callback_option(options, from, to) # :nodoc: if from = options[from] _from = Array(from).map(&:to_s).to_set - from = proc {|c| _from.include? c.action_name } + from = proc { |c| _from.include? c.action_name } options[to] = Array(options[to]).unshift(from) end end - # Skip before, after, and around action callbacks matching any of the names. - # - # ==== Parameters - # * <tt>names</tt> - A list of valid names that could be used for - # callbacks. Note that skipping uses Ruby equality, so it's - # impossible to skip a callback defined using an anonymous proc - # using #skip_action_callback. - def skip_action_callback(*names) - ActiveSupport::Deprecation.warn('`skip_action_callback` is deprecated and will be removed in Rails 5.1. Please use skip_before_action, skip_after_action or skip_around_action instead.') - skip_before_action(*names, raise: false) - skip_after_action(*names, raise: false) - skip_around_action(*names, raise: false) - end - - def skip_filter(*names) - ActiveSupport::Deprecation.warn("`skip_filter` is deprecated and will be removed in Rails 5.1. Use skip_before_action, skip_after_action or skip_around_action instead.") - skip_action_callback(*names) - end - # Take callback names and an optional callback proc, normalize them, # then call the block with each callback. This allows us to abstract # the normalization across several methods that use it. @@ -187,22 +168,12 @@ module AbstractController end end - define_method "#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("#{callback}_filter is deprecated and will be removed in Rails 5.1. Use #{callback}_action instead.") - send("#{callback}_action", *names, &blk) - end - define_method "prepend_#{callback}_action" do |*names, &blk| _insert_callbacks(names, blk) do |name, options| - set_callback(:process_action, callback, name, options.merge(:prepend => true)) + set_callback(:process_action, callback, name, options.merge(prepend: true)) end end - define_method "prepend_#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("prepend_#{callback}_filter is deprecated and will be removed in Rails 5.1. Use prepend_#{callback}_action instead.") - send("prepend_#{callback}_action", *names, &blk) - end - # Skip a before, after or around callback. See _insert_callbacks # for details on the allowed parameters. define_method "skip_#{callback}_action" do |*names| @@ -211,18 +182,8 @@ module AbstractController end end - define_method "skip_#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("skip_#{callback}_filter is deprecated and will be removed in Rails 5.1. Use skip_#{callback}_action instead.") - send("skip_#{callback}_action", *names, &blk) - end - # *_action is the same as append_*_action alias_method :"append_#{callback}_action", :"#{callback}_action" - - define_method "append_#{callback}_filter" do |*names, &blk| - ActiveSupport::Deprecation.warn("append_#{callback}_filter is deprecated and will be removed in Rails 5.1. Use append_#{callback}_action instead.") - send("append_#{callback}_action", *names, &blk) - end end end end diff --git a/actionpack/lib/abstract_controller/collector.rb b/actionpack/lib/abstract_controller/collector.rb index 55654be224..57714b0588 100644 --- a/actionpack/lib/abstract_controller/collector.rb +++ b/actionpack/lib/abstract_controller/collector.rb @@ -16,7 +16,7 @@ module AbstractController end Mime::Type.register_callback do |mime| - generate_method_for_mime(mime) unless self.instance_methods.include?(mime.to_sym) + generate_method_for_mime(mime) unless instance_methods.include?(mime.to_sym) end protected diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index ab4355296b..ef3be7af83 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -1,4 +1,4 @@ -require 'active_support/dependencies' +require "active_support/dependencies" module AbstractController module Helpers @@ -171,25 +171,25 @@ module AbstractController end private - # Makes all the (instance) methods in the helper module available to templates - # rendered through this controller. - # - # ==== Parameters - # * <tt>module</tt> - The module to include into the current helper module - # for the class - def add_template_helper(mod) - _helpers.module_eval { include mod } - end + # Makes all the (instance) methods in the helper module available to templates + # rendered through this controller. + # + # ==== Parameters + # * <tt>module</tt> - The module to include into the current helper module + # for the class + def add_template_helper(mod) + _helpers.module_eval { include mod } + end - def default_helper_module! - module_name = name.sub(/Controller$/, ''.freeze) - module_path = module_name.underscore - helper module_path - rescue LoadError => e - raise e unless e.is_missing? "helpers/#{module_path}_helper" - rescue NameError => e - raise e unless e.missing_name? "#{module_name}Helper" - end + def default_helper_module! + module_name = name.sub(/Controller$/, "".freeze) + module_path = module_name.underscore + helper module_path + rescue LoadError => e + raise e unless e.is_missing? "helpers/#{module_path}_helper" + rescue NameError => e + raise e unless e.missing_name? "#{module_name}Helper" + end end end end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 4ba2c26949..2cb22cb53d 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -1,9 +1,9 @@ -require 'abstract_controller/error' -require 'active_support/concern' -require 'active_support/core_ext/class/attribute' -require 'action_view' -require 'action_view/view_paths' -require 'set' +require "abstract_controller/error" +require "active_support/concern" +require "active_support/core_ext/class/attribute" +require "action_view" +require "action_view/view_paths" +require "set" module AbstractController class DoubleRenderError < Error diff --git a/actionpack/lib/abstract_controller/translation.rb b/actionpack/lib/abstract_controller/translation.rb index 56b8ce895e..9e3858802a 100644 --- a/actionpack/lib/abstract_controller/translation.rb +++ b/actionpack/lib/abstract_controller/translation.rb @@ -9,8 +9,8 @@ module AbstractController # to translate many keys within the same controller / action and gives you a # simple framework for scoping them consistently. def translate(key, options = {}) - if key.to_s.first == '.' - path = controller_path.tr('/', '.') + if key.to_s.first == "." + path = controller_path.tr("/", ".") defaults = [:"#{path}#{key}"] defaults << options[:default] if options[:default] options[:default] = defaults diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 62f5905205..50f20aa789 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -1,8 +1,8 @@ -require 'active_support/rails' -require 'abstract_controller' -require 'action_dispatch' -require 'action_controller/metal/live' -require 'action_controller/metal/strong_parameters' +require "active_support/rails" +require "abstract_controller" +require "action_dispatch" +require "action_controller/metal/live" +require "action_controller/metal/strong_parameters" module ActionController extend ActiveSupport::Autoload @@ -23,6 +23,7 @@ module ActionController autoload :Cookies autoload :DataStreaming autoload :EtagWithTemplateDigest + autoload :EtagWithFlash autoload :Flash autoload :ForceSSL autoload :Head @@ -40,6 +41,7 @@ module ActionController autoload :Rescue autoload :Streaming autoload :StrongParameters + autoload :ParameterEncoding autoload :Testing autoload :UrlFor end @@ -48,14 +50,14 @@ module ActionController autoload :ApiRendering end - autoload :TestCase, 'action_controller/test_case' - autoload :TemplateAssertions, 'action_controller/test_case' + autoload :TestCase, "action_controller/test_case" + autoload :TemplateAssertions, "action_controller/test_case" end # Common Active Support usage in Action Controller -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/load_error' -require 'active_support/core_ext/module/attr_internal' -require 'active_support/core_ext/name_error' -require 'active_support/core_ext/uri' -require 'active_support/inflector' +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/load_error" +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/name_error" +require "active_support/core_ext/uri" +require "active_support/inflector" diff --git a/actionpack/lib/action_controller/api.rb b/actionpack/lib/action_controller/api.rb index 6bbebb7b4c..5cd8d77ddb 100644 --- a/actionpack/lib/action_controller/api.rb +++ b/actionpack/lib/action_controller/api.rb @@ -1,6 +1,6 @@ -require 'action_view' -require 'action_controller' -require 'action_controller/log_subscriber' +require "action_view" +require "action_controller" +require "action_controller/log_subscriber" module ActionController # API Controller is a lightweight version of <tt>ActionController::Base</tt>, diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index d546d7260c..ca8066cd82 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -1,4 +1,4 @@ -require 'action_view' +require "action_view" require "action_controller/log_subscriber" require "action_controller/metal/params_wrapper" @@ -32,7 +32,7 @@ module ActionController # new post), it initiates a redirect instead. This redirect works by returning an external # "302 Moved" HTTP response that takes the user to the index action. # - # These two methods represent the two basic action archetypes used in Action Controllers. Get-and-show and do-and-redirect. + # These two methods represent the two basic action archetypes used in Action Controllers: Get-and-show and do-and-redirect. # Most actions are variations on these themes. # # == Requests @@ -51,8 +51,8 @@ module ActionController # == Parameters # # All request parameters, whether they come from a query string in the URL or form data submitted through a POST request are - # available through the params method which returns a hash. For example, an action that was performed through - # <tt>/posts?category=All&limit=5</tt> will include <tt>{ "category" => "All", "limit" => "5" }</tt> in params. + # available through the <tt>params</tt> method which returns a hash. For example, an action that was performed through + # <tt>/posts?category=All&limit=5</tt> will include <tt>{ "category" => "All", "limit" => "5" }</tt> in <tt>params</tt>. # # It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as: # @@ -60,7 +60,7 @@ module ActionController # <input type="text" name="post[address]" value="hyacintvej"> # # A request stemming from a form holding these inputs will include <tt>{ "post" => { "name" => "david", "address" => "hyacintvej" } }</tt>. - # If the address input had been named <tt>post[address][street]</tt>, the params would have included + # If the address input had been named <tt>post[address][street]</tt>, the <tt>params</tt> would have included # <tt>{ "post" => { "address" => { "street" => "hyacintvej" } } }</tt>. There's no limit to the depth of the nesting. # # == Sessions @@ -213,11 +213,12 @@ module ActionController Renderers::All, ConditionalGet, EtagWithTemplateDigest, + EtagWithFlash, Caching, MimeResponds, ImplicitRender, StrongParameters, - + ParameterEncoding, Cookies, Flash, FormBuilder, diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb index a0917b4fdb..d29a5fe68f 100644 --- a/actionpack/lib/action_controller/log_subscriber.rb +++ b/actionpack/lib/action_controller/log_subscriber.rb @@ -51,7 +51,7 @@ module ActionController def unpermitted_parameters(event) debug do unpermitted_keys = event.payload[:keys] - "Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.join(", ")}" + "Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.map { |e| ":#{e}" }.join(", ")}" end end @@ -59,7 +59,7 @@ module ActionController expire_fragment expire_page write_page).each do |method| class_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{method}(event) - return unless logger.info? + return unless logger.info? && ActionController::Base.enable_fragment_cache_logging key_or_path = event.payload[:key] || event.payload[:path] human_name = #{method.to_s.humanize.inspect} info("\#{human_name} \#{key_or_path} (\#{event.duration.round(1)}ms)") diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index f6e67b02d7..ed93a2f09c 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/array/extract_options' -require 'action_dispatch/middleware/stack' -require 'action_dispatch/http/request' -require 'action_dispatch/http/response' +require "active_support/core_ext/array/extract_options" +require "action_dispatch/middleware/stack" +require "action_dispatch/http/request" +require "action_dispatch/http/response" module ActionController # Extend ActionDispatch middleware stack to make it aware of options @@ -34,29 +34,29 @@ module ActionController private - INCLUDE = ->(list, action) { list.include? action } - EXCLUDE = ->(list, action) { !list.include? action } - NULL = ->(list, action) { true } - - def build_middleware(klass, args, block) - options = args.extract_options! - only = Array(options.delete(:only)).map(&:to_s) - except = Array(options.delete(:except)).map(&:to_s) - args << options unless options.empty? - - strategy = NULL - list = nil - - if only.any? - strategy = INCLUDE - list = only - elsif except.any? - strategy = EXCLUDE - list = except - end + INCLUDE = ->(list, action) { list.include? action } + EXCLUDE = ->(list, action) { !list.include? action } + NULL = ->(list, action) { true } + + def build_middleware(klass, args, block) + options = args.extract_options! + only = Array(options.delete(:only)).map(&:to_s) + except = Array(options.delete(:except)).map(&:to_s) + args << options unless options.empty? + + strategy = NULL + list = nil + + if only.any? + strategy = INCLUDE + list = only + elsif except.any? + strategy = EXCLUDE + list = except + end - Middleware.new(get_class(klass), args, list, strategy, block) - end + Middleware.new(klass, args, list, strategy, block) + end end # <tt>ActionController::Metal</tt> is the simplest possible controller, providing a @@ -130,7 +130,7 @@ module ActionController # ==== Returns # * <tt>string</tt> def self.controller_name - @controller_name ||= name.demodulize.sub(/Controller$/, '').underscore + @controller_name ||= name.demodulize.sub(/Controller$/, "").underscore end def self.make_response!(request) @@ -139,15 +139,19 @@ module ActionController end end + def self.encoding_for_param(action, param) # :nodoc: + ::Encoding::UTF_8 + end + # Delegates to the class' <tt>controller_name</tt> def controller_name self.class.controller_name end attr_internal :response, :request - delegate :session, :to => "@_request" + delegate :session, to: "@_request" delegate :headers, :status=, :location=, :content_type=, - :status, :location, :content_type, :to => "@_response" + :status, :location, :content_type, to: "@_response" def initialize @_request = nil diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb index e21449f376..89bf60a0bb 100644 --- a/actionpack/lib/action_controller/metal/conditional_get.rb +++ b/actionpack/lib/action_controller/metal/conditional_get.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/hash/keys" module ActionController module ConditionalGet @@ -232,20 +232,21 @@ module ActionController # The method will also ensure an HTTP Date header for client compatibility. def expires_in(seconds, options = {}) response.cache_control.merge!( - :max_age => seconds, - :public => options.delete(:public), - :must_revalidate => options.delete(:must_revalidate) + max_age: seconds, + public: options.delete(:public), + must_revalidate: options.delete(:must_revalidate) ) options.delete(:private) - response.cache_control[:extras] = options.map {|k,v| "#{k}=#{v}"} + response.cache_control[:extras] = options.map { |k,v| "#{k}=#{v}" } response.date = Time.now unless response.date? end - # Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should - # occur by the browser or intermediate caches (like caching proxy servers). + # Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt>. This means the + # resource will be marked as stale, so clients must always revalidate. + # Intermediate/browser caches may still store the asset. def expires_now - response.cache_control.replace(:no_cache => true) + response.cache_control.replace(no_cache: true) end # Cache or yield the block. The cache is supposed to never expire. diff --git a/actionpack/lib/action_controller/metal/data_streaming.rb b/actionpack/lib/action_controller/metal/data_streaming.rb index 6cd6130032..f089c8423b 100644 --- a/actionpack/lib/action_controller/metal/data_streaming.rb +++ b/actionpack/lib/action_controller/metal/data_streaming.rb @@ -1,4 +1,4 @@ -require 'action_controller/metal/exceptions' +require "action_controller/metal/exceptions" module ActionController #:nodoc: # Methods for sending arbitrary data and for streaming files to the browser, @@ -8,8 +8,8 @@ module ActionController #:nodoc: include ActionController::Rendering - DEFAULT_SEND_FILE_TYPE = 'application/octet-stream'.freeze #:nodoc: - DEFAULT_SEND_FILE_DISPOSITION = 'attachment'.freeze #:nodoc: + DEFAULT_SEND_FILE_TYPE = "application/octet-stream".freeze #:nodoc: + DEFAULT_SEND_FILE_DISPOSITION = "attachment".freeze #:nodoc: protected # Sends the file. This uses a server-appropriate method (such as X-Sendfile) @@ -64,12 +64,13 @@ module ActionController #:nodoc: # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 # for the Cache-Control header spec. def send_file(path, options = {}) #:doc: - raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path) + raise MissingFile, "Cannot read file #{path}" unless File.file?(path) && File.readable?(path) options[:filename] ||= File.basename(path) unless options[:url_based_filename] send_file_headers! options self.status = options[:status] || 200 + self.content_type = options[:type] if options.key?(:type) self.content_type = options[:content_type] if options.key?(:content_type) response.send_file path end @@ -122,7 +123,7 @@ module ActionController #:nodoc: else if !type_provided && options[:filename] # If type wasn't provided, try guessing from file extension. - content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.delete('.')) || content_type + content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.delete(".")) || content_type end self.content_type = content_type end @@ -131,10 +132,10 @@ module ActionController #:nodoc: unless disposition.nil? disposition = disposition.to_s disposition += %(; filename="#{options[:filename]}") if options[:filename] - headers['Content-Disposition'] = disposition + headers["Content-Disposition"] = disposition end - headers['Content-Transfer-Encoding'] = 'binary' + headers["Content-Transfer-Encoding"] = "binary" response.sending_file = true diff --git a/actionpack/lib/action_controller/metal/etag_with_flash.rb b/actionpack/lib/action_controller/metal/etag_with_flash.rb new file mode 100644 index 0000000000..474d75f02e --- /dev/null +++ b/actionpack/lib/action_controller/metal/etag_with_flash.rb @@ -0,0 +1,16 @@ +module ActionController + # When you're using the flash, it's generally used as a conditional on the view. + # This means the content of the view depends on the flash. Which in turn means + # that the etag for a response should be computed with the content of the flash + # in mind. This does that by including the content of the flash as a component + # in the etag that's generated for a response. + module EtagWithFlash + extend ActiveSupport::Concern + + include ActionController::ConditionalGet + + included do + etag { flash unless flash.empty? } + end + end +end diff --git a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb index 669cf55bca..6c103bb042 100644 --- a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb +++ b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb @@ -33,18 +33,24 @@ module ActionController end private - def determine_template_etag(options) - if template = pick_template_for_etag(options) - lookup_and_digest_template(template) + def determine_template_etag(options) + if template = pick_template_for_etag(options) + lookup_and_digest_template(template) + end end - end - def pick_template_for_etag(options) - options.fetch(:template) { "#{controller_name}/#{action_name}" } - end + # Pick the template digest to include in the ETag. If the +:template+ option + # is present, use the named template. If +:template+ is nil or absent, use + # the default controller/action template. If +:template+ is false, omit the + # template digest from the ETag. + def pick_template_for_etag(options) + unless options[:template] == false + options[:template] || "#{controller_path}/#{action_name}" + end + end - def lookup_and_digest_template(template) - ActionView::Digestor.digest name: template, finder: lookup_context - end + def lookup_and_digest_template(template) + ActionView::Digestor.digest name: template, finder: lookup_context + end end end diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb index 5c0ada37be..3761e6172b 100644 --- a/actionpack/lib/action_controller/metal/exceptions.rb +++ b/actionpack/lib/action_controller/metal/exceptions.rb @@ -3,20 +3,10 @@ module ActionController end class BadRequest < ActionControllerError #:nodoc: - def initialize(msg = nil, e = nil) - if e - ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ - "Exceptions will automatically capture the original exception.", caller) - end - + def initialize(msg = nil) super(msg) set_backtrace $!.backtrace if $! end - - def original_exception - ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) - cause - end end class RenderError < ActionControllerError #:nodoc: @@ -35,7 +25,7 @@ module ActionController class MethodNotAllowed < ActionControllerError #:nodoc: def initialize(*allowed_methods) - super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.") + super("Only #{allowed_methods.to_sentence(locale: :en)} requests are allowed.") end end @@ -49,7 +39,7 @@ module ActionController end class SessionOverflowError < ActionControllerError #:nodoc: - DEFAULT_MESSAGE = 'Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data.' + DEFAULT_MESSAGE = "Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data." def initialize(message = nil) super(message || DEFAULT_MESSAGE) diff --git a/actionpack/lib/action_controller/metal/force_ssl.rb b/actionpack/lib/action_controller/metal/force_ssl.rb index ea8e91ce24..b8976497a4 100644 --- a/actionpack/lib/action_controller/metal/force_ssl.rb +++ b/actionpack/lib/action_controller/metal/force_ssl.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/slice' +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" module ActionController # This module provides a method which will redirect the browser to use HTTPS @@ -76,10 +76,10 @@ module ActionController def force_ssl_redirect(host_or_options = nil) unless request.ssl? options = { - :protocol => 'https://', - :host => request.host, - :path => request.fullpath, - :status => :moved_permanently + protocol: "https://", + host: request.host, + path: request.fullpath, + status: :moved_permanently } if host_or_options.is_a?(Hash) diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb index 5e9832fd4e..4dff23dd85 100644 --- a/actionpack/lib/action_controller/metal/head.rb +++ b/actionpack/lib/action_controller/metal/head.rb @@ -18,13 +18,7 @@ module ActionController # See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list of valid +status+ symbols. def head(status, options = {}) if status.is_a?(Hash) - msg = status[:status] ? 'The :status option' : 'The implicit :ok status' - options, status = status, status.delete(:status) - - ActiveSupport::Deprecation.warn(<<-MSG.squish) - #{msg} on `head` has been deprecated and will be removed in Rails 5.1. - Please pass the status as a separate parameter before the options, instead. - MSG + raise ArgumentError, "#{status.inspect} is not a valid value for `status`." end status ||= :ok @@ -33,7 +27,7 @@ module ActionController content_type = options.delete(:content_type) options.each do |key, value| - headers[key.to_s.dasherize.split('-').each { |v| v[0] = v[0].chr.upcase }.join('-')] = value.to_s + headers[key.to_s.dasherize.split("-").each { |v| v[0] = v[0].chr.upcase }.join("-")] = value.to_s end self.status = status @@ -41,7 +35,7 @@ module ActionController self.response_body = "" - if include_content?(self.response_code) + if include_content?(response_code) self.content_type = content_type || (Mime[formats.first] if formats) self.response.charset = false end @@ -50,15 +44,15 @@ module ActionController end private - def include_content?(status) - case status - when 100..199 - false - when 204, 205, 304 - false - else - true + def include_content?(status) + case status + when 100..199 + false + when 204, 205, 304 + false + else + true + end end - end end end diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 295f0cb66f..476d081239 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -108,10 +108,10 @@ module ActionController end private - # Extract helper names from files in <tt>app/helpers/**/*_helper.rb</tt> - def all_application_helpers - all_helpers_from_path(helpers_path) - end + # Extract helper names from files in <tt>app/helpers/**/*_helper.rb</tt> + def all_application_helpers + all_helpers_from_path(helpers_path) + end end # Provides a proxy to access helper methods from outside the view. diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 4639348509..a335bf109e 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -1,5 +1,5 @@ -require 'base64' -require 'active_support/security_utils' +require "base64" +require "active_support/security_utils" module ActionController # Makes it dead easy to do HTTP Basic, Digest and Token authentication. @@ -99,23 +99,23 @@ module ActionController end def has_basic_credentials?(request) - request.authorization.present? && (auth_scheme(request).downcase == 'basic') + request.authorization.present? && (auth_scheme(request).downcase == "basic") end def user_name_and_password(request) - decode_credentials(request).split(':', 2) + decode_credentials(request).split(":", 2) end def decode_credentials(request) - ::Base64.decode64(auth_param(request) || '') + ::Base64.decode64(auth_param(request) || "") end def auth_scheme(request) - request.authorization.to_s.split(' ', 2).first + request.authorization.to_s.split(" ", 2).first end def auth_param(request) - request.authorization.to_s.split(' ', 2).second + request.authorization.to_s.split(" ", 2).second end def encode_credentials(user_name, password) @@ -208,7 +208,7 @@ module ActionController password = password_procedure.call(credentials[:username]) return false unless password - method = request.get_header('rack.methodoverride.original_method') || request.get_header('REQUEST_METHOD') + method = request.get_header("rack.methodoverride.original_method") || request.get_header("REQUEST_METHOD") uri = credentials[:uri] [true, false].any? do |trailing_question_mark| @@ -226,17 +226,17 @@ module ActionController # of a plain-text password. def expected_response(http_method, uri, credentials, password, password_is_ha1=true) ha1 = password_is_ha1 ? password : ha1(credentials, password) - ha2 = ::Digest::MD5.hexdigest([http_method.to_s.upcase, uri].join(':')) - ::Digest::MD5.hexdigest([ha1, credentials[:nonce], credentials[:nc], credentials[:cnonce], credentials[:qop], ha2].join(':')) + ha2 = ::Digest::MD5.hexdigest([http_method.to_s.upcase, uri].join(":")) + ::Digest::MD5.hexdigest([ha1, credentials[:nonce], credentials[:nc], credentials[:cnonce], credentials[:qop], ha2].join(":")) end def ha1(credentials, password) - ::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(':')) + ::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(":")) end def encode_credentials(http_method, credentials, password, password_is_ha1) credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password, password_is_ha1) - "Digest " + credentials.sort_by {|x| x[0].to_s }.map {|v| "#{v[0]}='#{v[1]}'" }.join(', ') + "Digest " + credentials.sort_by { |x| x[0].to_s }.map { |v| "#{v[0]}='#{v[1]}'" }.join(", ") end def decode_credentials_header(request) @@ -244,9 +244,9 @@ module ActionController end def decode_credentials(header) - ActiveSupport::HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/, '').split(',').map do |pair| - key, value = pair.split('=', 2) - [key.strip, value.to_s.gsub(/^"|"$/,'').delete('\'')] + ActiveSupport::HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/, "").split(",").map do |pair| + key, value = pair.split("=", 2) + [key.strip, value.to_s.gsub(/^"|"$/,"").delete('\'')] end] end @@ -324,7 +324,6 @@ module ActionController def opaque(secret_key) ::Digest::MD5.hexdigest(secret_key) end - end # Makes it dead easy to do HTTP Token authentication. @@ -406,7 +405,7 @@ module ActionController # # RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L] module Token - TOKEN_KEY = 'token=' + TOKEN_KEY = "token=" TOKEN_REGEX = /^(Token|Bearer)\s+/ AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/ extend self @@ -476,14 +475,14 @@ module ActionController # This removes the <tt>"</tt> characters wrapping the value. def rewrite_param_values(array_params) - array_params.each { |param| (param[1] || "").gsub! %r/^"|"$/, '' } + array_params.each { |param| (param[1] || "").gsub! %r/^"|"$/, "" } end # This method takes an authorization body and splits up the key-value # pairs by the standardized <tt>:</tt>, <tt>;</tt>, or <tt>\t</tt> # delimiters defined in +AUTHN_PAIR_DELIMITERS+. def raw_params(auth) - _raw_params = auth.sub(TOKEN_REGEX, '').split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/) + _raw_params = auth.sub(TOKEN_REGEX, "").split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/) if !(_raw_params.first =~ %r{\A#{TOKEN_KEY}}) _raw_params[0] = "#{TOKEN_KEY}#{_raw_params.first}" diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb index 6192fc0f9c..8615c16c6f 100644 --- a/actionpack/lib/action_controller/metal/implicit_render.rb +++ b/actionpack/lib/action_controller/metal/implicit_render.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/strip' +require "active_support/core_ext/string/strip" module ActionController # Handles implicit rendering for a controller action that does not @@ -27,7 +27,6 @@ module ActionController # Finally, if we DON'T find a template AND the request isn't a browser page # load, then we implicitly respond with 204 No Content. module ImplicitRender - # :stopdoc: include BasicImplicitRender @@ -49,7 +48,7 @@ module ActionController "NOTE! For XHR/Ajax or API requests, this action would normally " \ "respond with 204 No Content: an empty white screen. Since you're " \ "loading it in a web browser, we assume that you expected to " \ - "actually render a template, not… nothing, so we're showing an " \ + "actually render a template, not nothing, so we're showing an " \ "error to be extra-clear. If you expect 204 No Content, carry on. " \ "That's what you'll get from an XHR or API request. Give it a shot." @@ -62,8 +61,8 @@ module ActionController def method_for_action(action_name) super || if template_exists?(action_name.to_s, _prefixes) - "default_render" - end + "default_render" + end end private diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb index 624a6d5b76..2ede96c667 100644 --- a/actionpack/lib/action_controller/metal/instrumentation.rb +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -1,5 +1,5 @@ -require 'benchmark' -require 'abstract_controller/logger' +require "benchmark" +require "abstract_controller/logger" module ActionController # Adds instrumentation to several ends in ActionController::Base. It also provides @@ -16,13 +16,13 @@ module ActionController def process_action(*args) raw_payload = { - :controller => self.class.name, - :action => self.action_name, - :params => request.filtered_parameters, - :headers => request.headers, - :format => request.format.ref, - :method => request.request_method, - :path => request.fullpath + controller: self.class.name, + action: action_name, + params: request.filtered_parameters, + headers: request.headers, + format: request.format.ref, + method: request.request_method, + path: request.fullpath } ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup) @@ -48,7 +48,7 @@ module ActionController def send_file(path, options={}) ActiveSupport::Notifications.instrument("send_file.action_controller", - options.merge(:path => path)) do + options.merge(path: path)) do super end end @@ -72,7 +72,7 @@ module ActionController # A hook invoked every time a before callback is halted. def halted_callback_hook(filter) - ActiveSupport::Notifications.instrument("halted_callback.action_controller", :filter => filter) + ActiveSupport::Notifications.instrument("halted_callback.action_controller", filter: filter) end # A hook which allows you to clean up any time, wrongly taken into account in diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb index 5d395cd8bd..26a16104db 100644 --- a/actionpack/lib/action_controller/metal/live.rb +++ b/actionpack/lib/action_controller/metal/live.rb @@ -1,6 +1,6 @@ -require 'action_dispatch/http/response' -require 'delegate' -require 'active_support/json' +require "action_dispatch/http/response" +require "delegate" +require "active_support/json" module ActionController # Mix this module into your controller, and all actions in that controller @@ -84,7 +84,6 @@ module ActionController # Note: SSEs are not currently supported by IE. However, they are supported # by Chrome, Firefox, Opera, and Safari. class SSE - WHITELISTED_OPTIONS = %w( retry event id ) def initialize(stream, options = {}) @@ -206,7 +205,12 @@ module ActionController private def each_chunk(&block) - while str = @buf.pop + loop do + str = nil + ActiveSupport::Dependencies.interlock.permit_concurrent_loads do + str = @buf.pop + end + break unless str yield str end end @@ -215,18 +219,18 @@ module ActionController class Response < ActionDispatch::Response #:nodoc: all private - def before_committed - super - jar = request.cookie_jar - # The response can be committed multiple times - jar.write self unless committed? - end + def before_committed + super + jar = request.cookie_jar + # The response can be committed multiple times + jar.write self unless committed? + end - def build_buffer(response, body) - buf = Live::Buffer.new response - body.each { |part| buf.write part } - buf - end + def build_buffer(response, body) + buf = Live::Buffer.new response + body.each { |part| buf.write part } + buf + end end def process(name) diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 2e89af1a5e..f6aabcb102 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -1,4 +1,4 @@ -require 'abstract_controller/collector' +require "abstract_controller/collector" module ActionController #:nodoc: module MimeResponds @@ -280,8 +280,8 @@ module ActionController #:nodoc: def any(*args, &block) if block_given? - if args.any? && args.none?{ |a| a == @variant } - args.each{ |v| @variants[v] = block } + if args.any? && args.none? { |a| a == @variant } + args.each { |v| @variants[v] = block } else @variants[:any] = block end diff --git a/actionpack/lib/action_controller/metal/parameter_encoding.rb b/actionpack/lib/action_controller/metal/parameter_encoding.rb new file mode 100644 index 0000000000..c457fd0d06 --- /dev/null +++ b/actionpack/lib/action_controller/metal/parameter_encoding.rb @@ -0,0 +1,30 @@ +module ActionController + # Allows encoding to be specified per parameter per action. + module ParameterEncoding + extend ActiveSupport::Concern + + module ClassMethods + def inherited(klass) # :nodoc: + super + klass.setup_param_encode + end + + def setup_param_encode # :nodoc: + @_parameter_encodings = {} + end + + def encoding_for_param(action, param) # :nodoc: + if @_parameter_encodings[action.to_s] && @_parameter_encodings[action.to_s][param.to_s] + @_parameter_encodings[action.to_s][param.to_s] + else + super + end + end + + def parameter_encoding(action, param_name, encoding) + @_parameter_encodings[action.to_s] ||= {} + @_parameter_encodings[action.to_s][param_name.to_s] = encoding + end + end + end +end diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index c38fc40b81..9d1b740025 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/module/anonymous' -require 'action_dispatch/http/mime_type' +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/module/anonymous" +require "action_dispatch/http/mime_type" module ActionController # Wraps the parameters hash into a nested hash. This will allow clients to @@ -71,7 +71,7 @@ module ActionController EXCLUDE_PARAMETERS = %w(authenticity_token _method utf8) - require 'mutex_m' + require "mutex_m" class Options < Struct.new(:name, :format, :include, :exclude, :klass, :model) # :nodoc: include Mutex_m @@ -128,30 +128,30 @@ module ActionController end private - # Determine the wrapper model from the controller's name. By convention, - # this could be done by trying to find the defined model that has the - # same singular name as the controller. For example, +UsersController+ - # will try to find if the +User+ model exists. - # - # This method also does namespace lookup. Foo::Bar::UsersController will - # try to find Foo::Bar::User, Foo::User and finally User. - def _default_wrap_model #:nodoc: - return nil if klass.anonymous? - model_name = klass.name.sub(/Controller$/, '').classify - - begin - if model_klass = model_name.safe_constantize - model_klass - else - namespaces = model_name.split("::") - namespaces.delete_at(-2) - break if namespaces.last == model_name - model_name = namespaces.join("::") - end - end until model_klass + # Determine the wrapper model from the controller's name. By convention, + # this could be done by trying to find the defined model that has the + # same singular name as the controller. For example, +UsersController+ + # will try to find if the +User+ model exists. + # + # This method also does namespace lookup. Foo::Bar::UsersController will + # try to find Foo::Bar::User, Foo::User and finally User. + def _default_wrap_model #:nodoc: + return nil if klass.anonymous? + model_name = klass.name.sub(/Controller$/, "").classify + + begin + if model_klass = model_name.safe_constantize + model_klass + else + namespaces = model_name.split("::") + namespaces.delete_at(-2) + break if namespaces.last == model_name + model_name = namespaces.join("::") + end + end until model_klass - model_klass - end + model_klass + end end included do @@ -198,9 +198,9 @@ module ActionController when Hash options = name_or_model_or_options when false - options = options.merge(:format => []) + options = options.merge(format: []) when Symbol, String - options = options.merge(:name => name_or_model_or_options) + options = options.merge(name: name_or_model_or_options) else model = name_or_model_or_options end diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index 3c7cc15627..2b060e3698 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -24,10 +24,10 @@ module ActionController # === Examples: # # redirect_to action: "show", id: 5 - # redirect_to post + # redirect_to @post # redirect_to "http://www.rubyonrails.org" # redirect_to "/images/screenshot.jpg" - # redirect_to articles_url + # redirect_to posts_url # redirect_to proc { edit_post_url(@post) } # # The redirection happens as a "302 Found" header unless otherwise specified using the <tt>:status</tt> option: @@ -77,11 +77,11 @@ module ActionController # is missing this header, the <tt>fallback_location</tt> will be used. # # redirect_back fallback_location: { action: "show", id: 5 } - # redirect_back fallback_location: post + # redirect_back fallback_location: @post # redirect_back fallback_location: "http://www.rubyonrails.org" - # redirect_back fallback_location: "/images/screenshot.jpg" - # redirect_back fallback_location: articles_url - # redirect_back fallback_location: proc { edit_post_url(@post) } + # redirect_back fallback_location: "/images/screenshot.jpg" + # redirect_back fallback_location: posts_url + # redirect_back fallback_location: proc { edit_post_url(@post) } # # All options that can be passed to <tt>redirect_to</tt> are accepted as # options and the behavior is identical. @@ -104,14 +104,6 @@ module ActionController options when String request.protocol + request.host_with_port + options - when :back - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - `redirect_to :back` is deprecated and will be removed from Rails 5.1. - Please use `redirect_back(fallback_location: fallback_location)` where - `fallback_location` represents the location to use if the request has - no HTTP referer information. - MESSAGE - request.headers["Referer"] or raise RedirectBackError when Proc _compute_redirect_to_location request, options.call else diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 1735609cd9..f8a037189c 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -1,4 +1,4 @@ -require 'set' +require "set" module ActionController # See <tt>Renderers.add</tt> @@ -71,8 +71,6 @@ module ActionController # format.csv { render csv: @csvable, filename: @csvable.name } # end # end - # To use renderers and their mime types in more concise ways, see - # <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt> def self.add(key, &block) define_method(_render_with_renderer_method_name(key), &block) RENDERERS << key.to_sym @@ -94,7 +92,6 @@ module ActionController end module ClassMethods - # Adds, by name, a renderer or renderers to the +_renderers+ available # to call within controller actions. # diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index cce6fe7787..67365a143e 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -1,10 +1,10 @@ -require 'active_support/core_ext/string/filters' +require "active_support/core_ext/string/filters" module ActionController module Rendering extend ActiveSupport::Concern - RENDER_FORMATS_IN_PRIORITY = [:body, :text, :plain, :html] + RENDER_FORMATS_IN_PRIORITY = [:body, :plain, :html] module ClassMethods # Documentation at ActionController::Renderer#render @@ -32,7 +32,7 @@ module ActionController # Check for double render errors and set the content_type after rendering. def render(*args) #:nodoc: - raise ::AbstractController::DoubleRenderError if self.response_body + raise ::AbstractController::DoubleRenderError if response_body super end @@ -49,84 +49,68 @@ module ActionController end def render_to_body(options = {}) - super || _render_in_priorities(options) || ' ' + super || _render_in_priorities(options) || " " end private - def _render_in_priorities(options) - RENDER_FORMATS_IN_PRIORITY.each do |format| - return options[format] if options.key?(format) - end - - nil - end - - def _set_html_content_type - self.content_type = Mime[:html].to_s - end + def _render_in_priorities(options) + RENDER_FORMATS_IN_PRIORITY.each do |format| + return options[format] if options.key?(format) + end - def _set_rendered_content_type(format) - unless response.content_type - self.content_type = format.to_s + nil end - end - - # Normalize arguments by catching blocks and setting them on :update. - def _normalize_args(action=nil, options={}, &blk) #:nodoc: - options = super - options[:update] = blk if block_given? - options - end - # Normalize both text and status options. - def _normalize_options(options) #:nodoc: - _normalize_text(options) - - if options[:text] - ActiveSupport::Deprecation.warn <<-WARNING.squish - `render :text` is deprecated because it does not actually render a - `text/plain` response. Switch to `render plain: 'plain text'` to - render as `text/plain`, `render html: '<strong>HTML</strong>'` to - render as `text/html`, or `render body: 'raw'` to match the deprecated - behavior and render with the default Content-Type, which is - `text/plain`. - WARNING + def _set_html_content_type + self.content_type = Mime[:html].to_s end - if options[:html] - options[:html] = ERB::Util.html_escape(options[:html]) + def _set_rendered_content_type(format) + unless response.content_type + self.content_type = format.to_s + end end - if options.delete(:nothing) - ActiveSupport::Deprecation.warn("`:nothing` option is deprecated and will be removed in Rails 5.1. Use `head` method to respond with empty response body.") - options[:body] = nil + # Normalize arguments by catching blocks and setting them on :update. + def _normalize_args(action=nil, options={}, &blk) #:nodoc: + options = super + options[:update] = blk if block_given? + options end - if options[:status] - options[:status] = Rack::Utils.status_code(options[:status]) - end + # Normalize both text and status options. + def _normalize_options(options) #:nodoc: + _normalize_text(options) - super - end + if options[:html] + options[:html] = ERB::Util.html_escape(options[:html]) + end - def _normalize_text(options) - RENDER_FORMATS_IN_PRIORITY.each do |format| - if options.key?(format) && options[format].respond_to?(:to_text) - options[format] = options[format].to_text + if options[:status] + options[:status] = Rack::Utils.status_code(options[:status]) + end + + super + end + + def _normalize_text(options) + RENDER_FORMATS_IN_PRIORITY.each do |format| + if options.key?(format) && options[format].respond_to?(:to_text) + options[format] = options[format].to_text + end end end - end - # Process controller specific options, as status, content-type and location. - def _process_options(options) #:nodoc: - status, content_type, location = options.values_at(:status, :content_type, :location) + # Process controller specific options, as status, content-type and location. + def _process_options(options) #:nodoc: + status, content_type, location = options.values_at(:status, :content_type, :location) - self.status = status if status - self.content_type = content_type if content_type - self.headers["Location"] = url_for(location) if location + self.status = status if status + self.content_type = content_type if content_type + self.headers["Location"] = url_for(location) if location - super - end + super + end end end diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 0559fbc6ce..3d3c121280 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -1,6 +1,6 @@ -require 'rack/session/abstract/id' -require 'action_controller/metal/exceptions' -require 'active_support/security_utils' +require "rack/session/abstract/id" +require "action_controller/metal/exceptions" +require "active_support/security_utils" module ActionController #:nodoc: class InvalidAuthenticityToken < ActionControllerError #:nodoc: @@ -109,10 +109,10 @@ module ActionController #:nodoc: # * <tt>:only/:except</tt> - Only apply forgery protection to a subset of actions. For example <tt>only: [ :create, :create_all ]</tt>. # * <tt>:if/:unless</tt> - Turn off the forgery protection entirely depending on the passed Proc or method reference. # * <tt>:prepend</tt> - By default, the verification of the authentication token will be added at the position of the - # protect_from_forgery call in your application. This means any callbacks added before are run first. This is useful - # when you want your forgery protection to depend on other callbacks, like authentication methods (Oauth vs Cookie auth). + # protect_from_forgery call in your application. This means any callbacks added before are run first. This is useful + # when you want your forgery protection to depend on other callbacks, like authentication methods (Oauth vs Cookie auth). # - # If you need to add verification to the beginning of the callback chain, use <tt>prepend: true</tt>. + # If you need to add verification to the beginning of the callback chain, use <tt>prepend: true</tt>. # * <tt>:with</tt> - Set the method to handle unverified request. # # Valid unverified request handling methods are: @@ -130,11 +130,11 @@ module ActionController #:nodoc: private - def protection_method_class(name) - ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify) - rescue NameError - raise ArgumentError, 'Invalid request forgery protection method, use :null_session, :exception, or :reset_session' - end + def protection_method_class(name) + ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify) + rescue NameError + raise ArgumentError, "Invalid request forgery protection method, use :null_session, :exception, or :reset_session" + end end module ProtectionMethods @@ -154,26 +154,26 @@ module ActionController #:nodoc: protected - class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc: - def initialize(req) - super(nil, req) - @data = {} - @loaded = true - end + class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc: + def initialize(req) + super(nil, req) + @data = {} + @loaded = true + end - # no-op - def destroy; end + # no-op + def destroy; end - def exists? - true + def exists? + true + end end - end - class NullCookieJar < ActionDispatch::Cookies::CookieJar #:nodoc: - def write(*) - # nothing + class NullCookieJar < ActionDispatch::Cookies::CookieJar #:nodoc: + def write(*) + # nothing + end end - end end class ResetSession @@ -382,7 +382,7 @@ module ActionController #:nodoc: def xor_byte_strings(s1, s2) s2_bytes = s2.bytes s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 } - s2_bytes.pack('C*') + s2_bytes.pack("C*") end # The form's authenticity parameter. Override to provide your own. @@ -408,7 +408,7 @@ module ActionController #:nodoc: def normalize_action_path(action_path) uri = URI.parse(action_path) - uri.path.chomp('/') + uri.path.chomp("/") end end end diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb index 17f4030f25..2d99e4045b 100644 --- a/actionpack/lib/action_controller/metal/rescue.rb +++ b/actionpack/lib/action_controller/metal/rescue.rb @@ -19,7 +19,7 @@ module ActionController #:nodoc: def process_action(*args) super rescue Exception => exception - request.env['action_dispatch.show_detailed_exceptions'] ||= show_detailed_exceptions? + request.env["action_dispatch.show_detailed_exceptions"] ||= show_detailed_exceptions? rescue_with_handler(exception) || raise end end diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index a6115674aa..481f19f1ef 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -1,4 +1,4 @@ -require 'rack/chunked' +require "rack/chunked" module ActionController #:nodoc: # Allows views to be streamed back to the client as they are rendered. diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 46589901fd..b64617d084 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -1,12 +1,14 @@ -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/hash/transform_values' -require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/string/filters' -require 'active_support/rescuable' -require 'action_dispatch/http/upload' -require 'rack/test' -require 'stringio' -require 'set' +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/hash/transform_values" +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/string/filters" +require "active_support/core_ext/object/to_query" +require "active_support/rescuable" +require "action_dispatch/http/upload" +require "rack/test" +require "stringio" +require "set" +require "yaml" module ActionController # Raised when a required parameter is missing. @@ -31,13 +33,13 @@ module ActionController # # params = ActionController::Parameters.new(a: "123", b: "456") # params.permit(:c) - # # => ActionController::UnpermittedParameters: found unpermitted parameters: a, b + # # => ActionController::UnpermittedParameters: found unpermitted parameters: :a, :b class UnpermittedParameters < IndexError attr_reader :params # :nodoc: def initialize(params) # :nodoc: @params = params - super("found unpermitted parameter#{'s' if params.size > 1 }: #{params.join(", ")}") + super("found unpermitted parameter#{'s' if params.size > 1 }: #{params.map { |e| ":#{e}" }.join(", ")}") end end @@ -58,8 +60,7 @@ module ActionController # }) # # permitted = params.require(:person).permit(:name, :age) - # permitted # => {"name"=>"Francesco", "age"=>22} - # permitted.class # => ActionController::Parameters + # permitted # => <ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true> # permitted.permitted? # => true # # Person.first.update!(permitted) @@ -87,7 +88,7 @@ module ActionController # # params = ActionController::Parameters.new(a: "123", b: "456") # params.permit(:c) - # # => {} + # # => <ActionController::Parameters {} permitted: true> # # ActionController::Parameters.action_on_unpermitted_parameters = :raise # @@ -107,6 +108,8 @@ module ActionController # params["key"] # => "value" class Parameters cattr_accessor :permit_all_parameters, instance_accessor: false + self.permit_all_parameters = false + cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?, @@ -148,15 +151,6 @@ module ActionController def ==(other) if other.respond_to?(:permitted?) self.permitted? == other.permitted? && self.parameters == other.parameters - elsif other.is_a?(Hash) - ActiveSupport::Deprecation.warn <<-WARNING.squish - Comparing equality between `ActionController::Parameters` and a - `Hash` is deprecated and will be removed in Rails 5.1. Please only do - comparisons between instances of `ActionController::Parameters`. If - you need to compare to a hash, first convert it using - `ActionController::Parameters#new`. - WARNING - @parameters == other.with_indifferent_access else @parameters == other end @@ -255,7 +249,7 @@ module ActionController # either present or the singleton +false+, returns said value: # # ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person) - # # => {"name"=>"Francesco"} + # # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false> # # Otherwise raises <tt>ActionController::ParameterMissing</tt>: # @@ -276,12 +270,12 @@ module ActionController # returned: # # params = ActionController::Parameters.new(user: { ... }, profile: { ... }) - # user_params, profile_params = params.require(:user, :profile) + # user_params, profile_params = params.require([:user, :profile]) # # Otherwise, the method re-raises the first exception found: # # params = ActionController::Parameters.new(user: {}, profile: {}) - # user_params, profile_params = params.require(:user, :profile) + # user_params, profile_params = params.require([:user, :profile]) # # ActionController::ParameterMissing: param is missing or the value is empty: user # # Technically this method can be used to fetch terminal values: @@ -374,13 +368,13 @@ module ActionController # }) # # params.require(:person).permit(:contact) - # # => {} + # # => <ActionController::Parameters {} permitted: true> # # params.require(:person).permit(contact: :phone) - # # => {"contact"=>{"phone"=>"555-1234"}} + # # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true> # # params.require(:person).permit(contact: [ :email, :phone ]) - # # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}} + # # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true> def permit(*filters) params = self.class.new @@ -402,7 +396,7 @@ module ActionController # returns +nil+. # # params = ActionController::Parameters.new(person: { name: 'Francesco' }) - # params[:person] # => {"name"=>"Francesco"} + # params[:person] # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false> # params[:none] # => nil def [](key) convert_hashes_to_parameters(key, @parameters[key]) @@ -421,7 +415,7 @@ module ActionController # is given, then that will be run and its result returned. # # params = ActionController::Parameters.new(person: { name: 'Francesco' }) - # params.fetch(:person) # => {"name"=>"Francesco"} + # params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false> # params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none # params.fetch(:none, 'Francesco') # => "Francesco" # params.fetch(:none) { 'Francesco' } # => "Francesco" @@ -457,8 +451,8 @@ module ActionController # don't exist, returns an empty hash. # # params = ActionController::Parameters.new(a: 1, b: 2, c: 3) - # params.slice(:a, :b) # => {"a"=>1, "b"=>2} - # params.slice(:d) # => {} + # params.slice(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false> + # params.slice(:d) # => <ActionController::Parameters {} permitted: false> def slice(*keys) new_instance_with_inherited_permitted_status(@parameters.slice(*keys)) end @@ -474,8 +468,8 @@ module ActionController # filters out the given +keys+. # # params = ActionController::Parameters.new(a: 1, b: 2, c: 3) - # params.except(:a, :b) # => {"c"=>3} - # params.except(:d) # => {"a"=>1,"b"=>2,"c"=>3} + # params.except(:a, :b) # => <ActionController::Parameters {"c"=>3} permitted: false> + # params.except(:d) # => <ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false> def except(*keys) new_instance_with_inherited_permitted_status(@parameters.except(*keys)) end @@ -483,8 +477,8 @@ module ActionController # Removes and returns the key/value pairs matching the given keys. # # params = ActionController::Parameters.new(a: 1, b: 2, c: 3) - # params.extract!(:a, :b) # => {"a"=>1, "b"=>2} - # params # => {"c"=>3} + # params.extract!(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false> + # params # => <ActionController::Parameters {"c"=>3} permitted: false> def extract!(*keys) new_instance_with_inherited_permitted_status(@parameters.extract!(*keys)) end @@ -494,7 +488,7 @@ module ActionController # # params = ActionController::Parameters.new(a: 1, b: 2, c: 3) # params.transform_values { |x| x * 2 } - # # => {"a"=>2, "b"=>4, "c"=>6} + # # => <ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false> def transform_values(&block) if block new_instance_with_inherited_permitted_status( @@ -571,25 +565,11 @@ module ActionController convert_value_to_parameters(@parameters.values_at(*keys)) end - # Returns an exact copy of the <tt>ActionController::Parameters</tt> - # instance. +permitted+ state is kept on the duped object. - # - # params = ActionController::Parameters.new(a: 1) - # params.permit! - # params.permitted? # => true - # copy_params = params.dup # => {"a"=>1} - # copy_params.permitted? # => true - def dup - super.tap do |duplicate| - duplicate.permitted = @permitted - end - end - # Returns a new <tt>ActionController::Parameters</tt> with all keys from # +other_hash+ merges into current hash. def merge(other_hash) new_instance_with_inherited_permitted_status( - @parameters.merge(other_hash) + @parameters.merge(other_hash.to_h) ) end @@ -604,21 +584,39 @@ module ActionController "<#{self.class} #{@parameters} permitted: #{@permitted}>" end - def method_missing(method_sym, *args, &block) - if @parameters.respond_to?(method_sym) - message = <<-DEPRECATE.squish - Method #{method_sym} is deprecated and will be removed in Rails 5.1, - as `ActionController::Parameters` no longer inherits from - hash. Using this deprecated behavior exposes potential security - problems. If you continue to use this method you may be creating - a security vulnerability in your app that can be exploited. Instead, - consider using one of these documented methods which are not - deprecated: http://api.rubyonrails.org/v#{ActionPack.version}/classes/ActionController/Parameters.html - DEPRECATE - ActiveSupport::Deprecation.warn(message) - @parameters.public_send(method_sym, *args, &block) - else - super + def self.hook_into_yaml_loading # :nodoc: + # Wire up YAML format compatibility with Rails 4.2 and Psych 2.0.8 and 2.0.9+. + # Makes the YAML parser call `init_with` when it encounters the keys below + # instead of trying its own parsing routines. + YAML.load_tags["!ruby/hash-with-ivars:ActionController::Parameters"] = name + YAML.load_tags["!ruby/hash:ActionController::Parameters"] = name + end + hook_into_yaml_loading + + def init_with(coder) # :nodoc: + case coder.tag + when "!ruby/hash:ActionController::Parameters" + # YAML 2.0.8's format where hash instance variables weren't stored. + @parameters = coder.map.with_indifferent_access + @permitted = false + when "!ruby/hash-with-ivars:ActionController::Parameters" + # YAML 2.0.9's Hash subclass format where keys and values + # were stored under an elements hash and `permitted` within an ivars hash. + @parameters = coder.map["elements"].with_indifferent_access + @permitted = coder.map["ivars"][:@permitted] + when "!ruby/object:ActionController::Parameters" + # YAML's Object format. Only needed because of the format + # backwardscompability above, otherwise equivalent to YAML's initialization. + @parameters, @permitted = coder.map["parameters"], coder.map["permitted"] + end + end + + undef_method :to_param + + # Returns duplicate of object including all parameters + def deep_dup + self.class.new(@parameters.deep_dup).tap do |duplicate| + duplicate.permitted = @permitted end end @@ -704,7 +702,7 @@ module ActionController end def unpermitted_keys(params) - self.keys - params.keys - self.always_permitted_parameters + keys - params.keys - always_permitted_parameters end # @@ -735,7 +733,7 @@ module ActionController ] def permitted_scalar?(value) - PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)} + PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) } end def permitted_scalar_filter(params, key) @@ -751,7 +749,7 @@ module ActionController end def array_of_permitted_scalars?(value) - if value.is_a?(Array) && value.all? {|element| permitted_scalar?(element)} + if value.is_a?(Array) && value.all? { |element| permitted_scalar?(element) } yield value end end @@ -782,6 +780,11 @@ module ActionController end end end + + def initialize_copy(source) + super + @parameters = @parameters.dup + end end # == Strong \Parameters diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index ac37b00010..9bb416178a 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -13,7 +13,7 @@ module ActionController module ClassMethods def before_filters - _process_action_callbacks.find_all{|x| x.kind == :before}.map(&:name) + _process_action_callbacks.find_all { |x| x.kind == :before }.map(&:name) end end end diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index dbf7241a14..9f3cc099d6 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -27,10 +27,10 @@ module ActionController def url_options @_url_options ||= { - :host => request.host, - :port => request.optional_port, - :protocol => request.protocol, - :_recall => request.path_parameters + host: request.host, + port: request.optional_port, + protocol: request.protocol, + _recall: request.path_parameters }.merge!(super).freeze if (same_origin = _routes.equal?(request.routes)) || diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 28b20052b5..6513a556ee 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -11,7 +11,7 @@ module ActionController config.eager_load_namespaces << ActionController - initializer "action_controller.assets_config", :group => :all do |app| + initializer "action_controller.assets_config", group: :all do |app| app.config.action_controller.assets_dir ||= app.config.paths["public"].first end diff --git a/actionpack/lib/action_controller/renderer.rb b/actionpack/lib/action_controller/renderer.rb index a8c8d66682..243a54330e 100644 --- a/actionpack/lib/action_controller/renderer.rb +++ b/actionpack/lib/action_controller/renderer.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/hash/keys" module ActionController # ActionController::Renderer allows you to render arbitrary templates @@ -37,11 +37,11 @@ module ActionController attr_reader :defaults, :controller DEFAULTS = { - http_host: 'example.org', + http_host: "example.org", https: false, - method: 'get', - script_name: '', - input: '' + method: "get", + script_name: "", + input: "" }.freeze # Create a new renderer instance for a specific controller class. @@ -69,7 +69,7 @@ module ActionController # Render templates with any options from ActionController::Base#render_to_string. def render(*args) - raise 'missing controller' unless controller + raise "missing controller" unless controller request = ActionDispatch::Request.new @env request.routes = controller._routes @@ -88,21 +88,23 @@ module ActionController end RACK_KEY_TRANSLATION = { - http_host: 'HTTP_HOST', - https: 'HTTPS', - method: 'REQUEST_METHOD', - script_name: 'SCRIPT_NAME', - input: 'rack.input' + http_host: "HTTP_HOST", + https: "HTTPS", + method: "REQUEST_METHOD", + script_name: "SCRIPT_NAME", + input: "rack.input" } IDENTITY = ->(_) { _ } RACK_VALUE_TRANSLATION = { - https: ->(v) { v ? 'on' : 'off' }, + https: ->(v) { v ? "on" : "off" }, method: ->(v) { v.upcase }, } - def rack_key_for(key); RACK_KEY_TRANSLATION[key]; end + def rack_key_for(key) + RACK_KEY_TRANSLATION.fetch(key, key.to_s) + end def rack_value_for(key, value) RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index b1b3e87934..33c0201951 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -1,13 +1,12 @@ -require 'rack/session/abstract/id' -require 'active_support/core_ext/hash/conversions' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/hash/keys' -require 'action_controller/template_assertions' -require 'rails-dom-testing' +require "rack/session/abstract/id" +require "active_support/core_ext/hash/conversions" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/hash/keys" +require "action_controller/template_assertions" +require "rails-dom-testing" module ActionController - # :stopdoc: class Metal include Testing::Functional end @@ -27,18 +26,20 @@ module ActionController # Please use ActionDispatch::IntegrationTest going forward. class TestRequest < ActionDispatch::TestRequest #:nodoc: DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup - DEFAULT_ENV.delete 'PATH_INFO' + DEFAULT_ENV.delete "PATH_INFO" def self.new_session TestSession.new end + attr_reader :controller_class + # Create a new test request with default `env` values - def self.create + def self.create(controller_class) env = {} env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application env["rack.request.cookie_hash"] = {}.with_indifferent_access - new(default_env.merge(env), new_session) + new(default_env.merge(env), new_session, controller_class) end def self.default_env @@ -46,13 +47,14 @@ module ActionController end private_class_method :default_env - def initialize(env, session) + def initialize(env, session, controller_class) super(env) self.session = session - self.session_options = TestSession::DEFAULT_OPTIONS + self.session_options = TestSession::DEFAULT_OPTIONS.dup + @controller_class = controller_class @custom_param_parsers = { - xml: lambda { |raw_post| Hash.from_xml(raw_post)['hash'] } + xml: lambda { |raw_post| Hash.from_xml(raw_post)["hash"] } } end @@ -61,7 +63,7 @@ module ActionController end def content_type=(type) - set_header 'CONTENT_TYPE', type + set_header "CONTENT_TYPE", type end def assign_parameters(routes, controller_path, action, parameters, generated_path, query_string_keys) @@ -83,7 +85,7 @@ module ActionController end if get? - if self.query_string.blank? + if query_string.blank? self.query_string = non_path_parameters.to_query end else @@ -91,8 +93,8 @@ module ActionController self.content_type = ENCODER.content_type data = ENCODER.build_multipart non_path_parameters else - fetch_header('CONTENT_TYPE') do |k| - set_header k, 'application/x-www-form-urlencoded' + fetch_header("CONTENT_TYPE") do |k| + set_header k, "application/x-www-form-urlencoded" end case content_mime_type.to_sym @@ -110,8 +112,8 @@ module ActionController end end - set_header 'CONTENT_LENGTH', data.length.to_s - set_header 'rack.input', StringIO.new(data) + set_header "CONTENT_LENGTH", data.length.to_s + set_header "rack.input", StringIO.new(data) end fetch_header("PATH_INFO") do |k| @@ -152,9 +154,9 @@ module ActionController private - def params_parsers - super.merge @custom_param_parsers - end + def params_parsers + super.merge @custom_param_parsers + end end class LiveTestResponse < Live::Response @@ -208,10 +210,18 @@ module ActionController end # Superclass for ActionController functional tests. Functional tests allow you to - # test a single controller action per test method. This should not be confused with - # integration tests (see ActionDispatch::IntegrationTest), which are more like - # "stories" that can involve multiple controllers and multiple actions (i.e. multiple - # different HTTP requests). + # test a single controller action per test method. + # + # == Use integration style controller tests over functional style controller tests. + # + # Rails discourages the use of functional tests in favor of integration tests + # (use ActionDispatch::IntegrationTest). + # + # New Rails applications no longer generate functional style controller tests and they should + # only be used for backward compatibility. Integration style controller tests perform actual + # requests, whereas functional style controller tests merely simulate a request. Besides, + # integration tests are as fast as functional tests and provide lot of helpers such as +as+, + # +parsed_body+ for effective testing of controller actions including even API endpoints. # # == Basic example # @@ -320,7 +330,6 @@ module ActionController attr_reader :response, :request module ClassMethods - # Sets the controller class name. Useful if the name can't be inferred from test class. # Normalizes +controller_class+ before using. # @@ -377,56 +386,41 @@ module ActionController # # Note that the request method is not verified. The different methods are # available to make the tests more expressive. - def get(action, *args) - res = process_with_kwargs("GET", action, *args) + def get(action, **args) + res = process(action, method: "GET", **args) cookies.update res.cookies res end # Simulate a POST request with the given parameters and set/volley the response. # See +get+ for more details. - def post(action, *args) - process_with_kwargs("POST", action, *args) + def post(action, **args) + process(action, method: "POST", **args) end # Simulate a PATCH request with the given parameters and set/volley the response. # See +get+ for more details. - def patch(action, *args) - process_with_kwargs("PATCH", action, *args) + def patch(action, **args) + process(action, method: "PATCH", **args) end # Simulate a PUT request with the given parameters and set/volley the response. # See +get+ for more details. - def put(action, *args) - process_with_kwargs("PUT", action, *args) + def put(action, **args) + process(action, method: "PUT", **args) end # Simulate a DELETE request with the given parameters and set/volley the response. # See +get+ for more details. - def delete(action, *args) - process_with_kwargs("DELETE", action, *args) + def delete(action, **args) + process(action, method: "DELETE", **args) end # Simulate a HEAD request with the given parameters and set/volley the response. # See +get+ for more details. - def head(action, *args) - process_with_kwargs("HEAD", action, *args) - end - - def xml_http_request(*args) - ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc) - xhr and xml_http_request methods are deprecated in favor of - `get :index, xhr: true` and `post :create, xhr: true` - MSG - - @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' - @request.env['HTTP_ACCEPT'] ||= [Mime[:js], Mime[:html], Mime[:xml], 'text/xml', '*/*'].join(', ') - __send__(*args).tap do - @request.env.delete 'HTTP_X_REQUESTED_WITH' - @request.env.delete 'HTTP_ACCEPT' - end + def head(action, **args) + process(action, method: "HEAD", **args) end - alias xhr :xml_http_request # Simulate an HTTP request to +action+ by specifying request method, # parameters and set/volley the response. @@ -440,6 +434,8 @@ module ActionController # - +session+: A hash of parameters to store in the session. This may be +nil+. # - +flash+: A hash of parameters to store in the flash. This may be +nil+. # - +format+: Request format. Defaults to +nil+. Can be string or symbol. + # - +as+: Content type. Defaults to +nil+. Must be a symbol that corresponds + # to a mime type. # # Example calling +create+ action and sending two params: # @@ -456,56 +452,39 @@ module ActionController # respectively which will make tests more expressive. # # Note that the request method is not verified. - def process(action, *args) + def process(action, method: "GET", params: {}, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil) check_required_ivars - if kwarg_request?(args) - parameters, session, body, flash, http_method, format, xhr = args[0].values_at(:params, :session, :body, :flash, :method, :format, :xhr) - else - http_method, parameters, session, flash = args - format = nil - - if parameters.is_a?(String) && http_method != 'HEAD' - body = parameters - parameters = nil - end - - if parameters || session || flash - non_kwarg_request_warning - end - end - if body - @request.set_header 'RAW_POST_DATA', body - end - - if http_method - http_method = http_method.to_s.upcase - else - http_method = "GET" + @request.set_header "RAW_POST_DATA", body end - parameters ||= {} - - if format - parameters[:format] = format - end + http_method = method.to_s.upcase @html_document = nil - self.cookies.update @request.cookies - self.cookies.update_cookies_from_jar - @request.set_header 'HTTP_COOKIE', cookies.to_header - @request.delete_header 'action_dispatch.cookies' + cookies.update(@request.cookies) + cookies.update_cookies_from_jar + @request.set_header "HTTP_COOKIE", cookies.to_header + @request.delete_header "action_dispatch.cookies" - @request = TestRequest.new scrub_env!(@request.env), @request.session + @request = TestRequest.new scrub_env!(@request.env), @request.session, @controller.class @response = build_response @response_klass @response.request = @request @controller.recycle! - @request.set_header 'REQUEST_METHOD', http_method + @request.set_header "REQUEST_METHOD", http_method - parameters = parameters.symbolize_keys + if as + @request.content_type = Mime[as].to_s + format ||= as + end + + parameters = params.symbolize_keys + + if format + parameters[:format] = format + end generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action.to_s)) generated_path = generated_path(generated_extras) @@ -517,9 +496,9 @@ module ActionController @request.flash.update(flash || {}) if xhr - @request.set_header 'HTTP_X_REQUESTED_WITH', 'XMLHttpRequest' - @request.fetch_header('HTTP_ACCEPT') do |k| - @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], 'text/xml', '*/*'].join(', ') + @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest" + @request.fetch_header("HTTP_ACCEPT") do |k| + @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ") end end @@ -534,27 +513,27 @@ module ActionController @request = @controller.request @response = @controller.response - @request.delete_header 'HTTP_COOKIE' + @request.delete_header "HTTP_COOKIE" if @request.have_cookie_jar? unless @request.cookie_jar.committed? @request.cookie_jar.write(@response) - self.cookies.update(@request.cookie_jar.instance_variable_get(:@cookies)) + cookies.update(@request.cookie_jar.instance_variable_get(:@cookies)) end end @response.prepare! if flash_value = @request.flash.to_session_value - @request.session['flash'] = flash_value + @request.session["flash"] = flash_value else - @request.session.delete('flash') + @request.session.delete("flash") end if xhr - @request.delete_header 'HTTP_X_REQUESTED_WITH' - @request.delete_header 'HTTP_ACCEPT' + @request.delete_header "HTTP_X_REQUESTED_WITH" + @request.delete_header "HTTP_ACCEPT" end - @request.query_string = '' + @request.query_string = "" @response.sent! end @@ -592,7 +571,7 @@ module ActionController end end - @request = TestRequest.create + @request = TestRequest.create(@controller.class) @response = build_response @response_klass @response.request = @request @@ -611,71 +590,35 @@ module ActionController include ActionDispatch::Assertions class_attribute :_controller_class setup :setup_controller_request_and_response + ActiveSupport.run_load_hooks(:action_controller_test_case, self) end private - def scrub_env!(env) - env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ } - env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ } - env.delete 'action_dispatch.request.query_parameters' - env.delete 'action_dispatch.request.request_parameters' - env - end - - def process_with_kwargs(http_method, action, *args) - if kwarg_request?(args) - args.first.merge!(method: http_method) - process(action, *args) - else - non_kwarg_request_warning if args.any? - - args = args.unshift(http_method) - process(action, *args) + def scrub_env!(env) + env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ } + env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ } + env.delete "action_dispatch.request.query_parameters" + env.delete "action_dispatch.request.request_parameters" + env["rack.input"] = StringIO.new + env end - end - REQUEST_KWARGS = %i(params session flash method body xhr) - def kwarg_request?(args) - args[0].respond_to?(:keys) && ( - (args[0].key?(:format) && args[0].keys.size == 1) || - args[0].keys.any? { |k| REQUEST_KWARGS.include?(k) } - ) - end - - def non_kwarg_request_warning - ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc) - ActionController::TestCase HTTP request methods will accept only - keyword arguments in future Rails versions. - - Examples: - - get :show, params: { id: 1 }, session: { user_id: 1 } - process :update, method: :post, params: { id: 1 } - MSG - end - - def document_root_element - html_document.root - end + def document_root_element + html_document.root + end - def check_required_ivars - # Sanity check for required instance variables so we can give an - # understandable error message. - [:@routes, :@controller, :@request, :@response].each do |iv_name| - if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil? - raise "#{iv_name} is nil: make sure you set it in your test's setup method." + def check_required_ivars + # Sanity check for required instance variables so we can give an + # understandable error message. + [:@routes, :@controller, :@request, :@response].each do |iv_name| + if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil? + raise "#{iv_name} is nil: make sure you set it in your test's setup method." + end end end - end - - def html_format?(parameters) - return true unless parameters.key?(:format) - Mime.fetch(parameters[:format]) { Mime['html'] }.html? - end end include Behavior end - # :startdoc: end diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index 01d49475de..7931e53c3e 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -21,15 +21,15 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'active_support' -require 'active_support/rails' -require 'active_support/core_ext/module/attribute_accessors' +require "active_support" +require "active_support/rails" +require "active_support/core_ext/module/attribute_accessors" -require 'action_pack' -require 'rack' +require "action_pack" +require "rack" module Rack - autoload :Test, 'rack/test' + autoload :Test, "rack/test" end module ActionDispatch @@ -39,21 +39,21 @@ module ActionDispatch end eager_autoload do - autoload_under 'http' do + autoload_under "http" do autoload :Request autoload :Response end end - autoload_under 'middleware' do + autoload_under "middleware" do autoload :RequestId autoload :Callbacks autoload :Cookies autoload :DebugExceptions + autoload :DebugLocks autoload :ExceptionWrapper autoload :Executor autoload :Flash - autoload :ParamsParser autoload :PublicExceptions autoload :Reloader autoload :RemoteIp @@ -63,7 +63,7 @@ module ActionDispatch end autoload :Journey - autoload :MiddlewareStack, 'action_dispatch/middleware/stack' + autoload :MiddlewareStack, "action_dispatch/middleware/stack" autoload :Routing module Http @@ -75,23 +75,23 @@ module ActionDispatch autoload :Parameters autoload :ParameterFilter autoload :Upload - autoload :UploadedFile, 'action_dispatch/http/upload' + autoload :UploadedFile, "action_dispatch/http/upload" autoload :URL end module Session - autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store' - autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store' - autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store' - autoload :CacheStore, 'action_dispatch/middleware/session/cache_store' + autoload :AbstractStore, "action_dispatch/middleware/session/abstract_store" + autoload :CookieStore, "action_dispatch/middleware/session/cookie_store" + autoload :MemCacheStore, "action_dispatch/middleware/session/mem_cache_store" + autoload :CacheStore, "action_dispatch/middleware/session/cache_store" end mattr_accessor :test_app - autoload_under 'testing' do + autoload_under "testing" do autoload :Assertions autoload :Integration - autoload :IntegrationTest, 'action_dispatch/testing/integration' + autoload :IntegrationTest, "action_dispatch/testing/integration" autoload :TestProcess autoload :TestRequest autoload :TestResponse @@ -99,7 +99,7 @@ module ActionDispatch end end -autoload :Mime, 'action_dispatch/http/mime_type' +autoload :Mime, "action_dispatch/http/mime_type" ActiveSupport.on_load(:action_view) do ActionView::Base.default_formats ||= Mime::SET.symbols diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb index 9fa2e38ae3..985e0fb972 100644 --- a/actionpack/lib/action_dispatch/http/cache.rb +++ b/actionpack/lib/action_dispatch/http/cache.rb @@ -2,9 +2,8 @@ module ActionDispatch module Http module Cache module Request - - HTTP_IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze - HTTP_IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze + HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze + HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze def if_modified_since if since = get_header(HTTP_IF_MODIFIED_SINCE) @@ -27,7 +26,7 @@ module ActionDispatch def etag_matches?(etag) if etag validators = if_none_match_etags - validators.include?(etag) || validators.include?('*') + validators.include?(etag) || validators.include?("*") end end @@ -102,11 +101,11 @@ module ActionDispatch end def weak_etag=(weak_validators) - set_header 'ETag', generate_weak_etag(weak_validators) + set_header "ETag", generate_weak_etag(weak_validators) end def strong_etag=(strong_validators) - set_header 'ETag', generate_strong_etag(strong_validators) + set_header "ETag", generate_strong_etag(strong_validators) end def etag?; etag; end @@ -123,7 +122,7 @@ module ActionDispatch private - DATE = 'Date'.freeze + DATE = "Date".freeze LAST_MODIFIED = "Last-Modified".freeze SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate]) @@ -137,7 +136,7 @@ module ActionDispatch def cache_control_segments if cache_control = _cache_control - cache_control.delete(' ').split(',') + cache_control.delete(" ").split(",") else [] end @@ -147,10 +146,10 @@ module ActionDispatch cache_control = {} cache_control_segments.each do |segment| - directive, argument = segment.split('=', 2) + directive, argument = segment.split("=", 2) if SPECIAL_KEYS.include? directive - key = directive.tr('-', '_') + key = directive.tr("-", "_") cache_control[key.to_sym] = argument || true else cache_control[:extras] ||= [] diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb index 041eca48ca..e5874a39f6 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -1,4 +1,4 @@ -require 'action_dispatch/http/parameter_filter' +require "action_dispatch/http/parameter_filter" module ActionDispatch module Http @@ -70,7 +70,7 @@ module ActionDispatch ParameterFilter.new(filters) end - KV_RE = '[^&;=]+' + KV_RE = "[^&;=]+" PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})} def filtered_query_string query_string.gsub(PAIR_RE) do |_| diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb index f4b806b8b5..fc3c44582a 100644 --- a/actionpack/lib/action_dispatch/http/filter_redirect.rb +++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb @@ -1,8 +1,7 @@ module ActionDispatch module Http module FilterRedirect - - FILTERED = '[FILTERED]'.freeze # :nodoc: + FILTERED = "[FILTERED]".freeze # :nodoc: def filtered_location # :nodoc: if location_filter_match? @@ -16,7 +15,7 @@ module ActionDispatch def location_filters if request - request.get_header('action_dispatch.redirect_filter') || [] + request.get_header("action_dispatch.redirect_filter") || [] else [] end @@ -31,7 +30,6 @@ module ActionDispatch end end end - end end end diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb index 69a934b7cd..3c03976f03 100644 --- a/actionpack/lib/action_dispatch/http/headers.rb +++ b/actionpack/lib/action_dispatch/http/headers.rb @@ -3,7 +3,7 @@ module ActionDispatch # Provides access to the request's HTTP headers from the environment. # # env = { "CONTENT_TYPE" => "text/plain", "HTTP_USER_AGENT" => "curl/7.43.0" } - # headers = ActionDispatch::Http::Headers.new(env) + # headers = ActionDispatch::Http::Headers.from_hash(env) # headers["Content-Type"] # => "text/plain" # headers["User-Agent"] # => "curl/7.43.0" # @@ -86,7 +86,7 @@ module ActionDispatch @req.fetch_header(env_name(key)) do return default unless default == DEFAULT return yield if block_given? - raise NameError, key + raise KeyError, key end end @@ -115,16 +115,16 @@ module ActionDispatch private - # Converts an HTTP header name to an environment variable name if it is - # not contained within the headers hash. - def env_name(key) - key = key.to_s - if key =~ HTTP_HEADER - key = key.upcase.tr('-', '_') - key = "HTTP_" + key unless CGI_VARIABLES.include?(key) + # Converts an HTTP header name to an environment variable name if it is + # not contained within the headers hash. + def env_name(key) + key = key.to_s + if key =~ HTTP_HEADER + key = key.upcase.tr("-", "_") + key = "HTTP_" + key unless CGI_VARIABLES.include?(key) + end + key end - key - end end end end diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 0a58ce2b96..d0c9413efa 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/module/attribute_accessors' +require "active_support/core_ext/module/attribute_accessors" module ActionDispatch module Http @@ -16,7 +16,7 @@ module ActionDispatch # X-Post-Data-Format HTTP header if present. def content_mime_type fetch_header("action_dispatch.request.content_type") do |k| - v = if get_header('CONTENT_TYPE') =~ /^([^,\;]*)/ + v = if get_header("CONTENT_TYPE") =~ /^([^,\;]*)/ Mime::Type.lookup($1.strip.downcase) else nil @@ -30,13 +30,13 @@ module ActionDispatch end def has_content_type? - has_header? 'CONTENT_TYPE' + has_header? "CONTENT_TYPE" end # Returns the accepted MIME type for the request. def accepts fetch_header("action_dispatch.request.accepts") do |k| - header = get_header('HTTP_ACCEPT').to_s.strip + header = get_header("HTTP_ACCEPT").to_s.strip v = if header.empty? [content_mime_type] @@ -152,23 +152,23 @@ module ActionDispatch protected - BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ + BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ - def valid_accept_header - (xhr? && (accept.present? || content_mime_type)) || - (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS) - end + def valid_accept_header + (xhr? && (accept.present? || content_mime_type)) || + (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS) + end - def use_accept_header - !self.class.ignore_accept_header - end + def use_accept_header + !self.class.ignore_accept_header + end - def format_from_path_extension - path = get_header('action_dispatch.original_path') || get_header('PATH_INFO') - if match = path && path.match(/\.(\w+)\z/) - Mime[match.captures.first] + def format_from_path_extension + path = get_header("action_dispatch.original_path") || get_header("PATH_INFO") + if match = path && path.match(/\.(\w+)\z/) + Mime[match.captures.first] + end end - end end end end diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 4672ea7199..58eb8d0baf 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -1,8 +1,8 @@ # -*- frozen-string-literal: true -*- -require 'singleton' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/string/starts_ends_with' +require "singleton" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/string/starts_ends_with" module Mime class Mimes @@ -45,32 +45,6 @@ module Mime return type if type.is_a?(Type) EXTENSION_LOOKUP.fetch(type.to_s) { |k| yield k } end - - def const_missing(sym) - ext = sym.downcase - if Mime[ext] - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Accessing mime types via constants is deprecated. - Please change `Mime::#{sym}` to `Mime[:#{ext}]`. - MSG - Mime[ext] - else - super - end - end - - def const_defined?(sym, inherit = true) - ext = sym.downcase - if Mime[ext] - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Accessing mime types via constants is deprecated. - Please change `Mime.const_defined?(#{sym})` to `Mime[:#{ext}]`. - MSG - true - else - super - end - end end # Encapsulates the notion of a mime type. Can be used at render time, for example, with: @@ -99,7 +73,7 @@ module Mime def initialize(index, name, q = nil) @index = index @name = name - q ||= 0.0 if @name == '*/*'.freeze # default wildcard match to end of list + q ||= 0.0 if @name == "*/*".freeze # default wildcard match to end of list @q = ((q || 1.0).to_f * 100).to_i end @@ -114,7 +88,7 @@ module Mime def self.sort!(list) list.sort! - text_xml_idx = find_item_by_name list, 'text/xml' + text_xml_idx = find_item_by_name list, "text/xml" app_xml_idx = find_item_by_name list, Mime[:xml].to_s # Take care of the broken text/xml entry by renaming or deleting it @@ -141,7 +115,7 @@ module Mime type = list[idx] break if type.q < app_xml.q - if type.name.ends_with? '+xml' + if type.name.ends_with? "+xml" list[app_xml_idx], list[idx] = list[idx], app_xml app_xml_idx = idx end @@ -195,12 +169,12 @@ module Mime end def parse(accept_header) - if !accept_header.include?(',') + if !accept_header.include?(",") accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact else list, index = [], 0 - accept_header.split(',').each do |header| + accept_header.split(",").each do |header| params, q = header.split(PARAMETER_SEPARATOR_REGEXP) next unless params @@ -306,31 +280,31 @@ module Mime protected - attr_reader :string, :synonyms + attr_reader :string, :synonyms private - def to_ary; end - def to_a; end + def to_ary; end + def to_a; end - def method_missing(method, *args) - if method.to_s.ends_with? '?' - method[0..-2].downcase.to_sym == to_sym - else - super + def method_missing(method, *args) + if method.to_s.ends_with? "?" + method[0..-2].downcase.to_sym == to_sym + else + super + end end - end - def respond_to_missing?(method, include_private = false) #:nodoc: - method.to_s.ends_with? '?' - end + def respond_to_missing?(method, include_private = false) #:nodoc: + method.to_s.ends_with? "?" + end end class AllType < Type include Singleton def initialize - super '*/*', :all + super "*/*", :all end def all?; true; end @@ -352,14 +326,14 @@ module Mime def ref; end def respond_to_missing?(method, include_private = false) - method.to_s.ends_with? '?' + method.to_s.ends_with? "?" end private - def method_missing(method, *args) - false if method.to_s.ends_with? '?' - end + def method_missing(method, *args) + false if method.to_s.ends_with? "?" + end end end -require 'action_dispatch/http/mime_types' +require "action_dispatch/http/mime_types" diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb index e826551f4b..01fe35f5c6 100644 --- a/actionpack/lib/action_dispatch/http/parameter_filter.rb +++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb @@ -1,7 +1,9 @@ +require "active_support/core_ext/object/duplicable" + module ActionDispatch module Http class ParameterFilter - FILTERED = '[FILTERED]'.freeze # :nodoc: + FILTERED = "[FILTERED]".freeze # :nodoc: def initialize(filters = []) @filters = filters @@ -37,8 +39,8 @@ module ActionDispatch deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) } deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) } - regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty? - deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty? + regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty? + deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty? new regexps, deep_regexps, blocks end @@ -58,7 +60,7 @@ module ActionDispatch parents.push(key) if deep_regexps if regexps.any? { |r| key =~ r } value = FILTERED - elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r } + elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r } value = FILTERED elsif value.is_a?(Hash) value = call(value, parents) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index ff5031d7d5..ddd15b748b 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -3,15 +3,23 @@ module ActionDispatch module Parameters extend ActiveSupport::Concern - PARAMETERS_KEY = 'action_dispatch.request.path_parameters' + PARAMETERS_KEY = "action_dispatch.request.path_parameters" DEFAULT_PARSERS = { Mime[:json].symbol => -> (raw_post) { data = ActiveSupport::JSON.decode(raw_post) - data.is_a?(Hash) ? data : {:_json => data} + data.is_a?(Hash) ? data : { _json: data } } } + # Raised when raw data from the request cannot be parsed by the parser + # defined for request's content mime type. + class ParseError < StandardError + def initialize + super($!.message) + end + end + included do class << self attr_reader :parameter_parsers @@ -37,14 +45,22 @@ module ActionDispatch query_parameters.dup end params.merge!(path_parameters) + params = set_custom_encoding(params) set_header("action_dispatch.request.parameters", params) params end alias :params :parameters def path_parameters=(parameters) #:nodoc: - delete_header('action_dispatch.request.parameters') + delete_header("action_dispatch.request.parameters") + + # If any of the path parameters has an invalid encoding then + # raise since it's likely to trigger errors further on. + Request::Utils.check_param_encoding(parameters) + set_header PARAMETERS_KEY, parameters + rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e + raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}") end # Returns a hash with the \parameters used to form the \path of the request. @@ -57,24 +73,43 @@ module ActionDispatch private - def parse_formatted_parameters(parsers) - return yield if content_length.zero? + def set_custom_encoding(params) + action = params[:action] + params.each do |k, v| + if v.is_a?(String) && v.encoding != encoding_template(action, k) + params[k] = v.force_encoding(encoding_template(action, k)) + end + end + + params + end - strategy = parsers.fetch(content_mime_type.symbol) { return yield } + def encoding_template(action, param) + controller_class.encoding_for_param(action, param) + end - begin - strategy.call(raw_post) - rescue # JSON or Ruby code block errors - my_logger = logger || ActiveSupport::Logger.new($stderr) - my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}" + def parse_formatted_parameters(parsers) + return yield if content_length.zero? || content_mime_type.nil? - raise ParamsParser::ParseError + strategy = parsers.fetch(content_mime_type.symbol) { return yield } + + begin + strategy.call(raw_post) + rescue # JSON or Ruby code block errors + my_logger = logger || ActiveSupport::Logger.new($stderr) + my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}" + + raise ParseError + end end - end - def params_parsers - ActionDispatch::Request.parameter_parsers - end + def params_parsers + ActionDispatch::Request.parameter_parsers + end end end + + module ParamsParser + ParseError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("ActionDispatch::ParamsParser::ParseError", "ActionDispatch::Http::Parameters::ParseError") + end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index b0ed681623..9986d6e1e9 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -1,16 +1,16 @@ -require 'stringio' - -require 'active_support/inflector' -require 'action_dispatch/http/headers' -require 'action_controller/metal/exceptions' -require 'rack/request' -require 'action_dispatch/http/cache' -require 'action_dispatch/http/mime_negotiation' -require 'action_dispatch/http/parameters' -require 'action_dispatch/http/filter_parameters' -require 'action_dispatch/http/upload' -require 'action_dispatch/http/url' -require 'active_support/core_ext/array/conversions' +require "stringio" + +require "active_support/inflector" +require "action_dispatch/http/headers" +require "action_controller/metal/exceptions" +require "rack/request" +require "action_dispatch/http/cache" +require "action_dispatch/http/mime_negotiation" +require "action_dispatch/http/parameters" +require "action_dispatch/http/filter_parameters" +require "action_dispatch/http/upload" +require "action_dispatch/http/url" +require "active_support/core_ext/array/conversions" module ActionDispatch class Request @@ -22,8 +22,8 @@ module ActionDispatch include ActionDispatch::Http::URL include Rack::Request::Env - autoload :Session, 'action_dispatch/request/session' - autoload :Utils, 'action_dispatch/request/utils' + autoload :Session, "action_dispatch/request/session" + autoload :Utils, "action_dispatch/request/utils" LOCALHOST = Regexp.union [/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/] @@ -66,29 +66,18 @@ module ActionDispatch def commit_cookie_jar! # :nodoc: end - def check_path_parameters! - # If any of the path parameters has an invalid encoding then - # raise since it's likely to trigger errors further on. - path_parameters.each do |key, value| - next unless value.respond_to?(:valid_encoding?) - unless value.valid_encoding? - raise ActionController::BadRequest, "Invalid parameter encoding: #{key} => #{value.inspect}" - end - end - end - PASS_NOT_FOUND = Class.new { # :nodoc: def self.action(_); self; end - def self.call(_); [404, {'X-Cascade' => 'pass'}, []]; end + def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end + def self.encoding_for_param(action, param); ::Encoding::UTF_8; end } def controller_class - check_path_parameters! params = path_parameters if params.key?(:controller) controller_param = params[:controller].underscore - params[:action] ||= 'index' + params[:action] ||= "index" const_name = "#{controller_param.camelize}Controller" ActiveSupport::Dependencies.constantize(const_name) else @@ -160,11 +149,11 @@ module ActionDispatch end def controller_instance # :nodoc: - get_header('action_controller.instance'.freeze) + get_header("action_controller.instance".freeze) end def controller_instance=(controller) # :nodoc: - set_header('action_controller.instance'.freeze, controller) + set_header("action_controller.instance".freeze, controller) end def http_auth_salt @@ -175,7 +164,7 @@ module ActionDispatch # We're treating `nil` as "unset", and we want the default setting to be # `true`. This logic should be extracted to `env_config` and calculated # once. - !(get_header('action_dispatch.show_exceptions'.freeze) == false) + !(get_header("action_dispatch.show_exceptions".freeze) == false) end # Returns a symbol form of the #request_method @@ -187,7 +176,7 @@ module ActionDispatch # even if it was overridden by middleware. See #request_method for # more information. def method - @method ||= check_method(get_header("rack.methodoverride.original_method") || get_header('REQUEST_METHOD')) + @method ||= check_method(get_header("rack.methodoverride.original_method") || get_header("REQUEST_METHOD")) end # Returns a symbol form of the #method @@ -249,7 +238,7 @@ module ActionDispatch # (case-insensitive), which may need to be manually added depending on the # choice of JavaScript libraries and frameworks. def xml_http_request? - get_header('HTTP_X_REQUESTED_WITH') =~ /XMLHttpRequest/i + get_header("HTTP_X_REQUESTED_WITH") =~ /XMLHttpRequest/i end alias :xhr? :xml_http_request? @@ -288,24 +277,24 @@ module ActionDispatch # Returns the lowercase name of the HTTP server software. def server_software - (get_header('SERVER_SOFTWARE') && /^([a-zA-Z]+)/ =~ get_header('SERVER_SOFTWARE')) ? $1.downcase : nil + (get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil end # Read the request \body. This is useful for web services that need to # work with raw requests directly. def raw_post - unless has_header? 'RAW_POST_DATA' + unless has_header? "RAW_POST_DATA" raw_post_body = body - set_header('RAW_POST_DATA', raw_post_body.read(content_length)) + set_header("RAW_POST_DATA", raw_post_body.read(content_length)) raw_post_body.rewind if raw_post_body.respond_to?(:rewind) end - get_header 'RAW_POST_DATA' + get_header "RAW_POST_DATA" end # The request body is an IO input stream. If the RAW_POST_DATA environment # variable is already set, wrap it in a StringIO. def body - if raw_post = get_header('RAW_POST_DATA') + if raw_post = get_header("RAW_POST_DATA") raw_post.force_encoding(Encoding::BINARY) StringIO.new(raw_post) else @@ -326,7 +315,7 @@ module ActionDispatch end def body_stream #:nodoc: - get_header('rack.input') + get_header("rack.input") end # TODO This should be broken apart into AD::Request::Session and probably @@ -368,7 +357,7 @@ module ActionDispatch end self.request_parameters = Request::Utils.normalize_encode_params(pr) end - rescue ParamsParser::ParseError # one of the parse strategies blew up + rescue Http::Parameters::ParseError # one of the parse strategies blew up self.request_parameters = Request::Utils.normalize_encode_params(super || {}) raise rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e @@ -379,10 +368,10 @@ module ActionDispatch # Returns the authorization header regardless of whether it was specified directly or through one of the # proxy alternatives. def authorization - get_header('HTTP_AUTHORIZATION') || - get_header('X-HTTP_AUTHORIZATION') || - get_header('X_HTTP_AUTHORIZATION') || - get_header('REDIRECT_X_HTTP_AUTHORIZATION') + get_header("HTTP_AUTHORIZATION") || + get_header("X-HTTP_AUTHORIZATION") || + get_header("X_HTTP_AUTHORIZATION") || + get_header("REDIRECT_X_HTTP_AUTHORIZATION") end # True if the request came from localhost, 127.0.0.1, or ::1. @@ -403,7 +392,7 @@ module ActionDispatch end def ssl? - super || scheme == 'wss'.freeze + super || scheme == "wss".freeze end private diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 1515d59df3..e8173e2a99 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'action_dispatch/http/filter_redirect' -require 'action_dispatch/http/cache' -require 'monitor' +require "active_support/core_ext/module/attribute_accessors" +require "action_dispatch/http/filter_redirect" +require "action_dispatch/http/cache" +require "monitor" module ActionDispatch # :nodoc: # Represents an HTTP response generated by a controller action. Use it to @@ -41,7 +41,7 @@ module ActionDispatch # :nodoc: def []=(k,v) if @response.sending? || @response.sent? - raise ActionDispatch::IllegalStateError, 'header already sent' + raise ActionDispatch::IllegalStateError, "header already sent" end super @@ -67,7 +67,7 @@ module ActionDispatch # :nodoc: alias_method :headers, :header - delegate :[], :[]=, :to => :@header + delegate :[], :[]=, to: :@header def each(&block) sending! @@ -103,8 +103,8 @@ module ActionDispatch # :nodoc: def body @str_body ||= begin - buf = '' - each { |chunk| buf << chunk } + buf = "" + each { |chunk| buf << chunk } buf end end @@ -224,8 +224,10 @@ module ActionDispatch # :nodoc: # Sets the HTTP content type. def content_type=(content_type) - header_info = parse_content_type - set_content_type content_type.to_s, header_info.charset || self.class.default_charset + return unless content_type + new_header_info = parse_content_type(content_type.to_s) + prev_header_info = parsed_content_type_header + set_content_type new_header_info.mime_type, new_header_info.charset || prev_header_info.charset || self.class.default_charset end # Sets the HTTP response's content MIME type. For example, in the controller @@ -238,7 +240,7 @@ module ActionDispatch # :nodoc: # information. def content_type - parse_content_type.mime_type + parsed_content_type_header.mime_type end def sending_file=(v) @@ -253,7 +255,7 @@ module ActionDispatch # :nodoc: # response.charset = 'utf-16' # => 'utf-16' # response.charset = nil # => 'utf-8' def charset=(charset) - header_info = parse_content_type + header_info = parsed_content_type_header if false == charset set_header CONTENT_TYPE, header_info.mime_type else @@ -265,7 +267,7 @@ module ActionDispatch # :nodoc: # The charset of the response. HTML wants to know the encoding of the # content you're giving them, so we need to send that along. def charset - header_info = parse_content_type + header_info = parsed_content_type_header header_info.charset || self.class.default_charset end @@ -329,7 +331,7 @@ module ActionDispatch # :nodoc: # Stream the file's contents if Rack::Sendfile isn't present. def each - File.open(to_path, 'rb') do |file| + File.open(to_path, "rb") do |file| while chunk = file.read(16384) yield chunk end @@ -389,7 +391,7 @@ module ActionDispatch # :nodoc: if header = get_header(SET_COOKIE) header = header.split("\n") if header.respond_to?(:to_str) header.each do |cookie| - if pair = cookie.split(';').first + if pair = cookie.split(";").first key, value = pair.split("=").map { |v| Rack::Utils.unescape(v) } cookies[key] = value end @@ -403,8 +405,7 @@ module ActionDispatch # :nodoc: ContentTypeHeader = Struct.new :mime_type, :charset NullContentTypeHeader = ContentTypeHeader.new nil, nil - def parse_content_type - content_type = get_header CONTENT_TYPE + def parse_content_type(content_type) if content_type type, charset = content_type.split(/;\s*charset=/) type = nil if type.empty? @@ -414,8 +415,14 @@ module ActionDispatch # :nodoc: end end + # Small internal convenience method to get the parsed version of the current + # content type header. + def parsed_content_type_header + parse_content_type(get_header(CONTENT_TYPE)) + end + def set_content_type(content_type, charset) - type = (content_type || '').dup + type = (content_type || "").dup type << "; charset=#{charset}" if charset set_header CONTENT_TYPE, type end @@ -450,7 +457,7 @@ module ActionDispatch # :nodoc: def assign_default_content_type_and_charset! return if content_type - ct = parse_content_type + ct = parsed_content_type_header set_content_type(ct.mime_type || Mime[:html].to_s, ct.charset || self.class.default_charset) end @@ -475,7 +482,7 @@ module ActionDispatch # :nodoc: end def respond_to?(method, include_private = false) - if method.to_s == 'to_path' + if method.to_s == "to_path" @response.stream.respond_to?(method) else super @@ -494,7 +501,7 @@ module ActionDispatch # :nodoc: def handle_no_content! if NO_CONTENT_CODES.include?(@status) @header.delete CONTENT_TYPE - @header.delete 'Content-Length' + @header.delete "Content-Length" end end diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index a221f4c5af..9aa73c862b 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -25,7 +25,7 @@ module ActionDispatch def initialize(hash) # :nodoc: @tempfile = hash[:tempfile] - raise(ArgumentError, ':tempfile is required') unless @tempfile + raise(ArgumentError, ":tempfile is required") unless @tempfile @original_filename = hash[:filename] if @original_filename diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 7a1350a46d..06ffa983d1 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/module/attribute_accessors' +require "active_support/core_ext/module/attribute_accessors" module ActionDispatch module Http @@ -42,7 +42,7 @@ module ActionDispatch # # Second-level domain example # extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www" def extract_subdomain(host, tld_length) - extract_subdomains(host, tld_length).join('.') + extract_subdomains(host, tld_length).join(".") end def url_for(options) @@ -59,7 +59,7 @@ module ActionDispatch port = options[:port] unless host - raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' + raise ArgumentError, "Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true" end build_host_url(host, port, protocol, options, path_for(options)) @@ -92,17 +92,17 @@ module ActionDispatch end def extract_domain_from(host, tld_length) - host.split('.').last(1 + tld_length).join('.') + host.split(".").last(1 + tld_length).join(".") end def extract_subdomains_from(host, tld_length) - parts = host.split('.') + parts = host.split(".") parts[0..-(tld_length + 2)] end def add_trailing_slash(path) # includes querysting - if path.include?('?') + if path.include?("?") path.sub!(/\?/, '/\&') # does not have a .format elsif !path.include?(".") @@ -162,7 +162,7 @@ module ActionDispatch if subdomain == true return _host if domain.nil? - host << extract_subdomains_from(_host, tld_length).join('.') + host << extract_subdomains_from(_host, tld_length).join(".") elsif subdomain host << subdomain.to_param end @@ -192,11 +192,7 @@ module ActionDispatch # Returns the complete URL used for this request. # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com' # req.url # => "http://example.com" def url protocol + host_with_port + fullpath @@ -204,68 +200,52 @@ module ActionDispatch # Returns 'https://' if this is an SSL request and 'http://' otherwise. # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com' # req.protocol # => "http://" # - # req = Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on' # req.protocol # => "https://" def protocol - @protocol ||= ssl? ? 'https://' : 'http://' + @protocol ||= ssl? ? "https://" : "http://" end # Returns the \host and port for this request, such as "example.com:8080". # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com' # req.raw_host_with_port # => "example.com" # - # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80' # req.raw_host_with_port # => "example.com:80" # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.raw_host_with_port # => "example.com:8080" def raw_host_with_port if forwarded = x_forwarded_host.presence forwarded.split(/,\s?/).last else - get_header('HTTP_HOST') || "#{server_name || server_addr}:#{get_header('SERVER_PORT')}" + get_header("HTTP_HOST") || "#{server_name || server_addr}:#{get_header('SERVER_PORT')}" end end # Returns the host for this request, such as "example.com". # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.host # => "example.com" def host - raw_host_with_port.sub(/:\d+$/, ''.freeze) + raw_host_with_port.sub(/:\d+$/, "".freeze) end # Returns a \host:\port string for this request, such as "example.com" or # "example.com:8080". Port is only included if it is not a default port # (80 or 443) # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com' # req.host_with_port # => "example.com" # - # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80' # req.host_with_port # => "example.com" # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.host_with_port # => "example.com:8080" def host_with_port "#{host}#{port_string}" @@ -273,14 +253,10 @@ module ActionDispatch # Returns the port number of this request as an integer. # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com' # req.port # => 80 # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.port # => 8080 def port @port ||= begin @@ -294,29 +270,21 @@ module ActionDispatch # Returns the standard \port number for this request's protocol. # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.standard_port # => 80 def standard_port case protocol - when 'https://' then 443 + when "https://" then 443 else 80 end end # Returns whether this request is using the standard port # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80' # req.standard_port? # => true # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.standard_port? # => false def standard_port? port == standard_port @@ -325,14 +293,10 @@ module ActionDispatch # Returns a number \port suffix like 8080 if the \port number of this request # is not the default HTTP \port 80 or HTTPS \port 443. # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80' # req.optional_port # => nil # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.optional_port # => 8080 def optional_port standard_port? ? nil : port @@ -341,32 +305,24 @@ module ActionDispatch # Returns a string \port suffix, including colon, like ":8080" if the \port # number of this request is not the default HTTP \port 80 or HTTPS \port 443. # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'HTTP_HOST' => 'example.com:80' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80' # req.port_string # => "" # - # req = Request.new 'HTTP_HOST' => 'example.com:8080' + # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080' # req.port_string # => ":8080" def port_string - standard_port? ? '' : ":#{port}" + standard_port? ? "" : ":#{port}" end # Returns the requested port, such as 8080, based on SERVER_PORT # - # class Request < Rack::Request - # include ActionDispatch::Http::URL - # end - # - # req = Request.new 'SERVER_PORT' => '80' + # req = ActionDispatch::Request.new 'SERVER_PORT' => '80' # req.server_port # => 80 # - # req = Request.new 'SERVER_PORT' => '8080' + # req = ActionDispatch::Request.new 'SERVER_PORT' => '8080' # req.server_port # => 8080 def server_port - get_header('SERVER_PORT').to_i + get_header("SERVER_PORT").to_i end # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify diff --git a/actionpack/lib/action_dispatch/journey.rb b/actionpack/lib/action_dispatch/journey.rb index ad42713482..d1cfc51f3e 100644 --- a/actionpack/lib/action_dispatch/journey.rb +++ b/actionpack/lib/action_dispatch/journey.rb @@ -1,5 +1,5 @@ -require 'action_dispatch/journey/router' -require 'action_dispatch/journey/gtg/builder' -require 'action_dispatch/journey/gtg/simulator' -require 'action_dispatch/journey/nfa/builder' -require 'action_dispatch/journey/nfa/simulator' +require "action_dispatch/journey/router" +require "action_dispatch/journey/gtg/builder" +require "action_dispatch/journey/gtg/simulator" +require "action_dispatch/journey/nfa/builder" +require "action_dispatch/journey/nfa/simulator" diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb index 200477b002..dc8b24b089 100644 --- a/actionpack/lib/action_dispatch/journey/formatter.rb +++ b/actionpack/lib/action_dispatch/journey/formatter.rb @@ -1,4 +1,4 @@ -require 'action_controller/metal/exceptions' +require "action_controller/metal/exceptions" module ActionDispatch module Journey @@ -44,8 +44,12 @@ module ActionDispatch return [route.format(parameterized_parts), params] end - message = "No route matches #{Hash[constraints.sort_by{|k,v| k.to_s}].inspect}" - message << " missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty? + unmatched_keys = (missing_keys || []) & constraints.keys + missing_keys = (missing_keys || []) - unmatched_keys + + message = "No route matches #{Hash[constraints.sort_by { |k,v| k.to_s }].inspect}" + message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty? + message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty? raise ActionController::UrlGenerationError, message end diff --git a/actionpack/lib/action_dispatch/journey/gtg/builder.rb b/actionpack/lib/action_dispatch/journey/gtg/builder.rb index 450588cda6..9990c66627 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/builder.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/builder.rb @@ -1,4 +1,4 @@ -require 'action_dispatch/journey/gtg/transition_table' +require "action_dispatch/journey/gtg/transition_table" module ActionDispatch module Journey # :nodoc: @@ -75,7 +75,7 @@ module ActionDispatch when Nodes::Unary nullable?(node.left) else - raise ArgumentError, 'unknown nullable: %s' % node.class.name + raise ArgumentError, "unknown nullable: %s" % node.class.name end end @@ -96,7 +96,7 @@ module ActionDispatch when Nodes::Terminal nullable?(node) ? [] : [node] else - raise ArgumentError, 'unknown firstpos: %s' % node.class.name + raise ArgumentError, "unknown firstpos: %s" % node.class.name end end @@ -117,7 +117,7 @@ module ActionDispatch when Nodes::Unary lastpos(node.left) else - raise ArgumentError, 'unknown lastpos: %s' % node.class.name + raise ArgumentError, "unknown lastpos: %s" % node.class.name end end diff --git a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb index 94b0a24344..d692f6415c 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb @@ -1,4 +1,4 @@ -require 'strscan' +require "strscan" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb index d7ce6042c2..0be18dc26f 100644 --- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb @@ -1,4 +1,4 @@ -require 'action_dispatch/journey/nfa/dot' +require "action_dispatch/journey/nfa/dot" module ActionDispatch module Journey # :nodoc: @@ -72,20 +72,20 @@ module ActionDispatch end def to_svg - svg = IO.popen('dot -Tsvg', 'w+') { |f| + svg = IO.popen("dot -Tsvg", "w+") { |f| f.write(to_dot) f.close_write f.readlines } 3.times { svg.shift } - svg.join.sub(/width="[^"]*"/, '').sub(/height="[^"]*"/, '') + svg.join.sub(/width="[^"]*"/, "").sub(/height="[^"]*"/, "") end - def visualizer(paths, title = 'FSM') - viz_dir = File.join File.dirname(__FILE__), '..', 'visualizer' - fsm_js = File.read File.join(viz_dir, 'fsm.js') - fsm_css = File.read File.join(viz_dir, 'fsm.css') - erb = File.read File.join(viz_dir, 'index.html.erb') + def visualizer(paths, title = "FSM") + viz_dir = File.join File.dirname(__FILE__), "..", "visualizer" + fsm_js = File.read File.join(viz_dir, "fsm.js") + fsm_css = File.read File.join(viz_dir, "fsm.css") + erb = File.read File.join(viz_dir, "index.html.erb") states = "function tt() { return #{to_json}; }" fun_routes = paths.sample(3).map do |ast| @@ -93,10 +93,10 @@ module ActionDispatch case n when Nodes::Symbol case n.left - when ':id' then rand(100).to_s - when ':format' then %w{ xml json }.sample + when ":id" then rand(100).to_s + when ":format" then %w{ xml json }.sample else - 'omg' + "omg" end when Nodes::Terminal then n.symbol else @@ -115,7 +115,7 @@ module ActionDispatch svg = svg javascripts = javascripts - require 'erb' + require "erb" template = ERB.new erb template.result(binding) end @@ -148,7 +148,7 @@ module ActionDispatch when Regexp @regexp_states else - raise ArgumentError, 'unknown symbol: %s' % sym.class + raise ArgumentError, "unknown symbol: %s" % sym.class end end end diff --git a/actionpack/lib/action_dispatch/journey/nfa/builder.rb b/actionpack/lib/action_dispatch/journey/nfa/builder.rb index ee6494c3e4..19e5752ae5 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/builder.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/builder.rb @@ -1,5 +1,5 @@ -require 'action_dispatch/journey/nfa/transition_table' -require 'action_dispatch/journey/gtg/transition_table' +require "action_dispatch/journey/nfa/transition_table" +require "action_dispatch/journey/gtg/transition_table" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/nfa/dot.rb b/actionpack/lib/action_dispatch/journey/nfa/dot.rb index 7063b44bb5..8119e5d9da 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/dot.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/dot.rb @@ -18,7 +18,7 @@ module ActionDispatch # (memos || []).map { |v| " #{k} -> #{v.object_id};" } #}.uniq - <<-eodot + <<-eodot digraph nfa { rankdir=LR; node [shape = doublecircle]; @@ -26,7 +26,7 @@ digraph nfa { node [shape = circle]; #{edges.join "\n"} } - eodot + eodot end end end diff --git a/actionpack/lib/action_dispatch/journey/nfa/simulator.rb b/actionpack/lib/action_dispatch/journey/nfa/simulator.rb index b23270db3c..324d0eed15 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/simulator.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/simulator.rb @@ -1,4 +1,4 @@ -require 'strscan' +require "strscan" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb index 0ccab21801..4737adc724 100644 --- a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb +++ b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb @@ -1,4 +1,4 @@ -require 'action_dispatch/journey/nfa/dot' +require "action_dispatch/journey/nfa/dot" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/nodes/node.rb b/actionpack/lib/action_dispatch/journey/nodes/node.rb index 2793c5668d..0d874a84c9 100644 --- a/actionpack/lib/action_dispatch/journey/nodes/node.rb +++ b/actionpack/lib/action_dispatch/journey/nodes/node.rb @@ -1,4 +1,4 @@ -require 'action_dispatch/journey/visitors' +require "action_dispatch/journey/visitors" module ActionDispatch module Journey # :nodoc: @@ -18,7 +18,7 @@ module ActionDispatch end def to_s - Visitors::String::INSTANCE.accept(self, '') + Visitors::String::INSTANCE.accept(self, "") end def to_dot @@ -30,7 +30,7 @@ module ActionDispatch end def name - left.tr '*:'.freeze, ''.freeze + left.tr "*:".freeze, "".freeze end def type @@ -80,7 +80,7 @@ module ActionDispatch def initialize(left) super @regexp = DEFAULT_EXP - @name = left.tr '*:'.freeze, ''.freeze + @name = left.tr "*:".freeze, "".freeze end def default_regexp? @@ -104,7 +104,7 @@ module ActionDispatch def type; :STAR; end def name - left.name.tr '*:', '' + left.name.tr "*:", "" end end diff --git a/actionpack/lib/action_dispatch/journey/parser.rb b/actionpack/lib/action_dispatch/journey/parser.rb index 9012297400..01ff2109cb 100644 --- a/actionpack/lib/action_dispatch/journey/parser.rb +++ b/actionpack/lib/action_dispatch/journey/parser.rb @@ -4,195 +4,193 @@ # from Racc grammer file "". # -require 'racc/parser.rb' +require "racc/parser.rb" - -require 'action_dispatch/journey/parser_extras' +require "action_dispatch/journey/parser_extras" module ActionDispatch module Journey class Parser < Racc::Parser -##### State transition tables begin ### - -racc_action_table = [ - 13, 15, 14, 7, 21, 16, 8, 19, 13, 15, - 14, 7, 17, 16, 8, 13, 15, 14, 7, 24, - 16, 8, 13, 15, 14, 7, 19, 16, 8 ] - -racc_action_check = [ - 2, 2, 2, 2, 17, 2, 2, 2, 0, 0, - 0, 0, 1, 0, 0, 19, 19, 19, 19, 20, - 19, 19, 7, 7, 7, 7, 22, 7, 7 ] - -racc_action_pointer = [ - 6, 12, -2, nil, nil, nil, nil, 20, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 4, nil, 13, - 13, nil, 17, nil, nil ] - -racc_action_default = [ - -19, -19, -2, -3, -4, -5, -6, -19, -10, -11, - -12, -13, -14, -15, -16, -17, -18, -19, -1, -19, - -19, 25, -8, -9, -7 ] - -racc_goto_table = [ - 1, 22, 18, 23, nil, nil, nil, 20 ] - -racc_goto_check = [ - 1, 2, 1, 3, nil, nil, nil, 1 ] - -racc_goto_pointer = [ - nil, 0, -18, -16, nil, nil, nil, nil, nil, nil, - nil ] - -racc_goto_default = [ - nil, nil, 2, 3, 4, 5, 6, 9, 10, 11, - 12 ] - -racc_reduce_table = [ - 0, 0, :racc_error, - 2, 11, :_reduce_1, - 1, 11, :_reduce_2, - 1, 11, :_reduce_none, - 1, 12, :_reduce_none, - 1, 12, :_reduce_none, - 1, 12, :_reduce_none, - 3, 15, :_reduce_7, - 3, 13, :_reduce_8, - 3, 13, :_reduce_9, - 1, 16, :_reduce_10, - 1, 14, :_reduce_none, - 1, 14, :_reduce_none, - 1, 14, :_reduce_none, - 1, 14, :_reduce_none, - 1, 19, :_reduce_15, - 1, 17, :_reduce_16, - 1, 18, :_reduce_17, - 1, 20, :_reduce_18 ] - -racc_reduce_n = 19 - -racc_shift_n = 25 - -racc_token_table = { - false => 0, - :error => 1, - :SLASH => 2, - :LITERAL => 3, - :SYMBOL => 4, - :LPAREN => 5, - :RPAREN => 6, - :DOT => 7, - :STAR => 8, - :OR => 9 } - -racc_nt_base = 10 - -racc_use_result_var = false - -Racc_arg = [ - racc_action_table, - racc_action_check, - racc_action_default, - racc_action_pointer, - racc_goto_table, - racc_goto_check, - racc_goto_default, - racc_goto_pointer, - racc_nt_base, - racc_reduce_table, - racc_token_table, - racc_shift_n, - racc_reduce_n, - racc_use_result_var ] - -Racc_token_to_s_table = [ - "$end", - "error", - "SLASH", - "LITERAL", - "SYMBOL", - "LPAREN", - "RPAREN", - "DOT", - "STAR", - "OR", - "$start", - "expressions", - "expression", - "or", - "terminal", - "group", - "star", - "symbol", - "literal", - "slash", - "dot" ] - -Racc_debug_parser = false - -##### State transition tables end ##### - -# reduce 0 omitted - -def _reduce_1(val, _values) - Cat.new(val.first, val.last) -end - -def _reduce_2(val, _values) - val.first -end - -# reduce 3 omitted - -# reduce 4 omitted - -# reduce 5 omitted - -# reduce 6 omitted - -def _reduce_7(val, _values) - Group.new(val[1]) -end - -def _reduce_8(val, _values) - Or.new([val.first, val.last]) -end - -def _reduce_9(val, _values) - Or.new([val.first, val.last]) -end - -def _reduce_10(val, _values) - Star.new(Symbol.new(val.last)) -end - -# reduce 11 omitted - -# reduce 12 omitted - -# reduce 13 omitted - -# reduce 14 omitted - -def _reduce_15(val, _values) - Slash.new('/') -end - -def _reduce_16(val, _values) - Symbol.new(val.first) -end - -def _reduce_17(val, _values) - Literal.new(val.first) -end - -def _reduce_18(val, _values) - Dot.new(val.first) -end - -def _reduce_none(val, _values) - val[0] -end - + ##### State transition tables begin ### + + racc_action_table = [ + 13, 15, 14, 7, 21, 16, 8, 19, 13, 15, + 14, 7, 17, 16, 8, 13, 15, 14, 7, 24, + 16, 8, 13, 15, 14, 7, 19, 16, 8 ] + + racc_action_check = [ + 2, 2, 2, 2, 17, 2, 2, 2, 0, 0, + 0, 0, 1, 0, 0, 19, 19, 19, 19, 20, + 19, 19, 7, 7, 7, 7, 22, 7, 7 ] + + racc_action_pointer = [ + 6, 12, -2, nil, nil, nil, nil, 20, nil, nil, + nil, nil, nil, nil, nil, nil, nil, 4, nil, 13, + 13, nil, 17, nil, nil ] + + racc_action_default = [ + -19, -19, -2, -3, -4, -5, -6, -19, -10, -11, + -12, -13, -14, -15, -16, -17, -18, -19, -1, -19, + -19, 25, -8, -9, -7 ] + + racc_goto_table = [ + 1, 22, 18, 23, nil, nil, nil, 20 ] + + racc_goto_check = [ + 1, 2, 1, 3, nil, nil, nil, 1 ] + + racc_goto_pointer = [ + nil, 0, -18, -16, nil, nil, nil, nil, nil, nil, + nil ] + + racc_goto_default = [ + nil, nil, 2, 3, 4, 5, 6, 9, 10, 11, + 12 ] + + racc_reduce_table = [ + 0, 0, :racc_error, + 2, 11, :_reduce_1, + 1, 11, :_reduce_2, + 1, 11, :_reduce_none, + 1, 12, :_reduce_none, + 1, 12, :_reduce_none, + 1, 12, :_reduce_none, + 3, 15, :_reduce_7, + 3, 13, :_reduce_8, + 3, 13, :_reduce_9, + 1, 16, :_reduce_10, + 1, 14, :_reduce_none, + 1, 14, :_reduce_none, + 1, 14, :_reduce_none, + 1, 14, :_reduce_none, + 1, 19, :_reduce_15, + 1, 17, :_reduce_16, + 1, 18, :_reduce_17, + 1, 20, :_reduce_18 ] + + racc_reduce_n = 19 + + racc_shift_n = 25 + + racc_token_table = { + false => 0, + :error => 1, + :SLASH => 2, + :LITERAL => 3, + :SYMBOL => 4, + :LPAREN => 5, + :RPAREN => 6, + :DOT => 7, + :STAR => 8, + :OR => 9 } + + racc_nt_base = 10 + + racc_use_result_var = false + + Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + + Racc_token_to_s_table = [ + "$end", + "error", + "SLASH", + "LITERAL", + "SYMBOL", + "LPAREN", + "RPAREN", + "DOT", + "STAR", + "OR", + "$start", + "expressions", + "expression", + "or", + "terminal", + "group", + "star", + "symbol", + "literal", + "slash", + "dot" ] + + Racc_debug_parser = false + + ##### State transition tables end ##### + + # reduce 0 omitted + + def _reduce_1(val, _values) + Cat.new(val.first, val.last) + end + + def _reduce_2(val, _values) + val.first + end + + # reduce 3 omitted + + # reduce 4 omitted + + # reduce 5 omitted + + # reduce 6 omitted + + def _reduce_7(val, _values) + Group.new(val[1]) + end + + def _reduce_8(val, _values) + Or.new([val.first, val.last]) + end + + def _reduce_9(val, _values) + Or.new([val.first, val.last]) + end + + def _reduce_10(val, _values) + Star.new(Symbol.new(val.last)) + end + + # reduce 11 omitted + + # reduce 12 omitted + + # reduce 13 omitted + + # reduce 14 omitted + + def _reduce_15(val, _values) + Slash.new("/") + end + + def _reduce_16(val, _values) + Symbol.new(val.first) + end + + def _reduce_17(val, _values) + Literal.new(val.first) + end + + def _reduce_18(val, _values) + Dot.new(val.first) + end + + def _reduce_none(val, _values) + val[0] + end end # class Parser - end # module Journey - end # module ActionDispatch + end # module Journey +end # module ActionDispatch diff --git a/actionpack/lib/action_dispatch/journey/parser_extras.rb b/actionpack/lib/action_dispatch/journey/parser_extras.rb index fff0299812..ec26e634e8 100644 --- a/actionpack/lib/action_dispatch/journey/parser_extras.rb +++ b/actionpack/lib/action_dispatch/journey/parser_extras.rb @@ -1,5 +1,5 @@ -require 'action_dispatch/journey/scanner' -require 'action_dispatch/journey/nodes/node' +require "action_dispatch/journey/scanner" +require "action_dispatch/journey/nodes/node" module ActionDispatch module Journey # :nodoc: diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb index 018b89a2b7..0902b9233e 100644 --- a/actionpack/lib/action_dispatch/journey/path/pattern.rb +++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb @@ -4,7 +4,7 @@ module ActionDispatch class Pattern # :nodoc: attr_reader :spec, :requirements, :anchored - def self.from_string string + def self.from_string(string) build(string, {}, "/.?", true) end @@ -98,7 +98,7 @@ module ActionDispatch end def visit_STAR(node) - re = @matchers[node.left.to_sym] || '.+' + re = @matchers[node.left.to_sym] || ".+" "(#{re})" end @@ -175,7 +175,7 @@ module ActionDispatch if @requirements.key?(node) re = /#{@requirements[node]}|/ - @offsets.push((re.match('').length - 1) + @offsets.last) + @offsets.push((re.match("").length - 1) + @offsets.last) else @offsets << @offsets.last end diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb index cfd6681dd1..a9713ff292 100644 --- a/actionpack/lib/action_dispatch/journey/route.rb +++ b/actionpack/lib/action_dispatch/journey/route.rb @@ -29,16 +29,15 @@ module ActionDispatch class All def self.call(_); true; end - def self.verb; ''; end + def self.verb; ""; end end - VERB_TO_CLASS = VERBS.each_with_object({ :all => All }) do |verb, hash| + VERB_TO_CLASS = VERBS.each_with_object(all: All) do |verb, hash| klass = const_get verb hash[verb] = klass hash[verb.downcase] = klass hash[verb.downcase.to_sym] = klass end - end def self.verb_matcher(verb) @@ -164,17 +163,17 @@ module ActionDispatch end def verb - verbs.join('|') + verbs.join("|") end private - def verbs - @request_method_match.map(&:verb) - end + def verbs + @request_method_match.map(&:verb) + end - def match_verb(request) - @request_method_match.any? { |m| m.call request } - end + def match_verb(request) + @request_method_match.any? { |m| m.call request } + end end end end diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb index 06cdce1724..d0ef549335 100644 --- a/actionpack/lib/action_dispatch/journey/router.rb +++ b/actionpack/lib/action_dispatch/journey/router.rb @@ -1,14 +1,14 @@ -require 'action_dispatch/journey/router/utils' -require 'action_dispatch/journey/routes' -require 'action_dispatch/journey/formatter' +require "action_dispatch/journey/router/utils" +require "action_dispatch/journey/routes" +require "action_dispatch/journey/formatter" before = $-w $-w = false -require 'action_dispatch/journey/parser' +require "action_dispatch/journey/parser" $-w = before -require 'action_dispatch/journey/route' -require 'action_dispatch/journey/path/pattern' +require "action_dispatch/journey/route" +require "action_dispatch/journey/path/pattern" module ActionDispatch module Journey # :nodoc: @@ -29,7 +29,7 @@ module ActionDispatch script_name = req.script_name unless route.path.anchored - req.script_name = (script_name.to_s + match.to_s).chomp('/') + req.script_name = (script_name.to_s + match.to_s).chomp("/") req.path_info = match.post_match req.path_info = "/" + req.path_info unless req.path_info.start_with? "/" end @@ -38,7 +38,7 @@ module ActionDispatch status, headers, body = route.app.serve(req) - if 'pass' == headers['X-Cascade'] + if "pass" == headers["X-Cascade"] req.script_name = script_name req.path_info = path_info req.path_parameters = set_params @@ -48,7 +48,7 @@ module ActionDispatch return [status, headers, body] end - return [404, {'X-Cascade' => 'pass'}, ['Not Found']] + return [404, { "X-Cascade" => "pass" }, ["Not Found"]] end def recognize(rails_req) @@ -72,7 +72,9 @@ module ActionDispatch private def partitioned_routes - routes.partitioned_routes + routes.partition { |r| + r.path.anchored && r.ast.grep(Nodes::Symbol).all? { |n| n.default_regexp? } + } end def ast @@ -92,7 +94,7 @@ module ActionDispatch simulator.memos(path) { [] } end - def find_routes req + def find_routes(req) routes = filter_routes(req.path_info).concat custom_routes.find_all { |r| r.path.match(req.path_info) } diff --git a/actionpack/lib/action_dispatch/journey/router/utils.rb b/actionpack/lib/action_dispatch/journey/router/utils.rb index 9793ca1c7a..ce5d350763 100644 --- a/actionpack/lib/action_dispatch/journey/router/utils.rb +++ b/actionpack/lib/action_dispatch/journey/router/utils.rb @@ -14,10 +14,10 @@ module ActionDispatch # normalize_path("/%ab") # => "/%AB" def self.normalize_path(path) path = "/#{path}" - path.squeeze!('/'.freeze) - path.sub!(%r{/+\Z}, ''.freeze) + path.squeeze!("/".freeze) + path.sub!(%r{/+\Z}, "".freeze) path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase } - path = '/' if path == ''.freeze + path = "/" if path == "".freeze path end @@ -28,7 +28,7 @@ module ActionDispatch US_ASCII = Encoding::US_ASCII UTF_8 = Encoding::UTF_8 EMPTY = "".force_encoding(US_ASCII).freeze - DEC2HEX = (0..255).to_a.map{ |i| ENCODE % i }.map{ |s| s.force_encoding(US_ASCII) } + DEC2HEX = (0..255).to_a.map { |i| ENCODE % i }.map { |s| s.force_encoding(US_ASCII) } ALPHA = "a-zA-Z".freeze DIGIT = "0-9".freeze @@ -55,12 +55,12 @@ module ActionDispatch def unescape_uri(uri) encoding = uri.encoding == US_ASCII ? UTF_8 : uri.encoding - uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack('C') }.force_encoding(encoding) + uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack("C") }.force_encoding(encoding) end protected def escape(component, pattern) - component.gsub(pattern){ |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII) + component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII) end def percent_encode(unsafe) diff --git a/actionpack/lib/action_dispatch/journey/scanner.rb b/actionpack/lib/action_dispatch/journey/scanner.rb index 19e0bc03d6..4b8c8ab063 100644 --- a/actionpack/lib/action_dispatch/journey/scanner.rb +++ b/actionpack/lib/action_dispatch/journey/scanner.rb @@ -1,4 +1,4 @@ -require 'strscan' +require "strscan" module ActionDispatch module Journey # :nodoc: @@ -50,7 +50,7 @@ module ActionDispatch when text = @ss.scan(/(?<!\\):\w+/) [:SYMBOL, text] when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\:|\\\(|\\\))+/) - [:LITERAL, text.tr('\\', '')] + [:LITERAL, text.tr('\\', "")] # any char when text = @ss.scan(/./) [:LITERAL, text] diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb index 306d2e674a..452dc84cc5 100644 --- a/actionpack/lib/action_dispatch/journey/visitors.rb +++ b/actionpack/lib/action_dispatch/journey/visitors.rb @@ -37,7 +37,7 @@ module ActionDispatch @parameters.each do |index| param = parts[index] value = hash[param.name] - return ''.freeze unless value + return "".freeze unless value parts[index] = param.escape value end @@ -57,7 +57,7 @@ module ActionDispatch private - def visit node + def visit(node) send(DISPATCH_CACHE[node.type], node) end @@ -97,7 +97,7 @@ module ActionDispatch visit(node, seed) end - def visit node, seed + def visit(node, seed) send(DISPATCH_CACHE[node.type], node, seed) end @@ -166,28 +166,28 @@ module ActionDispatch class String < FunctionalVisitor # :nodoc: private - def binary(node, seed) - visit(node.right, visit(node.left, seed)) - end + def binary(node, seed) + visit(node.right, visit(node.left, seed)) + end - def nary(node, seed) - last_child = node.children.last - node.children.inject(seed) { |s, c| - string = visit(c, s) - string << "|".freeze unless last_child == c - string - } - end + def nary(node, seed) + last_child = node.children.last + node.children.inject(seed) { |s, c| + string = visit(c, s) + string << "|".freeze unless last_child == c + string + } + end - def terminal(node, seed) - seed + node.left - end + def terminal(node, seed) + seed + node.left + end - def visit_GROUP(node, seed) - visit(node.left, seed << "(".freeze) << ")".freeze - end + def visit_GROUP(node, seed) + visit(node.left, seed << "(".freeze) << ")".freeze + end - INSTANCE = new + INSTANCE = new end class Dot < FunctionalVisitor # :nodoc: diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb index c782779b34..fef246532b 100644 --- a/actionpack/lib/action_dispatch/middleware/callbacks.rb +++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb @@ -15,8 +15,8 @@ module ActionDispatch ActiveSupport::Reloader.to_complete(*args, &block) end - deprecate to_prepare: 'use ActiveSupport::Reloader.to_prepare instead', - to_cleanup: 'use ActiveSupport::Reloader.to_complete instead' + deprecate to_prepare: "use ActiveSupport::Reloader.to_prepare instead", + to_cleanup: "use ActiveSupport::Reloader.to_complete instead" def before(*args, &block) set_callback(:call, :before, *args, &block) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index f2f3150b56..6f4fab396a 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -1,13 +1,13 @@ -require 'active_support/core_ext/hash/keys' -require 'active_support/key_generator' -require 'active_support/message_verifier' -require 'active_support/json' -require 'rack/utils' +require "active_support/core_ext/hash/keys" +require "active_support/key_generator" +require "active_support/message_verifier" +require "active_support/json" +require "rack/utils" module ActionDispatch class Request def cookie_jar - fetch_header('action_dispatch.cookies'.freeze) do + fetch_header("action_dispatch.cookies".freeze) do self.cookie_jar = Cookies::CookieJar.build(self, cookies) end end @@ -20,11 +20,11 @@ module ActionDispatch } def have_cookie_jar? - has_header? 'action_dispatch.cookies'.freeze + has_header? "action_dispatch.cookies".freeze end def cookie_jar=(jar) - set_header 'action_dispatch.cookies'.freeze, jar + set_header "action_dispatch.cookies".freeze, jar end def key_generator @@ -237,9 +237,9 @@ module ActionDispatch private - def upgrade_legacy_signed_cookies? - request.secret_token.present? && request.secret_key_base.present? - end + def upgrade_legacy_signed_cookies? + request.secret_token.present? && request.secret_key_base.present? + end end # Passing the ActiveSupport::MessageEncryptor::NullSerializer downstream @@ -338,13 +338,13 @@ module ActionDispatch end def to_header - @cookies.map { |k,v| "#{escape(k)}=#{escape(v)}" }.join '; ' + @cookies.map { |k,v| "#{escape(k)}=#{escape(v)}" }.join "; " end def handle_options(options) #:nodoc: options[:path] ||= "/" - if options[:domain] == :all || options[:domain] == 'all' + if options[:domain] == :all || options[:domain] == "all" # if there is a provided tld length then we use it otherwise default domain regexp domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP @@ -355,7 +355,7 @@ module ActionDispatch end elsif options[:domain].is_a? Array # if host matches one of the supplied domains without a dot in front of it - options[:domain] = options[:domain].find {|domain| request.host.include? domain.sub(/^\./, '') } + options[:domain] = options[:domain].find { |domain| request.host.include? domain.sub(/^\./, "") } end end @@ -367,12 +367,12 @@ module ActionDispatch value = options[:value] else value = options - options = { :value => value } + options = { value: value } end handle_options(options) - if @cookies[name.to_s] != value or options[:expires] + if @cookies[name.to_s] != value || options[:expires] @cookies[name.to_s] = value @set_cookies[name.to_s] = options @delete_cookies.delete(name.to_s) @@ -406,7 +406,7 @@ module ActionDispatch # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie def clear(options = {}) - @cookies.each_key{ |k| delete(k, options) } + @cookies.each_key { |k| delete(k, options) } end def write(headers) @@ -420,26 +420,26 @@ module ActionDispatch private - def escape(string) - ::Rack::Utils.escape(string) - end + def escape(string) + ::Rack::Utils.escape(string) + end - def make_set_cookie_header(header) - header = @set_cookies.inject(header) { |m, (k, v)| - if write_cookie?(v) - ::Rack::Utils.add_cookie_to_header(m, k, v) - else - m - end - } - @delete_cookies.inject(header) { |m, (k, v)| - ::Rack::Utils.add_remove_cookie_to_header(m, k, v) - } - end + def make_set_cookie_header(header) + header = @set_cookies.inject(header) { |m, (k, v)| + if write_cookie?(v) + ::Rack::Utils.add_cookie_to_header(m, k, v) + else + m + end + } + @delete_cookies.inject(header) { |m, (k, v)| + ::Rack::Utils.add_remove_cookie_to_header(m, k, v) + } + end - def write_cookie?(cookie) - request.ssl? || !cookie[:secure] || always_write_cookie - end + def write_cookie?(cookie) + request.ssl? || !cookie[:secure] || always_write_cookie + end end class AbstractCookieJar # :nodoc: @@ -528,7 +528,7 @@ module ActionDispatch end def digest - request.cookies_digest || 'SHA1' + request.cookies_digest || "SHA1" end def key_generator @@ -576,8 +576,8 @@ module ActionDispatch "Read the upgrade documentation to learn more about this new config option." end - secret = key_generator.generate_key(request.encrypted_cookie_salt || '') - sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || '') + secret = key_generator.generate_key(request.encrypted_cookie_salt || "")[0, ActiveSupport::MessageEncryptor.key_len] + sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || "") @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer) end diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index 5f758d641a..ee644f41c8 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -1,16 +1,16 @@ -require 'action_dispatch/http/request' -require 'action_dispatch/middleware/exception_wrapper' -require 'action_dispatch/routing/inspector' -require 'action_view' -require 'action_view/base' +require "action_dispatch/http/request" +require "action_dispatch/middleware/exception_wrapper" +require "action_dispatch/routing/inspector" +require "action_view" +require "action_view/base" -require 'pp' +require "pp" module ActionDispatch # This middleware is responsible for logging exceptions and # showing a debugging page in case the request is local. class DebugExceptions - RESCUES_TEMPLATE_PATH = File.expand_path('../templates', __FILE__) + RESCUES_TEMPLATE_PATH = File.expand_path("../templates", __FILE__) class DebugView < ActionView::Base def debug_params(params) @@ -19,7 +19,7 @@ module ActionDispatch clean_params.delete("controller") if clean_params.empty? - 'None' + "None" else PP.pp(clean_params, "", 200) end @@ -27,15 +27,23 @@ module ActionDispatch def debug_headers(headers) if headers.present? - headers.inspect.gsub(',', ",\n") + headers.inspect.gsub(",", ",\n") else - 'None' + "None" end end def debug_hash(object) object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n") end + + def render(*) + if logger = ActionView::Base.logger + logger.silence { super } + else + super + end + end end def initialize(app, routes_app = nil, response_format = :default) @@ -48,7 +56,7 @@ module ActionDispatch request = ActionDispatch::Request.new env _, headers, body = response = @app.call(env) - if headers['X-Cascade'] == 'pass' + if headers["X-Cascade"] == "pass" body.close if body.respond_to?(:close) raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}" end @@ -61,129 +69,129 @@ module ActionDispatch private - def render_exception(request, exception) - backtrace_cleaner = request.get_header('action_dispatch.backtrace_cleaner') - wrapper = ExceptionWrapper.new(backtrace_cleaner, exception) - log_error(request, wrapper) + def render_exception(request, exception) + backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner") + wrapper = ExceptionWrapper.new(backtrace_cleaner, exception) + log_error(request, wrapper) - if request.get_header('action_dispatch.show_detailed_exceptions') - content_type = request.formats.first + if request.get_header("action_dispatch.show_detailed_exceptions") + content_type = request.formats.first - if api_request?(content_type) - render_for_api_request(content_type, wrapper) + if api_request?(content_type) + render_for_api_request(content_type, wrapper) + else + render_for_browser_request(request, wrapper) + end else - render_for_browser_request(request, wrapper) + raise exception end - else - raise exception end - end - def render_for_browser_request(request, wrapper) - template = create_template(request, wrapper) - file = "rescues/#{wrapper.rescue_template}" + def render_for_browser_request(request, wrapper) + template = create_template(request, wrapper) + file = "rescues/#{wrapper.rescue_template}" - if request.xhr? - body = template.render(template: file, layout: false, formats: [:text]) - format = "text/plain" - else - body = template.render(template: file, layout: 'rescues/layout') - format = "text/html" + if request.xhr? + body = template.render(template: file, layout: false, formats: [:text]) + format = "text/plain" + else + body = template.render(template: file, layout: "rescues/layout") + format = "text/html" + end + render(wrapper.status_code, body, format) end - render(wrapper.status_code, body, format) - end - def render_for_api_request(content_type, wrapper) - body = { - status: wrapper.status_code, - error: Rack::Utils::HTTP_STATUS_CODES.fetch( - wrapper.status_code, - Rack::Utils::HTTP_STATUS_CODES[500] - ), - exception: wrapper.exception.inspect, - traces: wrapper.traces - } - - to_format = "to_#{content_type.to_sym}" + def render_for_api_request(content_type, wrapper) + body = { + status: wrapper.status_code, + error: Rack::Utils::HTTP_STATUS_CODES.fetch( + wrapper.status_code, + Rack::Utils::HTTP_STATUS_CODES[500] + ), + exception: wrapper.exception.inspect, + traces: wrapper.traces + } + + to_format = "to_#{content_type.to_sym}" + + if content_type && body.respond_to?(to_format) + formatted_body = body.public_send(to_format) + format = content_type + else + formatted_body = body.to_json + format = Mime[:json] + end - if content_type && body.respond_to?(to_format) - formatted_body = body.public_send(to_format) - format = content_type - else - formatted_body = body.to_json - format = Mime[:json] + render(wrapper.status_code, formatted_body, format) end - render(wrapper.status_code, formatted_body, format) - end + def create_template(request, wrapper) + traces = wrapper.traces - def create_template(request, wrapper) - traces = wrapper.traces + trace_to_show = "Application Trace" + if traces[trace_to_show].empty? && wrapper.rescue_template != "routing_error" + trace_to_show = "Full Trace" + end - trace_to_show = 'Application Trace' - if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error' - trace_to_show = 'Full Trace' - end + if source_to_show = traces[trace_to_show].first + source_to_show_id = source_to_show[:id] + end - if source_to_show = traces[trace_to_show].first - source_to_show_id = source_to_show[:id] + DebugView.new([RESCUES_TEMPLATE_PATH], + request: request, + exception: wrapper.exception, + traces: traces, + show_source_idx: source_to_show_id, + trace_to_show: trace_to_show, + routes_inspector: routes_inspector(wrapper.exception), + source_extracts: wrapper.source_extracts, + line_number: wrapper.line_number, + file: wrapper.file + ) end - DebugView.new([RESCUES_TEMPLATE_PATH], - request: request, - exception: wrapper.exception, - traces: traces, - show_source_idx: source_to_show_id, - trace_to_show: trace_to_show, - routes_inspector: routes_inspector(wrapper.exception), - source_extracts: wrapper.source_extracts, - line_number: wrapper.line_number, - file: wrapper.file - ) - end - - def render(status, body, format) - [status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]] - end + def render(status, body, format) + [status, { "Content-Type" => "#{format}; charset=#{Response.default_charset}", "Content-Length" => body.bytesize.to_s }, [body]] + end - def log_error(request, wrapper) - logger = logger(request) - return unless logger + def log_error(request, wrapper) + logger = logger(request) + return unless logger - exception = wrapper.exception + exception = wrapper.exception - trace = wrapper.application_trace - trace = wrapper.framework_trace if trace.empty? + trace = wrapper.application_trace + trace = wrapper.framework_trace if trace.empty? - ActiveSupport::Deprecation.silence do - logger.fatal " " - logger.fatal "#{exception.class} (#{exception.message}):" - log_array logger, exception.annoted_source_code if exception.respond_to?(:annoted_source_code) - logger.fatal " " - log_array logger, trace + ActiveSupport::Deprecation.silence do + logger.fatal " " + logger.fatal "#{exception.class} (#{exception.message}):" + log_array logger, exception.annoted_source_code if exception.respond_to?(:annoted_source_code) + logger.fatal " " + log_array logger, trace + end end - end - def log_array(logger, array) - array.map { |line| logger.fatal line } - end + def log_array(logger, array) + array.map { |line| logger.fatal line } + end - def logger(request) - request.logger || ActionView::Base.logger || stderr_logger - end + def logger(request) + request.logger || ActionView::Base.logger || stderr_logger + end - def stderr_logger - @stderr_logger ||= ActiveSupport::Logger.new($stderr) - end + def stderr_logger + @stderr_logger ||= ActiveSupport::Logger.new($stderr) + end - def routes_inspector(exception) - if @routes_app.respond_to?(:routes) && (exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)) - ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes) + def routes_inspector(exception) + if @routes_app.respond_to?(:routes) && (exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)) + ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes) + end end - end - def api_request?(content_type) - @response_format == :api && !content_type.html? - end + def api_request?(content_type) + @response_format == :api && !content_type.html? + end end end diff --git a/actionpack/lib/action_dispatch/middleware/debug_locks.rb b/actionpack/lib/action_dispatch/middleware/debug_locks.rb new file mode 100644 index 0000000000..74b952528e --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/debug_locks.rb @@ -0,0 +1,122 @@ +module ActionDispatch + # This middleware can be used to diagnose deadlocks in the autoload interlock. + # + # To use it, insert it near the top of the middleware stack, using + # <tt>config/application.rb</tt>: + # + # config.middleware.insert_before Rack::Sendfile, ActionDispatch::DebugLocks + # + # After restarting the application and re-triggering the deadlock condition, + # <tt>/rails/locks</tt> will show a summary of all threads currently known to + # the interlock, which lock level they are holding or awaiting, and their + # current backtrace. + # + # Generally a deadlock will be caused by the interlock conflicting with some + # other external lock or blocking I/O call. These cannot be automatically + # identified, but should be visible in the displayed backtraces. + # + # NOTE: The formatting and content of this middleware's output is intended for + # human consumption, and should be expected to change between releases. + # + # This middleware exposes operational details of the server, with no access + # control. It should only be enabled when in use, and removed thereafter. + class DebugLocks + def initialize(app, path = "/rails/locks") + @app = app + @path = path + end + + def call(env) + req = ActionDispatch::Request.new env + + if req.get? + path = req.path_info.chomp("/".freeze) + if path == @path + return render_details(req) + end + end + + @app.call(env) + end + + private + def render_details(req) + threads = ActiveSupport::Dependencies.interlock.raw_state do |threads| + # The Interlock itself comes to a complete halt as long as this block + # is executing. That gives us a more consistent picture of everything, + # but creates a pretty strong Observer Effect. + # + # Most directly, that means we need to do as little as possible in + # this block. More widely, it means this middleware should remain a + # strictly diagnostic tool (to be used when something has gone wrong), + # and not for any sort of general monitoring. + + threads.each.with_index do |(thread, info), idx| + info[:index] = idx + info[:backtrace] = thread.backtrace + end + + threads + end + + str = threads.map do |thread, info| + if info[:exclusive] + lock_state = "Exclusive" + elsif info[:sharing] > 0 + lock_state = "Sharing" + lock_state << " x#{info[:sharing]}" if info[:sharing] > 1 + else + lock_state = "No lock" + end + + if info[:waiting] + lock_state << " (yielded share)" + end + + msg = "Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n" + + if info[:sleeper] + msg << " Waiting in #{info[:sleeper]}" + msg << " to #{info[:purpose].to_s.inspect}" unless info[:purpose].nil? + msg << "\n" + + if info[:compatible] + compat = info[:compatible].map { |c| c == false ? "share" : c.to_s.inspect } + msg << " may be pre-empted for: #{compat.join(', ')}\n" + end + + blockers = threads.values.select { |binfo| blocked_by?(info, binfo, threads.values) } + msg << " blocked by: #{blockers.map { |i| i[:index] }.join(', ')}\n" if blockers.any? + end + + blockees = threads.values.select { |binfo| blocked_by?(binfo, info, threads.values) } + msg << " blocking: #{blockees.map { |i| i[:index] }.join(', ')}\n" if blockees.any? + + msg << "\n#{info[:backtrace].join("\n")}\n" if info[:backtrace] + end.join("\n\n---\n\n\n") + + [200, { "Content-Type" => "text/plain", "Content-Length" => str.size }, [str]] + end + + def blocked_by?(victim, blocker, all_threads) + return false if victim.equal?(blocker) + + case victim[:sleeper] + when :start_sharing + blocker[:exclusive] || + (!victim[:waiting] && blocker[:compatible] && !blocker[:compatible].include?(false)) + when :start_exclusive + blocker[:sharing] > 0 || + blocker[:exclusive] || + (blocker[:compatible] && !blocker[:compatible].include?(victim[:purpose])) + when :yield_shares + blocker[:exclusive] + when :stop_exclusive + blocker[:exclusive] || + victim[:compatible] && + victim[:compatible].include?(blocker[:purpose]) && + all_threads.all? { |other| !other[:compatible] || blocker.equal?(other) || other[:compatible].include?(blocker[:purpose]) } + end + end + end +end diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index 59edc66086..99dc37c568 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -1,33 +1,33 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'rack/utils' +require "active_support/core_ext/module/attribute_accessors" +require "rack/utils" module ActionDispatch class ExceptionWrapper cattr_accessor :rescue_responses @@rescue_responses = Hash.new(:internal_server_error) @@rescue_responses.merge!( - 'ActionController::RoutingError' => :not_found, - 'AbstractController::ActionNotFound' => :not_found, - 'ActionController::MethodNotAllowed' => :method_not_allowed, - 'ActionController::UnknownHttpMethod' => :method_not_allowed, - 'ActionController::NotImplemented' => :not_implemented, - 'ActionController::UnknownFormat' => :not_acceptable, - 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity, - 'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity, - 'ActionDispatch::ParamsParser::ParseError' => :bad_request, - 'ActionController::BadRequest' => :bad_request, - 'ActionController::ParameterMissing' => :bad_request, - 'Rack::Utils::ParameterTypeError' => :bad_request, - 'Rack::Utils::InvalidParameterError' => :bad_request + "ActionController::RoutingError" => :not_found, + "AbstractController::ActionNotFound" => :not_found, + "ActionController::MethodNotAllowed" => :method_not_allowed, + "ActionController::UnknownHttpMethod" => :method_not_allowed, + "ActionController::NotImplemented" => :not_implemented, + "ActionController::UnknownFormat" => :not_acceptable, + "ActionController::InvalidAuthenticityToken" => :unprocessable_entity, + "ActionController::InvalidCrossOriginRequest" => :unprocessable_entity, + "ActionDispatch::Http::Parameters::ParseError" => :bad_request, + "ActionController::BadRequest" => :bad_request, + "ActionController::ParameterMissing" => :bad_request, + "Rack::QueryParser::ParameterTypeError" => :bad_request, + "Rack::QueryParser::InvalidParameterError" => :bad_request ) cattr_accessor :rescue_templates - @@rescue_templates = Hash.new('diagnostics') + @@rescue_templates = Hash.new("diagnostics") @@rescue_templates.merge!( - 'ActionView::MissingTemplate' => 'missing_template', - 'ActionController::RoutingError' => 'routing_error', - 'AbstractController::ActionNotFound' => 'unknown_action', - 'ActionView::Template::Error' => 'template_error' + "ActionView::MissingTemplate" => "missing_template", + "ActionController::RoutingError" => "routing_error", + "AbstractController::ActionNotFound" => "unknown_action", + "ActionView::Template::Error" => "template_error" ) attr_reader :backtrace_cleaner, :exception, :line_number, :file @@ -100,49 +100,49 @@ module ActionDispatch private - def backtrace - Array(@exception.backtrace) - end + def backtrace + Array(@exception.backtrace) + end - def original_exception(exception) - if @@rescue_responses.has_key?(exception.cause.class.name) - exception.cause - else - exception + def original_exception(exception) + if @@rescue_responses.has_key?(exception.cause.class.name) + exception.cause + else + exception + end end - end - def clean_backtrace(*args) - if backtrace_cleaner - backtrace_cleaner.clean(backtrace, *args) - else - backtrace + def clean_backtrace(*args) + if backtrace_cleaner + backtrace_cleaner.clean(backtrace, *args) + else + backtrace + end end - end - def source_fragment(path, line) - return unless Rails.respond_to?(:root) && Rails.root - full_path = Rails.root.join(path) - if File.exist?(full_path) - File.open(full_path, "r") do |file| - start = [line - 3, 0].max - lines = file.each_line.drop(start).take(6) - Hash[*(start+1..(lines.count+start)).zip(lines).flatten] + def source_fragment(path, line) + return unless Rails.respond_to?(:root) && Rails.root + full_path = Rails.root.join(path) + if File.exist?(full_path) + File.open(full_path, "r") do |file| + start = [line - 3, 0].max + lines = file.each_line.drop(start).take(6) + Hash[*(start+1..(lines.count+start)).zip(lines).flatten] + end end end - end - def extract_file_and_line_number(trace) - # Split by the first colon followed by some digits, which works for both - # Windows and Unix path styles. - file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace - [file, line.to_i] - end + def extract_file_and_line_number(trace) + # Split by the first colon followed by some digits, which works for both + # Windows and Unix path styles. + file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace + [file, line.to_i] + end - def expand_backtrace - @exception.backtrace.unshift( - @exception.to_s.split("\n") - ).flatten! - end + def expand_backtrace + @exception.backtrace.unshift( + @exception.to_s.split("\n") + ).flatten! + end end end diff --git a/actionpack/lib/action_dispatch/middleware/executor.rb b/actionpack/lib/action_dispatch/middleware/executor.rb index 06245b403b..3d43f97a2b 100644 --- a/actionpack/lib/action_dispatch/middleware/executor.rb +++ b/actionpack/lib/action_dispatch/middleware/executor.rb @@ -1,4 +1,4 @@ -require 'rack/body_proxy' +require "rack/body_proxy" module ActionDispatch class Executor diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb index 80703940ed..6900934712 100644 --- a/actionpack/lib/action_dispatch/middleware/flash.rb +++ b/actionpack/lib/action_dispatch/middleware/flash.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/hash/keys" module ActionDispatch # The flash provides a way to pass temporary primitive-types (String, Array, Hash) between actions. Anything you place in the flash will be exposed @@ -36,7 +36,7 @@ module ActionDispatch # # See docs on the FlashHash class for more details about the flash. class Flash - KEY = 'action_dispatch.request.flash_hash'.freeze + KEY = "action_dispatch.request.flash_hash".freeze module RequestMethods # Access the contents of the flash. Use <tt>flash["notice"]</tt> to @@ -60,14 +60,14 @@ module ActionDispatch session = self.session || {} flash_hash = self.flash_hash - if flash_hash && (flash_hash.present? || session.key?('flash')) + if flash_hash && (flash_hash.present? || session.key?("flash")) session["flash"] = flash_hash.to_session_value self.flash = flash_hash.dup end if (!session.respond_to?(:loaded?) || session.loaded?) && # (reset_session uses {}, which doesn't implement #loaded?) - session.key?('flash') && session['flash'].nil? - session.delete('flash') + session.key?("flash") && session["flash"].nil? + session.delete("flash") end end @@ -118,8 +118,8 @@ module ActionDispatch end new(flashes, flashes.keys) when Hash # Rails 4.0 - flashes = value['flashes'] - if discard = value['discard'] + flashes = value["flashes"] + if discard = value["discard"] flashes.except!(*discard) end new(flashes, flashes.keys) @@ -133,7 +133,7 @@ module ActionDispatch def to_session_value #:nodoc: flashes_to_keep = @flashes.except(*@discard) return nil if flashes_to_keep.empty? - { 'discard' => [], 'flashes' => flashes_to_keep } + { "discard" => [], "flashes" => flashes_to_keep } end def initialize(flashes = {}, discard = []) #:nodoc: @@ -277,15 +277,15 @@ module ActionDispatch end protected - def now_is_loaded? - @now - end + def now_is_loaded? + @now + end - def stringify_array(array) - array.map do |item| - item.kind_of?(Symbol) ? item.to_s : item + def stringify_array(array) + array.map do |item| + item.kind_of?(Symbol) ? item.to_s : item + end end - end end def self.new(app) app; end diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb deleted file mode 100644 index faf3262b8f..0000000000 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'action_dispatch/http/request' - -module ActionDispatch - # ActionDispatch::ParamsParser works for all the requests having any Content-Length - # (like POST). It takes raw data from the request and puts it through the parser - # that is picked based on Content-Type header. - # - # In case of any error while parsing data ParamsParser::ParseError is raised. - class ParamsParser - # Raised when raw data from the request cannot be parsed by the parser - # defined for request's content mime type. - class ParseError < StandardError - - def initialize(message = nil, original_exception = nil) - if message - ActiveSupport::Deprecation.warn("Passing #message is deprecated and has no effect. " \ - "#{self.class} will automatically capture the message " \ - "of the original exception.", caller) - end - - if original_exception - ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ - "Exceptions will automatically capture the original exception.", caller) - end - - super($!.message) - end - - def original_exception - ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) - cause - end - end - - # Create a new +ParamsParser+ middleware instance. - # - # The +parsers+ argument can take Hash of parsers where key is identifying - # content mime type, and value is a lambda that is going to process data. - def self.new(app, parsers = {}) - ActiveSupport::Deprecation.warn('ActionDispatch::ParamsParser is deprecated and will be removed in Rails 5.1. Configure the parameter parsing in ActionDispatch::Request.parameter_parsers.') - parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key } - ActionDispatch::Request.parameter_parsers = ActionDispatch::Request::DEFAULT_PARSERS.merge(parsers) - app - end - end -end diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb index 0f27984550..46f0f675b9 100644 --- a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb @@ -20,36 +20,36 @@ module ActionDispatch request = ActionDispatch::Request.new(env) status = request.path_info[1..-1].to_i content_type = request.formats.first - body = { :status => status, :error => Rack::Utils::HTTP_STATUS_CODES.fetch(status, Rack::Utils::HTTP_STATUS_CODES[500]) } + body = { status: status, error: Rack::Utils::HTTP_STATUS_CODES.fetch(status, Rack::Utils::HTTP_STATUS_CODES[500]) } render(status, content_type, body) end private - def render(status, content_type, body) - format = "to_#{content_type.to_sym}" if content_type - if format && body.respond_to?(format) - render_format(status, content_type, body.public_send(format)) - else - render_html(status) + def render(status, content_type, body) + format = "to_#{content_type.to_sym}" if content_type + if format && body.respond_to?(format) + render_format(status, content_type, body.public_send(format)) + else + render_html(status) + end end - end - def render_format(status, content_type, body) - [status, {'Content-Type' => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}", - 'Content-Length' => body.bytesize.to_s}, [body]] - end + def render_format(status, content_type, body) + [status, { "Content-Type" => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}", + "Content-Length" => body.bytesize.to_s }, [body]] + end - def render_html(status) - path = "#{public_path}/#{status}.#{I18n.locale}.html" - path = "#{public_path}/#{status}.html" unless (found = File.exist?(path)) + def render_html(status) + path = "#{public_path}/#{status}.#{I18n.locale}.html" + path = "#{public_path}/#{status}.html" unless (found = File.exist?(path)) - if found || File.exist?(path) - render_format(status, 'text/html', File.read(path)) - else - [404, { "X-Cascade" => "pass" }, []] + if found || File.exist?(path) + render_format(status, "text/html", File.read(path)) + else + [404, { "X-Cascade" => "pass" }, []] + end end - end end end diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb index 112bde6596..90c64037aa 100644 --- a/actionpack/lib/action_dispatch/middleware/reloader.rb +++ b/actionpack/lib/action_dispatch/middleware/reloader.rb @@ -43,10 +43,10 @@ module ActionDispatch class << self attr_accessor :default_reloader # :nodoc: - deprecate to_prepare: 'use ActiveSupport::Reloader.to_prepare instead', - to_cleanup: 'use ActiveSupport::Reloader.to_complete instead', - prepare!: 'use Rails.application.reloader.prepare! instead', - cleanup!: 'use Rails.application.reloader.reload! instead of cleanup + prepare' + deprecate to_prepare: "use ActiveSupport::Reloader.to_prepare instead", + to_cleanup: "use ActiveSupport::Reloader.to_complete instead", + prepare!: "use Rails.application.reloader.prepare! instead", + cleanup!: "use Rails.application.reloader.reload! instead of cleanup + prepare" end self.default_reloader = ActiveSupport::Reloader diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb index 31b75498b6..523eeb5b05 100644 --- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb +++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb @@ -1,4 +1,4 @@ -require 'ipaddr' +require "ipaddr" module ActionDispatch # This middleware calculates the IP address of the remote client that is @@ -176,8 +176,6 @@ module ActionDispatch @proxies.any? { |proxy| proxy === ip } end end - end - end end diff --git a/actionpack/lib/action_dispatch/middleware/request_id.rb b/actionpack/lib/action_dispatch/middleware/request_id.rb index 1555ff72af..1925ffd9dd 100644 --- a/actionpack/lib/action_dispatch/middleware/request_id.rb +++ b/actionpack/lib/action_dispatch/middleware/request_id.rb @@ -1,9 +1,10 @@ -require 'securerandom' -require 'active_support/core_ext/string/access' +require "securerandom" +require "active_support/core_ext/string/access" module ActionDispatch - # Makes a unique request id available to the action_dispatch.request_id env variable (which is then accessible through - # ActionDispatch::Request#uuid or the alias ActionDispatch::Request#request_id) and sends the same id to the client via the X-Request-Id header. + # Makes a unique request id available to the +action_dispatch.request_id+ env variable (which is then accessible + # through <tt>ActionDispatch::Request#request_id</tt> or the alias <tt>ActionDispatch::Request#uuid</tt>) and sends + # the same id to the client via the X-Request-Id header. # # The unique request id is either based on the X-Request-Id header in the request, which would typically be generated # by a firewall, load balancer, or the web server, or, if this header is not available, a random uuid. If the @@ -12,7 +13,7 @@ module ActionDispatch # The unique request id can be used to trace a request end-to-end and would typically end up being part of log files # from multiple pieces of the stack. class RequestId - X_REQUEST_ID = "X-Request-Id".freeze # :nodoc: + X_REQUEST_ID = "X-Request-Id".freeze #:nodoc: def initialize(app) @app = app diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 5fb5953811..49b82e7128 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -1,34 +1,23 @@ -require 'rack/utils' -require 'rack/request' -require 'rack/session/abstract/id' -require 'action_dispatch/middleware/cookies' -require 'action_dispatch/request/session' +require "rack/utils" +require "rack/request" +require "rack/session/abstract/id" +require "action_dispatch/middleware/cookies" +require "action_dispatch/request/session" module ActionDispatch module Session class SessionRestoreError < StandardError #:nodoc: - - def initialize(const_error = nil) - if const_error - ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ - "Exceptions will automatically capture the original exception.", caller) - end - + def initialize super("Session contains objects whose class definition isn't available.\n" + "Remember to require the classes for all objects kept in the session.\n" + "(Original exception: #{$!.message} [#{$!.class}])\n") set_backtrace $!.backtrace end - - def original_exception - ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) - cause - end end module Compatibility def initialize(app, options = {}) - options[:key] ||= '_session_id' + options[:key] ||= "_session_id" super end @@ -46,9 +35,9 @@ module ActionDispatch end private - def make_request(env) - ActionDispatch::Request.new env - end + def make_request(env) + ActionDispatch::Request.new env + end end module StaleSessionCheck @@ -94,9 +83,9 @@ module ActionDispatch private - def set_cookie(request, session_id, cookie) - request.cookie_jar[key] = cookie - end + def set_cookie(request, session_id, cookie) + request.cookie_jar[key] = cookie + end end end end diff --git a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb index 589ae46e38..71274bc13a 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb @@ -1,4 +1,4 @@ -require 'action_dispatch/middleware/session/abstract_store' +require "action_dispatch/middleware/session/abstract_store" module ActionDispatch module Session @@ -19,7 +19,7 @@ module ActionDispatch # Get a session from the cache. def find_session(env, sid) - unless sid and session = @cache.read(cache_key(sid)) + unless sid && (session = @cache.read(cache_key(sid))) sid, session = generate_sid, {} end [sid, session] @@ -29,7 +29,7 @@ module ActionDispatch def write_session(env, sid, session, options) key = cache_key(sid) if session - @cache.write(key, session, :expires_in => options[:expire_after]) + @cache.write(key, session, expires_in: options[:expire_after]) else @cache.delete(key) end diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index dec9c60ef2..8409109ede 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/hash/keys' -require 'action_dispatch/middleware/session/abstract_store' -require 'rack/session/cookie' +require "active_support/core_ext/hash/keys" +require "action_dispatch/middleware/session/abstract_store" +require "rack/session/cookie" module ActionDispatch module Session @@ -64,7 +64,7 @@ module ActionDispatch # <tt>:httponly</tt>. class CookieStore < AbstractStore def initialize(app, options={}) - super(app, options.merge!(:cookie_only => true)) + super(app, options.merge!(cookie_only: true)) end def delete_session(req, session_id, options) @@ -84,46 +84,46 @@ module ActionDispatch private - def extract_session_id(req) - stale_session_check! do - unpacked_cookie_data(req)["session_id"] + def extract_session_id(req) + stale_session_check! do + unpacked_cookie_data(req)["session_id"] + end end - end - def unpacked_cookie_data(req) - req.fetch_header("action_dispatch.request.unsigned_session_cookie") do |k| - v = stale_session_check! do - if data = get_cookie(req) - data.stringify_keys! + def unpacked_cookie_data(req) + req.fetch_header("action_dispatch.request.unsigned_session_cookie") do |k| + v = stale_session_check! do + if data = get_cookie(req) + data.stringify_keys! + end + data || {} end - data || {} + req.set_header k, v end - req.set_header k, v end - end - def persistent_session_id!(data, sid=nil) - data ||= {} - data["session_id"] ||= sid || generate_sid - data - end + def persistent_session_id!(data, sid=nil) + data ||= {} + data["session_id"] ||= sid || generate_sid + data + end - def write_session(req, sid, session_data, options) - session_data["session_id"] = sid - session_data - end + def write_session(req, sid, session_data, options) + session_data["session_id"] = sid + session_data + end - def set_cookie(request, session_id, cookie) - cookie_jar(request)[@key] = cookie - end + def set_cookie(request, session_id, cookie) + cookie_jar(request)[@key] = cookie + end - def get_cookie(req) - cookie_jar(req)[@key] - end + def get_cookie(req) + cookie_jar(req)[@key] + end - def cookie_jar(request) - request.cookie_jar.signed_or_encrypted - end + def cookie_jar(request) + request.cookie_jar.signed_or_encrypted + end end end end diff --git a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb index cb19786f0b..ee2b1f26ad 100644 --- a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb @@ -1,6 +1,6 @@ -require 'action_dispatch/middleware/session/abstract_store' +require "action_dispatch/middleware/session/abstract_store" begin - require 'rack/session/dalli' + require "rack/session/dalli" rescue LoadError => e $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install" raise e diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 64695f9738..90f26a1c33 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -1,5 +1,5 @@ -require 'action_dispatch/http/request' -require 'action_dispatch/middleware/exception_wrapper' +require "action_dispatch/http/request" +require "action_dispatch/middleware/exception_wrapper" module ActionDispatch # This middleware rescues any exception returned by the application @@ -15,7 +15,7 @@ module ActionDispatch # If any exception happens inside the exceptions app, this middleware # catches the exceptions and returns a FAILSAFE_RESPONSE. class ShowExceptions - FAILSAFE_RESPONSE = [500, { 'Content-Type' => 'text/plain' }, + FAILSAFE_RESPONSE = [500, { "Content-Type" => "text/plain" }, ["500 Internal Server Error\n" \ "If you are the administrator of this website, then please read this web " \ "application's log file and/or the web server's log file to find out what " \ @@ -39,22 +39,22 @@ module ActionDispatch private - def render_exception(request, exception) - backtrace_cleaner = request.get_header 'action_dispatch.backtrace_cleaner' - wrapper = ExceptionWrapper.new(backtrace_cleaner, exception) - status = wrapper.status_code - request.set_header "action_dispatch.exception", wrapper.exception - request.set_header "action_dispatch.original_path", request.path_info - request.path_info = "/#{status}" - response = @exceptions_app.call(request.env) - response[1]['X-Cascade'] == 'pass' ? pass_response(status) : response - rescue Exception => failsafe_error - $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}" - FAILSAFE_RESPONSE - end + def render_exception(request, exception) + backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner" + wrapper = ExceptionWrapper.new(backtrace_cleaner, exception) + status = wrapper.status_code + request.set_header "action_dispatch.exception", wrapper.exception + request.set_header "action_dispatch.original_path", request.path_info + request.path_info = "/#{status}" + response = @exceptions_app.call(request.env) + response[1]["X-Cascade"] == "pass" ? pass_response(status) : response + rescue Exception => failsafe_error + $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}" + FAILSAFE_RESPONSE + end - def pass_response(status) - [status, {"Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0"}, []] - end + def pass_response(status) + [status, { "Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0" }, []] + end end end diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb index ab3077b308..557721c301 100644 --- a/actionpack/lib/action_dispatch/middleware/ssl.rb +++ b/actionpack/lib/action_dispatch/middleware/ssl.rb @@ -18,9 +18,9 @@ module ActionDispatch # Enabled by default. Configure `config.ssl_options` with `hsts: false` to disable. # # Set `config.ssl_options` with `hsts: { … }` to configure HSTS: - # * `expires`: How long, in seconds, these settings will stick. Defaults to - # `180.days` (recommended). The minimum required to qualify for browser - # preload lists is `18.weeks`. + # * `expires`: How long, in seconds, these settings will stick. The minimum + # required to qualify for browser preload lists is `18.weeks`. Defaults to + # `180.days` (recommended). # * `subdomains`: Set to `true` to tell the browser to apply these settings # to all subdomains. This protects your cookies from interception by a # vulnerable site on a subdomain. Defaults to `true`. @@ -29,6 +29,7 @@ module ActionDispatch # first visit* since it hasn't seen your HSTS header yet. To close this # gap, browser vendors include a baked-in list of HSTS-enabled sites. # Go to https://hstspreload.appspot.com to submit your site for inclusion. + # Defaults to `false`. # # To turn off HSTS, omitting the header is not enough. Browsers will remember the # original HSTS directive until it expires. Instead, use the header to tell browsers to @@ -44,35 +45,17 @@ module ActionDispatch HSTS_EXPIRES_IN = 15552000 def self.default_hsts_options - { expires: HSTS_EXPIRES_IN, subdomains: false, preload: false } + { expires: HSTS_EXPIRES_IN, subdomains: true, preload: false } end - def initialize(app, redirect: {}, hsts: {}, secure_cookies: true, **options) + def initialize(app, redirect: {}, hsts: {}, secure_cookies: true) @app = app - if options[:host] || options[:port] - ActiveSupport::Deprecation.warn <<-end_warning.strip_heredoc - The `:host` and `:port` options are moving within `:redirect`: - `config.ssl_options = { redirect: { host: …, port: … } }`. - end_warning - @redirect = options.slice(:host, :port) - else - @redirect = redirect - end + @redirect = redirect @exclude = @redirect && @redirect[:exclude] || proc { !@redirect } @secure_cookies = secure_cookies - if hsts != true && hsts != false && hsts[:subdomains].nil? - hsts[:subdomains] = false - - ActiveSupport::Deprecation.warn <<-end_warning.strip_heredoc - In Rails 5.1, The `:subdomains` option of HSTS config will be treated as true if - unspecified. Set `config.ssl_options = { hsts: { subdomains: false } }` to opt out - of this behavior. - end_warning - end - @hsts_header = build_hsts_header(normalize_hsts_options(hsts)) end @@ -92,7 +75,7 @@ module ActionDispatch private def set_hsts_header!(headers) - headers['Strict-Transport-Security'.freeze] ||= @hsts_header + headers["Strict-Transport-Security".freeze] ||= @hsts_header end def normalize_hsts_options(options) @@ -118,10 +101,10 @@ module ActionDispatch end def flag_cookies_as_secure!(headers) - if cookies = headers['Set-Cookie'.freeze] + if cookies = headers["Set-Cookie".freeze] cookies = cookies.split("\n".freeze) - headers['Set-Cookie'.freeze] = cookies.map { |cookie| + headers["Set-Cookie".freeze] = cookies.map { |cookie| if cookie !~ /;\s*secure\s*(;|$)/i "#{cookie}; secure" else @@ -132,12 +115,20 @@ module ActionDispatch end def redirect_to_https(request) - [ @redirect.fetch(:status, 301), - { 'Content-Type' => 'text/html', - 'Location' => https_location_for(request) }, + [ @redirect.fetch(:status, redirection_status(request)), + { "Content-Type" => "text/html", + "Location" => https_location_for(request) }, @redirect.fetch(:body, []) ] end + def redirection_status(request) + if request.get? || request.head? + 301 # Issue a permanent redirect via a GET request. + else + 307 # Issue a fresh request redirect to preserve the HTTP method. + end + end + def https_location_for(request) host = @redirect[:host] || request.host port = @redirect[:port] || request.port diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 0b4bee5462..6949b31e75 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -88,7 +88,6 @@ module ActionDispatch end def delete(target) - target = get_class target middlewares.delete_if { |m| m.klass == target } end @@ -102,32 +101,14 @@ module ActionDispatch private - def assert_index(index, where) - index = get_class index - i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index } - raise "No such middleware to insert #{where}: #{index.inspect}" unless i - i - end - - def get_class(klass) - if klass.is_a?(String) || klass.is_a?(Symbol) - classcache = ActiveSupport::Dependencies::Reference - converted_klass = classcache[klass.to_s] - ActiveSupport::Deprecation.warn <<-eowarn -Passing strings or symbols to the middleware builder is deprecated, please change -them to actual class references. For example: - - "#{klass}" => #{converted_klass} - - eowarn - converted_klass - else - klass + def assert_index(index, where) + i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index } + raise "No such middleware to insert #{where}: #{index.inspect}" unless i + i end - end - def build_middleware(klass, args, block) - Middleware.new(get_class(klass), args, block) - end + def build_middleware(klass, args, block) + Middleware.new(klass, args, block) + end end end diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb index 2c5721dc22..5c71f0fc48 100644 --- a/actionpack/lib/action_dispatch/middleware/static.rb +++ b/actionpack/lib/action_dispatch/middleware/static.rb @@ -1,5 +1,5 @@ -require 'rack/utils' -require 'active_support/core_ext/uri' +require "rack/utils" +require "active_support/core_ext/uri" module ActionDispatch # This middleware returns a file's contents from disk in the body response. @@ -13,8 +13,8 @@ module ActionDispatch # located at `public/assets/application.js` if the file exists. If the file # does not exist, a 404 "File not Found" response will be returned. class FileHandler - def initialize(root, index: 'index', headers: {}) - @root = root.chomp('/') + def initialize(root, index: "index", headers: {}) + @root = root.chomp("/") @file_server = ::Rack::File.new(@root, headers) @index = index end @@ -33,7 +33,7 @@ module ActionDispatch paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"] if match = paths.detect { |p| - path = File.join(@root, p.force_encoding('UTF-8'.freeze)) + path = File.join(@root, p.force_encoding("UTF-8".freeze)) begin File.file?(path) && File.readable?(path) rescue SystemCallError @@ -46,7 +46,7 @@ module ActionDispatch end def call(env) - serve ActionDispatch::Request.new env + serve(Rack::Request.new(env)) end def serve(request) @@ -59,13 +59,13 @@ module ActionDispatch if status == 304 return [status, headers, body] end - headers['Content-Encoding'] = 'gzip' - headers['Content-Type'] = content_type(path) + headers["Content-Encoding"] = "gzip" + headers["Content-Type"] = content_type(path) else status, headers, body = @file_server.call(request.env) end - headers['Vary'] = 'Accept-Encoding' if gzip_path + headers["Vary"] = "Accept-Encoding" if gzip_path return [status, headers, body] ensure @@ -78,11 +78,11 @@ module ActionDispatch end def content_type(path) - ::Rack::Mime.mime_type(::File.extname(path), 'text/plain'.freeze) + ::Rack::Mime.mime_type(::File.extname(path), "text/plain".freeze) end def gzip_encoding_accepted?(request) - request.accept_encoding =~ /\bgzip\b/i + request.accept_encoding.any? { |enc, quality| enc =~ /\bgzip\b/i } end def gzip_file_path(path) @@ -106,23 +106,16 @@ module ActionDispatch # produce a directory traversal using this middleware. Only 'GET' and 'HEAD' # requests will result in a file being returned. class Static - def initialize(app, path, deprecated_cache_control = :not_set, index: 'index', headers: {}) - if deprecated_cache_control != :not_set - ActiveSupport::Deprecation.warn("The `cache_control` argument is deprecated," \ - "replaced by `headers: { 'Cache-Control' => #{deprecated_cache_control} }`, " \ - " and will be removed in Rails 5.1.") - headers['Cache-Control'.freeze] = deprecated_cache_control - end - + def initialize(app, path, index: "index", headers: {}) @app = app @file_handler = FileHandler.new(path, index: index, headers: headers) end def call(env) - req = ActionDispatch::Request.new env + req = Rack::Request.new env if req.get? || req.head? - path = req.path_info.chomp('/'.freeze) + path = req.path_info.chomp("/".freeze) if match = @file_handler.match?(path) req.path_info = match return @file_handler.serve(req) diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index e9e6a2e597..48cc91bbfa 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -8,20 +8,20 @@ module ActionDispatch config.action_dispatch.show_exceptions = true config.action_dispatch.tld_length = 1 config.action_dispatch.ignore_accept_header = false - config.action_dispatch.rescue_templates = { } - config.action_dispatch.rescue_responses = { } + config.action_dispatch.rescue_templates = {} + config.action_dispatch.rescue_responses = {} config.action_dispatch.default_charset = nil config.action_dispatch.rack_cache = false - config.action_dispatch.http_auth_salt = 'http authentication' - config.action_dispatch.signed_cookie_salt = 'signed cookie' - config.action_dispatch.encrypted_cookie_salt = 'encrypted cookie' - config.action_dispatch.encrypted_signed_cookie_salt = 'signed encrypted cookie' + config.action_dispatch.http_auth_salt = "http authentication" + config.action_dispatch.signed_cookie_salt = "signed cookie" + config.action_dispatch.encrypted_cookie_salt = "encrypted cookie" + config.action_dispatch.encrypted_signed_cookie_salt = "signed encrypted cookie" config.action_dispatch.perform_deep_munge = true config.action_dispatch.default_headers = { - 'X-Frame-Options' => 'SAMEORIGIN', - 'X-XSS-Protection' => '1; mode=block', - 'X-Content-Type-Options' => 'nosniff' + "X-Frame-Options" => "SAMEORIGIN", + "X-XSS-Protection" => "1; mode=block", + "X-Content-Type-Options" => "nosniff" } config.eager_load_namespaces << ActionDispatch diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index 47568f6ad0..b883ca0f61 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -1,4 +1,4 @@ -require 'rack/session/abstract/id' +require "rack/session/abstract/id" module ActionDispatch class Request @@ -204,26 +204,26 @@ module ActionDispatch private - def load_for_read! - load! if !loaded? && exists? - end + def load_for_read! + load! if !loaded? && exists? + end - def load_for_write! - load! unless loaded? - end + def load_for_write! + load! unless loaded? + end - def load! - id, session = @by.load_session @req - options[:id] = id - @delegate.replace(stringify_keys(session)) - @loaded = true - end + def load! + id, session = @by.load_session @req + options[:id] = id + @delegate.replace(stringify_keys(session)) + @loaded = true + end - def stringify_keys(other) - other.each_with_object({}) { |(key, value), hash| - hash[key.to_s] = value - } - end + def stringify_keys(other) + other.each_with_object({}) { |(key, value), hash| + hash[key.to_s] = value + } + end end end end diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb index bb3df3c311..282bdbd2be 100644 --- a/actionpack/lib/action_dispatch/request/utils.rb +++ b/actionpack/lib/action_dispatch/request/utils.rb @@ -1,7 +1,6 @@ module ActionDispatch class Request class Utils # :nodoc: - mattr_accessor :perform_deep_munge self.perform_deep_munge = true @@ -64,4 +63,3 @@ module ActionDispatch end end end - diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb index 2459a45827..b91ffb8419 100644 --- a/actionpack/lib/action_dispatch/routing/inspector.rb +++ b/actionpack/lib/action_dispatch/routing/inspector.rb @@ -1,5 +1,5 @@ -require 'delegate' -require 'active_support/core_ext/string/strip' +require "delegate" +require "active_support/core_ext/string/strip" module ActionDispatch module Routing @@ -33,11 +33,11 @@ module ActionDispatch end def controller - parts.include?(:controller) ? ':controller' : requirements[:controller] + parts.include?(:controller) ? ":controller" : requirements[:controller] end def action - parts.include?(:action) ? ':action' : requirements[:action] + parts.include?(:action) ? ":action" : requirements[:action] end def internal? @@ -80,48 +80,48 @@ module ActionDispatch private - def normalize_filter(filter) - if filter.is_a?(Hash) && filter[:controller] - { controller: /#{filter[:controller].downcase.sub(/_?controller\z/, '').sub('::', '/')}/ } - elsif filter - { controller: /#{filter}/, action: /#{filter}/, verb: /#{filter}/, name: /#{filter}/, path: /#{filter}/ } + def normalize_filter(filter) + if filter.is_a?(Hash) && filter[:controller] + { controller: /#{filter[:controller].downcase.sub(/_?controller\z/, '').sub('::', '/')}/ } + elsif filter + { controller: /#{filter}/, action: /#{filter}/, verb: /#{filter}/, name: /#{filter}/, path: /#{filter}/ } + end end - end - def filter_routes(filter) - if filter - @routes.select do |route| - route_wrapper = RouteWrapper.new(route) - filter.any? { |default, value| route_wrapper.send(default) =~ value } + def filter_routes(filter) + if filter + @routes.select do |route| + route_wrapper = RouteWrapper.new(route) + filter.any? { |default, value| route_wrapper.send(default) =~ value } + end + else + @routes end - else - @routes end - end - def collect_routes(routes) - routes.collect do |route| - RouteWrapper.new(route) - end.reject(&:internal?).collect do |route| - collect_engine_routes(route) + def collect_routes(routes) + routes.collect do |route| + RouteWrapper.new(route) + end.reject(&:internal?).collect do |route| + collect_engine_routes(route) - { name: route.name, - verb: route.verb, - path: route.path, - reqs: route.reqs } + { name: route.name, + verb: route.verb, + path: route.path, + reqs: route.reqs } + end end - end - def collect_engine_routes(route) - name = route.endpoint - return unless route.engine? - return if @engines[name] + def collect_engine_routes(route) + name = route.endpoint + return unless route.engine? + return if @engines[name] - routes = route.rack_app.routes - if routes.is_a?(ActionDispatch::Routing::RouteSet) - @engines[name] = collect_routes(routes.routes) + routes = route.rack_app.routes + if routes.is_a?(ActionDispatch::Routing::RouteSet) + @engines[name] = collect_routes(routes.routes) + end end - end end class ConsoleFormatter @@ -161,7 +161,7 @@ module ActionDispatch private def draw_section(routes) - header_lengths = ['Prefix', 'Verb', 'URI Pattern'].map(&:length) + header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length) name_width, verb_width, path_width = widths(routes).zip(header_lengths).map(&:max) routes.map do |r| diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 40b6500553..c481c190bf 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,9 +1,9 @@ -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/enumerable' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/regexp' -require 'action_dispatch/routing/redirection' -require 'action_dispatch/routing/endpoint' +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/enumerable" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" +require "action_dispatch/routing/redirection" +require "action_dispatch/routing/endpoint" module ActionDispatch module Routing @@ -41,7 +41,7 @@ module ActionDispatch end def serve(req) - return [ 404, {'X-Cascade' => 'pass'}, [] ] unless matches?(req) + return [ 404, { "X-Cascade" => "pass" }, [] ] unless matches?(req) @strategy.call @app, req end @@ -93,7 +93,7 @@ module ActionDispatch end def self.optional_format?(path, format) - format != false && !path.include?(':format') && !path.end_with?('/') + format != false && !path.include?(":format") && !path.end_with?("/") end def initialize(set, ast, defaults, controller, default_action, modyoule, to, formatted, scope_constraints, blocks, via, options_constraints, anchor, options) @@ -138,7 +138,7 @@ module ActionDispatch @defaults = formats[:defaults].merge(@defaults).merge(normalize_defaults(options)) if path_params.include?(:action) && !@requirements.key?(:action) - @defaults[:action] ||= 'index' + @defaults[:action] ||= "index" end @required_defaults = (split_options[:required_defaults] || []).map(&:first) @@ -270,7 +270,7 @@ module ActionDispatch { requirements: { format: Regexp.compile(formatted) }, defaults: { format: formatted } } else - { requirements: { }, defaults: { } } + { requirements: {}, defaults: {} } end end @@ -333,7 +333,7 @@ module ActionDispatch def split_to(to) if to =~ /#/ - to.split('#') + to.split("#") else [] end @@ -614,7 +614,7 @@ module ActionDispatch target_as = name_for_action(options[:as], path) options[:via] ||= :all - match(path, options.merge(:to => app, :anchor => false, :format => false)) + match(path, options.merge(to: app, anchor: false, format: false)) define_generate_prefix(app, target_as) if rails_app self @@ -661,7 +661,7 @@ module ActionDispatch super(options) else prefix_options = options.slice(*_route.segment_keys) - prefix_options[:relative_url_root] = ''.freeze + prefix_options[:relative_url_root] = "".freeze # we must actually delete prefix segment keys to avoid passing them to next url_for _route.segment_keys.each { |k| options.delete(k) } _routes.url_helpers.send("#{name}_path", prefix_options) @@ -716,11 +716,7 @@ module ActionDispatch def map_method(method, args, &block) options = args.extract_options! options[:via] = method - if options.key?(:defaults) - defaults(options.delete(:defaults)) { match(*args, options, &block) } - else - match(*args, options, &block) - end + match(*args, options, &block) self end end @@ -814,7 +810,7 @@ module ActionDispatch options = args.extract_options!.dup scope = {} - options[:path] = args.flatten.join('/') if args.any? + options[:path] = args.flatten.join("/") if args.any? options[:constraints] ||= {} unless nested_scope? @@ -838,7 +834,7 @@ module ActionDispatch end if options.key? :anchor - raise ArgumentError, 'anchor is ignored unless passed to `match`' + raise ArgumentError, "anchor is ignored unless passed to `match`" end @scope.options.each do |option| @@ -985,7 +981,7 @@ module ActionDispatch # resources :iphones # end def constraints(constraints = {}) - scope(:constraints => constraints) { yield } + scope(constraints: constraints) { yield } end # Allows you to set default parameters for a route, such as this: @@ -1062,6 +1058,10 @@ module ActionDispatch def merge_shallow_scope(parent, child) #:nodoc: child ? true : false end + + def merge_to_scope(parent, child) + child + end end # Resource routing allows you to quickly declare all of the common routes @@ -1553,11 +1553,13 @@ module ActionDispatch # match 'path' => 'controller#action', via: patch # match 'path', to: 'controller#action', via: :post # match 'path', 'otherpath', on: :member, via: :get - def match(path, *rest) + def match(path, *rest, &block) if rest.empty? && Hash === path options = path path, to = options.find { |name, _value| name.is_a?(String) } + raise ArgumentError, "Route path not specified" if path.nil? + case to when Symbol options[:action] = to @@ -1578,110 +1580,13 @@ module ActionDispatch paths = [path] + rest end - if options[:on] && !VALID_ON_OPTIONS.include?(options[:on]) - raise ArgumentError, "Unknown scope #{on.inspect} given to :on" - end - - if @scope[:controller] && @scope[:action] - options[:to] ||= "#{@scope[:controller]}##{@scope[:action]}" - end - - controller = options.delete(:controller) || @scope[:controller] - option_path = options.delete :path - to = options.delete :to - via = Mapping.check_via Array(options.delete(:via) { - @scope[:via] - }) - formatted = options.delete(:format) { @scope[:format] } - anchor = options.delete(:anchor) { true } - options_constraints = options.delete(:constraints) || {} - - path_types = paths.group_by(&:class) - path_types.fetch(String, []).each do |_path| - route_options = options.dup - if _path && option_path - ActiveSupport::Deprecation.warn <<-eowarn -Specifying strings for both :path and the route path is deprecated. Change things like this: - - match #{_path.inspect}, :path => #{option_path.inspect} - -to this: - - match #{option_path.inspect}, :as => #{_path.inspect}, :action => #{path.inspect} - eowarn - route_options[:action] = _path - route_options[:as] = _path - _path = option_path - end - to = get_to_from_path(_path, to, route_options[:action]) - decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints) - end - - path_types.fetch(Symbol, []).each do |action| - route_options = options.dup - decomposed_match(action, controller, route_options, option_path, to, via, formatted, anchor, options_constraints) - end - - self - end - - def get_to_from_path(path, to, action) - return to if to || action - - path_without_format = path.sub(/\(\.:format\)$/, '') - if using_match_shorthand?(path_without_format) - path_without_format.gsub(%r{^/}, "").sub(%r{/([^/]*)$}, '#\1').tr("-", "_") - else - nil - end - end - - def using_match_shorthand?(path) - path =~ %r{^/?[-\w]+/[-\w/]+$} - end - - def decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) # :nodoc: - if on = options.delete(:on) - send(on) { decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) } + if options.key?(:defaults) + defaults(options.delete(:defaults)) { map_match(paths, options, &block) } else - case @scope.scope_level - when :resources - nested { decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) } - when :resource - member { decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) } - else - add_route(path, controller, options, _path, to, via, formatted, anchor, options_constraints) - end + map_match(paths, options, &block) end end - def add_route(action, controller, options, _path, to, via, formatted, anchor, options_constraints) # :nodoc: - path = path_for_action(action, _path) - raise ArgumentError, "path is required" if path.blank? - - action = action.to_s - - default_action = options.delete(:action) || @scope[:action] - - if action =~ /^[\w\-\/]+$/ - default_action ||= action.tr('-', '_') unless action.include?("/") - else - action = nil - end - - as = if !options.fetch(:as, true) # if it's set to nil or false - options.delete(:as) - else - name_for_action(options.delete(:as), action) - end - - path = Mapping.normalize_path URI.parser.escape(path), formatted - ast = Journey::Parser.parse path - - mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options) - @set.add_route(mapping, ast, as, anchor) - end - # You can specify what Rails should route "/" to with the root method: # # root to: 'pages#main' @@ -1698,7 +1603,7 @@ to this: def root(path, options = {}) if path.is_a?(String) options[:to] = path - elsif path.is_a?(Hash) and options.empty? + elsif path.is_a?(Hash) && options.empty? options = path else raise ArgumentError, "must be called with a path and/or options" @@ -1787,7 +1692,7 @@ to this: end def resource_scope(resource) #:nodoc: - @scope = @scope.new(:scope_level_resource => resource) + @scope = @scope.new(scope_level_resource: resource) controller(resource.resource_scope) { yield } ensure @@ -1795,7 +1700,7 @@ to this: end def nested_options #:nodoc: - options = { :as => parent_resource.member_name } + options = { as: parent_resource.member_name } options[:constraints] = { parent_resource.nested_param => param_constraint } if param_constraint? @@ -1822,8 +1727,8 @@ to this: end def shallow_scope #:nodoc: - scope = { :as => @scope[:shallow_prefix], - :path => @scope[:shallow_path] } + scope = { as: @scope[:shallow_prefix], + path: @scope[:shallow_path] } @scope = @scope.new scope yield @@ -1852,8 +1757,8 @@ to this: prefix = action end - if prefix && prefix != '/' && !prefix.empty? - Mapper.normalize_name prefix.to_s.tr('-', '_') + if prefix && prefix != "/" && !prefix.empty? + Mapper.normalize_name prefix.to_s.tr("-", "_") end end @@ -1869,7 +1774,7 @@ to this: end action_name = @scope.action_name(name_prefix, prefix, collection_name, member_name) - candidate = action_name.select(&:present?).join('_') + candidate = action_name.select(&:present?).join("_") unless candidate.empty? # If a name was not explicitly given, we check if it is valid @@ -1898,19 +1803,120 @@ to this: def api_only? @set.api_only? end + private - def path_scope(path) - @scope = @scope.new(path: merge_path_scope(@scope[:path], path)) - yield - ensure - @scope = @scope.parent - end + def path_scope(path) + @scope = @scope.new(path: merge_path_scope(@scope[:path], path)) + yield + ensure + @scope = @scope.parent + end - def match_root_route(options) - name = has_named_route?(:root) ? nil : :root - match '/', { :as => name, :via => :get }.merge!(options) - end + def map_match(paths, options) + if options[:on] && !VALID_ON_OPTIONS.include?(options[:on]) + raise ArgumentError, "Unknown scope #{on.inspect} given to :on" + end + + if @scope[:to] + options[:to] ||= @scope[:to] + end + + if @scope[:controller] && @scope[:action] + options[:to] ||= "#{@scope[:controller]}##{@scope[:action]}" + end + + controller = options.delete(:controller) || @scope[:controller] + option_path = options.delete :path + to = options.delete :to + via = Mapping.check_via Array(options.delete(:via) { + @scope[:via] + }) + formatted = options.delete(:format) { @scope[:format] } + anchor = options.delete(:anchor) { true } + options_constraints = options.delete(:constraints) || {} + + path_types = paths.group_by(&:class) + path_types.fetch(String, []).each do |_path| + route_options = options.dup + if _path && option_path + raise ArgumentError, "Ambigous route definition. Both :path and the route path where specified as strings." + end + to = get_to_from_path(_path, to, route_options[:action]) + decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints) + end + + path_types.fetch(Symbol, []).each do |action| + route_options = options.dup + decomposed_match(action, controller, route_options, option_path, to, via, formatted, anchor, options_constraints) + end + + self + end + + def get_to_from_path(path, to, action) + return to if to || action + + path_without_format = path.sub(/\(\.:format\)$/, "") + if using_match_shorthand?(path_without_format) + path_without_format.gsub(%r{^/}, "").sub(%r{/([^/]*)$}, '#\1').tr("-", "_") + else + nil + end + end + + def using_match_shorthand?(path) + path =~ %r{^/?[-\w]+/[-\w/]+$} + end + + def decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) # :nodoc: + if on = options.delete(:on) + send(on) { decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) } + else + case @scope.scope_level + when :resources + nested { decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) } + when :resource + member { decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) } + else + add_route(path, controller, options, _path, to, via, formatted, anchor, options_constraints) + end + end + end + + def add_route(action, controller, options, _path, to, via, formatted, anchor, options_constraints) # :nodoc: + path = path_for_action(action, _path) + raise ArgumentError, "path is required" if path.blank? + + action = action.to_s + + default_action = options.delete(:action) || @scope[:action] + + if action =~ /^[\w\-\/]+$/ + default_action ||= action.tr("-", "_") unless action.include?("/") + else + action = nil + end + + as = if !options.fetch(:as, true) # if it's set to nil or false + options.delete(:as) + else + name_for_action(options.delete(:as), action) + end + + path = Mapping.normalize_path URI.parser.escape(path), formatted + ast = Journey::Parser.parse path + + mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options) + @set.add_route(mapping, ast, as, anchor) + end + + def match_root_route(options) + name = has_named_route?(name_for_action(:root, nil)) ? nil : :root + args = ["/", { as: name, via: :get }.merge!(options)] + + match(*args) + end end # Routing Concerns allow you to declare common routes that can be reused @@ -2021,7 +2027,7 @@ to this: class Scope # :nodoc: OPTIONS = [:path, :shallow_path, :as, :shallow_prefix, :module, :controller, :action, :path_names, :constraints, - :shallow, :blocks, :defaults, :via, :format, :options] + :shallow, :blocks, :defaults, :via, :format, :options, :to] RESOURCE_SCOPES = [:resource, :resources] RESOURCE_METHOD_SCOPES = [:collection, :member, :new] @@ -2101,7 +2107,7 @@ to this: def initialize(set) #:nodoc: @set = set - @scope = Scope.new({ :path_names => @set.resources_path_names }) + @scope = Scope.new(path_names: @set.resources_path_names) @concerns = {} end diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index 9934f5547a..4f1aaeefc8 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -4,7 +4,7 @@ module ActionDispatch # given an Active Record model instance. They are to be used in combination with # ActionController::Resources. # - # These methods are useful when you want to generate correct URL or path to a RESTful + # These methods are useful when you want to generate the correct URL or path to a RESTful # resource without having to know the exact type of the record in question. # # Nested resources and/or namespaces are also supported, as illustrated in the example: @@ -79,7 +79,7 @@ module ActionDispatch # polymorphic_url([blog, post], anchor: 'my_anchor', script_name: "/my_app") # # => "http://example.com/my_app/blogs/1/posts/1#my_anchor" # - # For all of these options, see the documentation for <tt>url_for</tt>. + # For all of these options, see the documentation for {url_for}[rdoc-ref:ActionDispatch::Routing::UrlFor]. # # ==== Functionality # @@ -134,7 +134,6 @@ module ActionDispatch opts end - %w(edit new).each do |action| module_eval <<-EOT, __FILE__, __LINE__ + 1 def #{action}_polymorphic_url(record_or_hash, options = {}) @@ -149,176 +148,175 @@ module ActionDispatch private - def polymorphic_url_for_action(action, record_or_hash, options) - polymorphic_url(record_or_hash, options.merge(:action => action)) - end + def polymorphic_url_for_action(action, record_or_hash, options) + polymorphic_url(record_or_hash, options.merge(action: action)) + end - def polymorphic_path_for_action(action, record_or_hash, options) - polymorphic_path(record_or_hash, options.merge(:action => action)) - end + def polymorphic_path_for_action(action, record_or_hash, options) + polymorphic_path(record_or_hash, options.merge(action: action)) + end - class HelperMethodBuilder # :nodoc: - CACHE = { 'path' => {}, 'url' => {} } + class HelperMethodBuilder # :nodoc: + CACHE = { "path" => {}, "url" => {} } - def self.get(action, type) - type = type.to_s - CACHE[type].fetch(action) { build action, type } - end + def self.get(action, type) + type = type.to_s + CACHE[type].fetch(action) { build action, type } + end - def self.url; CACHE['url'.freeze][nil]; end - def self.path; CACHE['path'.freeze][nil]; end + def self.url; CACHE["url".freeze][nil]; end + def self.path; CACHE["path".freeze][nil]; end - def self.build(action, type) - prefix = action ? "#{action}_" : "" - suffix = type - if action.to_s == 'new' - HelperMethodBuilder.singular prefix, suffix - else - HelperMethodBuilder.plural prefix, suffix + def self.build(action, type) + prefix = action ? "#{action}_" : "" + suffix = type + if action.to_s == "new" + HelperMethodBuilder.singular prefix, suffix + else + HelperMethodBuilder.plural prefix, suffix + end end - end - def self.singular(prefix, suffix) - new(->(name) { name.singular_route_key }, prefix, suffix) - end + def self.singular(prefix, suffix) + new(->(name) { name.singular_route_key }, prefix, suffix) + end - def self.plural(prefix, suffix) - new(->(name) { name.route_key }, prefix, suffix) - end + def self.plural(prefix, suffix) + new(->(name) { name.route_key }, prefix, suffix) + end - def self.polymorphic_method(recipient, record_or_hash_or_array, action, type, options) - builder = get action, type + def self.polymorphic_method(recipient, record_or_hash_or_array, action, type, options) + builder = get action, type + + case record_or_hash_or_array + when Array + record_or_hash_or_array = record_or_hash_or_array.compact + if record_or_hash_or_array.empty? + raise ArgumentError, "Nil location provided. Can't build URI." + end + if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy) + recipient = record_or_hash_or_array.shift + end + + method, args = builder.handle_list record_or_hash_or_array + when String, Symbol + method, args = builder.handle_string record_or_hash_or_array + when Class + method, args = builder.handle_class record_or_hash_or_array - case record_or_hash_or_array - when Array - record_or_hash_or_array = record_or_hash_or_array.compact - if record_or_hash_or_array.empty? + when nil raise ArgumentError, "Nil location provided. Can't build URI." + else + method, args = builder.handle_model record_or_hash_or_array end - if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy) - recipient = record_or_hash_or_array.shift - end - - method, args = builder.handle_list record_or_hash_or_array - when String, Symbol - method, args = builder.handle_string record_or_hash_or_array - when Class - method, args = builder.handle_class record_or_hash_or_array - when nil - raise ArgumentError, "Nil location provided. Can't build URI." - else - method, args = builder.handle_model record_or_hash_or_array + if options.empty? + recipient.send(method, *args) + else + recipient.send(method, *args, options) + end end + attr_reader :suffix, :prefix - if options.empty? - recipient.send(method, *args) - else - recipient.send(method, *args, options) + def initialize(key_strategy, prefix, suffix) + @key_strategy = key_strategy + @prefix = prefix + @suffix = suffix end - end - - attr_reader :suffix, :prefix - - def initialize(key_strategy, prefix, suffix) - @key_strategy = key_strategy - @prefix = prefix - @suffix = suffix - end - - def handle_string(record) - [get_method_for_string(record), []] - end - - def handle_string_call(target, str) - target.send get_method_for_string str - end - def handle_class(klass) - [get_method_for_class(klass), []] - end + def handle_string(record) + [get_method_for_string(record), []] + end - def handle_class_call(target, klass) - target.send get_method_for_class klass - end + def handle_string_call(target, str) + target.send get_method_for_string str + end - def handle_model(record) - args = [] + def handle_class(klass) + [get_method_for_class(klass), []] + end - model = record.to_model - named_route = if model.persisted? - args << model - get_method_for_string model.model_name.singular_route_key - else - get_method_for_class model - end + def handle_class_call(target, klass) + target.send get_method_for_class klass + end - [named_route, args] - end + def handle_model(record) + args = [] - def handle_model_call(target, model) - method, args = handle_model model - target.send(method, *args) - end + model = record.to_model + named_route = if model.persisted? + args << model + get_method_for_string model.model_name.singular_route_key + else + get_method_for_class model + end - def handle_list(list) - record_list = list.dup - record = record_list.pop + [named_route, args] + end - args = [] + def handle_model_call(target, model) + method, args = handle_model model + target.send(method, *args) + end - route = record_list.map { |parent| - case parent + def handle_list(list) + record_list = list.dup + record = record_list.pop + + args = [] + + route = record_list.map { |parent| + case parent + when Symbol, String + parent.to_s + when Class + args << parent + parent.model_name.singular_route_key + else + args << parent.to_model + parent.to_model.model_name.singular_route_key + end + } + + route << + case record when Symbol, String - parent.to_s + record.to_s when Class - args << parent - parent.model_name.singular_route_key + @key_strategy.call record.model_name else - args << parent.to_model - parent.to_model.model_name.singular_route_key + model = record.to_model + if model.persisted? + args << model + model.model_name.singular_route_key + else + @key_strategy.call model.model_name + end end - } - - route << - case record - when Symbol, String - record.to_s - when Class - @key_strategy.call record.model_name - else - model = record.to_model - if model.persisted? - args << model - model.model_name.singular_route_key - else - @key_strategy.call model.model_name - end - end - route << suffix + route << suffix - named_route = prefix + route.join("_") - [named_route, args] - end + named_route = prefix + route.join("_") + [named_route, args] + end - private + private - def get_method_for_class(klass) - name = @key_strategy.call klass.model_name - get_method_for_string name - end + def get_method_for_class(klass) + name = @key_strategy.call klass.model_name + get_method_for_string name + end - def get_method_for_string(str) - "#{prefix}#{str}_#{suffix}" - end + def get_method_for_string(str) + "#{prefix}#{str}_#{suffix}" + end - [nil, 'new', 'edit'].each do |action| - CACHE['url'][action] = build action, 'url' - CACHE['path'][action] = build action, 'path' + [nil, "new", "edit"].each do |action| + CACHE["url"][action] = build action, "url" + CACHE["path"][action] = build action, "path" + end end - end end end end diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index d6987f4d09..87bcceccc0 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -1,9 +1,9 @@ -require 'action_dispatch/http/request' -require 'active_support/core_ext/uri' -require 'active_support/core_ext/array/extract_options' -require 'rack/utils' -require 'action_controller/metal/exceptions' -require 'action_dispatch/routing/endpoint' +require "action_dispatch/http/request" +require "active_support/core_ext/uri" +require "active_support/core_ext/array/extract_options" +require "rack/utils" +require "action_controller/metal/exceptions" +require "action_dispatch/routing/endpoint" module ActionDispatch module Routing @@ -22,7 +22,6 @@ module ActionDispatch end def serve(req) - req.check_path_parameters! uri = URI.parse(path(req.path_parameters, req)) unless uri.host @@ -40,9 +39,9 @@ module ActionDispatch body = %(<html><body>You are being <a href="#{ERB::Util.unwrapped_html_escape(uri.to_s)}">redirected</a>.</body></html>) headers = { - 'Location' => uri.to_s, - 'Content-Type' => 'text/html', - 'Content-Length' => body.length.to_s + "Location" => uri.to_s, + "Content-Type" => "text/html", + "Content-Length" => body.length.to_s } [ status, headers, [body] ] @@ -58,19 +57,19 @@ module ActionDispatch private def relative_path?(path) - path && !path.empty? && path[0] != '/' + path && !path.empty? && path[0] != "/" end def escape(params) - Hash[params.map{ |k,v| [k, Rack::Utils.escape(v)] }] + Hash[params.map { |k,v| [k, Rack::Utils.escape(v)] }] end def escape_fragment(params) - Hash[params.map{ |k,v| [k, Journey::Router::Utils.escape_fragment(v)] }] + Hash[params.map { |k,v| [k, Journey::Router::Utils.escape_fragment(v)] }] end def escape_path(params) - Hash[params.map{ |k,v| [k, Journey::Router::Utils.escape_path(v)] }] + Hash[params.map { |k,v| [k, Journey::Router::Utils.escape_path(v)] }] end end @@ -104,11 +103,11 @@ module ActionDispatch def path(params, request) url_options = { - :protocol => request.protocol, - :host => request.host, - :port => request.optional_port, - :path => request.path, - :params => request.query_parameters + protocol: request.protocol, + host: request.host, + port: request.optional_port, + path: request.path, + params: request.query_parameters }.merge! options if !params.empty? && url_options[:path].match(/%\{\w*\}/) @@ -129,12 +128,11 @@ module ActionDispatch end def inspect - "redirect(#{status}, #{options.map{ |k,v| "#{k}: #{v}" }.join(', ')})" + "redirect(#{status}, #{options.map { |k,v| "#{k}: #{v}" }.join(', ')})" end end module Redirection - # Redirect any path to another path: # # get "/stories" => redirect("/posts") diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index ed7130b58e..a1bc357c8b 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -1,12 +1,12 @@ -require 'action_dispatch/journey' -require 'active_support/concern' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/module/remove_method' -require 'active_support/core_ext/array/extract_options' -require 'action_controller/metal/exceptions' -require 'action_dispatch/http/request' -require 'action_dispatch/routing/endpoint' +require "action_dispatch/journey" +require "active_support/concern" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/array/extract_options" +require "action_controller/metal/exceptions" +require "action_dispatch/http/request" +require "action_dispatch/routing/endpoint" module ActionDispatch module Routing @@ -34,7 +34,7 @@ module ActionDispatch if @raise_on_name_error raise else - return [404, {'X-Cascade' => 'pass'}, []] + return [404, { "X-Cascade" => "pass" }, []] end end @@ -59,7 +59,7 @@ module ActionDispatch private - def controller(_); @controller_class; end + def controller(_); @controller_class; end end # A NamedRouteCollection instance is a collection of named routes, and also @@ -180,40 +180,40 @@ module ActionDispatch private - def optimized_helper(args) - params = parameterize_args(args) do - raise_generation_error(args) - end + def optimized_helper(args) + params = parameterize_args(args) do + raise_generation_error(args) + end - @route.format params - end + @route.format params + end - def optimize_routes_generation?(t) - t.send(:optimize_routes_generation?) - end + def optimize_routes_generation?(t) + t.send(:optimize_routes_generation?) + end - def parameterize_args(args) - params = {} - @arg_size.times { |i| - key = @required_parts[i] - value = args[i].to_param - yield key if value.nil? || value.empty? - params[key] = value - } - params - end + def parameterize_args(args) + params = {} + @arg_size.times { |i| + key = @required_parts[i] + value = args[i].to_param + yield key if value.nil? || value.empty? + params[key] = value + } + params + end - def raise_generation_error(args) - missing_keys = [] - params = parameterize_args(args) { |missing_key| - missing_keys << missing_key - } - constraints = Hash[@route.requirements.merge(params).sort_by{|k,v| k.to_s}] - message = "No route matches #{constraints.inspect}" - message << " missing required keys: #{missing_keys.sort.inspect}" + def raise_generation_error(args) + missing_keys = [] + params = parameterize_args(args) { |missing_key| + missing_keys << missing_key + } + constraints = Hash[@route.requirements.merge(params).sort_by { |k,v| k.to_s }] + message = "No route matches #{constraints.inspect}" + message << ", missing required keys: #{missing_keys.sort.inspect}" - raise ActionController::UrlGenerationError, message - end + raise ActionController::UrlGenerationError, message + end end def initialize(route, options, route_name, url_strategy) @@ -264,38 +264,39 @@ module ActionDispatch end private - # Create a url helper allowing ordered parameters to be associated - # with corresponding dynamic segments, so you can do: - # - # foo_url(bar, baz, bang) - # - # Instead of: - # - # foo_url(bar: bar, baz: baz, bang: bang) - # - # Also allow options hash, so you can do: - # - # foo_url(bar, baz, bang, sort_by: 'baz') - # - def define_url_helper(mod, route, name, opts, route_key, url_strategy) - helper = UrlHelper.create(route, opts, route_key, url_strategy) - mod.module_eval do - define_method(name) do |*args| - last = args.last - options = case last - when Hash - args.pop - when ActionController::Parameters - if last.permitted? - args.pop.to_h - else - raise ArgumentError, ActionDispatch::Routing::INSECURE_URL_PARAMETERS_MESSAGE - end - end - helper.call self, args, options + # Create a url helper allowing ordered parameters to be associated + # with corresponding dynamic segments, so you can do: + # + # foo_url(bar, baz, bang) + # + # Instead of: + # + # foo_url(bar: bar, baz: baz, bang: bang) + # + # Also allow options hash, so you can do: + # + # foo_url(bar, baz, bang, sort_by: 'baz') + # + def define_url_helper(mod, route, name, opts, route_key, url_strategy) + helper = UrlHelper.create(route, opts, route_key, url_strategy) + mod.module_eval do + define_method(name) do |*args| + last = args.last + options = \ + case last + when Hash + args.pop + when ActionController::Parameters + if last.permitted? + args.pop.to_h + else + raise ArgumentError, ActionDispatch::Routing::INSECURE_URL_PARAMETERS_MESSAGE + end + end + helper.call self, args, options + end end end - end end # strategy for building urls to send to the client @@ -310,7 +311,7 @@ module ActionDispatch alias :routes :set def self.default_resources_path_names - { :new => 'new', :edit => 'edit' } + { new: "new", edit: "edit" } end def self.new_with_config(config) @@ -581,12 +582,12 @@ module ActionDispatch # be "index", not the recalled action of "show". if options[:controller] - options[:action] ||= 'index' + options[:action] ||= "index" options[:controller] = options[:controller].to_s end if options.key?(:action) - options[:action] = (options[:action] || 'index').to_s + options[:action] = (options[:action] || "index").to_s end end @@ -596,8 +597,8 @@ module ActionDispatch # :controller, :action or :id is not found, don't pull any # more keys from the recall. def normalize_controller_action_id! - use_recall_for(:controller) or return - use_recall_for(:action) or return + use_recall_for(:controller) || return + use_recall_for(:action) || return use_recall_for(:id) end @@ -605,7 +606,7 @@ module ActionDispatch # is specified, the controller becomes "foo/baz/bat" def use_relative_controller! if !named_route && different_controller? && !controller.start_with?("/") - old_parts = current_controller.split('/') + old_parts = current_controller.split("/") size = controller.count("/") + 1 parts = old_parts[0...-size] << controller @options[:controller] = parts.join("/") @@ -670,7 +671,7 @@ module ActionDispatch end def find_script_name(options) - options.delete(:script_name) || find_relative_url_root(options) || '' + options.delete(:script_name) || find_relative_url_root(options) || "" end def find_relative_url_root(options) @@ -731,7 +732,7 @@ module ActionDispatch extras = environment[:extras] || {} begin - env = Rack::MockRequest.env_for(path, {:method => method}) + env = Rack::MockRequest.env_for(path, method: method) rescue URI::InvalidURIError => e raise ActionController::RoutingError, e.message end diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb index 040ea04046..ee847eaeed 100644 --- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb +++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/array/extract_options" module ActionDispatch module Routing @@ -19,7 +19,7 @@ module ActionDispatch end end - def respond_to?(method, include_private = false) + def respond_to_missing?(method, include_private = false) super || @helpers.respond_to?(method) end diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 5ee138e6c6..a1ac5a2b6c 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -194,20 +194,20 @@ module ActionDispatch protected - def optimize_routes_generation? - _routes.optimize_routes_generation? && default_url_options.empty? - end + def optimize_routes_generation? + _routes.optimize_routes_generation? && default_url_options.empty? + end - def _with_routes(routes) - old_routes, @_routes = @_routes, routes - yield - ensure - @_routes = old_routes - end + def _with_routes(routes) + old_routes, @_routes = @_routes, routes + yield + ensure + @_routes = old_routes + end - def _routes_context - self - end + def _routes_context + self + end end end end diff --git a/actionpack/lib/action_dispatch/testing/assertion_response.rb b/actionpack/lib/action_dispatch/testing/assertion_response.rb index 404b96bbcd..c37726957e 100644 --- a/actionpack/lib/action_dispatch/testing/assertion_response.rb +++ b/actionpack/lib/action_dispatch/testing/assertion_response.rb @@ -34,12 +34,12 @@ module ActionDispatch private - def code_from_name(name) - GENERIC_RESPONSE_CODES[name] || Rack::Utils::SYMBOL_TO_STATUS_CODE[name] - end + def code_from_name(name) + GENERIC_RESPONSE_CODES[name] || Rack::Utils::SYMBOL_TO_STATUS_CODE[name] + end - def name_from_code(code) - GENERIC_RESPONSE_CODES.invert[code] || Rack::Utils::HTTP_STATUS_CODES[code] - end + def name_from_code(code) + GENERIC_RESPONSE_CODES.invert[code] || Rack::Utils::HTTP_STATUS_CODES[code] + end end end diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb index fae266273e..b362931ef7 100644 --- a/actionpack/lib/action_dispatch/testing/assertions.rb +++ b/actionpack/lib/action_dispatch/testing/assertions.rb @@ -1,9 +1,9 @@ -require 'rails-dom-testing' +require "rails-dom-testing" module ActionDispatch module Assertions - autoload :ResponseAssertions, 'action_dispatch/testing/assertions/response' - autoload :RoutingAssertions, 'action_dispatch/testing/assertions/routing' + autoload :ResponseAssertions, "action_dispatch/testing/assertions/response" + autoload :RoutingAssertions, "action_dispatch/testing/assertions/routing" extend ActiveSupport::Concern diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index cd55b7d975..a2eaccd9ef 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -79,11 +79,16 @@ module ActionDispatch def generate_response_message(expected, actual = @response.response_code) "Expected response to be a <#{code_with_name(expected)}>,"\ " but was a <#{code_with_name(actual)}>" - .concat location_if_redirected + .concat(location_if_redirected).concat(response_body_if_short) + end + + def response_body_if_short + return "" if @response.body.size > 500 + "\nResponse body: #{@response.body}" end def location_if_redirected - return '' unless @response.redirection? && @response.location.present? + return "" unless @response.redirection? && @response.location.present? location = normalize_argument_to_redirection(@response.location) " redirect to <#{location}>" end diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 44ad2c10d8..e53bc6af12 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -1,7 +1,7 @@ -require 'uri' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/string/access' -require 'action_controller/metal/exceptions' +require "uri" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/string/access" +require "action_controller/metal/exceptions" module ActionDispatch module Assertions @@ -82,7 +82,7 @@ module ActionDispatch expected_path = uri.path.to_s.empty? ? "/" : uri.path end else - expected_path = "/#{expected_path}" unless expected_path.first == '/' + expected_path = "/#{expected_path}" unless expected_path.first == "/" end # Load routes.rb if it hasn't been loaded. @@ -127,7 +127,7 @@ module ActionDispatch options[:controller] = "/#{controller}" end - generate_options = options.dup.delete_if{ |k, _| defaults.key?(k) } + generate_options = options.dup.delete_if { |k, _| defaults.key?(k) } assert_generates(path.is_a?(Hash) ? path[:path] : path, generate_options, defaults, extras, message) end @@ -184,7 +184,7 @@ module ActionDispatch end # Assume given controller - request = ActionController::TestRequest.create + request = ActionController::TestRequest.create @controller.class if path =~ %r{://} fail_on(URI::InvalidURIError, msg) do @@ -202,7 +202,7 @@ module ActionDispatch request.request_method = method if method params = fail_on(ActionController::RoutingError, msg) do - @routes.recognize_path(path, { :method => method, :extras => extras }) + @routes.recognize_path(path, method: method, extras: extras) end request.path_parameters = params.with_indifferent_access diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 8777666f9f..e2ea96513c 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -1,106 +1,51 @@ -require 'stringio' -require 'uri' -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/object/try' -require 'active_support/core_ext/string/strip' -require 'rack/test' -require 'minitest' +require "stringio" +require "uri" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/object/try" +require "active_support/core_ext/string/strip" +require "rack/test" +require "minitest" + +require "action_dispatch/testing/request_encoder" module ActionDispatch module Integration #:nodoc: module RequestHelpers - # Performs a GET request with the given parameters. - # - # - +path+: The URI (as a String) on which you want to perform a GET - # request. - # - +params+: The HTTP parameters that you want to pass. This may - # be +nil+, - # a Hash, or a String that is appropriately encoded - # (<tt>application/x-www-form-urlencoded</tt> or - # <tt>multipart/form-data</tt>). - # - +headers+: Additional headers to pass, as a Hash. The headers will be - # merged into the Rack env hash. - # - +env+: Additional env to pass, as a Hash. The headers will be - # merged into the Rack env hash. - # - # This method returns a Response object, which one can use to - # inspect the details of the response. Furthermore, if this method was - # called from an ActionDispatch::IntegrationTest object, then that - # object's <tt>@response</tt> instance variable will point to the same - # response object. - # - # You can also perform POST, PATCH, PUT, DELETE, and HEAD requests with - # +#post+, +#patch+, +#put+, +#delete+, and +#head+. - # - # Example: - # - # get '/feed', params: { since: 201501011400 } - # post '/profile', headers: { "X-Test-Header" => "testvalue" } - def get(path, *args) - process_with_kwargs(:get, path, *args) + # Performs a GET request with the given parameters. See +#process+ for more + # details. + def get(path, **args) + process(:get, path, **args) end - # Performs a POST request with the given parameters. See +#get+ for more + # Performs a POST request with the given parameters. See +#process+ for more # details. - def post(path, *args) - process_with_kwargs(:post, path, *args) + def post(path, **args) + process(:post, path, **args) end - # Performs a PATCH request with the given parameters. See +#get+ for more + # Performs a PATCH request with the given parameters. See +#process+ for more # details. - def patch(path, *args) - process_with_kwargs(:patch, path, *args) + def patch(path, **args) + process(:patch, path, **args) end - # Performs a PUT request with the given parameters. See +#get+ for more + # Performs a PUT request with the given parameters. See +#process+ for more # details. - def put(path, *args) - process_with_kwargs(:put, path, *args) + def put(path, **args) + process(:put, path, **args) end - # Performs a DELETE request with the given parameters. See +#get+ for + # Performs a DELETE request with the given parameters. See +#process+ for # more details. - def delete(path, *args) - process_with_kwargs(:delete, path, *args) + def delete(path, **args) + process(:delete, path, **args) end - # Performs a HEAD request with the given parameters. See +#get+ for more + # Performs a HEAD request with the given parameters. See +#process+ for more # details. def head(path, *args) - process_with_kwargs(:head, path, *args) - end - - # Performs an XMLHttpRequest request with the given parameters, mirroring - # an AJAX request made from JavaScript. - # - # The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or - # +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart - # string; the headers are a hash. - # - # Example: - # - # xhr :get, '/feed', params: { since: 201501011400 } - def xml_http_request(request_method, path, *args) - if kwarg_request?(args) - params, headers, env = args.first.values_at(:params, :headers, :env) - else - params = args[0] - headers = args[1] - env = {} - - if params.present? || headers.present? - non_kwarg_request_warning - end - end - - ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc) - xhr and xml_http_request methods are deprecated in favor of - `get "/posts", xhr: true` and `post "/posts/1", xhr: true`. - MSG - - process(request_method, path, params: params, headers: headers, xhr: true) + process(:head, path, *args) end - alias xhr :xml_http_request # Follow a single redirect response. If the last response was not a # redirect, an exception will be raised. Otherwise, the redirect is @@ -110,59 +55,6 @@ module ActionDispatch get(response.location) status end - - # Performs a request using the specified method, following any subsequent - # redirect. Note that the redirects are followed until the response is - # not a redirect--this means you may run into an infinite loop if your - # redirect loops back to itself. - # - # Example: - # - # request_via_redirect :post, '/welcome', - # params: { ref_id: 14 }, - # headers: { "X-Test-Header" => "testvalue" } - def request_via_redirect(http_method, path, *args) - ActiveSupport::Deprecation.warn('`request_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior.') - process_with_kwargs(http_method, path, *args) - - follow_redirect! while redirect? - status - end - - # Performs a GET request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def get_via_redirect(path, *args) - ActiveSupport::Deprecation.warn('`get_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior.') - request_via_redirect(:get, path, *args) - end - - # Performs a POST request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def post_via_redirect(path, *args) - ActiveSupport::Deprecation.warn('`post_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior.') - request_via_redirect(:post, path, *args) - end - - # Performs a PATCH request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def patch_via_redirect(path, *args) - ActiveSupport::Deprecation.warn('`patch_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior.') - request_via_redirect(:patch, path, *args) - end - - # Performs a PUT request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def put_via_redirect(path, *args) - ActiveSupport::Deprecation.warn('`put_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior.') - request_via_redirect(:put, path, *args) - end - - # Performs a DELETE request, following any subsequent redirect. - # See +request_via_redirect+ for more information. - def delete_via_redirect(path, *args) - ActiveSupport::Deprecation.warn('`delete_via_redirect` is deprecated and will be removed in Rails 5.1. Please use `follow_redirect!` manually after the request call for the same behavior.') - request_via_redirect(:delete, path, *args) - end end # An instance of this class represents a set of requests and responses @@ -177,14 +69,14 @@ module ActionDispatch DEFAULT_HOST = "www.example.com" include Minitest::Assertions - include TestProcess, RequestHelpers, Assertions + include RequestHelpers, Assertions %w( status status_message headers body redirect? ).each do |method| - delegate method, :to => :response, :allow_nil => true + delegate method, to: :response, allow_nil: true end %w( path ).each do |method| - delegate method, :to => :request, :allow_nil => true + delegate method, to: :request, allow_nil: true end # The hostname used in the last request. @@ -235,7 +127,7 @@ module ActionDispatch url_options.reverse_merge!(@app.routes.default_url_options) end - url_options.reverse_merge!(:host => host, :protocol => https? ? "https" : "http") + url_options.reverse_merge!(host: host, protocol: https? ? "https" : "http") end end @@ -281,169 +173,129 @@ module ActionDispatch @https end - # Set the host name to use in the next request. + # Performs the actual request. # - # session.host! "www.example.com" - alias :host! :host= - - private - def _mock_session - @_mock_session ||= Rack::MockSession.new(@app, host) - end - - def process_with_kwargs(http_method, path, *args) - if kwarg_request?(args) - process(http_method, path, *args) - else - non_kwarg_request_warning if args.any? - process(http_method, path, { params: args[0], headers: args[1] }) - end - end - - REQUEST_KWARGS = %i(params headers env xhr as) - def kwarg_request?(args) - args[0].respond_to?(:keys) && args[0].keys.any? { |k| REQUEST_KWARGS.include?(k) } - end - - def non_kwarg_request_warning - ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc) - ActionDispatch::IntegrationTest HTTP request methods will accept only - the following keyword arguments in future Rails versions: - #{REQUEST_KWARGS.join(', ')} - - Examples: - - get '/profile', - params: { id: 1 }, - headers: { 'X-Extra-Header' => '123' }, - env: { 'action_dispatch.custom' => 'custom' }, - xhr: true, - as: :json - MSG + # - +method+: The HTTP method (GET, POST, PATCH, PUT, DELETE, HEAD, OPTIONS) + # as a symbol. + # - +path+: The URI (as a String) on which you want to perform the + # request. + # - +params+: The HTTP parameters that you want to pass. This may + # be +nil+, + # a Hash, or a String that is appropriately encoded + # (<tt>application/x-www-form-urlencoded</tt> or + # <tt>multipart/form-data</tt>). + # - +headers+: Additional headers to pass, as a Hash. The headers will be + # merged into the Rack env hash. + # - +env+: Additional env to pass, as a Hash. The headers will be + # merged into the Rack env hash. + # + # This method is rarely used directly. Use +#get+, +#post+, or other standard + # HTTP methods in integration tests. +#process+ is only required when using a + # request method that doesn't have a method defined in the integration tests. + # + # This method returns a Response object, which one can use to + # inspect the details of the response. Furthermore, if this method was + # called from an ActionDispatch::IntegrationTest object, then that + # object's <tt>@response</tt> instance variable will point to the same + # response object. + # + # Example: + # process :get, '/author', params: { since: 201501011400 } + def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil) + request_encoder = RequestEncoder.encoder(as) + headers ||= {} + + if method == :get && as == :json && params + headers["X-Http-Method-Override"] = "GET" + method = :post end - # Performs the actual request. - def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil) - request_encoder = RequestEncoder.encoder(as) - - if path =~ %r{://} - location = URI.parse(path) + if path =~ %r{://} + path = build_expanded_path(path, request_encoder) do |location| https! URI::HTTPS === location if location.scheme + if url_host = location.host default = Rack::Request::DEFAULT_PORTS[location.scheme] url_host += ":#{location.port}" if default != location.port host! url_host end - path = request_encoder.append_format_to location.path - path = location.query ? "#{path}?#{location.query}" : path - else - path = request_encoder.append_format_to path end + elsif as + path = build_expanded_path(path, request_encoder) + end - hostname, port = host.split(':') - - request_env = { - :method => method, - :params => request_encoder.encode_params(params), - - "SERVER_NAME" => hostname, - "SERVER_PORT" => port || (https? ? "443" : "80"), - "HTTPS" => https? ? "on" : "off", - "rack.url_scheme" => https? ? "https" : "http", - - "REQUEST_URI" => path, - "HTTP_HOST" => host, - "REMOTE_ADDR" => remote_addr, - "CONTENT_TYPE" => request_encoder.content_type, - "HTTP_ACCEPT" => accept - } + hostname, port = host.split(":") - if xhr - headers ||= {} - headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' - headers['HTTP_ACCEPT'] ||= [Mime[:js], Mime[:html], Mime[:xml], 'text/xml', '*/*'].join(', ') - end + request_env = { + :method => method, + :params => request_encoder.encode_params(params), - # this modifies the passed request_env directly - if headers.present? - Http::Headers.from_hash(request_env).merge!(headers) - end - if env.present? - Http::Headers.from_hash(request_env).merge!(env) - end + "SERVER_NAME" => hostname, + "SERVER_PORT" => port || (https? ? "443" : "80"), + "HTTPS" => https? ? "on" : "off", + "rack.url_scheme" => https? ? "https" : "http", - session = Rack::Test::Session.new(_mock_session) - - # NOTE: rack-test v0.5 doesn't build a default uri correctly - # Make sure requested path is always a full uri - session.request(build_full_uri(path, request_env), request_env) - - @request_count += 1 - @request = ActionDispatch::Request.new(session.last_request.env) - response = _mock_session.last_response - @response = ActionDispatch::TestResponse.from_response(response) - @response.request = @request - @response.response_parser = RequestEncoder.parser(@response.content_type) - @html_document = nil - @url_options = nil + "REQUEST_URI" => path, + "HTTP_HOST" => host, + "REMOTE_ADDR" => remote_addr, + "CONTENT_TYPE" => request_encoder.content_type, + "HTTP_ACCEPT" => accept + } - @controller = @request.controller_instance + wrapped_headers = Http::Headers.from_hash({}) + wrapped_headers.merge!(headers) if headers - response.status + if xhr + wrapped_headers["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" + wrapped_headers["HTTP_ACCEPT"] ||= [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ") end - def build_full_uri(path, env) - "#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}" + # this modifies the passed request_env directly + if wrapped_headers.present? + Http::Headers.from_hash(request_env).merge!(wrapped_headers) + end + if env.present? + Http::Headers.from_hash(request_env).merge!(env) end - class RequestEncoder # :nodoc: - @encoders = {} - - attr_reader :response_parser - - def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false) - @mime = Mime[mime_name] - - unless @mime - raise ArgumentError, "Can't register a request encoder for " \ - "unregistered MIME Type: #{mime_name}. See `Mime::Type.register`." - end + session = Rack::Test::Session.new(_mock_session) - @url_encoded_form = url_encoded_form - @path_format = ".#{@mime.symbol}" unless @url_encoded_form - @response_parser = response_parser || -> body { body } - @param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc - end - - def append_format_to(path) - path << @path_format unless @url_encoded_form - path - end + # NOTE: rack-test v0.5 doesn't build a default uri correctly + # Make sure requested path is always a full uri + session.request(build_full_uri(path, request_env), request_env) - def content_type - @mime.to_s - end + @request_count += 1 + @request = ActionDispatch::Request.new(session.last_request.env) + response = _mock_session.last_response + @response = ActionDispatch::TestResponse.from_response(response) + @response.request = @request + @html_document = nil + @url_options = nil - def encode_params(params) - @param_encoder.call(params) - end + @controller = @request.controller_instance - def self.parser(content_type) - mime = Mime::Type.lookup(content_type) - encoder(mime ? mime.ref : nil).response_parser - end + response.status + end - def self.encoder(name) - @encoders[name] || WWWFormEncoder - end + # Set the host name to use in the next request. + # + # session.host! "www.example.com" + alias :host! :host= - def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil) - @encoders[mime_name] = new(mime_name, param_encoder, response_parser) - end + private + def _mock_session + @_mock_session ||= Rack::MockSession.new(@app, host) + end - register_encoder :json, response_parser: -> body { JSON.parse(body) } + def build_full_uri(path, env) + "#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}" + end - WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true) + def build_expanded_path(path, request_encoder) + location = URI.parse(path) + yield location if block_given? + path = request_encoder.append_format_to location.path + location.query ? "#{path}?#{location.query}" : path end end @@ -454,9 +306,13 @@ module ActionDispatch attr_reader :app + def initialize(*args, &blk) + super(*args, &blk) + @integration_session = nil + end + def before_setup # :nodoc: @app = nil - @integration_session = nil super end @@ -490,7 +346,7 @@ module ActionDispatch xml_http_request xhr get_via_redirect post_via_redirect).each do |method| define_method(method) do |*args| # reset the html_document variable, except for cookies/assigns calls - unless method == 'cookies' || method == 'assigns' + unless method == "cookies" || method == "assigns" @html_document = nil end @@ -532,7 +388,7 @@ module ActionDispatch integration_session.default_url_options = options end - def respond_to?(method, include_private = false) + def respond_to_missing?(method, include_private = false) integration_session.respond_to?(method, include_private) || super end @@ -701,42 +557,48 @@ module ActionDispatch # end # end # + # See the {request helpers documentation}[rdoc-ref:ActionDispatch::Integration::RequestHelpers] for help on how to + # use +get+, etc. + # + # === Changing the request encoding + # # You can also test your JSON API easily by setting what the request should # be encoded as: # - # require 'test_helper' + # require "test_helper" # # class ApiTest < ActionDispatch::IntegrationTest - # test 'creates articles' do + # test "creates articles" do # assert_difference -> { Article.count } do - # post articles_path, params: { article: { title: 'Ahoy!' } }, as: :json + # post articles_path, params: { article: { title: "Ahoy!" } }, as: :json # end # # assert_response :success - # assert_equal({ id: Arcticle.last.id, title: 'Ahoy!' }, response.parsed_body) + # assert_equal({ id: Arcticle.last.id, title: "Ahoy!" }, response.parsed_body) # end # end # - # The `as` option sets the format to JSON, sets the content type to - # 'application/json' and encodes the parameters as JSON. + # The +as+ option sets the format to JSON, sets the content type to + # "application/json" and encodes the parameters as JSON. # - # Calling `parsed_body` on the response parses the response body as what - # the last request was encoded as. If the request wasn't encoded `as` something, - # it's the same as calling `body`. + # Calling +parsed_body+ on the response parses the response body based on the + # last response MIME type. # - # For any custom MIME Types you've registered, you can even add your own encoders with: + # For any custom MIME types you've registered, you can even add your own encoders with: # # ActionDispatch::IntegrationTest.register_encoder :wibble, # param_encoder: -> params { params.to_wibble }, # response_parser: -> body { body } # - # Where `param_encoder` defines how the params should be encoded and - # `response_parser` defines how the response body should be parsed through - # `parsed_body`. + # Where +param_encoder+ defines how the params should be encoded and + # +response_parser+ defines how the response body should be parsed through + # +parsed_body+. # # Consult the Rails Testing Guide for more. class IntegrationTest < ActiveSupport::TestCase + include TestProcess + module UrlOptions extend ActiveSupport::Concern def url_options @@ -759,7 +621,11 @@ module ActionDispatch module ClassMethods def app - defined?(@@app) ? @@app : ActionDispatch.test_app + if defined?(@@app) && @@app + @@app + else + ActionDispatch.test_app + end end def app=(app) @@ -767,7 +633,7 @@ module ActionDispatch end def register_encoder(*args) - Integration::Session::RequestEncoder.register_encoder(*args) + RequestEncoder.register_encoder(*args) end end diff --git a/actionpack/lib/action_dispatch/testing/request_encoder.rb b/actionpack/lib/action_dispatch/testing/request_encoder.rb new file mode 100644 index 0000000000..b0b994b2d0 --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/request_encoder.rb @@ -0,0 +1,54 @@ +module ActionDispatch + class RequestEncoder # :nodoc: + @encoders = {} + + attr_reader :response_parser + + def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false) + @mime = Mime[mime_name] + + unless @mime + raise ArgumentError, "Can't register a request encoder for " \ + "unregistered MIME Type: #{mime_name}. See `Mime::Type.register`." + end + + @url_encoded_form = url_encoded_form + @path_format = ".#{@mime.symbol}" unless @url_encoded_form + @response_parser = response_parser || -> body { body } + @param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc + end + + def append_format_to(path) + if @url_encoded_form + path + else + path + @path_format + end + end + + def content_type + @mime.to_s + end + + def encode_params(params) + @param_encoder.call(params) + end + + def self.parser(content_type) + mime = Mime::Type.lookup(content_type) + encoder(mime ? mime.ref : nil).response_parser + end + + def self.encoder(name) + @encoders[name] || WWWFormEncoder + end + + def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil) + @encoders[mime_name] = new(mime_name, param_encoder, response_parser) + end + + register_encoder :json, response_parser: -> body { JSON.parse(body) } + + WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true) + end +end diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb index 1ecd7d14a7..8b03b776fa 100644 --- a/actionpack/lib/action_dispatch/testing/test_process.rb +++ b/actionpack/lib/action_dispatch/testing/test_process.rb @@ -1,5 +1,5 @@ -require 'action_dispatch/middleware/cookies' -require 'action_dispatch/middleware/flash' +require "action_dispatch/middleware/cookies" +require "action_dispatch/middleware/flash" module ActionDispatch module TestProcess @@ -34,7 +34,8 @@ module ActionDispatch # # post :change_avatar, avatar: fixture_file_upload('files/spongebob.png', 'image/png', :binary) def fixture_file_upload(path, mime_type = nil, binary = false) - if self.class.respond_to?(:fixture_path) && self.class.fixture_path + if self.class.respond_to?(:fixture_path) && self.class.fixture_path && + !File.exist?(path) path = File.join(self.class.fixture_path, path) end Rack::Test::UploadedFile.new(path, mime_type, binary) diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index 46523a8600..91b25ec155 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -1,12 +1,12 @@ -require 'active_support/core_ext/hash/indifferent_access' -require 'rack/utils' +require "active_support/core_ext/hash/indifferent_access" +require "rack/utils" module ActionDispatch class TestRequest < Request - DEFAULT_ENV = Rack::MockRequest.env_for('/', - 'HTTP_HOST' => 'test.host', - 'REMOTE_ADDR' => '0.0.0.0', - 'HTTP_USER_AGENT' => 'Rails Testing', + DEFAULT_ENV = Rack::MockRequest.env_for("/", + "HTTP_HOST" => "test.host", + "REMOTE_ADDR" => "0.0.0.0", + "HTTP_USER_AGENT" => "Rails Testing", ) # Create a new test request with default `env` values @@ -22,23 +22,23 @@ module ActionDispatch private_class_method :default_env def request_method=(method) - set_header('REQUEST_METHOD', method.to_s.upcase) + super(method.to_s.upcase) end def host=(host) - set_header('HTTP_HOST', host) + set_header("HTTP_HOST", host) end def port=(number) - set_header('SERVER_PORT', number.to_i) + set_header("SERVER_PORT", number.to_i) end def request_uri=(uri) - set_header('REQUEST_URI', uri) + set_header("REQUEST_URI", uri) end def path=(path) - set_header('PATH_INFO', path) + set_header("PATH_INFO", path) end def action=(action_name) @@ -46,24 +46,24 @@ module ActionDispatch end def if_modified_since=(last_modified) - set_header('HTTP_IF_MODIFIED_SINCE', last_modified) + set_header("HTTP_IF_MODIFIED_SINCE", last_modified) end def if_none_match=(etag) - set_header('HTTP_IF_NONE_MATCH', etag) + set_header("HTTP_IF_NONE_MATCH", etag) end def remote_addr=(addr) - set_header('REMOTE_ADDR', addr) + set_header("REMOTE_ADDR", addr) end def user_agent=(user_agent) - set_header('HTTP_USER_AGENT', user_agent) + set_header("HTTP_USER_AGENT", user_agent) end def accept=(mime_types) - delete_header('action_dispatch.request.accepts') - set_header('HTTP_ACCEPT', Array(mime_types).collect(&:to_s).join(",")) + delete_header("action_dispatch.request.accepts") + set_header("HTTP_ACCEPT", Array(mime_types).collect(&:to_s).join(",")) end end end diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index 9d4b73a43d..5c89f9c75e 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -1,3 +1,5 @@ +require "action_dispatch/testing/request_encoder" + module ActionDispatch # Integration test methods such as ActionDispatch::Integration::Session#get # and ActionDispatch::Integration::Session#post return objects of class @@ -10,6 +12,11 @@ module ActionDispatch new response.status, response.headers, response.body end + def initialize(*) # :nodoc: + super + @response_parser = RequestEncoder.parser(content_type) + end + # Was the response successful? alias_method :success?, :successful? @@ -19,8 +26,6 @@ module ActionDispatch # Was there a server-side error? alias_method :error?, :server_error? - attr_writer :response_parser # :nodoc: - def parsed_body @parsed_body ||= @response_parser.call(body) end diff --git a/actionpack/lib/action_pack.rb b/actionpack/lib/action_pack.rb index 941877d10d..ee6dabd133 100644 --- a/actionpack/lib/action_pack.rb +++ b/actionpack/lib/action_pack.rb @@ -21,4 +21,4 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'action_pack/version' +require "action_pack/version" diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index 7088cd2760..3d96158431 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActionPack # Returns the version of the currently loaded ActionPack as a <tt>Gem::Version</tt> diff --git a/actionpack/test/abstract/callbacks_test.rb b/actionpack/test/abstract/callbacks_test.rb index 07571602e4..9c2261bf76 100644 --- a/actionpack/test/abstract/callbacks_test.rb +++ b/actionpack/test/abstract/callbacks_test.rb @@ -1,8 +1,7 @@ -require 'abstract_unit' +require "abstract_unit" module AbstractController module Testing - class ControllerWithCallbacks < AbstractController::Base include AbstractController::Callbacks end @@ -114,8 +113,8 @@ module AbstractController end class CallbacksWithConditions < ControllerWithCallbacks - before_action :list, :only => :index - before_action :authenticate, :except => :index + before_action :list, only: :index + before_action :authenticate, except: :index def index self.response_body = @list.join(", ") @@ -126,14 +125,14 @@ module AbstractController end private - def list - @list = ["Hello", "World"] - end - - def authenticate - @list ||= [] - @authenticated = "true" - end + def list + @list = ["Hello", "World"] + end + + def authenticate + @list ||= [] + @authenticated = "true" + end end class TestCallbacksWithConditions < ActiveSupport::TestCase @@ -170,14 +169,14 @@ module AbstractController end private - def list - @list = ["Hello", "World"] - end - - def authenticate - @list = [] - @authenticated = "true" - end + def list + @list = ["Hello", "World"] + end + + def authenticate + @list = [] + @authenticated = "true" + end end class TestCallbacksWithArrayConditions < ActiveSupport::TestCase @@ -202,7 +201,7 @@ module AbstractController end class ChangedConditions < Callback2 - before_action :first, :only => :index + before_action :first, only: :index def not_index @text ||= nil @@ -265,53 +264,5 @@ module AbstractController assert_equal "Hello world Howdy!", controller.response_body end end - - class AliasedCallbacks < ControllerWithCallbacks - ActiveSupport::Deprecation.silence do - before_filter :first - after_filter :second - around_filter :aroundz - end - - def first - @text = "Hello world" - end - - def second - @second = "Goodbye" - end - - def aroundz - @aroundz = "FIRST" - yield - @aroundz << "SECOND" - end - - def index - @text ||= nil - self.response_body = @text.to_s - end - end - - class TestAliasedCallbacks < ActiveSupport::TestCase - def setup - @controller = AliasedCallbacks.new - end - - test "before_filter works" do - @controller.process(:index) - assert_equal "Hello world", @controller.response_body - end - - test "after_filter works" do - @controller.process(:index) - assert_equal "Goodbye", @controller.instance_variable_get("@second") - end - - test "around_filter works" do - @controller.process(:index) - assert_equal "FIRSTSECOND", @controller.instance_variable_get("@aroundz") - end - end end end diff --git a/actionpack/test/abstract/collector_test.rb b/actionpack/test/abstract/collector_test.rb index edbb84d462..7fe19e6b10 100644 --- a/actionpack/test/abstract/collector_test.rb +++ b/actionpack/test/abstract/collector_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module AbstractController module Testing diff --git a/actionpack/test/abstract/translation_test.rb b/actionpack/test/abstract/translation_test.rb index 1435928578..0c4071df8d 100644 --- a/actionpack/test/abstract/translation_test.rb +++ b/actionpack/test/abstract/translation_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module AbstractController module Testing @@ -9,21 +9,20 @@ module AbstractController class TranslationControllerTest < ActiveSupport::TestCase def setup @controller = TranslationController.new - I18n.backend.store_translations(:en, { + I18n.backend.store_translations(:en, one: { - two: 'bar', + two: "bar", }, abstract_controller: { testing: { translation: { index: { - foo: 'bar', + foo: "bar", }, - no_action: 'no_action_tr', + no_action: "no_action_tr", }, }, - }, - }) + }) end def test_action_controller_base_responds_to_translate @@ -44,30 +43,30 @@ module AbstractController def test_lazy_lookup @controller.stub :action_name, :index do - assert_equal 'bar', @controller.t('.foo') + assert_equal "bar", @controller.t(".foo") end end def test_lazy_lookup_with_symbol @controller.stub :action_name, :index do - assert_equal 'bar', @controller.t(:'.foo') + assert_equal "bar", @controller.t(:'.foo') end end def test_lazy_lookup_fallback @controller.stub :action_name, :index do - assert_equal 'no_action_tr', @controller.t(:'.no_action') + assert_equal "no_action_tr", @controller.t(:'.no_action') end end def test_default_translation @controller.stub :action_name, :index do - assert_equal 'bar', @controller.t('one.two') + assert_equal "bar", @controller.t("one.two") end end def test_localize - time, expected = Time.gm(2000), 'Sat, 01 Jan 2000 00:00:00 +0000' + time, expected = Time.gm(2000), "Sat, 01 Jan 2000 00:00:00 +0000" I18n.stub :localize, expected do assert_equal expected, @controller.l(time) end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 1e1d6f5429..6d28753947 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -1,8 +1,8 @@ -$:.unshift(File.dirname(__FILE__) + '/lib') -$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') -$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') +$:.unshift(File.dirname(__FILE__) + "/lib") +$:.unshift(File.dirname(__FILE__) + "/fixtures/helpers") +$:.unshift(File.dirname(__FILE__) + "/fixtures/alternate_helpers") -require 'active_support/core_ext/kernel/reporting' +require "active_support/core_ext/kernel/reporting" # These are the normal settings that will be set up by Railties # TODO: Have these tests support other combinations of these values @@ -11,31 +11,30 @@ silence_warnings do Encoding.default_external = "UTF-8" end -require 'drb' +require "drb" begin - require 'drb/unix' + require "drb/unix" rescue LoadError puts "'drb/unix' is not available" end -if ENV['TRAVIS'] +if ENV["TRAVIS"] PROCESS_COUNT = 0 else - PROCESS_COUNT = (ENV['N'] || 4).to_i + PROCESS_COUNT = (ENV["N"] || 4).to_i end -require 'active_support/testing/autorun' -require 'abstract_controller' -require 'abstract_controller/railties/routes_helpers' -require 'action_controller' -require 'action_view' -require 'action_view/testing/resolvers' -require 'action_dispatch' -require 'active_support/dependencies' -require 'active_model' -require 'active_record' +require "active_support/testing/autorun" +require "abstract_controller" +require "abstract_controller/railties/routes_helpers" +require "action_controller" +require "action_view" +require "action_view/testing/resolvers" +require "action_dispatch" +require "active_support/dependencies" +require "active_model" -require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late +require "pp" # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late module Rails class << self @@ -57,13 +56,13 @@ ActiveSupport::Deprecation.debug = true # Disable available locale checks to avoid warnings running the test suite. I18n.enforce_available_locales = false -FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') +FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), "fixtures") SharedTestRoutes = ActionDispatch::Routing::RouteSet.new SharedTestRoutes.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action)' + get ":controller(/:action)" end end @@ -105,6 +104,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase middleware.use ActionDispatch::Callbacks middleware.use ActionDispatch::Cookies middleware.use ActionDispatch::Flash + middleware.use Rack::MethodOverride middleware.use Rack::Head yield(middleware) if block_given? end @@ -114,7 +114,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase app.routes.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action)' + get ":controller(/:action)" end end @@ -122,27 +122,19 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase # Stub Rails dispatcher so it does not get controller references and # simply return the controller#action as Rack::Body. class NullController < ::ActionController::Metal - def initialize(controller_name) - @controller = controller_name - end - - def make_response!(request) - self.class.make_response! request - end - - def dispatch(action, req, res) - [200, {'Content-Type' => 'text/html'}, ["#{@controller}##{action}"]] + def self.dispatch(action, req, res) + [200, { "Content-Type" => "text/html" }, ["#{req.params[:controller]}##{action}"]] end end - class NullControllerRequest < DelegateClass(ActionDispatch::Request) + class NullControllerRequest < ActionDispatch::Request def controller_class - NullController.new params[:controller] + NullController end end - def make_request env - NullControllerRequest.new super + def make_request(env) + NullControllerRequest.new env end end @@ -159,7 +151,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase yield temporary_routes ensure self.class.app = old_app - self.remove! + remove! silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) } end @@ -172,7 +164,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase ActiveSupport::Dependencies.autoload_paths << path yield ensure - ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path} + ActiveSupport::Dependencies.autoload_paths.reject! { |p| p == path } ActiveSupport::Dependencies.clear end end @@ -183,7 +175,7 @@ end class Rack::TestCase < ActionDispatch::IntegrationTest def self.testing(klass = nil) if klass - @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '') + @testing = "/#{klass.name.underscore}".sub!(/_controller$/, "") else @testing end @@ -247,18 +239,17 @@ module ActionController end end - class ::ApplicationController < ActionController::Base end module ActionDispatch class DebugExceptions private - remove_method :stderr_logger - # Silence logger - def stderr_logger - nil - end + remove_method :stderr_logger + # Silence logger + def stderr_logger + nil + end end end @@ -268,16 +259,16 @@ module ActionDispatch host = uri_or_host.host unless path path ||= uri_or_host.path - params = {'PATH_INFO' => path, - 'REQUEST_METHOD' => method, - 'HTTP_HOST' => host} + params = { "PATH_INFO" => path, + "REQUEST_METHOD" => method, + "HTTP_HOST" => host } routes.call(params) end def request_path_params(path, options = {}) - method = options[:method] || 'GET' - resp = send_request URI('http://localhost' + path), method.to_s.upcase, nil + method = options[:method] || "GET" + resp = send_request URI("http://localhost" + path), method.to_s.upcase, nil status = resp.first if status == 404 raise ActionController::RoutingError, "No route matches #{path.inspect}" @@ -286,23 +277,23 @@ module ActionDispatch end def get(uri_or_host, path = nil) - send_request(uri_or_host, 'GET', path)[2].join + send_request(uri_or_host, "GET", path)[2].join end def post(uri_or_host, path = nil) - send_request(uri_or_host, 'POST', path)[2].join + send_request(uri_or_host, "POST", path)[2].join end def put(uri_or_host, path = nil) - send_request(uri_or_host, 'PUT', path)[2].join + send_request(uri_or_host, "PUT", path)[2].join end def delete(uri_or_host, path = nil) - send_request(uri_or_host, 'DELETE', path)[2].join + send_request(uri_or_host, "DELETE", path)[2].join end def patch(uri_or_host, path = nil) - send_request(uri_or_host, 'PATCH', path)[2].join + send_request(uri_or_host, "PATCH", path)[2].join end end end @@ -310,7 +301,7 @@ end module RoutingTestHelpers def url_for(set, options) route_name = options.delete :use_route - set.url_for options.merge(:only_path => true), route_name + set.url_for options.merge(only_path: true), route_name end def make_set(strict = true) @@ -348,9 +339,9 @@ module RoutingTestHelpers private - def make_request(env) - Request.new super, url_helpers, @block, strict - end + def make_request(env) + Request.new super, url_helpers, @block, strict + end end end @@ -364,15 +355,15 @@ class AccountsController < ResourcesController; end class ImagesController < ResourcesController; end # Skips the current run on Rubinius using Minitest::Assertions#skip -def rubinius_skip(message = '') - skip message if RUBY_ENGINE == 'rbx' +def rubinius_skip(message = "") + skip message if RUBY_ENGINE == "rbx" end # Skips the current run on JRuby using Minitest::Assertions#skip -def jruby_skip(message = '') +def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end -require 'active_support/testing/method_call_assertions' +require "active_support/testing/method_call_assertions" class ForkingExecutor class Server @@ -382,27 +373,27 @@ class ForkingExecutor @queue = Queue.new end - def record reporter, result + def record(reporter, result) reporter.record result end - def << o + def <<(o) o[2] = DRbObject.new(o[2]) if o @queue << o end def pop; @queue.pop; end end - def initialize size + def initialize(size) @size = size @queue = Server.new - file = File.join Dir.tmpdir, Dir::Tmpname.make_tmpname('rails-tests', 'fd') + file = File.join Dir.tmpdir, Dir::Tmpname.make_tmpname("rails-tests", "fd") @url = "drbunix://#{file}" @pool = nil DRb.start_service @url, @queue end - def << work; @queue << work; end + def <<(work); @queue << work; end def shutdown pool = @size.times.map { @@ -426,18 +417,18 @@ class ForkingExecutor end private - def translate_exceptions(result) - result.failures.map! { |e| - begin - Marshal.dump e - e - rescue TypeError - ex = Exception.new e.message - ex.set_backtrace e.backtrace - Minitest::UnexpectedError.new ex - end - } - end + def translate_exceptions(result) + result.failures.map! { |e| + begin + Marshal.dump e + e + rescue TypeError + ex = Exception.new e.message + ex.set_backtrace e.backtrace + Minitest::UnexpectedError.new ex + end + } + end end if RUBY_ENGINE == "ruby" && PROCESS_COUNT > 0 diff --git a/actionpack/test/assertions/response_assertions_test.rb b/actionpack/test/assertions/response_assertions_test.rb index 57a67a48b5..14a04ccdb1 100644 --- a/actionpack/test/assertions/response_assertions_test.rb +++ b/actionpack/test/assertions/response_assertions_test.rb @@ -1,15 +1,16 @@ -require 'abstract_unit' -require 'action_dispatch/testing/assertions/response' +require "abstract_unit" +require "action_dispatch/testing/assertions/response" module ActionDispatch module Assertions class ResponseAssertionsTest < ActiveSupport::TestCase include ResponseAssertions - FakeResponse = Struct.new(:response_code, :location) do + FakeResponse = Struct.new(:response_code, :location, :body) do def initialize(*) super self.location ||= "http://test.example.com/posts" + self.body ||= "" end [:successful, :not_found, :redirection, :server_error].each do |sym| @@ -26,7 +27,7 @@ module ActionDispatch def test_assert_response_predicate_methods [:success, :missing, :redirect, :error].each do |sym| - @response = FakeResponse.new RESPONSE_PREDICATES[sym].to_s.sub(/\?/, '').to_sym + @response = FakeResponse.new RESPONSE_PREDICATES[sym].to_s.sub(/\?/, "").to_sym assert_response sym assert_raises(Minitest::Assertion) { @@ -92,7 +93,7 @@ module ActionDispatch def test_error_message_shows_302_redirect_when_302_asserted_for_success @response = ActionDispatch::Response.new @response.status = 302 - @response.location = 'http://test.host/posts/redirect/1' + @response.location = "http://test.host/posts/redirect/1" error = assert_raises(Minitest::Assertion) { assert_response :success } expected = "Expected response to be a <2XX: success>,"\ @@ -104,7 +105,7 @@ module ActionDispatch def test_error_message_shows_302_redirect_when_302_asserted_for_301 @response = ActionDispatch::Response.new @response.status = 302 - @response.location = 'http://test.host/posts/redirect/2' + @response.location = "http://test.host/posts/redirect/2" error = assert_raises(Minitest::Assertion) { assert_response 301 } expected = "Expected response to be a <301: Moved Permanently>,"\ @@ -112,6 +113,27 @@ module ActionDispatch " redirect to <http://test.host/posts/redirect/2>" assert_match expected, error.message end + + def test_error_message_shows_short_response_body + @response = ActionDispatch::Response.new + @response.status = 400 + @response.body = "not too long" + error = assert_raises(Minitest::Assertion) { assert_response 200 } + expected = "Expected response to be a <200: OK>,"\ + " but was a <400: Bad Request>" \ + "\nResponse body: not too long" + assert_match expected, error.message + end + + def test_error_message_does_not_show_long_response_body + @response = ActionDispatch::Response.new + @response.status = 400 + @response.body = "not too long" * 50 + error = assert_raises(Minitest::Assertion) { assert_response 200 } + expected = "Expected response to be a <200: OK>,"\ + " but was a <400: Bad Request>" + assert_match expected, error.message + end end end end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index db71aa2160..b08f1f1707 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -1,33 +1,32 @@ -require 'abstract_unit' -require 'controller/fake_controllers' +require "abstract_unit" +require "controller/fake_controllers" class ActionPackAssertionsController < ActionController::Base - def nothing() head :ok end - def hello_xml_world() render :template => "test/hello_xml_world"; end + def hello_xml_world() render template: "test/hello_xml_world"; end def hello_xml_world_pdf self.content_type = "application/pdf" - render :template => "test/hello_xml_world" + render template: "test/hello_xml_world" end def hello_xml_world_pdf_header response.headers["Content-Type"] = "application/pdf; charset=utf-8" - render :template => "test/hello_xml_world" + render template: "test/hello_xml_world" end def redirect_internal() redirect_to "/nothing"; end - def redirect_to_action() redirect_to :action => "flash_me", :id => 1, :params => { "panda" => "fun" }; end + def redirect_to_action() redirect_to action: "flash_me", id: 1, params: { "panda" => "fun" }; end - def redirect_to_controller() redirect_to :controller => "elsewhere", :action => "flash_me"; end + def redirect_to_controller() redirect_to controller: "elsewhere", action: "flash_me"; end - def redirect_to_controller_with_symbol() redirect_to :controller => :elsewhere, :action => :flash_me; end + def redirect_to_controller_with_symbol() redirect_to controller: :elsewhere, action: :flash_me; end - def redirect_to_path() redirect_to '/some/path' end + def redirect_to_path() redirect_to "/some/path" end - def redirect_invalid_external_route() redirect_to 'ht_tp://www.rubyonrails.org' end + def redirect_invalid_external_route() redirect_to "ht_tp://www.rubyonrails.org" end def redirect_to_named_route() redirect_to route_one_url end @@ -35,14 +34,14 @@ class ActionPackAssertionsController < ActionController::Base def redirect_external_protocol_relative() redirect_to "//www.rubyonrails.org"; end - def response404() head '404 AWOL' end + def response404() head "404 AWOL" end - def response500() head '500 Sorry' end + def response500() head "500 Sorry" end - def response599() head '599 Whoah!' end + def response599() head "599 Whoah!" end def flash_me - flash['hello'] = 'my name is inigo montoya...' + flash["hello"] = "my name is inigo montoya..." render plain: "Inconceivable!" end @@ -53,7 +52,7 @@ class ActionPackAssertionsController < ActionController::Base def assign_this @howdy = "ho" - render :inline => "Mr. Henke" + render inline: "Mr. Henke" end def render_based_on_parameters @@ -69,7 +68,7 @@ class ActionPackAssertionsController < ActionController::Base end def session_stuffing - session['xmas'] = 'turkey' + session["xmas"] = "turkey" render plain: "ho ho ho" end @@ -84,11 +83,11 @@ class ActionPackAssertionsController < ActionController::Base end def render_file_absolute_path - render :file => File.expand_path('../../../README.rdoc', __FILE__) + render file: File.expand_path("../../../README.rdoc", __FILE__) end def render_file_relative_path - render :file => 'README.rdoc' + render file: "README.rdoc" end end @@ -97,7 +96,7 @@ end # is expecting something other than an error. class AssertResponseWithUnexpectedErrorController < ActionController::Base def index - raise 'FAIL' + raise "FAIL" end def show @@ -116,21 +115,20 @@ module Admin end def redirect_to_absolute_controller - redirect_to :controller => '/content' + redirect_to controller: "/content" end def redirect_to_fellow_controller - redirect_to :controller => 'user' + redirect_to controller: "user" end def redirect_to_top_level_named_route - redirect_to top_level_url(:id => "foo") + redirect_to top_level_url(id: "foo") end end end class ActionPackAssertionsControllerTest < ActionController::TestCase - def test_render_file_absolute_path get :render_file_absolute_path assert_match(/\A= Action Pack/, @response.body) @@ -144,30 +142,30 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_get_request assert_raise(RuntimeError) { get :raise_exception_on_get } get :raise_exception_on_post - assert_equal 'request method: GET', @response.body + assert_equal "request method: GET", @response.body end def test_post_request assert_raise(RuntimeError) { post :raise_exception_on_post } post :raise_exception_on_get - assert_equal 'request method: POST', @response.body + assert_equal "request method: POST", @response.body end def test_get_post_request_switch post :raise_exception_on_get - assert_equal 'request method: POST', @response.body + assert_equal "request method: POST", @response.body get :raise_exception_on_post - assert_equal 'request method: GET', @response.body + assert_equal "request method: GET", @response.body post :raise_exception_on_get - assert_equal 'request method: POST', @response.body + assert_equal "request method: POST", @response.body get :raise_exception_on_post - assert_equal 'request method: GET', @response.body + assert_equal "request method: GET", @response.body end def test_string_constraint with_routing do |set| set.draw do - get "photos", :to => 'action_pack_assertions#nothing', :constraints => {:subdomain => "admin"} + get "photos", to: "action_pack_assertions#nothing", constraints: { subdomain: "admin" } end end end @@ -175,22 +173,22 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_assert_redirect_to_named_route_failure with_routing do |set| set.draw do - get 'route_one', :to => 'action_pack_assertions#nothing', :as => :route_one - get 'route_two', :to => 'action_pack_assertions#nothing', :id => 'two', :as => :route_two + get "route_one", to: "action_pack_assertions#nothing", as: :route_one + get "route_two", to: "action_pack_assertions#nothing", id: "two", as: :route_two ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end process :redirect_to_named_route assert_raise(ActiveSupport::TestCase::Assertion) do - assert_redirected_to 'http://test.host/route_two' + assert_redirected_to "http://test.host/route_two" end assert_raise(ActiveSupport::TestCase::Assertion) do assert_redirected_to %r(^http://test.host/route_two) end assert_raise(ActiveSupport::TestCase::Assertion) do - assert_redirected_to :controller => 'action_pack_assertions', :action => 'nothing', :id => 'two' + assert_redirected_to controller: "action_pack_assertions", action: "nothing", id: "two" end assert_raise(ActiveSupport::TestCase::Assertion) do assert_redirected_to route_two_url @@ -203,10 +201,10 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase with_routing do |set| set.draw do - get 'admin/inner_module', :to => 'admin/inner_module#index', :as => :admin_inner_module + get "admin/inner_module", to: "admin/inner_module#index", as: :admin_inner_module ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end process :redirect_to_index @@ -220,10 +218,10 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase with_routing do |set| set.draw do - get '/action_pack_assertions/:id', :to => 'action_pack_assertions#index', :as => :top_level + get "/action_pack_assertions/:id", to: "action_pack_assertions#index", as: :top_level ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end process :redirect_to_top_level_named_route @@ -239,15 +237,15 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase with_routing do |set| set.draw do # this controller exists in the admin namespace as well which is the only difference from previous test - get '/user/:id', :to => 'user#index', :as => :top_level + get "/user/:id", to: "user#index", as: :top_level ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end process :redirect_to_top_level_named_route # assert_redirected_to top_level_url('foo') would pass because of exact match early return - assert_redirected_to top_level_path('foo') + assert_redirected_to top_level_path("foo") end end @@ -259,7 +257,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase assert_no_match( /#{request.protocol}#{request.host}\/\/www.rubyonrails.org/, ex.message, - 'protocol relative url was incorrectly normalized' + "protocol relative url was incorrectly normalized" ) end end @@ -283,7 +281,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_flash_exist process :flash_me assert flash.any? - assert flash['hello'].present? + assert flash["hello"].present? end def test_flash_does_not_exist @@ -293,7 +291,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_session_exist process :session_stuffing - assert_equal 'turkey', session['xmas'] + assert_equal "turkey", session["xmas"] end def session_does_not_exist @@ -303,13 +301,13 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_redirection_location process :redirect_internal - assert_equal 'http://test.host/nothing', @response.redirect_url + assert_equal "http://test.host/nothing", @response.redirect_url process :redirect_external - assert_equal 'http://www.rubyonrails.org', @response.redirect_url + assert_equal "http://www.rubyonrails.org", @response.redirect_url process :redirect_external_protocol_relative - assert_equal '//www.rubyonrails.org', @response.redirect_url + assert_equal "//www.rubyonrails.org", @response.redirect_url end def test_no_redirect_url @@ -376,24 +374,24 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_assert_redirection_fails_with_incorrect_controller process :redirect_to_controller assert_raise(ActiveSupport::TestCase::Assertion) do - assert_redirected_to :controller => "action_pack_assertions", :action => "flash_me" + assert_redirected_to controller: "action_pack_assertions", action: "flash_me" end end def test_assert_redirection_with_extra_controller_option get :redirect_to_action - assert_redirected_to :controller => 'action_pack_assertions', :action => "flash_me", :id => 1, :params => { :panda => 'fun' } + assert_redirected_to controller: "action_pack_assertions", action: "flash_me", id: 1, params: { panda: "fun" } end def test_redirected_to_url_leading_slash process :redirect_to_path - assert_redirected_to '/some/path' + assert_redirected_to "/some/path" end def test_redirected_to_url_no_leading_slash_fails process :redirect_to_path assert_raise ActiveSupport::TestCase::Assertion do - assert_redirected_to 'some/path' + assert_redirected_to "some/path" end end @@ -404,43 +402,43 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_redirected_to_url_full_url process :redirect_to_path - assert_redirected_to 'http://test.host/some/path' + assert_redirected_to "http://test.host/some/path" end def test_assert_redirection_with_symbol process :redirect_to_controller_with_symbol assert_nothing_raised { - assert_redirected_to :controller => "elsewhere", :action => "flash_me" + assert_redirected_to controller: "elsewhere", action: "flash_me" } process :redirect_to_controller_with_symbol assert_nothing_raised { - assert_redirected_to :controller => :elsewhere, :action => :flash_me + assert_redirected_to controller: :elsewhere, action: :flash_me } end def test_redirected_to_with_nested_controller @controller = Admin::InnerModuleController.new get :redirect_to_absolute_controller - assert_redirected_to :controller => '/content' + assert_redirected_to controller: "/content" get :redirect_to_fellow_controller - assert_redirected_to :controller => 'admin/user' + assert_redirected_to controller: "admin/user" end def test_assert_response_uses_exception_message @controller = AssertResponseWithUnexpectedErrorController.new - e = assert_raise RuntimeError, 'Expected non-success response' do + e = assert_raise RuntimeError, "Expected non-success response" do get :index end assert_response :success - assert_includes 'FAIL', e.message + assert_includes "FAIL", e.message end def test_assert_response_failure_response_with_no_exception @controller = AssertResponseWithUnexpectedErrorController.new get :show assert_response 500 - assert_equal 'Boom', response.body + assert_equal "Boom", response.body end end @@ -449,21 +447,21 @@ class ActionPackHeaderTest < ActionController::TestCase def test_rendering_xml_sets_content_type process :hello_xml_world - assert_equal('application/xml; charset=utf-8', @response.headers['Content-Type']) + assert_equal("application/xml; charset=utf-8", @response.headers["Content-Type"]) end def test_rendering_xml_respects_content_type process :hello_xml_world_pdf - assert_equal('application/pdf; charset=utf-8', @response.headers['Content-Type']) + assert_equal("application/pdf; charset=utf-8", @response.headers["Content-Type"]) end def test_rendering_xml_respects_content_type_when_set_in_the_header process :hello_xml_world_pdf_header - assert_equal('application/pdf; charset=utf-8', @response.headers['Content-Type']) + assert_equal("application/pdf; charset=utf-8", @response.headers["Content-Type"]) end def test_render_text_with_custom_content_type get :render_text_with_custom_content_type - assert_equal 'application/rss+xml; charset=utf-8', @response.headers['Content-Type'] + assert_equal "application/rss+xml; charset=utf-8", @response.headers["Content-Type"] end end diff --git a/actionpack/test/controller/api/conditional_get_test.rb b/actionpack/test/controller/api/conditional_get_test.rb index b4f1673be0..7b70829101 100644 --- a/actionpack/test/controller/api/conditional_get_test.rb +++ b/actionpack/test/controller/api/conditional_get_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/integer/time' -require 'active_support/core_ext/numeric/time' +require "abstract_unit" +require "active_support/core_ext/integer/time" +require "active_support/core_ext/numeric/time" class ConditionalGetApiController < ActionController::API before_action :handle_last_modified_and_etags, only: :two @@ -17,9 +17,9 @@ class ConditionalGetApiController < ActionController::API private - def handle_last_modified_and_etags - fresh_when(last_modified: Time.now.utc.beginning_of_day, etag: [ :foo, 123 ]) - end + def handle_last_modified_and_etags + fresh_when(last_modified: Time.now.utc.beginning_of_day, etag: [ :foo, 123 ]) + end end class ConditionalGetApiTest < ActionController::TestCase @@ -31,7 +31,7 @@ class ConditionalGetApiTest < ActionController::TestCase def test_request_gets_last_modified get :two - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] assert_response :success end @@ -52,6 +52,6 @@ class ConditionalGetApiTest < ActionController::TestCase get :one assert_equal 304, @response.status.to_i assert @response.body.blank? - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end end diff --git a/actionpack/test/controller/api/data_streaming_test.rb b/actionpack/test/controller/api/data_streaming_test.rb index 0e7d97d1f4..f15b78d102 100644 --- a/actionpack/test/controller/api/data_streaming_test.rb +++ b/actionpack/test/controller/api/data_streaming_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' +require "abstract_unit" module TestApiFileUtils def file_path() File.expand_path(__FILE__) end - def file_data() @data ||= File.open(file_path, 'rb') { |f| f.read } end + def file_data() @data ||= File.open(file_path, "rb") { |f| f.read } end end class DataStreamingApiController < ActionController::API @@ -19,7 +19,7 @@ class DataStreamingApiTest < ActionController::TestCase tests DataStreamingApiController def test_data - response = process('two') + response = process("two") assert_kind_of String, response.body assert_equal file_data, response.body end diff --git a/actionpack/test/controller/api/force_ssl_test.rb b/actionpack/test/controller/api/force_ssl_test.rb index 8578340d82..d239964e4a 100644 --- a/actionpack/test/controller/api/force_ssl_test.rb +++ b/actionpack/test/controller/api/force_ssl_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ForceSSLApiController < ActionController::API force_ssl diff --git a/actionpack/test/controller/api/implicit_render_test.rb b/actionpack/test/controller/api/implicit_render_test.rb index 26f9cd8f78..b51ee0cf42 100644 --- a/actionpack/test/controller/api/implicit_render_test.rb +++ b/actionpack/test/controller/api/implicit_render_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ImplicitRenderAPITestController < ActionController::API def empty_action diff --git a/actionpack/test/controller/api/params_wrapper_test.rb b/actionpack/test/controller/api/params_wrapper_test.rb index 53b3a0c3cc..a1da852040 100644 --- a/actionpack/test/controller/api/params_wrapper_test.rb +++ b/actionpack/test/controller/api/params_wrapper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ParamsWrapperForApiTest < ActionController::TestCase class UsersController < ActionController::API @@ -17,10 +17,10 @@ class ParamsWrapperForApiTest < ActionController::TestCase tests UsersController def test_specify_wrapper_name - @request.env['CONTENT_TYPE'] = 'application/json' - post :test, params: { 'username' => 'sikachu' } + @request.env["CONTENT_TYPE"] = "application/json" + post :test, params: { "username" => "sikachu" } - expected = { 'username' => 'sikachu', 'person' => { 'username' => 'sikachu' }} + expected = { "username" => "sikachu", "person" => { "username" => "sikachu" } } assert_equal expected, @controller.last_parameters end end diff --git a/actionpack/test/controller/api/redirect_to_test.rb b/actionpack/test/controller/api/redirect_to_test.rb index 18877c4b3a..ab14409f40 100644 --- a/actionpack/test/controller/api/redirect_to_test.rb +++ b/actionpack/test/controller/api/redirect_to_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class RedirectToApiController < ActionController::API def one diff --git a/actionpack/test/controller/api/renderers_test.rb b/actionpack/test/controller/api/renderers_test.rb index 911a8144b2..04e34a1f8f 100644 --- a/actionpack/test/controller/api/renderers_test.rb +++ b/actionpack/test/controller/api/renderers_test.rb @@ -1,14 +1,14 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash/conversions' +require "abstract_unit" +require "active_support/core_ext/hash/conversions" class RenderersApiController < ActionController::API class Model def to_json(options = {}) - { a: 'b' }.to_json(options) + { a: "b" }.to_json(options) end def to_xml(options = {}) - { a: 'b' }.to_xml(options) + { a: "b" }.to_xml(options) end end @@ -21,11 +21,7 @@ class RenderersApiController < ActionController::API end def plain - render plain: 'Hi from plain', status: 500 - end - - def text - render text: 'Hi from text', status: 500 + render plain: "Hi from plain", status: 500 end end @@ -35,26 +31,18 @@ class RenderersApiTest < ActionController::TestCase def test_render_json get :one assert_response :success - assert_equal({ a: 'b' }.to_json, @response.body) + assert_equal({ a: "b" }.to_json, @response.body) end def test_render_xml get :two assert_response :success - assert_equal({ a: 'b' }.to_xml, @response.body) + assert_equal({ a: "b" }.to_xml, @response.body) end def test_render_plain get :plain assert_response :internal_server_error - assert_equal('Hi from plain', @response.body) - end - - def test_render_text - assert_deprecated do - get :text - end - assert_response :internal_server_error - assert_equal('Hi from text', @response.body) + assert_equal("Hi from plain", @response.body) end end diff --git a/actionpack/test/controller/api/url_for_test.rb b/actionpack/test/controller/api/url_for_test.rb index 0d8691a091..cb4ae7a88a 100644 --- a/actionpack/test/controller/api/url_for_test.rb +++ b/actionpack/test/controller/api/url_for_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class UrlForApiController < ActionController::API def one; end @@ -10,7 +10,7 @@ class UrlForApiTest < ActionController::TestCase def setup super - @request.host = 'www.example.com' + @request.host = "www.example.com" end def test_url_for diff --git a/actionpack/test/controller/api/with_cookies_test.rb b/actionpack/test/controller/api/with_cookies_test.rb index 4491dc9002..8928237dfd 100644 --- a/actionpack/test/controller/api/with_cookies_test.rb +++ b/actionpack/test/controller/api/with_cookies_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class WithCookiesController < ActionController::API include ActionController::Cookies @@ -12,10 +12,10 @@ class WithCookiesTest < ActionController::TestCase tests WithCookiesController def test_with_cookies - request.cookies[:foobar] = 'bazbang' + request.cookies[:foobar] = "bazbang" get :with_cookies - assert_equal 'bazbang', response.body + assert_equal "bazbang", response.body end end diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index 577a3d5800..42a5157010 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/logger' -require 'controller/fake_models' +require "abstract_unit" +require "active_support/logger" +require "controller/fake_models" # Provide some controller to run the tests on. module Submodule @@ -19,11 +19,11 @@ end class DefaultUrlOptionsController < ActionController::Base def from_view - render :inline => "<%= #{params[:route]} %>" + render inline: "<%= #{params[:route]} %>" end def default_url_options - { :host => 'www.override.com', :action => 'new', :locale => 'en' } + { host: "www.override.com", action: "new", locale: "en" } end end @@ -33,17 +33,17 @@ class OptionalDefaultUrlOptionsController < ActionController::Base end def default_url_options - { format: 'atom', id: 'default-id' } + { format: "atom", id: "default-id" } end end class UrlOptionsController < ActionController::Base def from_view - render :inline => "<%= #{params[:route]} %>" + render inline: "<%= #{params[:route]} %>" end def url_options - super.merge(:host => 'www.override.com') + super.merge(host: "www.override.com") end end @@ -58,17 +58,16 @@ class ActionMissingController < ActionController::Base end class ControllerClassTests < ActiveSupport::TestCase - def test_controller_path - assert_equal 'empty', EmptyController.controller_path + assert_equal "empty", EmptyController.controller_path assert_equal EmptyController.controller_path, EmptyController.new.controller_path - assert_equal 'submodule/contained_empty', Submodule::ContainedEmptyController.controller_path + assert_equal "submodule/contained_empty", Submodule::ContainedEmptyController.controller_path assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path end def test_controller_name - assert_equal 'empty', EmptyController.controller_name - assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name + assert_equal "empty", EmptyController.controller_name + assert_equal "contained_empty", Submodule::ContainedEmptyController.controller_name end def test_no_deprecation_when_action_view_record_identifier_is_included @@ -80,13 +79,13 @@ class ControllerClassTests < ActiveSupport::TestCase dom_id = RecordIdentifierIncludedController.new.dom_id(record) end - assert_equal 'comment_1', dom_id + assert_equal "comment_1", dom_id dom_class = nil assert_not_deprecated do dom_class = RecordIdentifierIncludedController.new.dom_class(record) end - assert_equal 'comment', dom_class + assert_equal "comment", dom_class end end @@ -112,7 +111,7 @@ class ControllerInstanceTests < ActiveSupport::TestCase end def test_temporary_anonymous_controllers - name = 'ExamplesController' + name = "ExamplesController" klass = Class.new(ActionController::Base) Object.const_set(name, klass) @@ -152,40 +151,40 @@ class UrlOptionsTest < ActionController::TestCase def setup super - @request.host = 'www.example.com' + @request.host = "www.example.com" end def test_url_for_query_params_included rs = ActionDispatch::Routing::RouteSet.new rs.draw do - get 'home' => 'pages#home' + get "home" => "pages#home" end options = { - :action => "home", - :controller => "pages", - :only_path => true, - :params => { "token" => "secret" } + action: "home", + controller: "pages", + only_path: true, + params: { "token" => "secret" } } - assert_equal '/home?token=secret', rs.url_for(options) + assert_equal "/home?token=secret", rs.url_for(options) end def test_url_options_override with_routing do |set| set.draw do - get 'from_view', :to => 'url_options#from_view', :as => :from_view + get "from_view", to: "url_options#from_view", as: :from_view ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end get :from_view, params: { route: "from_view_url" } - assert_equal 'http://www.override.com/from_view', @response.body - assert_equal 'http://www.override.com/from_view', @controller.send(:from_view_url) - assert_equal 'http://www.override.com/default_url_options/index', @controller.url_for(:controller => 'default_url_options') + assert_equal "http://www.override.com/from_view", @response.body + assert_equal "http://www.override.com/from_view", @controller.send(:from_view_url) + assert_equal "http://www.override.com/default_url_options/index", @controller.url_for(controller: "default_url_options") end end @@ -195,7 +194,7 @@ class UrlOptionsTest < ActionController::TestCase get "account/overview" end - assert !@controller.class.action_methods.include?("account_overview_path") + assert_not_includes @controller.class.action_methods, "account_overview_path" end end end @@ -205,24 +204,24 @@ class DefaultUrlOptionsTest < ActionController::TestCase def setup super - @request.host = 'www.example.com' + @request.host = "www.example.com" end def test_default_url_options_override with_routing do |set| set.draw do - get 'from_view', :to => 'default_url_options#from_view', :as => :from_view + get "from_view", to: "default_url_options#from_view", as: :from_view ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end get :from_view, params: { route: "from_view_url" } - assert_equal 'http://www.override.com/from_view?locale=en', @response.body - assert_equal 'http://www.override.com/from_view?locale=en', @controller.send(:from_view_url) - assert_equal 'http://www.override.com/default_url_options/new?locale=en', @controller.url_for(:controller => 'default_url_options') + assert_equal "http://www.override.com/from_view?locale=en", @response.body + assert_equal "http://www.override.com/from_view?locale=en", @controller.send(:from_view_url) + assert_equal "http://www.override.com/default_url_options/new?locale=en", @controller.url_for(controller: "default_url_options") end end @@ -234,23 +233,23 @@ class DefaultUrlOptionsTest < ActionController::TestCase end ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end get :from_view, params: { route: "description_path(1)" } - assert_equal '/en/descriptions/1', @response.body - assert_equal '/en/descriptions', @controller.send(:descriptions_path) - assert_equal '/pl/descriptions', @controller.send(:descriptions_path, "pl") - assert_equal '/pl/descriptions', @controller.send(:descriptions_path, :locale => "pl") - assert_equal '/pl/descriptions.xml', @controller.send(:descriptions_path, "pl", "xml") - assert_equal '/en/descriptions.xml', @controller.send(:descriptions_path, :format => "xml") - assert_equal '/en/descriptions/1', @controller.send(:description_path, 1) - assert_equal '/pl/descriptions/1', @controller.send(:description_path, "pl", 1) - assert_equal '/pl/descriptions/1', @controller.send(:description_path, 1, :locale => "pl") - assert_equal '/pl/descriptions/1.xml', @controller.send(:description_path, "pl", 1, "xml") - assert_equal '/en/descriptions/1.xml', @controller.send(:description_path, 1, :format => "xml") + assert_equal "/en/descriptions/1", @response.body + assert_equal "/en/descriptions", @controller.send(:descriptions_path) + assert_equal "/pl/descriptions", @controller.send(:descriptions_path, "pl") + assert_equal "/pl/descriptions", @controller.send(:descriptions_path, locale: "pl") + assert_equal "/pl/descriptions.xml", @controller.send(:descriptions_path, "pl", "xml") + assert_equal "/en/descriptions.xml", @controller.send(:descriptions_path, format: "xml") + assert_equal "/en/descriptions/1", @controller.send(:description_path, 1) + assert_equal "/pl/descriptions/1", @controller.send(:description_path, "pl", 1) + assert_equal "/pl/descriptions/1", @controller.send(:description_path, 1, locale: "pl") + assert_equal "/pl/descriptions/1.xml", @controller.send(:description_path, "pl", 1, "xml") + assert_equal "/en/descriptions/1.xml", @controller.send(:description_path, 1, format: "xml") end end end @@ -259,10 +258,10 @@ class OptionalDefaultUrlOptionsControllerTest < ActionController::TestCase def test_default_url_options_override_missing_positional_arguments with_routing do |set| set.draw do - get "/things/:id(.:format)" => 'things#show', :as => :thing + get "/things/:id(.:format)" => "things#show", :as => :thing end - assert_equal '/things/1.atom', thing_path('1') - assert_equal '/things/default-id.atom', thing_path + assert_equal "/things/1.atom", thing_path("1") + assert_equal "/things/default-id.atom", thing_path end end end @@ -272,7 +271,7 @@ class EmptyUrlOptionsTest < ActionController::TestCase def setup super - @request.host = 'www.example.com' + @request.host = "www.example.com" end def test_ensure_url_for_works_as_expected_when_called_with_no_options_if_default_url_options_is_not_set @@ -289,7 +288,7 @@ class EmptyUrlOptionsTest < ActionController::TestCase resources :things end - assert_equal '/things', @controller.send(:things_path) + assert_equal "/things", @controller.send(:things_path) end end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 7faf3cd8c6..18490c7d73 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -1,10 +1,10 @@ -require 'fileutils' -require 'abstract_unit' -require 'lib/controller/fake_models' +require "fileutils" +require "abstract_unit" +require "lib/controller/fake_models" -CACHE_DIR = 'test_cache' +CACHE_DIR = "test_cache" # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed -FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR) +FILE_STORE_PATH = File.join(File.dirname(__FILE__), "/../temp/", CACHE_DIR) class FragmentCachingMetalTestController < ActionController::Metal abstract! @@ -21,14 +21,14 @@ class FragmentCachingMetalTest < ActionController::TestCase @controller = FragmentCachingMetalTestController.new @controller.perform_caching = true @controller.cache_store = @store - @params = { controller: 'posts', action: 'index' } + @params = { controller: "posts", action: "index" } @controller.params = @params @controller.request = @request @controller.response = @response end def test_fragment_cache_key - assert_equal 'views/what a key', @controller.fragment_cache_key('what a key') + assert_equal "views/what a key", @controller.fragment_cache_key("what a key") end end @@ -49,96 +49,96 @@ class FragmentCachingTest < ActionController::TestCase @controller = FragmentCachingTestController.new @controller.perform_caching = true @controller.cache_store = @store - @params = {:controller => 'posts', :action => 'index'} + @params = { controller: "posts", action: "index" } @controller.params = @params @controller.request = @request @controller.response = @response end def test_fragment_cache_key - assert_equal 'views/what a key', @controller.fragment_cache_key('what a key') + assert_equal "views/what a key", @controller.fragment_cache_key("what a key") assert_equal "views/test.host/fragment_caching_test/some_action", - @controller.fragment_cache_key(:controller => 'fragment_caching_test',:action => 'some_action') + @controller.fragment_cache_key(controller: "fragment_caching_test",action: "some_action") end def test_read_fragment_with_caching_enabled - @store.write('views/name', 'value') - assert_equal 'value', @controller.read_fragment('name') + @store.write("views/name", "value") + assert_equal "value", @controller.read_fragment("name") end def test_read_fragment_with_caching_disabled @controller.perform_caching = false - @store.write('views/name', 'value') - assert_nil @controller.read_fragment('name') + @store.write("views/name", "value") + assert_nil @controller.read_fragment("name") end def test_fragment_exist_with_caching_enabled - @store.write('views/name', 'value') - assert @controller.fragment_exist?('name') - assert !@controller.fragment_exist?('other_name') + @store.write("views/name", "value") + assert @controller.fragment_exist?("name") + assert !@controller.fragment_exist?("other_name") end def test_fragment_exist_with_caching_disabled @controller.perform_caching = false - @store.write('views/name', 'value') - assert !@controller.fragment_exist?('name') - assert !@controller.fragment_exist?('other_name') + @store.write("views/name", "value") + assert !@controller.fragment_exist?("name") + assert !@controller.fragment_exist?("other_name") end def test_write_fragment_with_caching_enabled - assert_nil @store.read('views/name') - assert_equal 'value', @controller.write_fragment('name', 'value') - assert_equal 'value', @store.read('views/name') + assert_nil @store.read("views/name") + assert_equal "value", @controller.write_fragment("name", "value") + assert_equal "value", @store.read("views/name") end def test_write_fragment_with_caching_disabled - assert_nil @store.read('views/name') + assert_nil @store.read("views/name") @controller.perform_caching = false - assert_equal 'value', @controller.write_fragment('name', 'value') - assert_nil @store.read('views/name') + assert_equal "value", @controller.write_fragment("name", "value") + assert_nil @store.read("views/name") end def test_expire_fragment_with_simple_key - @store.write('views/name', 'value') - @controller.expire_fragment 'name' - assert_nil @store.read('views/name') + @store.write("views/name", "value") + @controller.expire_fragment "name" + assert_nil @store.read("views/name") end def test_expire_fragment_with_regexp - @store.write('views/name', 'value') - @store.write('views/another_name', 'another_value') - @store.write('views/primalgrasp', 'will not expire ;-)') + @store.write("views/name", "value") + @store.write("views/another_name", "another_value") + @store.write("views/primalgrasp", "will not expire ;-)") @controller.expire_fragment(/name/) - assert_nil @store.read('views/name') - assert_nil @store.read('views/another_name') - assert_equal 'will not expire ;-)', @store.read('views/primalgrasp') + assert_nil @store.read("views/name") + assert_nil @store.read("views/another_name") + assert_equal "will not expire ;-)", @store.read("views/primalgrasp") end def test_fragment_for - @store.write('views/expensive', 'fragment content') + @store.write("views/expensive", "fragment content") fragment_computed = false view_context = @controller.view_context - buffer = 'generated till now -> '.html_safe - buffer << view_context.send(:fragment_for, 'expensive') { fragment_computed = true } + buffer = "generated till now -> ".html_safe + buffer << view_context.send(:fragment_for, "expensive") { fragment_computed = true } assert !fragment_computed - assert_equal 'generated till now -> fragment content', buffer + assert_equal "generated till now -> fragment content", buffer end def test_html_safety - assert_nil @store.read('views/name') - content = 'value'.html_safe - assert_equal content, @controller.write_fragment('name', content) + assert_nil @store.read("views/name") + content = "value".html_safe + assert_equal content, @controller.write_fragment("name", content) - cached = @store.read('views/name') + cached = @store.read("views/name") assert_equal content, cached assert_equal String, cached.class - html_safe = @controller.read_fragment('name') + html_safe = @controller.read_fragment("name") assert_equal content, html_safe assert html_safe.html_safe? end @@ -184,6 +184,7 @@ class FunctionalFragmentCachingTest < ActionController::TestCase @controller = FunctionalCachingController.new @controller.perform_caching = true @controller.cache_store = @store + @controller.enable_fragment_cache_logging = true end def test_fragment_caching @@ -277,7 +278,6 @@ CACHED @store.read("views/test.host/functional_caching/formatted_fragment_cached/#{template_digest("functional_caching/formatted_fragment_cached")}") end - def test_fragment_caching_with_variant get :formatted_fragment_cached_with_variant, format: "html", params: { v: :phone } assert_response :success @@ -296,7 +296,6 @@ CACHED end class CacheHelperOutputBufferTest < ActionController::TestCase - class MockController def read_fragment(name, options) return false @@ -325,7 +324,7 @@ class CacheHelperOutputBufferTest < ActionController::TestCase cache_helper.stub :output_buffer, output_buffer do assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do assert_nothing_raised do - cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + cache_helper.send :fragment_for, "Test fragment name", "Test fragment", &Proc.new { nil } end end end @@ -346,7 +345,7 @@ class CacheHelperOutputBufferTest < ActionController::TestCase cache_helper.stub :output_buffer, output_buffer do assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do assert_nothing_raised do - cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + cache_helper.send :fragment_for, "Test fragment name", "Test fragment", &Proc.new { nil } end end end @@ -376,26 +375,31 @@ class CollectionCacheController < ActionController::Base attr_accessor :partial_rendered_times def index - @customers = [Customer.new('david', params[:id] || 1)] + @customers = [Customer.new("david", params[:id] || 1)] end def index_ordered - @customers = [Customer.new('david', 1), Customer.new('david', 2), Customer.new('david', 3)] - render 'index' + @customers = [Customer.new("david", 1), Customer.new("david", 2), Customer.new("david", 3)] + render "index" end def index_explicit_render_in_controller - @customers = [Customer.new('david', 1)] - render partial: 'customers/customer', collection: @customers, cached: true + @customers = [Customer.new("david", 1)] + render partial: "customers/customer", collection: @customers, cached: true end def index_with_comment - @customers = [Customer.new('david', 1)] - render partial: 'customers/commented_customer', collection: @customers, as: :customer, cached: true + @customers = [Customer.new("david", 1)] + render partial: "customers/commented_customer", collection: @customers, as: :customer, cached: true + end + + def index_with_callable_cache_key + @customers = [Customer.new("david", 1)] + render partial: "customers/customer", collection: @customers, cached: -> customer { "cached_david" } end end -class AutomaticCollectionCacheTest < ActionController::TestCase +class CollectionCacheTest < ActionController::TestCase def setup super @controller = CollectionCacheController.new @@ -408,7 +412,7 @@ class AutomaticCollectionCacheTest < ActionController::TestCase def test_collection_fetches_cached_views get :index assert_equal 1, @controller.partial_rendered_times - assert_customer_cached 'david/1', 'david, 1' + assert_customer_cached "david/1", "david, 1" get :index assert_equal 1, @controller.partial_rendered_times @@ -417,17 +421,17 @@ class AutomaticCollectionCacheTest < ActionController::TestCase def test_preserves_order_when_reading_from_cache_plus_rendering get :index, params: { id: 2 } assert_equal 1, @controller.partial_rendered_times - assert_select ':root', 'david, 2' + assert_select ":root", "david, 2" get :index_ordered assert_equal 3, @controller.partial_rendered_times - assert_select ':root', "david, 1\n david, 2\n david, 3" + assert_select ":root", "david, 1\n david, 2\n david, 3" end def test_explicit_render_call_with_options get :index_explicit_render_in_controller - assert_select ':root', "david, 1" + assert_select ":root", "david, 1" end def test_caching_works_with_beginning_comment @@ -438,6 +442,11 @@ class AutomaticCollectionCacheTest < ActionController::TestCase assert_equal 1, @controller.partial_rendered_times end + def test_caching_with_callable_cache_key + get :index_with_callable_cache_key + assert_customer_cached "cached_david", "david, 1" + end + private def assert_customer_cached(key, content) assert_match content, @@ -463,9 +472,9 @@ class FragmentCacheKeyTest < ActionController::TestCase def test_fragment_cache_key @controller.account_id = "123" - assert_equal 'views/v1/123/what a key', @controller.fragment_cache_key('what a key') + assert_equal "views/v1/123/what a key", @controller.fragment_cache_key("what a key") @controller.account_id = nil - assert_equal 'views/v1//what a key', @controller.fragment_cache_key('what a key') + assert_equal "views/v1//what a key", @controller.fragment_cache_key("what a key") end end diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb index c02607b55e..fcb2632b80 100644 --- a/actionpack/test/controller/content_type_test.rb +++ b/actionpack/test/controller/content_type_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class OldContentTypeController < ActionController::Base # :ported: @@ -14,7 +14,7 @@ class OldContentTypeController < ActionController::Base # :ported: def render_content_type_from_render - render body: "hello world!", :content_type => Mime[:rss] + render body: "hello world!", content_type: Mime[:rss] end # :ported: @@ -37,7 +37,7 @@ class OldContentTypeController < ActionController::Base def render_change_for_builder response.content_type = Mime[:html] - render :action => "render_default_for_builder" + render action: "render_default_for_builder" end def render_default_content_types_for_respond_to @@ -131,13 +131,13 @@ class ContentTypeTest < ActionController::TestCase private - def with_default_charset(charset) - old_default_charset = ActionDispatch::Response.default_charset - ActionDispatch::Response.default_charset = charset - yield - ensure - ActionDispatch::Response.default_charset = old_default_charset - end + def with_default_charset(charset) + old_default_charset = ActionDispatch::Response.default_charset + ActionDispatch::Response.default_charset = charset + yield + ensure + ActionDispatch::Response.default_charset = old_default_charset + end end class AcceptBasedContentTypeTest < ActionController::TestCase diff --git a/actionpack/test/controller/default_url_options_with_before_action_test.rb b/actionpack/test/controller/default_url_options_with_before_action_test.rb index 12fbe0424e..e3fe7a6495 100644 --- a/actionpack/test/controller/default_url_options_with_before_action_test.rb +++ b/actionpack/test/controller/default_url_options_with_before_action_test.rb @@ -1,7 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" class ControllerWithBeforeActionAndDefaultUrlOptions < ActionController::Base - before_action { I18n.locale = params[:locale] } after_action { I18n.locale = "en" } @@ -10,16 +9,15 @@ class ControllerWithBeforeActionAndDefaultUrlOptions < ActionController::Base end def redirect - redirect_to :action => "target" + redirect_to action: "target" end def default_url_options - {:locale => "de"} + { locale: "de" } end end class ControllerWithBeforeActionAndDefaultUrlOptionsTest < ActionController::TestCase - # This test has its roots in issue #1872 test "should redirect with correct locale :de" do get :redirect, params: { locale: "de" } diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 08271012e9..a34878cee8 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' +require "abstract_unit" class ActionController::Base class << self - %w(append_around_action prepend_after_action prepend_around_action prepend_before_action skip_after_action skip_before_action skip_action_callback).each do |pending| + %w(append_around_action prepend_after_action prepend_around_action prepend_before_action skip_after_action skip_before_action).each do |pending| define_method(pending) do |*args| $stderr.puts "#{pending} unimplemented: #{args.inspect}" end unless method_defined?(pending) @@ -21,7 +21,7 @@ class FilterTest < ActionController::TestCase after_action :clean_up def show - render :inline => "ran action" + render inline: "ran action" end private @@ -37,7 +37,7 @@ class FilterTest < ActionController::TestCase end class ChangingTheRequirementsController < TestController - before_action :ensure_login, :except => [:go_wild] + before_action :ensure_login, except: [:go_wild] def go_wild render plain: "gobble" @@ -56,14 +56,14 @@ class FilterTest < ActionController::TestCase end protected - (1..3).each do |i| - define_method "try_#{i}" do - instance_variable_set :@try, i - if action_name == "fail_#{i}" - head(404) + (1..3).each do |i| + define_method "try_#{i}" do + instance_variable_set :@try, i + if action_name == "fail_#{i}" + head(404) + end end end - end end class RenderingController < ActionController::Base @@ -72,14 +72,14 @@ class FilterTest < ActionController::TestCase def show @ran_action = true - render :inline => "ran action" + render inline: "ran action" end private def before_action_rendering @ran_filter ||= [] @ran_filter << "before_action_rendering" - render :inline => "something else" + render inline: "something else" end def unreached_after_action @@ -102,19 +102,19 @@ class FilterTest < ActionController::TestCase def show @ran_action = true - render :inline => "ran show action" + render inline: "ran show action" end def target_of_redirection @ran_target_of_redirection = true - render :inline => "ran target_of_redirection action" + render inline: "ran target_of_redirection action" end private def before_action_redirects @ran_filter ||= [] @ran_filter << "before_action_redirects" - redirect_to(:action => 'target_of_redirection') + redirect_to(action: "target_of_redirection") end def unreached_after_action @@ -133,15 +133,15 @@ class FilterTest < ActionController::TestCase class ConditionalFilterController < ActionController::Base def show - render :inline => "ran action" + render inline: "ran action" end def another_action - render :inline => "ran action" + render inline: "ran action" end def show_without_action - render :inline => "ran action without action" + render inline: "ran action without action" end private @@ -157,28 +157,28 @@ class FilterTest < ActionController::TestCase end class ConditionalCollectionFilterController < ConditionalFilterController - before_action :ensure_login, :except => [ :show_without_action, :another_action ] + before_action :ensure_login, except: [ :show_without_action, :another_action ] end class OnlyConditionSymController < ConditionalFilterController - before_action :ensure_login, :only => :show + before_action :ensure_login, only: :show end class ExceptConditionSymController < ConditionalFilterController - before_action :ensure_login, :except => :show_without_action + before_action :ensure_login, except: :show_without_action end class BeforeAndAfterConditionController < ConditionalFilterController - before_action :ensure_login, :only => :show - after_action :clean_up_tmp, :only => :show + before_action :ensure_login, only: :show + after_action :clean_up_tmp, only: :show end class OnlyConditionProcController < ConditionalFilterController - before_action(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_action", true) } + before_action(only: :show) { |c| c.instance_variable_set(:"@ran_proc_action", true) } end class ExceptConditionProcController < ConditionalFilterController - before_action(:except => :show_without_action) {|c| c.instance_variable_set(:"@ran_proc_action", true) } + before_action(except: :show_without_action) { |c| c.instance_variable_set(:"@ran_proc_action", true) } end class ConditionalClassFilter @@ -186,24 +186,24 @@ class FilterTest < ActionController::TestCase end class OnlyConditionClassController < ConditionalFilterController - before_action ConditionalClassFilter, :only => :show + before_action ConditionalClassFilter, only: :show end class ExceptConditionClassController < ConditionalFilterController - before_action ConditionalClassFilter, :except => :show_without_action + before_action ConditionalClassFilter, except: :show_without_action end class AnomolousYetValidConditionController < ConditionalFilterController - before_action(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.instance_variable_set(:"@ran_proc_action1", true)}, :except => :show_without_action) { |c| c.instance_variable_set(:"@ran_proc_action2", true)} + before_action(ConditionalClassFilter, :ensure_login, Proc.new { |c| c.instance_variable_set(:"@ran_proc_action1", true) }, except: :show_without_action) { |c| c.instance_variable_set(:"@ran_proc_action2", true) } end class OnlyConditionalOptionsFilter < ConditionalFilterController - before_action :ensure_login, :only => :index, :if => Proc.new {|c| c.instance_variable_set(:"@ran_conditional_index_proc", true) } + before_action :ensure_login, only: :index, if: Proc.new { |c| c.instance_variable_set(:"@ran_conditional_index_proc", true) } end class ConditionalOptionsFilter < ConditionalFilterController - before_action :ensure_login, :if => Proc.new { |c| true } - before_action :clean_up_tmp, :if => Proc.new { |c| false } + before_action :ensure_login, if: Proc.new { |c| true } + before_action :clean_up_tmp, if: Proc.new { |c| false } end class ConditionalOptionsSkipFilter < ConditionalFilterController @@ -222,7 +222,7 @@ class FilterTest < ActionController::TestCase skip_before_action :clean_up_tmp, only: :login, if: -> { true } def login - render plain: 'ok' + render plain: "ok" end end @@ -234,7 +234,7 @@ class FilterTest < ActionController::TestCase skip_before_action :clean_up_tmp, if: -> { true }, except: :login def login - render plain: 'ok' + render plain: "ok" end end @@ -255,14 +255,14 @@ class FilterTest < ActionController::TestCase class SkippingAndLimitedController < TestController skip_before_action :ensure_login - before_action :ensure_login, :only => :index + before_action :ensure_login, only: :index def index - render plain: 'ok' + render plain: "ok" end def public - render plain: 'ok' + render plain: "ok" end end @@ -272,7 +272,7 @@ class FilterTest < ActionController::TestCase before_action :ensure_login def index - render plain: 'ok' + render plain: "ok" end private @@ -283,17 +283,17 @@ class FilterTest < ActionController::TestCase end class ConditionalSkippingController < TestController - skip_before_action :ensure_login, :only => [ :login ] - skip_after_action :clean_up, :only => [ :login ] + skip_before_action :ensure_login, only: [ :login ] + skip_after_action :clean_up, only: [ :login ] - before_action :find_user, :only => [ :change_password ] + before_action :find_user, only: [ :change_password ] def login - render :inline => "ran action" + render inline: "ran action" end def change_password - render :inline => "ran action" + render inline: "ran action" end protected @@ -304,29 +304,29 @@ class FilterTest < ActionController::TestCase end class ConditionalParentOfConditionalSkippingController < ConditionalFilterController - before_action :conditional_in_parent_before, :only => [:show, :another_action] - after_action :conditional_in_parent_after, :only => [:show, :another_action] + before_action :conditional_in_parent_before, only: [:show, :another_action] + after_action :conditional_in_parent_after, only: [:show, :another_action] private def conditional_in_parent_before @ran_filter ||= [] - @ran_filter << 'conditional_in_parent_before' + @ran_filter << "conditional_in_parent_before" end def conditional_in_parent_after @ran_filter ||= [] - @ran_filter << 'conditional_in_parent_after' + @ran_filter << "conditional_in_parent_after" end end class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController - skip_before_action :conditional_in_parent_before, :only => :another_action - skip_after_action :conditional_in_parent_after, :only => :another_action + skip_before_action :conditional_in_parent_before, only: :another_action + skip_after_action :conditional_in_parent_after, only: :another_action end class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController - skip_before_action :conditional_in_parent_before, :only => :show + skip_before_action :conditional_in_parent_before, only: :show end class ProcController < PrependingController @@ -418,14 +418,14 @@ class FilterTest < ActionController::TestCase class OutOfOrder < StandardError; end before_action :first - before_action :second, :only => :foo + before_action :second, only: :foo def foo - render plain: 'foo' + render plain: "foo" end def bar - render plain: 'bar' + render plain: "bar" end protected @@ -458,20 +458,20 @@ class FilterTest < ActionController::TestCase def before_all @ran_filter ||= [] - @ran_filter << 'before_all' + @ran_filter << "before_all" end def after_all @ran_filter ||= [] - @ran_filter << 'after_all' + @ran_filter << "after_all" end def between_before_all_and_after_all @ran_filter ||= [] - @ran_filter << 'between_before_all_and_after_all' + @ran_filter << "between_before_all_and_after_all" end def show - render plain: 'hello' + render plain: "hello" end end @@ -494,14 +494,13 @@ class FilterTest < ActionController::TestCase end class NonYieldingAroundFilterController < ActionController::Base - before_action :filter_one around_action :non_yielding_action before_action :action_two after_action :action_three def index - render :inline => "index" + render inline: "index" end private @@ -522,22 +521,21 @@ class FilterTest < ActionController::TestCase def action_three @filters << "action_three" end - end class ImplicitActionsController < ActionController::Base - before_action :find_only, :only => :edit - before_action :find_except, :except => :edit + before_action :find_only, only: :edit + before_action :find_except, except: :edit private - def find_only - @only = 'Only' - end + def find_only + @only = "Only" + end - def find_except - @except = 'Except' - end + def find_except + @except = "Except" + end end def test_non_yielding_around_actions_do_not_raise @@ -611,12 +609,12 @@ class FilterTest < ActionController::TestCase end def test_if_is_ignored_when_used_with_only - test_process(SkipFilterUsingOnlyAndIf, 'login') + test_process(SkipFilterUsingOnlyAndIf, "login") assert_not @controller.instance_variable_defined?(:@ran_filter) end def test_except_is_ignored_when_used_with_if - test_process(SkipFilterUsingIfAndExcept, 'login') + test_process(SkipFilterUsingIfAndExcept, "login") assert_equal %w(ensure_login), @controller.instance_variable_get(:@ran_filter) end @@ -745,13 +743,13 @@ class FilterTest < ActionController::TestCase def test_actions_with_mixed_specialization_run_in_order assert_nothing_raised do - response = test_process(MixedSpecializationController, 'bar') - assert_equal 'bar', response.body + response = test_process(MixedSpecializationController, "bar") + assert_equal "bar", response.body end assert_nothing_raised do - response = test_process(MixedSpecializationController, 'foo') - assert_equal 'foo', response.body + response = test_process(MixedSpecializationController, "foo") + assert_equal "foo", response.body end end @@ -795,7 +793,7 @@ class FilterTest < ActionController::TestCase def test_conditional_skipping_of_actions_when_parent_action_is_also_conditional test_process(ChildOfConditionalParentController) assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), @controller.instance_variable_get(:@ran_filter) - test_process(ChildOfConditionalParentController, 'another_action') + test_process(ChildOfConditionalParentController, "another_action") assert_not @controller.instance_variable_defined?(:@ran_filter) end @@ -824,15 +822,15 @@ class FilterTest < ActionController::TestCase end def test_actions_obey_only_and_except_for_implicit_actions - test_process(ImplicitActionsController, 'show') - assert_equal 'Except', @controller.instance_variable_get(:@except) + test_process(ImplicitActionsController, "show") + assert_equal "Except", @controller.instance_variable_get(:@except) assert_not @controller.instance_variable_defined?(:@only) - assert_equal 'show', response.body + assert_equal "show", response.body - test_process(ImplicitActionsController, 'edit') - assert_equal 'Only', @controller.instance_variable_get(:@only) + test_process(ImplicitActionsController, "edit") + assert_equal "Only", @controller.instance_variable_get(:@only) assert_not @controller.instance_variable_defined?(:@except) - assert_equal 'edit', response.body + assert_equal "edit", response.body end private @@ -859,14 +857,14 @@ class PostsController < ActionController::Base private def default_action - render :inline => "#{action_name} called" + render inline: "#{action_name} called" end end class ControllerWithSymbolAsFilter < PostsController - around_action :raise_before, :only => :raises_before - around_action :raise_after, :only => :raises_after - around_action :without_exception, :only => :no_raise + around_action :raise_before, only: :raises_before + around_action :raise_after, only: :raises_after + around_action :without_exception, only: :no_raise private def raise_before @@ -898,7 +896,7 @@ class ControllerWithFilterClass < PostsController end end - around_action YieldingFilter, :only => :raises_after + around_action YieldingFilter, only: :raises_after end class ControllerWithFilterInstance < PostsController @@ -909,11 +907,11 @@ class ControllerWithFilterInstance < PostsController end end - around_action YieldingFilter.new, :only => :raises_after + around_action YieldingFilter.new, only: :raises_after end class ControllerWithProcFilter < PostsController - around_action(:only => :no_raise) do |c,b| + around_action(only: :no_raise) do |c,b| c.instance_variable_set(:"@before", true) b.call c.instance_variable_set(:"@after", true) @@ -921,7 +919,7 @@ class ControllerWithProcFilter < PostsController end class ControllerWithNestedFilters < ControllerWithSymbolAsFilter - around_action :raise_before, :raise_after, :without_exception, :only => :raises_both + around_action :raise_before, :raise_after, :without_exception, only: :raises_both end class ControllerWithAllTypesOfFilters < PostsController @@ -931,26 +929,26 @@ class ControllerWithAllTypesOfFilters < PostsController around_action :around_again private - def before - @ran_filter ||= [] - @ran_filter << 'before' - end + def before + @ran_filter ||= [] + @ran_filter << "before" + end - def around - @ran_filter << 'around (before yield)' - yield - @ran_filter << 'around (after yield)' - end + def around + @ran_filter << "around (before yield)" + yield + @ran_filter << "around (after yield)" + end - def after - @ran_filter << 'after' - end + def after + @ran_filter << "after" + end - def around_again - @ran_filter << 'around_again (before yield)' - yield - @ran_filter << 'around_again (after yield)' - end + def around_again + @ran_filter << "around_again (before yield)" + yield + @ran_filter << "around_again (after yield)" + end end class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters @@ -958,46 +956,39 @@ class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters skip_after_action :after end -class SkipFilterUsingSkipActionCallback < ControllerWithAllTypesOfFilters - ActiveSupport::Deprecation.silence do - skip_action_callback :around_again - skip_action_callback :after - end -end - class YieldingAroundFiltersTest < ActionController::TestCase include PostsController::AroundExceptions def test_base controller = PostsController - assert_nothing_raised { test_process(controller,'no_raise') } - assert_nothing_raised { test_process(controller,'raises_before') } - assert_nothing_raised { test_process(controller,'raises_after') } - assert_nothing_raised { test_process(controller,'no_action') } + assert_nothing_raised { test_process(controller,"no_raise") } + assert_nothing_raised { test_process(controller,"raises_before") } + assert_nothing_raised { test_process(controller,"raises_after") } + assert_nothing_raised { test_process(controller,"no_action") } end def test_with_symbol controller = ControllerWithSymbolAsFilter - assert_nothing_raised { test_process(controller,'no_raise') } - assert_raise(Before) { test_process(controller,'raises_before') } - assert_raise(After) { test_process(controller,'raises_after') } - assert_nothing_raised { test_process(controller,'no_raise') } + assert_nothing_raised { test_process(controller,"no_raise") } + assert_raise(Before) { test_process(controller,"raises_before") } + assert_raise(After) { test_process(controller,"raises_after") } + assert_nothing_raised { test_process(controller,"no_raise") } end def test_with_class controller = ControllerWithFilterClass - assert_nothing_raised { test_process(controller,'no_raise') } - assert_raise(After) { test_process(controller,'raises_after') } + assert_nothing_raised { test_process(controller,"no_raise") } + assert_raise(After) { test_process(controller,"raises_after") } end def test_with_instance controller = ControllerWithFilterInstance - assert_nothing_raised { test_process(controller,'no_raise') } - assert_raise(After) { test_process(controller,'raises_after') } + assert_nothing_raised { test_process(controller,"no_raise") } + assert_raise(After) { test_process(controller,"raises_after") } end def test_with_proc - test_process(ControllerWithProcFilter,'no_raise') + test_process(ControllerWithProcFilter,"no_raise") assert @controller.instance_variable_get(:@before) assert @controller.instance_variable_get(:@after) end @@ -1006,70 +997,49 @@ class YieldingAroundFiltersTest < ActionController::TestCase controller = ControllerWithNestedFilters assert_nothing_raised do begin - test_process(controller,'raises_both') + test_process(controller,"raises_both") rescue Before, After end end assert_raise Before do begin - test_process(controller,'raises_both') + test_process(controller,"raises_both") rescue After end end end def test_action_order_with_all_action_types - test_process(ControllerWithAllTypesOfFilters,'no_raise') - assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) after around (after yield)', @controller.instance_variable_get(:@ran_filter).join(' ') + test_process(ControllerWithAllTypesOfFilters,"no_raise") + assert_equal "before around (before yield) around_again (before yield) around_again (after yield) after around (after yield)", @controller.instance_variable_get(:@ran_filter).join(" ") end def test_action_order_with_skip_action_method - test_process(ControllerWithTwoLessFilters,'no_raise') - assert_equal 'before around (before yield) around (after yield)', @controller.instance_variable_get(:@ran_filter).join(' ') + test_process(ControllerWithTwoLessFilters,"no_raise") + assert_equal "before around (before yield) around (after yield)", @controller.instance_variable_get(:@ran_filter).join(" ") end def test_first_action_in_multiple_before_action_chain_halts controller = ::FilterTest::TestMultipleFiltersController.new - response = test_process(controller, 'fail_1') - assert_equal '', response.body + response = test_process(controller, "fail_1") + assert_equal "", response.body assert_equal 1, controller.instance_variable_get(:@try) end def test_second_action_in_multiple_before_action_chain_halts controller = ::FilterTest::TestMultipleFiltersController.new - response = test_process(controller, 'fail_2') - assert_equal '', response.body + response = test_process(controller, "fail_2") + assert_equal "", response.body assert_equal 2, controller.instance_variable_get(:@try) end def test_last_action_in_multiple_before_action_chain_halts controller = ::FilterTest::TestMultipleFiltersController.new - response = test_process(controller, 'fail_3') - assert_equal '', response.body + response = test_process(controller, "fail_3") + assert_equal "", response.body assert_equal 3, controller.instance_variable_get(:@try) end - def test_skipping_with_skip_action_callback - test_process(SkipFilterUsingSkipActionCallback,'no_raise') - assert_equal 'before around (before yield) around (after yield)', @controller.instance_variable_get(:@ran_filter).join(' ') - end - - def test_deprecated_skip_action_callback - assert_deprecated do - Class.new(PostsController) do - skip_action_callback :clean_up - end - end - end - - def test_deprecated_skip_filter - assert_deprecated do - Class.new(PostsController) do - skip_filter :clean_up - end - end - end - protected def test_process(controller, action = "show") @controller = controller.is_a?(Class) ? controller.new : controller diff --git a/actionpack/test/controller/flash_hash_test.rb b/actionpack/test/controller/flash_hash_test.rb index f87077dd86..32f0db71f5 100644 --- a/actionpack/test/controller/flash_hash_test.rb +++ b/actionpack/test/controller/flash_hash_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch class FlashHashTest < ActiveSupport::TestCase @@ -7,62 +7,62 @@ module ActionDispatch end def test_set_get - @hash[:foo] = 'zomg' - assert_equal 'zomg', @hash[:foo] + @hash[:foo] = "zomg" + assert_equal "zomg", @hash[:foo] end def test_keys assert_equal [], @hash.keys - @hash['foo'] = 'zomg' - assert_equal ['foo'], @hash.keys + @hash["foo"] = "zomg" + assert_equal ["foo"], @hash.keys - @hash['bar'] = 'zomg' - assert_equal ['foo', 'bar'].sort, @hash.keys.sort + @hash["bar"] = "zomg" + assert_equal ["foo", "bar"].sort, @hash.keys.sort end def test_update - @hash['foo'] = 'bar' - @hash.update('foo' => 'baz', 'hello' => 'world') + @hash["foo"] = "bar" + @hash.update("foo" => "baz", "hello" => "world") - assert_equal 'baz', @hash['foo'] - assert_equal 'world', @hash['hello'] + assert_equal "baz", @hash["foo"] + assert_equal "world", @hash["hello"] end def test_key - @hash['foo'] = 'bar' + @hash["foo"] = "bar" - assert @hash.key?('foo') + assert @hash.key?("foo") assert @hash.key?(:foo) - assert_not @hash.key?('bar') + assert_not @hash.key?("bar") assert_not @hash.key?(:bar) end def test_delete - @hash['foo'] = 'bar' - @hash.delete 'foo' + @hash["foo"] = "bar" + @hash.delete "foo" - assert !@hash.key?('foo') - assert_nil @hash['foo'] + assert !@hash.key?("foo") + assert_nil @hash["foo"] end def test_to_hash - @hash['foo'] = 'bar' - assert_equal({'foo' => 'bar'}, @hash.to_hash) + @hash["foo"] = "bar" + assert_equal({ "foo" => "bar" }, @hash.to_hash) - @hash.to_hash['zomg'] = 'aaron' - assert !@hash.key?('zomg') - assert_equal({'foo' => 'bar'}, @hash.to_hash) + @hash.to_hash["zomg"] = "aaron" + assert !@hash.key?("zomg") + assert_equal({ "foo" => "bar" }, @hash.to_hash) end def test_to_session_value - @hash['foo'] = 'bar' - assert_equal({ 'discard' => [], 'flashes' => { 'foo' => 'bar' } }, @hash.to_session_value) + @hash["foo"] = "bar" + assert_equal({ "discard" => [], "flashes" => { "foo" => "bar" } }, @hash.to_session_value) - @hash.now['qux'] = 1 - assert_equal({ 'flashes' => { 'foo' => 'bar' }, 'discard' => [] }, @hash.to_session_value) + @hash.now["qux"] = 1 + assert_equal({ "flashes" => { "foo" => "bar" }, "discard" => [] }, @hash.to_session_value) - @hash.discard('foo') + @hash.discard("foo") assert_equal(nil, @hash.to_session_value) @hash.sweep @@ -71,19 +71,19 @@ module ActionDispatch def test_from_session_value # {"session_id"=>"f8e1b8152ba7609c28bbb17ec9263ba7", "flash"=>#<ActionDispatch::Flash::FlashHash:0x00000000000000 @used=#<Set: {"farewell"}>, @closed=false, @flashes={"greeting"=>"Hello", "farewell"=>"Goodbye"}, @now=nil>} - rails_3_2_cookie = 'BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJWY4ZTFiODE1MmJhNzYwOWMyOGJiYjE3ZWM5MjYzYmE3BjsAVEkiCmZsYXNoBjsARm86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToKQHVzZWRvOghTZXQGOgpAaGFzaHsGSSINZmFyZXdlbGwGOwBUVDoMQGNsb3NlZEY6DUBmbGFzaGVzewdJIg1ncmVldGluZwY7AFRJIgpIZWxsbwY7AFRJIg1mYXJld2VsbAY7AFRJIgxHb29kYnllBjsAVDoJQG5vdzA=' + rails_3_2_cookie = "BAh7B0kiD3Nlc3Npb25faWQGOgZFRkkiJWY4ZTFiODE1MmJhNzYwOWMyOGJiYjE3ZWM5MjYzYmE3BjsAVEkiCmZsYXNoBjsARm86JUFjdGlvbkRpc3BhdGNoOjpGbGFzaDo6Rmxhc2hIYXNoCToKQHVzZWRvOghTZXQGOgpAaGFzaHsGSSINZmFyZXdlbGwGOwBUVDoMQGNsb3NlZEY6DUBmbGFzaGVzewdJIg1ncmVldGluZwY7AFRJIgpIZWxsbwY7AFRJIg1mYXJld2VsbAY7AFRJIgxHb29kYnllBjsAVDoJQG5vdzA=" session = Marshal.load(Base64.decode64(rails_3_2_cookie)) - hash = Flash::FlashHash.from_session_value(session['flash']) - assert_equal({'greeting' => 'Hello'}, hash.to_hash) + hash = Flash::FlashHash.from_session_value(session["flash"]) + assert_equal({ "greeting" => "Hello" }, hash.to_hash) assert_equal(nil, hash.to_session_value) end def test_from_session_value_on_json_serializer decrypted_data = "{ \"session_id\":\"d98bdf6d129618fc2548c354c161cfb5\", \"flash\":{\"discard\":[\"farewell\"], \"flashes\":{\"greeting\":\"Hello\",\"farewell\":\"Goodbye\"}} }" session = ActionDispatch::Cookies::JsonSerializer.load(decrypted_data) - hash = Flash::FlashHash.from_session_value(session['flash']) + hash = Flash::FlashHash.from_session_value(session["flash"]) - assert_equal({'greeting' => 'Hello'}, hash.to_hash) + assert_equal({ "greeting" => "Hello" }, hash.to_hash) assert_equal(nil, hash.to_session_value) assert_equal "Hello", hash[:greeting] assert_equal "Hello", hash["greeting"] @@ -91,15 +91,15 @@ module ActionDispatch def test_empty? assert @hash.empty? - @hash['zomg'] = 'bears' + @hash["zomg"] = "bears" assert !@hash.empty? @hash.clear assert @hash.empty? end def test_each - @hash['hello'] = 'world' - @hash['foo'] = 'bar' + @hash["hello"] = "world" + @hash["foo"] = "bar" things = [] @hash.each do |k,v| @@ -110,13 +110,13 @@ module ActionDispatch end def test_replace - @hash['hello'] = 'world' - @hash.replace('omg' => 'aaron') - assert_equal({'omg' => 'aaron'}, @hash.to_hash) + @hash["hello"] = "world" + @hash.replace("omg" => "aaron") + assert_equal({ "omg" => "aaron" }, @hash.to_hash) end def test_discard_no_args - @hash['hello'] = 'world' + @hash["hello"] = "world" @hash.discard @hash.sweep @@ -124,49 +124,49 @@ module ActionDispatch end def test_discard_one_arg - @hash['hello'] = 'world' - @hash['omg'] = 'world' - @hash.discard 'hello' + @hash["hello"] = "world" + @hash["omg"] = "world" + @hash.discard "hello" @hash.sweep - assert_equal({'omg' => 'world'}, @hash.to_hash) + assert_equal({ "omg" => "world" }, @hash.to_hash) end def test_keep_sweep - @hash['hello'] = 'world' + @hash["hello"] = "world" @hash.sweep - assert_equal({'hello' => 'world'}, @hash.to_hash) + assert_equal({ "hello" => "world" }, @hash.to_hash) end def test_update_sweep - @hash['hello'] = 'world' - @hash.update({'hi' => 'mom'}) + @hash["hello"] = "world" + @hash.update("hi" => "mom") @hash.sweep - assert_equal({'hello' => 'world', 'hi' => 'mom'}, @hash.to_hash) + assert_equal({ "hello" => "world", "hi" => "mom" }, @hash.to_hash) end def test_update_delete_sweep - @hash['hello'] = 'world' - @hash.delete 'hello' - @hash.update({'hello' => 'mom'}) + @hash["hello"] = "world" + @hash.delete "hello" + @hash.update("hello" => "mom") @hash.sweep - assert_equal({'hello' => 'mom'}, @hash.to_hash) + assert_equal({ "hello" => "mom" }, @hash.to_hash) end def test_delete_sweep - @hash['hello'] = 'world' - @hash['hi'] = 'mom' - @hash.delete 'hi' + @hash["hello"] = "world" + @hash["hi"] = "mom" + @hash.delete "hi" @hash.sweep - assert_equal({'hello' => 'world'}, @hash.to_hash) + assert_equal({ "hello" => "world" }, @hash.to_hash) end def test_clear_sweep - @hash['hello'] = 'world' + @hash["hello"] = "world" @hash.clear @hash.sweep @@ -174,38 +174,38 @@ module ActionDispatch end def test_replace_sweep - @hash['hello'] = 'world' - @hash.replace({'hi' => 'mom'}) + @hash["hello"] = "world" + @hash.replace("hi" => "mom") @hash.sweep - assert_equal({'hi' => 'mom'}, @hash.to_hash) + assert_equal({ "hi" => "mom" }, @hash.to_hash) end def test_discard_then_add - @hash['hello'] = 'world' - @hash['omg'] = 'world' - @hash.discard 'hello' - @hash['hello'] = 'world' + @hash["hello"] = "world" + @hash["omg"] = "world" + @hash.discard "hello" + @hash["hello"] = "world" @hash.sweep - assert_equal({'omg' => 'world', 'hello' => 'world'}, @hash.to_hash) + assert_equal({ "omg" => "world", "hello" => "world" }, @hash.to_hash) end def test_keep_all_sweep - @hash['hello'] = 'world' - @hash['omg'] = 'world' - @hash.discard 'hello' + @hash["hello"] = "world" + @hash["omg"] = "world" + @hash.discard "hello" @hash.keep @hash.sweep - assert_equal({'omg' => 'world', 'hello' => 'world'}, @hash.to_hash) + assert_equal({ "omg" => "world", "hello" => "world" }, @hash.to_hash) end def test_double_sweep - @hash['hello'] = 'world' + @hash["hello"] = "world" @hash.sweep - assert_equal({'hello' => 'world'}, @hash.to_hash) + assert_equal({ "hello" => "world" }, @hash.to_hash) @hash.sweep assert_equal({}, @hash.to_hash) diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index eef48e8480..dc641c19ab 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' -require 'active_support/key_generator' +require "abstract_unit" +require "active_support/key_generator" class FlashTest < ActionController::TestCase class TestController < ActionController::Base def set_flash flash["that"] = "hello" - render :inline => "hello" + render inline: "hello" end def set_flash_now @@ -14,32 +14,32 @@ class FlashTest < ActionController::TestCase flash.now["foo"] ||= "err" @flashy = flash.now["that"] @flash_copy = {}.update flash - render :inline => "hello" + render inline: "hello" end def attempt_to_use_flash_now @flash_copy = {}.update flash @flashy = flash["that"] - render :inline => "hello" + render inline: "hello" end def use_flash @flash_copy = {}.update flash @flashy = flash["that"] - render :inline => "hello" + render inline: "hello" end def use_flash_and_keep_it @flash_copy = {}.update flash @flashy = flash["that"] flash.keep - render :inline => "hello" + render inline: "hello" end def use_flash_and_update_it flash.update("this" => "hello again") @flash_copy = {}.update flash - render :inline => "hello" + render inline: "hello" end def use_flash_after_reset_session @@ -49,11 +49,11 @@ class FlashTest < ActionController::TestCase @flashy_that_reset = flash["that"] flash["this"] = "good-bye" @flashy_this = flash["this"] - render :inline => "hello" + render inline: "hello" end # methods for test_sweep_after_halted_action_chain - before_action :halt_and_redir, only: 'filter_halting_action' + before_action :halt_and_redir, only: "filter_halting_action" def std_action @flash_copy = {}.update(flash) @@ -66,34 +66,34 @@ class FlashTest < ActionController::TestCase def halt_and_redir flash["foo"] = "bar" - redirect_to :action => "std_action" + redirect_to action: "std_action" @flash_copy = {}.update(flash) end def redirect_with_alert - redirect_to '/nowhere', :alert => "Beware the nowheres!" + redirect_to "/nowhere", alert: "Beware the nowheres!" end def redirect_with_notice - redirect_to '/somewhere', :notice => "Good luck in the somewheres!" + redirect_to "/somewhere", notice: "Good luck in the somewheres!" end def render_with_flash_now_alert flash.now.alert = "Beware the nowheres now!" - render :inline => "hello" + render inline: "hello" end def render_with_flash_now_notice flash.now.notice = "Good luck in the somewheres now!" - render :inline => "hello" + render inline: "hello" end def redirect_with_other_flashes - redirect_to '/wonderland', :flash => { :joyride => "Horses!" } + redirect_to "/wonderland", flash: { joyride: "Horses!" } end def redirect_with_foo_flash - redirect_to "/wonderland", :foo => 'for great justice' + redirect_to "/wonderland", foo: "for great justice" end end @@ -172,17 +172,17 @@ class FlashTest < ActionController::TestCase def test_keep_and_discard_return_values flash = ActionDispatch::Flash::FlashHash.new - flash.update(:foo => :foo_indeed, :bar => :bar_indeed) + flash.update(foo: :foo_indeed, bar: :bar_indeed) assert_equal(:foo_indeed, flash.discard(:foo)) # valid key passed assert_nil flash.discard(:unknown) # non existent key passed - assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.discard().to_hash) # nothing passed - assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.discard(nil).to_hash) # nothing passed + assert_equal({ "foo" => :foo_indeed, "bar" => :bar_indeed }, flash.discard().to_hash) # nothing passed + assert_equal({ "foo" => :foo_indeed, "bar" => :bar_indeed }, flash.discard(nil).to_hash) # nothing passed assert_equal(:foo_indeed, flash.keep(:foo)) # valid key passed assert_nil flash.keep(:unknown) # non existent key passed - assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.keep().to_hash) # nothing passed - assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.keep(nil).to_hash) # nothing passed + assert_equal({ "foo" => :foo_indeed, "bar" => :bar_indeed }, flash.keep().to_hash) # nothing passed + assert_equal({ "foo" => :foo_indeed, "bar" => :bar_indeed }, flash.keep(nil).to_hash) # nothing passed end def test_redirect_to_with_alert @@ -227,7 +227,7 @@ class FlashTest < ActionController::TestCase add_flash_types :foo end subclass_controller_with_no_flash_type = Class.new(test_controller_with_flash_type_foo) - assert subclass_controller_with_no_flash_type._flash_types.include?(:foo) + assert_includes subclass_controller_with_no_flash_type._flash_types, :foo end def test_does_not_add_flash_type_to_parent_class @@ -239,8 +239,8 @@ class FlashTest < ActionController::TestCase end class FlashIntegrationTest < ActionDispatch::IntegrationTest - SessionKey = '_myapp_session' - Generator = ActiveSupport::LegacyKeyGenerator.new('b3c631c314c0bbca50c1b2843150fe33') + SessionKey = "_myapp_session" + Generator = ActiveSupport::LegacyKeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33") class TestController < ActionController::Base add_flash_types :bar @@ -256,22 +256,29 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest end def use_flash - render :inline => "flash: #{flash["that"]}" + render inline: "flash: #{flash["that"]}" end def set_bar flash[:bar] = "for great justice" head :ok end + + def set_flash_optionally + flash.now.notice = params[:flash] + if stale? etag: "abe" + render inline: "maybe flash" + end + end end def test_flash with_test_route_set do - get '/set_flash' + get "/set_flash" assert_response :success assert_equal "hello", @request.flash["that"] - get '/use_flash' + get "/use_flash" assert_response :success assert_equal "flash: hello", @response.body end @@ -279,7 +286,7 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest def test_just_using_flash_does_not_stream_a_cookie_back with_test_route_set do - get '/use_flash' + get "/use_flash" assert_response :success assert_nil @response.headers["Set-Cookie"] assert_equal "flash: ", @response.body @@ -288,25 +295,47 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest def test_setting_flash_does_not_raise_in_following_requests with_test_route_set do - env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new } - get '/set_flash', env: env - get '/set_flash', env: env + env = { "action_dispatch.request.flash_hash" => ActionDispatch::Flash::FlashHash.new } + get "/set_flash", env: env + get "/set_flash", env: env end end def test_setting_flash_now_does_not_raise_in_following_requests with_test_route_set do - env = { 'action_dispatch.request.flash_hash' => ActionDispatch::Flash::FlashHash.new } - get '/set_flash_now', env: env - get '/set_flash_now', env: env + env = { "action_dispatch.request.flash_hash" => ActionDispatch::Flash::FlashHash.new } + get "/set_flash_now", env: env + get "/set_flash_now", env: env end end def test_added_flash_types_method with_test_route_set do - get '/set_bar' + get "/set_bar" assert_response :success - assert_equal 'for great justice', @controller.bar + assert_equal "for great justice", @controller.bar + end + end + + def test_flash_factored_into_etag + with_test_route_set do + get "/set_flash_optionally" + no_flash_etag = response.etag + + get "/set_flash_optionally", params: { flash: "hello!" } + hello_flash_etag = response.etag + + assert_not_equal no_flash_etag, hello_flash_etag + + get "/set_flash_optionally", params: { flash: "hello!" } + another_hello_flash_etag = response.etag + + assert_equal another_hello_flash_etag, hello_flash_etag + + get "/set_flash_optionally", params: { flash: "goodbye!" } + goodbye_flash_etag = response.etag + + assert_not_equal another_hello_flash_etag, goodbye_flash_etag end end @@ -324,12 +353,12 @@ class FlashIntegrationTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':action', :to => FlashIntegrationTest::TestController + get ":action", to: FlashIntegrationTest::TestController end end @app = self.class.build_app(set) do |middleware| - middleware.use ActionDispatch::Session::CookieStore, :key => SessionKey + middleware.use ActionDispatch::Session::CookieStore, key: SessionKey middleware.use ActionDispatch::Flash middleware.delete ActionDispatch::ShowExceptions end diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb index 03a9c9ae78..2b3859aa57 100644 --- a/actionpack/test/controller/force_ssl_test.rb +++ b/actionpack/test/controller/force_ssl_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ForceSSLController < ActionController::Base def banana @@ -15,15 +15,15 @@ class ForceSSLControllerLevel < ForceSSLController end class ForceSSLCustomOptions < ForceSSLController - force_ssl :host => "secure.example.com", :only => :redirect_host - force_ssl :port => 8443, :only => :redirect_port - force_ssl :subdomain => 'secure', :only => :redirect_subdomain - force_ssl :domain => 'secure.com', :only => :redirect_domain - force_ssl :path => '/foo', :only => :redirect_path - force_ssl :status => :found, :only => :redirect_status - force_ssl :flash => { :message => 'Foo, Bar!' }, :only => :redirect_flash - force_ssl :alert => 'Foo, Bar!', :only => :redirect_alert - force_ssl :notice => 'Foo, Bar!', :only => :redirect_notice + force_ssl host: "secure.example.com", only: :redirect_host + force_ssl port: 8443, only: :redirect_port + force_ssl subdomain: "secure", only: :redirect_subdomain + force_ssl domain: "secure.com", only: :redirect_domain + force_ssl path: "/foo", only: :redirect_path + force_ssl status: :found, only: :redirect_status + force_ssl flash: { message: "Foo, Bar!" }, only: :redirect_flash + force_ssl alert: "Foo, Bar!", only: :redirect_alert + force_ssl notice: "Foo, Bar!", only: :redirect_notice def force_ssl_action render plain: action_name @@ -53,42 +53,42 @@ class ForceSSLCustomOptions < ForceSSLController end class ForceSSLOnlyAction < ForceSSLController - force_ssl :only => :cheeseburger + force_ssl only: :cheeseburger end class ForceSSLExceptAction < ForceSSLController - force_ssl :except => :banana + force_ssl except: :banana end class ForceSSLIfCondition < ForceSSLController - force_ssl :if => :use_force_ssl? + force_ssl if: :use_force_ssl? def use_force_ssl? - action_name == 'cheeseburger' + action_name == "cheeseburger" end end class ForceSSLFlash < ForceSSLController - force_ssl :except => [:banana, :set_flash, :use_flash] + force_ssl except: [:banana, :set_flash, :use_flash] def set_flash flash["that"] = "hello" - redirect_to '/force_ssl_flash/cheeseburger' + redirect_to "/force_ssl_flash/cheeseburger" end def use_flash @flash_copy = {}.update flash @flashy = flash["that"] - render :inline => "hello" + render inline: "hello" end end class RedirectToSSL < ForceSSLController def banana - force_ssl_redirect || render(plain: 'monkey') + force_ssl_redirect || render(plain: "monkey") end def cheeseburger - force_ssl_redirect('secure.cheeseburger.host') || render(plain: 'ihaz') + force_ssl_redirect("secure.cheeseburger.host") || render(plain: "ihaz") end end @@ -114,7 +114,7 @@ end class ForceSSLCustomOptionsTest < ActionController::TestCase def setup - @request.env['HTTP_HOST'] = 'www.example.com:80' + @request.env["HTTP_HOST"] = "www.example.com:80" end def test_redirect_to_custom_host @@ -229,15 +229,13 @@ class ForceSSLFlashTest < ActionController::TestCase assert_response 302 assert_equal "http://test.host/force_ssl_flash/cheeseburger", redirect_to_url - # FIXME: AC::TestCase#build_request_uri doesn't build a new uri if PATH_INFO exists - @request.env.delete('PATH_INFO') + @request.env.delete("PATH_INFO") get :cheeseburger assert_response 301 assert_equal "https://test.host/force_ssl_flash/cheeseburger", redirect_to_url - # FIXME: AC::TestCase#build_request_uri doesn't build a new uri if PATH_INFO exists - @request.env.delete('PATH_INFO') + @request.env.delete("PATH_INFO") get :use_flash assert_equal "hello", @controller.instance_variable_get("@flash_copy")["that"] @@ -251,15 +249,15 @@ class ForceSSLDuplicateRoutesTest < ActionController::TestCase def test_force_ssl_redirects_to_same_path with_routing do |set| set.draw do - get '/foo', :to => 'force_ssl_controller_level#banana' - get '/bar', :to => 'force_ssl_controller_level#banana' + get "/foo", to: "force_ssl_controller_level#banana" + get "/bar", to: "force_ssl_controller_level#banana" end - @request.env['PATH_INFO'] = '/bar' + @request.env["PATH_INFO"] = "/bar" get :banana assert_response 301 - assert_equal 'https://test.host/bar', redirect_to_url + assert_equal "https://test.host/bar", redirect_to_url end end end @@ -270,12 +268,12 @@ class ForceSSLFormatTest < ActionController::TestCase def test_force_ssl_redirects_to_same_format with_routing do |set| set.draw do - get '/foo', :to => 'force_ssl_controller_level#banana' + get "/foo", to: "force_ssl_controller_level#banana" end get :banana, format: :json assert_response 301 - assert_equal 'https://test.host/foo.json', redirect_to_url + assert_equal "https://test.host/foo.json", redirect_to_url end end end @@ -286,18 +284,18 @@ class ForceSSLOptionalSegmentsTest < ActionController::TestCase def test_force_ssl_redirects_to_same_format with_routing do |set| set.draw do - scope '(:locale)' do - defaults :locale => 'en' do - get '/foo', :to => 'force_ssl_controller_level#banana' + scope "(:locale)" do + defaults locale: "en" do + get "/foo", to: "force_ssl_controller_level#banana" end end end - @request.env['PATH_INFO'] = '/en/foo' - get :banana, params: { locale: 'en' } - assert_equal 'en', @controller.params[:locale] + @request.env["PATH_INFO"] = "/en/foo" + get :banana, params: { locale: "en" } + assert_equal "en", @controller.params[:locale] assert_response 301 - assert_equal 'https://test.host/en/foo', redirect_to_url + assert_equal "https://test.host/en/foo", redirect_to_url end end end @@ -316,17 +314,17 @@ class RedirectToSSLTest < ActionController::TestCase end def test_cheeseburgers_does_not_redirect_if_already_https - request.env['HTTPS'] = 'on' + request.env["HTTPS"] = "on" get :cheeseburger assert_response 200 - assert_equal 'ihaz', response.body + assert_equal "ihaz", response.body end end class ForceSSLControllerLevelTest < ActionController::TestCase def test_no_redirect_websocket_ssl_request - request.env['rack.url_scheme'] = 'wss' - request.env['Upgrade'] = 'websocket' + request.env["rack.url_scheme"] = "wss" + request.env["Upgrade"] = "websocket" get :cheeseburger assert_response 200 end diff --git a/actionpack/test/controller/form_builder_test.rb b/actionpack/test/controller/form_builder_test.rb index 99eeaf9ab6..5a3dc2ee03 100644 --- a/actionpack/test/controller/form_builder_test.rb +++ b/actionpack/test/controller/form_builder_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class FormBuilderController < ActionController::Base class SpecializedFormBuilder < ActionView::Helpers::FormBuilder ; end diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index ef85e141a0..4c6a772062 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -1,17 +1,17 @@ -require 'abstract_unit' +require "abstract_unit" -ActionController::Base.helpers_path = File.expand_path('../../fixtures/helpers', __FILE__) +ActionController::Base.helpers_path = File.expand_path("../../fixtures/helpers", __FILE__) module Fun class GamesController < ActionController::Base def render_hello_world - render :inline => "hello: <%= stratego %>" + render inline: "hello: <%= stratego %>" end end class PdfController < ActionController::Base def test - render :inline => "test: <%= foobar %>" + render inline: "test: <%= foobar %>" end end end @@ -35,11 +35,11 @@ class JustMeController < ActionController::Base clear_helpers def flash - render :inline => "<h1><%= notice %></h1>" + render inline: "<h1><%= notice %></h1>" end def lib - render :inline => '<%= useful_function %>' + render inline: "<%= useful_function %>" end end @@ -48,7 +48,7 @@ end class HelpersPathsController < ActionController::Base paths = ["helpers2_pack", "helpers1_pack"].map do |path| - File.join(File.expand_path('../../fixtures', __FILE__), path) + File.join(File.expand_path("../../fixtures", __FILE__), path) end $:.unshift(*paths) @@ -56,12 +56,12 @@ class HelpersPathsController < ActionController::Base helper :all def index - render :inline => "<%= conflicting_helper %>" + render inline: "<%= conflicting_helper %>" end end class HelpersTypoController < ActionController::Base - path = File.expand_path('../../fixtures/helpers_typo', __FILE__) + path = File.expand_path("../../fixtures/helpers_typo", __FILE__) $:.unshift(path) self.helpers_path = path end @@ -89,7 +89,7 @@ class HelpersTypoControllerTest < ActiveSupport::TestCase end def test_helper_typo_error_message - e = assert_raise(NameError) { HelpersTypoController.helper 'admin/users' } + e = assert_raise(NameError) { HelpersTypoController.helper "admin/users" } assert_equal "Couldn't find Admin::UsersHelper, expected it to be defined in helpers/admin/users_helper.rb", e.message end @@ -106,7 +106,7 @@ class HelperTest < ActiveSupport::TestCase def setup # Increment symbol counter. - @symbol = (@@counter ||= 'A0').succ!.dup + @symbol = (@@counter ||= "A0").succ!.dup # Generate new controller class. controller_class_name = "Helper#{@symbol}Controller" @@ -125,13 +125,13 @@ class HelperTest < ActiveSupport::TestCase def test_helper_method assert_nothing_raised { @controller_class.helper_method :delegate_method } - assert master_helper_methods.include?(:delegate_method) + assert_includes master_helper_methods, :delegate_method end def test_helper_attr assert_nothing_raised { @controller_class.helper_attr :delegate_attr } - assert master_helper_methods.include?(:delegate_attr) - assert master_helper_methods.include?(:delegate_attr=) + assert_includes master_helper_methods, :delegate_attr + assert_includes master_helper_methods, :delegate_attr= end def call_controller(klass, action) @@ -139,7 +139,7 @@ class HelperTest < ActiveSupport::TestCase end def test_helper_for_nested_controller - assert_equal 'hello: Iz guuut!', + assert_equal "hello: Iz guuut!", call_controller(Fun::GamesController, "render_hello_world").last.body end @@ -168,43 +168,43 @@ class HelperTest < ActiveSupport::TestCase methods = AllHelpersController._helpers.instance_methods # abc_helper.rb - assert methods.include?(:bare_a) + assert_includes methods, :bare_a # fun/games_helper.rb - assert methods.include?(:stratego) + assert_includes methods, :stratego # fun/pdf_helper.rb - assert methods.include?(:foobar) + assert_includes methods, :foobar end def test_all_helpers_with_alternate_helper_dir - @controller_class.helpers_path = File.expand_path('../../fixtures/alternate_helpers', __FILE__) + @controller_class.helpers_path = File.expand_path("../../fixtures/alternate_helpers", __FILE__) # Reload helpers @controller_class._helpers = Module.new @controller_class.helper :all # helpers/abc_helper.rb should not be included - assert !master_helper_methods.include?(:bare_a) + assert_not_includes master_helper_methods, :bare_a # alternate_helpers/foo_helper.rb - assert master_helper_methods.include?(:baz) + assert_includes master_helper_methods, :baz end def test_helper_proxy methods = AllHelpersController.helpers.methods # Action View - assert methods.include?(:pluralize) + assert_includes methods, :pluralize # abc_helper.rb - assert methods.include?(:bare_a) + assert_includes methods, :bare_a # fun/games_helper.rb - assert methods.include?(:stratego) + assert_includes methods, :stratego # fun/pdf_helper.rb - assert methods.include?(:foobar) + assert_includes methods, :foobar end def test_helper_proxy_in_instance @@ -224,9 +224,9 @@ class HelperTest < ActiveSupport::TestCase end def test_helper_proxy_config - AllHelpersController.config.my_var = 'smth' + AllHelpersController.config.my_var = "smth" - assert_equal 'smth', AllHelpersController.helpers.config.my_var + assert_equal "smth", AllHelpersController.helpers.config.my_var end private @@ -243,31 +243,30 @@ class HelperTest < ActiveSupport::TestCase end def test_helper=(helper_module) - silence_warnings { self.class.const_set('TestHelper', helper_module) } + silence_warnings { self.class.const_set("TestHelper", helper_module) } end end - class IsolatedHelpersTest < ActionController::TestCase class A < ActionController::Base def index - render :inline => '<%= shout %>' + render inline: "<%= shout %>" end end class B < A - helper { def shout; 'B' end } + helper { def shout; "B" end } def index - render :inline => '<%= shout %>' + render inline: "<%= shout %>" end end class C < A - helper { def shout; 'C' end } + helper { def shout; "C" end } def index - render :inline => '<%= shout %>' + render inline: "<%= shout %>" end end @@ -277,7 +276,7 @@ class IsolatedHelpersTest < ActionController::TestCase def setup super - @request.action = 'index' + @request.action = "index" end def test_helper_in_a @@ -285,10 +284,10 @@ class IsolatedHelpersTest < ActionController::TestCase end def test_helper_in_b - assert_equal 'B', call_controller(B, "index").last.body + assert_equal "B", call_controller(B, "index").last.body end def test_helper_in_c - assert_equal 'C', call_controller(C, "index").last.body + assert_equal "C", call_controller(C, "index").last.body end end diff --git a/actionpack/test/controller/http_basic_authentication_test.rb b/actionpack/test/controller/http_basic_authentication_test.rb index adcf259317..d9ae787689 100644 --- a/actionpack/test/controller/http_basic_authentication_test.rb +++ b/actionpack/test/controller/http_basic_authentication_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class HttpBasicAuthenticationTest < ActionController::TestCase class DummyController < ActionController::Base @@ -7,88 +7,88 @@ class HttpBasicAuthenticationTest < ActionController::TestCase before_action :authenticate_long_credentials, only: :show before_action :auth_with_special_chars, only: :special_creds - http_basic_authenticate_with :name => "David", :password => "Goliath", :only => :search + http_basic_authenticate_with name: "David", password: "Goliath", only: :search def index render plain: "Hello Secret" end def display - render plain: 'Definitely Maybe' if @logged_in + render plain: "Definitely Maybe" if @logged_in end def show - render plain: 'Only for loooooong credentials' + render plain: "Only for loooooong credentials" end def special_creds - render plain: 'Only for special credentials' + render plain: "Only for special credentials" end def search - render plain: 'All inline' + render plain: "All inline" end private - def authenticate - authenticate_or_request_with_http_basic do |username, password| - username == 'lifo' && password == 'world' + def authenticate + authenticate_or_request_with_http_basic do |username, password| + username == "lifo" && password == "world" + end end - end - def authenticate_with_request - if authenticate_with_http_basic { |username, password| username == 'pretty' && password == 'please' } - @logged_in = true - else - request_http_basic_authentication("SuperSecret", "Authentication Failed\n") + def authenticate_with_request + if authenticate_with_http_basic { |username, password| username == "pretty" && password == "please" } + @logged_in = true + else + request_http_basic_authentication("SuperSecret", "Authentication Failed\n") + end end - end - def auth_with_special_chars - authenticate_or_request_with_http_basic do |username, password| - username == 'login!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t' && password == 'pwd:!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t' + def auth_with_special_chars + authenticate_or_request_with_http_basic do |username, password| + username == 'login!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t' && password == 'pwd:!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t' + end end - end - def authenticate_long_credentials - authenticate_or_request_with_http_basic do |username, password| - username == '1234567890123456789012345678901234567890' && password == '1234567890123456789012345678901234567890' + def authenticate_long_credentials + authenticate_or_request_with_http_basic do |username, password| + username == "1234567890123456789012345678901234567890" && password == "1234567890123456789012345678901234567890" + end end - end end - AUTH_HEADERS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION', 'REDIRECT_X_HTTP_AUTHORIZATION'] + AUTH_HEADERS = ["HTTP_AUTHORIZATION", "X-HTTP_AUTHORIZATION", "X_HTTP_AUTHORIZATION", "REDIRECT_X_HTTP_AUTHORIZATION"] tests DummyController AUTH_HEADERS.each do |header| test "successful authentication with #{header.downcase}" do - @request.env[header] = encode_credentials('lifo', 'world') + @request.env[header] = encode_credentials("lifo", "world") get :index assert_response :success - assert_equal 'Hello Secret', @response.body, "Authentication failed for request header #{header}" + assert_equal "Hello Secret", @response.body, "Authentication failed for request header #{header}" end test "successful authentication with #{header.downcase} and long credentials" do - @request.env[header] = encode_credentials('1234567890123456789012345678901234567890', '1234567890123456789012345678901234567890') + @request.env[header] = encode_credentials("1234567890123456789012345678901234567890", "1234567890123456789012345678901234567890") get :show assert_response :success - assert_equal 'Only for loooooong credentials', @response.body, "Authentication failed for request header #{header} and long credentials" + assert_equal "Only for loooooong credentials", @response.body, "Authentication failed for request header #{header} and long credentials" end end AUTH_HEADERS.each do |header| test "unsuccessful authentication with #{header.downcase}" do - @request.env[header] = encode_credentials('h4x0r', 'world') + @request.env[header] = encode_credentials("h4x0r", "world") get :index assert_response :unauthorized assert_equal "HTTP Basic: Access denied.\n", @response.body, "Authentication didn't fail for request header #{header}" end test "unsuccessful authentication with #{header.downcase} and long credentials" do - @request.env[header] = encode_credentials('h4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0r', 'worldworldworldworldworldworldworldworld') + @request.env[header] = encode_credentials("h4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0r", "worldworldworldworldworldworldworldworld") get :show assert_response :unauthorized @@ -104,19 +104,19 @@ class HttpBasicAuthenticationTest < ActionController::TestCase end def test_encode_credentials_has_no_newline - username = 'laskjdfhalksdjfhalkjdsfhalksdjfhklsdjhalksdjfhalksdjfhlakdsjfh' - password = 'kjfhueyt9485osdfasdkljfh4lkjhakldjfhalkdsjf' + username = "laskjdfhalksdjfhalkjdsfhalksdjfhklsdjhalksdjfhalksdjfhlakdsjfh" + password = "kjfhueyt9485osdfasdkljfh4lkjhakldjfhalkdsjf" result = ActionController::HttpAuthentication::Basic.encode_credentials( username, password) assert_no_match(/\n/, result) end test "successful authentication with uppercase authorization scheme" do - @request.env['HTTP_AUTHORIZATION'] = "BASIC #{::Base64.encode64("lifo:world")}" + @request.env["HTTP_AUTHORIZATION"] = "BASIC #{::Base64.encode64("lifo:world")}" get :index assert_response :success - assert_equal 'Hello Secret', @response.body, 'Authentication failed when authorization scheme BASIC' + assert_equal "Hello Secret", @response.body, "Authentication failed when authorization scheme BASIC" end test "authentication request without credential" do @@ -124,54 +124,54 @@ class HttpBasicAuthenticationTest < ActionController::TestCase assert_response :unauthorized assert_equal "Authentication Failed\n", @response.body - assert_equal 'Basic realm="SuperSecret"', @response.headers['WWW-Authenticate'] + assert_equal 'Basic realm="SuperSecret"', @response.headers["WWW-Authenticate"] end test "authentication request with invalid credential" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials('pretty', 'foo') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials("pretty", "foo") get :display assert_response :unauthorized assert_equal "Authentication Failed\n", @response.body - assert_equal 'Basic realm="SuperSecret"', @response.headers['WWW-Authenticate'] + assert_equal 'Basic realm="SuperSecret"', @response.headers["WWW-Authenticate"] end test "authentication request with valid credential" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials('pretty', 'please') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials("pretty", "please") get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with valid credential special chars" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials('login!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t', 'pwd:!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials('login!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t', 'pwd:!@#$%^&*()_+{}[];"\',./<>?`~ \n\r\t') get :special_creds assert_response :success - assert_equal 'Only for special credentials', @response.body + assert_equal "Only for special credentials", @response.body end test "authenticate with class method" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials('David', 'Goliath') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials("David", "Goliath") get :search assert_response :success - @request.env['HTTP_AUTHORIZATION'] = encode_credentials('David', 'WRONG!') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials("David", "WRONG!") get :search assert_response :unauthorized end test "authentication request with wrong scheme" do - header = 'Bearer ' + encode_credentials('David', 'Goliath').split(' ', 2)[1] - @request.env['HTTP_AUTHORIZATION'] = header + header = "Bearer " + encode_credentials("David", "Goliath").split(" ", 2)[1] + @request.env["HTTP_AUTHORIZATION"] = header get :search assert_response :unauthorized end private - def encode_credentials(username, password) - "Basic #{::Base64.encode64("#{username}:#{password}")}" - end + def encode_credentials(username, password) + "Basic #{::Base64.encode64("#{username}:#{password}")}" + end end diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb index f06912bd5a..343b7b643d 100644 --- a/actionpack/test/controller/http_digest_authentication_test.rb +++ b/actionpack/test/controller/http_digest_authentication_test.rb @@ -1,41 +1,41 @@ -require 'abstract_unit' -require 'active_support/key_generator' +require "abstract_unit" +require "active_support/key_generator" class HttpDigestAuthenticationTest < ActionController::TestCase class DummyDigestController < ActionController::Base before_action :authenticate, only: :index before_action :authenticate_with_request, only: :display - USERS = { 'lifo' => 'world', 'pretty' => 'please', - 'dhh' => ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":"))} + USERS = { "lifo" => "world", "pretty" => "please", + "dhh" => ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":")) } def index render plain: "Hello Secret" end def display - render plain: 'Definitely Maybe' if @logged_in + render plain: "Definitely Maybe" if @logged_in end private - def authenticate - authenticate_or_request_with_http_digest("SuperSecret") do |username| - # Returns the password - USERS[username] + def authenticate + authenticate_or_request_with_http_digest("SuperSecret") do |username| + # Returns the password + USERS[username] + end end - end - def authenticate_with_request - if authenticate_with_http_digest("SuperSecret") { |username| USERS[username] } - @logged_in = true - else - request_http_digest_authentication("SuperSecret", "Authentication Failed") + def authenticate_with_request + if authenticate_with_http_digest("SuperSecret") { |username| USERS[username] } + @logged_in = true + else + request_http_digest_authentication("SuperSecret", "Authentication Failed") + end end - end end - AUTH_HEADERS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION', 'REDIRECT_X_HTTP_AUTHORIZATION'] + AUTH_HEADERS = ["HTTP_AUTHORIZATION", "X-HTTP_AUTHORIZATION", "X_HTTP_AUTHORIZATION", "REDIRECT_X_HTTP_AUTHORIZATION"] tests DummyDigestController @@ -51,17 +51,17 @@ class HttpDigestAuthenticationTest < ActionController::TestCase AUTH_HEADERS.each do |header| test "successful authentication with #{header.downcase}" do - @request.env[header] = encode_credentials(:username => 'lifo', :password => 'world') + @request.env[header] = encode_credentials(username: "lifo", password: "world") get :index assert_response :success - assert_equal 'Hello Secret', @response.body, "Authentication failed for request header #{header}" + assert_equal "Hello Secret", @response.body, "Authentication failed for request header #{header}" end end AUTH_HEADERS.each do |header| test "unsuccessful authentication with #{header.downcase}" do - @request.env[header] = encode_credentials(:username => 'h4x0r', :password => 'world') + @request.env[header] = encode_credentials(username: "h4x0r", password: "world") get :index assert_response :unauthorized @@ -74,21 +74,21 @@ class HttpDigestAuthenticationTest < ActionController::TestCase assert_response :unauthorized assert_equal "Authentication Failed", @response.body - credentials = decode_credentials(@response.headers['WWW-Authenticate']) - assert_equal 'SuperSecret', credentials[:realm] + credentials = decode_credentials(@response.headers["WWW-Authenticate"]) + assert_equal "SuperSecret", credentials[:realm] end test "authentication request with nil credentials" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => nil, :password => nil) + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: nil, password: nil) get :index assert_response :unauthorized assert_equal "HTTP Digest: Access denied.\n", @response.body, "Authentication didn't fail for request" - assert_not_equal 'Hello Secret', @response.body, "Authentication didn't fail for request" + assert_not_equal "Hello Secret", @response.body, "Authentication didn't fail for request" end test "authentication request with invalid password" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "foo") get :display assert_response :unauthorized @@ -96,7 +96,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase end test "authentication request with invalid nonce" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please', :nonce => "xxyyzz") + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please", nonce: "xxyyzz") get :display assert_response :unauthorized @@ -104,7 +104,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase end test "authentication request with invalid opaque" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo', :opaque => "xxyyzz") + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "foo", opaque: "xxyyzz") get :display assert_response :unauthorized @@ -112,7 +112,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase end test "authentication request with invalid realm" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'foo', :realm => "NotSecret") + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "foo", realm: "NotSecret") get :display assert_response :unauthorized @@ -120,127 +120,127 @@ class HttpDigestAuthenticationTest < ActionController::TestCase end test "authentication request with valid credential" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please") get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with valid credential and nil session" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please") get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with request-uri that doesn't match credentials digest-uri" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please') - @request.env['PATH_INFO'] = "/proxied/uri" + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please") + @request.env["PATH_INFO"] = "/proxied/uri" get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with absolute request uri (as in webrick)" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please") @request.env["SERVER_NAME"] = "test.host" - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest" + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest" get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with absolute uri in credentials (as in IE)" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:url => "http://test.host/http_digest_authentication_test/dummy_digest", - :username => 'pretty', :password => 'please') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(url: "http://test.host/http_digest_authentication_test/dummy_digest", + username: "pretty", password: "please") get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with absolute uri in both request and credentials (as in Webrick with IE)" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:url => "http://test.host/http_digest_authentication_test/dummy_digest", - :username => 'pretty', :password => 'please') - @request.env['SERVER_NAME'] = "test.host" - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest" + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(url: "http://test.host/http_digest_authentication_test/dummy_digest", + username: "pretty", password: "please") + @request.env["SERVER_NAME"] = "test.host" + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest" get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with password stored as ha1 digest hash" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'dhh', - :password => ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":")), - :password_is_ha1 => true) + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "dhh", + password: ::Digest::MD5::hexdigest(["dhh","SuperSecret","secret"].join(":")), + password_is_ha1: true) get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with _method" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please', :method => :post) - @request.env['rack.methodoverride.original_method'] = 'POST' + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please", method: :post) + @request.env["rack.methodoverride.original_method"] = "POST" put :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "validate_digest_response should fail with nil returning password_procedure" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => nil, :password => nil) - assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@request, "SuperSecret"){nil} + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: nil, password: nil) + assert !ActionController::HttpAuthentication::Digest.validate_digest_response(@request, "SuperSecret") { nil } end test "authentication request with request-uri ending in '/'" do - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest/" - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please') + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest/" + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please") # simulate normalizing PATH_INFO - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest" + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest" get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with request-uri ending in '?'" do - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest/?" - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please') + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest/?" + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "pretty", password: "please") # simulate normalizing PATH_INFO - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest" + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest" get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "authentication request with absolute uri in credentials (as in IE) ending with /" do - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest/" - @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:uri => "http://test.host/http_digest_authentication_test/dummy_digest/", - :username => 'pretty', :password => 'please') + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest/" + @request.env["HTTP_AUTHORIZATION"] = encode_credentials(uri: "http://test.host/http_digest_authentication_test/dummy_digest/", + username: "pretty", password: "please") # simulate normalizing PATH_INFO - @request.env['PATH_INFO'] = "/http_digest_authentication_test/dummy_digest" + @request.env["PATH_INFO"] = "/http_digest_authentication_test/dummy_digest" get :display assert_response :success - assert_equal 'Definitely Maybe', @response.body + assert_equal "Definitely Maybe", @response.body end test "when sent a basic auth header, returns Unauthorized" do - @request.env['HTTP_AUTHORIZATION'] = 'Basic Gwf2aXq8ZLF3Hxq=' + @request.env["HTTP_AUTHORIZATION"] = "Basic Gwf2aXq8ZLF3Hxq=" get :display @@ -249,32 +249,32 @@ class HttpDigestAuthenticationTest < ActionController::TestCase private - def encode_credentials(options) - options.reverse_merge!(:nc => "00000001", :cnonce => "0a4f113b", :password_is_ha1 => false) - password = options.delete(:password) + def encode_credentials(options) + options.reverse_merge!(nc: "00000001", cnonce: "0a4f113b", password_is_ha1: false) + password = options.delete(:password) - # Perform unauthenticated request to retrieve digest parameters to use on subsequent request - method = options.delete(:method) || 'GET' + # Perform unauthenticated request to retrieve digest parameters to use on subsequent request + method = options.delete(:method) || "GET" - case method.to_s.upcase - when 'GET' - get :index - when 'POST' - post :index - end + case method.to_s.upcase + when "GET" + get :index + when "POST" + post :index + end - assert_response :unauthorized + assert_response :unauthorized - credentials = decode_credentials(@response.headers['WWW-Authenticate']) - credentials.merge!(options) - path_info = @request.env['PATH_INFO'].to_s - uri = options[:uri] || path_info - credentials.merge!(:uri => uri) - @request.env["ORIGINAL_FULLPATH"] = path_info - ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1]) - end + credentials = decode_credentials(@response.headers["WWW-Authenticate"]) + credentials.merge!(options) + path_info = @request.env["PATH_INFO"].to_s + uri = options[:uri] || path_info + credentials.merge!(uri: uri) + @request.env["ORIGINAL_FULLPATH"] = path_info + ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1]) + end - def decode_credentials(header) - ActionController::HttpAuthentication::Digest.decode_credentials(header) - end + def decode_credentials(header) + ActionController::HttpAuthentication::Digest.decode_credentials(header) + end end diff --git a/actionpack/test/controller/http_token_authentication_test.rb b/actionpack/test/controller/http_token_authentication_test.rb index 98e3c891a7..3842136682 100644 --- a/actionpack/test/controller/http_token_authentication_test.rb +++ b/actionpack/test/controller/http_token_authentication_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class HttpTokenAuthenticationTest < ActionController::TestCase class DummyController < ActionController::Base @@ -11,67 +11,67 @@ class HttpTokenAuthenticationTest < ActionController::TestCase end def display - render plain: 'Definitely Maybe' + render plain: "Definitely Maybe" end def show - render plain: 'Only for loooooong credentials' + render plain: "Only for loooooong credentials" end private - def authenticate - authenticate_or_request_with_http_token do |token, _| - token == 'lifo' + def authenticate + authenticate_or_request_with_http_token do |token, _| + token == "lifo" + end end - end - def authenticate_with_request - if authenticate_with_http_token { |token, options| token == '"quote" pretty' && options[:algorithm] == 'test' } - @logged_in = true - else - request_http_token_authentication("SuperSecret", "Authentication Failed\n") + def authenticate_with_request + if authenticate_with_http_token { |token, options| token == '"quote" pretty' && options[:algorithm] == "test" } + @logged_in = true + else + request_http_token_authentication("SuperSecret", "Authentication Failed\n") + end end - end - def authenticate_long_credentials - authenticate_or_request_with_http_token do |token, options| - token == '1234567890123456789012345678901234567890' && options[:algorithm] == 'test' + def authenticate_long_credentials + authenticate_or_request_with_http_token do |token, options| + token == "1234567890123456789012345678901234567890" && options[:algorithm] == "test" + end end - end end - AUTH_HEADERS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION', 'REDIRECT_X_HTTP_AUTHORIZATION'] + AUTH_HEADERS = ["HTTP_AUTHORIZATION", "X-HTTP_AUTHORIZATION", "X_HTTP_AUTHORIZATION", "REDIRECT_X_HTTP_AUTHORIZATION"] tests DummyController AUTH_HEADERS.each do |header| test "successful authentication with #{header.downcase}" do - @request.env[header] = encode_credentials('lifo') + @request.env[header] = encode_credentials("lifo") get :index assert_response :success - assert_equal 'Hello Secret', @response.body, "Authentication failed for request header #{header}" + assert_equal "Hello Secret", @response.body, "Authentication failed for request header #{header}" end test "successful authentication with #{header.downcase} and long credentials" do - @request.env[header] = encode_credentials('1234567890123456789012345678901234567890', :algorithm => 'test') + @request.env[header] = encode_credentials("1234567890123456789012345678901234567890", algorithm: "test") get :show assert_response :success - assert_equal 'Only for loooooong credentials', @response.body, "Authentication failed for request header #{header} and long credentials" + assert_equal "Only for loooooong credentials", @response.body, "Authentication failed for request header #{header} and long credentials" end end AUTH_HEADERS.each do |header| test "unsuccessful authentication with #{header.downcase}" do - @request.env[header] = encode_credentials('h4x0r') + @request.env[header] = encode_credentials("h4x0r") get :index assert_response :unauthorized assert_equal "HTTP Token: Access denied.\n", @response.body, "Authentication didn't fail for request header #{header}" end test "unsuccessful authentication with #{header.downcase} and long credentials" do - @request.env[header] = encode_credentials('h4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0r') + @request.env[header] = encode_credentials("h4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0r") get :show assert_response :unauthorized @@ -80,7 +80,7 @@ class HttpTokenAuthenticationTest < ActionController::TestCase end test "authentication request with badly formatted header" do - @request.env['HTTP_AUTHORIZATION'] = 'Token token$"lifo"' + @request.env["HTTP_AUTHORIZATION"] = 'Token token$"lifo"' get :index assert_response :unauthorized @@ -88,18 +88,18 @@ class HttpTokenAuthenticationTest < ActionController::TestCase end test "successful authentication request with Bearer instead of Token" do - @request.env['HTTP_AUTHORIZATION'] = 'Bearer lifo' + @request.env["HTTP_AUTHORIZATION"] = "Bearer lifo" get :index assert_response :success end test "authentication request with tab in header" do - @request.env['HTTP_AUTHORIZATION'] = "Token\ttoken=\"lifo\"" + @request.env["HTTP_AUTHORIZATION"] = "Token\ttoken=\"lifo\"" get :index assert_response :success - assert_equal 'Hello Secret', @response.body + assert_equal "Hello Secret", @response.body end test "authentication request without credential" do @@ -107,16 +107,16 @@ class HttpTokenAuthenticationTest < ActionController::TestCase assert_response :unauthorized assert_equal "Authentication Failed\n", @response.body - assert_equal 'Token realm="SuperSecret"', @response.headers['WWW-Authenticate'] + assert_equal 'Token realm="SuperSecret"', @response.headers["WWW-Authenticate"] end test "authentication request with invalid credential" do - @request.env['HTTP_AUTHORIZATION'] = encode_credentials('"quote" pretty') + @request.env["HTTP_AUTHORIZATION"] = encode_credentials('"quote" pretty') get :display assert_response :unauthorized assert_equal "Authentication Failed\n", @response.body - assert_equal 'Token realm="SuperSecret"', @response.headers['WWW-Authenticate'] + assert_equal 'Token realm="SuperSecret"', @response.headers["WWW-Authenticate"] end test "token_and_options returns correct token" do @@ -127,7 +127,7 @@ class HttpTokenAuthenticationTest < ActionController::TestCase end test "token_and_options returns correct token with value after the equal sign" do - token = 'rcHu+=HzSFw89Ypyhn/896A==f34' + token = "rcHu+=HzSFw89Ypyhn/896A==f34" actual = ActionController::HttpAuthentication::Token.token_and_options(sample_request(token)).first expected = token assert_equal(expected, actual) @@ -148,7 +148,7 @@ class HttpTokenAuthenticationTest < ActionController::TestCase end test "token_and_options returns empty string with empty token" do - token = '' + token = "" actual = ActionController::HttpAuthentication::Token.token_and_options(sample_request(token)).first expected = token assert_equal(expected, actual) @@ -156,10 +156,10 @@ class HttpTokenAuthenticationTest < ActionController::TestCase test "token_and_options returns correct token with nounce option" do token = "rcHu+HzSFw89Ypyhn/896A=" - nonce_hash = {nonce: "123abc"} + nonce_hash = { nonce: "123abc" } actual = ActionController::HttpAuthentication::Token.token_and_options(sample_request(token, nonce_hash)) expected_token = token - expected_nonce = {"nonce" => nonce_hash[:nonce]} + expected_nonce = { "nonce" => nonce_hash[:nonce] } assert_equal(expected_token, actual.first) assert_equal(expected_nonce, actual.last) end @@ -190,7 +190,7 @@ class HttpTokenAuthenticationTest < ActionController::TestCase private - def sample_request(token, options = {nonce: "def"}) + def sample_request(token, options = { nonce: "def" }) authorization = options.inject([%{Token token="#{token}"}]) do |arr, (k, v)| arr << "#{k}=\"#{v}\"" end.join(", ") diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 34fb3b1003..67a42989c2 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -1,10 +1,10 @@ -require 'abstract_unit' -require 'controller/fake_controllers' -require 'rails/engine' +require "abstract_unit" +require "controller/fake_controllers" +require "rails/engine" class SessionTest < ActiveSupport::TestCase StubApp = lambda { |env| - [200, {"Content-Type" => "text/html", "Content-Length" => "13"}, ["Hello, World!"]] + [200, { "Content-Type" => "text/html", "Content-Length" => "13" }, ["Hello, World!"]] } def setup @@ -31,97 +31,8 @@ class SessionTest < ActiveSupport::TestCase end end - def test_request_via_redirect_uses_given_method - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue"} - assert_called_with @session, :process, [:put, path, params: args, headers: headers] do - @session.stub :redirect?, false do - assert_deprecated { @session.request_via_redirect(:put, path, params: args, headers: headers) } - end - end - end - - def test_deprecated_request_via_redirect_uses_given_method - path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } - assert_called_with @session, :process, [:put, path, params: args, headers: headers] do - @session.stub :redirect?, false do - assert_deprecated { @session.request_via_redirect(:put, path, args, headers) } - end - end - end - - def test_request_via_redirect_follows_redirects - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue"} - value_series = [true, true, false] - assert_called @session, :follow_redirect!, times: 2 do - @session.stub :redirect?, ->{ value_series.shift } do - assert_deprecated { @session.request_via_redirect(:get, path, params: args, headers: headers) } - end - end - end - - def test_request_via_redirect_returns_status - path = "/somepath"; args = {:id => '1'}; headers = {"X-Test-Header" => "testvalue"} - @session.stub :redirect?, false do - @session.stub :status, 200 do - assert_deprecated do - assert_equal 200, @session.request_via_redirect(:get, path, params: args, headers: headers) - end - end - end - end - - def test_deprecated_get_via_redirect - path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } - - assert_called_with @session, :request_via_redirect, [:get, path, args, headers] do - assert_deprecated do - @session.get_via_redirect(path, args, headers) - end - end - end - - def test_deprecated_post_via_redirect - path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } - - assert_called_with @session, :request_via_redirect, [:post, path, args, headers] do - assert_deprecated do - @session.post_via_redirect(path, args, headers) - end - end - end - - def test_deprecated_patch_via_redirect - path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } - - assert_called_with @session, :request_via_redirect, [:patch, path, args, headers] do - assert_deprecated do - @session.patch_via_redirect(path, args, headers) - end - end - end - - def test_deprecated_put_via_redirect - path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } - - assert_called_with @session, :request_via_redirect, [:put, path, args, headers] do - assert_deprecated do - @session.put_via_redirect(path, args, headers) - end - end - end - - def test_deprecated_delete_via_redirect - path = "/somepath"; args = { id: '1' }; headers = { "X-Test-Header" => "testvalue" } - - assert_called_with @session, :request_via_redirect, [:delete, path, args, headers] do - assert_deprecated do - @session.delete_via_redirect(path, args, headers) - end - end - end - def test_get - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:get, path, params: params, headers: headers] do @session.get(path, params: params, headers: headers) @@ -129,229 +40,88 @@ class SessionTest < ActiveSupport::TestCase end def test_get_with_env_and_headers - path = "/index"; params = "blah"; headers = { location: 'blah' }; env = { 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' } + path = "/index"; params = "blah"; headers = { location: "blah" }; env = { "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" } assert_called_with @session, :process, [:get, path, params: params, headers: headers, env: env] do @session.get(path, params: params, headers: headers, env: env) end end - def test_deprecated_get - path = "/index"; params = "blah"; headers = { location: 'blah' } - - assert_called_with @session, :process, [:get, path, params: params, headers: headers] do - assert_deprecated { - @session.get(path, params, headers) - } - end - end - def test_post - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:post, path, params: params, headers: headers] do - assert_deprecated { - @session.post(path, params, headers) - } - end - end - - def test_deprecated_post - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:post, path, params: params, headers: headers] do @session.post(path, params: params, headers: headers) end end def test_patch - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:patch, path, params: params, headers: headers] do @session.patch(path, params: params, headers: headers) end end - def test_deprecated_patch - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:patch, path, params: params, headers: headers] do - assert_deprecated { - @session.patch(path, params, headers) - } - end - end - def test_put - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:put, path, params: params, headers: headers] do @session.put(path, params: params, headers: headers) end end - def test_deprecated_put - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:put, path, params: params, headers: headers] do - assert_deprecated { - @session.put(path, params, headers) - } - end - end - def test_delete - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:delete, path, params: params, headers: headers] do - assert_deprecated { - @session.delete(path,params,headers) - } - end - end - - def test_deprecated_delete - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:delete, path, params: params, headers: headers] do @session.delete(path, params: params, headers: headers) end end def test_head - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:head, path, params: params, headers: headers] do @session.head(path, params: params, headers: headers) end end - def deprecated_test_head - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:head, path, params: params, headers: headers] do - assert_deprecated { - @session.head(path, params, headers) - } - end - end - def test_xml_http_request_get - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:get, path, params: params, headers: headers, xhr: true] do - @session.get(path, params: params, headers: headers, xhr: true) - end - end - - def test_deprecated_xml_http_request_get - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:get, path, params: params, headers: headers, xhr: true] do @session.get(path, params: params, headers: headers, xhr: true) end end - def test_deprecated_args_xml_http_request_get - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:get, path, params: params, headers: headers, xhr: true] do - assert_deprecated(/xml_http_request/) { - @session.xml_http_request(:get, path, params, headers) - } - end - end - def test_xml_http_request_post - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:post, path, params: params, headers: headers, xhr: true] do @session.post(path, params: params, headers: headers, xhr: true) end end - def test_deprecated_xml_http_request_post - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:post, path, params: params, headers: headers, xhr: true] do - @session.post(path, params: params, headers: headers, xhr: true) - end - end - - def test_deprecated_args_xml_http_request_post - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:post, path, params: params, headers: headers, xhr: true] do - assert_deprecated(/xml_http_request/) { @session.xml_http_request(:post,path,params,headers) } - end - end - def test_xml_http_request_patch - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:patch, path, params: params, headers: headers, xhr: true] do - @session.patch(path, params: params, headers: headers, xhr: true) - end - end - - def test_deprecated_xml_http_request_patch - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:patch, path, params: params, headers: headers, xhr: true] do @session.patch(path, params: params, headers: headers, xhr: true) end end - def test_deprecated_args_xml_http_request_patch - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:patch, path, params: params, headers: headers, xhr: true] do - assert_deprecated(/xml_http_request/) { @session.xml_http_request(:patch,path,params,headers) } - end - end - def test_xml_http_request_put - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:put, path, params: params, headers: headers, xhr: true] do - @session.put(path, params: params, headers: headers, xhr: true) - end - end - - def test_deprecated_xml_http_request_put - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:put, path, params: params, headers: headers, xhr: true] do @session.put(path, params: params, headers: headers, xhr: true) end end - def test_deprecated_args_xml_http_request_put - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:put, path, params: params, headers: headers, xhr: true] do - assert_deprecated(/xml_http_request/) { @session.xml_http_request(:put, path, params, headers) } - end - end - def test_xml_http_request_delete - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:delete, path, params: params, headers: headers, xhr: true] do @session.delete(path, params: params, headers: headers, xhr: true) end end - def test_deprecated_xml_http_request_delete - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:delete, path, params: params, headers: headers, xhr: true] do - assert_deprecated { @session.xml_http_request(:delete, path, params: params, headers: headers) } - end - end - - def test_deprecated_args_xml_http_request_delete - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:delete, path, params: params, headers: headers, xhr: true] do - assert_deprecated(/xml_http_request/) { @session.xml_http_request(:delete, path, params, headers) } - end - end - def test_xml_http_request_head - path = "/index"; params = "blah"; headers = { location: 'blah' } + path = "/index"; params = "blah"; headers = { location: "blah" } assert_called_with @session, :process, [:head, path, params: params, headers: headers, xhr: true] do @session.head(path, params: params, headers: headers, xhr: true) end end - - def test_deprecated_xml_http_request_head - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:head, path, params: params, headers: headers, xhr: true] do - assert_deprecated(/xml_http_request/) { @session.xml_http_request(:head, path, params: params, headers: headers) } - end - end - - def test_deprecated_args_xml_http_request_head - path = "/index"; params = "blah"; headers = { location: 'blah' } - assert_called_with @session, :process, [:head, path, params: params, headers: headers, xhr: true] do - assert_deprecated { @session.xml_http_request(:head, path, params, headers) } - end - end end class IntegrationTestTest < ActiveSupport::TestCase @@ -372,12 +142,12 @@ class IntegrationTestTest < ActiveSupport::TestCase def test_does_not_prevent_method_missing_passing_up_to_ancestors mixin = Module.new do def method_missing(name, *args) - name.to_s == 'foo' ? 'pass' : super + name.to_s == "foo" ? "pass" : super end end @test.class.superclass.__send__(:include, mixin) begin - assert_equal 'pass', @test.foo + assert_equal "pass", @test.foo ensure # leave other tests as unaffected as possible mixin.__send__(:remove_method, :method_missing) @@ -392,7 +162,7 @@ class IntegrationTestUsesCorrectClass < ActionDispatch::IntegrationTest reset! %w( get post head patch put delete ).each do |verb| - assert_nothing_raised { __send__(verb, '/') } + assert_nothing_raised { __send__(verb, "/") } end end end @@ -403,9 +173,10 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest respond_to do |format| format.html { render plain: "OK", status: 200 } format.js { render plain: "JS OK", status: 200 } - format.xml { render :xml => "<root></root>", :status => 200 } - format.rss { render :xml => "<root></root>", :status => 200 } - format.atom { render :xml => "<root></root>", :status => 200 } + format.json { render json: "JSON OK", status: 200 } + format.xml { render xml: "<root></root>", status: 200 } + format.rss { render xml: "<root></root>", status: 200 } + format.atom { render xml: "<root></root>", status: 200 } end end @@ -428,7 +199,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest end def set_cookie - cookies["foo"] = 'bar' + cookies["foo"] = "bar" head :ok end @@ -437,18 +208,18 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest end def redirect - redirect_to action_url('get') + redirect_to action_url("get") end def remove_header response.headers.delete params[:header] - head :ok, 'c' => '3' + head :ok, "c" => "3" end end def test_get with_test_route_set do - get '/get' + get "/get" assert_equal 200, status assert_equal "OK", status_message assert_response 200 @@ -465,7 +236,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_get_xml_rss_atom %w[ application/xml application/rss+xml application/atom+xml ].each do |mime_string| with_test_route_set do - get "/get", headers: {"HTTP_ACCEPT" => mime_string} + get "/get", headers: { "HTTP_ACCEPT" => mime_string } assert_equal 200, status assert_equal "OK", status_message assert_response 200 @@ -482,7 +253,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_post with_test_route_set do - post '/post' + post "/post" assert_equal 201, status assert_equal "Created", status_message assert_response 201 @@ -496,55 +267,55 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest end end - test 'response cookies are added to the cookie jar for the next request' do + test "response cookies are added to the cookie jar for the next request" do with_test_route_set do - self.cookies['cookie_1'] = "sugar" - self.cookies['cookie_2'] = "oatmeal" - get '/cookie_monster' + self.cookies["cookie_1"] = "sugar" + self.cookies["cookie_2"] = "oatmeal" + get "/cookie_monster" assert_equal "cookie_1=; path=/\ncookie_3=chocolate; path=/", headers["Set-Cookie"] - assert_equal({"cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate"}, cookies.to_hash) + assert_equal({ "cookie_1"=>"", "cookie_2"=>"oatmeal", "cookie_3"=>"chocolate" }, cookies.to_hash) end end - test 'cookie persist to next request' do + test "cookie persist to next request" do with_test_route_set do - get '/set_cookie' + get "/set_cookie" assert_response :success assert_equal "foo=bar; path=/", headers["Set-Cookie"] - assert_equal({"foo"=>"bar"}, cookies.to_hash) + assert_equal({ "foo"=>"bar" }, cookies.to_hash) - get '/get_cookie' + get "/get_cookie" assert_response :success assert_equal "bar", body assert_equal nil, headers["Set-Cookie"] - assert_equal({"foo"=>"bar"}, cookies.to_hash) + assert_equal({ "foo"=>"bar" }, cookies.to_hash) end end - test 'cookie persist to next request on another domain' do + test "cookie persist to next request on another domain" do with_test_route_set do host! "37s.backpack.test" - get '/set_cookie' + get "/set_cookie" assert_response :success assert_equal "foo=bar; path=/", headers["Set-Cookie"] - assert_equal({"foo"=>"bar"}, cookies.to_hash) + assert_equal({ "foo"=>"bar" }, cookies.to_hash) - get '/get_cookie' + get "/get_cookie" assert_response :success assert_equal "bar", body assert_equal nil, headers["Set-Cookie"] - assert_equal({"foo"=>"bar"}, cookies.to_hash) + assert_equal({ "foo"=>"bar" }, cookies.to_hash) end end def test_redirect with_test_route_set do - get '/redirect' + get "/redirect" assert_equal 302, status assert_equal "Found", status_message assert_response 302 @@ -558,27 +329,15 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest assert_response :success assert_equal "/get", path - get '/moved' + get "/moved" assert_response :redirect - assert_redirected_to '/method' + assert_redirected_to "/method" end end def test_xml_http_request_get with_test_route_set do - get '/get', xhr: true - assert_equal 200, status - assert_equal "OK", status_message - assert_response 200 - assert_response :success - assert_response :ok - assert_equal "JS OK", response.body - end - end - - def test_deprecated_xml_http_request_get - with_test_route_set do - assert_deprecated { xhr :get, '/get' } + get "/get", xhr: true assert_equal 200, status assert_equal "OK", status_message assert_response 200 @@ -590,7 +349,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_request_with_bad_format with_test_route_set do - get '/get.php', xhr: true + get "/get.php", xhr: true assert_equal 406, status assert_response 406 assert_response :not_acceptable @@ -599,12 +358,12 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_get_with_query_string with_test_route_set do - get '/get_with_params?foo=bar' - assert_equal '/get_with_params?foo=bar', request.env["REQUEST_URI"] - assert_equal '/get_with_params?foo=bar', request.fullpath + get "/get_with_params?foo=bar" + assert_equal "/get_with_params?foo=bar", request.env["REQUEST_URI"] + assert_equal "/get_with_params?foo=bar", request.fullpath assert_equal "foo=bar", request.env["QUERY_STRING"] - assert_equal 'foo=bar', request.query_string - assert_equal 'bar', request.parameters['foo'] + assert_equal "foo=bar", request.query_string + assert_equal "bar", request.parameters["foo"] assert_equal 200, status assert_equal "foo: bar", response.body @@ -613,77 +372,91 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_get_with_parameters with_test_route_set do - get '/get_with_params', params: { foo: "bar" } - assert_equal '/get_with_params', request.env["PATH_INFO"] - assert_equal '/get_with_params', request.path_info - assert_equal 'foo=bar', request.env["QUERY_STRING"] - assert_equal 'foo=bar', request.query_string - assert_equal 'bar', request.parameters['foo'] + get "/get_with_params", params: { foo: "bar" } + assert_equal "/get_with_params", request.env["PATH_INFO"] + assert_equal "/get_with_params", request.path_info + assert_equal "foo=bar", request.env["QUERY_STRING"] + assert_equal "foo=bar", request.query_string + assert_equal "bar", request.parameters["foo"] assert_equal 200, status assert_equal "foo: bar", response.body end end + def test_post_then_get_with_parameters_do_not_leak_across_requests + with_test_route_set do + post "/post", params: { leaks: "does-leak?" } + + get "/get_with_params", params: { foo: "bar" } + + assert request.env["rack.input"].string.empty? + assert_equal "foo=bar", request.env["QUERY_STRING"] + assert_equal "foo=bar", request.query_string + assert_equal "bar", request.parameters["foo"] + assert request.parameters["leaks"].nil? + end + end + def test_head with_test_route_set do - head '/get' + head "/get" assert_equal 200, status assert_equal "", body - head '/post' + head "/post" assert_equal 201, status assert_equal "", body - get '/get/method' + get "/get/method" assert_equal 200, status assert_equal "method: get", body - head '/get/method' + head "/get/method" assert_equal 200, status assert_equal "", body end end def test_generate_url_with_controller - assert_equal 'http://www.example.com/foo', url_for(:controller => "foo") + assert_equal "http://www.example.com/foo", url_for(controller: "foo") end def test_port_via_host! with_test_route_set do - host! 'www.example.com:8080' - get '/get' + host! "www.example.com:8080" + get "/get" assert_equal 8080, request.port end end def test_port_via_process with_test_route_set do - get 'http://www.example.com:8080/get' + get "http://www.example.com:8080/get" assert_equal 8080, request.port end end def test_https_and_port_via_host_and_https! with_test_route_set do - host! 'www.example.com' + host! "www.example.com" https! true - get '/get' + get "/get" assert_equal 443, request.port assert_equal true, request.ssl? - host! 'www.example.com:443' + host! "www.example.com:443" https! true - get '/get' + get "/get" assert_equal 443, request.port assert_equal true, request.ssl? - host! 'www.example.com:8443' + host! "www.example.com:8443" https! true - get '/get' + get "/get" assert_equal 8443, request.port assert_equal true, request.ssl? end @@ -691,11 +464,11 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_https_and_port_via_process with_test_route_set do - get 'https://www.example.com/get' + get "https://www.example.com/get" assert_equal 443, request.port assert_equal true, request.ssl? - get 'https://www.example.com:8443/get' + get "https://www.example.com:8443/get" assert_equal 8443, request.port assert_equal true, request.ssl? end @@ -703,14 +476,26 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest def test_respect_removal_of_default_headers_by_a_controller_action with_test_route_set do - with_default_headers 'a' => '1', 'b' => '2' do - get '/remove_header', params: { header: 'a' } + with_default_headers "a" => "1", "b" => "2" do + get "/remove_header", params: { header: "a" } end end - assert_not_includes @response.headers, 'a', 'Response should not include default header removed by the controller action' - assert_includes @response.headers, 'b' - assert_includes @response.headers, 'c' + assert_not_includes @response.headers, "a", "Response should not include default header removed by the controller action" + assert_includes @response.headers, "b" + assert_includes @response.headers, "c" + end + + def test_accept_not_overriden_when_xhr_true + with_test_route_set do + get "/get", headers: { "Accept" => "application/json" }, xhr: true + assert_equal "application/json", request.accept + assert_equal "application/json", response.content_type + + get "/get", headers: { "HTTP_ACCEPT" => "application/json" }, xhr: true + assert_equal "application/json", request.accept + assert_equal "application/json", response.content_type + end end private @@ -730,15 +515,15 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest end set.draw do - get 'moved' => redirect('/method') + get "moved" => redirect("/method") ActiveSupport::Deprecation.silence do - match ':action', :to => controller, :via => [:get, :post], :as => :action - get 'get/:action', :to => controller, :as => :get_action + match ":action", to: controller, via: [:get, :post], as: :action + get "get/:action", to: controller, as: :get_action end end - self.singleton_class.include(set.url_helpers) + singleton_class.include(set.url_helpers) yield end @@ -751,9 +536,9 @@ class MetalIntegrationTest < ActionDispatch::IntegrationTest class Poller def self.call(env) if env["PATH_INFO"] =~ /^\/success/ - [200, {"Content-Type" => "text/plain", "Content-Length" => "12"}, ["Hello World!"]] + [200, { "Content-Type" => "text/plain", "Content-Length" => "12" }, ["Hello World!"]] else - [404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []] + [404, { "Content-Type" => "text/plain", "Content-Length" => "0" }, []] end end end @@ -774,15 +559,15 @@ class MetalIntegrationTest < ActionDispatch::IntegrationTest get "/failure" assert_response 404 assert_response :not_found - assert_equal '', response.body + assert_equal "", response.body end def test_generate_url_without_controller - assert_equal 'http://www.example.com/foo', url_for(:controller => "foo") + assert_equal "http://www.example.com/foo", url_for(controller: "foo") end def test_pass_headers - get "/success", headers: {"Referer" => "http://www.example.com/foo", "Host" => "http://nohost.com"} + get "/success", headers: { "Referer" => "http://www.example.com/foo", "Host" => "http://nohost.com" } assert_equal "http://nohost.com", @request.env["HTTP_HOST"] assert_equal "http://www.example.com/foo", @request.env["HTTP_REFERER"] @@ -821,7 +606,6 @@ class MetalIntegrationTest < ActionDispatch::IntegrationTest get "https://test.com:80" assert_equal "test.com:80", @request.env["HTTP_HOST"] end - end class ApplicationIntegrationTest < ActionDispatch::IntegrationTest @@ -845,7 +629,7 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest end routes.draw do - get 'baz', :to => 'application_integration_test/test#index', :as => :baz + get "baz", to: "application_integration_test/test#index", as: :baz end def self.call(*) @@ -853,14 +637,14 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest end routes.draw do - get '', :to => 'application_integration_test/test#index', :as => :empty_string + get "", to: "application_integration_test/test#index", as: :empty_string - get 'foo', :to => 'application_integration_test/test#index', :as => :foo - get 'bar', :to => 'application_integration_test/test#index', :as => :bar + get "foo", to: "application_integration_test/test#index", as: :foo + get "bar", to: "application_integration_test/test#index", as: :bar - mount MountedApp => '/mounted', :as => "mounted" - get 'fooz' => proc { |env| [ 200, {'X-Cascade' => 'pass'}, [ "omg" ] ] }, :anchor => false - get 'fooz', :to => 'application_integration_test/test#index' + mount MountedApp => "/mounted", :as => "mounted" + get "fooz" => proc { |env| [ 200, { "X-Cascade" => "pass" }, [ "omg" ] ] }, :anchor => false + get "fooz", to: "application_integration_test/test#index" end def app @@ -868,30 +652,30 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest end test "includes route helpers" do - assert_equal '/', empty_string_path - assert_equal '/foo', foo_path - assert_equal '/bar', bar_path + assert_equal "/", empty_string_path + assert_equal "/foo", foo_path + assert_equal "/bar", bar_path end test "includes mounted helpers" do - assert_equal '/mounted/baz', mounted.baz_path + assert_equal "/mounted/baz", mounted.baz_path end test "path after cascade pass" do - get '/fooz' - assert_equal 'index', response.body - assert_equal '/fooz', path + get "/fooz" + assert_equal "index", response.body + assert_equal "/fooz", path end test "route helpers after controller access" do - get '/' - assert_equal '/', empty_string_path + get "/" + assert_equal "/", empty_string_path - get '/foo' - assert_equal '/foo', foo_path + get "/foo" + assert_equal "/foo", foo_path - get '/bar' - assert_equal '/bar', bar_path + get "/bar" + assert_equal "/bar", bar_path end test "missing route helper before controller access" do @@ -899,14 +683,14 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest end test "missing route helper after controller access" do - get '/foo' + get "/foo" assert_raise(NameError) { missing_path } end test "process do not modify the env passed as argument" do - env = { :SERVER_NAME => 'server', 'action_dispatch.custom' => 'custom' } + env = { :SERVER_NAME => "server", "action_dispatch.custom" => "custom" } old_env = env.dup - get '/foo', env: env + get "/foo", env: env assert_equal old_env, env end end @@ -928,7 +712,7 @@ class EnvironmentFilterIntegrationTest < ActionDispatch::IntegrationTest end routes.draw do - match '/post', :to => 'environment_filter_integration_test/test#post', :via => :post + match "/post", to: "environment_filter_integration_test/test#post", via: :post end def app @@ -936,11 +720,11 @@ class EnvironmentFilterIntegrationTest < ActionDispatch::IntegrationTest end test "filters rack request form vars" do - post "/post", params: { username: 'cjolly', password: 'secret' } + post "/post", params: { username: "cjolly", password: "secret" } - assert_equal 'cjolly', request.filtered_parameters['username'] - assert_equal '[FILTERED]', request.filtered_parameters['password'] - assert_equal '[FILTERED]', request.filtered_env['rack.request.form_vars'] + assert_equal "cjolly", request.filtered_parameters["username"] + assert_equal "[FILTERED]", request.filtered_parameters["password"] + assert_equal "[FILTERED]", request.filtered_env["rack.request.form_vars"] end end @@ -961,7 +745,7 @@ class UrlOptionsIntegrationTest < ActionDispatch::IntegrationTest class BarController < ActionController::Base def default_url_options - { :host => "bar.com" } + { host: "bar.com" } end def index @@ -982,9 +766,9 @@ class UrlOptionsIntegrationTest < ActionDispatch::IntegrationTest end routes.draw do - default_url_options :host => "foo.com" + default_url_options host: "foo.com" - scope :module => "url_options_integration_test" do + scope module: "url_options_integration_test" do get "/foo" => "foo#index", :as => :foos get "/foo/:id" => "foo#show", :as => :foo get "/foo/:id/edit" => "foo#edit", :as => :edit_foo @@ -1024,7 +808,7 @@ class UrlOptionsIntegrationTest < ActionDispatch::IntegrationTest test "current request path parameters are recalled" do get "/foo/1" assert_response :success - assert_equal "/foo/1/edit", url_for(:action => 'edit', :only_path => true) + assert_equal "/foo/1/edit", url_for(action: "edit", only_path: true) end end @@ -1048,12 +832,12 @@ class HeadWithStatusActionIntegrationTest < ActionDispatch::IntegrationTest end routes.draw do - get "/foo/status" => 'head_with_status_action_integration_test/foo#status' + get "/foo/status" => "head_with_status_action_integration_test/foo#status" end test "get /foo/status with head result does not cause stack overflow error" do assert_nothing_raised do - get '/foo/status' + get "/foo/status" end assert_response :ok end @@ -1062,7 +846,7 @@ end class IntegrationWithRoutingTest < ActionDispatch::IntegrationTest class FooController < ActionController::Base def index - render plain: 'ok' + render plain: "ok" end end @@ -1072,25 +856,25 @@ class IntegrationWithRoutingTest < ActionDispatch::IntegrationTest with_routing do |routes| routes.draw do namespace klass_namespace do - resources :foo, path: '/with' + resources :foo, path: "/with" end end - get '/integration_with_routing_test/with' + get "/integration_with_routing_test/with" assert_response 200 - assert_equal 'ok', response.body + assert_equal "ok", response.body end with_routing do |routes| routes.draw do namespace klass_namespace do - resources :foo, path: '/routing' + resources :foo, path: "/routing" end end - get '/integration_with_routing_test/routing' + get "/integration_with_routing_test/routing" assert_response 200 - assert_equal 'ok', response.body + assert_equal "ok", response.body end end end @@ -1102,8 +886,8 @@ class IntegrationRequestsWithoutSetup < ActionDispatch::IntegrationTest class FooController < ActionController::Base def ok - cookies[:key] = 'ok' - render plain: 'ok' + cookies[:key] = "ok" + render plain: "ok" end end @@ -1111,15 +895,15 @@ class IntegrationRequestsWithoutSetup < ActionDispatch::IntegrationTest with_routing do |routes| routes.draw do ActiveSupport::Deprecation.silence do - get ':action' => FooController + get ":action" => FooController end end - get '/ok' + get "/ok" assert_response 200 - assert_equal 'ok', response.body - assert_equal 'ok', cookies['key'] + assert_equal "ok", response.body + assert_equal "ok", cookies["key"] end end end @@ -1127,12 +911,12 @@ end # to ensure that session requirements in setup are persisted in the tests class IntegrationRequestsWithSessionSetup < ActionDispatch::IntegrationTest setup do - cookies['user_name'] = 'david' + cookies["user_name"] = "david" end def test_cookies_set_in_setup_are_persisted_through_the_session get "/foo" - assert_equal({"user_name"=>"david"}, cookies.to_hash) + assert_equal({ "user_name"=>"david" }, cookies.to_hash) end end @@ -1143,7 +927,7 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest end def foos_wibble - render plain: 'ok' + render plain: "ok" end end @@ -1151,25 +935,25 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest with_routing do |routes| routes.draw do ActiveSupport::Deprecation.silence do - post ':action' => FooController + post ":action" => FooController end end - post '/foos_json.json', params: { foo: 'fighters' }.to_json, - headers: { 'Content-Type' => 'application/json' } + post "/foos_json.json", params: { foo: "fighters" }.to_json, + headers: { "Content-Type" => "application/json" } assert_response :success - assert_equal({ 'foo' => 'fighters' }, response.parsed_body) + assert_equal({ "foo" => "fighters" }, response.parsed_body) end end def test_encoding_as_json post_to_foos as: :json do assert_response :success - assert_match 'foos_json.json', request.path - assert_equal 'application/json', request.content_type - assert_equal({ 'foo' => 'fighters' }, request.request_parameters) - assert_equal({ 'foo' => 'fighters' }, response.parsed_body) + assert_match "foos_json.json", request.path + assert_equal "application/json", request.content_type + assert_equal({ "foo" => "fighters" }, request.request_parameters) + assert_equal({ "foo" => "fighters" }, response.parsed_body) end end @@ -1180,17 +964,17 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest end def test_registering_custom_encoder - Mime::Type.register 'text/wibble', :wibble + Mime::Type.register "text/wibble", :wibble ActionDispatch::IntegrationTest.register_encoder(:wibble, param_encoder: -> params { params }) post_to_foos as: :wibble do assert_response :success - assert_match 'foos_wibble.wibble', request.path - assert_equal 'text/wibble', request.content_type + assert_match "foos_wibble.wibble", request.path + assert_equal "text/wibble", request.content_type assert_equal Hash.new, request.request_parameters # Unregistered MIME Type can't be parsed. - assert_equal 'ok', response.parsed_body + assert_equal "ok", response.parsed_body end ensure Mime::Type.unregister :wibble @@ -1200,13 +984,43 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest with_routing do |routes| routes.draw do ActiveSupport::Deprecation.silence do - get ':action' => FooController + get ":action" => FooController end end - get '/foos_json.json', params: { foo: 'heyo' } + get "/foos_json.json", params: { foo: "heyo" } - assert_equal({ 'foo' => 'heyo' }, response.parsed_body) + assert_equal({ "foo" => "heyo" }, response.parsed_body) + end + end + + def test_get_parameters_with_as_option + with_routing do |routes| + routes.draw do + ActiveSupport::Deprecation.silence do + get ":action" => FooController + end + end + + get "/foos_json?foo=heyo", as: :json + + assert_equal({ "foo" => "heyo" }, response.parsed_body) + end + end + + def test_get_request_with_json_uses_method_override_and_sends_a_post_request + with_routing do |routes| + routes.draw do + ActiveSupport::Deprecation.silence do + get ":action" => FooController + end + end + + get "/foos_json", params: { foo: "heyo" }, as: :json + + assert_equal "POST", request.method + assert_equal "GET", request.headers["X-Http-Method-Override"] + assert_equal({ "foo" => "heyo" }, response.parsed_body) end end @@ -1215,13 +1029,49 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest with_routing do |routes| routes.draw do ActiveSupport::Deprecation.silence do - post ':action' => FooController + post ":action" => FooController end end - post "/foos_#{as}", params: { foo: 'fighters' }, as: as + post "/foos_#{as}", params: { foo: "fighters" }, as: as yield end end end + +class IntegrationFileUploadTest < ActionDispatch::IntegrationTest + class IntegrationController < ActionController::Base + def test_file_upload + render plain: params[:file].size + end + end + + def self.routes + @routes ||= ActionDispatch::Routing::RouteSet.new + end + + def self.call(env) + routes.call(env) + end + + def app + self.class + end + + def self.fixture_path + File.dirname(__FILE__) + "/../fixtures/multipart" + end + + routes.draw do + post "test_file_upload", to: "integration_file_upload_test/integration#test_file_upload" + end + + def test_fixture_file_upload + post "/test_file_upload", + params: { + file: fixture_file_upload("/ruby_on_rails.jpg", "image/jpg") + } + assert_equal "45142", @response.body + end +end diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb index 5977124594..e76628b936 100644 --- a/actionpack/test/controller/live_stream_test.rb +++ b/actionpack/test/controller/live_stream_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'concurrent/atomic/count_down_latch' +require "abstract_unit" +require "concurrent/atomic/count_down_latch" Thread.abort_on_exception = true module ActionController @@ -8,10 +8,10 @@ module ActionController include ActionController::Live def basic_sse - response.headers['Content-Type'] = 'text/event-stream' + response.headers["Content-Type"] = "text/event-stream" sse = SSE.new(response.stream) sse.write("{\"name\":\"John\"}") - sse.write({ name: "Ryan" }) + sse.write(name: "Ryan") ensure sse.close end @@ -19,7 +19,7 @@ module ActionController def sse_with_event sse = SSE.new(response.stream, event: "send-name") sse.write("{\"name\":\"John\"}") - sse.write({ name: "Ryan" }) + sse.write(name: "Ryan") ensure sse.close end @@ -115,7 +115,7 @@ module ActionController attr_accessor :latch, :tc, :error_latch def self.controller_path - 'test' + "test" end def set_cookie @@ -125,7 +125,7 @@ module ActionController end def render_text - render plain: 'zomg' + render plain: "zomg" end def default_header @@ -134,7 +134,7 @@ module ActionController end def basic_stream - response.headers['Content-Type'] = 'text/event-stream' + response.headers["Content-Type"] = "text/event-stream" %w{ hello world }.each do |word| response.stream.write word end @@ -142,7 +142,7 @@ module ActionController end def blocking_stream - response.headers['Content-Type'] = 'text/event-stream' + response.headers["Content-Type"] = "text/event-stream" %w{ hello world }.each do |word| response.stream.write word latch.wait @@ -150,10 +150,26 @@ module ActionController response.stream.close end + def write_sleep_autoload + path = File.join(File.dirname(__FILE__), "../fixtures") + ActiveSupport::Dependencies.autoload_paths << path + + response.headers["Content-Type"] = "text/event-stream" + response.stream.write "before load" + sleep 0.01 + silence_warning do + ::LoadMe + end + response.stream.close + latch.count_down + + ActiveSupport::Dependencies.autoload_paths.reject! { |p| p == path } + end + def thread_locals - tc.assert_equal 'aaron', Thread.current[:setting] + tc.assert_equal "aaron", Thread.current[:setting] - response.headers['Content-Type'] = 'text/event-stream' + response.headers["Content-Type"] = "text/event-stream" %w{ hello world }.each do |word| response.stream.write word end @@ -161,20 +177,20 @@ module ActionController end def with_stale - render plain: 'stale' if stale?(etag: "123", template: false) + render plain: "stale" if stale?(etag: "123", template: false) end def exception_in_view - render 'doesntexist' + render "doesntexist" end def exception_in_view_after_commit response.stream.write "" - render 'doesntexist' + render "doesntexist" end def exception_with_callback - response.headers['Content-Type'] = 'text/event-stream' + response.headers["Content-Type"] = "text/event-stream" response.stream.on_error do response.stream.write %(data: "500 Internal Server Error"\n\n) @@ -182,11 +198,11 @@ module ActionController end response.stream.write "" # make sure the response is committed - raise 'An exception occurred...' + raise "An exception occurred..." end def exception_in_controller - raise Exception, 'Exception in controller' + raise Exception, "Exception in controller" end def bad_request_error @@ -194,50 +210,50 @@ module ActionController end def exception_in_exception_callback - response.headers['Content-Type'] = 'text/event-stream' + response.headers["Content-Type"] = "text/event-stream" response.stream.on_error do - raise 'We need to go deeper.' + raise "We need to go deeper." end - response.stream.write '' + response.stream.write "" response.stream.write params[:widget][:didnt_check_for_nil] end def overfill_buffer_and_die logger = ActionController::Base.logger || Logger.new($stdout) response.stream.on_error do - logger.warn 'Error while streaming.' + logger.warn "Error while streaming." error_latch.count_down end # Write until the buffer is full. It doesn't expose that # information directly, so we must hard-code its size: 10.times do - response.stream.write '.' + response.stream.write "." end # .. plus one more, because the #each frees up a slot: - response.stream.write '.' + response.stream.write "." latch.count_down # This write will block, and eventually raise - response.stream.write 'x' + response.stream.write "x" 20.times do - response.stream.write '.' + response.stream.write "." end end def ignore_client_disconnect response.stream.ignore_disconnect = true - response.stream.write '' # commit + response.stream.write "" # commit # These writes will be ignored 15.times do - response.stream.write 'x' + response.stream.write "x" end - logger.info 'Work complete' + logger.info "Work complete" latch.count_down end end @@ -245,9 +261,9 @@ module ActionController tests TestController def assert_stream_closed - assert response.stream.closed?, 'stream should be closed' - assert response.committed?, 'response should be committed' - assert response.sent?, 'response should be sent' + assert response.stream.closed?, "stream should be closed" + assert response.committed?, "response should be committed" + assert response.sent?, "response should be sent" end def capture_log_output @@ -271,21 +287,29 @@ module ActionController def test_set_cookie get :set_cookie - assert_equal({'hello' => 'world'}, @response.cookies) + assert_equal({ "hello" => "world" }, @response.cookies) assert_equal "hello world", @response.body end def test_write_to_stream get :basic_stream assert_equal "helloworld", @response.body - assert_equal 'text/event-stream', @response.headers['Content-Type'] + assert_equal "text/event-stream", @response.headers["Content-Type"] + end + + def test_delayed_autoload_after_write_within_interlock_hook + # Simulate InterlockHook + ActiveSupport::Dependencies.interlock.start_running + res = get :write_sleep_autoload + res.each {} + ActiveSupport::Dependencies.interlock.done_running end def test_async_stream rubinius_skip "https://github.com/rubinius/rubinius/issues/2934" @controller.latch = Concurrent::CountDownLatch.new - parts = ['hello', 'world'] + parts = ["hello", "world"] get :blocking_stream @@ -299,7 +323,7 @@ module ActionController end } - assert t.join(3), 'timeout expired before the thread terminated' + assert t.join(3), "timeout expired before the thread terminated" end def test_abort_with_full_buffer @@ -307,7 +331,7 @@ module ActionController @controller.error_latch = Concurrent::CountDownLatch.new capture_log_output do |output| - get :overfill_buffer_and_die, :format => 'plain' + get :overfill_buffer_and_die, format: "plain" t = Thread.new(response) { |resp| resp.await_commit @@ -321,7 +345,7 @@ module ActionController t.join @controller.error_latch.wait - assert_match 'Error while streaming', output.rewind && output.read + assert_match "Error while streaming", output.rewind && output.read end end @@ -344,26 +368,26 @@ module ActionController Timeout.timeout(3) do @controller.latch.wait end - assert_match 'Work complete', output.rewind && output.read + assert_match "Work complete", output.rewind && output.read end end def test_thread_locals_get_copied @controller.tc = self Thread.current[:originating_thread] = Thread.current.object_id - Thread.current[:setting] = 'aaron' + Thread.current[:setting] = "aaron" get :thread_locals end def test_live_stream_default_header get :default_header - assert response.headers['Content-Type'] + assert response.headers["Content-Type"] end def test_render_text get :render_text - assert_equal 'zomg', response.body + assert_equal "zomg", response.body assert_stream_closed end @@ -375,7 +399,7 @@ module ActionController capture_log_output do |output| get :exception_in_view_after_commit assert_match %r((window\.location = "/500\.html"</script></html>)$), response.body - assert_match 'Missing template test/doesntexist', output.rewind && output.read + assert_match "Missing template test/doesntexist", output.rewind && output.read assert_stream_closed end assert response.body @@ -389,8 +413,8 @@ module ActionController capture_log_output do |output| get :exception_in_view_after_commit, format: :json - assert_equal '', response.body - assert_match 'Missing template test/doesntexist', output.rewind && output.read + assert_equal "", response.body + assert_match "Missing template test/doesntexist", output.rewind && output.read assert_stream_closed end end @@ -399,34 +423,34 @@ module ActionController current_threads = Thread.list capture_log_output do |output| - get :exception_with_callback, format: 'text/event-stream' + get :exception_with_callback, format: "text/event-stream" # Wait on the execution of all threads (Thread.list - current_threads).each(&:join) assert_equal %(data: "500 Internal Server Error"\n\n), response.body - assert_match 'An exception occurred...', output.rewind && output.read + assert_match "An exception occurred...", output.rewind && output.read assert_stream_closed end end def test_exception_in_controller_before_streaming assert_raises(ActionController::LiveStreamTest::Exception) do - get :exception_in_controller, format: 'text/event-stream' + get :exception_in_controller, format: "text/event-stream" end end def test_bad_request_in_controller_before_streaming assert_raises(ActionController::BadRequest) do - get :bad_request_error, format: 'text/event-stream' + get :bad_request_error, format: "text/event-stream" end end def test_exceptions_raised_handling_exceptions_and_committed capture_log_output do |output| - get :exception_in_exception_callback, format: 'text/event-stream' - assert_equal '', response.body - assert_match 'We need to go deeper', output.rewind && output.read + get :exception_in_exception_callback, format: "text/event-stream" + assert_equal "", response.body + assert_match "We need to go deeper", output.rewind && output.read assert_stream_closed end end @@ -456,10 +480,10 @@ class LiveStreamRouterTest < ActionDispatch::IntegrationTest include ActionController::Live def index - response.headers['Content-Type'] = 'text/event-stream' + response.headers["Content-Type"] = "text/event-stream" sse = SSE.new(response.stream) sse.write("{\"name\":\"John\"}") - sse.write({ name: "Ryan" }) + sse.write(name: "Ryan") ensure sse.close end @@ -474,7 +498,7 @@ class LiveStreamRouterTest < ActionDispatch::IntegrationTest end routes.draw do - get '/test' => 'live_stream_router_test/test#index' + get "/test" => "live_stream_router_test/test#index" end def app diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb index 3576015513..0f2242b693 100644 --- a/actionpack/test/controller/localized_templates_test.rb +++ b/actionpack/test/controller/localized_templates_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class LocalizedController < ActionController::Base def hello_world diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb index 57cf2dafdf..45a120acb6 100644 --- a/actionpack/test/controller/log_subscriber_test.rb +++ b/actionpack/test/controller/log_subscriber_test.rb @@ -4,7 +4,7 @@ require "action_controller/log_subscriber" module Another class LogSubscribersController < ActionController::Base - wrap_parameters :person, :include => :name, :format => :json + wrap_parameters :person, include: :name, format: :json class SpecialException < Exception end @@ -31,7 +31,7 @@ module Another end def data_sender - send_data "cool data", :filename => "file.txt" + send_data "cool data", filename: "file.txt" end def file_sender @@ -39,27 +39,27 @@ module Another end def with_fragment_cache - render :inline => "<%= cache('foo'){ 'bar' } %>" + render inline: "<%= cache('foo'){ 'bar' } %>" end def with_fragment_cache_and_percent_in_key - render :inline => "<%= cache('foo%bar'){ 'Contains % sign in key' } %>" + render inline: "<%= cache('foo%bar'){ 'Contains % sign in key' } %>" end def with_fragment_cache_if_with_true_condition - render :inline => "<%= cache_if(true, 'foo') { 'bar' } %>" + render inline: "<%= cache_if(true, 'foo') { 'bar' } %>" end def with_fragment_cache_if_with_false_condition - render :inline => "<%= cache_if(false, 'foo') { 'bar' } %>" + render inline: "<%= cache_if(false, 'foo') { 'bar' } %>" end def with_fragment_cache_unless_with_false_condition - render :inline => "<%= cache_unless(false, 'foo') { 'bar' } %>" + render inline: "<%= cache_unless(false, 'foo') { 'bar' } %>" end def with_fragment_cache_unless_with_true_condition - render :inline => "<%= cache_unless(true, 'foo') { 'bar' } %>" + render inline: "<%= cache_unless(true, 'foo') { 'bar' } %>" end def with_exception @@ -92,10 +92,11 @@ class ACLogSubscriberTest < ActionController::TestCase def setup super + ActionController::Base.enable_fragment_cache_logging = true @old_logger = ActionController::Base.logger - @cache_path = File.join Dir.tmpdir, Dir::Tmpname.make_tmpname('tmp', 'cache') + @cache_path = File.join Dir.tmpdir, Dir::Tmpname.make_tmpname("tmp", "cache") @controller.cache_store = :file_store, @cache_path ActionController::LogSubscriber.attach_to :action_controller end @@ -105,6 +106,7 @@ class ACLogSubscriberTest < ActionController::TestCase ActiveSupport::LogSubscriber.log_subscribers.clear FileUtils.rm_rf(@cache_path) ActionController::Base.logger = @old_logger + ActionController::Base.enable_fragment_cache_logging = true end def set_logger(logger) @@ -136,11 +138,11 @@ class ACLogSubscriberTest < ActionController::TestCase def test_process_action_without_parameters get :show wait - assert_nil logs.detect {|l| l =~ /Parameters/ } + assert_nil logs.detect { |l| l =~ /Parameters/ } end def test_process_action_with_parameters - get :show, params: { id: '10' } + get :show, params: { id: "10" } wait assert_equal 3, logs.size @@ -148,8 +150,8 @@ class ACLogSubscriberTest < ActionController::TestCase end def test_multiple_process_with_parameters - get :show, params: { id: '10' } - get :show, params: { id: '20' } + get :show, params: { id: "10" } + get :show, params: { id: "20" } wait @@ -159,8 +161,8 @@ class ACLogSubscriberTest < ActionController::TestCase end def test_process_action_with_wrapped_parameters - @request.env['CONTENT_TYPE'] = 'application/json' - post :show, params: { id: '10', name: 'jose' } + @request.env["CONTENT_TYPE"] = "application/json" + post :show, params: { id: "10", name: "jose" } wait assert_equal 3, logs.size @@ -186,14 +188,14 @@ class ACLogSubscriberTest < ActionController::TestCase def test_process_action_headers get :show wait - assert_equal "Rails Testing", @controller.last_payload[:headers]['User-Agent'] + assert_equal "Rails Testing", @controller.last_payload[:headers]["User-Agent"] end def test_process_action_with_filter_parameters @request.env["action_dispatch.parameter_filter"] = [:lifo, :amount] get :show, params: { - lifo: 'Pratik', amount: '420', step: '1' + lifo: "Pratik", amount: "420", step: "1" } wait @@ -212,7 +214,7 @@ class ACLogSubscriberTest < ActionController::TestCase end def test_filter_redirect_url_by_string - @request.env['action_dispatch.redirect_filter'] = ['secret'] + @request.env["action_dispatch.redirect_filter"] = ["secret"] get :filterable_redirector wait @@ -221,7 +223,7 @@ class ACLogSubscriberTest < ActionController::TestCase end def test_filter_redirect_url_by_regexp - @request.env['action_dispatch.redirect_filter'] = [/secret\.foo.+/] + @request.env["action_dispatch.redirect_filter"] = [/secret\.foo.+/] get :filterable_redirector wait @@ -258,6 +260,20 @@ class ACLogSubscriberTest < ActionController::TestCase @controller.config.perform_caching = true end + def test_with_fragment_cache_when_log_disabled + @controller.config.perform_caching = true + ActionController::Base.enable_fragment_cache_logging = false + get :with_fragment_cache + wait + + assert_equal 2, logs.size + assert_equal "Processing by Another::LogSubscribersController#with_fragment_cache as HTML", logs[0] + assert_match(/Completed 200 OK in \d+ms/, logs[1]) + ensure + @controller.config.perform_caching = true + ActionController::Base.enable_fragment_cache_logging = true + end + def test_with_fragment_cache_if_with_true @controller.config.perform_caching = true get :with_fragment_cache_if_with_true_condition diff --git a/actionpack/test/controller/metal/renderers_test.rb b/actionpack/test/controller/metal/renderers_test.rb index 247e872674..7dc3dd6a6d 100644 --- a/actionpack/test/controller/metal/renderers_test.rb +++ b/actionpack/test/controller/metal/renderers_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash/conversions' +require "abstract_unit" +require "active_support/core_ext/hash/conversions" class MetalRenderingController < ActionController::Metal include AbstractController::Rendering @@ -10,11 +10,11 @@ end class MetalRenderingJsonController < MetalRenderingController class Model def to_json(options = {}) - { a: 'b' }.to_json(options) + { a: "b" }.to_json(options) end def to_xml(options = {}) - { a: 'b' }.to_xml(options) + { a: "b" }.to_xml(options) end end @@ -35,14 +35,14 @@ class RenderersMetalTest < ActionController::TestCase def test_render_json get :one assert_response :success - assert_equal({ a: 'b' }.to_json, @response.body) - assert_equal 'application/json', @response.content_type + assert_equal({ a: "b" }.to_json, @response.body) + assert_equal "application/json", @response.content_type end def test_render_xml get :two assert_response :success assert_equal(" ", @response.body) - assert_equal 'text/plain', @response.content_type + assert_equal "text/plain", @response.content_type end end diff --git a/actionpack/test/controller/mime/accept_format_test.rb b/actionpack/test/controller/mime/accept_format_test.rb index e20c08da4e..a2834c9f39 100644 --- a/actionpack/test/controller/mime/accept_format_test.rb +++ b/actionpack/test/controller/mime/accept_format_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class StarStarMimeController < ActionController::Base layout nil @@ -11,7 +11,7 @@ end class StarStarMimeControllerTest < ActionController::TestCase def test_javascript_with_format @request.accept = "text/javascript" - get :index, format: 'js' + get :index, format: "js" assert_match "function addition(a,b){ return a+b; }", @response.body end @@ -71,7 +71,7 @@ class MimeControllerLayoutsTest < ActionController::TestCase @request.accept = "text/iphone" get :index - assert_equal 'Hello iPhone', @response.body + assert_equal "Hello iPhone", @response.body end def test_format_with_inherited_layouts diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb index 993f4001de..c5f8165d04 100644 --- a/actionpack/test/controller/mime/respond_to_test.rb +++ b/actionpack/test/controller/mime/respond_to_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" require "active_support/log_subscriber/test_helper" class RespondToController < ActionController::Base @@ -45,13 +45,12 @@ class RespondToController < ActionController::Base def json_xml_or_html respond_to do |type| - type.json { render body: 'JSON' } - type.xml { render :xml => 'XML' } - type.html { render body: 'HTML' } + type.json { render body: "JSON" } + type.xml { render xml: "XML" } + type.html { render body: "HTML" } end end - def forced_xml request.format = :xml @@ -77,7 +76,7 @@ class RespondToController < ActionController::Base def missing_templates respond_to do |type| # This test requires a block that is empty - type.json { } + type.json {} type.xml end end @@ -109,7 +108,6 @@ class RespondToController < ActionController::Base end end - def custom_constant_handling respond_to do |type| type.html { render body: "HTML" } @@ -133,8 +131,8 @@ class RespondToController < ActionController::Base def handle_any_any respond_to do |type| - type.html { render body: 'HTML' } - type.any { render body: 'Whatever you ask for, I got it' } + type.html { render body: "HTML" } + type.any { render body: "Whatever you ask for, I got it" } end end @@ -146,7 +144,7 @@ class RespondToController < ActionController::Base def json_with_callback respond_to do |type| - type.json { render :json => 'JS', :callback => 'alert' } + type.json { render json: "JS", callback: "alert" } end end @@ -163,8 +161,8 @@ class RespondToController < ActionController::Base request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone" respond_to do |type| - type.html { @type = "Firefox"; render :action => "iphone_with_html_response_type" } - type.iphone { @type = "iPhone" ; render :action => "iphone_with_html_response_type" } + type.html { @type = "Firefox"; render action: "iphone_with_html_response_type" } + type.iphone { @type = "iPhone" ; render action: "iphone_with_html_response_type" } end end @@ -223,7 +221,7 @@ class RespondToController < ActionController::Base def variant_any respond_to do |format| format.html do |variant| - variant.any(:tablet, :phablet){ render body: "any" } + variant.any(:tablet, :phablet) { render body: "any" } variant.phone { render body: "phone" } end end @@ -240,7 +238,7 @@ class RespondToController < ActionController::Base def variant_inline_any respond_to do |format| - format.html.any(:tablet, :phablet){ render body: "any" } + format.html.any(:tablet, :phablet) { render body: "any" } format.html.phone { render body: "phone" } end end @@ -261,7 +259,7 @@ class RespondToController < ActionController::Base def variant_any_with_none respond_to do |format| - format.html.any(:none, :phone){ render body: "none or phone" } + format.html.any(:none, :phone) { render body: "none or phone" } end end @@ -269,8 +267,8 @@ class RespondToController < ActionController::Base respond_to do |format| format.html { render body: "HTML" } format.any(:js, :xml) do |variant| - variant.phone{ render body: "phone" } - variant.any(:tablet, :phablet){ render body: "tablet" } + variant.phone { render body: "phone" } + variant.any(:tablet, :phablet) { render body: "tablet" } end end end @@ -278,10 +276,10 @@ class RespondToController < ActionController::Base protected def set_layout case action_name - when "all_types_with_layout", "iphone_with_html_response_type" - "respond_to/layouts/standard" - when "iphone_with_html_response_type_without_layout" - "respond_to/layouts/missing" + when "all_types_with_layout", "iphone_with_html_response_type" + "respond_to/layouts/standard" + when "iphone_with_html_response_type_without_layout" + "respond_to/layouts/missing" end end end @@ -305,10 +303,10 @@ class RespondToControllerTest < ActionController::TestCase def test_html @request.accept = "text/html" get :js_or_html - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body get :html_or_xml - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body assert_raises(ActionController::UnknownFormat) do get :just_xml @@ -318,29 +316,29 @@ class RespondToControllerTest < ActionController::TestCase def test_all @request.accept = "*/*" get :js_or_html - assert_equal 'HTML', @response.body # js is not part of all + assert_equal "HTML", @response.body # js is not part of all get :html_or_xml - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body get :just_xml - assert_equal 'XML', @response.body + assert_equal "XML", @response.body end def test_xml @request.accept = "application/xml" get :html_xml_or_rss - assert_equal 'XML', @response.body + assert_equal "XML", @response.body end def test_js_or_html @request.accept = "text/javascript, text/html" get :js_or_html, xhr: true - assert_equal 'JS', @response.body + assert_equal "JS", @response.body @request.accept = "text/javascript, text/html" get :html_or_xml, xhr: true - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body @request.accept = "text/javascript, text/html" @@ -352,25 +350,25 @@ class RespondToControllerTest < ActionController::TestCase def test_json_or_yaml_with_leading_star_star @request.accept = "*/*, application/json" get :json_xml_or_html - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body @request.accept = "*/* , application/json" get :json_xml_or_html - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body end def test_json_or_yaml get :json_or_yaml, xhr: true - assert_equal 'JSON', @response.body + assert_equal "JSON", @response.body - get :json_or_yaml, format: 'json' - assert_equal 'JSON', @response.body + get :json_or_yaml, format: "json" + assert_equal "JSON", @response.body - get :json_or_yaml, format: 'yaml' - assert_equal 'YAML', @response.body + get :json_or_yaml, format: "yaml" + assert_equal "YAML", @response.body - { 'YAML' => %w(text/yaml), - 'JSON' => %w(application/json text/x-json) + { "YAML" => %w(text/yaml), + "JSON" => %w(application/json text/x-json) }.each do |body, content_types| content_types.each do |content_type| @request.accept = content_type @@ -383,20 +381,20 @@ class RespondToControllerTest < ActionController::TestCase def test_js_or_anything @request.accept = "text/javascript, */*" get :js_or_html, xhr: true - assert_equal 'JS', @response.body + assert_equal "JS", @response.body get :html_or_xml, xhr: true - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body get :just_xml, xhr: true - assert_equal 'XML', @response.body + assert_equal "XML", @response.body end def test_using_defaults @request.accept = "*/*" get :using_defaults assert_equal "text/html", @response.content_type - assert_equal 'Hello world!', @response.body + assert_equal "Hello world!", @response.body @request.accept = "application/xml" get :using_defaults @@ -422,7 +420,7 @@ class RespondToControllerTest < ActionController::TestCase @request.accept = "*/*" get :using_defaults_with_type_list assert_equal "text/html", @response.content_type - assert_equal 'Hello world!', @response.body + assert_equal "Hello world!", @response.body @request.accept = "application/xml" get :using_defaults_with_type_list @@ -447,7 +445,7 @@ class RespondToControllerTest < ActionController::TestCase def test_synonyms @request.accept = "application/javascript" get :js_or_html - assert_equal 'JS', @response.body + assert_equal "JS", @response.body @request.accept = "application/x-xml" get :html_xml_or_rss @@ -458,82 +456,82 @@ class RespondToControllerTest < ActionController::TestCase @request.accept = "application/crazy-xml" get :custom_type_handling assert_equal "application/crazy-xml", @response.content_type - assert_equal 'Crazy XML', @response.body + assert_equal "Crazy XML", @response.body @request.accept = "text/html" get :custom_type_handling assert_equal "text/html", @response.content_type - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body end def test_xhtml_alias @request.accept = "application/xhtml+xml,application/xml" get :html_or_xml - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body end def test_firefox_simulation @request.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" get :html_or_xml - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body end def test_handle_any @request.accept = "*/*" get :handle_any - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body @request.accept = "text/javascript" get :handle_any - assert_equal 'Either JS or XML', @response.body + assert_equal "Either JS or XML", @response.body @request.accept = "text/xml" get :handle_any - assert_equal 'Either JS or XML', @response.body + assert_equal "Either JS or XML", @response.body end def test_handle_any_any @request.accept = "*/*" get :handle_any_any - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body end def test_handle_any_any_parameter_format - get :handle_any_any, format: 'html' - assert_equal 'HTML', @response.body + get :handle_any_any, format: "html" + assert_equal "HTML", @response.body end def test_handle_any_any_explicit_html @request.accept = "text/html" get :handle_any_any - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body end def test_handle_any_any_javascript @request.accept = "text/javascript" get :handle_any_any - assert_equal 'Whatever you ask for, I got it', @response.body + assert_equal "Whatever you ask for, I got it", @response.body end def test_handle_any_any_xml @request.accept = "text/xml" get :handle_any_any - assert_equal 'Whatever you ask for, I got it', @response.body + assert_equal "Whatever you ask for, I got it", @response.body end def test_handle_any_any_unkown_format - get :handle_any_any, format: 'php' - assert_equal 'Whatever you ask for, I got it', @response.body + get :handle_any_any, format: "php" + assert_equal "Whatever you ask for, I got it", @response.body end def test_browser_check_with_any_any @request.accept = "application/json, application/xml" get :json_xml_or_html - assert_equal 'JSON', @response.body + assert_equal "JSON", @response.body @request.accept = "application/json, application/xml, */*" get :json_xml_or_html - assert_equal 'HTML', @response.body + assert_equal "HTML", @response.body end def test_html_type_with_layout @@ -543,15 +541,15 @@ class RespondToControllerTest < ActionController::TestCase end def test_json_with_callback_sets_javascript_content_type - @request.accept = 'application/json' + @request.accept = "application/json" get :json_with_callback - assert_equal '/**/alert(JS)', @response.body - assert_equal 'text/javascript', @response.content_type + assert_equal "/**/alert(JS)", @response.body + assert_equal "text/javascript", @response.content_type end def test_xhr get :js_or_html, xhr: true - assert_equal 'JS', @response.body + assert_equal "JS", @response.body end def test_custom_constant @@ -676,7 +674,7 @@ class RespondToControllerTest < ActionController::TestCase get :variant_without_implicit_template_rendering, xhr: true, params: { v: :does_not_matter } assert_response :no_content - assert_equal 1, logger.logged(:info).select{ |s| s == NO_CONTENT_WARNING }.size, "Implicit head :no_content not logged" + assert_equal 1, logger.logged(:info).select { |s| s == NO_CONTENT_WARNING }.size, "Implicit head :no_content not logged" ensure ActionController::Base.logger = old_logger end @@ -685,10 +683,10 @@ class RespondToControllerTest < ActionController::TestCase logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new old_logger, ActionController::Base.logger = ActionController::Base.logger, logger - get :variant_without_implicit_template_rendering, format: 'json', params: { v: :does_not_matter } + get :variant_without_implicit_template_rendering, format: "json", params: { v: :does_not_matter } assert_response :no_content - assert_equal 1, logger.logged(:info).select{ |s| s == NO_CONTENT_WARNING }.size, "Implicit head :no_content not logged" + assert_equal 1, logger.logged(:info).select { |s| s == NO_CONTENT_WARNING }.size, "Implicit head :no_content not logged" ensure ActionController::Base.logger = old_logger end diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb index ee3c498b1c..9956f0b107 100644 --- a/actionpack/test/controller/new_base/bare_metal_test.rb +++ b/actionpack/test/controller/new_base/bare_metal_test.rb @@ -102,38 +102,38 @@ module BareMetalTest test "head :continue (100) does not return a content-type header" do headers = HeadController.action(:continue).call(Rack::MockRequest.env_for("/")).second - assert_nil headers['Content-Type'] - assert_nil headers['Content-Length'] + assert_nil headers["Content-Type"] + assert_nil headers["Content-Length"] end test "head :switching_protocols (101) does not return a content-type header" do headers = HeadController.action(:switching_protocols).call(Rack::MockRequest.env_for("/")).second - assert_nil headers['Content-Type'] - assert_nil headers['Content-Length'] + assert_nil headers["Content-Type"] + assert_nil headers["Content-Length"] end test "head :processing (102) does not return a content-type header" do headers = HeadController.action(:processing).call(Rack::MockRequest.env_for("/")).second - assert_nil headers['Content-Type'] - assert_nil headers['Content-Length'] + assert_nil headers["Content-Type"] + assert_nil headers["Content-Length"] end test "head :no_content (204) does not return a content-type header" do headers = HeadController.action(:no_content).call(Rack::MockRequest.env_for("/")).second - assert_nil headers['Content-Type'] - assert_nil headers['Content-Length'] + assert_nil headers["Content-Type"] + assert_nil headers["Content-Length"] end test "head :reset_content (205) does not return a content-type header" do headers = HeadController.action(:reset_content).call(Rack::MockRequest.env_for("/")).second - assert_nil headers['Content-Type'] - assert_nil headers['Content-Length'] + assert_nil headers["Content-Type"] + assert_nil headers["Content-Length"] end test "head :not_modified (304) does not return a content-type header" do headers = HeadController.action(:not_modified).call(Rack::MockRequest.env_for("/")).second - assert_nil headers['Content-Type'] - assert_nil headers['Content-Length'] + assert_nil headers["Content-Type"] + assert_nil headers["Content-Length"] end test "head :no_content (204) does not return any content" do diff --git a/actionpack/test/controller/new_base/base_test.rb b/actionpack/test/controller/new_base/base_test.rb index 0755dafe93..3765d406fc 100644 --- a/actionpack/test/controller/new_base/base_test.rb +++ b/actionpack/test/controller/new_base/base_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" # Tests the controller dispatching happy path module Dispatching @@ -69,48 +69,48 @@ module Dispatching end test "controller path" do - assert_equal 'dispatching/empty', EmptyController.controller_path + assert_equal "dispatching/empty", EmptyController.controller_path assert_equal EmptyController.controller_path, EmptyController.new.controller_path end test "non-default controller path" do - assert_equal 'i_am_not_default', NonDefaultPathController.controller_path + assert_equal "i_am_not_default", NonDefaultPathController.controller_path assert_equal NonDefaultPathController.controller_path, NonDefaultPathController.new.controller_path end test "sub controller path" do - assert_equal 'dispatching/sub_empty', SubEmptyController.controller_path + assert_equal "dispatching/sub_empty", SubEmptyController.controller_path assert_equal SubEmptyController.controller_path, SubEmptyController.new.controller_path end test "namespaced controller path" do - assert_equal 'dispatching/submodule/contained_empty', Submodule::ContainedEmptyController.controller_path + assert_equal "dispatching/submodule/contained_empty", Submodule::ContainedEmptyController.controller_path assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path end test "namespaced non-default controller path" do - assert_equal 'i_am_extremely_not_default', Submodule::ContainedNonDefaultPathController.controller_path + assert_equal "i_am_extremely_not_default", Submodule::ContainedNonDefaultPathController.controller_path assert_equal Submodule::ContainedNonDefaultPathController.controller_path, Submodule::ContainedNonDefaultPathController.new.controller_path end test "namespaced sub controller path" do - assert_equal 'dispatching/submodule/contained_sub_empty', Submodule::ContainedSubEmptyController.controller_path + assert_equal "dispatching/submodule/contained_sub_empty", Submodule::ContainedSubEmptyController.controller_path assert_equal Submodule::ContainedSubEmptyController.controller_path, Submodule::ContainedSubEmptyController.new.controller_path end test "controller name" do - assert_equal 'empty', EmptyController.controller_name - assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name + assert_equal "empty", EmptyController.controller_name + assert_equal "contained_empty", Submodule::ContainedEmptyController.controller_name end test "non-default path controller name" do - assert_equal 'non_default_path', NonDefaultPathController.controller_name - assert_equal 'contained_non_default_path', Submodule::ContainedNonDefaultPathController.controller_name + assert_equal "non_default_path", NonDefaultPathController.controller_name + assert_equal "contained_non_default_path", Submodule::ContainedNonDefaultPathController.controller_name end test "sub controller name" do - assert_equal 'sub_empty', SubEmptyController.controller_name - assert_equal 'contained_sub_empty', Submodule::ContainedSubEmptyController.controller_name + assert_equal "sub_empty", SubEmptyController.controller_name + assert_equal "contained_sub_empty", Submodule::ContainedSubEmptyController.controller_name end test "action methods" do diff --git a/actionpack/test/controller/new_base/content_negotiation_test.rb b/actionpack/test/controller/new_base/content_negotiation_test.rb index c0e92b3b05..b870745031 100644 --- a/actionpack/test/controller/new_base/content_negotiation_test.rb +++ b/actionpack/test/controller/new_base/content_negotiation_test.rb @@ -1,7 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" module ContentNegotiation - # This has no layout and it works class BasicController < ActionController::Base self.view_paths = [ActionView::FixtureResolver.new( @@ -9,7 +8,7 @@ module ContentNegotiation )] def all - render plain: self.formats.inspect + render plain: formats.inspect end end diff --git a/actionpack/test/controller/new_base/content_type_test.rb b/actionpack/test/controller/new_base/content_type_test.rb index 0b3a26807d..85089bafe2 100644 --- a/actionpack/test/controller/new_base/content_type_test.rb +++ b/actionpack/test/controller/new_base/content_type_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ContentType class BaseController < ActionController::Base @@ -44,7 +44,7 @@ module ContentType with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':controller', :action => 'index' + get ":controller", action: "index" end end diff --git a/actionpack/test/controller/new_base/middleware_test.rb b/actionpack/test/controller/new_base/middleware_test.rb index 85a1f351f0..0493291c03 100644 --- a/actionpack/test/controller/new_base/middleware_test.rb +++ b/actionpack/test/controller/new_base/middleware_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module MiddlewareTest class MyMiddleware @@ -56,8 +56,8 @@ module MiddlewareTest end class ActionsController < ActionController::Metal - use MyMiddleware, :only => :show - middleware.insert_before MyMiddleware, ExclaimerMiddleware, :except => :index + use MyMiddleware, only: :show + middleware.insert_before MyMiddleware, ExclaimerMiddleware, except: :index def index self.response_body = "index" diff --git a/actionpack/test/controller/new_base/render_action_test.rb b/actionpack/test/controller/new_base/render_action_test.rb index 3bf1dd0ede..4b59a3d676 100644 --- a/actionpack/test/controller/new_base/render_action_test.rb +++ b/actionpack/test/controller/new_base/render_action_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module RenderAction # This has no layout and it works @@ -8,7 +8,7 @@ module RenderAction )] def hello_world - render :action => "hello_world" + render action: "hello_world" end def hello_world_as_string @@ -16,7 +16,7 @@ module RenderAction end def hello_world_as_string_with_options - render "hello_world", :status => 404 + render "hello_world", status: 404 end def hello_world_as_symbol @@ -24,25 +24,24 @@ module RenderAction end def hello_world_with_symbol - render :action => :hello_world + render action: :hello_world end def hello_world_with_layout - render :action => "hello_world", :layout => true + render action: "hello_world", layout: true end def hello_world_with_layout_false - render :action => "hello_world", :layout => false + render action: "hello_world", layout: false end def hello_world_with_layout_nil - render :action => "hello_world", :layout => nil + render action: "hello_world", layout: nil end def hello_world_with_custom_layout - render :action => "hello_world", :layout => "greetings" + render action: "hello_world", layout: "greetings" end - end class RenderActionTest < Rack::TestCase @@ -127,27 +126,27 @@ module RenderActionWithApplicationLayout )] def hello_world - render :action => "hello_world" + render action: "hello_world" end def hello_world_with_layout - render :action => "hello_world", :layout => true + render action: "hello_world", layout: true end def hello_world_with_layout_false - render :action => "hello_world", :layout => false + render action: "hello_world", layout: false end def hello_world_with_layout_nil - render :action => "hello_world", :layout => nil + render action: "hello_world", layout: nil end def hello_world_with_custom_layout - render :action => "hello_world", :layout => "greetings" + render action: "hello_world", layout: "greetings" end def with_builder_and_layout - render :action => "hello", :layout => "builder" + render action: "hello", layout: "builder" end end @@ -196,7 +195,6 @@ module RenderActionWithApplicationLayout assert_response "<html>\n<p>Hello</p>\n</html>\n" end end - end module RenderActionWithControllerLayout @@ -207,23 +205,23 @@ module RenderActionWithControllerLayout )] def hello_world - render :action => "hello_world" + render action: "hello_world" end def hello_world_with_layout - render :action => "hello_world", :layout => true + render action: "hello_world", layout: true end def hello_world_with_layout_false - render :action => "hello_world", :layout => false + render action: "hello_world", layout: false end def hello_world_with_layout_nil - render :action => "hello_world", :layout => nil + render action: "hello_world", layout: nil end def hello_world_with_custom_layout - render :action => "hello_world", :layout => "greetings" + render action: "hello_world", layout: "greetings" end end @@ -260,26 +258,25 @@ end module RenderActionWithBothLayouts class BasicController < ActionController::Base - self.view_paths = [ActionView::FixtureResolver.new({ - "render_action_with_both_layouts/basic/hello_world.html.erb" => "Hello World!", + self.view_paths = [ActionView::FixtureResolver.new( + "render_action_with_both_layouts/basic/hello_world.html.erb" => "Hello World!", "layouts/application.html.erb" => "Oh Hi <%= yield %> Bye", - "layouts/render_action_with_both_layouts/basic.html.erb" => "With Controller Layout! <%= yield %> Bye" - })] + "layouts/render_action_with_both_layouts/basic.html.erb" => "With Controller Layout! <%= yield %> Bye")] def hello_world - render :action => "hello_world" + render action: "hello_world" end def hello_world_with_layout - render :action => "hello_world", :layout => true + render action: "hello_world", layout: true end def hello_world_with_layout_false - render :action => "hello_world", :layout => false + render action: "hello_world", layout: false end def hello_world_with_layout_nil - render :action => "hello_world", :layout => nil + render action: "hello_world", layout: nil end end diff --git a/actionpack/test/controller/new_base/render_body_test.rb b/actionpack/test/controller/new_base/render_body_test.rb index c65c245773..b1467a0deb 100644 --- a/actionpack/test/controller/new_base/render_body_test.rb +++ b/actionpack/test/controller/new_base/render_body_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module RenderBody class MinimalController < ActionController::Metal @@ -66,7 +66,7 @@ module RenderBody end def with_custom_content_type - response.headers['Content-Type'] = 'application/json' + response.headers["Content-Type"] = "application/json" render body: '["troll","face"]' end @@ -85,7 +85,7 @@ module RenderBody test "rendering body from an action with default options renders the body with the layout" do with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller", action: "index" } } get "/render_body/simple" assert_body "hello david" @@ -95,7 +95,7 @@ module RenderBody test "rendering body from an action with default options renders the body without the layout" do with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller", action: "index" } } get "/render_body/with_layout" @@ -150,7 +150,7 @@ module RenderBody get "/render_body/with_layout/with_custom_content_type" assert_equal %w{ troll face }, JSON.parse(response.body) - assert_equal 'application/json', response.headers['Content-Type'] + assert_equal "application/json", response.headers["Content-Type"] end test "rendering body with layout: false" do diff --git a/actionpack/test/controller/new_base/render_context_test.rb b/actionpack/test/controller/new_base/render_context_test.rb index 177a1c088d..b64468a94e 100644 --- a/actionpack/test/controller/new_base/render_context_test.rb +++ b/actionpack/test/controller/new_base/render_context_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" # This is testing the decoupling of view renderer and view context # by allowing the controller to be used as view context. This is @@ -18,24 +18,24 @@ module RenderContext def hello_world @value = "Hello" - render :action => "hello_world", :layout => false + render action: "hello_world", layout: false end def with_layout @value = "Hello" - render :action => "hello_world", :layout => "basic" + render action: "hello_world", layout: "basic" end protected - # 3) Set view_context to self - def view_context - self - end + # 3) Set view_context to self + def view_context + self + end - def __controller_method__ - "controller context!" - end + def __controller_method__ + "controller context!" + end end class RenderContextTest < Rack::TestCase diff --git a/actionpack/test/controller/new_base/render_file_test.rb b/actionpack/test/controller/new_base/render_file_test.rb index 0c21bb0719..6d651e0104 100644 --- a/actionpack/test/controller/new_base/render_file_test.rb +++ b/actionpack/test/controller/new_base/render_file_test.rb @@ -1,36 +1,36 @@ -require 'abstract_unit' +require "abstract_unit" module RenderFile class BasicController < ActionController::Base self.view_paths = File.dirname(__FILE__) def index - render :file => File.join(File.dirname(__FILE__), *%w[.. .. fixtures test hello_world]) + render file: File.join(File.dirname(__FILE__), *%w[.. .. fixtures test hello_world]) end def with_instance_variables - @secret = 'in the sauce' - render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar') + @secret = "in the sauce" + render file: File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_ivar") end def relative_path - @secret = 'in the sauce' - render :file => '../../fixtures/test/render_file_with_ivar' + @secret = "in the sauce" + render file: "../../fixtures/test/render_file_with_ivar" end def relative_path_with_dot - @secret = 'in the sauce' - render :file => '../../fixtures/test/dot.directory/render_file_with_ivar' + @secret = "in the sauce" + render file: "../../fixtures/test/dot.directory/render_file_with_ivar" end def pathname - @secret = 'in the sauce' - render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar]) + @secret = "in the sauce" + render file: Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar]) end def with_locals - path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals') - render :file => path, :locals => {:secret => 'in the sauce'} + path = File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_locals") + render file: path, locals: { secret: "in the sauce" } end end diff --git a/actionpack/test/controller/new_base/render_html_test.rb b/actionpack/test/controller/new_base/render_html_test.rb index bfed136496..8019aa1eb5 100644 --- a/actionpack/test/controller/new_base/render_html_test.rb +++ b/actionpack/test/controller/new_base/render_html_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module RenderHtml class MinimalController < ActionController::Metal @@ -88,7 +88,7 @@ module RenderHtml test "rendering text from an action with default options renders the text with the layout" do with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller", action: "index" } } get "/render_html/simple" assert_body "hello david" @@ -98,7 +98,7 @@ module RenderHtml test "rendering text from an action with default options renders the text without the layout" do with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller", action: "index" } } get "/render_html/with_layout" diff --git a/actionpack/test/controller/new_base/render_implicit_action_test.rb b/actionpack/test/controller/new_base/render_implicit_action_test.rb index 5b4885f7e0..796283466a 100644 --- a/actionpack/test/controller/new_base/render_implicit_action_test.rb +++ b/actionpack/test/controller/new_base/render_implicit_action_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module RenderImplicitAction class SimpleController < ::ApplicationController @@ -6,7 +6,7 @@ module RenderImplicitAction "render_implicit_action/simple/hello_world.html.erb" => "Hello world!", "render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!", "render_implicit_action/simple/not_implemented.html.erb" => "Not Implemented" - ), ActionView::FileSystemResolver.new(File.expand_path('../../../controller', __FILE__))] + ), ActionView::FileSystemResolver.new(File.expand_path("../../../controller", __FILE__))] def hello_world() end end diff --git a/actionpack/test/controller/new_base/render_layout_test.rb b/actionpack/test/controller/new_base/render_layout_test.rb index 7ab3777026..0a3809560e 100644 --- a/actionpack/test/controller/new_base/render_layout_test.rb +++ b/actionpack/test/controller/new_base/render_layout_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ControllerLayouts class ImplicitController < ::ApplicationController @@ -10,15 +10,15 @@ module ControllerLayouts )] def index - render :template => "basic" + render template: "basic" end def override - render :template => "basic", :layout => "override" + render template: "basic", layout: "override" end def layout_false - render :layout => false + render layout: false end def builder_override @@ -32,7 +32,7 @@ module ControllerLayouts )] def index - render :template => "basic" + render template: "basic" end end @@ -55,7 +55,6 @@ module ControllerLayouts get "/controller_layouts/implicit/override" assert_body "Override! Hello world!" end - end class LayoutOptionsTest < Rack::TestCase @@ -76,7 +75,7 @@ module ControllerLayouts )] def explicit - render :layout => "application" + render layout: "application" end end diff --git a/actionpack/test/controller/new_base/render_partial_test.rb b/actionpack/test/controller/new_base/render_partial_test.rb index 9e5022c9f4..4511826978 100644 --- a/actionpack/test/controller/new_base/render_partial_test.rb +++ b/actionpack/test/controller/new_base/render_partial_test.rb @@ -1,9 +1,7 @@ -require 'abstract_unit' +require "abstract_unit" module RenderPartial - class BasicController < ActionController::Base - self.view_paths = [ActionView::FixtureResolver.new( "render_partial/basic/_basic.html.erb" => "BasicPartial!", "render_partial/basic/basic.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'basic' %><%= @test_unchanged %>", @@ -16,16 +14,16 @@ module RenderPartial )] def html_with_json_inside_json - render :action => "with_json" + render action: "with_json" end def changing - @test_unchanged = 'hello' - render :action => "basic" + @test_unchanged = "hello" + render action: "basic" end def overridden - @test_unchanged = 'hello' + @test_unchanged = "hello" end end @@ -59,5 +57,4 @@ module RenderPartial assert_response("goodbyeOverriddenPartial!goodbye") end end - end diff --git a/actionpack/test/controller/new_base/render_plain_test.rb b/actionpack/test/controller/new_base/render_plain_test.rb index 94afe7bcfe..44be8dd380 100644 --- a/actionpack/test/controller/new_base/render_plain_test.rb +++ b/actionpack/test/controller/new_base/render_plain_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module RenderPlain class MinimalController < ActionController::Metal @@ -80,7 +80,7 @@ module RenderPlain test "rendering text from an action with default options renders the text with the layout" do with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller", action: "index" } } get "/render_plain/simple" assert_body "hello david" @@ -90,7 +90,7 @@ module RenderPlain test "rendering text from an action with default options renders the text without the layout" do with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller", action: "index" } } get "/render_plain/with_layout" diff --git a/actionpack/test/controller/new_base/render_streaming_test.rb b/actionpack/test/controller/new_base/render_streaming_test.rb index 9ea056194a..5cd8f82323 100644 --- a/actionpack/test/controller/new_base/render_streaming_test.rb +++ b/actionpack/test/controller/new_base/render_streaming_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module RenderStreaming class BasicController < ActionController::Base @@ -12,32 +12,32 @@ module RenderStreaming layout "application" def hello_world - render :stream => true + render stream: true end def layout_exception - render :action => "hello_world", :stream => true, :layout => "boom" + render action: "hello_world", stream: true, layout: "boom" end def template_exception - render :action => "boom", :stream => true + render action: "boom", stream: true end def skip - render :action => "hello_world", :stream => false + render action: "hello_world", stream: false end def explicit - render :action => "hello_world", :stream => true + render action: "hello_world", stream: true end def no_layout - render :action => "hello_world", :stream => true, :layout => false + render action: "hello_world", stream: true, layout: false end def explicit_cache headers["Cache-Control"] = "private" - render :action => "hello_world", :stream => true + render action: "hello_world", stream: true end end diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb index 0d4c7cdb0a..1102305f3e 100644 --- a/actionpack/test/controller/new_base/render_template_test.rb +++ b/actionpack/test/controller/new_base/render_template_test.rb @@ -1,8 +1,7 @@ -require 'abstract_unit' +require "abstract_unit" module RenderTemplate class WithoutLayoutController < ActionController::Base - self.view_paths = [ActionView::FixtureResolver.new( "test/basic.html.erb" => "Hello from basic.html.erb", "shared.html.erb" => "Elastica", @@ -18,11 +17,11 @@ module RenderTemplate )] def index - render :template => "test/basic" + render template: "test/basic" end def html_with_json_inside_json - render :template => "test/with_json" + render template: "test/with_json" end def index_without_key @@ -30,46 +29,46 @@ module RenderTemplate end def in_top_directory - render :template => 'shared' + render template: "shared" end def in_top_directory_with_slash - render :template => '/shared' + render template: "/shared" end def in_top_directory_with_slash_without_key - render '/shared' + render "/shared" end def with_locals - render :template => "locals", :locals => { :secret => 'area51' } + render template: "locals", locals: { secret: "area51" } end def with_locals_without_key - render "locals", :locals => { :secret => 'area51' } + render "locals", locals: { secret: "area51" } end def builder_template - render :template => "xml_template" + render template: "xml_template" end def with_raw - render :template => "with_raw" + render template: "with_raw" end def with_implicit_raw - render :template => "with_implicit_raw" + render template: "with_implicit_raw" end def with_error - render :template => "test/with_error" + render template: "test/with_error" end private - def show_detailed_exceptions? - request.local? - end + def show_detailed_exceptions? + request.local? + end end class TestWithoutLayout < Rack::TestCase @@ -126,7 +125,7 @@ module RenderTemplate assert_body "Hello <strong>this is also raw</strong> in an html template" assert_status 200 - get :with_implicit_raw, params: { format: 'text' } + get :with_implicit_raw, params: { format: "text" } assert_body "Hello <strong>this is also raw</strong> in a text template" assert_status 200 @@ -154,30 +153,30 @@ module RenderTemplate )] def index - render :template => "test/basic" + render template: "test/basic" end def with_layout - render :template => "test/basic", :layout => true + render template: "test/basic", layout: true end def with_layout_false - render :template => "test/basic", :layout => false + render template: "test/basic", layout: false end def with_layout_nil - render :template => "test/basic", :layout => nil + render template: "test/basic", layout: nil end def with_custom_layout - render :template => "test/basic", :layout => "greetings" + render template: "test/basic", layout: "greetings" end end class TestWithLayout < Rack::TestCase test "rendering with implicit layout" do with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', :action => :index } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller", action: :index } } get "/render_template/with_layout" @@ -223,7 +222,7 @@ module RenderTemplate )] def with_forward_slash - render :template => "/test/basic" + render template: "/test/basic" end end diff --git a/actionpack/test/controller/new_base/render_test.rb b/actionpack/test/controller/new_base/render_test.rb index 1fb852a2c4..cea3f9b5fd 100644 --- a/actionpack/test/controller/new_base/render_test.rb +++ b/actionpack/test/controller/new_base/render_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module Render class BlankRenderController < ActionController::Base @@ -18,11 +18,11 @@ module Render end def access_request - render :action => "access_request" + render action: "access_request" end def render_action_name - render :action => "access_action_name" + render action: "access_action_name" end def overridden_with_own_view_paths_appended @@ -36,9 +36,9 @@ module Render private - def secretz - render plain: "FAIL WHALE!" - end + def secretz + render plain: "FAIL WHALE!" + end end class DoubleRenderController < ActionController::Base @@ -58,7 +58,7 @@ module Render with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ":controller", :action => 'index' + get ":controller", action: "index" end end @@ -73,7 +73,7 @@ module Render with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ":controller", :action => 'index' + get ":controller", action: "index" end end diff --git a/actionpack/test/controller/new_base/render_text_test.rb b/actionpack/test/controller/new_base/render_text_test.rb deleted file mode 100644 index d4111d432c..0000000000 --- a/actionpack/test/controller/new_base/render_text_test.rb +++ /dev/null @@ -1,188 +0,0 @@ -require 'abstract_unit' - -module RenderText - class MinimalController < ActionController::Metal - include AbstractController::Rendering - include ActionController::Rendering - - def index - render text: "Hello World!" - end - end - - class SimpleController < ActionController::Base - self.view_paths = [ActionView::FixtureResolver.new] - - def index - render text: "hello david" - end - end - - class WithLayoutController < ::ApplicationController - self.view_paths = [ActionView::FixtureResolver.new( - "layouts/application.html.erb" => "<%= yield %>, I'm here!", - "layouts/greetings.html.erb" => "<%= yield %>, I wish thee well.", - "layouts/ivar.html.erb" => "<%= yield %>, <%= @ivar %>" - )] - - def index - render text: "hello david" - end - - def custom_code - render text: "hello world", status: 404 - end - - def with_custom_code_as_string - render text: "hello world", status: "404 Not Found" - end - - def with_nil - render text: nil - end - - def with_nil_and_status - render text: nil, status: 403 - end - - def with_false - render text: false - end - - def with_layout_true - render text: "hello world", layout: true - end - - def with_layout_false - render text: "hello world", layout: false - end - - def with_layout_nil - render text: "hello world", layout: nil - end - - def with_custom_layout - render text: "hello world", layout: "greetings" - end - - def with_ivar_in_layout - @ivar = "hello world" - render text: "hello world", layout: "ivar" - end - end - - class RenderTextTest < Rack::TestCase - test "rendering text from a minimal controller" do - ActiveSupport::Deprecation.silence do - get "/render_text/minimal/index" - end - - assert_body "Hello World!" - assert_status 200 - end - - test "rendering text from an action with default options renders the text with the layout" do - with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } - - ActiveSupport::Deprecation.silence do - get "/render_text/simple" - end - - assert_body "hello david" - assert_status 200 - end - end - - test "rendering text from an action with default options renders the text without the layout" do - with_routing do |set| - set.draw { ActiveSupport::Deprecation.silence { get ':controller', action: 'index' } } - - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout" - end - - assert_body "hello david" - assert_status 200 - end - end - - test "rendering text, while also providing a custom status code" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/custom_code" - end - - assert_body "hello world" - assert_status 404 - end - - test "rendering text with nil returns an empty body" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/with_nil" - end - - assert_body "" - assert_status 200 - end - - test "Rendering text with nil and custom status code returns an empty body and the status" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/with_nil_and_status" - end - - assert_body "" - assert_status 403 - end - - test "rendering text with false returns the string 'false'" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/with_false" - end - - assert_body "false" - assert_status 200 - end - - test "rendering text with layout: true" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/with_layout_true" - end - - assert_body "hello world, I'm here!" - assert_status 200 - end - - test "rendering text with layout: 'greetings'" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/with_custom_layout" - end - - assert_body "hello world, I wish thee well." - assert_status 200 - end - - test "rendering text with layout: false" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/with_layout_false" - end - - assert_body "hello world" - assert_status 200 - end - - test "rendering text with layout: nil" do - ActiveSupport::Deprecation.silence do - get "/render_text/with_layout/with_layout_nil" - end - - assert_body "hello world" - assert_status 200 - end - - test "rendering text displays deprecation warning" do - assert_deprecated do - get "/render_text/with_layout/with_layout_nil" - end - end - end -end diff --git a/actionpack/test/controller/new_base/render_xml_test.rb b/actionpack/test/controller/new_base/render_xml_test.rb index b8527a943d..8bab413377 100644 --- a/actionpack/test/controller/new_base/render_xml_test.rb +++ b/actionpack/test/controller/new_base/render_xml_test.rb @@ -1,7 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" module RenderXml - # This has no layout and it works class BasicController < ActionController::Base self.view_paths = [ActionView::FixtureResolver.new( diff --git a/actionpack/test/controller/output_escaping_test.rb b/actionpack/test/controller/output_escaping_test.rb index c3c549fbfc..c7047d95ae 100644 --- a/actionpack/test/controller/output_escaping_test.rb +++ b/actionpack/test/controller/output_escaping_test.rb @@ -1,7 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" class OutputEscapingTest < ActiveSupport::TestCase - test "escape_html shouldn't die when passed nil" do assert ERB::Util.h(nil).blank? end @@ -13,5 +12,4 @@ class OutputEscapingTest < ActiveSupport::TestCase test "escapeHTML shouldn't touch explicitly safe strings" do assert_equal "<", ERB::Util.h("<".html_safe) end - end diff --git a/actionpack/test/controller/parameter_encoding_test.rb b/actionpack/test/controller/parameter_encoding_test.rb new file mode 100644 index 0000000000..7840b4f5c4 --- /dev/null +++ b/actionpack/test/controller/parameter_encoding_test.rb @@ -0,0 +1,73 @@ +require "abstract_unit" + +class ParameterEncodingController < ActionController::Base + parameter_encoding :test_bar, :bar, Encoding::ASCII_8BIT + parameter_encoding :test_baz, :baz, Encoding::ISO_8859_1 + parameter_encoding :test_baz_to_ascii, :baz, Encoding::ASCII_8BIT + + def test_foo + render body: params[:foo].encoding + end + + def test_bar + render body: params[:bar].encoding + end + + def test_baz + render body: params[:baz].encoding + end + + def test_no_change_to_baz + render body: params[:baz].encoding + end + + def test_baz_to_ascii + render body: params[:baz].encoding + end +end + +class ParameterEncodingTest < ActionController::TestCase + tests ParameterEncodingController + + test "properly transcodes UTF8 parameters into declared encodings" do + post :test_foo, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" } + + assert_response :success + assert_equal "UTF-8", @response.body + end + + test "properly transcodes ASCII_8BIT parameters into declared encodings" do + post :test_bar, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" } + + assert_response :success + assert_equal "ASCII-8BIT", @response.body + end + + test "properly transcodes ISO_8859_1 parameters into declared encodings" do + post :test_baz, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" } + + assert_response :success + assert_equal "ISO-8859-1", @response.body + end + + test "does not transcode parameters when not specified" do + post :test_no_change_to_baz, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" } + + assert_response :success + assert_equal "UTF-8", @response.body + end + + test "respects different encoding declarations for a param per action" do + post :test_baz_to_ascii, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" } + + assert_response :success + assert_equal "ASCII-8BIT", @response.body + end + + test "does not raise an error when passed a param declared as ASCII-8BIT that contains invalid bytes" do + get :test_bar, params: { "bar" => URI.parser.escape("bar\xE2baz".b) } + + assert_response :success + assert_equal "ASCII-8BIT", @response.body + end +end diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb index 17c62dc3fe..2893eb7b91 100644 --- a/actionpack/test/controller/parameters/accessors_test.rb +++ b/actionpack/test/controller/parameters/accessors_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'action_controller/metal/strong_parameters' -require 'active_support/core_ext/hash/transform_values' +require "abstract_unit" +require "action_controller/metal/strong_parameters" +require "active_support/core_ext/hash/transform_values" class ParametersAccessorsTest < ActiveSupport::TestCase setup do @@ -8,12 +8,12 @@ class ParametersAccessorsTest < ActiveSupport::TestCase @params = ActionController::Parameters.new( person: { - age: '32', + age: "32", name: { - first: 'David', - last: 'Heinemeier Hansson' + first: "David", + last: "Heinemeier Hansson" }, - addresses: [{city: 'Chicago', state: 'Illinois'}] + addresses: [{ city: "Chicago", state: "Illinois" }] } ) end @@ -131,14 +131,6 @@ class ParametersAccessorsTest < ActiveSupport::TestCase assert_not @params[:person].values_at(:name).first.permitted? end - test "equality with a hash is deprecated" do - hash1 = { foo: :bar } - params1 = ActionController::Parameters.new(hash1) - assert_deprecated("will be removed in Rails 5.1") do - assert(params1 == hash1) - end - end - test "is equal to Parameters instance with same params" do params1 = ActionController::Parameters.new(a: 1, b: 2) params2 = ActionController::Parameters.new(a: 1, b: 2) @@ -158,7 +150,7 @@ class ParametersAccessorsTest < ActiveSupport::TestCase assert(params2 == params1) end - test 'is not equal to an unpermitted Parameters instance with same params' do + test "is not equal to an unpermitted Parameters instance with same params" do params1 = ActionController::Parameters.new(a: 1).permit(:a) params2 = ActionController::Parameters.new(a: 1) assert(params1 != params2) @@ -173,7 +165,7 @@ class ParametersAccessorsTest < ActiveSupport::TestCase end test "equality with simple types works" do - assert(@params != 'Hello') + assert(@params != "Hello") assert(@params != 42) assert(@params != false) end diff --git a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb index c5bfb10b53..cd7c98f112 100644 --- a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb +++ b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_controller/metal/strong_parameters' +require "abstract_unit" +require "action_controller/metal/strong_parameters" class AlwaysPermittedParametersTest < ActiveSupport::TestCase def setup @@ -19,10 +19,9 @@ class AlwaysPermittedParametersTest < ActiveSupport::TestCase end test "permits parameters that are whitelisted" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { pages: 65 }, - format: "json" - }) + format: "json") permitted = params.permit book: [:pages] assert permitted.permitted? end diff --git a/actionpack/test/controller/parameters/dup_test.rb b/actionpack/test/controller/parameters/dup_test.rb new file mode 100644 index 0000000000..fb707a1354 --- /dev/null +++ b/actionpack/test/controller/parameters/dup_test.rb @@ -0,0 +1,65 @@ +require "abstract_unit" +require "action_controller/metal/strong_parameters" +require "active_support/core_ext/object/deep_dup" + +class ParametersDupTest < ActiveSupport::TestCase + setup do + ActionController::Parameters.permit_all_parameters = false + + @params = ActionController::Parameters.new( + person: { + age: "32", + name: { + first: "David", + last: "Heinemeier Hansson" + }, + addresses: [{ city: "Chicago", state: "Illinois" }] + } + ) + end + + test "a duplicate maintains the original's permitted status" do + @params.permit! + dupped_params = @params.dup + assert dupped_params.permitted? + end + + test "a duplicate maintains the original's parameters" do + @params.permit! + dupped_params = @params.dup + assert_equal @params.to_h, dupped_params.to_h + end + + test "changes to a duplicate's parameters do not affect the original" do + dupped_params = @params.dup + dupped_params.delete(:person) + assert_not_equal @params, dupped_params + end + + test "changes to a duplicate's permitted status do not affect the original" do + dupped_params = @params.dup + dupped_params.permit! + assert_not_equal @params, dupped_params + end + + test "deep_dup content" do + dupped_params = @params.deep_dup + dupped_params[:person][:age] = "45" + dupped_params[:person][:addresses].clear + + assert_not_equal @params[:person][:age], dupped_params[:person][:age] + assert_not_equal @params[:person][:addresses], dupped_params[:person][:addresses] + end + + test "deep_dup @permitted" do + dupped_params = @params.deep_dup + dupped_params.permit! + + assert_not @params.permitted? + end + + test "deep_dup @permitted is being copied" do + @params.permit! + assert @params.deep_dup.permitted? + end +end diff --git a/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb b/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb index 9ce04b9aeb..c800c1d3df 100644 --- a/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb +++ b/actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_controller/metal/strong_parameters' +require "abstract_unit" +require "action_controller/metal/strong_parameters" class LogOnUnpermittedParamsTest < ActiveSupport::TestCase def setup @@ -11,62 +11,58 @@ class LogOnUnpermittedParamsTest < ActiveSupport::TestCase end test "logs on unexpected param" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { pages: 65 }, - fishing: "Turnips" - }) + fishing: "Turnips") - assert_logged("Unpermitted parameter: fishing") do + assert_logged("Unpermitted parameter: :fishing") do params.permit(book: [:pages]) end end test "logs on unexpected params" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { pages: 65 }, fishing: "Turnips", - car: "Mersedes" - }) + car: "Mersedes") - assert_logged("Unpermitted parameters: fishing, car") do + assert_logged("Unpermitted parameters: :fishing, :car") do params.permit(book: [:pages]) end end test "logs on unexpected nested param" do - params = ActionController::Parameters.new({ - book: { pages: 65, title: "Green Cats and where to find then." } - }) + params = ActionController::Parameters.new( + book: { pages: 65, title: "Green Cats and where to find then." }) - assert_logged("Unpermitted parameter: title") do + assert_logged("Unpermitted parameter: :title") do params.permit(book: [:pages]) end end test "logs on unexpected nested params" do - params = ActionController::Parameters.new({ - book: { pages: 65, title: "Green Cats and where to find then.", author: "G. A. Dog" } - }) + params = ActionController::Parameters.new( + book: { pages: 65, title: "Green Cats and where to find then.", author: "G. A. Dog" }) - assert_logged("Unpermitted parameters: title, author") do + assert_logged("Unpermitted parameters: :title, :author") do params.permit(book: [:pages]) end end private - def assert_logged(message) - old_logger = ActionController::Base.logger - log = StringIO.new - ActionController::Base.logger = Logger.new(log) + def assert_logged(message) + old_logger = ActionController::Base.logger + log = StringIO.new + ActionController::Base.logger = Logger.new(log) - begin - yield + begin + yield - log.rewind - assert_match message, log.read - ensure - ActionController::Base.logger = old_logger + log.rewind + assert_match message, log.read + ensure + ActionController::Base.logger = old_logger + end end - end end diff --git a/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb b/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb index 15338059bc..88fb477c10 100644 --- a/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb +++ b/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'action_controller/metal/strong_parameters' +require "abstract_unit" +require "action_controller/metal/strong_parameters" class MultiParameterAttributesTest < ActiveSupport::TestCase test "permitted multi-parameter attribute keys" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { "shipped_at(1i)" => "2012", "shipped_at(2i)" => "3", @@ -15,8 +15,7 @@ class MultiParameterAttributesTest < ActiveSupport::TestCase "published_at(3i)" => "5", "price(1)" => "R$", "price(2f)" => "2.02" - } - }) + }) permitted = params.permit book: [ :shipped_at, :price ] diff --git a/actionpack/test/controller/parameters/mutators_test.rb b/actionpack/test/controller/parameters/mutators_test.rb index 744d8664be..e060e5180f 100644 --- a/actionpack/test/controller/parameters/mutators_test.rb +++ b/actionpack/test/controller/parameters/mutators_test.rb @@ -1,17 +1,17 @@ -require 'abstract_unit' -require 'action_controller/metal/strong_parameters' -require 'active_support/core_ext/hash/transform_values' +require "abstract_unit" +require "action_controller/metal/strong_parameters" +require "active_support/core_ext/hash/transform_values" class ParametersMutatorsTest < ActiveSupport::TestCase setup do @params = ActionController::Parameters.new( person: { - age: '32', + age: "32", name: { - first: 'David', - last: 'Heinemeier Hansson' + first: "David", + last: "Heinemeier Hansson" }, - addresses: [{city: 'Chicago', state: 'Illinois'}] + addresses: [{ city: "Chicago", state: "Illinois" }] } ) end diff --git a/actionpack/test/controller/parameters/nested_parameters_test.rb b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb index 7151a8567c..5f86901e30 100644 --- a/actionpack/test/controller/parameters/nested_parameters_test.rb +++ b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb @@ -1,13 +1,13 @@ -require 'abstract_unit' -require 'action_controller/metal/strong_parameters' +require "abstract_unit" +require "action_controller/metal/strong_parameters" -class NestedParametersTest < ActiveSupport::TestCase +class NestedParametersPermitTest < ActiveSupport::TestCase def assert_filtered_out(params, key) assert !params.has_key?(key), "key #{key.inspect} has not been filtered out" end test "permitted nested parameters" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { title: "Romeo and Juliet", authors: [{ @@ -23,11 +23,10 @@ class NestedParametersTest < ActiveSupport::TestCase genre: "Tragedy" }, id: { - isbn: 'x' + isbn: "x" } }, - magazine: "Mjallo!" - }) + magazine: "Mjallo!") permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages }, :id ] @@ -45,74 +44,69 @@ class NestedParametersTest < ActiveSupport::TestCase end test "permitted nested parameters with a string or a symbol as a key" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { - 'authors' => [ - { name: 'William Shakespeare', born: '1564-04-26' }, - { name: 'Christopher Marlowe' } + "authors" => [ + { name: "William Shakespeare", born: "1564-04-26" }, + { name: "Christopher Marlowe" } ] - } - }) + }) - permitted = params.permit book: [ { 'authors' => [ :name ] } ] + permitted = params.permit book: [ { "authors" => [ :name ] } ] - assert_equal 'William Shakespeare', permitted[:book]['authors'][0][:name] - assert_equal 'William Shakespeare', permitted[:book][:authors][0][:name] - assert_equal 'Christopher Marlowe', permitted[:book]['authors'][1][:name] - assert_equal 'Christopher Marlowe', permitted[:book][:authors][1][:name] + assert_equal "William Shakespeare", permitted[:book]["authors"][0][:name] + assert_equal "William Shakespeare", permitted[:book][:authors][0][:name] + assert_equal "Christopher Marlowe", permitted[:book]["authors"][1][:name] + assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name] permitted = params.permit book: [ { authors: [ :name ] } ] - assert_equal 'William Shakespeare', permitted[:book]['authors'][0][:name] - assert_equal 'William Shakespeare', permitted[:book][:authors][0][:name] - assert_equal 'Christopher Marlowe', permitted[:book]['authors'][1][:name] - assert_equal 'Christopher Marlowe', permitted[:book][:authors][1][:name] + assert_equal "William Shakespeare", permitted[:book]["authors"][0][:name] + assert_equal "William Shakespeare", permitted[:book][:authors][0][:name] + assert_equal "Christopher Marlowe", permitted[:book]["authors"][1][:name] + assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name] end test "nested arrays with strings" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { genres: ["Tragedy"] - } - }) + }) - permitted = params.permit book: {genres: []} + permitted = params.permit book: { genres: [] } assert_equal ["Tragedy"], permitted[:book][:genres] end test "permit may specify symbols or strings" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { title: "Romeo and Juliet", author: "William Shakespeare" }, - magazine: "Shakespeare Today" - }) + magazine: "Shakespeare Today") - permitted = params.permit({book: ["title", :author]}, "magazine") + permitted = params.permit({ book: ["title", :author] }, "magazine") assert_equal "Romeo and Juliet", permitted[:book][:title] assert_equal "William Shakespeare", permitted[:book][:author] assert_equal "Shakespeare Today", permitted[:magazine] end test "nested array with strings that should be hashes" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { genres: ["Tragedy"] - } - }) + }) permitted = params.permit book: { genres: :type } assert_empty permitted[:book][:genres] end test "nested array with strings that should be hashes and additional values" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { title: "Romeo and Juliet", genres: ["Tragedy"] - } - }) + }) permitted = params.permit book: [ :title, { genres: :type } ] assert_equal "Romeo and Juliet", permitted[:book][:title] @@ -120,66 +114,62 @@ class NestedParametersTest < ActiveSupport::TestCase end test "nested string that should be a hash" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { genre: "Tragedy" - } - }) + }) permitted = params.permit book: { genre: :type } assert_nil permitted[:book][:genre] end test "fields_for-style nested params" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { authors_attributes: { - :'0' => { name: 'William Shakespeare', age_of_death: '52' }, - :'1' => { name: 'Unattributed Assistant' }, - :'2' => { name: %w(injected names) } + '0': { name: "William Shakespeare", age_of_death: "52" }, + '1': { name: "Unattributed Assistant" }, + '2': { name: %w(injected names) } } - } - }) + }) permitted = params.permit book: { authors_attributes: [ :name ] } - assert_not_nil permitted[:book][:authors_attributes]['0'] - assert_not_nil permitted[:book][:authors_attributes]['1'] - assert_empty permitted[:book][:authors_attributes]['2'] - assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['0'][:name] - assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['1'][:name] + assert_not_nil permitted[:book][:authors_attributes]["0"] + assert_not_nil permitted[:book][:authors_attributes]["1"] + assert_empty permitted[:book][:authors_attributes]["2"] + assert_equal "William Shakespeare", permitted[:book][:authors_attributes]["0"][:name] + assert_equal "Unattributed Assistant", permitted[:book][:authors_attributes]["1"][:name] - assert_filtered_out permitted[:book][:authors_attributes]['0'], :age_of_death + assert_filtered_out permitted[:book][:authors_attributes]["0"], :age_of_death end test "fields_for-style nested params with negative numbers" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { authors_attributes: { - :'-1' => { name: 'William Shakespeare', age_of_death: '52' }, - :'-2' => { name: 'Unattributed Assistant' } + '-1': { name: "William Shakespeare", age_of_death: "52" }, + '-2': { name: "Unattributed Assistant" } } - } - }) + }) permitted = params.permit book: { authors_attributes: [:name] } - assert_not_nil permitted[:book][:authors_attributes]['-1'] - assert_not_nil permitted[:book][:authors_attributes]['-2'] - assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['-1'][:name] - assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['-2'][:name] + assert_not_nil permitted[:book][:authors_attributes]["-1"] + assert_not_nil permitted[:book][:authors_attributes]["-2"] + assert_equal "William Shakespeare", permitted[:book][:authors_attributes]["-1"][:name] + assert_equal "Unattributed Assistant", permitted[:book][:authors_attributes]["-2"][:name] - assert_filtered_out permitted[:book][:authors_attributes]['-1'], :age_of_death + assert_filtered_out permitted[:book][:authors_attributes]["-1"], :age_of_death end test "nested number as key" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( product: { properties: { - '0' => "prop0", - '1' => "prop1" + "0" => "prop0", + "1" => "prop1" } - } - }) - params = params.require(:product).permit(:properties => ["0"]) + }) + params = params.require(:product).permit(properties: ["0"]) assert_not_nil params[:properties]["0"] assert_nil params[:properties]["1"] assert_equal "prop0", params[:properties]["0"] diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb index b75eb0e3bf..728d8e1279 100644 --- a/actionpack/test/controller/parameters/parameters_permit_test.rb +++ b/actionpack/test/controller/parameters/parameters_permit_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'action_dispatch/http/upload' -require 'action_controller/metal/strong_parameters' +require "abstract_unit" +require "action_dispatch/http/upload" +require "action_controller/metal/strong_parameters" class ParametersPermitTest < ActiveSupport::TestCase def assert_filtered_out(params, key) @@ -10,24 +10,24 @@ class ParametersPermitTest < ActiveSupport::TestCase setup do @params = ActionController::Parameters.new( person: { - age: '32', + age: "32", name: { - first: 'David', - last: 'Heinemeier Hansson' + first: "David", + last: "Heinemeier Hansson" }, - addresses: [{city: 'Chicago', state: 'Illinois'}] + addresses: [{ city: "Chicago", state: "Illinois" }] } ) @struct_fields = [] %w(0 1 12).each do |number| - ['', 'i', 'f'].each do |suffix| + ["", "i", "f"].each do |suffix| @struct_fields << "sf(#{number}#{suffix})" end end end - def walk_permitted params + def walk_permitted(params) params.each do |k,v| case v when ActionController::Parameters @@ -38,25 +38,25 @@ class ParametersPermitTest < ActiveSupport::TestCase end end - test 'iteration should not impact permit' do - hash = {"foo"=>{"bar"=>{"0"=>{"baz"=>"hello", "zot"=>"1"}}}} + test "iteration should not impact permit" do + hash = { "foo"=>{ "bar"=>{ "0"=>{ "baz"=>"hello", "zot"=>"1" } } } } params = ActionController::Parameters.new(hash) walk_permitted params sanitized = params[:foo].permit(bar: [:baz]) - assert_equal({"0"=>{"baz"=>"hello"}}, sanitized[:bar].to_unsafe_h) + assert_equal({ "0"=>{ "baz"=>"hello" } }, sanitized[:bar].to_unsafe_h) end - test 'if nothing is permitted, the hash becomes empty' do - params = ActionController::Parameters.new(id: '1234') + test "if nothing is permitted, the hash becomes empty" do + params = ActionController::Parameters.new(id: "1234") permitted = params.permit assert permitted.permitted? assert permitted.empty? end - test 'key: permitted scalar values' do - values = ['a', :a, nil] + test "key: permitted scalar values" do + values = ["a", :a, nil] values += [0, 1.0, 2**128, BigDecimal.new(1)] values += [true, false] values += [Date.today, Time.now, DateTime.now] @@ -76,15 +76,15 @@ class ParametersPermitTest < ActiveSupport::TestCase end end - test 'key: unknown keys are filtered out' do - params = ActionController::Parameters.new(id: '1234', injected: 'injected') + test "key: unknown keys are filtered out" do + params = ActionController::Parameters.new(id: "1234", injected: "injected") permitted = params.permit(:id) - assert_equal '1234', permitted[:id] + assert_equal "1234", permitted[:id] assert_filtered_out permitted, :injected end - test 'key: arrays are filtered out' do - [[], [1], ['1']].each do |array| + test "key: arrays are filtered out" do + [[], [1], ["1"]].each do |array| params = ActionController::Parameters.new(id: array) permitted = params.permit(:id) assert_filtered_out permitted, :id @@ -97,8 +97,8 @@ class ParametersPermitTest < ActiveSupport::TestCase end end - test 'key: hashes are filtered out' do - [{}, {foo: 1}, {foo: 'bar'}].each do |hash| + test "key: hashes are filtered out" do + [{}, { foo: 1 }, { foo: "bar" }].each do |hash| params = ActionController::Parameters.new(id: hash) permitted = params.permit(:id) assert_filtered_out permitted, :id @@ -111,7 +111,7 @@ class ParametersPermitTest < ActiveSupport::TestCase end end - test 'key: non-permitted scalar values are filtered out' do + test "key: non-permitted scalar values are filtered out" do params = ActionController::Parameters.new(id: Object.new) permitted = params.permit(:id) assert_filtered_out permitted, :id @@ -123,19 +123,19 @@ class ParametersPermitTest < ActiveSupport::TestCase end end - test 'key: it is not assigned if not present in params' do - params = ActionController::Parameters.new(name: 'Joe') + test "key: it is not assigned if not present in params" do + params = ActionController::Parameters.new(name: "Joe") permitted = params.permit(:id) assert !permitted.has_key?(:id) end - test 'key to empty array: empty arrays pass' do + test "key to empty array: empty arrays pass" do params = ActionController::Parameters.new(id: []) permitted = params.permit(id: []) assert_equal [], permitted[:id] end - test 'do not break params filtering on nil values' do + test "do not break params filtering on nil values" do params = ActionController::Parameters.new(a: 1, b: [1, 2, 3], c: nil) permitted = params.permit(:a, c: [], b: []) @@ -144,24 +144,24 @@ class ParametersPermitTest < ActiveSupport::TestCase assert_equal nil, permitted[:c] end - test 'key to empty array: arrays of permitted scalars pass' do - [['foo'], [1], ['foo', 'bar'], [1, 2, 3]].each do |array| + test "key to empty array: arrays of permitted scalars pass" do + [["foo"], [1], ["foo", "bar"], [1, 2, 3]].each do |array| params = ActionController::Parameters.new(id: array) permitted = params.permit(id: []) assert_equal array, permitted[:id] end end - test 'key to empty array: permitted scalar values do not pass' do - ['foo', 1].each do |permitted_scalar| + test "key to empty array: permitted scalar values do not pass" do + ["foo", 1].each do |permitted_scalar| params = ActionController::Parameters.new(id: permitted_scalar) permitted = params.permit(id: []) assert_filtered_out permitted, :id end end - test 'key to empty array: arrays of non-permitted scalar do not pass' do - [[Object.new], [[]], [[1]], [{}], [{id: '1'}]].each do |non_permitted_scalar| + test "key to empty array: arrays of non-permitted scalar do not pass" do + [[Object.new], [[]], [[1]], [{}], [{ id: "1" }]].each do |non_permitted_scalar| params = ActionController::Parameters.new(id: non_permitted_scalar) permitted = params.permit(id: []) assert_filtered_out permitted, :id @@ -181,7 +181,7 @@ class ParametersPermitTest < ActiveSupport::TestCase assert_equal nil, params[:foo] end - test 'hashes in array values get wrapped' do + test "hashes in array values get wrapped" do params = ActionController::Parameters.new(foo: [{}, {}]) params[:foo].each do |hash| assert !hash.permitted? @@ -191,7 +191,7 @@ class ParametersPermitTest < ActiveSupport::TestCase # Strong params has an optimization to avoid looping every time you read # a key whose value is an array and building a new object. We check that # optimization here. - test 'arrays are converted at most once' do + test "arrays are converted at most once" do params = ActionController::Parameters.new(foo: [{}]) assert_same params[:foo], params[:foo] end @@ -202,11 +202,11 @@ class ParametersPermitTest < ActiveSupport::TestCase # This test checks that if we push a hash to an array (in-place modification) # the cache does not get fooled, the hash is still wrapped as strong params, # and not permitted. - test 'mutated arrays are detected' do - params = ActionController::Parameters.new(users: [{id: 1}]) + test "mutated arrays are detected" do + params = ActionController::Parameters.new(users: [{ id: 1 }]) permitted = params.permit(users: [:id]) - permitted[:users] << {injected: 1} + permitted[:users] << { injected: 1 } assert_not permitted[:users].last.permitted? end @@ -220,7 +220,7 @@ class ParametersPermitTest < ActiveSupport::TestCase assert_equal nil, @params.fetch(:foo) { nil } end - test 'KeyError in fetch block should not be covered up' do + test "KeyError in fetch block should not be covered up" do params = ActionController::Parameters.new e = assert_raises(KeyError) do params.fetch(:missing_key) { {}.fetch(:also_missing) } @@ -237,6 +237,13 @@ class ParametersPermitTest < ActiveSupport::TestCase assert @params.merge(a: "b").permitted? end + test "merge with parameters" do + other_params = ActionController::Parameters.new(id: "1234").permit! + merged_params = @params.merge(other_params) + + assert merged_params[:id] + end + test "modifying the parameters" do @params[:person][:hometown] = "Chicago" @params[:person][:family] = { brother: "Jonas" } @@ -245,11 +252,6 @@ class ParametersPermitTest < ActiveSupport::TestCase assert_equal "Jonas", @params[:person][:family][:brother] end - test "permit state is kept on a dup" do - @params.permit! - assert_equal @params.permitted?, @params.dup.permitted? - end - test "permit is recursive" do @params.permit! assert @params.permitted? @@ -261,9 +263,9 @@ class ParametersPermitTest < ActiveSupport::TestCase test "permitted takes a default value when Parameters.permit_all_parameters is set" do begin ActionController::Parameters.permit_all_parameters = true - params = ActionController::Parameters.new({ person: { + params = ActionController::Parameters.new(person: { age: "32", name: { first: "David", last: "Heinemeier Hansson" } - }}) + }) assert params.slice(:person).permitted? assert params[:person][:name].permitted? @@ -320,10 +322,10 @@ class ParametersPermitTest < ActiveSupport::TestCase end test "to_unsafe_h returns unfiltered params even after accessing few keys" do - params = ActionController::Parameters.new("f"=>{"language_facet"=>["Tibetan"]}) - expected = {"f"=>{"language_facet"=>["Tibetan"]}} + params = ActionController::Parameters.new("f"=>{ "language_facet"=>["Tibetan"] }) + expected = { "f"=>{ "language_facet"=>["Tibetan"] } } - assert params['f'].is_a? ActionController::Parameters + assert params["f"].is_a? ActionController::Parameters assert_equal expected, params.to_unsafe_h end @@ -334,10 +336,10 @@ class ParametersPermitTest < ActiveSupport::TestCase end.new params = ActionController::Parameters.new(prem: { likes: %i( dancing ) }) - assert_equal({ 'prem' => { 'likes' => %i( dancing ) } }, params.permit!.to_h) + assert_equal({ "prem" => { "likes" => %i( dancing ) } }, params.permit!.to_h) params = ActionController::Parameters.new(companies: [ company, :acme ]) - assert_equal({ 'companies' => [ company, :acme ] }, params.permit!.to_h) + assert_equal({ "companies" => [ company, :acme ] }, params.permit!.to_h) assert_not company.dupped end @@ -348,16 +350,16 @@ class ParametersPermitTest < ActiveSupport::TestCase end.new params = ActionController::Parameters.new(prem: { likes: %i( dancing ) }) - assert_equal({ 'prem' => { 'likes' => %i( dancing ) } }, params.to_unsafe_h) + assert_equal({ "prem" => { "likes" => %i( dancing ) } }, params.to_unsafe_h) params = ActionController::Parameters.new(companies: [ company, :acme ]) - assert_equal({ 'companies' => [ company, :acme ] }, params.to_unsafe_h) + assert_equal({ "companies" => [ company, :acme ] }, params.to_unsafe_h) assert_not company.dupped end test "include? returns true when the key is present" do assert @params.include? :person - assert @params.include? 'person' + assert @params.include? "person" assert_not @params.include? :gorilla end @@ -369,4 +371,10 @@ class ParametersPermitTest < ActiveSupport::TestCase refute params.permit(foo: [:bar]).has_key?(:foo) refute params.permit(foo: :bar).has_key?(:foo) end + + test "#permitted? is false by default" do + params = ActionController::Parameters.new + + assert_equal false, params.permitted? + end end diff --git a/actionpack/test/controller/parameters/raise_on_unpermitted_params_test.rb b/actionpack/test/controller/parameters/raise_on_unpermitted_params_test.rb index f9cc9f96f1..8fab7b28e9 100644 --- a/actionpack/test/controller/parameters/raise_on_unpermitted_params_test.rb +++ b/actionpack/test/controller/parameters/raise_on_unpermitted_params_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_controller/metal/strong_parameters' +require "abstract_unit" +require "action_controller/metal/strong_parameters" class RaiseOnUnpermittedParamsTest < ActiveSupport::TestCase def setup @@ -11,10 +11,9 @@ class RaiseOnUnpermittedParamsTest < ActiveSupport::TestCase end test "raises on unexpected params" do - params = ActionController::Parameters.new({ + params = ActionController::Parameters.new( book: { pages: 65 }, - fishing: "Turnips" - }) + fishing: "Turnips") assert_raises(ActionController::UnpermittedParameters) do params.permit(book: [:pages]) @@ -22,9 +21,8 @@ class RaiseOnUnpermittedParamsTest < ActiveSupport::TestCase end test "raises on unexpected nested params" do - params = ActionController::Parameters.new({ - book: { pages: 65, title: "Green Cats and where to find then." } - }) + params = ActionController::Parameters.new( + book: { pages: 65, title: "Green Cats and where to find then." }) assert_raises(ActionController::UnpermittedParameters) do params.permit(book: [:pages]) diff --git a/actionpack/test/controller/parameters/serialization_test.rb b/actionpack/test/controller/parameters/serialization_test.rb new file mode 100644 index 0000000000..6fba2fde91 --- /dev/null +++ b/actionpack/test/controller/parameters/serialization_test.rb @@ -0,0 +1,53 @@ +require "abstract_unit" +require "action_controller/metal/strong_parameters" +require "active_support/core_ext/string/strip" + +class ParametersSerializationTest < ActiveSupport::TestCase + setup do + @old_permitted_parameters = ActionController::Parameters.permit_all_parameters + ActionController::Parameters.permit_all_parameters = false + end + + teardown do + ActionController::Parameters.permit_all_parameters = @old_permitted_parameters + end + + test "yaml serialization" do + params = ActionController::Parameters.new(key: :value) + yaml_dump = YAML.dump(params) + assert_match("--- !ruby/object:ActionController::Parameters", yaml_dump) + assert_match(/parameters: !ruby\/hash:ActiveSupport::HashWithIndifferentAccess\n\s+key: :value/, yaml_dump) + assert_match("permitted: false", yaml_dump) + end + + test "yaml deserialization" do + params = ActionController::Parameters.new(key: :value) + roundtripped = YAML.load(YAML.dump(params)) + + assert_equal params, roundtripped + assert_not roundtripped.permitted? + end + + test "yaml backwardscompatible with psych 2.0.8 format" do + params = YAML.load <<-end_of_yaml.strip_heredoc + --- !ruby/hash:ActionController::Parameters + key: :value + end_of_yaml + + assert_equal :value, params[:key] + assert_not params.permitted? + end + + test "yaml backwardscompatible with psych 2.0.9+ format" do + params = YAML.load(<<-end_of_yaml.strip_heredoc) + --- !ruby/hash-with-ivars:ActionController::Parameters + elements: + key: :value + ivars: + :@permitted: false + end_of_yaml + + assert_equal :value, params[:key] + assert_not params.permitted? + end +end diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index 7226beed26..1549405fe7 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -1,10 +1,10 @@ -require 'abstract_unit' +require "abstract_unit" module Admin; class User; end; end module ParamsWrapperTestHelp def with_default_wrapper_options(&block) - @controller.class._set_wrapper_options({:format => [:json]}) + @controller.class._set_wrapper_options(format: [:json]) @controller.class.inherited(@controller.class) yield end @@ -48,17 +48,17 @@ class ParamsWrapperTest < ActionController::TestCase def test_filtered_parameters with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu' } - assert_equal @request.filtered_parameters, { 'controller' => 'params_wrapper_test/users', 'action' => 'parse', 'username' => 'sikachu', 'user' => { 'username' => 'sikachu' } } + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu" } + assert_equal @request.filtered_parameters, "controller" => "params_wrapper_test/users", "action" => "parse", "username" => "sikachu", "user" => { "username" => "sikachu" } end end def test_derived_name_from_controller with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu' } - assert_parameters({ 'username' => 'sikachu', 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu" } + assert_parameters("username" => "sikachu", "user" => { "username" => "sikachu" }) end end @@ -66,9 +66,9 @@ class ParamsWrapperTest < ActionController::TestCase with_default_wrapper_options do UsersController.wrap_parameters :person - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu' } - assert_parameters({ 'username' => 'sikachu', 'person' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu" } + assert_parameters("username" => "sikachu", "person" => { "username" => "sikachu" }) end end @@ -76,99 +76,99 @@ class ParamsWrapperTest < ActionController::TestCase with_default_wrapper_options do UsersController.wrap_parameters Person - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu' } - assert_parameters({ 'username' => 'sikachu', 'person' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu" } + assert_parameters("username" => "sikachu", "person" => { "username" => "sikachu" }) end end def test_specify_include_option with_default_wrapper_options do - UsersController.wrap_parameters :include => :username + UsersController.wrap_parameters include: :username - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "user" => { "username" => "sikachu" }) end end def test_specify_exclude_option with_default_wrapper_options do - UsersController.wrap_parameters :exclude => :title + UsersController.wrap_parameters exclude: :title - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "user" => { "username" => "sikachu" }) end end def test_specify_both_wrapper_name_and_include_option with_default_wrapper_options do - UsersController.wrap_parameters :person, :include => :username + UsersController.wrap_parameters :person, include: :username - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "person" => { "username" => "sikachu" }) end end def test_not_enabled_format with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/xml' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer' }) + @request.env["CONTENT_TYPE"] = "application/xml" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer") end end def test_wrap_parameters_false with_default_wrapper_options do UsersController.wrap_parameters false - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer' }) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer") end end def test_specify_format with_default_wrapper_options do - UsersController.wrap_parameters :format => :xml + UsersController.wrap_parameters format: :xml - @request.env['CONTENT_TYPE'] = 'application/xml' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }}) + @request.env["CONTENT_TYPE"] = "application/xml" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "user" => { "username" => "sikachu", "title" => "Developer" }) end end def test_not_wrap_reserved_parameters with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'authenticity_token' => 'pwned', '_method' => 'put', 'utf8' => '☃', 'username' => 'sikachu' } - assert_parameters({ 'authenticity_token' => 'pwned', '_method' => 'put', 'utf8' => '☃', 'username' => 'sikachu', 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "authenticity_token" => "pwned", "_method" => "put", "utf8" => "☃", "username" => "sikachu" } + assert_parameters("authenticity_token" => "pwned", "_method" => "put", "utf8" => "☃", "username" => "sikachu", "user" => { "username" => "sikachu" }) end end def test_no_double_wrap_if_key_exists with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'user' => { 'username' => 'sikachu' }} - assert_parameters({ 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "user" => { "username" => "sikachu" } } + assert_parameters("user" => { "username" => "sikachu" }) end end def test_nested_params with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'person' => { 'username' => 'sikachu' }} - assert_parameters({ 'person' => { 'username' => 'sikachu' }, 'user' => {'person' => { 'username' => 'sikachu' }}}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "person" => { "username" => "sikachu" } } + assert_parameters("person" => { "username" => "sikachu" }, "user" => { "person" => { "username" => "sikachu" } }) end end def test_derived_wrapped_keys_from_matching_model assert_called(User, :attribute_names, times: 2, returns: ["username"]) do with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "user" => { "username" => "sikachu" }) end end end @@ -178,37 +178,37 @@ class ParamsWrapperTest < ActionController::TestCase assert_called(Person, :attribute_names, times: 2, returns: ["username"]) do UsersController.wrap_parameters Person - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "person" => { "username" => "sikachu" }) end end end def test_not_wrapping_abstract_model with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "user" => { "username" => "sikachu", "title" => "Developer" }) end end def test_preserves_query_string_params with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - get :parse, params: { 'user' => { 'username' => 'nixon' } } + @request.env["CONTENT_TYPE"] = "application/json" + get :parse, params: { "user" => { "username" => "nixon" } } assert_parameters( - {'user' => { 'username' => 'nixon' } } + "user" => { "username" => "nixon" } ) end end def test_empty_parameter_set with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' + @request.env["CONTENT_TYPE"] = "application/json" post :parse, params: {} assert_parameters( - {'user' => { } } + "user" => {} ) end end @@ -252,9 +252,9 @@ class NamespacedParamsWrapperTest < ActionController::TestCase def test_derived_name_from_controller with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu' } - assert_parameters({'username' => 'sikachu', 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu" } + assert_parameters("username" => "sikachu", "user" => { "username" => "sikachu" }) end end @@ -262,9 +262,9 @@ class NamespacedParamsWrapperTest < ActionController::TestCase Admin.const_set(:User, Class.new(SampleOne)) begin with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "user" => { "username" => "sikachu" }) end ensure Admin.send :remove_const, :User @@ -275,15 +275,14 @@ class NamespacedParamsWrapperTest < ActionController::TestCase Object.const_set(:User, Class.new(SampleTwo)) begin with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'title' => 'Developer' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "title" => "Developer" } + assert_parameters("username" => "sikachu", "title" => "Developer", "user" => { "title" => "Developer" }) end ensure Object.send :remove_const, :User end end - end class AnonymousControllerParamsWrapperTest < ActionController::TestCase @@ -302,18 +301,18 @@ class AnonymousControllerParamsWrapperTest < ActionController::TestCase def test_does_not_implicitly_wrap_params with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu' } - assert_parameters({ 'username' => 'sikachu' }) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu" } + assert_parameters("username" => "sikachu") end end def test_does_wrap_params_if_name_provided with_default_wrapper_options do - @controller.class.wrap_parameters(:name => "guest") - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu' } - assert_parameters({ 'username' => 'sikachu', 'guest' => { 'username' => 'sikachu' }}) + @controller.class.wrap_parameters(name: "guest") + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu" } + assert_parameters("username" => "sikachu", "guest" => { "username" => "sikachu" }) end end end @@ -323,7 +322,7 @@ class IrregularInflectionParamsWrapperTest < ActionController::TestCase class ParamswrappernewsItem def self.attribute_names - ['test_attr'] + ["test_attr"] end end @@ -343,24 +342,24 @@ class IrregularInflectionParamsWrapperTest < ActionController::TestCase def test_uses_model_attribute_names_with_irregular_inflection with_dup do ActiveSupport::Inflector.inflections do |inflect| - inflect.irregular 'paramswrappernews_item', 'paramswrappernews' + inflect.irregular "paramswrappernews_item", "paramswrappernews" end with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'test_attr' => 'test_value' } - assert_parameters({ 'username' => 'sikachu', 'test_attr' => 'test_value', 'paramswrappernews_item' => { 'test_attr' => 'test_value' }}) + @request.env["CONTENT_TYPE"] = "application/json" + post :parse, params: { "username" => "sikachu", "test_attr" => "test_value" } + assert_parameters("username" => "sikachu", "test_attr" => "test_value", "paramswrappernews_item" => { "test_attr" => "test_value" }) end end end private - def with_dup - original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en] - ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original.dup) - yield - ensure - ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original) - end + def with_dup + original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en] + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original.dup) + yield + ensure + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original) + end end diff --git a/actionpack/test/controller/permitted_params_test.rb b/actionpack/test/controller/permitted_params_test.rb index 7c753a45a5..6205a09816 100644 --- a/actionpack/test/controller/permitted_params_test.rb +++ b/actionpack/test/controller/permitted_params_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class PeopleController < ActionController::Base def create diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb index 4af3c628d0..0e61b92bcf 100644 --- a/actionpack/test/controller/redirect_test.rb +++ b/actionpack/test/controller/redirect_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class Workshop extend ActiveModel::Naming @@ -21,43 +21,39 @@ end class RedirectController < ActionController::Base # empty method not used anywhere to ensure methods like # `status` and `location` aren't called on `redirect_to` calls - def status; render plain: 'called status'; end - def location; render plain: 'called location'; end + def status; render plain: "called status"; end + def location; render plain: "called location"; end def simple_redirect - redirect_to :action => "hello_world" + redirect_to action: "hello_world" end def redirect_with_status - redirect_to({:action => "hello_world", :status => 301}) + redirect_to(action: "hello_world", status: 301) end def redirect_with_status_hash - redirect_to({:action => "hello_world"}, {:status => 301}) + redirect_to({ action: "hello_world" }, status: 301) end def redirect_with_protocol - redirect_to :action => "hello_world", :protocol => "https" + redirect_to action: "hello_world", protocol: "https" end def url_redirect_with_status - redirect_to("http://www.example.com", :status => :moved_permanently) + redirect_to("http://www.example.com", status: :moved_permanently) end def url_redirect_with_status_hash - redirect_to("http://www.example.com", {:status => 301}) + redirect_to("http://www.example.com", status: 301) end def relative_url_redirect_with_status - redirect_to("/things/stuff", :status => :found) + redirect_to("/things/stuff", status: :found) end def relative_url_redirect_with_status_hash - redirect_to("/things/stuff", {:status => 301}) - end - - def redirect_to_back_with_status - redirect_to :back, :status => 307 + redirect_to("/things/stuff", status: 301) end def redirect_back_with_status @@ -65,11 +61,11 @@ class RedirectController < ActionController::Base end def host_redirect - redirect_to :action => "other_host", :only_path => false, :host => 'other.test.host' + redirect_to action: "other_host", only_path: false, host: "other.test.host" end def module_redirect - redirect_to :controller => 'module_test/module_redirect', :action => "hello_world" + redirect_to controller: "module_test/module_redirect", action: "hello_world" end def redirect_to_url @@ -88,10 +84,6 @@ class RedirectController < ActionController::Base redirect_to "//www.rubyonrails.org/" end - def redirect_to_back - redirect_to :back - end - def redirect_to_existing_record redirect_to Workshop.new(5) end @@ -105,7 +97,7 @@ class RedirectController < ActionController::Base end def redirect_to_params - redirect_to ActionController::Parameters.new(status: 200, protocol: 'javascript', f: '%0Aeval(name)') + redirect_to ActionController::Parameters.new(status: 200, protocol: "javascript", f: "%0Aeval(name)") end def redirect_to_with_block @@ -118,7 +110,7 @@ class RedirectController < ActionController::Base end def redirect_to_with_block_and_options - redirect_to proc { {:action => "hello_world"} } + redirect_to proc { { action: "hello_world" } } end def redirect_with_header_break @@ -133,7 +125,7 @@ class RedirectController < ActionController::Base protected def dashbord_url(id, message) - url_for :action => "dashboard", :params => { "id" => id, "message" => message } + url_for action: "dashboard", params: { "id" => id, "message" => message } end end @@ -206,21 +198,10 @@ class RedirectTest < ActionController::TestCase assert_equal "http://test.host/things/stuff", redirect_to_url end - def test_redirect_to_back_with_status - @request.env["HTTP_REFERER"] = "http://www.example.com/coming/from" - - assert_deprecated do - get :redirect_to_back_with_status - end - - assert_response 307 - assert_equal "http://www.example.com/coming/from", redirect_to_url - end - def test_simple_redirect_using_options get :host_redirect assert_response :redirect - assert_redirected_to :action => "other_host", :only_path => false, :host => 'other.test.host' + assert_redirected_to action: "other_host", only_path: false, host: "other.test.host" end def test_module_redirect @@ -232,7 +213,7 @@ class RedirectTest < ActionController::TestCase def test_module_redirect_using_options get :module_redirect assert_response :redirect - assert_redirected_to :controller => 'module_test/module_redirect', :action => 'hello_world' + assert_redirected_to controller: "module_test/module_redirect", action: "hello_world" end def test_redirect_to_url @@ -259,29 +240,6 @@ class RedirectTest < ActionController::TestCase assert_equal "//www.rubyonrails.org/", redirect_to_url end - def test_redirect_to_back - @request.env["HTTP_REFERER"] = "http://www.example.com/coming/from" - - assert_deprecated do - get :redirect_to_back - end - - assert_response :redirect - assert_equal "http://www.example.com/coming/from", redirect_to_url - end - - def test_redirect_to_back_with_no_referer - assert_raise(ActionController::RedirectBackError) { - @request.env["HTTP_REFERER"] = nil - - assert_deprecated do - get :redirect_to_back - end - - get :redirect_to_back - } - end - def test_redirect_back referer = "http://www.example.com/coming/from" @request.env["HTTP_REFERER"] = referer @@ -305,7 +263,7 @@ class RedirectTest < ActionController::TestCase resources :workshops ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end @@ -349,7 +307,7 @@ class RedirectTest < ActionController::TestCase with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end @@ -364,7 +322,7 @@ end module ModuleTest class ModuleRedirectController < ::RedirectController def module_redirect - redirect_to :controller => '/redirect', :action => "hello_world" + redirect_to controller: "/redirect", action: "hello_world" end end @@ -380,7 +338,7 @@ module ModuleTest def test_simple_redirect_using_options get :host_redirect assert_response :redirect - assert_redirected_to :action => "other_host", :only_path => false, :host => 'other.test.host' + assert_redirected_to action: "other_host", only_path: false, host: "other.test.host" end def test_module_redirect @@ -392,7 +350,7 @@ module ModuleTest def test_module_redirect_using_options get :module_redirect assert_response :redirect - assert_redirected_to :controller => '/redirect', :action => "hello_world" + assert_redirected_to controller: "/redirect", action: "hello_world" end end end diff --git a/actionpack/test/controller/render_js_test.rb b/actionpack/test/controller/render_js_test.rb index 6b661de064..290218d4a2 100644 --- a/actionpack/test/controller/render_js_test.rb +++ b/actionpack/test/controller/render_js_test.rb @@ -1,21 +1,21 @@ -require 'abstract_unit' -require 'controller/fake_models' -require 'pathname' +require "abstract_unit" +require "controller/fake_models" +require "pathname" class RenderJSTest < ActionController::TestCase class TestController < ActionController::Base protect_from_forgery def self.controller_path - 'test' + "test" end def render_vanilla_js_hello - render :js => "alert('hello')" + render js: "alert('hello')" end def show_partial - render :partial => 'partial' + render partial: "partial" end end @@ -28,7 +28,7 @@ class RenderJSTest < ActionController::TestCase end def test_should_render_js_partial - get :show_partial, format: 'js', xhr: true - assert_equal 'partial js', @response.body + get :show_partial, format: "js", xhr: true + assert_equal "partial js", @response.body end end diff --git a/actionpack/test/controller/render_json_test.rb b/actionpack/test/controller/render_json_test.rb index 3773900cc4..213829bd9e 100644 --- a/actionpack/test/controller/render_json_test.rb +++ b/actionpack/test/controller/render_json_test.rb @@ -1,18 +1,18 @@ -require 'abstract_unit' -require 'controller/fake_models' -require 'active_support/logger' -require 'pathname' +require "abstract_unit" +require "controller/fake_models" +require "active_support/logger" +require "pathname" class RenderJsonTest < ActionController::TestCase class JsonRenderable def as_json(options={}) - hash = { :a => :b, :c => :d, :e => :f } + hash = { a: :b, c: :d, e: :f } hash.except!(*options[:except]) if options[:except] hash end def to_json(options = {}) - super :except => [:c, :e] + super except: [:c, :e] end end @@ -20,47 +20,47 @@ class RenderJsonTest < ActionController::TestCase protect_from_forgery def self.controller_path - 'test' + "test" end def render_json_nil - render :json => nil + render json: nil end def render_json_render_to_string - render plain: render_to_string(json: '[]') + render plain: render_to_string(json: "[]") end def render_json_hello_world - render :json => ActiveSupport::JSON.encode(:hello => 'world') + render json: ActiveSupport::JSON.encode(hello: "world") end def render_json_hello_world_with_status - render :json => ActiveSupport::JSON.encode(:hello => 'world'), :status => 401 + render json: ActiveSupport::JSON.encode(hello: "world"), status: 401 end def render_json_hello_world_with_callback - render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert' + render json: ActiveSupport::JSON.encode(hello: "world"), callback: "alert" end def render_json_with_custom_content_type - render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript' + render json: ActiveSupport::JSON.encode(hello: "world"), content_type: "text/javascript" end def render_symbol_json - render :json => ActiveSupport::JSON.encode(:hello => 'world') + render json: ActiveSupport::JSON.encode(hello: "world") end def render_json_with_render_to_string - render :json => {:hello => render_to_string(:partial => 'partial')} + render json: { hello: render_to_string(partial: "partial") } end def render_json_with_extra_options - render :json => JsonRenderable.new, :except => [:c, :e] + render json: JsonRenderable.new, except: [:c, :e] end def render_json_without_options - render :json => JsonRenderable.new + render json: JsonRenderable.new end end @@ -77,20 +77,19 @@ class RenderJsonTest < ActionController::TestCase def test_render_json_nil get :render_json_nil - assert_equal 'null', @response.body - assert_equal 'application/json', @response.content_type + assert_equal "null", @response.body + assert_equal "application/json", @response.content_type end def test_render_json_render_to_string get :render_json_render_to_string - assert_equal '[]', @response.body + assert_equal "[]", @response.body end - def test_render_json get :render_json_hello_world assert_equal '{"hello":"world"}', @response.body - assert_equal 'application/json', @response.content_type + assert_equal "application/json", @response.content_type end def test_render_json_with_status @@ -102,31 +101,31 @@ class RenderJsonTest < ActionController::TestCase def test_render_json_with_callback get :render_json_hello_world_with_callback, xhr: true assert_equal '/**/alert({"hello":"world"})', @response.body - assert_equal 'text/javascript', @response.content_type + assert_equal "text/javascript", @response.content_type end def test_render_json_with_custom_content_type get :render_json_with_custom_content_type, xhr: true assert_equal '{"hello":"world"}', @response.body - assert_equal 'text/javascript', @response.content_type + assert_equal "text/javascript", @response.content_type end def test_render_symbol_json get :render_symbol_json assert_equal '{"hello":"world"}', @response.body - assert_equal 'application/json', @response.content_type + assert_equal "application/json", @response.content_type end def test_render_json_with_render_to_string get :render_json_with_render_to_string assert_equal '{"hello":"partial html"}', @response.body - assert_equal 'application/json', @response.content_type + assert_equal "application/json", @response.content_type end def test_render_json_forwards_extra_options get :render_json_with_extra_options assert_equal '{"a":"b"}', @response.body - assert_equal 'application/json', @response.content_type + assert_equal "application/json", @response.content_type end def test_render_json_calls_to_json_from_object diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 8d3134630d..76139d59e2 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -1,15 +1,18 @@ -require 'abstract_unit' -require 'controller/fake_models' +require "abstract_unit" +require "controller/fake_models" class TestControllerWithExtraEtags < ActionController::Base + def self.controller_name; "test"; end + def self.controller_path; "test"; end + etag { nil } - etag { 'ab' } + etag { "ab" } etag { :cde } etag { [:f] } etag { nil } def fresh - render plain: "stale" if stale?(etag: '123', template: false) + render plain: "stale" if stale?(etag: "123", template: false) end def array @@ -17,14 +20,18 @@ class TestControllerWithExtraEtags < ActionController::Base end def strong - render plain: "stale" if stale?(strong_etag: 'strong') + render plain: "stale" if stale?(strong_etag: "strong", template: false) end def with_template - if stale? template: 'test/hello_world' - render plain: 'stale' + if stale? template: "test/hello_world" + render plain: "stale" end end + + def with_implicit_template + fresh_when(etag: "123") + end end class ImplicitRenderTestController < ActionController::Base @@ -35,6 +42,14 @@ class ImplicitRenderTestController < ActionController::Base end end +module Namespaced + class ImplicitRenderTestController < ActionController::Base + def hello_world + fresh_when(etag: "abc") + end + end +end + class TestController < ActionController::Base protect_from_forgery @@ -56,8 +71,8 @@ class TestController < ActionController::Base end def conditional_hello - if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123]) - render :action => 'hello_world' + if stale?(last_modified: Time.now.utc.beginning_of_day, etag: [:foo, 123]) + render action: "hello_world" end end @@ -65,7 +80,7 @@ class TestController < ActionController::Base record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day, "foo/123") if stale?(record) - render :action => 'hello_world' + render action: "hello_world" end end @@ -100,70 +115,58 @@ class TestController < ActionController::Base old_record = Struct.new(:updated_at, :cache_key).new(ts - 1.day, "bar/123") if stale?(Collection.new([record, old_record])) - render action: 'hello_world' + render action: "hello_world" end end def conditional_hello_with_expires_in expires_in 60.1.seconds - render :action => 'hello_world' + render action: "hello_world" end def conditional_hello_with_expires_in_with_public - expires_in 1.minute, :public => true - render :action => 'hello_world' + expires_in 1.minute, public: true + render action: "hello_world" end def conditional_hello_with_expires_in_with_must_revalidate - expires_in 1.minute, :must_revalidate => true - render :action => 'hello_world' + expires_in 1.minute, must_revalidate: true + render action: "hello_world" end def conditional_hello_with_expires_in_with_public_and_must_revalidate - expires_in 1.minute, :public => true, :must_revalidate => true - render :action => 'hello_world' + expires_in 1.minute, public: true, must_revalidate: true + render action: "hello_world" end def conditional_hello_with_expires_in_with_public_with_more_keys - expires_in 1.minute, :public => true, 's-maxage' => 5.hours - render :action => 'hello_world' + expires_in 1.minute, :public => true, "s-maxage" => 5.hours + render action: "hello_world" end def conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax - expires_in 1.minute, :public => true, :private => nil, 's-maxage' => 5.hours - render :action => 'hello_world' + expires_in 1.minute, :public => true, :private => nil, "s-maxage" => 5.hours + render action: "hello_world" end def conditional_hello_with_expires_now expires_now - render :action => 'hello_world' + render action: "hello_world" end def conditional_hello_with_cache_control_headers - response.headers['Cache-Control'] = 'no-transform' + response.headers["Cache-Control"] = "no-transform" expires_now - render :action => 'hello_world' - end - - def respond_with_empty_body - render nothing: true + render action: "hello_world" end def conditional_hello_with_bangs - render :action => 'hello_world' + render action: "hello_world" end - before_action :handle_last_modified_and_etags, :only=>:conditional_hello_with_bangs + before_action :handle_last_modified_and_etags, only: :conditional_hello_with_bangs def handle_last_modified_and_etags - fresh_when(:last_modified => Time.now.utc.beginning_of_day, :etag => [ :foo, 123 ]) - end - - def head_with_status_hash - head status: :created - end - - def head_with_hash_does_not_include_status - head warning: :deprecated + fresh_when(last_modified: Time.now.utc.beginning_of_day, etag: [ :foo, 123 ]) end def head_created @@ -171,19 +174,19 @@ class TestController < ActionController::Base end def head_created_with_application_json_content_type - head :created, :content_type => "application/json" + head :created, content_type: "application/json" end def head_ok_with_image_png_content_type - head :ok, :content_type => "image/png" + head :ok, content_type: "image/png" end def head_with_location_header - head :ok, :location => "/foo" + head :ok, location: "/foo" end def head_with_location_object - head :ok, :location => Customer.new("david", 1) + head :ok, location: Customer.new("david", 1) end def head_with_symbolic_status @@ -199,20 +202,20 @@ class TestController < ActionController::Base end def head_with_custom_header - head :ok, :x_custom_header => "something" + head :ok, x_custom_header: "something" end def head_with_www_authenticate_header - head :ok, 'WWW-Authenticate' => 'something' + head :ok, "WWW-Authenticate" => "something" end def head_with_status_code_first - head :forbidden, :x_custom_header => "something" + head :forbidden, x_custom_header: "something" end def head_and_return - head :ok and return - raise 'should not reach this line' + head(:ok) && return + raise "should not reach this line" end def head_with_no_content @@ -232,7 +235,7 @@ class TestController < ActionController::Base def determine_layout case action_name - when "hello_world", "layout_test", "rendering_without_layout", + when "hello_world", "layout_test", "rendering_without_layout", "rendering_nothing_on_layout", "render_text_hello_world", "render_text_hello_world_with_layout", "hello_world_with_layout_false", @@ -242,22 +245,35 @@ class TestController < ActionController::Base "render_with_explicit_string_template", "update_page", "update_page_with_instance_variables" - "layouts/standard" - when "action_talk_to_layout", "layout_overriding_layout" - "layouts/talk_from_action" - when "render_implicit_html_template_from_xhr_request" - (request.xhr? ? 'layouts/xhr' : 'layouts/standard') + "layouts/standard" + when "action_talk_to_layout", "layout_overriding_layout" + "layouts/talk_from_action" + when "render_implicit_html_template_from_xhr_request" + (request.xhr? ? "layouts/xhr" : "layouts/standard") end end end +module TemplateModificationHelper + private + def modify_template(name) + path = File.expand_path("../../fixtures/#{name}.erb", __FILE__) + original = File.read(path) + File.write(path, "#{original} Modified!") + ActionView::LookupContext::DetailsKey.clear + yield + ensure + File.write(path, original) + end +end + class MetalTestController < ActionController::Metal include AbstractController::Rendering include ActionView::Rendering include ActionController::Rendering def accessing_logger_in_template - render :inline => "<%= logger.class %>" + render inline: "<%= logger.class %>" end end @@ -271,14 +287,14 @@ class ExpiresInRenderTest < ActionController::TestCase def test_dynamic_render_with_file # This is extremely bad, but should be possible to do. - assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')) + assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")) response = get :dynamic_render_with_file, params: { id: '../\\../test/abstract_unit.rb' } - assert_equal File.read(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')), + assert_equal File.read(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")), response.body end def test_dynamic_render_with_absolute_path - file = Tempfile.new('name') + file = Tempfile.new("name") file.write "secrets!" file.flush assert_raises ActionView::MissingTemplate do @@ -290,7 +306,7 @@ class ExpiresInRenderTest < ActionController::TestCase end def test_dynamic_render - assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')) + assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")) assert_raises ActionView::MissingTemplate do get :dynamic_render, params: { id: '../\\../test/abstract_unit.rb' } end @@ -298,9 +314,9 @@ class ExpiresInRenderTest < ActionController::TestCase def test_permitted_dynamic_render_file_hash skip "FIXME: this test passes on 4-2-stable but not master. Why?" - assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')) + assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")) response = get :dynamic_render_permit, params: { id: { file: '../\\../test/abstract_unit.rb' } } - assert_equal File.read(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')), + assert_equal File.read(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")), response.body end @@ -351,12 +367,6 @@ class ExpiresInRenderTest < ActionController::TestCase assert_match(/no-transform/, @response.headers["Cache-Control"]) end - def test_render_nothing_deprecated - assert_deprecated do - get :respond_with_empty_body - end - end - def test_date_header_when_expires_in time = Time.mktime(2011,10,30) Time.stub :now, time do @@ -376,7 +386,7 @@ class LastModifiedRenderTest < ActionController::TestCase def test_responds_with_last_modified get :conditional_hello - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_request_not_modified @@ -384,7 +394,7 @@ class LastModifiedRenderTest < ActionController::TestCase get :conditional_hello assert_equal 304, @response.status.to_i assert @response.body.blank? - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_request_not_modified_but_etag_differs @@ -395,16 +405,16 @@ class LastModifiedRenderTest < ActionController::TestCase end def test_request_modified - @request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT' + @request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT" get :conditional_hello assert_equal 200, @response.status.to_i assert @response.body.present? - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_responds_with_last_modified_with_record get :conditional_hello_with_record - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_request_not_modified_with_record @@ -413,7 +423,7 @@ class LastModifiedRenderTest < ActionController::TestCase assert_equal 304, @response.status.to_i assert @response.body.blank? assert_not_nil @response.etag - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_request_not_modified_but_etag_differs_with_record @@ -424,16 +434,16 @@ class LastModifiedRenderTest < ActionController::TestCase end def test_request_modified_with_record - @request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT' + @request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT" get :conditional_hello_with_record assert_equal 200, @response.status.to_i assert @response.body.present? - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_responds_with_last_modified_with_collection_of_records get :conditional_hello_with_collection_of_records - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_request_not_modified_with_collection_of_records @@ -441,7 +451,7 @@ class LastModifiedRenderTest < ActionController::TestCase get :conditional_hello_with_collection_of_records assert_equal 304, @response.status.to_i assert @response.body.blank? - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_request_not_modified_but_etag_differs_with_collection_of_records @@ -452,16 +462,16 @@ class LastModifiedRenderTest < ActionController::TestCase end def test_request_modified_with_collection_of_records - @request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT' + @request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT" get :conditional_hello_with_collection_of_records assert_equal 200, @response.status.to_i assert @response.body.present? - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] end def test_request_with_bang_gets_last_modified get :conditional_hello_with_bangs - assert_equal @last_modified, @response.headers['Last-Modified'] + assert_equal @last_modified, @response.headers["Last-Modified"] assert_response :success end @@ -480,13 +490,14 @@ end class EtagRenderTest < ActionController::TestCase tests TestControllerWithExtraEtags + include TemplateModificationHelper def test_strong_etag - @request.if_none_match = strong_etag(['strong', 'ab', :cde, [:f]]) + @request.if_none_match = strong_etag(["strong", "ab", :cde, [:f]]) get :strong assert_response :not_modified - @request.if_none_match = '*' + @request.if_none_match = "*" get :strong assert_response :not_modified @@ -494,13 +505,13 @@ class EtagRenderTest < ActionController::TestCase get :strong assert_response :ok - @request.if_none_match = weak_etag(['strong', 'ab', :cde, [:f]]) + @request.if_none_match = weak_etag(["strong", "ab", :cde, [:f]]) get :strong assert_response :ok end def test_multiple_etags - @request.if_none_match = weak_etag(["123", 'ab', :cde, [:f]]) + @request.if_none_match = weak_etag(["123", "ab", :cde, [:f]]) get :fresh assert_response :not_modified @@ -510,7 +521,7 @@ class EtagRenderTest < ActionController::TestCase end def test_array - @request.if_none_match = weak_etag([%w(1 2 3), 'ab', :cde, [:f]]) + @request.if_none_match = weak_etag([%w(1 2 3), "ab", :cde, [:f]]) get :array assert_response :not_modified @@ -528,20 +539,28 @@ class EtagRenderTest < ActionController::TestCase get :with_template assert_response :not_modified - # Modify the template digest - path = File.expand_path('../../fixtures/test/hello_world.erb', __FILE__) - old = File.read(path) + modify_template("test/hello_world") do + request.if_none_match = etag + get :with_template + assert_response :ok + assert_not_equal etag, @response.etag + end + end - begin - File.write path, 'foo' - ActionView::LookupContext::DetailsKey.clear + def test_etag_reflects_implicit_template_digest + get :with_implicit_template + assert_response :ok + assert_not_nil etag = @response.etag + + request.if_none_match = etag + get :with_implicit_template + assert_response :not_modified + modify_template("test/with_implicit_template") do request.if_none_match = etag - get :with_template + get :with_implicit_template assert_response :ok assert_not_equal etag, @response.etag - ensure - File.write path, old end end @@ -555,6 +574,28 @@ class EtagRenderTest < ActionController::TestCase end end +class NamespacedEtagRenderTest < ActionController::TestCase + tests Namespaced::ImplicitRenderTestController + include TemplateModificationHelper + + def test_etag_reflects_template_digest + get :hello_world + assert_response :ok + assert_not_nil etag = @response.etag + + request.if_none_match = etag + get :hello_world + assert_response :not_modified + + modify_template("namespaced/implicit_render_test/hello_world") do + request.if_none_match = etag + get :hello_world + assert_response :ok + assert_not_equal etag, @response.etag + end + end +end + class MetalRenderTest < ActionController::TestCase tests MetalTestController @@ -567,7 +608,7 @@ end class ActionControllerBaseRenderTest < ActionController::TestCase def test_direct_render_to_string ac = ActionController::Base.new() - assert_equal "Hello world!", ac.render_to_string(template: 'test/hello_world') + assert_equal "Hello world!", ac.render_to_string(template: "test/hello_world") end end @@ -593,7 +634,7 @@ class ImplicitRenderTest < ActionController::TestCase def test_implicit_unknown_format_response assert_raises(ActionController::UnknownFormat) do - get :empty_action_with_template, format: 'json' + get :empty_action_with_template, format: "json" end end end @@ -611,19 +652,6 @@ class HeadRenderTest < ActionController::TestCase assert_response :created end - def test_passing_hash_to_head_as_first_parameter_deprecated - assert_deprecated do - get :head_with_status_hash - end - end - - def test_head_with_default_value_is_deprecated - assert_deprecated do - get :head_with_hash_does_not_include_status - assert_response :ok - end - end - def test_head_created_with_application_json_content_type post :head_created_with_application_json_content_type assert @response.body.blank? @@ -651,7 +679,7 @@ class HeadRenderTest < ActionController::TestCase resources :customers ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end @@ -687,7 +715,7 @@ class HeadRenderTest < ActionController::TestCase get :head_with_symbolic_status, params: { status: "no_content" } assert_equal 204, @response.status - assert !@response.headers.include?('Content-Length') + assert_not_includes @response.headers, "Content-Length" assert_response :no_content Rack::Utils::SYMBOL_TO_STATUS_CODE.each do |status, code| @@ -738,7 +766,7 @@ class HttpCacheForeverTest < ActionController::TestCase class HttpCacheForeverController < ActionController::Base def cache_me_forever http_cache_forever(public: params[:public]) do - render plain: 'hello' + render plain: "hello" end end end @@ -746,7 +774,7 @@ class HttpCacheForeverTest < ActionController::TestCase tests HttpCacheForeverController def test_cache_with_public - get :cache_me_forever, params: {public: true} + get :cache_me_forever, params: { public: true } assert_response :ok assert_equal "max-age=#{100.years}, public", @response.headers["Cache-Control"] assert_not_nil @response.etag @@ -765,7 +793,7 @@ class HttpCacheForeverTest < ActionController::TestCase get :cache_me_forever assert_response :ok - @request.if_modified_since = @response.headers['Last-Modified'] + @request.if_modified_since = @response.headers["Last-Modified"] get :cache_me_forever assert_response :not_modified end diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb index 137236c496..24866d7d6a 100644 --- a/actionpack/test/controller/render_xml_test.rb +++ b/actionpack/test/controller/render_xml_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'controller/fake_models' -require 'pathname' +require "abstract_unit" +require "controller/fake_models" +require "pathname" class RenderXmlTest < ActionController::TestCase class XmlRenderable @@ -14,31 +14,31 @@ class RenderXmlTest < ActionController::TestCase protect_from_forgery def self.controller_path - 'test' + "test" end def render_with_location - render :xml => "<hello/>", :location => "http://example.com", :status => 201 + render xml: "<hello/>", location: "http://example.com", status: 201 end def render_with_object_location customer = Customer.new("Some guy", 1) - render :xml => "<customer/>", :location => customer, :status => :created + render xml: "<customer/>", location: customer, status: :created end def render_with_to_xml - render :xml => XmlRenderable.new + render xml: XmlRenderable.new end def formatted_xml_erb end def render_xml_with_custom_content_type - render :xml => "<blah/>", :content_type => "application/atomsvc+xml" + render xml: "<blah/>", content_type: "application/atomsvc+xml" end def render_xml_with_custom_options - render :xml => XmlRenderable.new, :root => "i-am-THE-xml" + render xml: XmlRenderable.new, root: "i-am-THE-xml" end end @@ -74,7 +74,7 @@ class RenderXmlTest < ActionController::TestCase resources :customers ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end @@ -85,7 +85,7 @@ class RenderXmlTest < ActionController::TestCase def test_should_render_formatted_xml_erb_template get :formatted_xml_erb, format: :xml - assert_equal '<test>passed formatted xml erb</test>', @response.body + assert_equal "<test>passed formatted xml erb</test>", @response.body end def test_should_render_xml_but_keep_custom_content_type @@ -94,7 +94,7 @@ class RenderXmlTest < ActionController::TestCase end def test_should_use_implicit_content_type - get :implicit_content_type, format: 'atom' + get :implicit_content_type, format: "atom" assert_equal Mime[:atom], @response.content_type end end diff --git a/actionpack/test/controller/renderer_test.rb b/actionpack/test/controller/renderer_test.rb index 372c09bc23..866600b935 100644 --- a/actionpack/test/controller/renderer_test.rb +++ b/actionpack/test/controller/renderer_test.rb @@ -1,98 +1,106 @@ -require 'abstract_unit' +require "abstract_unit" class RendererTest < ActiveSupport::TestCase - test 'action controller base has a renderer' do + test "action controller base has a renderer" do assert ActionController::Base.renderer end - test 'creating with a controller' do + test "creating with a controller" do controller = CommentsController renderer = ActionController::Renderer.for controller assert_equal controller, renderer.controller end - test 'creating from a controller' do + test "creating from a controller" do controller = AccountsController renderer = controller.renderer assert_equal controller, renderer.controller end - test 'rendering with a class renderer' do + test "rendering with a class renderer" do renderer = ApplicationController.renderer - content = renderer.render template: 'ruby_template' + content = renderer.render template: "ruby_template" - assert_equal 'Hello from Ruby code', content + assert_equal "Hello from Ruby code", content end - test 'rendering with an instance renderer' do + test "rendering with an instance renderer" do renderer = ApplicationController.renderer.new - content = renderer.render file: 'test/hello_world' + content = renderer.render file: "test/hello_world" - assert_equal 'Hello world!', content + assert_equal "Hello world!", content end - test 'rendering with a controller class' do - assert_equal 'Hello world!', ApplicationController.render('test/hello_world') + test "rendering with a controller class" do + assert_equal "Hello world!", ApplicationController.render("test/hello_world") end - test 'rendering with locals' do + test "rendering with locals" do renderer = ApplicationController.renderer - content = renderer.render template: 'test/render_file_with_locals', - locals: { secret: 'bar' } + content = renderer.render template: "test/render_file_with_locals", + locals: { secret: "bar" } assert_equal "The secret is bar\n", content end - test 'rendering with assigns' do + test "rendering with assigns" do renderer = ApplicationController.renderer - content = renderer.render template: 'test/render_file_with_ivar', - assigns: { secret: 'foo' } + content = renderer.render template: "test/render_file_with_ivar", + assigns: { secret: "foo" } assert_equal "The secret is foo\n", content end - test 'rendering with custom env' do - renderer = ApplicationController.renderer.new method: 'post' - content = renderer.render inline: '<%= request.post? %>' + test "rendering with custom env" do + renderer = ApplicationController.renderer.new method: "post" + content = renderer.render inline: "<%= request.post? %>" - assert_equal 'true', content + assert_equal "true", content end - test 'rendering with defaults' do + test "rendering with custom env using a key that is not in RACK_KEY_TRANSLATION" do + value = "warden is here" + renderer = ApplicationController.renderer.new warden: value + content = renderer.render inline: "<%= request.env['warden'] %>" + + assert_equal value, content + end + + test "rendering with defaults" do renderer = ApplicationController.renderer.new https: true - content = renderer.render inline: '<%= request.ssl? %>' + content = renderer.render inline: "<%= request.ssl? %>" - assert_equal 'true', content + assert_equal "true", content end - test 'same defaults from the same controller' do + test "same defaults from the same controller" do renderer_defaults = ->(controller) { controller.renderer.defaults } assert_equal renderer_defaults[AccountsController], renderer_defaults[AccountsController] assert_equal renderer_defaults[AccountsController], renderer_defaults[CommentsController] end - test 'rendering with different formats' do - html = 'Hello world!' + test "rendering with different formats" do + html = "Hello world!" xml = "<p>Hello world!</p>\n" - assert_equal html, render['respond_to/using_defaults'] - assert_equal xml, render['respond_to/using_defaults.xml.builder'] - assert_equal xml, render['respond_to/using_defaults', formats: :xml] + assert_equal html, render["respond_to/using_defaults"] + assert_equal xml, render["respond_to/using_defaults.xml.builder"] + assert_equal xml, render["respond_to/using_defaults", formats: :xml] end - test 'rendering with helpers' do + test "rendering with helpers" do assert_equal "<p>1\n<br />2</p>", render[inline: '<%= simple_format "1\n2" %>'] end - test 'rendering with user specified defaults' do - ApplicationController.renderer.defaults.merge!({ hello: 'hello', https: true }) + test "rendering with user specified defaults" do + ApplicationController.renderer.defaults.merge!(hello: "hello", https: true) renderer = ApplicationController.renderer.new - content = renderer.render inline: '<%= request.ssl? %>' + content = renderer.render inline: "<%= request.ssl? %>" - assert_equal 'true', content + assert_equal "true", content end private diff --git a/actionpack/test/controller/renderers_test.rb b/actionpack/test/controller/renderers_test.rb index e6c2e4636e..122f5be549 100644 --- a/actionpack/test/controller/renderers_test.rb +++ b/actionpack/test/controller/renderers_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'controller/fake_models' -require 'active_support/logger' +require "abstract_unit" +require "controller/fake_models" +require "active_support/logger" class RenderersTest < ActionController::TestCase class XmlRenderable @@ -11,13 +11,13 @@ class RenderersTest < ActionController::TestCase end class JsonRenderable def as_json(options={}) - hash = { :a => :b, :c => :d, :e => :f } + hash = { a: :b, c: :d, e: :f } hash.except!(*options[:except]) if options[:except] hash end def to_json(options = {}) - super :except => [:c, :e] + super except: [:c, :e] end end class CsvRenderable @@ -26,9 +26,8 @@ class RenderersTest < ActionController::TestCase end end class TestController < ActionController::Base - def render_simon_says - render :simon => "foo" + render simon: "foo" end def respond_to_mime @@ -36,7 +35,7 @@ class RenderersTest < ActionController::TestCase type.json do render json: JsonRenderable.new end - type.js { render json: 'JS', callback: 'alert' } + type.js { render json: "JS", callback: "alert" } type.csv { render csv: CsvRenderable.new } type.xml { render xml: XmlRenderable.new } type.html { render body: "HTML" } @@ -70,7 +69,7 @@ class RenderersTest < ActionController::TestCase def test_raises_missing_template_no_renderer assert_raise ActionView::MissingTemplate do - get :respond_to_mime, format: 'csv' + get :respond_to_mime, format: "csv" end assert_equal Mime[:csv], @response.content_type assert_equal "", @response.body @@ -81,7 +80,7 @@ class RenderersTest < ActionController::TestCase send_data value.to_csv, type: Mime[:csv] end @request.accept = "text/csv" - get :respond_to_mime, format: 'csv' + get :respond_to_mime, format: "csv" assert_equal Mime[:csv], @response.content_type assert_equal "c,s,v", @response.body ensure diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb index e5d698d5c2..fa049fbc9f 100644 --- a/actionpack/test/controller/request/test_request_test.rb +++ b/actionpack/test/controller/request/test_request_test.rb @@ -1,12 +1,16 @@ -require 'abstract_unit' -require 'stringio' +require "abstract_unit" +require "stringio" class ActionController::TestRequestTest < ActionController::TestCase - def test_test_request_has_session_options_initialized assert @request.session_options end + def test_mutating_session_options_does_not_affect_default_options + @request.session_options[:myparam] = 123 + assert_equal nil, ActionController::TestSession::DEFAULT_OPTIONS[:myparam] + end + ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_key do |option| test "rack default session options #{option} exists in session options and is default" do assert_equal(ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS[option], @@ -19,5 +23,4 @@ class ActionController::TestRequestTest < ActionController::TestCase "Missing rack session option #{option} in request.session_options") end end - end diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index d3f2ec6aa1..90d5ab3c67 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -1,42 +1,42 @@ -require 'abstract_unit' +require "abstract_unit" require "active_support/log_subscriber/test_helper" # common controller actions module RequestForgeryProtectionActions def index - render :inline => "<%= form_tag('/') {} %>" + render inline: "<%= form_tag('/') {} %>" end def show_button - render :inline => "<%= button_to('New', '/') %>" + render inline: "<%= button_to('New', '/') %>" end def unsafe - render plain: 'pwn' + render plain: "pwn" end def meta - render :inline => "<%= csrf_meta_tags %>" + render inline: "<%= csrf_meta_tags %>" end def form_for_remote - render :inline => "<%= form_for(:some_resource, :remote => true ) {} %>" + render inline: "<%= form_for(:some_resource, :remote => true ) {} %>" end def form_for_remote_with_token - render :inline => "<%= form_for(:some_resource, :remote => true, :authenticity_token => true ) {} %>" + render inline: "<%= form_for(:some_resource, :remote => true, :authenticity_token => true ) {} %>" end def form_for_with_token - render :inline => "<%= form_for(:some_resource, :authenticity_token => true ) {} %>" + render inline: "<%= form_for(:some_resource, :authenticity_token => true ) {} %>" end def form_for_remote_with_external_token - render :inline => "<%= form_for(:some_resource, :remote => true, :authenticity_token => 'external_token') {} %>" + render inline: "<%= form_for(:some_resource, :remote => true, :authenticity_token => 'external_token') {} %>" end def same_origin_js - render js: 'foo();' + render js: "foo();" end def negotiate_same_origin @@ -52,30 +52,29 @@ module RequestForgeryProtectionActions def negotiate_cross_origin negotiate_same_origin end - end # sample controllers class RequestForgeryProtectionControllerUsingResetSession < ActionController::Base include RequestForgeryProtectionActions - protect_from_forgery :only => %w(index meta same_origin_js negotiate_same_origin), :with => :reset_session + protect_from_forgery only: %w(index meta same_origin_js negotiate_same_origin), with: :reset_session end class RequestForgeryProtectionControllerUsingException < ActionController::Base include RequestForgeryProtectionActions - protect_from_forgery :only => %w(index meta same_origin_js negotiate_same_origin), :with => :exception + protect_from_forgery only: %w(index meta same_origin_js negotiate_same_origin), with: :exception end class RequestForgeryProtectionControllerUsingNullSession < ActionController::Base - protect_from_forgery :with => :null_session + protect_from_forgery with: :null_session def signed - cookies.signed[:foo] = 'bar' + cookies.signed[:foo] = "bar" head :ok end def encrypted - cookies.encrypted[:foo] = 'bar' + cookies.encrypted[:foo] = "bar" head :ok end @@ -90,46 +89,45 @@ class PrependProtectForgeryBaseController < ActionController::Base attr_accessor :called_callbacks def index - render inline: 'OK' + render inline: "OK" end protected - def add_called_callback(name) - @called_callbacks ||= [] - @called_callbacks << name - end - + def add_called_callback(name) + @called_callbacks ||= [] + @called_callbacks << name + end - def custom_action - add_called_callback("custom_action") - end + def custom_action + add_called_callback("custom_action") + end - def verify_authenticity_token - add_called_callback("verify_authenticity_token") - end + def verify_authenticity_token + add_called_callback("verify_authenticity_token") + end end class FreeCookieController < RequestForgeryProtectionControllerUsingResetSession self.allow_forgery_protection = false def index - render :inline => "<%= form_tag('/') {} %>" + render inline: "<%= form_tag('/') {} %>" end def show_button - render :inline => "<%= button_to('New', '/') %>" + render inline: "<%= button_to('New', '/') %>" end end class CustomAuthenticityParamController < RequestForgeryProtectionControllerUsingResetSession def form_authenticity_param - 'foobar' + "foobar" end end class PerFormTokensController < ActionController::Base - protect_from_forgery :with => :exception + protect_from_forgery with: :exception self.per_form_csrf_tokens = true def index @@ -141,18 +139,18 @@ class PerFormTokensController < ActionController::Base end def post_one - render plain: '' + render plain: "" end def post_two - render plain: '' + render plain: "" end end # common test methods module RequestForgeryProtectionTests def setup - @token = Base64.strict_encode64('railstestrailstestrailstestrails') + @token = Base64.strict_encode64("railstestrailstestrailstestrails") @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token ActionController::Base.request_forgery_protection_token = :custom_authenticity_token end @@ -166,7 +164,7 @@ module RequestForgeryProtectionTests assert_not_blocked do get :index end - assert_select 'form>input[name=?][value=?]', 'custom_authenticity_token', @token + assert_select "form>input[name=?][value=?]", "custom_authenticity_token", @token end end @@ -175,7 +173,7 @@ module RequestForgeryProtectionTests assert_not_blocked do get :show_button end - assert_select 'form>input[name=?][value=?]', 'custom_authenticity_token', @token + assert_select "form>input[name=?][value=?]", "custom_authenticity_token", @token end end @@ -206,7 +204,7 @@ module RequestForgeryProtectionTests assert_not_blocked do get :form_for_remote_with_external_token end - assert_select 'form>input[name=?][value=?]', 'custom_authenticity_token', 'external_token' + assert_select "form>input[name=?][value=?]", "custom_authenticity_token", "external_token" ensure ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = original end @@ -216,7 +214,7 @@ module RequestForgeryProtectionTests assert_not_blocked do get :form_for_remote_with_external_token end - assert_select 'form>input[name=?][value=?]', 'custom_authenticity_token', 'external_token' + assert_select "form>input[name=?][value=?]", "custom_authenticity_token", "external_token" end def test_should_render_form_with_token_tag_if_remote_and_authenticity_token_requested @@ -224,7 +222,7 @@ module RequestForgeryProtectionTests assert_not_blocked do get :form_for_remote_with_token end - assert_select 'form>input[name=?][value=?]', 'custom_authenticity_token', @token + assert_select "form>input[name=?][value=?]", "custom_authenticity_token", @token end end @@ -233,7 +231,7 @@ module RequestForgeryProtectionTests assert_not_blocked do get :form_for_with_token end - assert_select 'form>input[name=?][value=?]', 'custom_authenticity_token', @token + assert_select "form>input[name=?][value=?]", "custom_authenticity_token", @token end end @@ -254,7 +252,7 @@ module RequestForgeryProtectionTests end def test_should_not_allow_post_without_token_irrespective_of_format - assert_blocked { post :index, format: 'xml' } + assert_blocked { post :index, format: "xml" } end def test_should_not_allow_patch_without_token @@ -303,25 +301,25 @@ module RequestForgeryProtectionTests def test_should_allow_post_with_token_in_header session[:_csrf_token] = @token - @request.env['HTTP_X_CSRF_TOKEN'] = @token + @request.env["HTTP_X_CSRF_TOKEN"] = @token assert_not_blocked { post :index } end def test_should_allow_delete_with_token_in_header session[:_csrf_token] = @token - @request.env['HTTP_X_CSRF_TOKEN'] = @token + @request.env["HTTP_X_CSRF_TOKEN"] = @token assert_not_blocked { delete :index } end def test_should_allow_patch_with_token_in_header session[:_csrf_token] = @token - @request.env['HTTP_X_CSRF_TOKEN'] = @token + @request.env["HTTP_X_CSRF_TOKEN"] = @token assert_not_blocked { patch :index } end def test_should_allow_put_with_token_in_header session[:_csrf_token] = @token - @request.env['HTTP_X_CSRF_TOKEN'] = @token + @request.env["HTTP_X_CSRF_TOKEN"] = @token assert_not_blocked { put :index } end @@ -330,7 +328,7 @@ module RequestForgeryProtectionTests session[:_csrf_token] = @token @controller.stub :form_authenticity_token, @token do assert_not_blocked do - @request.set_header 'HTTP_ORIGIN', 'http://test.host' + @request.set_header "HTTP_ORIGIN", "http://test.host" post :index, params: { custom_authenticity_token: @token } end end @@ -353,7 +351,7 @@ module RequestForgeryProtectionTests session[:_csrf_token] = @token @controller.stub :form_authenticity_token, @token do assert_blocked do - @request.set_header 'HTTP_ORIGIN', 'http://bad.host' + @request.set_header "HTTP_ORIGIN", "http://bad.host" post :index, params: { custom_authenticity_token: @token } end end @@ -393,16 +391,16 @@ module RequestForgeryProtectionTests def test_should_only_allow_same_origin_js_get_with_xhr_header assert_cross_origin_blocked { get :same_origin_js } - assert_cross_origin_blocked { get :same_origin_js, format: 'js' } + assert_cross_origin_blocked { get :same_origin_js, format: "js" } assert_cross_origin_blocked do - @request.accept = 'text/javascript' + @request.accept = "text/javascript" get :negotiate_same_origin end assert_cross_origin_not_blocked { get :same_origin_js, xhr: true } - assert_cross_origin_not_blocked { get :same_origin_js, xhr: true, format: 'js'} + assert_cross_origin_not_blocked { get :same_origin_js, xhr: true, format: "js" } assert_cross_origin_not_blocked do - @request.accept = 'text/javascript' + @request.accept = "text/javascript" get :negotiate_same_origin, xhr: true end end @@ -442,32 +440,32 @@ module RequestForgeryProtectionTests def test_should_allow_non_get_js_without_xhr_header session[:_csrf_token] = @token assert_cross_origin_not_blocked { post :same_origin_js, params: { custom_authenticity_token: @token } } - assert_cross_origin_not_blocked { post :same_origin_js, params: { format: 'js', custom_authenticity_token: @token } } + assert_cross_origin_not_blocked { post :same_origin_js, params: { format: "js", custom_authenticity_token: @token } } assert_cross_origin_not_blocked do - @request.accept = 'text/javascript' - post :negotiate_same_origin, params: { custom_authenticity_token: @token} + @request.accept = "text/javascript" + post :negotiate_same_origin, params: { custom_authenticity_token: @token } end end def test_should_only_allow_cross_origin_js_get_without_xhr_header_if_protection_disabled assert_cross_origin_not_blocked { get :cross_origin_js } - assert_cross_origin_not_blocked { get :cross_origin_js, format: 'js' } + assert_cross_origin_not_blocked { get :cross_origin_js, format: "js" } assert_cross_origin_not_blocked do - @request.accept = 'text/javascript' + @request.accept = "text/javascript" get :negotiate_cross_origin end assert_cross_origin_not_blocked { get :cross_origin_js, xhr: true } - assert_cross_origin_not_blocked { get :cross_origin_js, xhr: true, format: 'js' } + assert_cross_origin_not_blocked { get :cross_origin_js, xhr: true, format: "js" } assert_cross_origin_not_blocked do - @request.accept = 'text/javascript' + @request.accept = "text/javascript" get :negotiate_cross_origin, xhr: true end end def test_should_not_raise_error_if_token_is_not_a_string assert_blocked do - patch :index, params: { custom_authenticity_token: { foo: 'bar' } } + patch :index, params: { custom_authenticity_token: { foo: "bar" } } end end @@ -509,20 +507,11 @@ end class RequestForgeryProtectionControllerUsingResetSessionTest < ActionController::TestCase include RequestForgeryProtectionTests - setup do - @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token - ActionController::Base.request_forgery_protection_token = :custom_authenticity_token - end - - teardown do - ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token - end - - test 'should emit a csrf-param meta tag and a csrf-token meta tag' do - @controller.stub :form_authenticity_token, @token + '<=?' do + test "should emit a csrf-param meta tag and a csrf-token meta tag" do + @controller.stub :form_authenticity_token, @token + "<=?" do get :meta - assert_select 'meta[name=?][content=?]', 'csrf-param', 'custom_authenticity_token' - assert_select 'meta[name=?]', 'csrf-token' + assert_select "meta[name=?][content=?]", "csrf-param", "custom_authenticity_token" + assert_select "meta[name=?]", "csrf-token" regexp = "#{@token}<=\?" assert_match(/#{regexp}/, @response.body) end @@ -532,7 +521,7 @@ end class RequestForgeryProtectionControllerUsingNullSessionTest < ActionController::TestCase class NullSessionDummyKeyGenerator def generate_key(secret) - '03312270731a2ed0d11ed091c2338a06' + "03312270731a2ed0d11ed091c2338a06" end end @@ -540,17 +529,17 @@ class RequestForgeryProtectionControllerUsingNullSessionTest < ActionController: @request.env[ActionDispatch::Cookies::GENERATOR_KEY] = NullSessionDummyKeyGenerator.new end - test 'should allow to set signed cookies' do + test "should allow to set signed cookies" do post :signed assert_response :ok end - test 'should allow to set encrypted cookies' do + test "should allow to set encrypted cookies" do post :encrypted assert_response :ok end - test 'should allow reset_session' do + test "should allow reset_session" do post :try_to_reset_session assert_response :ok end @@ -610,26 +599,26 @@ class FreeCookieControllerTest < ActionController::TestCase def test_should_not_render_form_with_token_tag SecureRandom.stub :base64, @token do get :index - assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false + assert_select "form>div>input[name=?][value=?]", "authenticity_token", @token, false end end def test_should_not_render_button_to_with_token_tag SecureRandom.stub :base64, @token do get :show_button - assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false + assert_select "form>div>input[name=?][value=?]", "authenticity_token", @token, false end end def test_should_allow_all_methods_without_token SecureRandom.stub :base64, @token do [:post, :patch, :put, :delete].each do |method| - assert_nothing_raised { send(method, :index)} + assert_nothing_raised { send(method, :index) } end end end - test 'should not emit a csrf-token meta tag' do + test "should not emit a csrf-token meta tag" do SecureRandom.stub :base64, @token do get :meta assert @response.body.blank? @@ -656,7 +645,7 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase ActionController::Base.logger = @logger begin @controller.stub :valid_authenticity_token?, :true do - post :index, params: { custom_token_name: 'foobar' } + post :index, params: { custom_token_name: "foobar" } assert_equal 0, @logger.logged(:warn).size end ensure @@ -668,7 +657,7 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase ActionController::Base.logger = @logger begin - post :index, params: { custom_token_name: 'bazqux' } + post :index, params: { custom_token_name: "bazqux" } assert_equal 1, @logger.logged(:warn).size ensure ActionController::Base.logger = @old_logger @@ -677,10 +666,19 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase end class PerFormTokensControllerTest < ActionController::TestCase + def setup + @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token + ActionController::Base.request_forgery_protection_token = :custom_authenticity_token + end + + def teardown + ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token + end + def test_per_form_token_is_same_size_as_global_token get :index expected = ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH - actual = @controller.send(:per_form_csrf_token, session, '/path', 'post').size + actual = @controller.send(:per_form_csrf_token, session, "/path", "post").size assert_equal expected, actual end @@ -692,9 +690,9 @@ class PerFormTokensControllerTest < ActionController::TestCase assert_matches_session_token_on_server form_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_nothing_raised do - post :post_one, params: {custom_authenticity_token: form_token} + post :post_one, params: { custom_authenticity_token: form_token } end assert_response :success end @@ -707,9 +705,9 @@ class PerFormTokensControllerTest < ActionController::TestCase assert_matches_session_token_on_server form_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_two' + @request.env["PATH_INFO"] = "/per_form_tokens/post_two" assert_raises(ActionController::InvalidAuthenticityToken) do - post :post_two, params: {custom_authenticity_token: form_token} + post :post_two, params: { custom_authenticity_token: form_token } end end @@ -721,21 +719,21 @@ class PerFormTokensControllerTest < ActionController::TestCase assert_matches_session_token_on_server form_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_raises(ActionController::InvalidAuthenticityToken) do - patch :post_one, params: {custom_authenticity_token: form_token} + patch :post_one, params: { custom_authenticity_token: form_token } end end def test_rejects_token_for_incorrect_method_button_to - get :button_to, params: { form_method: 'delete' } + get :button_to, params: { form_method: "delete" } form_token = assert_presence_and_fetch_form_csrf_token - assert_matches_session_token_on_server form_token, 'delete' + assert_matches_session_token_on_server form_token, "delete" # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_raises(ActionController::InvalidAuthenticityToken) do patch :post_one, params: { custom_authenticity_token: form_token } end @@ -746,10 +744,10 @@ class PerFormTokensControllerTest < ActionController::TestCase form_token = assert_presence_and_fetch_form_csrf_token - assert_matches_session_token_on_server form_token, 'post' + assert_matches_session_token_on_server form_token, "post" # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_nothing_raised do post :post_one, params: { custom_authenticity_token: form_token } end @@ -764,7 +762,7 @@ class PerFormTokensControllerTest < ActionController::TestCase assert_matches_session_token_on_server form_token, verb # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_nothing_raised do send verb, :post_one, params: { custom_authenticity_token: form_token } end @@ -777,50 +775,50 @@ class PerFormTokensControllerTest < ActionController::TestCase token = @controller.send(:form_authenticity_token) # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_nothing_raised do - post :post_one, params: {custom_authenticity_token: token} + post :post_one, params: { custom_authenticity_token: token } end assert_response :success end def test_ignores_params - get :index, params: {form_path: '/per_form_tokens/post_one?foo=bar'} + get :index, params: { form_path: "/per_form_tokens/post_one?foo=bar" } form_token = assert_presence_and_fetch_form_csrf_token assert_matches_session_token_on_server form_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one?foo=baz' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one?foo=baz" assert_nothing_raised do - post :post_one, params: {custom_authenticity_token: form_token, baz: 'foo'} + post :post_one, params: { custom_authenticity_token: form_token, baz: "foo" } end assert_response :success end def test_ignores_trailing_slash_during_generation - get :index, params: {form_path: '/per_form_tokens/post_one/'} + get :index, params: { form_path: "/per_form_tokens/post_one/" } form_token = assert_presence_and_fetch_form_csrf_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_nothing_raised do - post :post_one, params: {custom_authenticity_token: form_token} + post :post_one, params: { custom_authenticity_token: form_token } end assert_response :success end def test_ignores_origin_during_generation - get :index, params: {form_path: 'https://example.com/per_form_tokens/post_one/'} + get :index, params: { form_path: "https://example.com/per_form_tokens/post_one/" } form_token = assert_presence_and_fetch_form_csrf_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one" assert_nothing_raised do - post :post_one, params: {custom_authenticity_token: form_token} + post :post_one, params: { custom_authenticity_token: form_token } end assert_response :success end @@ -831,21 +829,21 @@ class PerFormTokensControllerTest < ActionController::TestCase form_token = assert_presence_and_fetch_form_csrf_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one/' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one/" assert_nothing_raised do - post :post_one, params: {custom_authenticity_token: form_token} + post :post_one, params: { custom_authenticity_token: form_token } end assert_response :success end def test_method_is_case_insensitive - get :index, params: {form_method: "POST"} + get :index, params: { form_method: "POST" } form_token = assert_presence_and_fetch_form_csrf_token # This is required because PATH_INFO isn't reset between requests. - @request.env['PATH_INFO'] = '/per_form_tokens/post_one/' + @request.env["PATH_INFO"] = "/per_form_tokens/post_one/" assert_nothing_raised do - post :post_one, params: {custom_authenticity_token: form_token} + post :post_one, params: { custom_authenticity_token: form_token } end assert_response :success end @@ -853,15 +851,15 @@ class PerFormTokensControllerTest < ActionController::TestCase private def assert_presence_and_fetch_form_csrf_token assert_select 'input[name="custom_authenticity_token"]' do |input| - form_csrf_token = input.first['value'] + form_csrf_token = input.first["value"] assert_not_nil form_csrf_token return form_csrf_token end end - def assert_matches_session_token_on_server(form_token, method = 'post') + def assert_matches_session_token_on_server(form_token, method = "post") actual = @controller.send(:unmask_token, Base64.strict_decode64(form_token)) - expected = @controller.send(:per_form_csrf_token, session, '/per_form_tokens/post_one', method) + expected = @controller.send(:per_form_csrf_token, session, "/per_form_tokens/post_one", method) assert_equal expected, actual end end diff --git a/actionpack/test/controller/required_params_test.rb b/actionpack/test/controller/required_params_test.rb index b6efcd6f9a..dd07c2486b 100644 --- a/actionpack/test/controller/required_params_test.rb +++ b/actionpack/test/controller/required_params_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class BooksController < ActionController::Base def create @@ -32,7 +32,6 @@ class ActionControllerRequiredParamsTest < ActionController::TestCase end class ParametersRequireTest < ActiveSupport::TestCase - test "required parameters should accept and return false value" do assert_equal(false, ActionController::Parameters.new(person: false).require(:person)) end @@ -50,17 +49,17 @@ class ParametersRequireTest < ActiveSupport::TestCase end test "require array when all required params are present" do - safe_params = ActionController::Parameters.new(person: {first_name: 'Gaurish', title: 'Mjallo', city: 'Barcelona'}) + safe_params = ActionController::Parameters.new(person: { first_name: "Gaurish", title: "Mjallo", city: "Barcelona" }) .require(:person) .require([:first_name, :title]) assert_kind_of Array, safe_params - assert_equal ['Gaurish', 'Mjallo'], safe_params + assert_equal ["Gaurish", "Mjallo"], safe_params end test "require array when a required param is missing" do assert_raises(ActionController::ParameterMissing) do - ActionController::Parameters.new(person: {first_name: 'Gaurish', title: nil}) + ActionController::Parameters.new(person: { first_name: "Gaurish", title: nil }) .require(:person) .require([:first_name, :title]) end @@ -73,9 +72,9 @@ class ParametersRequireTest < ActiveSupport::TestCase assert params.value?("cinco") end - test "Deprecated methods are deprecated" do - assert_deprecated do - ActionController::Parameters.new(foo: "bar").merge!({bar: "foo"}) + test "to_query is not supported" do + assert_raises(NoMethodError) do + ActionController::Parameters.new(foo: "bar").to_param end end end diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index c088e5a043..a98e6479b7 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class RescueController < ActionController::Base class NotAuthorized < StandardError @@ -34,47 +34,47 @@ class RescueController < ActionController::Base # We use a fully-qualified name in some strings, and a relative constant # name in some other to test correct handling of both cases. - rescue_from NotAuthorized, :with => :deny_access - rescue_from 'RescueController::NotAuthorizedToRescueAsString', :with => :deny_access + rescue_from NotAuthorized, with: :deny_access + rescue_from "RescueController::NotAuthorizedToRescueAsString", with: :deny_access - rescue_from RecordInvalid, :with => :show_errors - rescue_from 'RescueController::RecordInvalidToRescueAsString', :with => :show_errors + rescue_from RecordInvalid, with: :show_errors + rescue_from "RescueController::RecordInvalidToRescueAsString", with: :show_errors - rescue_from NotAllowed, :with => proc { head :forbidden } - rescue_from 'RescueController::NotAllowedToRescueAsString', :with => proc { head :forbidden } + rescue_from NotAllowed, with: proc { head :forbidden } + rescue_from "RescueController::NotAllowedToRescueAsString", with: proc { head :forbidden } rescue_from InvalidRequest, with: proc { |exception| render plain: exception.message } - rescue_from 'InvalidRequestToRescueAsString', with: proc { |exception| render plain: exception.message } + rescue_from "InvalidRequestToRescueAsString", with: proc { |exception| render plain: exception.message } rescue_from BadGateway do head 502 end - rescue_from 'BadGatewayToRescueAsString' do + rescue_from "BadGatewayToRescueAsString" do head 502 end rescue_from ResourceUnavailable do |exception| render plain: exception.message end - rescue_from 'ResourceUnavailableToRescueAsString' do |exception| + rescue_from "ResourceUnavailableToRescueAsString" do |exception| render plain: exception.message end rescue_from ActionView::TemplateError do - render plain: 'action_view templater error' + render plain: "action_view templater error" end rescue_from IOError do - render plain: 'io error' + render plain: "io error" end - before_action(only: :before_action_raises) { raise 'umm nice' } + before_action(only: :before_action_raises) { raise "umm nice" } def before_action_raises end def raises - render plain: 'already rendered' + render plain: "already rendered" raise "don't panic!" end @@ -160,7 +160,6 @@ class RescueController < ActionController::Base end class ExceptionInheritanceRescueController < ActionController::Base - class ParentException < StandardError end @@ -170,9 +169,9 @@ class ExceptionInheritanceRescueController < ActionController::Base class GrandchildException < ChildException end - rescue_from ChildException, :with => lambda { head :ok } - rescue_from ParentException, :with => lambda { head :created } - rescue_from GrandchildException, :with => lambda { head :no_content } + rescue_from ChildException, with: lambda { head :ok } + rescue_from ParentException, with: lambda { head :created } + rescue_from GrandchildException, with: lambda { head :no_content } def raise_parent_exception raise ParentException @@ -206,7 +205,7 @@ class ControllerInheritanceRescueController < ExceptionInheritanceRescueControll class SecondExceptionInChildController < StandardError end - rescue_from FirstExceptionInChildController, 'SecondExceptionInChildController', :with => lambda { head :gone } + rescue_from FirstExceptionInChildController, "SecondExceptionInChildController", with: lambda { head :gone } def raise_first_exception_in_child_controller raise FirstExceptionInChildController @@ -291,17 +290,17 @@ class RescueControllerTest < ActionController::TestCase assert_equal "RescueController::ResourceUnavailableToRescueAsString", @response.body end - test 'rescue when wrapper has more specific handler than cause' do + test "rescue when wrapper has more specific handler than cause" do get :exception_with_more_specific_handler_for_wrapper assert_response :forbidden end - test 'rescue when cause has more specific handler than wrapper' do + test "rescue when cause has more specific handler than wrapper" do get :exception_with_more_specific_handler_for_cause assert_response :unprocessable_entity end - test 'rescue when cause has handler, but wrapper doesnt' do + test "rescue when cause has handler, but wrapper doesnt" do get :exception_with_no_handler_for_wrapper assert_response :unprocessable_entity end @@ -311,10 +310,10 @@ class RescueTest < ActionDispatch::IntegrationTest class TestController < ActionController::Base class RecordInvalid < StandardError def message - 'invalid' + "invalid" end end - rescue_from RecordInvalid, :with => :show_errors + rescue_from RecordInvalid, with: :show_errors def foo render plain: "foo" @@ -325,7 +324,7 @@ class RescueTest < ActionDispatch::IntegrationTest end def b00m - raise 'b00m' + raise "b00m" end protected @@ -334,17 +333,17 @@ class RescueTest < ActionDispatch::IntegrationTest end end - test 'normal request' do + test "normal request" do with_test_routing do - get '/foo' - assert_equal 'foo', response.body + get "/foo" + assert_equal "foo", response.body end end - test 'rescue exceptions inside controller' do + test "rescue exceptions inside controller" do with_test_routing do - get '/invalid' - assert_equal 'invalid', response.body + get "/invalid" + assert_equal "invalid", response.body end end @@ -353,9 +352,9 @@ class RescueTest < ActionDispatch::IntegrationTest def with_test_routing with_routing do |set| set.draw do - get 'foo', :to => ::RescueTest::TestController.action(:foo) - get 'invalid', :to => ::RescueTest::TestController.action(:invalid) - get 'b00m', :to => ::RescueTest::TestController.action(:b00m) + get "foo", to: ::RescueTest::TestController.action(:foo) + get "invalid", to: ::RescueTest::TestController.action(:invalid) + get "b00m", to: ::RescueTest::TestController.action(:b00m) end yield end diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 8e38af5025..b572e7e8d5 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/try' -require 'active_support/core_ext/object/with_options' -require 'active_support/core_ext/array/extract_options' +require "abstract_unit" +require "active_support/core_ext/object/try" +require "active_support/core_ext/object/with_options" +require "active_support/core_ext/array/extract_options" class AdminController < ResourcesController; end class MessagesController < ResourcesController; end @@ -26,43 +26,43 @@ class ResourcesTest < ActionController::TestCase end def test_override_paths_for_member_and_collection_methods - collection_methods = { :rss => :get, :reorder => :post, :csv => :post } - member_methods = { :rss => :get, :atom => :get, :upload => :post, :fix => :post } - path_names = {:new => 'nuevo', :rss => 'canal', :fix => 'corrigir' } + collection_methods = { rss: :get, reorder: :post, csv: :post } + member_methods = { rss: :get, atom: :get, upload: :post, fix: :post } + path_names = { new: "nuevo", rss: "canal", fix: "corrigir" } with_restful_routing :messages, - :collection => collection_methods, - :member => member_methods, - :path_names => path_names do + collection: collection_methods, + member: member_methods, + path_names: path_names do assert_restful_routes_for :messages, - :collection => collection_methods, - :member => member_methods, - :path_names => path_names do |options| + collection: collection_methods, + member: member_methods, + path_names: path_names do |options| member_methods.each do |action, method| - assert_recognizes(options.merge(:action => action.to_s, :id => '1'), - :path => "/messages/1/#{path_names[action] || action}", - :method => method) + assert_recognizes(options.merge(action: action.to_s, id: "1"), + path: "/messages/1/#{path_names[action] || action}", + method: method) end collection_methods.each do |action, method| - assert_recognizes(options.merge(:action => action.to_s), - :path => "/messages/#{path_names[action] || action}", - :method => method) + assert_recognizes(options.merge(action: action.to_s), + path: "/messages/#{path_names[action] || action}", + method: method) end end assert_restful_named_routes_for :messages, - :collection => collection_methods, - :member => member_methods, - :path_names => path_names do |options| + collection: collection_methods, + member: member_methods, + path_names: path_names do |options| collection_methods.each_key do |action| - assert_named_route "/messages/#{path_names[action] || action}", "#{action}_messages_path", :action => action + assert_named_route "/messages/#{path_names[action] || action}", "#{action}_messages_path", action: action end member_methods.each_key do |action| - assert_named_route "/messages/1/#{path_names[action] || action}", "#{action}_message_path", :action => action, :id => "1" + assert_named_route "/messages/1/#{path_names[action] || action}", "#{action}_message_path", action: action, id: "1" end end @@ -77,182 +77,182 @@ class ResourcesTest < ActionController::TestCase end def test_multiple_resources_with_options - expected_options = {:controller => 'threads', :action => 'index'} + expected_options = { controller: "threads", action: "index" } with_restful_routing :messages, :comments, expected_options.slice(:controller) do - assert_recognizes(expected_options, :path => 'comments') - assert_recognizes(expected_options, :path => 'messages') + assert_recognizes(expected_options, path: "comments") + assert_recognizes(expected_options, path: "messages") end end def test_with_custom_conditions - with_restful_routing :messages, :conditions => { :subdomain => 'app' } do - assert @routes.recognize_path("/messages", :method => :get, :subdomain => 'app') + with_restful_routing :messages, conditions: { subdomain: "app" } do + assert @routes.recognize_path("/messages", method: :get, subdomain: "app") end end def test_irregular_id_with_no_constraints_should_raise_error - expected_options = {:controller => 'messages', :action => 'show', :id => '1.1.1'} + expected_options = { controller: "messages", action: "show", id: "1.1.1" } with_restful_routing :messages do assert_raise(Assertion) do - assert_recognizes(expected_options, :path => 'messages/1.1.1', :method => :get) + assert_recognizes(expected_options, path: "messages/1.1.1", method: :get) end end end def test_irregular_id_with_constraints_should_pass - expected_options = {:controller => 'messages', :action => 'show', :id => '1.1.1'} + expected_options = { controller: "messages", action: "show", id: "1.1.1" } - with_restful_routing(:messages, :constraints => {:id => /[0-9]\.[0-9]\.[0-9]/}) do - assert_recognizes(expected_options, :path => 'messages/1.1.1', :method => :get) + with_restful_routing(:messages, constraints: { id: /[0-9]\.[0-9]\.[0-9]/ }) do + assert_recognizes(expected_options, path: "messages/1.1.1", method: :get) end end def test_with_path_prefix_constraints - expected_options = {:controller => 'messages', :action => 'show', :thread_id => '1.1.1', :id => '1'} - with_restful_routing :messages, :path_prefix => '/thread/:thread_id', :constraints => {:thread_id => /[0-9]\.[0-9]\.[0-9]/} do - assert_recognizes(expected_options, :path => 'thread/1.1.1/messages/1', :method => :get) + expected_options = { controller: "messages", action: "show", thread_id: "1.1.1", id: "1" } + with_restful_routing :messages, path_prefix: "/thread/:thread_id", constraints: { thread_id: /[0-9]\.[0-9]\.[0-9]/ } do + assert_recognizes(expected_options, path: "thread/1.1.1/messages/1", method: :get) end end def test_irregular_id_constraints_should_get_passed_to_member_actions - expected_options = {:controller => 'messages', :action => 'custom', :id => '1.1.1'} + expected_options = { controller: "messages", action: "custom", id: "1.1.1" } - with_restful_routing(:messages, :member => {:custom => :get}, :constraints => {:id => /[0-9]\.[0-9]\.[0-9]/}) do - assert_recognizes(expected_options, :path => 'messages/1.1.1/custom', :method => :get) + with_restful_routing(:messages, member: { custom: :get }, constraints: { id: /[0-9]\.[0-9]\.[0-9]/ }) do + assert_recognizes(expected_options, path: "messages/1.1.1/custom", method: :get) end end def test_with_path_prefix - with_restful_routing :messages, :path_prefix => '/thread/:thread_id' do - assert_simply_restful_for :messages, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } + with_restful_routing :messages, path_prefix: "/thread/:thread_id" do + assert_simply_restful_for :messages, path_prefix: "thread/5/", options: { thread_id: "5" } end end def test_multiple_with_path_prefix - with_restful_routing :messages, :comments, :path_prefix => '/thread/:thread_id' do - assert_simply_restful_for :messages, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } - assert_simply_restful_for :comments, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } + with_restful_routing :messages, :comments, path_prefix: "/thread/:thread_id" do + assert_simply_restful_for :messages, path_prefix: "thread/5/", options: { thread_id: "5" } + assert_simply_restful_for :comments, path_prefix: "thread/5/", options: { thread_id: "5" } end end def test_with_name_prefix - with_restful_routing :messages, :as => 'post_messages' do - assert_simply_restful_for :messages, :name_prefix => 'post_' + with_restful_routing :messages, as: "post_messages" do + assert_simply_restful_for :messages, name_prefix: "post_" end end def test_with_collection_actions - actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete, 'e' => :patch } + actions = { "a" => :get, "b" => :put, "c" => :post, "d" => :delete, "e" => :patch } with_routing do |set| set.draw do resources :messages do - get :a, :on => :collection - put :b, :on => :collection - post :c, :on => :collection - delete :d, :on => :collection - patch :e, :on => :collection + get :a, on: :collection + put :b, on: :collection + post :c, on: :collection + delete :d, on: :collection + patch :e, on: :collection end end assert_restful_routes_for :messages do |options| actions.each do |action, method| - assert_recognizes(options.merge(:action => action), :path => "/messages/#{action}", :method => method) + assert_recognizes(options.merge(action: action), path: "/messages/#{action}", method: method) end end assert_restful_named_routes_for :messages do actions.each_key do |action| - assert_named_route "/messages/#{action}", "#{action}_messages_path", :action => action + assert_named_route "/messages/#{action}", "#{action}_messages_path", action: action end end end end def test_with_collection_actions_and_name_prefix - actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete, 'e' => :patch } + actions = { "a" => :get, "b" => :put, "c" => :post, "d" => :delete, "e" => :patch } with_routing do |set| set.draw do - scope '/threads/:thread_id' do - resources :messages, :as => 'thread_messages' do - get :a, :on => :collection - put :b, :on => :collection - post :c, :on => :collection - delete :d, :on => :collection - patch :e, :on => :collection + scope "/threads/:thread_id" do + resources :messages, as: "thread_messages" do + get :a, on: :collection + put :b, on: :collection + post :c, on: :collection + delete :d, on: :collection + patch :e, on: :collection end end end - assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options| + assert_restful_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do |options| actions.each do |action, method| - assert_recognizes(options.merge(:action => action), :path => "/threads/1/messages/#{action}", :method => method) + assert_recognizes(options.merge(action: action), path: "/threads/1/messages/#{action}", method: method) end end - assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do + assert_restful_named_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do actions.each_key do |action| - assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", :action => action + assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", action: action end end end end def test_with_collection_actions_and_name_prefix_and_member_action_with_same_name - actions = { 'a' => :get } + actions = { "a" => :get } with_routing do |set| set.draw do - scope '/threads/:thread_id' do - resources :messages, :as => 'thread_messages' do - get :a, :on => :collection - get :a, :on => :member + scope "/threads/:thread_id" do + resources :messages, as: "thread_messages" do + get :a, on: :collection + get :a, on: :member end end end - assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options| + assert_restful_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do |options| actions.each do |action, method| - assert_recognizes(options.merge(:action => action), :path => "/threads/1/messages/#{action}", :method => method) + assert_recognizes(options.merge(action: action), path: "/threads/1/messages/#{action}", method: method) end end - assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do + assert_restful_named_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do actions.each_key do |action| - assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", :action => action + assert_named_route "/threads/1/messages/#{action}", "#{action}_thread_messages_path", action: action end end end end def test_with_collection_action_and_name_prefix_and_formatted - actions = { 'a' => :get, 'b' => :put, 'c' => :post, 'd' => :delete, 'e' => :patch } + actions = { "a" => :get, "b" => :put, "c" => :post, "d" => :delete, "e" => :patch } with_routing do |set| set.draw do - scope '/threads/:thread_id' do - resources :messages, :as => 'thread_messages' do - get :a, :on => :collection - put :b, :on => :collection - post :c, :on => :collection - delete :d, :on => :collection - patch :e, :on => :collection + scope "/threads/:thread_id" do + resources :messages, as: "thread_messages" do + get :a, on: :collection + put :b, on: :collection + post :c, on: :collection + delete :d, on: :collection + patch :e, on: :collection end end end - assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options| + assert_restful_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do |options| actions.each do |action, method| - assert_recognizes(options.merge(:action => action, :format => 'xml'), :path => "/threads/1/messages/#{action}.xml", :method => method) + assert_recognizes(options.merge(action: action, format: "xml"), path: "/threads/1/messages/#{action}.xml", method: method) end end - assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do + assert_restful_named_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do actions.each_key do |action| - assert_named_route "/threads/1/messages/#{action}.xml", "#{action}_thread_messages_path", :action => action, :format => 'xml' + assert_named_route "/threads/1/messages/#{action}.xml", "#{action}_thread_messages_path", action: action, format: "xml" end end end @@ -260,11 +260,11 @@ class ResourcesTest < ActionController::TestCase def test_with_member_action [:patch, :put, :post].each do |method| - with_restful_routing :messages, :member => { :mark => method } do - mark_options = {:action => 'mark', :id => '1'} + with_restful_routing :messages, member: { mark: method } do + mark_options = { action: "mark", id: "1" } mark_path = "/messages/1/mark" assert_restful_routes_for :messages do |options| - assert_recognizes(options.merge(mark_options), :path => mark_path, :method => method) + assert_recognizes(options.merge(mark_options), path: mark_path, method: method) end assert_restful_named_routes_for :messages do @@ -275,24 +275,24 @@ class ResourcesTest < ActionController::TestCase end def test_with_member_action_and_requirement - expected_options = {:controller => 'messages', :action => 'mark', :id => '1.1.1'} + expected_options = { controller: "messages", action: "mark", id: "1.1.1" } - with_restful_routing(:messages, :constraints => {:id => /[0-9]\.[0-9]\.[0-9]/}, :member => { :mark => :get }) do - assert_recognizes(expected_options, :path => 'messages/1.1.1/mark', :method => :get) + with_restful_routing(:messages, constraints: { id: /[0-9]\.[0-9]\.[0-9]/ }, member: { mark: :get }) do + assert_recognizes(expected_options, path: "messages/1.1.1/mark", method: :get) end end def test_member_when_override_paths_for_default_restful_actions_with [:patch, :put, :post].each do |method| - with_restful_routing :messages, :member => { :mark => method }, :path_names => {:new => 'nuevo'} do - mark_options = {:action => 'mark', :id => '1', :controller => "messages"} + with_restful_routing :messages, member: { mark: method }, path_names: { new: "nuevo" } do + mark_options = { action: "mark", id: "1", controller: "messages" } mark_path = "/messages/1/mark" - assert_restful_routes_for :messages, :path_names => {:new => 'nuevo'} do |options| - assert_recognizes(options.merge(mark_options), :path => mark_path, :method => method) + assert_restful_routes_for :messages, path_names: { new: "nuevo" } do |options| + assert_recognizes(options.merge(mark_options), path: mark_path, method: method) end - assert_restful_named_routes_for :messages, :path_names => {:new => 'nuevo'} do + assert_restful_named_routes_for :messages, path_names: { new: "nuevo" } do assert_named_route mark_path, :mark_message_path, mark_options end end @@ -305,17 +305,17 @@ class ResourcesTest < ActionController::TestCase set.draw do resources :messages do member do - match :mark , :via => method - match :unmark, :via => method + match :mark , via: method + match :unmark, via: method end end end %w(mark unmark).each do |action| - action_options = {:action => action, :id => '1'} + action_options = { action: action, id: "1" } action_path = "/messages/1/#{action}" assert_restful_routes_for :messages do |options| - assert_recognizes(options.merge(action_options), :path => action_path, :method => method) + assert_recognizes(options.merge(action_options), path: action_path, method: method) end assert_restful_named_routes_for :messages do @@ -331,21 +331,21 @@ class ResourcesTest < ActionController::TestCase set.draw do resources :messages do collection do - match :search, :via => [:post, :get] + match :search, via: [:post, :get] end member do - match :toggle, :via => [:post, :get] + match :toggle, via: [:post, :get] end end end assert_restful_routes_for :messages do |options| [:get, :post].each do |method| - assert_recognizes(options.merge(:action => 'search'), :path => "/messages/search", :method => method) + assert_recognizes(options.merge(action: "search"), path: "/messages/search", method: method) end [:get, :post].each do |method| - assert_recognizes(options.merge(:action => 'toggle', :id => '1'), :path => '/messages/1/toggle', :method => method) + assert_recognizes(options.merge(action: "toggle", id: "1"), path: "/messages/1/toggle", method: method) end end end @@ -355,14 +355,14 @@ class ResourcesTest < ActionController::TestCase with_routing do |set| set.draw do resources :messages do - post :preview, :on => :new + post :preview, on: :new end end - preview_options = {:action => 'preview'} + preview_options = { action: "preview" } preview_path = "/messages/new/preview" assert_restful_routes_for :messages do |options| - assert_recognizes(options.merge(preview_options), :path => preview_path, :method => :post) + assert_recognizes(options.merge(preview_options), path: preview_path, method: :post) end assert_restful_named_routes_for :messages do @@ -374,20 +374,20 @@ class ResourcesTest < ActionController::TestCase def test_with_new_action_with_name_prefix with_routing do |set| set.draw do - scope('/threads/:thread_id') do - resources :messages, :as => "thread_messages" do - post :preview, :on => :new + scope("/threads/:thread_id") do + resources :messages, as: "thread_messages" do + post :preview, on: :new end end end - preview_options = {:action => 'preview', :thread_id => '1'} + preview_options = { action: "preview", thread_id: "1" } preview_path = "/threads/1/messages/new/preview" - assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options| - assert_recognizes(options.merge(preview_options), :path => preview_path, :method => :post) + assert_restful_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do |options| + assert_recognizes(options.merge(preview_options), path: preview_path, method: :post) end - assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do + assert_restful_named_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do assert_named_route preview_path, :preview_new_thread_message_path, preview_options end end @@ -396,20 +396,20 @@ class ResourcesTest < ActionController::TestCase def test_with_formatted_new_action_with_name_prefix with_routing do |set| set.draw do - scope('/threads/:thread_id') do - resources :messages, :as => "thread_messages" do - post :preview, :on => :new + scope("/threads/:thread_id") do + resources :messages, as: "thread_messages" do + post :preview, on: :new end end end - preview_options = {:action => 'preview', :thread_id => '1', :format => 'xml'} + preview_options = { action: "preview", thread_id: "1", format: "xml" } preview_path = "/threads/1/messages/new/preview.xml" - assert_restful_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options| - assert_recognizes(options.merge(preview_options), :path => preview_path, :method => :post) + assert_restful_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do |options| + assert_recognizes(options.merge(preview_options), path: preview_path, method: :post) end - assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do + assert_restful_named_routes_for :messages, path_prefix: "threads/1/", name_prefix: "thread_", options: { thread_id: "1" } do assert_named_route preview_path, :preview_new_thread_message_path, preview_options end end @@ -418,9 +418,9 @@ class ResourcesTest < ActionController::TestCase def test_override_new_method with_restful_routing :messages do assert_restful_routes_for :messages do |options| - assert_recognizes(options.merge(:action => "new"), :path => "/messages/new", :method => :get) + assert_recognizes(options.merge(action: "new"), path: "/messages/new", method: :get) assert_raise(ActionController::RoutingError) do - @routes.recognize_path("/messages/new", :method => :post) + @routes.recognize_path("/messages/new", method: :post) end end end @@ -428,13 +428,13 @@ class ResourcesTest < ActionController::TestCase with_routing do |set| set.draw do resources :messages do - match :new, :via => [:post, :get], :on => :new + match :new, via: [:post, :get], on: :new end end assert_restful_routes_for :messages do |options| - assert_recognizes(options.merge(:action => "new"), :path => "/messages/new", :method => :post) - assert_recognizes(options.merge(:action => "new"), :path => "/messages/new", :method => :get) + assert_recognizes(options.merge(action: "new"), path: "/messages/new", method: :post) + assert_recognizes(options.merge(action: "new"), path: "/messages/new", method: :get) end end end @@ -451,20 +451,20 @@ class ResourcesTest < ActionController::TestCase assert_simply_restful_for :threads assert_simply_restful_for :messages, - :name_prefix => 'thread_', - :path_prefix => 'threads/1/', - :options => { :thread_id => '1' } + name_prefix: "thread_", + path_prefix: "threads/1/", + options: { thread_id: "1" } assert_simply_restful_for :comments, - :name_prefix => 'thread_message_', - :path_prefix => 'threads/1/messages/2/', - :options => { :thread_id => '1', :message_id => '2' } + name_prefix: "thread_message_", + path_prefix: "threads/1/messages/2/", + options: { thread_id: "1", message_id: "2" } end end def test_shallow_nested_restful_routes with_routing do |set| set.draw do - resources :threads, :shallow => true do + resources :threads, shallow: true do resources :messages do resources :comments end @@ -472,17 +472,17 @@ class ResourcesTest < ActionController::TestCase end assert_simply_restful_for :threads, - :shallow => true + shallow: true assert_simply_restful_for :messages, - :name_prefix => 'thread_', - :path_prefix => 'threads/1/', - :shallow => true, - :options => { :thread_id => '1' } + name_prefix: "thread_", + path_prefix: "threads/1/", + shallow: true, + options: { thread_id: "1" } assert_simply_restful_for :comments, - :name_prefix => 'message_', - :path_prefix => 'messages/2/', - :shallow => true, - :options => { :message_id => '2' } + name_prefix: "message_", + path_prefix: "messages/2/", + shallow: true, + options: { message_id: "2" } end end @@ -491,7 +491,7 @@ class ResourcesTest < ActionController::TestCase set.draw do namespace :backoffice do namespace :admin do - resources :products, :shallow => true do + resources :products, shallow: true do resources :images end end @@ -499,18 +499,18 @@ class ResourcesTest < ActionController::TestCase end assert_simply_restful_for :products, - :controller => 'backoffice/admin/products', - :namespace => 'backoffice/admin/', - :name_prefix => 'backoffice_admin_', - :path_prefix => 'backoffice/admin/', - :shallow => true + controller: "backoffice/admin/products", + namespace: "backoffice/admin/", + name_prefix: "backoffice_admin_", + path_prefix: "backoffice/admin/", + shallow: true assert_simply_restful_for :images, - :controller => 'backoffice/admin/images', - :namespace => 'backoffice/admin/', - :name_prefix => 'backoffice_admin_product_', - :path_prefix => 'backoffice/admin/products/1/', - :shallow => true, - :options => { :product_id => '1' } + controller: "backoffice/admin/images", + namespace: "backoffice/admin/", + name_prefix: "backoffice_admin_product_", + path_prefix: "backoffice/admin/products/1/", + shallow: true, + options: { product_id: "1" } end end @@ -542,13 +542,13 @@ class ResourcesTest < ActionController::TestCase def test_should_create_nested_singleton_resource_routes with_routing do |set| set.draw do - resource :admin, :controller => 'admin' do + resource :admin, controller: "admin" do resource :account end end - assert_singleton_restful_for :admin, :controller => 'admin' - assert_singleton_restful_for :account, :name_prefix => "admin_", :path_prefix => 'admin/' + assert_singleton_restful_for :admin, controller: "admin" + assert_singleton_restful_for :account, name_prefix: "admin_", path_prefix: "admin/" end end @@ -557,14 +557,14 @@ class ResourcesTest < ActionController::TestCase with_routing do |set| set.draw do resource :account do - match :reset, :on => :member, :via => method + match :reset, on: :member, via: method end end - reset_options = {:action => 'reset'} + reset_options = { action: "reset" } reset_path = "/account/reset" assert_singleton_routes_for :account do |options| - assert_recognizes(options.merge(reset_options), :path => reset_path, :method => method) + assert_recognizes(options.merge(reset_options), path: reset_path, method: method) end assert_singleton_named_routes_for :account do @@ -579,16 +579,16 @@ class ResourcesTest < ActionController::TestCase with_routing do |set| set.draw do resource :account do - match :reset, :on => :member, :via => method - match :disable, :on => :member, :via => method + match :reset, on: :member, via: method + match :disable, on: :member, via: method end end %w(reset disable).each do |action| - action_options = {:action => action} + action_options = { action: action } action_path = "/account/#{action}" assert_singleton_routes_for :account do |options| - assert_recognizes(options.merge(action_options), :path => action_path, :method => method) + assert_recognizes(options.merge(action_options), path: action_path, method: method) end assert_singleton_named_routes_for :account do @@ -608,22 +608,22 @@ class ResourcesTest < ActionController::TestCase end assert_singleton_restful_for :account - assert_simply_restful_for :messages, :name_prefix => "account_", :path_prefix => 'account/' + assert_simply_restful_for :messages, name_prefix: "account_", path_prefix: "account/" end end def test_should_nest_resources_in_singleton_resource_with_path_scope with_routing do |set| set.draw do - scope ':site_id' do + scope ":site_id" do resource(:account) do resources :messages end end end - assert_singleton_restful_for :account, :path_prefix => '7/', :options => { :site_id => '7' } - assert_simply_restful_for :messages, :name_prefix => "account_", :path_prefix => '7/account/', :options => { :site_id => '7' } + assert_singleton_restful_for :account, path_prefix: "7/", options: { site_id: "7" } + assert_simply_restful_for :messages, name_prefix: "account_", path_prefix: "7/account/", options: { site_id: "7" } end end @@ -631,31 +631,31 @@ class ResourcesTest < ActionController::TestCase with_routing do |set| set.draw do resources :threads do - resource :admin, :controller => 'admin' + resource :admin, controller: "admin" end end assert_simply_restful_for :threads - assert_singleton_restful_for :admin, :controller => 'admin', :name_prefix => 'thread_', :path_prefix => 'threads/5/', :options => { :thread_id => '5' } + assert_singleton_restful_for :admin, controller: "admin", name_prefix: "thread_", path_prefix: "threads/5/", options: { thread_id: "5" } end end def test_should_not_allow_delete_or_patch_or_put_on_collection_path controller_name = :messages with_restful_routing controller_name do - options = { :controller => controller_name.to_s } + options = { controller: controller_name.to_s } collection_path = "/#{controller_name}" assert_raise(Assertion) do - assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :patch) + assert_recognizes(options.merge(action: "update"), path: collection_path, method: :patch) end assert_raise(Assertion) do - assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put) + assert_recognizes(options.merge(action: "update"), path: collection_path, method: :put) end assert_raise(Assertion) do - assert_recognizes(options.merge(:action => 'destroy'), :path => collection_path, :method => :delete) + assert_recognizes(options.merge(action: "destroy"), path: collection_path, method: :delete) end end end @@ -663,15 +663,15 @@ class ResourcesTest < ActionController::TestCase def test_new_style_named_routes_for_resource with_routing do |set| set.draw do - scope '/threads/:thread_id' do - resources :messages, :as => 'thread_messages' do - get :search, :on => :collection - get :preview, :on => :new + scope "/threads/:thread_id" do + resources :messages, as: "thread_messages" do + get :search, on: :collection + get :preview, on: :new end end end - assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' } + assert_simply_restful_for :messages, name_prefix: "thread_", path_prefix: "threads/1/", options: { thread_id: "1" } assert_named_route "/threads/1/messages/search", "search_thread_messages_path", {} assert_named_route "/threads/1/messages/new", "new_thread_message_path", {} assert_named_route "/threads/1/messages/new/preview", "preview_new_thread_message_path", {} @@ -681,14 +681,14 @@ class ResourcesTest < ActionController::TestCase def test_new_style_named_routes_for_singleton_resource with_routing do |set| set.draw do - scope '/admin' do - resource :account, :as => :admin_account do - get :login, :on => :member - get :preview, :on => :new + scope "/admin" do + resource :account, as: :admin_account do + get :login, on: :member + get :preview, on: :new end end end - assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/' + assert_singleton_restful_for :account, name_prefix: "admin_", path_prefix: "admin/" assert_named_route "/admin/account/login", "login_admin_account_path", {} assert_named_route "/admin/account/new", "new_admin_account_path", {} assert_named_route "/admin/account/new/preview", "preview_new_admin_account_path", {} @@ -703,7 +703,7 @@ class ResourcesTest < ActionController::TestCase end end - assert_simply_restful_for :products, :controller => "backoffice/products", :name_prefix => 'backoffice_', :path_prefix => 'backoffice/' + assert_simply_restful_for :products, controller: "backoffice/products", name_prefix: "backoffice_", path_prefix: "backoffice/" end end @@ -717,19 +717,19 @@ class ResourcesTest < ActionController::TestCase end end - assert_simply_restful_for :products, :controller => "backoffice/admin/products", :name_prefix => 'backoffice_admin_', :path_prefix => 'backoffice/admin/' + assert_simply_restful_for :products, controller: "backoffice/admin/products", name_prefix: "backoffice_admin_", path_prefix: "backoffice/admin/" end end def test_resources_using_namespace with_routing do |set| set.draw do - namespace :backoffice, :path => nil, :as => nil do + namespace :backoffice, path: nil, as: nil do resources :products end end - assert_simply_restful_for :products, :controller => "backoffice/products" + assert_simply_restful_for :products, controller: "backoffice/products" end end @@ -743,7 +743,7 @@ class ResourcesTest < ActionController::TestCase end end - assert_simply_restful_for :images, :controller => "backoffice/images", :name_prefix => 'backoffice_product_', :path_prefix => 'backoffice/products/1/', :options => {:product_id => '1'} + assert_simply_restful_for :images, controller: "backoffice/images", name_prefix: "backoffice_product_", path_prefix: "backoffice/products/1/", options: { product_id: "1" } end end @@ -759,107 +759,107 @@ class ResourcesTest < ActionController::TestCase end end - assert_simply_restful_for :images, :controller => "backoffice/admin/images", :name_prefix => 'backoffice_admin_product_', :path_prefix => 'backoffice/admin/products/1/', :options => {:product_id => '1'} + assert_simply_restful_for :images, controller: "backoffice/admin/images", name_prefix: "backoffice_admin_product_", path_prefix: "backoffice/admin/products/1/", options: { product_id: "1" } end end def test_with_path_segment with_restful_routing :messages do assert_simply_restful_for :messages - assert_recognizes({:controller => "messages", :action => "index"}, "/messages") - assert_recognizes({:controller => "messages", :action => "index"}, "/messages/") + assert_recognizes({ controller: "messages", action: "index" }, "/messages") + assert_recognizes({ controller: "messages", action: "index" }, "/messages/") end - with_routing do |set| - set.draw do - resources :messages, :path => 'reviews' - end - assert_simply_restful_for :messages, :as => 'reviews' - assert_recognizes({:controller => "messages", :action => "index"}, "/reviews") - assert_recognizes({:controller => "messages", :action => "index"}, "/reviews/") - end + with_routing do |set| + set.draw do + resources :messages, path: "reviews" + end + assert_simply_restful_for :messages, as: "reviews" + assert_recognizes({ controller: "messages", action: "index" }, "/reviews") + assert_recognizes({ controller: "messages", action: "index" }, "/reviews/") + end end def test_multiple_with_path_segment_and_controller with_routing do |set| set.draw do - resources :products do - resources :product_reviews, :path => 'reviews', :controller => 'messages' - end - resources :tutors do - resources :tutor_reviews, :path => 'reviews', :controller => 'comments' - end + resources :products do + resources :product_reviews, path: "reviews", controller: "messages" + end + resources :tutors do + resources :tutor_reviews, path: "reviews", controller: "comments" + end end - assert_simply_restful_for :product_reviews, :controller=>'messages', :as => 'reviews', :name_prefix => 'product_', :path_prefix => 'products/1/', :options => {:product_id => '1'} - assert_simply_restful_for :tutor_reviews,:controller=>'comments', :as => 'reviews', :name_prefix => 'tutor_', :path_prefix => 'tutors/1/', :options => {:tutor_id => '1'} + assert_simply_restful_for :product_reviews, controller: "messages", as: "reviews", name_prefix: "product_", path_prefix: "products/1/", options: { product_id: "1" } + assert_simply_restful_for :tutor_reviews,controller: "comments", as: "reviews", name_prefix: "tutor_", path_prefix: "tutors/1/", options: { tutor_id: "1" } end end def test_with_path_segment_path_prefix_constraints - expected_options = {:controller => 'messages', :action => 'show', :thread_id => '1.1.1', :id => '1'} + expected_options = { controller: "messages", action: "show", thread_id: "1.1.1", id: "1" } with_routing do |set| set.draw do - scope '/thread/:thread_id', :constraints => { :thread_id => /[0-9]\.[0-9]\.[0-9]/ } do - resources :messages, :path => 'comments' + scope "/thread/:thread_id", constraints: { thread_id: /[0-9]\.[0-9]\.[0-9]/ } do + resources :messages, path: "comments" end end - assert_recognizes(expected_options, :path => 'thread/1.1.1/comments/1', :method => :get) + assert_recognizes(expected_options, path: "thread/1.1.1/comments/1", method: :get) end end def test_resource_has_only_show_action with_routing do |set| set.draw do - resources :products, :only => :show + resources :products, only: :show end - assert_resource_allowed_routes('products', {}, { :id => '1' }, :show, [:index, :new, :create, :edit, :update, :destroy]) - assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :show, [:index, :new, :create, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", {}, { id: "1" }, :show, [:index, :new, :create, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", { format: "xml" }, { id: "1" }, :show, [:index, :new, :create, :edit, :update, :destroy]) end end def test_singleton_resource_has_only_show_action with_routing do |set| set.draw do - resource :account, :only => :show + resource :account, only: :show end - assert_singleton_resource_allowed_routes('accounts', {}, :show, [:index, :new, :create, :edit, :update, :destroy]) - assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :show, [:index, :new, :create, :edit, :update, :destroy]) + assert_singleton_resource_allowed_routes("accounts", {}, :show, [:index, :new, :create, :edit, :update, :destroy]) + assert_singleton_resource_allowed_routes("accounts", { format: "xml" }, :show, [:index, :new, :create, :edit, :update, :destroy]) end end def test_resource_does_not_have_destroy_action with_routing do |set| set.draw do - resources :products, :except => :destroy + resources :products, except: :destroy end - assert_resource_allowed_routes('products', {}, { :id => '1' }, [:index, :new, :create, :show, :edit, :update], :destroy) - assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, [:index, :new, :create, :show, :edit, :update], :destroy) + assert_resource_allowed_routes("products", {}, { id: "1" }, [:index, :new, :create, :show, :edit, :update], :destroy) + assert_resource_allowed_routes("products", { format: "xml" }, { id: "1" }, [:index, :new, :create, :show, :edit, :update], :destroy) end end def test_singleton_resource_does_not_have_destroy_action with_routing do |set| set.draw do - resource :account, :except => :destroy + resource :account, except: :destroy end - assert_singleton_resource_allowed_routes('accounts', {}, [:new, :create, :show, :edit, :update], :destroy) - assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, [:new, :create, :show, :edit, :update], :destroy) + assert_singleton_resource_allowed_routes("accounts", {}, [:new, :create, :show, :edit, :update], :destroy) + assert_singleton_resource_allowed_routes("accounts", { format: "xml" }, [:new, :create, :show, :edit, :update], :destroy) end end def test_resource_has_only_create_action_and_named_route with_routing do |set| set.draw do - resources :products, :only => :create + resources :products, only: :create end - assert_resource_allowed_routes('products', {}, { :id => '1' }, :create, [:index, :new, :show, :edit, :update, :destroy]) - assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :create, [:index, :new, :show, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", {}, { id: "1" }, :create, [:index, :new, :show, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", { format: "xml" }, { id: "1" }, :create, [:index, :new, :show, :edit, :update, :destroy]) assert_not_nil set.named_routes[:products] end @@ -868,11 +868,11 @@ class ResourcesTest < ActionController::TestCase def test_resource_has_only_update_action_and_named_route with_routing do |set| set.draw do - resources :products, :only => :update + resources :products, only: :update end - assert_resource_allowed_routes('products', {}, { :id => '1' }, :update, [:index, :new, :create, :show, :edit, :destroy]) - assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :update, [:index, :new, :create, :show, :edit, :destroy]) + assert_resource_allowed_routes("products", {}, { id: "1" }, :update, [:index, :new, :create, :show, :edit, :destroy]) + assert_resource_allowed_routes("products", { format: "xml" }, { id: "1" }, :update, [:index, :new, :create, :show, :edit, :destroy]) assert_not_nil set.named_routes[:product] end @@ -881,11 +881,11 @@ class ResourcesTest < ActionController::TestCase def test_resource_has_only_destroy_action_and_named_route with_routing do |set| set.draw do - resources :products, :only => :destroy + resources :products, only: :destroy end - assert_resource_allowed_routes('products', {}, { :id => '1' }, :destroy, [:index, :new, :create, :show, :edit, :update]) - assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, :destroy, [:index, :new, :create, :show, :edit, :update]) + assert_resource_allowed_routes("products", {}, { id: "1" }, :destroy, [:index, :new, :create, :show, :edit, :update]) + assert_resource_allowed_routes("products", { format: "xml" }, { id: "1" }, :destroy, [:index, :new, :create, :show, :edit, :update]) assert_not_nil set.named_routes[:product] end @@ -894,11 +894,11 @@ class ResourcesTest < ActionController::TestCase def test_singleton_resource_has_only_create_action_and_named_route with_routing do |set| set.draw do - resource :account, :only => :create + resource :account, only: :create end - assert_singleton_resource_allowed_routes('accounts', {}, :create, [:new, :show, :edit, :update, :destroy]) - assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :create, [:new, :show, :edit, :update, :destroy]) + assert_singleton_resource_allowed_routes("accounts", {}, :create, [:new, :show, :edit, :update, :destroy]) + assert_singleton_resource_allowed_routes("accounts", { format: "xml" }, :create, [:new, :show, :edit, :update, :destroy]) assert_not_nil set.named_routes[:account] end @@ -907,11 +907,11 @@ class ResourcesTest < ActionController::TestCase def test_singleton_resource_has_only_update_action_and_named_route with_routing do |set| set.draw do - resource :account, :only => :update + resource :account, only: :update end - assert_singleton_resource_allowed_routes('accounts', {}, :update, [:new, :create, :show, :edit, :destroy]) - assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :update, [:new, :create, :show, :edit, :destroy]) + assert_singleton_resource_allowed_routes("accounts", {}, :update, [:new, :create, :show, :edit, :destroy]) + assert_singleton_resource_allowed_routes("accounts", { format: "xml" }, :update, [:new, :create, :show, :edit, :destroy]) assert_not_nil set.named_routes[:account] end @@ -920,11 +920,11 @@ class ResourcesTest < ActionController::TestCase def test_singleton_resource_has_only_destroy_action_and_named_route with_routing do |set| set.draw do - resource :account, :only => :destroy + resource :account, only: :destroy end - assert_singleton_resource_allowed_routes('accounts', {}, :destroy, [:new, :create, :show, :edit, :update]) - assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, :destroy, [:new, :create, :show, :edit, :update]) + assert_singleton_resource_allowed_routes("accounts", {}, :destroy, [:new, :create, :show, :edit, :update]) + assert_singleton_resource_allowed_routes("accounts", { format: "xml" }, :destroy, [:new, :create, :show, :edit, :update]) assert_not_nil set.named_routes[:account] end @@ -933,120 +933,120 @@ class ResourcesTest < ActionController::TestCase def test_resource_has_only_collection_action with_routing do |set| set.draw do - resources :products, :only => [] do - get :sale, :on => :collection + resources :products, only: [] do + get :sale, on: :collection end end - assert_resource_allowed_routes('products', {}, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) - assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", {}, { id: "1" }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", { format: "xml" }, { id: "1" }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) - assert_recognizes({ :controller => 'products', :action => 'sale' }, :path => 'products/sale', :method => :get) - assert_recognizes({ :controller => 'products', :action => 'sale', :format => 'xml' }, :path => 'products/sale.xml', :method => :get) + assert_recognizes({ controller: "products", action: "sale" }, path: "products/sale", method: :get) + assert_recognizes({ controller: "products", action: "sale", format: "xml" }, path: "products/sale.xml", method: :get) end end def test_resource_has_only_member_action with_routing do |set| set.draw do - resources :products, :only => [] do - get :preview, :on => :member + resources :products, only: [] do + get :preview, on: :member end end - assert_resource_allowed_routes('products', {}, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) - assert_resource_allowed_routes('products', { :format => 'xml' }, { :id => '1' }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", {}, { id: "1" }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) + assert_resource_allowed_routes("products", { format: "xml" }, { id: "1" }, [], [:index, :new, :create, :show, :edit, :update, :destroy]) - assert_recognizes({ :controller => 'products', :action => 'preview', :id => '1' }, :path => 'products/1/preview', :method => :get) - assert_recognizes({ :controller => 'products', :action => 'preview', :id => '1', :format => 'xml' }, :path => 'products/1/preview.xml', :method => :get) + assert_recognizes({ controller: "products", action: "preview", id: "1" }, path: "products/1/preview", method: :get) + assert_recognizes({ controller: "products", action: "preview", id: "1", format: "xml" }, path: "products/1/preview.xml", method: :get) end end def test_singleton_resource_has_only_member_action with_routing do |set| set.draw do - resource :account, :only => [] do + resource :account, only: [] do member do get :signup end end end - assert_singleton_resource_allowed_routes('accounts', {}, [], [:new, :create, :show, :edit, :update, :destroy]) - assert_singleton_resource_allowed_routes('accounts', { :format => 'xml' }, [], [:new, :create, :show, :edit, :update, :destroy]) + assert_singleton_resource_allowed_routes("accounts", {}, [], [:new, :create, :show, :edit, :update, :destroy]) + assert_singleton_resource_allowed_routes("accounts", { format: "xml" }, [], [:new, :create, :show, :edit, :update, :destroy]) - assert_recognizes({ :controller => 'accounts', :action => 'signup' }, :path => 'account/signup', :method => :get) - assert_recognizes({ :controller => 'accounts', :action => 'signup', :format => 'xml' }, :path => 'account/signup.xml', :method => :get) + assert_recognizes({ controller: "accounts", action: "signup" }, path: "account/signup", method: :get) + assert_recognizes({ controller: "accounts", action: "signup", format: "xml" }, path: "account/signup.xml", method: :get) end end def test_nested_resource_has_only_show_and_member_action with_routing do |set| set.draw do - resources :products, :only => [:index, :show] do - resources :images, :only => :show do - get :thumbnail, :on => :member + resources :products, only: [:index, :show] do + resources :images, only: :show do + get :thumbnail, on: :member end end end - assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, :show, [:index, :new, :create, :edit, :update, :destroy], 'products/1/images') - assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, :show, [:index, :new, :create, :edit, :update, :destroy], 'products/1/images') + assert_resource_allowed_routes("images", { product_id: "1" }, { id: "2" }, :show, [:index, :new, :create, :edit, :update, :destroy], "products/1/images") + assert_resource_allowed_routes("images", { product_id: "1", format: "xml" }, { id: "2" }, :show, [:index, :new, :create, :edit, :update, :destroy], "products/1/images") - assert_recognizes({ :controller => 'images', :action => 'thumbnail', :product_id => '1', :id => '2' }, :path => 'products/1/images/2/thumbnail', :method => :get) - assert_recognizes({ :controller => 'images', :action => 'thumbnail', :product_id => '1', :id => '2', :format => 'jpg' }, :path => 'products/1/images/2/thumbnail.jpg', :method => :get) + assert_recognizes({ controller: "images", action: "thumbnail", product_id: "1", id: "2" }, path: "products/1/images/2/thumbnail", method: :get) + assert_recognizes({ controller: "images", action: "thumbnail", product_id: "1", id: "2", format: "jpg" }, path: "products/1/images/2/thumbnail.jpg", method: :get) end end def test_nested_resource_does_not_inherit_only_option with_routing do |set| set.draw do - resources :products, :only => :show do - resources :images, :except => :destroy + resources :products, only: :show do + resources :images, except: :destroy end end - assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update], :destroy, 'products/1/images') - assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update], :destroy, 'products/1/images') + assert_resource_allowed_routes("images", { product_id: "1" }, { id: "2" }, [:index, :new, :create, :show, :edit, :update], :destroy, "products/1/images") + assert_resource_allowed_routes("images", { product_id: "1", format: "xml" }, { id: "2" }, [:index, :new, :create, :show, :edit, :update], :destroy, "products/1/images") end end def test_nested_resource_does_not_inherit_only_option_by_default with_routing do |set| set.draw do - resources :products, :only => :show do + resources :products, only: :show do resources :images end end - assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update, :destroy], [], 'products/1/images') - assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update, :destroy], [], 'products/1/images') + assert_resource_allowed_routes("images", { product_id: "1" }, { id: "2" }, [:index, :new, :create, :show, :edit, :update, :destroy], [], "products/1/images") + assert_resource_allowed_routes("images", { product_id: "1", format: "xml" }, { id: "2" }, [:index, :new, :create, :show, :edit, :update, :destroy], [], "products/1/images") end end def test_nested_resource_does_not_inherit_except_option with_routing do |set| set.draw do - resources :products, :except => :show do - resources :images, :only => :destroy + resources :products, except: :show do + resources :images, only: :destroy end end - assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, :destroy, [:index, :new, :create, :show, :edit, :update], 'products/1/images') - assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, :destroy, [:index, :new, :create, :show, :edit, :update], 'products/1/images') + assert_resource_allowed_routes("images", { product_id: "1" }, { id: "2" }, :destroy, [:index, :new, :create, :show, :edit, :update], "products/1/images") + assert_resource_allowed_routes("images", { product_id: "1", format: "xml" }, { id: "2" }, :destroy, [:index, :new, :create, :show, :edit, :update], "products/1/images") end end def test_nested_resource_does_not_inherit_except_option_by_default with_routing do |set| set.draw do - resources :products, :except => :show do + resources :products, except: :show do resources :images end end - assert_resource_allowed_routes('images', { :product_id => '1' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update, :destroy], [], 'products/1/images') - assert_resource_allowed_routes('images', { :product_id => '1', :format => 'xml' }, { :id => '2' }, [:index, :new, :create, :show, :edit, :update, :destroy], [], 'products/1/images') + assert_resource_allowed_routes("images", { product_id: "1" }, { id: "2" }, [:index, :new, :create, :show, :edit, :update, :destroy], [], "products/1/images") + assert_resource_allowed_routes("images", { product_id: "1", format: "xml" }, { id: "2" }, [:index, :new, :create, :show, :edit, :update, :destroy], [], "products/1/images") end end @@ -1056,8 +1056,8 @@ class ResourcesTest < ActionController::TestCase resource :product end - assert_routing '/product', :controller => 'products', :action => 'show' - assert set.recognize_path("/product", :method => :get) + assert_routing "/product", controller: "products", action: "show" + assert set.recognize_path("/product", method: :get) end end @@ -1067,7 +1067,7 @@ class ResourcesTest < ActionController::TestCase match "/products", to: "products#show", via: :all end - assert_routing({ method: "all", path: "/products" }, { controller: "products", action: "show" }) + assert_routing({ method: "all", path: "/products" }, controller: "products", action: "show") end end @@ -1078,7 +1078,7 @@ class ResourcesTest < ActionController::TestCase end assert_raises(Minitest::Assertion) do - assert_routing({ method: "all", path: "/products" }, { controller: "products", action: "show" }) + assert_routing({ method: "all", path: "/products" }, controller: "products", action: "show") end end end @@ -1099,7 +1099,7 @@ class ResourcesTest < ActionController::TestCase with_routing do |set| set.draw do - scope(path_prefix || '') do + scope(path_prefix || "") do resources(*args) do if collection_methods collection do @@ -1125,7 +1125,7 @@ class ResourcesTest < ActionController::TestCase def with_singleton_resources(*args) with_routing do |set| - set.draw {resource(*args) } + set.draw { resource(*args) } yield end end @@ -1169,34 +1169,34 @@ class ResourcesTest < ActionController::TestCase formatted_edit_member_path = "#{member_path}/#{edit_action}.xml" with_options(route_options) do |controller| - controller.assert_routing collection_path, :action => 'index' - controller.assert_routing new_path, :action => 'new' - controller.assert_routing "#{collection_path}.xml", :action => 'index', :format => 'xml' - controller.assert_routing "#{new_path}.xml", :action => 'new', :format => 'xml' + controller.assert_routing collection_path, action: "index" + controller.assert_routing new_path, action: "new" + controller.assert_routing "#{collection_path}.xml", action: "index", format: "xml" + controller.assert_routing "#{new_path}.xml", action: "new", format: "xml" end with_options(options[:shallow_options]) do |controller| - controller.assert_routing member_path, :action => 'show', :id => '1' - controller.assert_routing edit_member_path, :action => 'edit', :id => '1' - controller.assert_routing "#{member_path}.xml", :action => 'show', :id => '1', :format => 'xml' - controller.assert_routing formatted_edit_member_path, :action => 'edit', :id => '1', :format => 'xml' - end - - assert_recognizes(route_options.merge(:action => 'index'), :path => collection_path, :method => :get) - assert_recognizes(route_options.merge(:action => 'new'), :path => new_path, :method => :get) - assert_recognizes(route_options.merge(:action => 'create'), :path => collection_path, :method => :post) - assert_recognizes(options[:shallow_options].merge(:action => 'show', :id => '1'), :path => member_path, :method => :get) - assert_recognizes(options[:shallow_options].merge(:action => 'edit', :id => '1'), :path => edit_member_path, :method => :get) - assert_recognizes(options[:shallow_options].merge(:action => 'update', :id => '1'), :path => member_path, :method => :put) - assert_recognizes(options[:shallow_options].merge(:action => 'destroy', :id => '1'), :path => member_path, :method => :delete) - - assert_recognizes(route_options.merge(:action => 'index', :format => 'xml'), :path => "#{collection_path}.xml", :method => :get) - assert_recognizes(route_options.merge(:action => 'new', :format => 'xml'), :path => "#{new_path}.xml", :method => :get) - assert_recognizes(route_options.merge(:action => 'create', :format => 'xml'), :path => "#{collection_path}.xml", :method => :post) - assert_recognizes(options[:shallow_options].merge(:action => 'show', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :get) - assert_recognizes(options[:shallow_options].merge(:action => 'edit', :id => '1', :format => 'xml'), :path => formatted_edit_member_path, :method => :get) - assert_recognizes(options[:shallow_options].merge(:action => 'update', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :put) - assert_recognizes(options[:shallow_options].merge(:action => 'destroy', :id => '1', :format => 'xml'), :path => "#{member_path}.xml", :method => :delete) + controller.assert_routing member_path, action: "show", id: "1" + controller.assert_routing edit_member_path, action: "edit", id: "1" + controller.assert_routing "#{member_path}.xml", action: "show", id: "1", format: "xml" + controller.assert_routing formatted_edit_member_path, action: "edit", id: "1", format: "xml" + end + + assert_recognizes(route_options.merge(action: "index"), path: collection_path, method: :get) + assert_recognizes(route_options.merge(action: "new"), path: new_path, method: :get) + assert_recognizes(route_options.merge(action: "create"), path: collection_path, method: :post) + assert_recognizes(options[:shallow_options].merge(action: "show", id: "1"), path: member_path, method: :get) + assert_recognizes(options[:shallow_options].merge(action: "edit", id: "1"), path: edit_member_path, method: :get) + assert_recognizes(options[:shallow_options].merge(action: "update", id: "1"), path: member_path, method: :put) + assert_recognizes(options[:shallow_options].merge(action: "destroy", id: "1"), path: member_path, method: :delete) + + assert_recognizes(route_options.merge(action: "index", format: "xml"), path: "#{collection_path}.xml", method: :get) + assert_recognizes(route_options.merge(action: "new", format: "xml"), path: "#{new_path}.xml", method: :get) + assert_recognizes(route_options.merge(action: "create", format: "xml"), path: "#{collection_path}.xml", method: :post) + assert_recognizes(options[:shallow_options].merge(action: "show", id: "1", format: "xml"), path: "#{member_path}.xml", method: :get) + assert_recognizes(options[:shallow_options].merge(action: "edit", id: "1", format: "xml"), path: formatted_edit_member_path, method: :get) + assert_recognizes(options[:shallow_options].merge(action: "update", id: "1", format: "xml"), path: "#{member_path}.xml", method: :put) + assert_recognizes(options[:shallow_options].merge(action: "destroy", id: "1", format: "xml"), path: "#{member_path}.xml", method: :delete) yield route_options if block_given? end @@ -1228,7 +1228,7 @@ class ResourcesTest < ActionController::TestCase shallow_path = "/#{options[:shallow] ? options[:namespace] : options[:path_prefix]}#{path}" full_path = "/#{options[:path_prefix]}#{path}" name_prefix = options[:name_prefix] - shallow_prefix = options[:shallow] ? options[:namespace].try(:gsub, /\//, '_') : options[:name_prefix] + shallow_prefix = options[:shallow] ? options[:namespace].try(:gsub, /\//, "_") : options[:name_prefix] new_action = "new" edit_action = "edit" @@ -1238,14 +1238,14 @@ class ResourcesTest < ActionController::TestCase end assert_named_route "#{full_path}", "#{name_prefix}#{controller_name}_path", route_options - assert_named_route "#{full_path}.xml", "#{name_prefix}#{controller_name}_path", route_options.merge(:format => 'xml') - assert_named_route "#{shallow_path}/1", "#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1') - assert_named_route "#{shallow_path}/1.xml", "#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml') + assert_named_route "#{full_path}.xml", "#{name_prefix}#{controller_name}_path", route_options.merge(format: "xml") + assert_named_route "#{shallow_path}/1", "#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(id: "1") + assert_named_route "#{shallow_path}/1.xml", "#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(id: "1", format: "xml") assert_named_route "#{full_path}/#{new_action}", "new_#{name_prefix}#{singular_name}_path", route_options - assert_named_route "#{full_path}/#{new_action}.xml", "new_#{name_prefix}#{singular_name}_path", route_options.merge(:format => 'xml') - assert_named_route "#{shallow_path}/1/#{edit_action}", "edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1') - assert_named_route "#{shallow_path}/1/#{edit_action}.xml", "edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml') + assert_named_route "#{full_path}/#{new_action}.xml", "new_#{name_prefix}#{singular_name}_path", route_options.merge(format: "xml") + assert_named_route "#{shallow_path}/1/#{edit_action}", "edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(id: "1") + assert_named_route "#{shallow_path}/1/#{edit_action}.xml", "edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(id: "1", format: "xml") yield route_options if block_given? end @@ -1260,27 +1260,27 @@ class ResourcesTest < ActionController::TestCase formatted_edit_path = "#{full_path}/edit.xml" with_options route_options do |controller| - controller.assert_routing full_path, :action => 'show' - controller.assert_routing new_path, :action => 'new' - controller.assert_routing edit_path, :action => 'edit' - controller.assert_routing "#{full_path}.xml", :action => 'show', :format => 'xml' - controller.assert_routing "#{new_path}.xml", :action => 'new', :format => 'xml' - controller.assert_routing formatted_edit_path, :action => 'edit', :format => 'xml' - end - - assert_recognizes(route_options.merge(:action => 'show'), :path => full_path, :method => :get) - assert_recognizes(route_options.merge(:action => 'new'), :path => new_path, :method => :get) - assert_recognizes(route_options.merge(:action => 'edit'), :path => edit_path, :method => :get) - assert_recognizes(route_options.merge(:action => 'create'), :path => full_path, :method => :post) - assert_recognizes(route_options.merge(:action => 'update'), :path => full_path, :method => :put) - assert_recognizes(route_options.merge(:action => 'destroy'), :path => full_path, :method => :delete) - - assert_recognizes(route_options.merge(:action => 'show', :format => 'xml'), :path => "#{full_path}.xml", :method => :get) - assert_recognizes(route_options.merge(:action => 'new', :format => 'xml'), :path => "#{new_path}.xml", :method => :get) - assert_recognizes(route_options.merge(:action => 'edit', :format => 'xml'), :path => formatted_edit_path, :method => :get) - assert_recognizes(route_options.merge(:action => 'create', :format => 'xml'), :path => "#{full_path}.xml", :method => :post) - assert_recognizes(route_options.merge(:action => 'update', :format => 'xml'), :path => "#{full_path}.xml", :method => :put) - assert_recognizes(route_options.merge(:action => 'destroy', :format => 'xml'), :path => "#{full_path}.xml", :method => :delete) + controller.assert_routing full_path, action: "show" + controller.assert_routing new_path, action: "new" + controller.assert_routing edit_path, action: "edit" + controller.assert_routing "#{full_path}.xml", action: "show", format: "xml" + controller.assert_routing "#{new_path}.xml", action: "new", format: "xml" + controller.assert_routing formatted_edit_path, action: "edit", format: "xml" + end + + assert_recognizes(route_options.merge(action: "show"), path: full_path, method: :get) + assert_recognizes(route_options.merge(action: "new"), path: new_path, method: :get) + assert_recognizes(route_options.merge(action: "edit"), path: edit_path, method: :get) + assert_recognizes(route_options.merge(action: "create"), path: full_path, method: :post) + assert_recognizes(route_options.merge(action: "update"), path: full_path, method: :put) + assert_recognizes(route_options.merge(action: "destroy"), path: full_path, method: :delete) + + assert_recognizes(route_options.merge(action: "show", format: "xml"), path: "#{full_path}.xml", method: :get) + assert_recognizes(route_options.merge(action: "new", format: "xml"), path: "#{new_path}.xml", method: :get) + assert_recognizes(route_options.merge(action: "edit", format: "xml"), path: formatted_edit_path, method: :get) + assert_recognizes(route_options.merge(action: "create", format: "xml"), path: "#{full_path}.xml", method: :post) + assert_recognizes(route_options.merge(action: "update", format: "xml"), path: "#{full_path}.xml", method: :put) + assert_recognizes(route_options.merge(action: "destroy", format: "xml"), path: "#{full_path}.xml", method: :delete) yield route_options if block_given? end @@ -1297,12 +1297,12 @@ class ResourcesTest < ActionController::TestCase name_prefix = options[:name_prefix] assert_named_route "#{full_path}", "#{name_prefix}#{singleton_name}_path", route_options - assert_named_route "#{full_path}.xml", "#{name_prefix}#{singleton_name}_path", route_options.merge(:format => 'xml') + assert_named_route "#{full_path}.xml", "#{name_prefix}#{singleton_name}_path", route_options.merge(format: "xml") assert_named_route "#{full_path}/new", "new_#{name_prefix}#{singleton_name}_path", route_options - assert_named_route "#{full_path}/new.xml", "new_#{name_prefix}#{singleton_name}_path", route_options.merge(:format => 'xml') + assert_named_route "#{full_path}/new.xml", "new_#{name_prefix}#{singleton_name}_path", route_options.merge(format: "xml") assert_named_route "#{full_path}/edit", "edit_#{name_prefix}#{singleton_name}_path", route_options - assert_named_route "#{full_path}/edit.xml", "edit_#{name_prefix}#{singleton_name}_path", route_options.merge(:format => 'xml') + assert_named_route "#{full_path}/edit.xml", "edit_#{name_prefix}#{singleton_name}_path", route_options.merge(format: "xml") end def assert_named_route(expected, route, options) @@ -1313,7 +1313,7 @@ class ResourcesTest < ActionController::TestCase def assert_resource_methods(expected, resource, action_method, method) assert_equal expected.length, resource.send("#{action_method}_methods")[method].size, "#{resource.send("#{action_method}_methods")[method].inspect}" expected.each do |action| - assert resource.send("#{action_method}_methods")[method].include?(action) + assert_includes resource.send("#{action_method}_methods")[method], action, "#{method} not in #{action_method} methods: #{resource.send("#{action_method}_methods")[method].inspect}" end end @@ -1321,41 +1321,41 @@ class ResourcesTest < ActionController::TestCase def assert_resource_allowed_routes(controller, options, shallow_options, allowed, not_allowed, path = controller) shallow_path = "#{path}/#{shallow_options[:id]}" format = options[:format] && ".#{options[:format]}" - options.merge!(:controller => controller) + options.merge!(controller: controller) shallow_options.merge!(options) - assert_whether_allowed(allowed, not_allowed, options, 'index', "#{path}#{format}", :get) - assert_whether_allowed(allowed, not_allowed, options, 'new', "#{path}/new#{format}", :get) - assert_whether_allowed(allowed, not_allowed, options, 'create', "#{path}#{format}", :post) - assert_whether_allowed(allowed, not_allowed, shallow_options, 'show', "#{shallow_path}#{format}", :get) - assert_whether_allowed(allowed, not_allowed, shallow_options, 'edit', "#{shallow_path}/edit#{format}", :get) - assert_whether_allowed(allowed, not_allowed, shallow_options, 'update', "#{shallow_path}#{format}", :put) - assert_whether_allowed(allowed, not_allowed, shallow_options, 'destroy', "#{shallow_path}#{format}", :delete) + assert_whether_allowed(allowed, not_allowed, options, "index", "#{path}#{format}", :get) + assert_whether_allowed(allowed, not_allowed, options, "new", "#{path}/new#{format}", :get) + assert_whether_allowed(allowed, not_allowed, options, "create", "#{path}#{format}", :post) + assert_whether_allowed(allowed, not_allowed, shallow_options, "show", "#{shallow_path}#{format}", :get) + assert_whether_allowed(allowed, not_allowed, shallow_options, "edit", "#{shallow_path}/edit#{format}", :get) + assert_whether_allowed(allowed, not_allowed, shallow_options, "update", "#{shallow_path}#{format}", :put) + assert_whether_allowed(allowed, not_allowed, shallow_options, "destroy", "#{shallow_path}#{format}", :delete) end def assert_singleton_resource_allowed_routes(controller, options, allowed, not_allowed, path = controller.singularize) format = options[:format] && ".#{options[:format]}" - options.merge!(:controller => controller) + options.merge!(controller: controller) - assert_whether_allowed(allowed, not_allowed, options, 'new', "#{path}/new#{format}", :get) - assert_whether_allowed(allowed, not_allowed, options, 'create', "#{path}#{format}", :post) - assert_whether_allowed(allowed, not_allowed, options, 'show', "#{path}#{format}", :get) - assert_whether_allowed(allowed, not_allowed, options, 'edit', "#{path}/edit#{format}", :get) - assert_whether_allowed(allowed, not_allowed, options, 'update', "#{path}#{format}", :put) - assert_whether_allowed(allowed, not_allowed, options, 'destroy', "#{path}#{format}", :delete) + assert_whether_allowed(allowed, not_allowed, options, "new", "#{path}/new#{format}", :get) + assert_whether_allowed(allowed, not_allowed, options, "create", "#{path}#{format}", :post) + assert_whether_allowed(allowed, not_allowed, options, "show", "#{path}#{format}", :get) + assert_whether_allowed(allowed, not_allowed, options, "edit", "#{path}/edit#{format}", :get) + assert_whether_allowed(allowed, not_allowed, options, "update", "#{path}#{format}", :put) + assert_whether_allowed(allowed, not_allowed, options, "destroy", "#{path}#{format}", :delete) end def assert_whether_allowed(allowed, not_allowed, options, action, path, method) action = action.to_sym - options = options.merge(:action => action.to_s) - path_options = { :path => path, :method => method } + options = options.merge(action: action.to_s) + path_options = { path: path, method: method } if Array(allowed).include?(action) assert_recognizes options, path_options elsif Array(not_allowed).include?(action) assert_not_recognizes options, path_options else - raise Assertion, 'Invalid Action has passed' + raise Assertion, "Invalid Action has passed" end end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 03bf8f8295..7be2ad2b28 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'controller/fake_controllers' -require 'active_support/core_ext/object/with_options' -require 'active_support/core_ext/object/json' +require "abstract_unit" +require "controller/fake_controllers" +require "active_support/core_ext/object/with_options" +require "active_support/core_ext/object/json" class MilestonesController < ActionController::Base def index() head :ok end @@ -16,12 +16,12 @@ class UriReservedCharactersRoutingTest < ActiveSupport::TestCase @set = ActionDispatch::Routing::RouteSet.new @set.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:variable/*additional' + get ":controller/:action/:variable/*additional" end end safe, unsafe = %w(: @ & = + $ , ;), %w(^ ? # [ ]) - hex = unsafe.map { |char| '%' + char.unpack('H2').first.upcase } + hex = unsafe.map { |char| "%" + char.unpack("H2").first.upcase } @segment = "#{safe.join}#{unsafe.join}".freeze @escaped = "#{safe.join}#{hex.join}".freeze @@ -29,30 +29,28 @@ class UriReservedCharactersRoutingTest < ActiveSupport::TestCase def test_route_generation_escapes_unsafe_path_characters assert_equal "/content/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2", - url_for(@set, { - :controller => "content", - :action => "act#{@segment}ion", - :variable => "var#{@segment}iable", - :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"] - }) + url_for(@set, + controller: "content", + action: "act#{@segment}ion", + variable: "var#{@segment}iable", + additional: ["add#{@segment}itional-1", "add#{@segment}itional-2"]) end def test_route_recognition_unescapes_path_components - options = { :controller => "content", - :action => "act#{@segment}ion", - :variable => "var#{@segment}iable", - :additional => "add#{@segment}itional-1/add#{@segment}itional-2" } + options = { controller: "content", + action: "act#{@segment}ion", + variable: "var#{@segment}iable", + additional: "add#{@segment}itional-1/add#{@segment}itional-2" } assert_equal options, @set.recognize_path("/content/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2") end def test_route_generation_allows_passing_non_string_values_to_generated_helper assert_equal "/content/action/variable/1/2", - url_for(@set, { - :controller => "content", - :action => "action", - :variable => "variable", - :additional => [1, 2] - }) + url_for(@set, + controller: "content", + action: "action", + variable: "variable", + additional: [1, 2]) end end @@ -86,106 +84,106 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_symbols_with_dashes rs.draw do - get '/:artist/:song-omg', :to => lambda { |env| + get "/:artist/:song-omg", to: lambda { |env| resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end - hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/faithfully-omg')) - assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash) + hash = ActiveSupport::JSON.decode get(URI("http://example.org/journey/faithfully-omg")) + assert_equal({ "artist"=>"journey", "song"=>"faithfully" }, hash) end def test_id_with_dash rs.draw do - get '/journey/:id', :to => lambda { |env| + get "/journey/:id", to: lambda { |env| resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end - hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/faithfully-omg')) - assert_equal({"id"=>"faithfully-omg"}, hash) + hash = ActiveSupport::JSON.decode get(URI("http://example.org/journey/faithfully-omg")) + assert_equal({ "id"=>"faithfully-omg" }, hash) end def test_dash_with_custom_regexp rs.draw do - get '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env| + get "/:artist/:song-omg", constraints: { song: /\d+/ }, to: lambda { |env| resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end - hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/123-omg')) - assert_equal({"artist"=>"journey", "song"=>"123"}, hash) - assert_equal 'Not Found', get(URI('http://example.org/journey/faithfully-omg')) + hash = ActiveSupport::JSON.decode get(URI("http://example.org/journey/123-omg")) + assert_equal({ "artist"=>"journey", "song"=>"123" }, hash) + assert_equal "Not Found", get(URI("http://example.org/journey/faithfully-omg")) end def test_pre_dash rs.draw do - get '/:artist/omg-:song', :to => lambda { |env| + get "/:artist/omg-:song", to: lambda { |env| resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end - hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/omg-faithfully')) - assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash) + hash = ActiveSupport::JSON.decode get(URI("http://example.org/journey/omg-faithfully")) + assert_equal({ "artist"=>"journey", "song"=>"faithfully" }, hash) end def test_pre_dash_with_custom_regexp rs.draw do - get '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env| + get "/:artist/omg-:song", constraints: { song: /\d+/ }, to: lambda { |env| resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end - hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/omg-123')) - assert_equal({"artist"=>"journey", "song"=>"123"}, hash) - assert_equal 'Not Found', get(URI('http://example.org/journey/omg-faithfully')) + hash = ActiveSupport::JSON.decode get(URI("http://example.org/journey/omg-123")) + assert_equal({ "artist"=>"journey", "song"=>"123" }, hash) + assert_equal "Not Found", get(URI("http://example.org/journey/omg-faithfully")) end def test_star_paths_are_greedy rs.draw do - get "/*path", :to => lambda { |env| + get "/*path", to: lambda { |env| x = env["action_dispatch.request.path_parameters"][:path] [200, {}, [x]] - }, :format => false + }, format: false end - u = URI('http://example.org/foo/bar.html') - assert_equal u.path.sub(/^\//, ''), get(u) + u = URI("http://example.org/foo/bar.html") + assert_equal u.path.sub(/^\//, ""), get(u) end def test_star_paths_are_greedy_but_not_too_much rs.draw do - get "/*path", :to => lambda { |env| + get "/*path", to: lambda { |env| x = ActiveSupport::JSON.encode env["action_dispatch.request.path_parameters"] [200, {}, [x]] } end expected = { "path" => "foo/bar", "format" => "html" } - u = URI('http://example.org/foo/bar.html') + u = URI("http://example.org/foo/bar.html") assert_equal expected, ActiveSupport::JSON.decode(get(u)) end def test_optional_star_paths_are_greedy rs.draw do - get "/(*filters)", :to => lambda { |env| + get "/(*filters)", to: lambda { |env| x = env["action_dispatch.request.path_parameters"][:filters] [200, {}, [x]] - }, :format => false + }, format: false end - u = URI('http://example.org/ne_27.065938,-80.6092/sw_25.489856,-82.542794') - assert_equal u.path.sub(/^\//, ''), get(u) + u = URI("http://example.org/ne_27.065938,-80.6092/sw_25.489856,-82.542794") + assert_equal u.path.sub(/^\//, ""), get(u) end def test_optional_star_paths_are_greedy_but_not_too_much rs.draw do - get "/(*filters)", :to => lambda { |env| + get "/(*filters)", to: lambda { |env| x = ActiveSupport::JSON.encode env["action_dispatch.request.path_parameters"] [200, {}, [x]] } @@ -193,65 +191,65 @@ class LegacyRouteSetTests < ActiveSupport::TestCase expected = { "filters" => "ne_27.065938,-80.6092/sw_25.489856,-82", "format" => "542794" } - u = URI('http://example.org/ne_27.065938,-80.6092/sw_25.489856,-82.542794') + u = URI("http://example.org/ne_27.065938,-80.6092/sw_25.489856,-82.542794") assert_equal expected, ActiveSupport::JSON.decode(get(u)) end def test_regexp_precidence rs.draw do - get '/whois/:domain', :constraints => { - :domain => /\w+\.[\w\.]+/ }, - :to => lambda { |env| [200, {}, %w{regexp}] } + get "/whois/:domain", constraints: { + domain: /\w+\.[\w\.]+/ }, + to: lambda { |env| [200, {}, %w{regexp}] } - get '/whois/:id', :to => lambda { |env| [200, {}, %w{id}] } + get "/whois/:id", to: lambda { |env| [200, {}, %w{id}] } end - assert_equal 'regexp', get(URI('http://example.org/whois/example.org')) - assert_equal 'id', get(URI('http://example.org/whois/123')) + assert_equal "regexp", get(URI("http://example.org/whois/example.org")) + assert_equal "id", get(URI("http://example.org/whois/123")) end def test_class_and_lambda_constraints subdomain = Class.new { - def matches? request - request.subdomain.present? and request.subdomain != 'clients' + def matches?(request) + request.subdomain.present? && request.subdomain != "clients" end } rs.draw do - get '/', :constraints => subdomain.new, - :to => lambda { |env| [200, {}, %w{default}] } - get '/', :constraints => { :subdomain => 'clients' }, - :to => lambda { |env| [200, {}, %w{clients}] } + get "/", constraints: subdomain.new, + to: lambda { |env| [200, {}, %w{default}] } + get "/", constraints: { subdomain: "clients" }, + to: lambda { |env| [200, {}, %w{clients}] } end - assert_equal 'default', get(URI('http://www.example.org/')) - assert_equal 'clients', get(URI('http://clients.example.org/')) + assert_equal "default", get(URI("http://www.example.org/")) + assert_equal "clients", get(URI("http://clients.example.org/")) end def test_lambda_constraints rs.draw do - get '/', :constraints => lambda { |req| - req.subdomain.present? and req.subdomain != "clients" }, - :to => lambda { |env| [200, {}, %w{default}] } + get "/", constraints: lambda { |req| + req.subdomain.present? && req.subdomain != "clients" }, + to: lambda { |env| [200, {}, %w{default}] } - get '/', :constraints => lambda { |req| + get "/", constraints: lambda { |req| req.subdomain.present? && req.subdomain == "clients" }, - :to => lambda { |env| [200, {}, %w{clients}] } + to: lambda { |env| [200, {}, %w{clients}] } end - assert_equal 'default', get(URI('http://www.example.org/')) - assert_equal 'clients', get(URI('http://clients.example.org/')) + assert_equal "default", get(URI("http://www.example.org/")) + assert_equal "clients", get(URI("http://clients.example.org/")) end def test_scoped_lambda scope_called = false rs.draw do - scope '/foo', :constraints => lambda { |req| scope_called = true } do - get '/', :to => lambda { |env| [200, {}, %w{default}] } + scope "/foo", constraints: lambda { |req| scope_called = true } do + get "/", to: lambda { |env| [200, {}, %w{default}] } end end - assert_equal 'default', get(URI('http://www.example.org/foo/')) + assert_equal "default", get(URI("http://www.example.org/foo/")) assert scope_called, "scope constraint should be called" end @@ -259,36 +257,36 @@ class LegacyRouteSetTests < ActiveSupport::TestCase inner_called = false rs.draw do - scope '/foo', :constraints => lambda { |req| flunk "should not be called" } do - get '/', :constraints => lambda { |req| inner_called = true }, - :to => lambda { |env| [200, {}, %w{default}] } + scope "/foo", constraints: lambda { |req| flunk "should not be called" } do + get "/", constraints: lambda { |req| inner_called = true }, + to: lambda { |env| [200, {}, %w{default}] } end end - assert_equal 'default', get(URI('http://www.example.org/foo/')) + assert_equal "default", get(URI("http://www.example.org/foo/")) assert inner_called, "inner constraint should be called" end def test_empty_string_match rs.draw do - get '/:username', :constraints => { :username => /[^\/]+/ }, - :to => lambda { |e| [200, {}, ['foo']] } + get "/:username", constraints: { username: /[^\/]+/ }, + to: lambda { |e| [200, {}, ["foo"]] } end - assert_equal 'Not Found', get(URI('http://example.org/')) - assert_equal 'foo', get(URI('http://example.org/hello')) + assert_equal "Not Found", get(URI("http://example.org/")) + assert_equal "foo", get(URI("http://example.org/hello")) end def test_non_greedy_glob_regexp params = nil rs.draw do - get '/posts/:id(/*filters)', :constraints => { :filters => /.+?/ }, - :to => lambda { |e| + get "/posts/:id(/*filters)", constraints: { filters: /.+?/ }, + to: lambda { |e| params = e["action_dispatch.request.path_parameters"] - [200, {}, ['foo']] + [200, {}, ["foo"]] } end - assert_equal 'foo', get(URI('http://example.org/posts/1/foo.js')) - assert_equal({:id=>"1", :filters=>"foo", :format=>"js"}, params) + assert_equal "foo", get(URI("http://example.org/posts/1/foo.js")) + assert_equal({ id: "1", filters: "foo", format: "js" }, params) end def test_specific_controller_action_failure @@ -297,136 +295,136 @@ class LegacyRouteSetTests < ActiveSupport::TestCase end assert_raises(ActionController::UrlGenerationError) do - url_for(rs, :controller => "omg", :action => "lol") + url_for(rs, controller: "omg", action: "lol") end end def test_default_setup - rs.draw { ActiveSupport::Deprecation.silence { get '/:controller(/:action(/:id))' } } - assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content")) - assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list")) - assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10")) + rs.draw { ActiveSupport::Deprecation.silence { get "/:controller(/:action(/:id))" } } + assert_equal({ controller: "content", action: "index" }, rs.recognize_path("/content")) + assert_equal({ controller: "content", action: "list" }, rs.recognize_path("/content/list")) + assert_equal({ controller: "content", action: "show", id: "10" }, rs.recognize_path("/content/show/10")) - assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10")) + assert_equal({ controller: "admin/user", action: "show", id: "10" }, rs.recognize_path("/admin/user/show/10")) - assert_equal '/admin/user/show/10', url_for(rs, { :controller => 'admin/user', :action => 'show', :id => 10 }) + assert_equal "/admin/user/show/10", url_for(rs, controller: "admin/user", action: "show", id: 10) - get URI('http://test.host/admin/user/list/10') + get URI("http://test.host/admin/user/list/10") - assert_equal({ :controller => 'admin/user', :action => 'list', :id => '10' }, + assert_equal({ controller: "admin/user", action: "list", id: "10" }, controller.request.path_parameters) - assert_equal '/admin/user/show', controller.url_for({ :action => 'show', :only_path => true }) - assert_equal '/admin/user/list/10', controller.url_for({:only_path => true}) + assert_equal "/admin/user/show", controller.url_for(action: "show", only_path: true) + assert_equal "/admin/user/list/10", controller.url_for(only_path: true) - assert_equal '/admin/stuff', controller.url_for({ :controller => 'stuff', :only_path => true }) - assert_equal '/stuff', controller.url_for({ :controller => '/stuff', :only_path => true }) + assert_equal "/admin/stuff", controller.url_for(controller: "stuff", only_path: true) + assert_equal "/stuff", controller.url_for(controller: "/stuff", only_path: true) end def test_route_with_colon_first rs.draw do ActiveSupport::Deprecation.silence do - get '/:controller/:action/:id', action: 'index', id: nil + get "/:controller/:action/:id", action: "index", id: nil end - get ':url', controller: 'content', action: 'translate' + get ":url", controller: "content", action: "translate" end - assert_equal({controller: 'content', action: 'translate', url: 'example'}, rs.recognize_path('/example')) + assert_equal({ controller: "content", action: "translate", url: "example" }, rs.recognize_path("/example")) end def test_route_with_regexp_for_action - rs.draw { ActiveSupport::Deprecation.silence { get '/:controller/:action', action: /auth[-|_].+/ } } + rs.draw { ActiveSupport::Deprecation.silence { get "/:controller/:action", action: /auth[-|_].+/ } } - assert_equal({ action: 'auth_google', controller: 'content' }, rs.recognize_path('/content/auth_google')) - assert_equal({ action: 'auth-facebook', controller: 'content' }, rs.recognize_path('/content/auth-facebook')) + assert_equal({ action: "auth_google", controller: "content" }, rs.recognize_path("/content/auth_google")) + assert_equal({ action: "auth-facebook", controller: "content" }, rs.recognize_path("/content/auth-facebook")) - assert_equal '/content/auth_google', url_for(rs, { controller: "content", action: "auth_google" }) - assert_equal '/content/auth-facebook', url_for(rs, { controller: "content", action: "auth-facebook" }) + assert_equal "/content/auth_google", url_for(rs, controller: "content", action: "auth_google") + assert_equal "/content/auth-facebook", url_for(rs, controller: "content", action: "auth-facebook") end def test_route_with_regexp_for_controller rs.draw do ActiveSupport::Deprecation.silence do - get ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/ - get '/:controller(/:action(/:id))' + get ":controller/:admintoken(/:action(/:id))", controller: /admin\/.+/ + get "/:controller(/:action(/:id))" end end - assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"}, + assert_equal({ controller: "admin/user", admintoken: "foo", action: "index" }, rs.recognize_path("/admin/user/foo")) - assert_equal({:controller => "content", :action => "foo"}, + assert_equal({ controller: "content", action: "foo" }, rs.recognize_path("/content/foo")) - assert_equal '/admin/user/foo', url_for(rs, { :controller => "admin/user", :admintoken => "foo", :action => "index" }) - assert_equal '/content/foo', url_for(rs, { :controller => "content", :action => "foo" }) + assert_equal "/admin/user/foo", url_for(rs, controller: "admin/user", admintoken: "foo", action: "index") + assert_equal "/content/foo", url_for(rs, controller: "content", action: "foo") end def test_route_with_regexp_and_captures_for_controller rs.draw do ActiveSupport::Deprecation.silence do - get '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/ + get "/:controller(/:action(/:id))", controller: /admin\/(accounts|users)/ end end - assert_equal({:controller => "admin/accounts", :action => "index"}, rs.recognize_path("/admin/accounts")) - assert_equal({:controller => "admin/users", :action => "index"}, rs.recognize_path("/admin/users")) + assert_equal({ controller: "admin/accounts", action: "index" }, rs.recognize_path("/admin/accounts")) + assert_equal({ controller: "admin/users", action: "index" }, rs.recognize_path("/admin/users")) assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") } end def test_route_with_regexp_and_dot rs.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:file', - :controller => /admin|user/, - :action => /upload|download/, - :defaults => {:file => nil}, - :constraints => {:file => %r{[^/]+(\.[^/]+)?}} + get ":controller/:action/:file", + controller: /admin|user/, + action: /upload|download/, + defaults: { file: nil }, + constraints: { file: %r{[^/]+(\.[^/]+)?} } end end # Without a file extension - assert_equal '/user/download/file', - url_for(rs, { :controller => "user", :action => "download", :file => "file" }) + assert_equal "/user/download/file", + url_for(rs, controller: "user", action: "download", file: "file") - assert_equal({:controller => "user", :action => "download", :file => "file"}, + assert_equal({ controller: "user", action: "download", file: "file" }, rs.recognize_path("/user/download/file")) # Now, let's try a file with an extension, really a dot (.) - assert_equal '/user/download/file.jpg', - url_for(rs, { :controller => "user", :action => "download", :file => "file.jpg" }) + assert_equal "/user/download/file.jpg", + url_for(rs, controller: "user", action: "download", file: "file.jpg") - assert_equal({:controller => "user", :action => "download", :file => "file.jpg"}, + assert_equal({ controller: "user", action: "download", file: "file.jpg" }, rs.recognize_path("/user/download/file.jpg")) end def test_basic_named_route rs.draw do - root :to => 'content#list', :as => 'home' + root to: "content#list", as: "home" end assert_equal("http://test.host/", setup_for_named_route.send(:home_url)) end def test_named_route_with_option rs.draw do - get 'page/:title' => 'content#show_page', :as => 'page' + get "page/:title" => "content#show_page", :as => "page" end assert_equal("http://test.host/page/new%20stuff", - setup_for_named_route.send(:page_url, :title => 'new stuff')) + setup_for_named_route.send(:page_url, title: "new stuff")) end def test_named_route_with_default rs.draw do - get 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page' + get "page/:title" => "content#show_page", :title => "AboutPage", :as => "page" end assert_equal("http://test.host/page/AboutRails", - setup_for_named_route.send(:page_url, :title => "AboutRails")) + setup_for_named_route.send(:page_url, title: "AboutRails")) end def test_named_route_with_path_prefix rs.draw do scope "my" do - get 'page' => 'content#show_page', :as => 'page' + get "page" => "content#show_page", :as => "page" end end @@ -437,7 +435,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_named_route_with_blank_path_prefix rs.draw do scope "" do - get 'page' => 'content#show_page', :as => 'page' + get "page" => "content#show_page", :as => "page" end end @@ -447,7 +445,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_named_route_with_nested_controller rs.draw do - get 'admin/user' => 'admin/user#index', :as => "users" + get "admin/user" => "admin/user#index", :as => "users" end assert_equal("http://test.host/admin/user", @@ -456,7 +454,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_optimised_named_route_with_host rs.draw do - get 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com' + get "page" => "content#show_page", :as => "pages", :host => "foo.com" end routes = setup_for_named_route assert_equal "http://foo.com/page", routes.pages_url @@ -469,14 +467,14 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_named_route_without_hash rs.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:id', :as => 'normal' + get ":controller/:action/:id", as: "normal" end end end def test_named_route_root rs.draw do - root :to => "hello#index" + root to: "hello#index" end routes = setup_for_named_route assert_equal("http://test.host/", routes.send(:root_url)) @@ -520,62 +518,62 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_named_route_with_regexps rs.draw do - get 'page/:year/:month/:day/:title' => 'page#show', :as => 'article', + get "page/:year/:month/:day/:title" => "page#show", :as => "article", :year => /\d+/, :month => /\d+/, :day => /\d+/ ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end routes = setup_for_named_route assert_equal "http://test.host/page/2005/6/10/hi", - routes.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6) + routes.send(:article_url, title: "hi", day: 10, year: 2005, month: 6) end def test_changing_controller - rs.draw { ActiveSupport::Deprecation.silence { get ':controller/:action/:id' } } + rs.draw { ActiveSupport::Deprecation.silence { get ":controller/:action/:id" } } - get URI('http://test.host/admin/user/index/10') + get URI("http://test.host/admin/user/index/10") - assert_equal '/admin/stuff/show/10', - controller.url_for({:controller => 'stuff', :action => 'show', :id => 10, :only_path => true}) + assert_equal "/admin/stuff/show/10", + controller.url_for(controller: "stuff", action: "show", id: 10, only_path: true) end def test_paths_escaped rs.draw do - get 'file/*path' => 'content#show_file', :as => 'path' + get "file/*path" => "content#show_file", :as => "path" ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end # No + to space in URI escaping, only for query params. results = rs.recognize_path "/file/hello+world/how+are+you%3F" assert results, "Recognition should have succeeded" - assert_equal 'hello+world/how+are+you?', results[:path] + assert_equal "hello+world/how+are+you?", results[:path] # Use %20 for space instead. results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F" assert results, "Recognition should have succeeded" - assert_equal 'hello world/how are you?', results[:path] + assert_equal "hello world/how are you?", results[:path] end def test_paths_slashes_unescaped_with_ordered_parameters rs.draw do - get '/file/*path' => 'content#index', :as => 'path' + get "/file/*path" => "content#index", :as => "path" end # No / to %2F in URI, only for query params. - assert_equal("/file/hello/world", setup_for_named_route.send(:path_path, ['hello', 'world'])) + assert_equal("/file/hello/world", setup_for_named_route.send(:path_path, ["hello", "world"])) end def test_non_controllers_cannot_be_matched rs.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") } @@ -583,186 +581,186 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_should_list_options_diff_when_routing_constraints_dont_match rs.draw do - get 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post' + get "post/:id" => "post#show", :constraints => { id: /\d+/ }, :as => "post" end assert_raise(ActionController::UrlGenerationError) do - url_for(rs, { :controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post" }) + url_for(rs, controller: "post", action: "show", bad_param: "foo", use_route: "post") end end def test_dynamic_path_allowed rs.draw do - get '*path' => 'content#show_file' + get "*path" => "content#show_file" end - assert_equal '/pages/boo', - url_for(rs, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) }) + assert_equal "/pages/boo", + url_for(rs, controller: "content", action: "show_file", path: %w(pages boo)) end def test_dynamic_recall_paths_allowed rs.draw do - get '*path' => 'content#show_file' + get "*path" => "content#show_file" end - get URI('http://test.host/pages/boo') - assert_equal({:controller=>"content", :action=>"show_file", :path=>"pages/boo"}, + get URI("http://test.host/pages/boo") + assert_equal({ controller: "content", action: "show_file", path: "pages/boo" }, controller.request.path_parameters) - assert_equal '/pages/boo', - controller.url_for(:only_path => true) + assert_equal "/pages/boo", + controller.url_for(only_path: true) end def test_backwards rs.draw do ActiveSupport::Deprecation.silence do - get 'page/:id(/:action)' => 'pages#show' - get ':controller(/:action(/:id))' + get "page/:id(/:action)" => "pages#show" + get ":controller(/:action(/:id))" end end - get URI('http://test.host/pages/show') - assert_equal '/page/20', controller.url_for({ :id => 20, :only_path => true }) - assert_equal '/page/20', url_for(rs, { :controller => 'pages', :id => 20, :action => 'show' }) - assert_equal '/pages/boo', url_for(rs, { :controller => 'pages', :action => 'boo' }) + get URI("http://test.host/pages/show") + assert_equal "/page/20", controller.url_for(id: 20, only_path: true) + assert_equal "/page/20", url_for(rs, controller: "pages", id: 20, action: "show") + assert_equal "/pages/boo", url_for(rs, controller: "pages", action: "boo") end def test_route_with_integer_default rs.draw do - get 'page(/:id)' => 'content#show_page', :id => 1 + get "page(/:id)" => "content#show_page", :id => 1 ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end - assert_equal '/page', url_for(rs, { :controller => 'content', :action => 'show_page' }) - assert_equal '/page', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 1 }) - assert_equal '/page', url_for(rs, { :controller => 'content', :action => 'show_page', :id => '1' }) - assert_equal '/page/10', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 10 }) + assert_equal "/page", url_for(rs, controller: "content", action: "show_page") + assert_equal "/page", url_for(rs, controller: "content", action: "show_page", id: 1) + assert_equal "/page", url_for(rs, controller: "content", action: "show_page", id: "1") + assert_equal "/page/10", url_for(rs, controller: "content", action: "show_page", id: 10) - assert_equal({:controller => "content", :action => 'show_page', :id => 1 }, rs.recognize_path("/page")) - assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1")) - assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10")) + assert_equal({ controller: "content", action: "show_page", id: 1 }, rs.recognize_path("/page")) + assert_equal({ controller: "content", action: "show_page", id: "1" }, rs.recognize_path("/page/1")) + assert_equal({ controller: "content", action: "show_page", id: "10" }, rs.recognize_path("/page/10")) end # For newer revision def test_route_with_text_default rs.draw do - get 'page/:id' => 'content#show_page', :id => 1 + get "page/:id" => "content#show_page", :id => 1 ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end - assert_equal '/page/foo', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 'foo' }) - assert_equal({ :controller => "content", :action => 'show_page', :id => 'foo' }, rs.recognize_path("/page/foo")) + assert_equal "/page/foo", url_for(rs, controller: "content", action: "show_page", id: "foo") + assert_equal({ controller: "content", action: "show_page", id: "foo" }, rs.recognize_path("/page/foo")) token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in Russian token.force_encoding(Encoding::BINARY) escaped_token = CGI::escape(token) - assert_equal '/page/' + escaped_token, url_for(rs, { :controller => 'content', :action => 'show_page', :id => token }) - assert_equal({ :controller => "content", :action => 'show_page', :id => token }, rs.recognize_path("/page/#{escaped_token}")) + assert_equal "/page/" + escaped_token, url_for(rs, controller: "content", action: "show_page", id: token) + assert_equal({ controller: "content", action: "show_page", id: token }, rs.recognize_path("/page/#{escaped_token}")) end def test_action_expiry - rs.draw { ActiveSupport::Deprecation.silence { get ':controller(/:action(/:id))' } } - get URI('http://test.host/content/show') - assert_equal '/content', controller.url_for(:controller => 'content', :only_path => true) + rs.draw { ActiveSupport::Deprecation.silence { get ":controller(/:action(/:id))" } } + get URI("http://test.host/content/show") + assert_equal "/content", controller.url_for(controller: "content", only_path: true) end def test_requirement_should_prevent_optional_id rs.draw do - get 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post' + get "post/:id" => "post#show", :constraints => { id: /\d+/ }, :as => "post" end - assert_equal '/post/10', url_for(rs, { :controller => 'post', :action => 'show', :id => 10 }) + assert_equal "/post/10", url_for(rs, controller: "post", action: "show", id: 10) assert_raise(ActionController::UrlGenerationError) do - url_for(rs, { :controller => 'post', :action => 'show' }) + url_for(rs, controller: "post", action: "show") end end def test_both_requirement_and_optional rs.draw do - get('test(/:year)' => 'post#show', :as => 'blog', - :defaults => { :year => nil }, - :constraints => { :year => /\d{4}/ } + get("test(/:year)" => "post#show", :as => "blog", + :defaults => { year: nil }, + :constraints => { year: /\d{4}/ } ) ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end - assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show' }) - assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show', :year => nil }) + assert_equal "/test", url_for(rs, controller: "post", action: "show") + assert_equal "/test", url_for(rs, controller: "post", action: "show", year: nil) assert_equal("http://test.host/test", setup_for_named_route.send(:blog_url)) end def test_set_to_nil_forgets rs.draw do - get 'pages(/:year(/:month(/:day)))' => 'content#list_pages', :month => nil, :day => nil + get "pages(/:year(/:month(/:day)))" => "content#list_pages", :month => nil, :day => nil ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end - assert_equal '/pages/2005', - url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005 }) - assert_equal '/pages/2005/6', - url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6 }) - assert_equal '/pages/2005/6/12', - url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12 }) + assert_equal "/pages/2005", + url_for(rs, controller: "content", action: "list_pages", year: 2005) + assert_equal "/pages/2005/6", + url_for(rs, controller: "content", action: "list_pages", year: 2005, month: 6) + assert_equal "/pages/2005/6/12", + url_for(rs, controller: "content", action: "list_pages", year: 2005, month: 6, day: 12) - get URI('http://test.host/pages/2005/6/12') - assert_equal({ :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' }, + get URI("http://test.host/pages/2005/6/12") + assert_equal({ controller: "content", action: "list_pages", year: "2005", month: "6", day: "12" }, controller.request.path_parameters) - assert_equal '/pages/2005/6/4', - controller.url_for({ :day => 4, :only_path => true }) + assert_equal "/pages/2005/6/4", + controller.url_for(day: 4, only_path: true) - assert_equal '/pages/2005/6', - controller.url_for({ :day => nil, :only_path => true }) + assert_equal "/pages/2005/6", + controller.url_for(day: nil, only_path: true) - assert_equal '/pages/2005', - controller.url_for({ :day => nil, :month => nil, :only_path => true }) + assert_equal "/pages/2005", + controller.url_for(day: nil, month: nil, only_path: true) end def test_root_url_generation_with_controller_and_action rs.draw do - root :to => "content#index" + root to: "content#index" end - assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' }) - assert_equal '/', url_for(rs, { :controller => 'content' }) + assert_equal "/", url_for(rs, controller: "content", action: "index") + assert_equal "/", url_for(rs, controller: "content") end def test_named_root_url_generation_with_controller_and_action rs.draw do - root :to => "content#index", :as => 'home' + root to: "content#index", as: "home" end - assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' }) - assert_equal '/', url_for(rs, { :controller => 'content' }) + assert_equal "/", url_for(rs, controller: "content", action: "index") + assert_equal "/", url_for(rs, controller: "content") assert_equal("http://test.host/", setup_for_named_route.send(:home_url)) end def test_named_route_method rs.draw do - get 'categories' => 'content#categories', :as => 'categories' + get "categories" => "content#categories", :as => "categories" ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end - assert_equal '/categories', url_for(rs, { :controller => 'content', :action => 'categories' }) - assert_equal '/content/hi', url_for(rs, { :controller => 'content', :action => 'hi' }) + assert_equal "/categories", url_for(rs, controller: "content", action: "categories") + assert_equal "/content/hi", url_for(rs, controller: "content", action: "hi") end def test_named_routes_array @@ -772,56 +770,55 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_nil_defaults rs.draw do - get 'journal' => 'content#list_journal', + get "journal" => "content#list_journal", :date => nil, :user_id => nil ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end - assert_equal '/journal', url_for(rs, { - :controller => 'content', - :action => 'list_journal', - :date => nil, - :user_id => nil - }) + assert_equal "/journal", url_for(rs, + controller: "content", + action: "list_journal", + date: nil, + user_id: nil) end def setup_request_method_routes_for(method) rs.draw do - match '/match' => "books##{method}", :via => method.to_sym + match "/match" => "books##{method}", :via => method.to_sym end end %w(GET PATCH POST PUT DELETE).each do |request_method| define_method("test_request_method_recognized_with_#{request_method}") do setup_request_method_routes_for(request_method.downcase) - params = rs.recognize_path("/match", :method => request_method) + params = rs.recognize_path("/match", method: request_method) assert_equal request_method.downcase, params[:action] end end def test_recognize_array_of_methods rs.draw do - match '/match' => 'books#get_or_post', :via => [:get, :post] - put '/match' => 'books#not_get_or_post' + match "/match" => "books#get_or_post", :via => [:get, :post] + put "/match" => "books#not_get_or_post" end - params = rs.recognize_path("/match", :method => :post) - assert_equal 'get_or_post', params[:action] + params = rs.recognize_path("/match", method: :post) + assert_equal "get_or_post", params[:action] - params = rs.recognize_path("/match", :method => :put) - assert_equal 'not_get_or_post', params[:action] + params = rs.recognize_path("/match", method: :put) + assert_equal "not_get_or_post", params[:action] end def test_subpath_recognized rs.draw do ActiveSupport::Deprecation.silence do - get '/books/:id/edit' => 'subpath_books#edit' - get '/items/:id/:action' => 'subpath_books' - get '/posts/new/:action' => 'subpath_books' - get '/posts/:id' => 'subpath_books#show' + get "/books/:id/edit" => "subpath_books#edit" + get "/items/:id/:action" => "subpath_books" + get "/posts/new/:action" => "subpath_books" + get "/posts/:id" => "subpath_books#show" end end @@ -845,20 +842,20 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_subpath_generated rs.draw do ActiveSupport::Deprecation.silence do - get '/books/:id/edit' => 'subpath_books#edit' - get '/items/:id/:action' => 'subpath_books' - get '/posts/new/:action' => 'subpath_books' + get "/books/:id/edit" => "subpath_books#edit" + get "/items/:id/:action" => "subpath_books" + get "/posts/new/:action" => "subpath_books" end end - assert_equal "/books/7/edit", url_for(rs, { :controller => "subpath_books", :id => 7, :action => "edit" }) - assert_equal "/items/15/complete", url_for(rs, { :controller => "subpath_books", :id => 15, :action => "complete" }) - assert_equal "/posts/new/preview", url_for(rs, { :controller => "subpath_books", :action => "preview" }) + assert_equal "/books/7/edit", url_for(rs, controller: "subpath_books", id: 7, action: "edit") + assert_equal "/items/15/complete", url_for(rs, controller: "subpath_books", id: 15, action: "complete") + assert_equal "/posts/new/preview", url_for(rs, controller: "subpath_books", action: "preview") end def test_failed_constraints_raises_exception_with_violated_constraints rs.draw do - get 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ } + get "foos/:id" => "foos#show", :as => "foo_with_requirement", :constraints => { id: /\d+/ } end assert_raise(ActionController::UrlGenerationError) do @@ -869,13 +866,13 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_routes_changed_correctly_after_clear rs = ::ActionDispatch::Routing::RouteSet.new rs.draw do - get 'ca' => 'ca#aa' - get 'cb' => 'cb#ab' - get 'cc' => 'cc#ac' + get "ca" => "ca#aa" + get "cb" => "cb#ab" + get "cc" => "cc#ac" ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' - get ':controller/:action/:id.:format' + get ":controller/:action/:id" + get ":controller/:action/:id.:format" end end @@ -885,12 +882,12 @@ class LegacyRouteSetTests < ActiveSupport::TestCase assert_equal %w(cc ac), [hash[:controller], hash[:action]] rs.draw do - get 'cb' => 'cb#ab' - get 'cc' => 'cc#ac' + get "cb" => "cb#ab" + get "cc" => "cc#ac" ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' - get ':controller/:action/:id.:format' + get ":controller/:action/:id" + get ":controller/:action/:id.:format" end end @@ -924,7 +921,7 @@ class RouteSetTest < ActiveSupport::TestCase set.draw do ActiveSupport::Deprecation.silence do - get '/:controller(/:action(/:id))' + get "/:controller(/:action(/:id))" end end set @@ -932,26 +929,26 @@ class RouteSetTest < ActiveSupport::TestCase end def test_generate_extras - set.draw { ActiveSupport::Deprecation.silence { get ':controller/(:action(/:id))' } } - path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + set.draw { ActiveSupport::Deprecation.silence { get ":controller/(:action(/:id))" } } + path, extras = set.generate_extras(controller: "foo", action: "bar", id: 15, this: "hello", that: "world") assert_equal "/foo/bar/15", path assert_equal %w(that this), extras.map(&:to_s).sort end def test_extra_keys - set.draw { ActiveSupport::Deprecation.silence { get ':controller/:action/:id' } } - extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + set.draw { ActiveSupport::Deprecation.silence { get ":controller/:action/:id" } } + extras = set.extra_keys(controller: "foo", action: "bar", id: 15, this: "hello", that: "world") assert_equal %w(that this), extras.map(&:to_s).sort end def test_generate_extras_not_first set.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:id.:format' - get ':controller/:action/:id' + get ":controller/:action/:id.:format" + get ":controller/:action/:id" end end - path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + path, extras = set.generate_extras(controller: "foo", action: "bar", id: 15, this: "hello", that: "world") assert_equal "/foo/bar/15", path assert_equal %w(that this), extras.map(&:to_s).sort end @@ -959,29 +956,29 @@ class RouteSetTest < ActiveSupport::TestCase def test_generate_not_first set.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:id.:format' - get ':controller/:action/:id' + get ":controller/:action/:id.:format" + get ":controller/:action/:id" end end assert_equal "/foo/bar/15?this=hello", - url_for(set, { :controller => "foo", :action => "bar", :id => 15, :this => "hello" }) + url_for(set, controller: "foo", action: "bar", id: 15, this: "hello") end def test_extra_keys_not_first set.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:id.:format' - get ':controller/:action/:id' + get ":controller/:action/:id.:format" + get ":controller/:action/:id" end end - extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world") + extras = set.extra_keys(controller: "foo", action: "bar", id: 15, this: "hello", that: "world") assert_equal %w(that this), extras.map(&:to_s).sort end def test_draw assert_equal 0, set.routes.size set.draw do - get '/hello/world' => 'a#b' + get "/hello/world" => "a#b" end assert_equal 1, set.routes.size end @@ -989,16 +986,16 @@ class RouteSetTest < ActiveSupport::TestCase def test_draw_symbol_controller_name assert_equal 0, set.routes.size set.draw do - get '/users/index' => 'users#index' + get "/users/index" => "users#index" end - set.recognize_path('/users/index', :method => :get) + set.recognize_path("/users/index", method: :get) assert_equal 1, set.routes.size end def test_named_draw assert_equal 0, set.routes.size set.draw do - get '/hello/world' => 'a#b', :as => 'hello' + get "/hello/world" => "a#b", :as => "hello" end assert_equal 1, set.routes.size assert_equal set.routes.first, set.named_routes[:hello] @@ -1007,57 +1004,57 @@ class RouteSetTest < ActiveSupport::TestCase def test_duplicate_named_route_raises_rather_than_pick_precedence assert_raise ArgumentError do set.draw do - get '/hello/world' => 'a#b', :as => 'hello' - get '/hello' => 'a#b', :as => 'hello' + get "/hello/world" => "a#b", :as => "hello" + get "/hello" => "a#b", :as => "hello" end end end def setup_named_route_test set.draw do - get '/people(/:id)' => 'people#show', :as => 'show' - get '/people' => 'people#index', :as => 'index' - get '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi' - get '/admin/users' => 'admin/users#index', :as => "users" + get "/people(/:id)" => "people#show", :as => "show" + get "/people" => "people#index", :as => "index" + get "/people/go/:foo/:bar/joe(/:id)" => "people#multi", :as => "multi" + get "/admin/users" => "admin/users#index", :as => "users" end - get URI('http://test.host/people') + get URI("http://test.host/people") controller end def test_named_route_url_method controller = setup_named_route_test - assert_equal "http://test.host/people/5", controller.send(:show_url, :id => 5) - assert_equal "/people/5", controller.send(:show_path, :id => 5) + assert_equal "http://test.host/people/5", controller.send(:show_url, id: 5) + assert_equal "/people/5", controller.send(:show_path, id: 5) assert_equal "http://test.host/people", controller.send(:index_url) assert_equal "/people", controller.send(:index_path) assert_equal "http://test.host/admin/users", controller.send(:users_url) - assert_equal '/admin/users', controller.send(:users_path) + assert_equal "/admin/users", controller.send(:users_path) end def test_named_route_url_method_with_anchor controller = setup_named_route_test - assert_equal "http://test.host/people/5#location", controller.send(:show_url, :id => 5, :anchor => 'location') - assert_equal "/people/5#location", controller.send(:show_path, :id => 5, :anchor => 'location') + assert_equal "http://test.host/people/5#location", controller.send(:show_url, id: 5, anchor: "location") + assert_equal "/people/5#location", controller.send(:show_path, id: 5, anchor: "location") - assert_equal "http://test.host/people#location", controller.send(:index_url, :anchor => 'location') - assert_equal "/people#location", controller.send(:index_path, :anchor => 'location') + assert_equal "http://test.host/people#location", controller.send(:index_url, anchor: "location") + assert_equal "/people#location", controller.send(:index_path, anchor: "location") - assert_equal "http://test.host/admin/users#location", controller.send(:users_url, :anchor => 'location') - assert_equal '/admin/users#location', controller.send(:users_path, :anchor => 'location') + assert_equal "http://test.host/admin/users#location", controller.send(:users_url, anchor: "location") + assert_equal "/admin/users#location", controller.send(:users_path, anchor: "location") assert_equal "http://test.host/people/go/7/hello/joe/5#location", - controller.send(:multi_url, 7, "hello", 5, :anchor => 'location') + controller.send(:multi_url, 7, "hello", 5, anchor: "location") assert_equal "http://test.host/people/go/7/hello/joe/5?baz=bar#location", - controller.send(:multi_url, 7, "hello", 5, :baz => "bar", :anchor => 'location') + controller.send(:multi_url, 7, "hello", 5, baz: "bar", anchor: "location") assert_equal "http://test.host/people?baz=bar#location", - controller.send(:index_url, :baz => "bar", :anchor => 'location') + controller.send(:index_url, baz: "bar", anchor: "location") assert_equal "http://test.host/people", controller.send(:index_url, anchor: nil) assert_equal "http://test.host/people", controller.send(:index_url, anchor: false) @@ -1065,17 +1062,17 @@ class RouteSetTest < ActiveSupport::TestCase def test_named_route_url_method_with_port controller = setup_named_route_test - assert_equal "http://test.host:8080/people/5", controller.send(:show_url, 5, :port=>8080) + assert_equal "http://test.host:8080/people/5", controller.send(:show_url, 5, port: 8080) end def test_named_route_url_method_with_host controller = setup_named_route_test - assert_equal "http://some.example.com/people/5", controller.send(:show_url, 5, :host=>"some.example.com") + assert_equal "http://some.example.com/people/5", controller.send(:show_url, 5, host: "some.example.com") end def test_named_route_url_method_with_protocol controller = setup_named_route_test - assert_equal "https://test.host/people/5", controller.send(:show_url, 5, :protocol => "https") + assert_equal "https://test.host/people/5", controller.send(:show_url, 5, protocol: "https") end def test_named_route_url_method_with_ordered_parameters @@ -1087,7 +1084,7 @@ class RouteSetTest < ActiveSupport::TestCase def test_named_route_url_method_with_ordered_parameters_and_hash controller = setup_named_route_test assert_equal "http://test.host/people/go/7/hello/joe/5?baz=bar", - controller.send(:multi_url, 7, "hello", 5, :baz => "bar") + controller.send(:multi_url, 7, "hello", 5, baz: "bar") end def test_named_route_url_method_with_ordered_parameters_and_empty_hash @@ -1099,46 +1096,46 @@ class RouteSetTest < ActiveSupport::TestCase def test_named_route_url_method_with_no_positional_arguments controller = setup_named_route_test assert_equal "http://test.host/people?baz=bar", - controller.send(:index_url, :baz => "bar") + controller.send(:index_url, baz: "bar") end def test_draw_default_route set.draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end assert_equal 1, set.routes.size - assert_equal '/users/show/10', url_for(set, { :controller => 'users', :action => 'show', :id => 10 }) - assert_equal '/users/index/10', url_for(set, { :controller => 'users', :id => 10 }) + assert_equal "/users/show/10", url_for(set, controller: "users", action: "show", id: 10) + assert_equal "/users/index/10", url_for(set, controller: "users", id: 10) - assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10')) - assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/')) + assert_equal({ controller: "users", action: "index", id: "10" }, set.recognize_path("/users/index/10")) + assert_equal({ controller: "users", action: "index", id: "10" }, set.recognize_path("/users/index/10/")) end def test_route_with_parameter_shell set.draw do - get 'page/:id' => 'pages#show', :id => /\d+/ + get "page/:id" => "pages#show", :id => /\d+/ ActiveSupport::Deprecation.silence do - get '/:controller(/:action(/:id))' + get "/:controller(/:action(/:id))" end end - assert_equal({:controller => 'pages', :action => 'index'}, request_path_params('/pages')) - assert_equal({:controller => 'pages', :action => 'index'}, request_path_params('/pages/index')) - assert_equal({:controller => 'pages', :action => 'list'}, request_path_params('/pages/list')) + assert_equal({ controller: "pages", action: "index" }, request_path_params("/pages")) + assert_equal({ controller: "pages", action: "index" }, request_path_params("/pages/index")) + assert_equal({ controller: "pages", action: "list" }, request_path_params("/pages/list")) - assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, request_path_params('/pages/show/10')) - assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, request_path_params('/page/10')) + assert_equal({ controller: "pages", action: "show", id: "10" }, request_path_params("/pages/show/10")) + assert_equal({ controller: "pages", action: "show", id: "10" }, request_path_params("/page/10")) end def test_route_constraints_on_request_object_with_anchors_are_valid assert_nothing_raised do set.draw do - get 'page/:id' => 'pages#show', :constraints => { :host => /^foo$/ } + get "page/:id" => "pages#show", :constraints => { host: /^foo$/ } end end end @@ -1146,27 +1143,27 @@ class RouteSetTest < ActiveSupport::TestCase def test_route_constraints_with_anchor_chars_are_invalid assert_raise ArgumentError do set.draw do - get 'page/:id' => 'pages#show', :id => /^\d+/ + get "page/:id" => "pages#show", :id => /^\d+/ end end assert_raise ArgumentError do set.draw do - get 'page/:id' => 'pages#show', :id => /\A\d+/ + get "page/:id" => "pages#show", :id => /\A\d+/ end end assert_raise ArgumentError do set.draw do - get 'page/:id' => 'pages#show', :id => /\d+$/ + get "page/:id" => "pages#show", :id => /\d+$/ end end assert_raise ArgumentError do set.draw do - get 'page/:id' => 'pages#show', :id => /\d+\Z/ + get "page/:id" => "pages#show", :id => /\d+\Z/ end end assert_raise ArgumentError do set.draw do - get 'page/:id' => 'pages#show', :id => /\d+\z/ + get "page/:id" => "pages#show", :id => /\d+\z/ end end end @@ -1174,7 +1171,7 @@ class RouteSetTest < ActiveSupport::TestCase def test_route_constraints_with_options_method_condition_is_valid assert_nothing_raised do set.draw do - match 'valid/route' => 'pages#show', :via => :options + match "valid/route" => "pages#show", :via => :options end end end @@ -1184,16 +1181,16 @@ class RouteSetTest < ActiveSupport::TestCase get "/people" => "missing#index" end - assert_raises(ActionController::RoutingError) { request_path_params '/people' } + assert_raises(ActionController::RoutingError) { request_path_params "/people" } end def test_recognize_with_encoded_id_and_regex set.draw do - get 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/ + get "page/:id" => "pages#show", :id => /[a-zA-Z0-9\+]+/ end - assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, request_path_params('/page/10')) - assert_equal({:controller => 'pages', :action => 'show', :id => 'hello+world'}, request_path_params('/page/hello+world')) + assert_equal({ controller: "pages", action: "show", id: "10" }, request_path_params("/page/10")) + assert_equal({ controller: "pages", action: "show", id: "hello+world" }, request_path_params("/page/hello+world")) end def test_recognize_with_http_methods @@ -1206,65 +1203,65 @@ class RouteSetTest < ActiveSupport::TestCase delete "/people/:id" => "people#destroy" end - params = request_path_params("/people", :method => :get) + params = request_path_params("/people", method: :get) assert_equal("index", params[:action]) - params = request_path_params("/people", :method => :post) + params = request_path_params("/people", method: :post) assert_equal("create", params[:action]) - params = request_path_params("/people/5", :method => :put) + params = request_path_params("/people/5", method: :put) assert_equal("update", params[:action]) - params = request_path_params("/people/5", :method => :patch) + params = request_path_params("/people/5", method: :patch) assert_equal("update", params[:action]) assert_raise(ActionController::UnknownHttpMethod) { - request_path_params("/people", :method => :bacon) + request_path_params("/people", method: :bacon) } - params = request_path_params("/people/5", :method => :get) + params = request_path_params("/people/5", method: :get) assert_equal("show", params[:action]) assert_equal("5", params[:id]) - params = request_path_params("/people/5", :method => :put) + params = request_path_params("/people/5", method: :put) assert_equal("update", params[:action]) assert_equal("5", params[:id]) - params = request_path_params("/people/5", :method => :patch) + params = request_path_params("/people/5", method: :patch) assert_equal("update", params[:action]) assert_equal("5", params[:id]) - params = request_path_params("/people/5", :method => :delete) + params = request_path_params("/people/5", method: :delete) assert_equal("destroy", params[:action]) assert_equal("5", params[:id]) assert_raise(ActionController::RoutingError) { - request_path_params("/people/5", :method => :post) + request_path_params("/people/5", method: :post) } end def test_recognize_with_alias_in_conditions set.draw do - match "/people" => 'people#index', :as => 'people', :via => :get - root :to => "people#index" + match "/people" => "people#index", :as => "people", :via => :get + root to: "people#index" end - params = request_path_params("/people", :method => :get) + params = request_path_params("/people", method: :get) assert_equal("people", params[:controller]) assert_equal("index", params[:action]) - params = request_path_params("/", :method => :get) + params = request_path_params("/", method: :get) assert_equal("people", params[:controller]) assert_equal("index", params[:action]) end def test_typo_recognition set.draw do - get 'articles/:year/:month/:day/:title' => 'articles#permalink', + get "articles/:year/:month/:day/:title" => "articles#permalink", :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/ end - params = request_path_params("/articles/2005/11/05/a-very-interesting-article", :method => :get) + params = request_path_params("/articles/2005/11/05/a-very-interesting-article", method: :get) assert_equal("permalink", params[:action]) assert_equal("2005", params[:year]) assert_equal("11", params[:month]) @@ -1275,7 +1272,7 @@ class RouteSetTest < ActiveSupport::TestCase def test_routing_traversal_does_not_load_extra_classes assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded" set.draw do - get '/profile' => 'profile#index' + get "/profile" => "profile#index" end request_path_params("/profile") rescue nil @@ -1291,17 +1288,17 @@ class RouteSetTest < ActiveSupport::TestCase get "people/:id(.:format)" => "people#show" end - params = request_path_params("/people/5", :method => :get) + params = request_path_params("/people/5", method: :get) assert_equal("show", params[:action]) assert_equal("5", params[:id]) - params = request_path_params("/people/5", :method => :put) + params = request_path_params("/people/5", method: :put) assert_equal("update", params[:action]) - params = request_path_params("/people/5", :method => :patch) + params = request_path_params("/people/5", method: :patch) assert_equal("update", params[:action]) - params = request_path_params("/people/5.png", :method => :get) + params = request_path_params("/people/5.png", method: :get) assert_equal("show", params[:action]) assert_equal("5", params[:id]) assert_equal("png", params[:format]) @@ -1309,18 +1306,18 @@ class RouteSetTest < ActiveSupport::TestCase def test_generate_with_default_action set.draw do - get "/people", :controller => "people", :action => "index" - get "/people/list", :controller => "people", :action => "list" + get "/people", controller: "people", action: "index" + get "/people/list", controller: "people", action: "list" end - url = url_for(set, { :controller => "people", :action => "list" }) + url = url_for(set, controller: "people", action: "list") assert_equal "/people/list", url end def test_root_map - set.draw { root :to => 'people#index' } + set.draw { root to: "people#index" } - params = request_path_params("", :method => :get) + params = request_path_params("", method: :get) assert_equal("people", params[:controller]) assert_equal("index", params[:action]) end @@ -1328,49 +1325,49 @@ class RouteSetTest < ActiveSupport::TestCase def test_namespace set.draw do - namespace 'api' do - get 'inventory' => 'products#inventory' + namespace "api" do + get "inventory" => "products#inventory" end end - params = request_path_params("/api/inventory", :method => :get) + params = request_path_params("/api/inventory", method: :get) assert_equal("api/products", params[:controller]) assert_equal("inventory", params[:action]) end def test_namespaced_root_map set.draw do - namespace 'api' do - root :to => 'products#index' + namespace "api" do + root to: "products#index" end end - params = request_path_params("/api", :method => :get) + params = request_path_params("/api", method: :get) assert_equal("api/products", params[:controller]) assert_equal("index", params[:action]) end def test_namespace_with_path_prefix set.draw do - scope :module => "api", :path => "prefix" do - get 'inventory' => 'products#inventory' + scope module: "api", path: "prefix" do + get "inventory" => "products#inventory" end end - params = request_path_params("/prefix/inventory", :method => :get) + params = request_path_params("/prefix/inventory", method: :get) assert_equal("api/products", params[:controller]) assert_equal("inventory", params[:action]) end def test_namespace_with_blank_path_prefix set.draw do - scope :module => "api", :path => "" do - get 'inventory' => 'products#inventory' + scope module: "api", path: "" do + get "inventory" => "products#inventory" end end - params = request_path_params("/inventory", :method => :get) + params = request_path_params("/inventory", method: :get) assert_equal("api/products", params[:controller]) assert_equal("inventory", params[:action]) end @@ -1380,37 +1377,37 @@ class RouteSetTest < ActiveSupport::TestCase set.draw do ActiveSupport::Deprecation.silence do - get ':controller/:id/:action' + get ":controller/:id/:action" end end - get URI('http://test.host/people/7/show') + get URI("http://test.host/people/7/show") - assert_equal "/people/7/destroy", controller.url_for(:action => 'destroy', :only_path => true) + assert_equal "/people/7/destroy", controller.url_for(action: "destroy", only_path: true) end def test_use_static_path_when_possible @set = make_set false set.draw do - get 'about' => "welcome#about" + get "about" => "welcome#about" ActiveSupport::Deprecation.silence do - get ':controller/:id/:action' + get ":controller/:id/:action" end end - get URI('http://test.host/welcom/get/7') + get URI("http://test.host/welcom/get/7") - assert_equal "/about", controller.url_for(:controller => 'welcome', - :action => 'about', - :only_path => true) + assert_equal "/about", controller.url_for(controller: "welcome", + action: "about", + only_path: true) end def test_generate - set.draw { ActiveSupport::Deprecation.silence { get ':controller/:action/:id' } } + set.draw { ActiveSupport::Deprecation.silence { get ":controller/:action/:id" } } - args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } + args = { controller: "foo", action: "bar", id: "7", x: "y" } assert_equal "/foo/bar/7?x=y", url_for(set, args) assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args) assert_equal [:x], set.extra_keys(args) @@ -1420,12 +1417,12 @@ class RouteSetTest < ActiveSupport::TestCase set.draw do scope "my" do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end end - args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } + args = { controller: "foo", action: "bar", id: "7", x: "y" } assert_equal "/my/foo/bar/7?x=y", url_for(set, args) end @@ -1433,12 +1430,12 @@ class RouteSetTest < ActiveSupport::TestCase set.draw do scope "" do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end end - args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" } + args = { controller: "foo", action: "bar", id: "7", x: "y" } assert_equal "/foo/bar/7?x=y", url_for(set, args) end @@ -1447,20 +1444,20 @@ class RouteSetTest < ActiveSupport::TestCase set.draw do ActiveSupport::Deprecation.silence do - get "/connection/manage(/:action)" => 'connection/manage#index' + get "/connection/manage(/:action)" => "connection/manage#index" get "/connection/connection" => "connection/connection#index" - get '/connection' => 'connection#index', :as => 'family_connection' + get "/connection" => "connection#index", :as => "family_connection" end end - assert_equal({ :controller => 'connection/manage', - :action => 'index', }, request_path_params('/connection/manage')) + assert_equal({ controller: "connection/manage", + action: "index", }, request_path_params("/connection/manage")) - url = controller.url_for({ :controller => "connection", :only_path => true }) + url = controller.url_for(controller: "connection", only_path: true) assert_equal "/connection/connection", url - url = controller.url_for({ :use_route => "family_connection", - :controller => "connection", :only_path => true }) + url = controller.url_for(use_route: "family_connection", + controller: "connection", only_path: true) assert_equal "/connection", url end @@ -1469,75 +1466,75 @@ class RouteSetTest < ActiveSupport::TestCase set.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end - get URI('http://test.host/books/show/10') + get URI("http://test.host/books/show/10") - assert_equal '/books', controller.url_for(:controller => 'books', - :only_path => true, - :action => 'index') + assert_equal "/books", controller.url_for(controller: "books", + only_path: true, + action: "index") end def test_query_params_will_be_shown_when_recalled @set = make_set false set.draw do - get 'show_weblog/:parameter' => 'weblog#show' + get "show_weblog/:parameter" => "weblog#show" ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end - get URI('http://test.host/weblog/show/1') + get URI("http://test.host/weblog/show/1") - assert_equal '/weblog/edit?parameter=1', controller.url_for( - {:action => 'edit', :parameter => 1, :only_path => true}) + assert_equal "/weblog/edit?parameter=1", controller.url_for( + action: "edit", parameter: 1, only_path: true) end def test_format_is_not_inherit set.draw do - get '/posts(.:format)' => 'posts#index' + get "/posts(.:format)" => "posts#index" end - get URI('http://test.host/posts.xml') - assert_equal({:controller => 'posts', :action => 'index', :format => 'xml'}, + get URI("http://test.host/posts.xml") + assert_equal({ controller: "posts", action: "index", format: "xml" }, controller.request.path_parameters) - assert_equal '/posts', controller.url_for( - {:controller => 'posts', :only_path => true}) + assert_equal "/posts", controller.url_for( + controller: "posts", only_path: true) - assert_equal '/posts.xml', controller.url_for( - {:controller => 'posts', :format => 'xml', :only_path => true}) + assert_equal "/posts.xml", controller.url_for( + controller: "posts", format: "xml", only_path: true) end def test_expiry_determination_should_consider_values_with_to_param @set = make_set false - set.draw { ActiveSupport::Deprecation.silence { get 'projects/:project_id/:controller/:action' } } + set.draw { ActiveSupport::Deprecation.silence { get "projects/:project_id/:controller/:action" } } - get URI('http://test.host/projects/1/weblog/show') + get URI("http://test.host/projects/1/weblog/show") assert_equal( - { :controller => 'weblog', :action => 'show', :project_id => '1' }, + { controller: "weblog", action: "show", project_id: "1" }, controller.request.path_parameters) - assert_equal '/projects/1/weblog/show', - controller.url_for({ :action => 'show', :project_id => 1, :only_path => true }) + assert_equal "/projects/1/weblog/show", + controller.url_for(action: "show", project_id: 1, only_path: true) end def test_named_route_in_nested_resource set.draw do resources :projects do member do - get 'milestones' => 'milestones#index', :as => 'milestones' + get "milestones" => "milestones#index", :as => "milestones" end end end - params = set.recognize_path("/projects/1/milestones", :method => :get) + params = set.recognize_path("/projects/1/milestones", method: :get) assert_equal("milestones", params[:controller]) assert_equal("index", params[:action]) end @@ -1546,7 +1543,7 @@ class RouteSetTest < ActiveSupport::TestCase assert_nothing_raised do set.draw do namespace :admin do - root :to => "home#index" + root to: "home#index" end end end @@ -1555,8 +1552,8 @@ class RouteSetTest < ActiveSupport::TestCase def test_setting_root_in_namespace_using_string assert_nothing_raised do set.draw do - namespace 'admin' do - root :to => "home#index" + namespace "admin" do + root to: "home#index" end end end @@ -1565,8 +1562,8 @@ class RouteSetTest < ActiveSupport::TestCase def test_route_constraints_with_unsupported_regexp_options_must_error assert_raise ArgumentError do set.draw do - get 'page/:name' => 'pages#show', - :constraints => { :name => /(david|jamis)/m } + get "page/:name" => "pages#show", + :constraints => { name: /(david|jamis)/m } end end end @@ -1574,14 +1571,14 @@ class RouteSetTest < ActiveSupport::TestCase def test_route_constraints_with_supported_options_must_not_error assert_nothing_raised do set.draw do - get 'page/:name' => 'pages#show', - :constraints => { :name => /(david|jamis)/i } + get "page/:name" => "pages#show", + :constraints => { name: /(david|jamis)/i } end end assert_nothing_raised do set.draw do - get 'page/:name' => 'pages#show', - :constraints => { :name => / # Desperately overcommented regexp + get "page/:name" => "pages#show", + :constraints => { name: / # Desperately overcommented regexp ( #Either david #The Creator | #Or @@ -1594,243 +1591,243 @@ class RouteSetTest < ActiveSupport::TestCase def test_route_with_subdomain_and_constraints_must_receive_params name_param = nil set.draw do - get 'page/:name' => 'pages#show', :constraints => lambda {|request| + get "page/:name" => "pages#show", :constraints => lambda { |request| name_param = request.params[:name] return true } end - assert_equal({:controller => 'pages', :action => 'show', :name => 'mypage'}, - set.recognize_path('http://subdomain.example.org/page/mypage')) - assert_equal(name_param, 'mypage') + assert_equal({ controller: "pages", action: "show", name: "mypage" }, + set.recognize_path("http://subdomain.example.org/page/mypage")) + assert_equal(name_param, "mypage") end def test_route_requirement_recognize_with_ignore_case set.draw do - get 'page/:name' => 'pages#show', - :constraints => {:name => /(david|jamis)/i} + get "page/:name" => "pages#show", + :constraints => { name: /(david|jamis)/i } end - assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis')) + assert_equal({ controller: "pages", action: "show", name: "jamis" }, set.recognize_path("/page/jamis")) assert_raise ActionController::RoutingError do - set.recognize_path('/page/davidjamis') + set.recognize_path("/page/davidjamis") end - assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID')) + assert_equal({ controller: "pages", action: "show", name: "DAVID" }, set.recognize_path("/page/DAVID")) end def test_route_requirement_generate_with_ignore_case set.draw do - get 'page/:name' => 'pages#show', - :constraints => {:name => /(david|jamis)/i} + get "page/:name" => "pages#show", + :constraints => { name: /(david|jamis)/i } end - url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'david' }) + url = url_for(set, controller: "pages", action: "show", name: "david") assert_equal "/page/david", url assert_raise(ActionController::UrlGenerationError) do - url_for(set, { :controller => 'pages', :action => 'show', :name => 'davidjamis' }) + url_for(set, controller: "pages", action: "show", name: "davidjamis") end - url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' }) + url = url_for(set, controller: "pages", action: "show", name: "JAMIS") assert_equal "/page/JAMIS", url end def test_route_requirement_recognize_with_extended_syntax set.draw do - get 'page/:name' => 'pages#show', - :constraints => {:name => / # Desperately overcommented regexp + get "page/:name" => "pages#show", + :constraints => { name: / # Desperately overcommented regexp ( #Either david #The Creator | #Or jamis #The Deployer - )/x} + )/x } end - assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis')) - assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david')) + assert_equal({ controller: "pages", action: "show", name: "jamis" }, set.recognize_path("/page/jamis")) + assert_equal({ controller: "pages", action: "show", name: "david" }, set.recognize_path("/page/david")) assert_raise ActionController::RoutingError do - set.recognize_path('/page/david #The Creator') + set.recognize_path("/page/david #The Creator") end assert_raise ActionController::RoutingError do - set.recognize_path('/page/David') + set.recognize_path("/page/David") end end def test_route_requirement_with_xi_modifiers set.draw do - get 'page/:name' => 'pages#show', - :constraints => {:name => / # Desperately overcommented regexp + get "page/:name" => "pages#show", + :constraints => { name: / # Desperately overcommented regexp ( #Either david #The Creator | #Or jamis #The Deployer - )/xi} + )/xi } end - assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, - set.recognize_path('/page/JAMIS')) + assert_equal({ controller: "pages", action: "show", name: "JAMIS" }, + set.recognize_path("/page/JAMIS")) assert_equal "/page/JAMIS", - url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' }) + url_for(set, controller: "pages", action: "show", name: "JAMIS") end def test_routes_with_symbols set.draw do - get 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol - get 'named' , :controller => :pages, :action => :show, :name => :as_symbol, :as => :named + get "unnamed", controller: :pages, action: :show, name: :as_symbol + get "named" , controller: :pages, action: :show, name: :as_symbol, as: :named end - assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/unnamed')) - assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/named')) + assert_equal({ controller: "pages", action: "show", name: :as_symbol }, set.recognize_path("/unnamed")) + assert_equal({ controller: "pages", action: "show", name: :as_symbol }, set.recognize_path("/named")) end def test_regexp_chunk_should_add_question_mark_for_optionals set.draw do - get '/' => 'foo#index' - get '/hello' => 'bar#index' + get "/" => "foo#index" + get "/hello" => "bar#index" end - assert_equal '/', url_for(set, { :controller => 'foo' }) - assert_equal '/hello', url_for(set, { :controller => 'bar' }) + assert_equal "/", url_for(set, controller: "foo") + assert_equal "/hello", url_for(set, controller: "bar") - assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/')) - assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello')) + assert_equal({ controller: "foo", action: "index" }, set.recognize_path("/")) + assert_equal({ controller: "bar", action: "index" }, set.recognize_path("/hello")) end def test_assign_route_options_with_anchor_chars set.draw do ActiveSupport::Deprecation.silence do - get '/cars/:action/:person/:car/', :controller => 'cars' + get "/cars/:action/:person/:car/", controller: "cars" end end - assert_equal '/cars/buy/1/2', url_for(set, { :controller => 'cars', :action => 'buy', :person => '1', :car => '2' }) + assert_equal "/cars/buy/1/2", url_for(set, controller: "cars", action: "buy", person: "1", car: "2") - assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2')) + assert_equal({ controller: "cars", action: "buy", person: "1", car: "2" }, set.recognize_path("/cars/buy/1/2")) end def test_segmentation_of_dot_path set.draw do ActiveSupport::Deprecation.silence do - get '/books/:action.rss', :controller => 'books' + get "/books/:action.rss", controller: "books" end end - assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list' }) + assert_equal "/books/list.rss", url_for(set, controller: "books", action: "list") - assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss')) + assert_equal({ controller: "books", action: "list" }, set.recognize_path("/books/list.rss")) end def test_segmentation_of_dynamic_dot_path set.draw do ActiveSupport::Deprecation.silence do - get '/books(/:action(.:format))', :controller => 'books' + get "/books(/:action(.:format))", controller: "books" end end - assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list', :format => 'rss' }) - assert_equal '/books/list.xml', url_for(set, { :controller => 'books', :action => 'list', :format => 'xml' }) - assert_equal '/books/list', url_for(set, { :controller => 'books', :action => 'list' }) - assert_equal '/books', url_for(set, { :controller => 'books', :action => 'index' }) + assert_equal "/books/list.rss", url_for(set, controller: "books", action: "list", format: "rss") + assert_equal "/books/list.xml", url_for(set, controller: "books", action: "list", format: "xml") + assert_equal "/books/list", url_for(set, controller: "books", action: "list") + assert_equal "/books", url_for(set, controller: "books", action: "index") - assert_equal({:controller => "books", :action => "list", :format => "rss"}, set.recognize_path('/books/list.rss')) - assert_equal({:controller => "books", :action => "list", :format => "xml"}, set.recognize_path('/books/list.xml')) - assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list')) - assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books')) + assert_equal({ controller: "books", action: "list", format: "rss" }, set.recognize_path("/books/list.rss")) + assert_equal({ controller: "books", action: "list", format: "xml" }, set.recognize_path("/books/list.xml")) + assert_equal({ controller: "books", action: "list" }, set.recognize_path("/books/list")) + assert_equal({ controller: "books", action: "index" }, set.recognize_path("/books")) end def test_slashes_are_implied set.draw { ActiveSupport::Deprecation.silence { get("/:controller(/:action(/:id))") } } - assert_equal '/content', url_for(set, { :controller => 'content', :action => 'index' }) - assert_equal '/content/list', url_for(set, { :controller => 'content', :action => 'list' }) - assert_equal '/content/show/1', url_for(set, { :controller => 'content', :action => 'show', :id => '1' }) + assert_equal "/content", url_for(set, controller: "content", action: "index") + assert_equal "/content/list", url_for(set, controller: "content", action: "list") + assert_equal "/content/show/1", url_for(set, controller: "content", action: "show", id: "1") - assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content')) - assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index')) - assert_equal({:controller => "content", :action => "list"}, set.recognize_path('/content/list')) - assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1')) + assert_equal({ controller: "content", action: "index" }, set.recognize_path("/content")) + assert_equal({ controller: "content", action: "index" }, set.recognize_path("/content/index")) + assert_equal({ controller: "content", action: "list" }, set.recognize_path("/content/list")) + assert_equal({ controller: "content", action: "show", id: "1" }, set.recognize_path("/content/show/1")) end def test_default_route_recognition - expected = {:controller => 'pages', :action => 'show', :id => '10'} - assert_equal expected, default_route_set.recognize_path('/pages/show/10') - assert_equal expected, default_route_set.recognize_path('/pages/show/10/') + expected = { controller: "pages", action: "show", id: "10" } + assert_equal expected, default_route_set.recognize_path("/pages/show/10") + assert_equal expected, default_route_set.recognize_path("/pages/show/10/") - expected[:id] = 'jamis' - assert_equal expected, default_route_set.recognize_path('/pages/show/jamis/') + expected[:id] = "jamis" + assert_equal expected, default_route_set.recognize_path("/pages/show/jamis/") expected.delete :id - assert_equal expected, default_route_set.recognize_path('/pages/show') - assert_equal expected, default_route_set.recognize_path('/pages/show/') + assert_equal expected, default_route_set.recognize_path("/pages/show") + assert_equal expected, default_route_set.recognize_path("/pages/show/") - expected[:action] = 'index' - assert_equal expected, default_route_set.recognize_path('/pages/') - assert_equal expected, default_route_set.recognize_path('/pages') + expected[:action] = "index" + assert_equal expected, default_route_set.recognize_path("/pages/") + assert_equal expected, default_route_set.recognize_path("/pages") - assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') } - assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/pages/how/goood/it/is/to/be/free') } + assert_raise(ActionController::RoutingError) { default_route_set.recognize_path("/") } + assert_raise(ActionController::RoutingError) { default_route_set.recognize_path("/pages/how/goood/it/is/to/be/free") } end def test_default_route_should_omit_default_action - assert_equal '/accounts', url_for(default_route_set, { :controller => 'accounts', :action => 'index' }) + assert_equal "/accounts", url_for(default_route_set, controller: "accounts", action: "index") end def test_default_route_should_include_default_action_when_id_present - assert_equal '/accounts/index/20', url_for(default_route_set, { :controller => 'accounts', :action => 'index', :id => '20' }) + assert_equal "/accounts/index/20", url_for(default_route_set, controller: "accounts", action: "index", id: "20") end def test_default_route_should_work_with_action_but_no_id - assert_equal '/accounts/list_all', url_for(default_route_set, { :controller => 'accounts', :action => 'list_all' }) + assert_equal "/accounts/list_all", url_for(default_route_set, controller: "accounts", action: "list_all") end def test_default_route_should_uri_escape_pluses - expected = { :controller => 'pages', :action => 'show', :id => 'hello world' } - assert_equal expected, default_route_set.recognize_path('/pages/show/hello%20world') - assert_equal '/pages/show/hello%20world', url_for(default_route_set, expected) + expected = { controller: "pages", action: "show", id: "hello world" } + assert_equal expected, default_route_set.recognize_path("/pages/show/hello%20world") + assert_equal "/pages/show/hello%20world", url_for(default_route_set, expected) - expected[:id] = 'hello+world' - assert_equal expected, default_route_set.recognize_path('/pages/show/hello+world') - assert_equal expected, default_route_set.recognize_path('/pages/show/hello%2Bworld') - assert_equal '/pages/show/hello+world', url_for(default_route_set, expected) + expected[:id] = "hello+world" + assert_equal expected, default_route_set.recognize_path("/pages/show/hello+world") + assert_equal expected, default_route_set.recognize_path("/pages/show/hello%2Bworld") + assert_equal "/pages/show/hello+world", url_for(default_route_set, expected) end def test_build_empty_query_string - assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo' }) + assert_uri_equal "/foo", url_for(default_route_set, controller: "foo") end def test_build_query_string_with_nil_value - assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo', :x => nil }) + assert_uri_equal "/foo", url_for(default_route_set, controller: "foo", x: nil) end def test_simple_build_query_string - assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => '1', :y => '2' }) + assert_uri_equal "/foo?x=1&y=2", url_for(default_route_set, controller: "foo", x: "1", y: "2") end def test_convert_ints_build_query_string - assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => 1, :y => 2 }) + assert_uri_equal "/foo?x=1&y=2", url_for(default_route_set, controller: "foo", x: 1, y: 2) end def test_escape_spaces_build_query_string - assert_uri_equal '/foo?x=hello+world&y=goodbye+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world', :y => 'goodbye world' }) + assert_uri_equal "/foo?x=hello+world&y=goodbye+world", url_for(default_route_set, controller: "foo", x: "hello world", y: "goodbye world") end def test_expand_array_build_query_string - assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', url_for(default_route_set, { :controller => 'foo', :x => [1, 2] }) + assert_uri_equal "/foo?x%5B%5D=1&x%5B%5D=2", url_for(default_route_set, controller: "foo", x: [1, 2]) end def test_escape_spaces_build_query_string_selected_keys - assert_uri_equal '/foo?x=hello+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world' }) + assert_uri_equal "/foo?x=hello+world", url_for(default_route_set, controller: "foo", x: "hello world") end def test_generate_with_default_params set.draw do - get 'dummy/page/:page' => 'dummy#show' - get 'dummy/dots/page.:page' => 'dummy#dots' - get 'ibocorp(/:page)' => 'ibocorp#show', - :constraints => { :page => /\d+/ }, - :defaults => { :page => 1 } + get "dummy/page/:page" => "dummy#show" + get "dummy/dots/page.:page" => "dummy#dots" + get "ibocorp(/:page)" => "ibocorp#show", + :constraints => { page: /\d+/ }, + :defaults => { page: 1 } ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end - assert_equal '/ibocorp', url_for(set, { :controller => 'ibocorp', :action => "show", :page => 1 }) + assert_equal "/ibocorp", url_for(set, controller: "ibocorp", action: "show", page: 1) end include ActionDispatch::RoutingVerbs @@ -1841,21 +1838,21 @@ class RouteSetTest < ActiveSupport::TestCase @set = make_set false set.draw do - get "blog/", :controller => "blog", :action => "index" + get "blog/", controller: "blog", action: "index" get "blog(/:year(/:month(/:day)))", - :controller => "blog", - :action => "show_date", - :constraints => { :year => /(19|20)\d\d/, :month => /[01]?\d/, :day => /[0-3]?\d/ }, - :day => nil, :month => nil + controller: "blog", + action: "show_date", + constraints: { year: /(19|20)\d\d/, month: /[01]?\d/, day: /[0-3]?\d/ }, + day: nil, month: nil - get "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/ + get "blog/show/:id", controller: "blog", action: "show", id: /\d+/ ActiveSupport::Deprecation.silence do get "blog/:controller/:action(/:id)" end - get "*anything", :controller => "blog", :action => "unknown_request" + get "*anything", controller: "blog", action: "unknown_request" end recognize_path = ->(path) { @@ -1863,24 +1860,24 @@ class RouteSetTest < ActiveSupport::TestCase controller.request.path_parameters } - assert_equal({:controller => "blog", :action => "index"}, recognize_path.("/blog")) - assert_equal({:controller => "blog", :action => "show", :id => "123"}, recognize_path.("/blog/show/123")) - assert_equal({:controller => "blog", :action => "show_date", :year => "2004", :day => nil, :month => nil }, recognize_path.("/blog/2004")) - assert_equal({:controller => "blog", :action => "show_date", :year => "2004", :month => "12", :day => nil }, recognize_path.("/blog/2004/12")) - assert_equal({:controller => "blog", :action => "show_date", :year => "2004", :month => "12", :day => "25"}, recognize_path.("/blog/2004/12/25")) - assert_equal({:controller => "articles", :action => "edit", :id => "123"}, recognize_path.("/blog/articles/edit/123")) - assert_equal({:controller => "articles", :action => "show_stats"}, recognize_path.("/blog/articles/show_stats")) - assert_equal({:controller => "blog", :action => "unknown_request", :anything => "blog/wibble"}, recognize_path.("/blog/wibble")) - assert_equal({:controller => "blog", :action => "unknown_request", :anything => "junk"}, recognize_path.("/junk")) + assert_equal({ controller: "blog", action: "index" }, recognize_path.("/blog")) + assert_equal({ controller: "blog", action: "show", id: "123" }, recognize_path.("/blog/show/123")) + assert_equal({ controller: "blog", action: "show_date", year: "2004", day: nil, month: nil }, recognize_path.("/blog/2004")) + assert_equal({ controller: "blog", action: "show_date", year: "2004", month: "12", day: nil }, recognize_path.("/blog/2004/12")) + assert_equal({ controller: "blog", action: "show_date", year: "2004", month: "12", day: "25" }, recognize_path.("/blog/2004/12/25")) + assert_equal({ controller: "articles", action: "edit", id: "123" }, recognize_path.("/blog/articles/edit/123")) + assert_equal({ controller: "articles", action: "show_stats" }, recognize_path.("/blog/articles/show_stats")) + assert_equal({ controller: "blog", action: "unknown_request", anything: "blog/wibble" }, recognize_path.("/blog/wibble")) + assert_equal({ controller: "blog", action: "unknown_request", anything: "junk" }, recognize_path.("/junk")) - get URI('http://example.org/blog/2006/07/28') + get URI("http://example.org/blog/2006/07/28") - assert_equal({:controller => "blog", :action => "show_date", :year => "2006", :month => "07", :day => "28"}, controller.request.path_parameters) - assert_equal("/blog/2006/07/25", controller.url_for({ :day => 25, :only_path => true })) - assert_equal("/blog/2005", controller.url_for({ :year => 2005, :only_path => true })) - assert_equal("/blog/show/123", controller.url_for({ :action => "show" , :id => 123, :only_path => true })) - assert_equal("/blog/2006", controller.url_for({ :year => 2006, :only_path => true })) - assert_equal("/blog/2006", controller.url_for({ :year => 2006, :month => nil, :only_path => true })) + assert_equal({ controller: "blog", action: "show_date", year: "2006", month: "07", day: "28" }, controller.request.path_parameters) + assert_equal("/blog/2006/07/25", controller.url_for(day: 25, only_path: true)) + assert_equal("/blog/2005", controller.url_for(year: 2005, only_path: true)) + assert_equal("/blog/show/123", controller.url_for(action: "show" , id: 123, only_path: true)) + assert_equal("/blog/2006", controller.url_for(year: 2006, only_path: true)) + assert_equal("/blog/2006", controller.url_for(year: 2006, month: nil, only_path: true)) end private @@ -1889,8 +1886,8 @@ class RouteSetTest < ActiveSupport::TestCase end def sort_query_string_params(uri) - path, qs = uri.split('?') - qs = qs.split('&').sort.join('&') if qs + path, qs = uri.split("?") + qs = qs.split("&").sort.join("&") if qs qs ? "#{path}?#{qs}" : path end end @@ -1905,59 +1902,59 @@ class RackMountIntegrationTests < ActiveSupport::TestCase resources :users, :posts end - namespace 'api' do - root :to => 'users#index' + namespace "api" do + root to: "users#index" end - get '/blog(/:year(/:month(/:day)))' => 'posts#show_date', + get "/blog(/:year(/:month(/:day)))" => "posts#show_date", :constraints => { - :year => /(19|20)\d\d/, - :month => /[01]?\d/, - :day => /[0-3]?\d/ + year: /(19|20)\d\d/, + month: /[01]?\d/, + day: /[0-3]?\d/ }, :day => nil, :month => nil - get 'archive/:year', :controller => 'archive', :action => 'index', - :defaults => { :year => nil }, - :constraints => { :year => /\d{4}/ }, - :as => "blog" + get "archive/:year", controller: "archive", action: "index", + defaults: { year: nil }, + constraints: { year: /\d{4}/ }, + as: "blog" resources :people - get 'legacy/people' => "people#index", :legacy => "true" - - get 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol - get 'id_default(/:id)' => "foo#id_default", :id => 1 - match 'get_or_post' => "foo#get_or_post", :via => [:get, :post] - get 'optional/:optional' => "posts#index" - get 'projects/:project_id' => "project#index", :as => "project" - get 'clients' => "projects#index" - - get 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i - get 'extended/geocode/:postalcode' => 'geocode#show',:constraints => { - :postalcode => /# Postcode format + get "legacy/people" => "people#index", :legacy => "true" + + get "symbols", controller: :symbols, action: :show, name: :as_symbol + get "id_default(/:id)" => "foo#id_default", :id => 1 + match "get_or_post" => "foo#get_or_post", :via => [:get, :post] + get "optional/:optional" => "posts#index" + get "projects/:project_id" => "project#index", :as => "project" + get "clients" => "projects#index" + + get "ignorecase/geocode/:postalcode" => "geocode#show", :postalcode => /hx\d\d-\d[a-z]{2}/i + get "extended/geocode/:postalcode" => "geocode#show",:constraints => { + postalcode: /# Postcode format \d{5} #Prefix (-\d{4})? #Suffix /x }, :as => "geocode" - get 'news(.:format)' => "news#index" + get "news(.:format)" => "news#index" ActiveSupport::Deprecation.silence do - get 'comment/:id(/:action)' => "comments#show" - get 'ws/:controller(/:action(/:id))', :ws => true - get 'account(/:action)' => "account#subscription" - get 'pages/:page_id/:controller(/:action(/:id))' - get ':controller/ping', :action => 'ping' + get "comment/:id(/:action)" => "comments#show" + get "ws/:controller(/:action(/:id))", ws: true + get "account(/:action)" => "account#subscription" + get "pages/:page_id/:controller(/:action(/:id))" + get ":controller/ping", action: "ping" end - get 'ã“ã‚“ã«ã¡ã¯/世界', :controller => 'news', :action => 'index' + get "ã“ã‚“ã«ã¡ã¯/世界", controller: "news", action: "index" ActiveSupport::Deprecation.silence do - match ':controller(/:action(/:id))(.:format)', :via => :all + match ":controller(/:action(/:id))(.:format)", via: :all end - root :to => "news#index" + root to: "news#index" } attr_reader :routes @@ -1969,118 +1966,118 @@ class RackMountIntegrationTests < ActiveSupport::TestCase end def test_recognize_path - assert_equal({:controller => 'admin/users', :action => 'index'}, @routes.recognize_path('/admin/users', :method => :get)) - assert_equal({:controller => 'admin/users', :action => 'create'}, @routes.recognize_path('/admin/users', :method => :post)) - assert_equal({:controller => 'admin/users', :action => 'new'}, @routes.recognize_path('/admin/users/new', :method => :get)) - assert_equal({:controller => 'admin/users', :action => 'show', :id => '1'}, @routes.recognize_path('/admin/users/1', :method => :get)) - assert_equal({:controller => 'admin/users', :action => 'update', :id => '1'}, @routes.recognize_path('/admin/users/1', :method => :put)) - assert_equal({:controller => 'admin/users', :action => 'destroy', :id => '1'}, @routes.recognize_path('/admin/users/1', :method => :delete)) - assert_equal({:controller => 'admin/users', :action => 'edit', :id => '1'}, @routes.recognize_path('/admin/users/1/edit', :method => :get)) - - assert_equal({:controller => 'admin/posts', :action => 'index'}, @routes.recognize_path('/admin/posts', :method => :get)) - assert_equal({:controller => 'admin/posts', :action => 'new'}, @routes.recognize_path('/admin/posts/new', :method => :get)) - - assert_equal({:controller => 'api/users', :action => 'index'}, @routes.recognize_path('/api', :method => :get)) - assert_equal({:controller => 'api/users', :action => 'index'}, @routes.recognize_path('/api/', :method => :get)) - - assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => nil, :day => nil }, @routes.recognize_path('/blog/2009', :method => :get)) - assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => '01', :day => nil }, @routes.recognize_path('/blog/2009/01', :method => :get)) - assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => '01', :day => '01'}, @routes.recognize_path('/blog/2009/01/01', :method => :get)) - - assert_equal({:controller => 'archive', :action => 'index', :year => '2010'}, @routes.recognize_path('/archive/2010')) - assert_equal({:controller => 'archive', :action => 'index'}, @routes.recognize_path('/archive')) - - assert_equal({:controller => 'people', :action => 'index'}, @routes.recognize_path('/people', :method => :get)) - assert_equal({:controller => 'people', :action => 'index', :format => 'xml'}, @routes.recognize_path('/people.xml', :method => :get)) - assert_equal({:controller => 'people', :action => 'create'}, @routes.recognize_path('/people', :method => :post)) - assert_equal({:controller => 'people', :action => 'new'}, @routes.recognize_path('/people/new', :method => :get)) - assert_equal({:controller => 'people', :action => 'show', :id => '1'}, @routes.recognize_path('/people/1', :method => :get)) - assert_equal({:controller => 'people', :action => 'show', :id => '1', :format => 'xml'}, @routes.recognize_path('/people/1.xml', :method => :get)) - assert_equal({:controller => 'people', :action => 'update', :id => '1'}, @routes.recognize_path('/people/1', :method => :put)) - assert_equal({:controller => 'people', :action => 'destroy', :id => '1'}, @routes.recognize_path('/people/1', :method => :delete)) - assert_equal({:controller => 'people', :action => 'edit', :id => '1'}, @routes.recognize_path('/people/1/edit', :method => :get)) - assert_equal({:controller => 'people', :action => 'edit', :id => '1', :format => 'xml'}, @routes.recognize_path('/people/1/edit.xml', :method => :get)) - - assert_equal({:controller => 'symbols', :action => 'show', :name => :as_symbol}, @routes.recognize_path('/symbols')) - assert_equal({:controller => 'foo', :action => 'id_default', :id => '1'}, @routes.recognize_path('/id_default/1')) - assert_equal({:controller => 'foo', :action => 'id_default', :id => '2'}, @routes.recognize_path('/id_default/2')) - assert_equal({:controller => 'foo', :action => 'id_default', :id => 1 }, @routes.recognize_path('/id_default')) - assert_equal({:controller => 'foo', :action => 'get_or_post'}, @routes.recognize_path('/get_or_post', :method => :get)) - assert_equal({:controller => 'foo', :action => 'get_or_post'}, @routes.recognize_path('/get_or_post', :method => :post)) - assert_raise(ActionController::RoutingError) { @routes.recognize_path('/get_or_post', :method => :put) } - assert_raise(ActionController::RoutingError) { @routes.recognize_path('/get_or_post', :method => :delete) } - - assert_equal({:controller => 'posts', :action => 'index', :optional => 'bar'}, @routes.recognize_path('/optional/bar')) - assert_raise(ActionController::RoutingError) { @routes.recognize_path('/optional') } - - assert_equal({:controller => 'posts', :action => 'show', :id => '1', :ws => true}, @routes.recognize_path('/ws/posts/show/1', :method => :get)) - assert_equal({:controller => 'posts', :action => 'list', :ws => true}, @routes.recognize_path('/ws/posts/list', :method => :get)) - assert_equal({:controller => 'posts', :action => 'index', :ws => true}, @routes.recognize_path('/ws/posts', :method => :get)) - - assert_equal({:controller => 'account', :action => 'subscription'}, @routes.recognize_path('/account', :method => :get)) - assert_equal({:controller => 'account', :action => 'subscription'}, @routes.recognize_path('/account/subscription', :method => :get)) - assert_equal({:controller => 'account', :action => 'billing'}, @routes.recognize_path('/account/billing', :method => :get)) - - assert_equal({:page_id => '1', :controller => 'notes', :action => 'index'}, @routes.recognize_path('/pages/1/notes', :method => :get)) - assert_equal({:page_id => '1', :controller => 'notes', :action => 'list'}, @routes.recognize_path('/pages/1/notes/list', :method => :get)) - assert_equal({:page_id => '1', :controller => 'notes', :action => 'show', :id => '2'}, @routes.recognize_path('/pages/1/notes/show/2', :method => :get)) - - assert_equal({:controller => 'posts', :action => 'ping'}, @routes.recognize_path('/posts/ping', :method => :get)) - assert_equal({:controller => 'posts', :action => 'index'}, @routes.recognize_path('/posts', :method => :get)) - assert_equal({:controller => 'posts', :action => 'index'}, @routes.recognize_path('/posts/index', :method => :get)) - assert_equal({:controller => 'posts', :action => 'show'}, @routes.recognize_path('/posts/show', :method => :get)) - assert_equal({:controller => 'posts', :action => 'show', :id => '1'}, @routes.recognize_path('/posts/show/1', :method => :get)) - assert_equal({:controller => 'posts', :action => 'create'}, @routes.recognize_path('/posts/create', :method => :post)) - - assert_equal({:controller => 'geocode', :action => 'show', :postalcode => 'hx12-1az'}, @routes.recognize_path('/ignorecase/geocode/hx12-1az')) - assert_equal({:controller => 'geocode', :action => 'show', :postalcode => 'hx12-1AZ'}, @routes.recognize_path('/ignorecase/geocode/hx12-1AZ')) - assert_equal({:controller => 'geocode', :action => 'show', :postalcode => '12345-1234'}, @routes.recognize_path('/extended/geocode/12345-1234')) - assert_equal({:controller => 'geocode', :action => 'show', :postalcode => '12345'}, @routes.recognize_path('/extended/geocode/12345')) - - assert_equal({:controller => 'news', :action => 'index' }, @routes.recognize_path('/', :method => :get)) - assert_equal({:controller => 'news', :action => 'index', :format => 'rss'}, @routes.recognize_path('/news.rss', :method => :get)) - - assert_raise(ActionController::RoutingError) { @routes.recognize_path('/none', :method => :get) } + assert_equal({ controller: "admin/users", action: "index" }, @routes.recognize_path("/admin/users", method: :get)) + assert_equal({ controller: "admin/users", action: "create" }, @routes.recognize_path("/admin/users", method: :post)) + assert_equal({ controller: "admin/users", action: "new" }, @routes.recognize_path("/admin/users/new", method: :get)) + assert_equal({ controller: "admin/users", action: "show", id: "1" }, @routes.recognize_path("/admin/users/1", method: :get)) + assert_equal({ controller: "admin/users", action: "update", id: "1" }, @routes.recognize_path("/admin/users/1", method: :put)) + assert_equal({ controller: "admin/users", action: "destroy", id: "1" }, @routes.recognize_path("/admin/users/1", method: :delete)) + assert_equal({ controller: "admin/users", action: "edit", id: "1" }, @routes.recognize_path("/admin/users/1/edit", method: :get)) + + assert_equal({ controller: "admin/posts", action: "index" }, @routes.recognize_path("/admin/posts", method: :get)) + assert_equal({ controller: "admin/posts", action: "new" }, @routes.recognize_path("/admin/posts/new", method: :get)) + + assert_equal({ controller: "api/users", action: "index" }, @routes.recognize_path("/api", method: :get)) + assert_equal({ controller: "api/users", action: "index" }, @routes.recognize_path("/api/", method: :get)) + + assert_equal({ controller: "posts", action: "show_date", year: "2009", month: nil, day: nil }, @routes.recognize_path("/blog/2009", method: :get)) + assert_equal({ controller: "posts", action: "show_date", year: "2009", month: "01", day: nil }, @routes.recognize_path("/blog/2009/01", method: :get)) + assert_equal({ controller: "posts", action: "show_date", year: "2009", month: "01", day: "01" }, @routes.recognize_path("/blog/2009/01/01", method: :get)) + + assert_equal({ controller: "archive", action: "index", year: "2010" }, @routes.recognize_path("/archive/2010")) + assert_equal({ controller: "archive", action: "index" }, @routes.recognize_path("/archive")) + + assert_equal({ controller: "people", action: "index" }, @routes.recognize_path("/people", method: :get)) + assert_equal({ controller: "people", action: "index", format: "xml" }, @routes.recognize_path("/people.xml", method: :get)) + assert_equal({ controller: "people", action: "create" }, @routes.recognize_path("/people", method: :post)) + assert_equal({ controller: "people", action: "new" }, @routes.recognize_path("/people/new", method: :get)) + assert_equal({ controller: "people", action: "show", id: "1" }, @routes.recognize_path("/people/1", method: :get)) + assert_equal({ controller: "people", action: "show", id: "1", format: "xml" }, @routes.recognize_path("/people/1.xml", method: :get)) + assert_equal({ controller: "people", action: "update", id: "1" }, @routes.recognize_path("/people/1", method: :put)) + assert_equal({ controller: "people", action: "destroy", id: "1" }, @routes.recognize_path("/people/1", method: :delete)) + assert_equal({ controller: "people", action: "edit", id: "1" }, @routes.recognize_path("/people/1/edit", method: :get)) + assert_equal({ controller: "people", action: "edit", id: "1", format: "xml" }, @routes.recognize_path("/people/1/edit.xml", method: :get)) + + assert_equal({ controller: "symbols", action: "show", name: :as_symbol }, @routes.recognize_path("/symbols")) + assert_equal({ controller: "foo", action: "id_default", id: "1" }, @routes.recognize_path("/id_default/1")) + assert_equal({ controller: "foo", action: "id_default", id: "2" }, @routes.recognize_path("/id_default/2")) + assert_equal({ controller: "foo", action: "id_default", id: 1 }, @routes.recognize_path("/id_default")) + assert_equal({ controller: "foo", action: "get_or_post" }, @routes.recognize_path("/get_or_post", method: :get)) + assert_equal({ controller: "foo", action: "get_or_post" }, @routes.recognize_path("/get_or_post", method: :post)) + assert_raise(ActionController::RoutingError) { @routes.recognize_path("/get_or_post", method: :put) } + assert_raise(ActionController::RoutingError) { @routes.recognize_path("/get_or_post", method: :delete) } + + assert_equal({ controller: "posts", action: "index", optional: "bar" }, @routes.recognize_path("/optional/bar")) + assert_raise(ActionController::RoutingError) { @routes.recognize_path("/optional") } + + assert_equal({ controller: "posts", action: "show", id: "1", ws: true }, @routes.recognize_path("/ws/posts/show/1", method: :get)) + assert_equal({ controller: "posts", action: "list", ws: true }, @routes.recognize_path("/ws/posts/list", method: :get)) + assert_equal({ controller: "posts", action: "index", ws: true }, @routes.recognize_path("/ws/posts", method: :get)) + + assert_equal({ controller: "account", action: "subscription" }, @routes.recognize_path("/account", method: :get)) + assert_equal({ controller: "account", action: "subscription" }, @routes.recognize_path("/account/subscription", method: :get)) + assert_equal({ controller: "account", action: "billing" }, @routes.recognize_path("/account/billing", method: :get)) + + assert_equal({ page_id: "1", controller: "notes", action: "index" }, @routes.recognize_path("/pages/1/notes", method: :get)) + assert_equal({ page_id: "1", controller: "notes", action: "list" }, @routes.recognize_path("/pages/1/notes/list", method: :get)) + assert_equal({ page_id: "1", controller: "notes", action: "show", id: "2" }, @routes.recognize_path("/pages/1/notes/show/2", method: :get)) + + assert_equal({ controller: "posts", action: "ping" }, @routes.recognize_path("/posts/ping", method: :get)) + assert_equal({ controller: "posts", action: "index" }, @routes.recognize_path("/posts", method: :get)) + assert_equal({ controller: "posts", action: "index" }, @routes.recognize_path("/posts/index", method: :get)) + assert_equal({ controller: "posts", action: "show" }, @routes.recognize_path("/posts/show", method: :get)) + assert_equal({ controller: "posts", action: "show", id: "1" }, @routes.recognize_path("/posts/show/1", method: :get)) + assert_equal({ controller: "posts", action: "create" }, @routes.recognize_path("/posts/create", method: :post)) + + assert_equal({ controller: "geocode", action: "show", postalcode: "hx12-1az" }, @routes.recognize_path("/ignorecase/geocode/hx12-1az")) + assert_equal({ controller: "geocode", action: "show", postalcode: "hx12-1AZ" }, @routes.recognize_path("/ignorecase/geocode/hx12-1AZ")) + assert_equal({ controller: "geocode", action: "show", postalcode: "12345-1234" }, @routes.recognize_path("/extended/geocode/12345-1234")) + assert_equal({ controller: "geocode", action: "show", postalcode: "12345" }, @routes.recognize_path("/extended/geocode/12345")) + + assert_equal({ controller: "news", action: "index" }, @routes.recognize_path("/", method: :get)) + assert_equal({ controller: "news", action: "index", format: "rss" }, @routes.recognize_path("/news.rss", method: :get)) + + assert_raise(ActionController::RoutingError) { @routes.recognize_path("/none", method: :get) } end def test_generate_extras - assert_equal ['/people', []], @routes.generate_extras(:controller => 'people') - assert_equal ['/people', [:foo]], @routes.generate_extras(:controller => 'people', :foo => 'bar') - assert_equal ['/people', []], @routes.generate_extras(:controller => 'people', :action => 'index') - assert_equal ['/people', [:foo]], @routes.generate_extras(:controller => 'people', :action => 'index', :foo => 'bar') - assert_equal ['/people/new', []], @routes.generate_extras(:controller => 'people', :action => 'new') - assert_equal ['/people/new', [:foo]], @routes.generate_extras(:controller => 'people', :action => 'new', :foo => 'bar') - assert_equal ['/people/1', []], @routes.generate_extras(:controller => 'people', :action => 'show', :id => '1') - assert_equal ['/people/1', [:bar, :foo]], sort_extras!(@routes.generate_extras(:controller => 'people', :action => 'show', :id => '1', :foo => '2', :bar => '3')) - assert_equal ['/people', [:person]], @routes.generate_extras(:controller => 'people', :action => 'create', :person => { :first_name => 'Josh', :last_name => 'Peek' }) - assert_equal ['/people', [:people]], @routes.generate_extras(:controller => 'people', :action => 'create', :people => ['Josh', 'Dave']) - - assert_equal ['/posts/show/1', []], @routes.generate_extras(:controller => 'posts', :action => 'show', :id => '1') - assert_equal ['/posts/show/1', [:bar, :foo]], sort_extras!(@routes.generate_extras(:controller => 'posts', :action => 'show', :id => '1', :foo => '2', :bar => '3')) - assert_equal ['/posts', []], @routes.generate_extras(:controller => 'posts', :action => 'index') - assert_equal ['/posts', [:foo]], @routes.generate_extras(:controller => 'posts', :action => 'index', :foo => 'bar') + assert_equal ["/people", []], @routes.generate_extras(controller: "people") + assert_equal ["/people", [:foo]], @routes.generate_extras(controller: "people", foo: "bar") + assert_equal ["/people", []], @routes.generate_extras(controller: "people", action: "index") + assert_equal ["/people", [:foo]], @routes.generate_extras(controller: "people", action: "index", foo: "bar") + assert_equal ["/people/new", []], @routes.generate_extras(controller: "people", action: "new") + assert_equal ["/people/new", [:foo]], @routes.generate_extras(controller: "people", action: "new", foo: "bar") + assert_equal ["/people/1", []], @routes.generate_extras(controller: "people", action: "show", id: "1") + assert_equal ["/people/1", [:bar, :foo]], sort_extras!(@routes.generate_extras(controller: "people", action: "show", id: "1", foo: "2", bar: "3")) + assert_equal ["/people", [:person]], @routes.generate_extras(controller: "people", action: "create", person: { first_name: "Josh", last_name: "Peek" }) + assert_equal ["/people", [:people]], @routes.generate_extras(controller: "people", action: "create", people: ["Josh", "Dave"]) + + assert_equal ["/posts/show/1", []], @routes.generate_extras(controller: "posts", action: "show", id: "1") + assert_equal ["/posts/show/1", [:bar, :foo]], sort_extras!(@routes.generate_extras(controller: "posts", action: "show", id: "1", foo: "2", bar: "3")) + assert_equal ["/posts", []], @routes.generate_extras(controller: "posts", action: "index") + assert_equal ["/posts", [:foo]], @routes.generate_extras(controller: "posts", action: "index", foo: "bar") end def test_extras - params = {:controller => 'people'} + params = { controller: "people" } assert_equal [], @routes.extra_keys(params) - assert_equal({:controller => 'people', :action => 'index'}, params) + assert_equal({ controller: "people", action: "index" }, params) - params = {:controller => 'people', :foo => 'bar'} + params = { controller: "people", foo: "bar" } assert_equal [:foo], @routes.extra_keys(params) - assert_equal({:controller => 'people', :action => 'index', :foo => 'bar'}, params) + assert_equal({ controller: "people", action: "index", foo: "bar" }, params) - params = {:controller => 'people', :action => 'create', :person => { :name => 'Josh'}} + params = { controller: "people", action: "create", person: { name: "Josh" } } assert_equal [:person], @routes.extra_keys(params) - assert_equal({:controller => 'people', :action => 'create', :person => { :name => 'Josh'}}, params) + assert_equal({ controller: "people", action: "create", person: { name: "Josh" } }, params) end def test_unicode_path - assert_equal({:controller => 'news', :action => 'index'}, @routes.recognize_path(URI.parser.escape('ã“ã‚“ã«ã¡ã¯/世界'), :method => :get)) + assert_equal({ controller: "news", action: "index" }, @routes.recognize_path(URI.parser.escape("ã“ã‚“ã«ã¡ã¯/世界"), method: :get)) end def test_downcased_unicode_path - assert_equal({:controller => 'news', :action => 'index'}, @routes.recognize_path(URI.parser.escape('ã“ã‚“ã«ã¡ã¯/世界').downcase, :method => :get)) + assert_equal({ controller: "news", action: "index" }, @routes.recognize_path(URI.parser.escape("ã“ã‚“ã«ã¡ã¯/世界").downcase, method: :get)) end private diff --git a/actionpack/test/controller/runner_test.rb b/actionpack/test/controller/runner_test.rb index 3e9383abb2..3c0c1907f9 100644 --- a/actionpack/test/controller/runner_test.rb +++ b/actionpack/test/controller/runner_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_dispatch/testing/integration' +require "abstract_unit" +require "action_dispatch/testing/integration" module ActionDispatch class RunnerTest < ActiveSupport::TestCase diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index 9df70dacbf..8dc565ac8d 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' +require "abstract_unit" module TestFileUtils def file_name() File.basename(__FILE__) end def file_path() File.expand_path(__FILE__) end - def file_data() @data ||= File.open(file_path, 'rb') { |f| f.read } end + def file_data() @data ||= File.open(file_path, "rb") { |f| f.read } end end class SendFileController < ActionController::Base @@ -23,14 +23,14 @@ class SendFileController < ActionController::Base end def file_from_before_action - raise 'No file sent from before action.' + raise "No file sent from before action." end def test_send_file_headers_bang options = { - :type => Mime[:png], - :disposition => 'disposition', - :filename => 'filename' + type: Mime[:png], + disposition: "disposition", + filename: "filename" } send_data "foo", options @@ -38,32 +38,32 @@ class SendFileController < ActionController::Base def test_send_file_headers_with_disposition_as_a_symbol options = { - :type => Mime[:png], - :disposition => :disposition, - :filename => 'filename' + type: Mime[:png], + disposition: :disposition, + filename: "filename" } send_data "foo", options end def test_send_file_headers_with_mime_lookup_with_symbol - options = { :type => :png } + options = { type: :png } send_data "foo", options end def test_send_file_headers_with_bad_symbol - options = { :type => :this_type_is_not_registered } + options = { type: :this_type_is_not_registered } send_data "foo", options end def test_send_file_headers_with_nil_content_type - options = { :type => nil } + options = { type: nil } send_data "foo", options end def test_send_file_headers_guess_type_from_extension - options = { :filename => params[:filename] } + options = { filename: params[:filename] } send_data "foo", options end @@ -84,9 +84,9 @@ class SendFileTest < ActionController::TestCase end def test_file_nostream - @controller.options = { :stream => false } + @controller.options = { stream: false } response = nil - assert_nothing_raised { response = process('file') } + assert_nothing_raised { response = process("file") } assert_not_nil response body = response.body assert_kind_of String, body @@ -95,12 +95,12 @@ class SendFileTest < ActionController::TestCase def test_file_stream response = nil - assert_nothing_raised { response = process('file') } + assert_nothing_raised { response = process("file") } assert_not_nil response assert_respond_to response.stream, :each assert_respond_to response.stream, :to_path - require 'stringio' + require "stringio" output = StringIO.new output.binmode output.string.force_encoding(file_data.encoding) @@ -109,16 +109,16 @@ class SendFileTest < ActionController::TestCase end def test_file_url_based_filename - @controller.options = { :url_based_filename => true } + @controller.options = { url_based_filename: true } response = nil - assert_nothing_raised { response = process('file') } + assert_nothing_raised { response = process("file") } assert_not_nil response assert_equal "attachment", response.headers["Content-Disposition"] end def test_data response = nil - assert_nothing_raised { response = process('data') } + assert_nothing_raised { response = process("data") } assert_not_nil response assert_kind_of String, response.body @@ -126,10 +126,10 @@ class SendFileTest < ActionController::TestCase end def test_headers_after_send_shouldnt_include_charset - response = process('data') + response = process("data") assert_equal "application/octet-stream", response.headers["Content-Type"] - response = process('file') + response = process("file") assert_equal "application/octet-stream", response.headers["Content-Type"] end @@ -141,25 +141,24 @@ class SendFileTest < ActionController::TestCase 5.times do get :test_send_file_headers_bang - assert_equal 'image/png', response.content_type - assert_equal 'disposition; filename="filename"', response.get_header('Content-Disposition') - assert_equal 'binary', response.get_header('Content-Transfer-Encoding') - assert_equal 'private', response.get_header('Cache-Control') + assert_equal "image/png", response.content_type + assert_equal 'disposition; filename="filename"', response.get_header("Content-Disposition") + assert_equal "binary", response.get_header("Content-Transfer-Encoding") + assert_equal "private", response.get_header("Cache-Control") end end def test_send_file_headers_with_disposition_as_a_symbol get :test_send_file_headers_with_disposition_as_a_symbol - assert_equal 'disposition; filename="filename"', response.get_header('Content-Disposition') + assert_equal 'disposition; filename="filename"', response.get_header("Content-Disposition") end def test_send_file_headers_with_mime_lookup_with_symbol get __method__ - assert_equal 'image/png', response.content_type + assert_equal "image/png", response.content_type end - def test_send_file_headers_with_bad_symbol error = assert_raise(ArgumentError) { get __method__ } assert_equal "Unknown MIME type this_type_is_not_registered", error.message @@ -172,15 +171,15 @@ class SendFileTest < ActionController::TestCase def test_send_file_headers_guess_type_from_extension { - 'image.png' => 'image/png', - 'image.jpeg' => 'image/jpeg', - 'image.jpg' => 'image/jpeg', - 'image.tif' => 'image/tiff', - 'image.gif' => 'image/gif', - 'movie.mpg' => 'video/mpeg', - 'file.zip' => 'application/zip', - 'file.unk' => 'application/octet-stream', - 'zip' => 'application/octet-stream' + "image.png" => "image/png", + "image.jpeg" => "image/jpeg", + "image.jpg" => "image/jpeg", + "image.tif" => "image/tiff", + "image.gif" => "image/gif", + "movie.mpg" => "video/mpeg", + "file.zip" => "application/zip", + "file.unk" => "application/octet-stream", + "zip" => "application/octet-stream" }.each do |filename,expected_type| get __method__, params: { filename: filename } assert_equal expected_type, response.content_type @@ -188,19 +187,19 @@ class SendFileTest < ActionController::TestCase end def test_send_file_with_default_content_disposition_header - process('data') - assert_equal 'attachment', @controller.headers['Content-Disposition'] + process("data") + assert_equal "attachment", @controller.headers["Content-Disposition"] end def test_send_file_without_content_disposition_header - @controller.options = {:disposition => nil} - process('data') - assert_nil @controller.headers['Content-Disposition'] + @controller.options = { disposition: nil } + process("data") + assert_nil @controller.headers["Content-Disposition"] end def test_send_file_from_before_action response = nil - assert_nothing_raised { response = process('file_from_before_action') } + assert_nothing_raised { response = process("file_from_before_action") } assert_not_nil response assert_kind_of String, response.body @@ -209,19 +208,19 @@ class SendFileTest < ActionController::TestCase %w(file data).each do |method| define_method "test_send_#{method}_status" do - @controller.options = { :stream => false, :status => 500 } + @controller.options = { stream: false, status: 500 } assert_not_nil process(method) assert_equal 500, @response.status end define_method "test_send_#{method}_content_type" do - @controller.options = { :stream => false, :content_type => "application/x-ruby" } + @controller.options = { stream: false, content_type: "application/x-ruby" } assert_nothing_raised { assert_not_nil process(method) } assert_equal "application/x-ruby", @response.content_type end define_method "test_default_send_#{method}_status" do - @controller.options = { :stream => false } + @controller.options = { stream: false } assert_nothing_raised { assert_not_nil process(method) } assert_equal 200, @response.status end @@ -229,9 +228,23 @@ class SendFileTest < ActionController::TestCase def test_send_file_with_action_controller_live @controller = SendFileWithActionControllerLive.new - @controller.options = { :content_type => "application/x-ruby" } + @controller.options = { content_type: "application/x-ruby" } - response = process('file') + response = process("file") assert_equal 200, response.status end + + def test_send_file_charset_with_type_options_key + @controller = SendFileWithActionControllerLive.new + @controller.options = { type: "text/calendar; charset=utf-8" } + response = process("file") + assert_equal "text/calendar; charset=utf-8", response.headers["Content-Type"] + end + + def test_send_file_charset_with_content_type_options_key + @controller = SendFileWithActionControllerLive.new + @controller.options = { content_type: "text/calendar" } + response = process("file") + assert_equal "text/calendar; charset=utf-8", response.headers["Content-Type"] + end end diff --git a/actionpack/test/controller/show_exceptions_test.rb b/actionpack/test/controller/show_exceptions_test.rb index 786dc15444..38c601ee81 100644 --- a/actionpack/test/controller/show_exceptions_test.rb +++ b/actionpack/test/controller/show_exceptions_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ShowExceptions class ShowExceptionsController < ActionController::Base @@ -10,11 +10,11 @@ module ShowExceptions end def boom - raise 'boom!' + raise "boom!" end def another_boom - raise 'boom!' + raise "boom!" end def show_detailed_exceptions? @@ -23,26 +23,26 @@ module ShowExceptions end class ShowExceptionsTest < ActionDispatch::IntegrationTest - test 'show error page from a remote ip' do + test "show error page from a remote ip" do @app = ShowExceptionsController.action(:boom) - self.remote_addr = '208.77.188.166' - get '/' + self.remote_addr = "208.77.188.166" + get "/" assert_equal "500 error fixture\n", body end - test 'show diagnostics from a local ip if show_detailed_exceptions? is set to request.local?' do + test "show diagnostics from a local ip if show_detailed_exceptions? is set to request.local?" do @app = ShowExceptionsController.action(:boom) - ['127.0.0.1', '127.0.0.127', '127.12.1.1', '::1', '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:1%0'].each do |ip_address| + ["127.0.0.1", "127.0.0.127", "127.12.1.1", "::1", "0:0:0:0:0:0:0:1", "0:0:0:0:0:0:0:1%0"].each do |ip_address| self.remote_addr = ip_address - get '/' + get "/" assert_match(/boom/, body) end end - test 'show diagnostics from a remote ip when env is already set' do + test "show diagnostics from a remote ip when env is already set" do @app = ShowExceptionsController.action(:another_boom) - self.remote_addr = '208.77.188.166' - get '/' + self.remote_addr = "208.77.188.166" + get "/" assert_match(/boom/, body) end end @@ -50,21 +50,21 @@ module ShowExceptions class ShowExceptionsOverriddenController < ShowExceptionsController private - def show_detailed_exceptions? - params['detailed'] == '1' - end + def show_detailed_exceptions? + params["detailed"] == "1" + end end class ShowExceptionsOverriddenTest < ActionDispatch::IntegrationTest - test 'show error page' do + test "show error page" do @app = ShowExceptionsOverriddenController.action(:boom) - get '/', params: { 'detailed' => '0' } + get "/", params: { "detailed" => "0" } assert_equal "500 error fixture\n", body end - test 'show diagnostics message' do + test "show diagnostics message" do @app = ShowExceptionsOverriddenController.action(:boom) - get '/', params: { 'detailed' => '1' } + get "/", params: { "detailed" => "1" } assert_match(/boom/, body) end end @@ -72,25 +72,25 @@ module ShowExceptions class ShowExceptionsFormatsTest < ActionDispatch::IntegrationTest def test_render_json_exception @app = ShowExceptionsOverriddenController.action(:boom) - get "/", headers: { 'HTTP_ACCEPT' => 'application/json' } + get "/", headers: { "HTTP_ACCEPT" => "application/json" } assert_response :internal_server_error - assert_equal 'application/json', response.content_type.to_s - assert_equal({ :status => 500, :error => 'Internal Server Error' }.to_json, response.body) + assert_equal "application/json", response.content_type.to_s + assert_equal({ status: 500, error: "Internal Server Error" }.to_json, response.body) end def test_render_xml_exception @app = ShowExceptionsOverriddenController.action(:boom) - get "/", headers: { 'HTTP_ACCEPT' => 'application/xml' } + get "/", headers: { "HTTP_ACCEPT" => "application/xml" } assert_response :internal_server_error - assert_equal 'application/xml', response.content_type.to_s - assert_equal({ :status => 500, :error => 'Internal Server Error' }.to_xml, response.body) + assert_equal "application/xml", response.content_type.to_s + assert_equal({ status: 500, error: "Internal Server Error" }.to_xml, response.body) end def test_render_fallback_exception @app = ShowExceptionsOverriddenController.action(:boom) - get "/", headers: { 'HTTP_ACCEPT' => 'text/csv' } + get "/", headers: { "HTTP_ACCEPT" => "text/csv" } assert_response :internal_server_error - assert_equal 'text/html', response.content_type.to_s + assert_equal "text/html", response.content_type.to_s end end @@ -101,9 +101,9 @@ module ShowExceptions @app.instance_variable_set(:@exceptions_app, nil) $stderr = StringIO.new - get '/', headers: { 'HTTP_ACCEPT' => 'text/json' } + get "/", headers: { "HTTP_ACCEPT" => "text/json" } assert_response :internal_server_error - assert_equal 'text/plain', response.content_type.to_s + assert_equal "text/plain", response.content_type.to_s ensure @app.instance_variable_set(:@exceptions_app, @exceptions_app) $stderr = STDERR diff --git a/actionpack/test/controller/streaming_test.rb b/actionpack/test/controller/streaming_test.rb index 6ee6444065..d685467cad 100644 --- a/actionpack/test/controller/streaming_test.rb +++ b/actionpack/test/controller/streaming_test.rb @@ -1,10 +1,10 @@ -require 'abstract_unit' +require "abstract_unit" module ActionController class StreamingResponseTest < ActionController::TestCase class TestController < ActionController::Base def self.controller_path - 'test' + "test" end def basic_stream diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index ea59156f65..33f11e67ef 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -1,40 +1,40 @@ -require 'abstract_unit' -require 'controller/fake_controllers' -require 'active_support/json/decoding' -require 'rails/engine' +require "abstract_unit" +require "controller/fake_controllers" +require "active_support/json/decoding" +require "rails/engine" class TestCaseTest < ActionController::TestCase def self.fixture_path; end; class TestController < ActionController::Base def no_op - render plain: 'dummy' + render plain: "dummy" end def set_flash flash["test"] = ">#{flash["test"]}<" - render plain: 'ignore me' + render plain: "ignore me" end def delete_flash flash.delete("test") - render plain: 'ignore me' + render plain: "ignore me" end def set_flash_now flash.now["test_now"] = ">#{flash["test_now"]}<" - render plain: 'ignore me' + render plain: "ignore me" end def set_session - session['string'] = 'A wonder' - session[:symbol] = 'it works' - render plain: 'Success' + session["string"] = "A wonder" + session[:symbol] = "it works" + render plain: "Success" end def reset_the_session reset_session - render plain: 'ignore me' + render plain: "ignore me" end def render_raw_post @@ -126,15 +126,15 @@ XML end def redirect_to_same_controller - redirect_to controller: 'test', action: 'test_uri', id: 5 + redirect_to controller: "test", action: "test_uri", id: 5 end def redirect_to_different_controller - redirect_to controller: 'fail', id: 5 + redirect_to controller: "fail", id: 5 end def create - head :created, location: 'created resource' + head :created, location: "created resource" end def render_cookie @@ -143,7 +143,7 @@ XML def delete_cookie cookies.delete("foo") - render plain: 'ok' + render plain: "ok" end def test_without_body @@ -155,7 +155,7 @@ XML end def boom - raise 'boom!' + raise "boom!" end private @@ -168,18 +168,18 @@ XML def setup super @controller = TestController.new - @request.delete_header 'PATH_INFO' + @request.delete_header "PATH_INFO" @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| r.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end end end class DefaultUrlOptionsCachingController < ActionController::Base - before_action { @dynamic_opt = 'opt' } + before_action { @dynamic_opt = "opt" } def test_url_options_reset render plain: url_for @@ -197,49 +197,41 @@ XML def test_assert_select_without_body get :test_without_body - assert_select 'body', 0 - assert_select 'div.foo' + assert_select "body", 0 + assert_select "div.foo" end def test_assert_select_with_body get :test_with_body - assert_select 'body.foo' + assert_select "body.foo" end def test_url_options_reset @controller = DefaultUrlOptionsCachingController.new get :test_url_options_reset - assert_nil @request.params['dynamic_opt'] + assert_nil @request.params["dynamic_opt"] assert_match(/dynamic_opt=opt/, @response.body) end def test_raw_post_handling - params = Hash[:page, { name: 'page name' }, 'some key', 123] + params = Hash[:page, { name: "page name" }, "some key", 123] post :render_raw_post, params: params.dup assert_equal params.to_query, @response.body end def test_body_stream - params = Hash[:page, { name: 'page name' }, 'some key', 123] + params = Hash[:page, { name: "page name" }, "some key", 123] post :render_body, params: params.dup assert_equal params.to_query, @response.body end - def test_deprecated_body_stream - params = Hash[:page, { name: 'page name' }, 'some key', 123] - - assert_deprecated { post :render_body, params.dup } - - assert_equal params.to_query, @response.body - end - def test_document_body_and_params_with_post post :test_params, params: { id: 1 } - assert_equal({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}, ::JSON.parse(@response.body)) + assert_equal({ "id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params" }, ::JSON.parse(@response.body)) end def test_document_body_with_post @@ -247,21 +239,11 @@ XML assert_equal "document body", @response.body end - def test_deprecated_document_body_with_post - assert_deprecated { post :render_body, "document body" } - assert_equal "document body", @response.body - end - def test_document_body_with_put put :render_body, body: "document body" assert_equal "document body", @response.body end - def test_deprecated_document_body_with_put - assert_deprecated { put :render_body, "document body" } - assert_equal "document body", @response.body - end - def test_head head :test_params assert_equal 200, @response.status @@ -269,31 +251,21 @@ XML def test_process_without_flash process :set_flash - assert_equal '><', flash['test'] - end - - def test_deprecated_process_with_flash - assert_deprecated { process :set_flash, "GET", nil, nil, { "test" => "value" } } - assert_equal '>value<', flash['test'] + assert_equal "><", flash["test"] end def test_process_with_flash process :set_flash, method: "GET", flash: { "test" => "value" } - assert_equal '>value<', flash['test'] - end - - def test_deprecated_process_with_flash_now - assert_deprecated { process :set_flash_now, "GET", nil, nil, { "test_now" => "value_now" } } - assert_equal '>value_now<', flash['test_now'] + assert_equal ">value<", flash["test"] end def test_process_with_flash_now process :set_flash_now, method: "GET", flash: { "test_now" => "value_now" } - assert_equal '>value_now<', flash['test_now'] + assert_equal ">value_now<", flash["test_now"] end def test_process_delete_flash @@ -305,64 +277,38 @@ XML def test_process_with_session process :set_session - assert_equal 'A wonder', session['string'], "A value stored in the session should be available by string key" - assert_equal 'A wonder', session[:string], "Test session hash should allow indifferent access" - assert_equal 'it works', session['symbol'], "Test session hash should allow indifferent access" - assert_equal 'it works', session[:symbol], "Test session hash should allow indifferent access" - end - - def test_process_with_session_arg - assert_deprecated { process :no_op, "GET", nil, { 'string' => 'value1', symbol: 'value2' } } - assert_equal 'value1', session['string'] - assert_equal 'value1', session[:string] - assert_equal 'value2', session['symbol'] - assert_equal 'value2', session[:symbol] + assert_equal "A wonder", session["string"], "A value stored in the session should be available by string key" + assert_equal "A wonder", session[:string], "Test session hash should allow indifferent access" + assert_equal "it works", session["symbol"], "Test session hash should allow indifferent access" + assert_equal "it works", session[:symbol], "Test session hash should allow indifferent access" end def test_process_with_session_kwarg - process :no_op, method: "GET", session: { 'string' => 'value1', symbol: 'value2' } - assert_equal 'value1', session['string'] - assert_equal 'value1', session[:string] - assert_equal 'value2', session['symbol'] - assert_equal 'value2', session[:symbol] - end - - def test_deprecated_process_merges_session_arg - session[:foo] = 'bar' - assert_deprecated { - get :no_op, nil, { bar: 'baz' } - } - assert_equal 'bar', session[:foo] - assert_equal 'baz', session[:bar] + process :no_op, method: "GET", session: { "string" => "value1", symbol: "value2" } + assert_equal "value1", session["string"] + assert_equal "value1", session[:string] + assert_equal "value2", session["symbol"] + assert_equal "value2", session[:symbol] end def test_process_merges_session_arg - session[:foo] = 'bar' - get :no_op, session: { bar: 'baz' } - assert_equal 'bar', session[:foo] - assert_equal 'baz', session[:bar] - end - - def test_deprecated_merged_session_arg_is_retained_across_requests - assert_deprecated { - get :no_op, nil, { foo: 'bar' } - } - assert_equal 'bar', session[:foo] - get :no_op - assert_equal 'bar', session[:foo] + session[:foo] = "bar" + get :no_op, session: { bar: "baz" } + assert_equal "bar", session[:foo] + assert_equal "baz", session[:bar] end def test_merged_session_arg_is_retained_across_requests - get :no_op, session: { foo: 'bar' } - assert_equal 'bar', session[:foo] + get :no_op, session: { foo: "bar" } + assert_equal "bar", session[:foo] get :no_op - assert_equal 'bar', session[:foo] + assert_equal "bar", session[:foo] end def test_process_overwrites_existing_session_arg - session[:foo] = 'bar' - get :no_op, session: { foo: 'baz' } - assert_equal 'baz', session[:foo] + session[:foo] = "bar" + get :no_op, session: { foo: "baz" } + assert_equal "baz", session[:foo] end def test_session_is_cleared_from_controller_after_reset_session @@ -393,11 +339,6 @@ XML assert_equal "/test_case_test/test/test_uri", @response.body end - def test_deprecated_process_with_request_uri_with_params - assert_deprecated { process :test_uri, "GET", id: 7 } - assert_equal "/test_case_test/test/test_uri/7", @response.body - end - def test_process_with_request_uri_with_params process :test_uri, method: "GET", @@ -406,14 +347,8 @@ XML assert_equal "/test_case_test/test/test_uri/7", @response.body end - def test_deprecated_process_with_request_uri_with_params_with_explicit_uri - @request.env['PATH_INFO'] = "/explicit/uri" - assert_deprecated { process :test_uri, "GET", id: 7 } - assert_equal "/explicit/uri", @response.body - end - def test_process_with_request_uri_with_params_with_explicit_uri - @request.env['PATH_INFO'] = "/explicit/uri" + @request.env["PATH_INFO"] = "/explicit/uri" process :test_uri, method: "GET", params: { id: 7 } assert_equal "/explicit/uri", @response.body end @@ -421,13 +356,13 @@ XML def test_process_with_query_string process :test_query_string, method: "GET", - params: { q: 'test' } + params: { q: "test" } assert_equal "q=test", @response.body end def test_process_with_query_string_with_explicit_uri - @request.env['PATH_INFO'] = '/explicit/uri' - @request.env['QUERY_STRING'] = 'q=test?extra=question' + @request.env["PATH_INFO"] = "/explicit/uri" + @request.env["QUERY_STRING"] = "q=test?extra=question" process :test_query_string assert_equal "q=test?extra=question", @response.body end @@ -444,7 +379,7 @@ XML begin $stderr = StringIO.new - assert_select 'area' #This will cause a warning if content is processed as HTML + assert_select "area" #This will cause a warning if content is processed as HTML $stderr.rewind && err = $stderr.read ensure $stderr = STDERR @@ -454,21 +389,21 @@ XML end def test_assert_generates - assert_generates 'controller/action/5', controller: 'controller', action: 'action', id: '5' - assert_generates 'controller/action/7', { id: "7" }, { controller: "controller", action: "action" } - assert_generates 'controller/action/5', { controller: "controller", action: "action", id: "5", name: "bob" }, {}, { name: "bob" } - assert_generates 'controller/action/7', { id: "7", name: "bob" }, { controller: "controller", action: "action" }, { name: "bob" } - assert_generates 'controller/action/7', { id: "7" }, { controller: "controller", action: "action", name: "bob" }, {} + assert_generates "controller/action/5", controller: "controller", action: "action", id: "5" + assert_generates "controller/action/7", { id: "7" }, controller: "controller", action: "action" + assert_generates "controller/action/5", { controller: "controller", action: "action", id: "5", name: "bob" }, {}, name: "bob" + assert_generates "controller/action/7", { id: "7", name: "bob" }, { controller: "controller", action: "action" }, name: "bob" + assert_generates "controller/action/7", { id: "7" }, { controller: "controller", action: "action", name: "bob" }, {} end def test_assert_routing - assert_routing 'content', controller: 'content', action: 'index' + assert_routing "content", controller: "content", action: "index" end def test_assert_routing_with_method with_routing do |set| set.draw { resources(:content) } - assert_routing({ method: 'post', path: 'content' }, { controller: 'content', action: 'create' }) + assert_routing({ method: "post", path: "content" }, controller: "content", action: "create") end end @@ -476,85 +411,71 @@ XML with_routing do |set| set.draw do namespace :admin do - get 'user' => 'user#index' + get "user" => "user#index" end end - assert_routing 'admin/user', controller: 'admin/user', action: 'index' + assert_routing "admin/user", controller: "admin/user", action: "index" end end def test_assert_routing_with_glob with_routing do |set| - set.draw { get('*path' => "pages#show") } - assert_routing('/company/about', { controller: 'pages', action: 'show', path: 'company/about' }) + set.draw { get("*path" => "pages#show") } + assert_routing("/company/about", controller: "pages", action: "show", path: "company/about") end end - def test_deprecated_params_passing - assert_deprecated { - get :test_params, page: { name: "Page name", month: '4', year: '2004', day: '6' } - } - parsed_params = ::JSON.parse(@response.body) - assert_equal( - { - 'controller' => 'test_case_test/test', 'action' => 'test_params', - 'page' => { 'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6' } - }, - parsed_params - ) - end - def test_params_passing get :test_params, params: { page: { name: "Page name", - month: '4', - year: '2004', - day: '6' + month: "4", + year: "2004", + day: "6" } } parsed_params = ::JSON.parse(@response.body) assert_equal( { - 'controller' => 'test_case_test/test', 'action' => 'test_params', - 'page' => { 'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6' } + "controller" => "test_case_test/test", "action" => "test_params", + "page" => { "name" => "Page name", "month" => "4", "year" => "2004", "day" => "6" } }, parsed_params ) end def test_query_param_named_action - get :test_query_parameters, params: {action: 'foobar'} + get :test_query_parameters, params: { action: "foobar" } parsed_params = JSON.parse(@response.body) - assert_equal({'action' => 'foobar'}, parsed_params) + assert_equal({ "action" => "foobar" }, parsed_params) end def test_request_param_named_action - post :test_request_parameters, params: {action: 'foobar'} + post :test_request_parameters, params: { action: "foobar" } parsed_params = eval(@response.body) - assert_equal({'action' => 'foobar'}, parsed_params) + assert_equal({ "action" => "foobar" }, parsed_params) end def test_kwarg_params_passing_with_session_and_flash get :test_params, params: { page: { name: "Page name", - month: '4', - year: '2004', - day: '6' + month: "4", + year: "2004", + day: "6" } - }, session: { 'foo' => 'bar' }, flash: { notice: 'created' } + }, session: { "foo" => "bar" }, flash: { notice: "created" } parsed_params = ::JSON.parse(@response.body) assert_equal( - {'controller' => 'test_case_test/test', 'action' => 'test_params', - 'page' => {'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6'}}, + { "controller" => "test_case_test/test", "action" => "test_params", + "page" => { "name" => "Page name", "month" => "4", "year" => "2004", "day" => "6" } }, parsed_params ) - assert_equal 'bar', session[:foo] - assert_equal 'created', flash[:notice] + assert_equal "bar", session[:foo] + assert_equal "created", flash[:notice] end def test_params_passing_with_integer @@ -563,38 +484,28 @@ XML } parsed_params = ::JSON.parse(@response.body) assert_equal( - {'controller' => 'test_case_test/test', 'action' => 'test_params', - 'page' => {'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6'}}, + { "controller" => "test_case_test/test", "action" => "test_params", + "page" => { "name" => "Page name", "month" => "4", "year" => "2004", "day" => "6" } }, parsed_params ) end def test_params_passing_with_integers_when_not_html_request - get :test_params, params: { format: 'json', count: 999 } + get :test_params, params: { format: "json", count: 999 } parsed_params = ::JSON.parse(@response.body) assert_equal( - {'controller' => 'test_case_test/test', 'action' => 'test_params', - 'format' => 'json', 'count' => '999' }, + { "controller" => "test_case_test/test", "action" => "test_params", + "format" => "json", "count" => "999" }, parsed_params ) end def test_params_passing_path_parameter_is_string_when_not_html_request - get :test_params, params: { format: 'json', id: 1 } + get :test_params, params: { format: "json", id: 1 } parsed_params = ::JSON.parse(@response.body) assert_equal( - {'controller' => 'test_case_test/test', 'action' => 'test_params', - 'format' => 'json', 'id' => '1' }, - parsed_params - ) - end - - def test_deprecated_params_passing_path_parameter_is_string_when_not_html_request - assert_deprecated { get :test_params, format: 'json', id: 1 } - parsed_params = ::JSON.parse(@response.body) - assert_equal( - {'controller' => 'test_case_test/test', 'action' => 'test_params', - 'format' => 'json', 'id' => '1' }, + { "controller" => "test_case_test/test", "action" => "test_params", + "format" => "json", "id" => "1" }, parsed_params ) end @@ -602,13 +513,13 @@ XML def test_params_passing_with_frozen_values assert_nothing_raised do get :test_params, params: { - frozen: 'icy'.freeze, frozens: ['icy'.freeze].freeze, deepfreeze: { frozen: 'icy'.freeze }.freeze + frozen: "icy".freeze, frozens: ["icy".freeze].freeze, deepfreeze: { frozen: "icy".freeze }.freeze } end parsed_params = ::JSON.parse(@response.body) assert_equal( - {'controller' => 'test_case_test/test', 'action' => 'test_params', - 'frozen' => 'icy', 'frozens' => ['icy'], 'deepfreeze' => { 'frozen' => 'icy' }}, + { "controller" => "test_case_test/test", "action" => "test_params", + "frozen" => "icy", "frozens" => ["icy"], "deepfreeze" => { "frozen" => "icy" } }, parsed_params ) end @@ -620,8 +531,8 @@ XML end test "set additional HTTP headers" do - @request.headers['Referer'] = "http://nohost.com/home" - @request.headers['Content-Type'] = "application/rss+xml" + @request.headers["Referer"] = "http://nohost.com/home" + @request.headers["Content-Type"] = "application/rss+xml" get :test_headers parsed_env = ActiveSupport::JSON.decode(@response.body) assert_equal "http://nohost.com/home", parsed_env["HTTP_REFERER"] @@ -629,36 +540,50 @@ XML end test "set additional env variables" do - @request.headers['HTTP_REFERER'] = "http://example.com/about" - @request.headers['CONTENT_TYPE'] = "application/json" + @request.headers["HTTP_REFERER"] = "http://example.com/about" + @request.headers["CONTENT_TYPE"] = "application/json" get :test_headers parsed_env = ActiveSupport::JSON.decode(@response.body) assert_equal "http://example.com/about", parsed_env["HTTP_REFERER"] assert_equal "application/json", parsed_env["CONTENT_TYPE"] end + def test_using_as_json_sets_request_content_type_to_json + post :render_body, params: { bool_value: true, str_value: "string", num_value: 2 }, as: :json + + assert_equal "application/json", @request.headers["CONTENT_TYPE"] + assert_equal true, @request.request_parameters[:bool_value] + assert_equal "string", @request.request_parameters[:str_value] + assert_equal 2, @request.request_parameters[:num_value] + end + + def test_using_as_json_sets_format_json + post :render_body, params: { bool_value: true, str_value: "string", num_value: 2 }, as: :json + assert_equal "json", @request.format + end + def test_mutating_content_type_headers_for_plain_text_files_sets_the_header - @request.headers['Content-Type'] = 'text/plain' - post :render_body, params: { name: 'foo.txt' } + @request.headers["Content-Type"] = "text/plain" + post :render_body, params: { name: "foo.txt" } - assert_equal 'text/plain', @request.headers['Content-type'] - assert_equal 'foo.txt', @request.request_parameters[:name] - assert_equal 'render_body', @request.path_parameters[:action] + assert_equal "text/plain", @request.headers["Content-type"] + assert_equal "foo.txt", @request.request_parameters[:name] + assert_equal "render_body", @request.path_parameters[:action] end def test_mutating_content_type_headers_for_html_files_sets_the_header - @request.headers['Content-Type'] = 'text/html' - post :render_body, params: { name: 'foo.html' } + @request.headers["Content-Type"] = "text/html" + post :render_body, params: { name: "foo.html" } - assert_equal 'text/html', @request.headers['Content-type'] - assert_equal 'foo.html', @request.request_parameters[:name] - assert_equal 'render_body', @request.path_parameters[:action] + assert_equal "text/html", @request.headers["Content-type"] + assert_equal "foo.html", @request.request_parameters[:name] + assert_equal "render_body", @request.path_parameters[:action] end def test_mutating_content_type_headers_for_non_registered_mime_type_raises_an_error assert_raises(RuntimeError) do - @request.headers['Content-Type'] = 'type/fake' - post :render_body, params: { name: 'foo.fake' } + @request.headers["Content-Type"] = "type/fake" + post :render_body, params: { name: "foo.fake" } end end @@ -669,24 +594,19 @@ XML assert_kind_of String, @request.path_parameters[:id] end - def test_deprecared_id_converted_to_string - assert_deprecated { get :test_params, id: 20, foo: Object.new} - assert_kind_of String, @request.path_parameters[:id] - end - def test_array_path_parameter_handled_properly with_routing do |set| set.draw do - get 'file/*path', to: 'test_case_test/test#test_params' + get "file/*path", to: "test_case_test/test#test_params" ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end - get :test_params, params: { path: ['hello', 'world'] } - assert_equal ['hello', 'world'], @request.path_parameters[:path] - assert_equal 'hello/world', @request.path_parameters[:path].to_param + get :test_params, params: { path: ["hello", "world"] } + assert_equal ["hello", "world"], @request.path_parameters[:path] + assert_equal "hello/world", @request.path_parameters[:path].to_param end end @@ -704,8 +624,8 @@ XML routes_id = @routes.object_id begin - with_routing { raise 'fail' } - fail 'Should not be here.' + with_routing { raise "fail" } + fail "Should not be here." rescue RuntimeError end @@ -724,46 +644,23 @@ XML def test_header_properly_reset_after_remote_http_request get :test_params, xhr: true - assert_nil @request.env['HTTP_X_REQUESTED_WITH'] - assert_nil @request.env['HTTP_ACCEPT'] - end - - def test_deprecated_xhr_with_params - assert_deprecated { xhr :get, :test_params, params: { id: 1 } } - - assert_equal({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}, ::JSON.parse(@response.body)) + assert_nil @request.env["HTTP_X_REQUESTED_WITH"] + assert_nil @request.env["HTTP_ACCEPT"] end def test_xhr_with_params get :test_params, params: { id: 1 }, xhr: true - assert_equal({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}, ::JSON.parse(@response.body)) + assert_equal({ "id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params" }, ::JSON.parse(@response.body)) end def test_xhr_with_session get :set_session, xhr: true - assert_equal 'A wonder', session['string'], "A value stored in the session should be available by string key" - assert_equal 'A wonder', session[:string], "Test session hash should allow indifferent access" - assert_equal 'it works', session['symbol'], "Test session hash should allow indifferent access" - assert_equal 'it works', session[:symbol], "Test session hash should allow indifferent access" - end - - def test_deprecated_xhr_with_session - assert_deprecated { xhr :get, :set_session } - - assert_equal 'A wonder', session['string'], "A value stored in the session should be available by string key" - assert_equal 'A wonder', session[:string], "Test session hash should allow indifferent access" - assert_equal 'it works', session['symbol'], "Test session hash should allow indifferent access" - assert_equal 'it works', session[:symbol], "Test session hash should allow indifferent access" - end - - def test_deprecated_params_reset_between_post_requests - assert_deprecated { post :no_op, foo: "bar" } - assert_equal "bar", @request.params[:foo] - - post :no_op - assert @request.params[:foo].blank? + assert_equal "A wonder", session["string"], "A value stored in the session should be available by string key" + assert_equal "A wonder", session[:string], "Test session hash should allow indifferent access" + assert_equal "it works", session["symbol"], "Test session hash should allow indifferent access" + assert_equal "it works", session[:symbol], "Test session hash should allow indifferent access" end def test_params_reset_between_post_requests @@ -804,54 +701,62 @@ XML end def test_request_format - get :test_format, params: { format: 'html' } - assert_equal 'text/html', @response.body + get :test_format, params: { format: "html" } + assert_equal "text/html", @response.body - get :test_format, params: { format: 'json' } - assert_equal 'application/json', @response.body + get :test_format, params: { format: "json" } + assert_equal "application/json", @response.body - get :test_format, params: { format: 'xml' } - assert_equal 'application/xml', @response.body + get :test_format, params: { format: "xml" } + assert_equal "application/xml", @response.body get :test_format - assert_equal 'text/html', @response.body + assert_equal "text/html", @response.body end def test_request_format_kwarg - get :test_format, format: 'html' - assert_equal 'text/html', @response.body + get :test_format, format: "html" + assert_equal "text/html", @response.body - get :test_format, format: 'json' - assert_equal 'application/json', @response.body + get :test_format, format: "json" + assert_equal "application/json", @response.body - get :test_format, format: 'xml' - assert_equal 'application/xml', @response.body + get :test_format, format: "xml" + assert_equal "application/xml", @response.body get :test_format - assert_equal 'text/html', @response.body + assert_equal "text/html", @response.body end def test_request_format_kwarg_overrides_params - get :test_format, format: 'json', params: { format: 'html' } - assert_equal 'application/json', @response.body + get :test_format, format: "json", params: { format: "html" } + assert_equal "application/json", @response.body end def test_should_have_knowledge_of_client_side_cookie_state_even_if_they_are_not_set - cookies['foo'] = 'bar' + cookies["foo"] = "bar" get :no_op - assert_equal 'bar', cookies['foo'] + assert_equal "bar", cookies["foo"] end def test_cookies_should_be_escaped_properly - cookies['foo'] = '+' + cookies["foo"] = "+" get :render_cookie - assert_equal '+', @response.body + assert_equal "+", @response.body end def test_should_detect_if_cookie_is_deleted - cookies['foo'] = 'bar' + cookies["foo"] = "bar" get :delete_cookie - assert_nil cookies['foo'] + assert_nil cookies["foo"] + end + + def test_multiple_mixed_method_process_should_scrub_rack_input + post :test_params, params: { id: 1, foo: "an foo" } + assert_equal({ "id"=>"1", "foo" => "an foo", "controller"=>"test_case_test/test", "action"=>"test_params" }, ::JSON.parse(@response.body)) + + get :test_params, params: { bar: "an bar" } + assert_equal({ "bar"=>"an bar", "controller"=>"test_case_test/test", "action"=>"test_params" }, ::JSON.parse(@response.body)) end %w(controller response request).each do |variable| @@ -870,15 +775,15 @@ XML end end - FILES_DIR = File.dirname(__FILE__) + '/../fixtures/multipart' + FILES_DIR = File.dirname(__FILE__) + "/../fixtures/multipart" - READ_BINARY = 'rb:binary' - READ_PLAIN = 'r:binary' + READ_BINARY = "rb:binary" + READ_PLAIN = "r:binary" def test_test_uploaded_file - filename = 'mona_lisa.jpg' + filename = "ruby_on_rails.jpg" path = "#{FILES_DIR}/#{filename}" - content_type = 'image/png' + content_type = "image/png" expected = File.read(path) expected.force_encoding(Encoding::BINARY) @@ -896,15 +801,15 @@ XML def test_fixture_path_is_accessed_from_self_instead_of_active_support_test_case TestCaseTest.stub :fixture_path, FILES_DIR do - uploaded_file = fixture_file_upload('/mona_lisa.jpg', 'image/png') - assert_equal File.open("#{FILES_DIR}/mona_lisa.jpg", READ_PLAIN).read, uploaded_file.read + uploaded_file = fixture_file_upload("/ruby_on_rails.jpg", "image/png") + assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read end end def test_test_uploaded_file_with_binary - filename = 'mona_lisa.jpg' + filename = "ruby_on_rails.jpg" path = "#{FILES_DIR}/#{filename}" - content_type = 'image/png' + content_type = "image/png" binary_uploaded_file = Rack::Test::UploadedFile.new(path, content_type, :binary) assert_equal File.open(path, READ_BINARY).read, binary_uploaded_file.read @@ -914,9 +819,9 @@ XML end def test_fixture_file_upload_with_binary - filename = 'mona_lisa.jpg' + filename = "ruby_on_rails.jpg" path = "#{FILES_DIR}/#{filename}" - content_type = 'image/jpg' + content_type = "image/jpg" binary_file_upload = fixture_file_upload(path, content_type, :binary) assert_equal File.open(path, READ_BINARY).read, binary_file_upload.read @@ -926,50 +831,48 @@ XML end def test_fixture_file_upload_should_be_able_access_to_tempfile - file = fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg") + file = fixture_file_upload(FILES_DIR + "/ruby_on_rails.jpg", "image/jpg") assert file.respond_to?(:tempfile), "expected tempfile should respond on fixture file object, got nothing" end def test_fixture_file_upload post :test_file_upload, params: { - file: fixture_file_upload(FILES_DIR + "/mona_lisa.jpg", "image/jpg") + file: fixture_file_upload(FILES_DIR + "/ruby_on_rails.jpg", "image/jpg") } - assert_equal '159528', @response.body + assert_equal "45142", @response.body end def test_fixture_file_upload_relative_to_fixture_path TestCaseTest.stub :fixture_path, FILES_DIR do - uploaded_file = fixture_file_upload("mona_lisa.jpg", "image/jpg") - assert_equal File.open("#{FILES_DIR}/mona_lisa.jpg", READ_PLAIN).read, uploaded_file.read + uploaded_file = fixture_file_upload("ruby_on_rails.jpg", "image/jpg") + assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read end end - def test_fixture_file_upload_ignores_nil_fixture_path - uploaded_file = fixture_file_upload("#{FILES_DIR}/mona_lisa.jpg", "image/jpg") - assert_equal File.open("#{FILES_DIR}/mona_lisa.jpg", READ_PLAIN).read, uploaded_file.read + def test_fixture_file_upload_ignores_fixture_path_given_full_path + TestCaseTest.stub :fixture_path, File.dirname(__FILE__) do + uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpg") + assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read + end end - def test_deprecated_action_dispatch_uploaded_file_upload - filename = 'mona_lisa.jpg' - path = "#{FILES_DIR}/#{filename}" - assert_deprecated { - post :test_file_upload, file: Rack::Test::UploadedFile.new(path, "image/jpg", true) - } - assert_equal '159528', @response.body + def test_fixture_file_upload_ignores_nil_fixture_path + uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpg") + assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read end def test_action_dispatch_uploaded_file_upload - filename = 'mona_lisa.jpg' + filename = "ruby_on_rails.jpg" path = "#{FILES_DIR}/#{filename}" post :test_file_upload, params: { file: Rack::Test::UploadedFile.new(path, "image/jpg", true) } - assert_equal '159528', @response.body + assert_equal "45142", @response.body end def test_test_uploaded_file_exception_when_file_doesnt_exist - assert_raise(RuntimeError) { Rack::Test::UploadedFile.new('non_existent_file') } + assert_raise(RuntimeError) { Rack::Test::UploadedFile.new("non_existent_file") } end def test_redirect_url_only_cares_about_location_header @@ -977,12 +880,12 @@ XML assert_response :created # Redirect url doesn't care that it wasn't a :redirect response. - assert_equal 'created resource', @response.redirect_url + assert_equal "created resource", @response.redirect_url assert_equal @response.redirect_url, redirect_to_url # Must be a :redirect response. assert_raise(ActiveSupport::TestCase::Assertion) do - assert_redirected_to 'created resource' + assert_redirected_to "created resource" end end @@ -996,12 +899,12 @@ XML assert_raise(RuntimeError) do process :boom, method: "GET", - params: { q: 'test1' } + params: { q: "test1" } end process :test_query_string, method: "GET", - params: { q: 'test2' } + params: { q: "test2" } assert_equal "q=test2", @response.body end @@ -1011,7 +914,7 @@ class ResponseDefaultHeadersTest < ActionController::TestCase class TestController < ActionController::Base def remove_header headers.delete params[:header] - head :ok, 'C' => '3' + head :ok, "C" => "3" end # Render a head response, but don't touch default headers @@ -1022,7 +925,7 @@ class ResponseDefaultHeadersTest < ActionController::TestCase def before_setup @original = ActionDispatch::Response.default_headers - @defaults = { 'A' => '1', 'B' => '2' } + @defaults = { "A" => "1", "B" => "2" } ActionDispatch::Response.default_headers = @defaults super end @@ -1034,11 +937,11 @@ class ResponseDefaultHeadersTest < ActionController::TestCase def setup super @controller = TestController.new - @request.env['PATH_INFO'] = nil + @request.env["PATH_INFO"] = nil @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| r.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end end @@ -1048,18 +951,18 @@ class ResponseDefaultHeadersTest < ActionController::TestCase get :leave_alone # Response headers start out with the defaults - assert_equal @defaults.merge('Content-Type' => 'text/html'), response.headers + assert_equal @defaults.merge("Content-Type" => "text/html"), response.headers end test "response deletes a default header" do - get :remove_header, params: { header: 'A' } + get :remove_header, params: { header: "A" } assert_response :ok # After a request, the response in the test case doesn't have the # defaults merged on top again. - assert_not_includes response.headers, 'A' - assert_includes response.headers, 'B' - assert_includes response.headers, 'C' + assert_not_includes response.headers, "A" + assert_includes response.headers, "B" + assert_includes response.headers, "C" end end @@ -1068,13 +971,13 @@ module EngineControllerTests isolate_namespace EngineControllerTests routes.draw do - get '/' => 'bar#index' + get "/" => "bar#index" end end class BarController < ActionController::Base def index - render plain: 'bar' + render plain: "bar" end end @@ -1083,7 +986,7 @@ module EngineControllerTests def test_engine_controller_route get :index - assert_equal @response.body, 'bar' + assert_equal @response.body, "bar" end end @@ -1096,7 +999,7 @@ module EngineControllerTests def test_engine_controller_route get :index - assert_equal @response.body, 'bar' + assert_equal @response.body, "bar" end end end @@ -1137,7 +1040,7 @@ class CrazySymbolNameTest < ActionController::TestCase end class CrazyStringNameTest < ActionController::TestCase - tests 'content' + tests "content" def test_set_controller_class_using_string assert_equal ContentController, self.class.controller_class @@ -1150,8 +1053,8 @@ class NamedRoutesControllerTest < ActionController::TestCase def test_should_be_able_to_use_named_routes_before_a_request_is_done with_routing do |set| set.draw { resources :contents } - assert_equal 'http://test.host/contents/new', new_content_url - assert_equal 'http://test.host/contents/1', content_url(id: 1) + assert_equal "http://test.host/contents/new", new_content_url + assert_equal "http://test.host/contents/1", content_url(id: 1) end end end @@ -1167,7 +1070,7 @@ class AnonymousControllerTest < ActionController::TestCase @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| r.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end end @@ -1175,7 +1078,7 @@ class AnonymousControllerTest < ActionController::TestCase def test_controller_name get :index - assert_equal 'anonymous', @response.body + assert_equal "anonymous", @response.body end end @@ -1193,19 +1096,19 @@ class RoutingDefaultsTest < ActionController::TestCase @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| r.draw do - get '/posts/:id', to: 'anonymous#post', bucket_type: 'post' - get '/projects/:id', to: 'anonymous#project', defaults: { bucket_type: 'project' } + get "/posts/:id", to: "anonymous#post", bucket_type: "post" + get "/projects/:id", to: "anonymous#project", defaults: { bucket_type: "project" } end end end def test_route_option_can_be_passed_via_process - get :post, params: { id: 1, bucket_type: 'post'} - assert_equal '/posts/1', @response.body + get :post, params: { id: 1, bucket_type: "post" } + assert_equal "/posts/1", @response.body end def test_route_default_is_not_required_for_building_request_uri get :project, params: { id: 2 } - assert_equal '/projects/2', @response.body + assert_equal "/projects/2", @response.body end end diff --git a/actionpack/test/controller/url_for_integration_test.rb b/actionpack/test/controller/url_for_integration_test.rb index a6ca5fc868..c7ea6c5ef6 100644 --- a/actionpack/test/controller/url_for_integration_test.rb +++ b/actionpack/test/controller/url_for_integration_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'controller/fake_controllers' -require 'active_support/core_ext/object/with_options' +require "abstract_unit" +require "controller/fake_controllers" +require "active_support/core_ext/object/with_options" module ActionPack class URLForIntegrationTest < ActiveSupport::TestCase @@ -14,54 +14,54 @@ module ActionPack resources :users, :posts end - namespace 'api' do - root :to => 'users#index' + namespace "api" do + root to: "users#index" end - get '/blog(/:year(/:month(/:day)))' => 'posts#show_date', + get "/blog(/:year(/:month(/:day)))" => "posts#show_date", :constraints => { - :year => /(19|20)\d\d/, - :month => /[01]?\d/, - :day => /[0-3]?\d/ + year: /(19|20)\d\d/, + month: /[01]?\d/, + day: /[0-3]?\d/ }, :day => nil, :month => nil - get 'archive/:year', :controller => 'archive', :action => 'index', - :defaults => { :year => nil }, - :constraints => { :year => /\d{4}/ }, - :as => "blog" + get "archive/:year", controller: "archive", action: "index", + defaults: { year: nil }, + constraints: { year: /\d{4}/ }, + as: "blog" resources :people #match 'legacy/people' => "people#index", :legacy => "true" - get 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol - get 'id_default(/:id)' => "foo#id_default", :id => 1 - match 'get_or_post' => "foo#get_or_post", :via => [:get, :post] - get 'optional/:optional' => "posts#index" - get 'projects/:project_id' => "project#index", :as => "project" - get 'clients' => "projects#index" + get "symbols", controller: :symbols, action: :show, name: :as_symbol + get "id_default(/:id)" => "foo#id_default", :id => 1 + match "get_or_post" => "foo#get_or_post", :via => [:get, :post] + get "optional/:optional" => "posts#index" + get "projects/:project_id" => "project#index", :as => "project" + get "clients" => "projects#index" - get 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i - get 'extended/geocode/:postalcode' => 'geocode#show',:constraints => { - :postalcode => /# Postcode format + get "ignorecase/geocode/:postalcode" => "geocode#show", :postalcode => /hx\d\d-\d[a-z]{2}/i + get "extended/geocode/:postalcode" => "geocode#show",:constraints => { + postalcode: /# Postcode format \d{5} #Prefix (-\d{4})? #Suffix /x }, :as => "geocode" - get 'news(.:format)' => "news#index" + get "news(.:format)" => "news#index" ActiveSupport::Deprecation.silence { - get 'comment/:id(/:action)' => "comments#show" - get 'ws/:controller(/:action(/:id))', :ws => true - get 'account(/:action)' => "account#subscription" - get 'pages/:page_id/:controller(/:action(/:id))' - get ':controller/ping', :action => 'ping' - get ':controller(/:action(/:id))(.:format)' + get "comment/:id(/:action)" => "comments#show" + get "ws/:controller(/:action(/:id))", ws: true + get "account(/:action)" => "account#subscription" + get "pages/:page_id/:controller(/:action(/:id))" + get ":controller/ping", action: "ping" + get ":controller(/:action(/:id))(.:format)" } - root :to => "news#index" + root to: "news#index" } attr_reader :routes @@ -73,111 +73,111 @@ module ActionPack end [ - ['/admin/users',[ { :use_route => 'admin_users' }]], - ['/admin/users',[ { :controller => 'admin/users' }]], - ['/admin/users',[ { :controller => 'admin/users', :action => 'index' }]], - ['/admin/users',[ { :action => 'index' }, { :controller => 'admin/users', :action => 'index' }, '/admin/users']], - ['/admin/users',[ { :controller => 'users', :action => 'index' }, { :controller => 'admin/accounts', :action => 'show', :id => '1' }, '/admin/accounts/show/1']], - ['/people',[ { :controller => '/people', :action => 'index' }, {:controller=>"admin/accounts", :action=>"foo", :id=>"bar"}, '/admin/accounts/foo/bar']], - - ['/admin/posts',[ { :controller => 'admin/posts' }]], - ['/admin/posts/new',[ { :controller => 'admin/posts', :action => 'new' }]], - - ['/blog/2009',[ { :controller => 'posts', :action => 'show_date', :year => 2009 }]], - ['/blog/2009/1',[ { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1 }]], - ['/blog/2009/1/1',[ { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1, :day => 1 }]], - - ['/archive/2010',[ { :controller => 'archive', :action => 'index', :year => '2010' }]], - ['/archive',[ { :controller => 'archive', :action => 'index' }]], - ['/archive?year=january',[ { :controller => 'archive', :action => 'index', :year => 'january' }]], - - ['/people',[ { :controller => 'people', :action => 'index' }]], - ['/people',[ { :action => 'index' }, { :controller => 'people', :action => 'index' }, '/people']], - ['/people',[ { :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }, '/people/show/1']], - ['/people',[ { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }, '/people/show/1']], - ['/people',[ {}, { :controller => 'people', :action => 'index' }, '/people']], - ['/people/1',[ { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'show', :id => '1' }, '/people/show/1']], - ['/people/new',[ { :use_route => 'new_person' }]], - ['/people/new',[ { :controller => 'people', :action => 'new' }]], - ['/people/1',[ { :use_route => 'person', :id => '1' }]], - ['/people/1',[ { :controller => 'people', :action => 'show', :id => '1' }]], - ['/people/1.xml',[ { :controller => 'people', :action => 'show', :id => '1', :format => 'xml' }]], - ['/people/1',[ { :controller => 'people', :action => 'show', :id => 1 }]], - ['/people/1',[ { :controller => 'people', :action => 'show', :id => Model.new('1') }]], - ['/people/1',[ { :action => 'show', :id => '1' }, { :controller => 'people', :action => 'index' }, '/people']], - ['/people/1',[ { :action => 'show', :id => 1 }, { :controller => 'people', :action => 'show', :id => '1' }, '/people/show/1']], - ['/people',[ { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }, '/people/show/1']], - ['/people/1',[ {}, { :controller => 'people', :action => 'show', :id => '1' }, '/people/show/1']], - ['/people/1',[ { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'index', :id => '1' }, '/people/index/1']], - ['/people/1/edit',[ { :controller => 'people', :action => 'edit', :id => '1' }]], - ['/people/1/edit.xml',[ { :controller => 'people', :action => 'edit', :id => '1', :format => 'xml' }]], - ['/people/1/edit',[ { :use_route => 'edit_person', :id => '1' }]], - ['/people/1?legacy=true',[ { :controller => 'people', :action => 'show', :id => '1', :legacy => 'true' }]], - ['/people?legacy=true',[ { :controller => 'people', :action => 'index', :legacy => 'true' }]], - - ['/id_default/2',[ { :controller => 'foo', :action => 'id_default', :id => '2' }]], - ['/id_default',[ { :controller => 'foo', :action => 'id_default', :id => '1' }]], - ['/id_default',[ { :controller => 'foo', :action => 'id_default', :id => 1 }]], - ['/id_default',[ { :controller => 'foo', :action => 'id_default' }]], - ['/optional/bar',[ { :controller => 'posts', :action => 'index', :optional => 'bar' }]], - ['/posts',[ { :controller => 'posts', :action => 'index' }]], - - ['/project',[ { :controller => 'project', :action => 'index' }]], - ['/projects/1',[ { :controller => 'project', :action => 'index', :project_id => '1' }]], - ['/projects/1',[ { :controller => 'project', :action => 'index'}, {:project_id => '1', :controller => 'project', :action => 'index' }, '/projects/1']], - ['/projects/1',[ { :use_route => 'project', :controller => 'project', :action => 'index', :project_id => '1' }]], - ['/projects/1',[ { :use_route => 'project', :controller => 'project', :action => 'index' }, { :controller => 'project', :action => 'index', :project_id => '1' }, '/projects/1']], - - ['/clients',[ { :controller => 'projects', :action => 'index' }]], - ['/clients?project_id=1',[ { :controller => 'projects', :action => 'index', :project_id => '1' }]], - ['/clients',[ { :controller => 'projects', :action => 'index' }, { :project_id => '1', :controller => 'project', :action => 'index' }, '/projects/1']], - - ['/comment/20',[ { :id => 20 }, { :controller => 'comments', :action => 'show' }, '/comments/show']], - ['/comment/20',[ { :controller => 'comments', :id => 20, :action => 'show' }]], - ['/comments/boo',[ { :controller => 'comments', :action => 'boo' }]], - - ['/ws/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1', :ws => true }]], - ['/ws/posts',[ { :controller => 'posts', :action => 'index', :ws => true }]], - - ['/account',[ { :controller => 'account', :action => 'subscription' }]], - ['/account/billing',[ { :controller => 'account', :action => 'billing' }]], - - ['/pages/1/notes/show/1',[ { :page_id => '1', :controller => 'notes', :action => 'show', :id => '1' }]], - ['/pages/1/notes/list',[ { :page_id => '1', :controller => 'notes', :action => 'list' }]], - ['/pages/1/notes',[ { :page_id => '1', :controller => 'notes', :action => 'index' }]], - ['/pages/1/notes',[ { :page_id => '1', :controller => 'notes' }]], - ['/notes',[ { :page_id => nil, :controller => 'notes' }]], - ['/notes',[ { :controller => 'notes' }]], - ['/notes/print',[ { :controller => 'notes', :action => 'print' }]], - ['/notes/print',[ {}, { :controller => 'notes', :action => 'print' }, '/notes/print']], - - ['/notes/index/1',[ { :controller => 'notes' }, { :controller => 'notes', :action => 'index', :id => '1' }, '/notes/index/1']], - ['/notes/index/1',[ { :controller => 'notes' }, { :controller => 'notes', :id => '1', :action => 'index' }, '/notes/index/1']], - ['/notes/index/1',[ { :action => 'index' }, { :controller => 'notes', :id => '1', :action => 'index' }, '/notes/index/1']], - ['/notes/index/1',[ {}, { :controller => 'notes', :id => '1', :action => 'index' }, '/notes/index/1']], - ['/notes/show/1',[ {}, { :controller => 'notes', :action => 'show', :id => '1' }, '/notes/show/1']], - ['/posts',[ { :controller => 'posts' }, { :controller => 'notes', :action => 'show', :id => '1' }, '/notes/show/1']], - ['/notes/list',[ { :action => 'list' }, { :controller => 'notes', :action => 'show', :id => '1' }, '/notes/show/1']], - - ['/posts/ping',[ { :controller => 'posts', :action => 'ping' }]], - ['/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1' }]], - ['/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1', :format => '' }]], - ['/posts',[ { :controller => 'posts' }]], - ['/posts',[ { :controller => 'posts', :action => 'index' }]], - ['/posts/create',[ { :action => 'create' }, {:day=>nil, :month=>nil, :controller=>"posts", :action=>"show_date"}, '/blog']], - ['/posts?foo=bar',[ { :controller => 'posts', :foo => 'bar' }]], - ['/posts?foo%5B%5D=bar&foo%5B%5D=baz', [{ :controller => 'posts', :foo => ['bar', 'baz'] }]], - ['/posts?page=2', [{ :controller => 'posts', :page => 2 }]], - ['/posts?q%5Bfoo%5D%5Ba%5D=b', [{ :controller => 'posts', :q => { :foo => { :a => 'b'}} }]], - - ['/news.rss', [{ :controller => 'news', :action => 'index', :format => 'rss' }]], + ["/admin/users",[ { use_route: "admin_users" }]], + ["/admin/users",[ { controller: "admin/users" }]], + ["/admin/users",[ { controller: "admin/users", action: "index" }]], + ["/admin/users",[ { action: "index" }, { controller: "admin/users", action: "index" }, "/admin/users"]], + ["/admin/users",[ { controller: "users", action: "index" }, { controller: "admin/accounts", action: "show", id: "1" }, "/admin/accounts/show/1"]], + ["/people",[ { controller: "/people", action: "index" }, { controller: "admin/accounts", action: "foo", id: "bar" }, "/admin/accounts/foo/bar"]], + + ["/admin/posts",[ { controller: "admin/posts" }]], + ["/admin/posts/new",[ { controller: "admin/posts", action: "new" }]], + + ["/blog/2009",[ { controller: "posts", action: "show_date", year: 2009 }]], + ["/blog/2009/1",[ { controller: "posts", action: "show_date", year: 2009, month: 1 }]], + ["/blog/2009/1/1",[ { controller: "posts", action: "show_date", year: 2009, month: 1, day: 1 }]], + + ["/archive/2010",[ { controller: "archive", action: "index", year: "2010" }]], + ["/archive",[ { controller: "archive", action: "index" }]], + ["/archive?year=january",[ { controller: "archive", action: "index", year: "january" }]], + + ["/people",[ { controller: "people", action: "index" }]], + ["/people",[ { action: "index" }, { controller: "people", action: "index" }, "/people"]], + ["/people",[ { action: "index" }, { controller: "people", action: "show", id: "1" }, "/people/show/1"]], + ["/people",[ { controller: "people", action: "index" }, { controller: "people", action: "show", id: "1" }, "/people/show/1"]], + ["/people",[ {}, { controller: "people", action: "index" }, "/people"]], + ["/people/1",[ { controller: "people", action: "show" }, { controller: "people", action: "show", id: "1" }, "/people/show/1"]], + ["/people/new",[ { use_route: "new_person" }]], + ["/people/new",[ { controller: "people", action: "new" }]], + ["/people/1",[ { use_route: "person", id: "1" }]], + ["/people/1",[ { controller: "people", action: "show", id: "1" }]], + ["/people/1.xml",[ { controller: "people", action: "show", id: "1", format: "xml" }]], + ["/people/1",[ { controller: "people", action: "show", id: 1 }]], + ["/people/1",[ { controller: "people", action: "show", id: Model.new("1") }]], + ["/people/1",[ { action: "show", id: "1" }, { controller: "people", action: "index" }, "/people"]], + ["/people/1",[ { action: "show", id: 1 }, { controller: "people", action: "show", id: "1" }, "/people/show/1"]], + ["/people",[ { controller: "people", action: "index" }, { controller: "people", action: "show", id: "1" }, "/people/show/1"]], + ["/people/1",[ {}, { controller: "people", action: "show", id: "1" }, "/people/show/1"]], + ["/people/1",[ { controller: "people", action: "show" }, { controller: "people", action: "index", id: "1" }, "/people/index/1"]], + ["/people/1/edit",[ { controller: "people", action: "edit", id: "1" }]], + ["/people/1/edit.xml",[ { controller: "people", action: "edit", id: "1", format: "xml" }]], + ["/people/1/edit",[ { use_route: "edit_person", id: "1" }]], + ["/people/1?legacy=true",[ { controller: "people", action: "show", id: "1", legacy: "true" }]], + ["/people?legacy=true",[ { controller: "people", action: "index", legacy: "true" }]], + + ["/id_default/2",[ { controller: "foo", action: "id_default", id: "2" }]], + ["/id_default",[ { controller: "foo", action: "id_default", id: "1" }]], + ["/id_default",[ { controller: "foo", action: "id_default", id: 1 }]], + ["/id_default",[ { controller: "foo", action: "id_default" }]], + ["/optional/bar",[ { controller: "posts", action: "index", optional: "bar" }]], + ["/posts",[ { controller: "posts", action: "index" }]], + + ["/project",[ { controller: "project", action: "index" }]], + ["/projects/1",[ { controller: "project", action: "index", project_id: "1" }]], + ["/projects/1",[ { controller: "project", action: "index" }, { project_id: "1", controller: "project", action: "index" }, "/projects/1"]], + ["/projects/1",[ { use_route: "project", controller: "project", action: "index", project_id: "1" }]], + ["/projects/1",[ { use_route: "project", controller: "project", action: "index" }, { controller: "project", action: "index", project_id: "1" }, "/projects/1"]], + + ["/clients",[ { controller: "projects", action: "index" }]], + ["/clients?project_id=1",[ { controller: "projects", action: "index", project_id: "1" }]], + ["/clients",[ { controller: "projects", action: "index" }, { project_id: "1", controller: "project", action: "index" }, "/projects/1"]], + + ["/comment/20",[ { id: 20 }, { controller: "comments", action: "show" }, "/comments/show"]], + ["/comment/20",[ { controller: "comments", id: 20, action: "show" }]], + ["/comments/boo",[ { controller: "comments", action: "boo" }]], + + ["/ws/posts/show/1",[ { controller: "posts", action: "show", id: "1", ws: true }]], + ["/ws/posts",[ { controller: "posts", action: "index", ws: true }]], + + ["/account",[ { controller: "account", action: "subscription" }]], + ["/account/billing",[ { controller: "account", action: "billing" }]], + + ["/pages/1/notes/show/1",[ { page_id: "1", controller: "notes", action: "show", id: "1" }]], + ["/pages/1/notes/list",[ { page_id: "1", controller: "notes", action: "list" }]], + ["/pages/1/notes",[ { page_id: "1", controller: "notes", action: "index" }]], + ["/pages/1/notes",[ { page_id: "1", controller: "notes" }]], + ["/notes",[ { page_id: nil, controller: "notes" }]], + ["/notes",[ { controller: "notes" }]], + ["/notes/print",[ { controller: "notes", action: "print" }]], + ["/notes/print",[ {}, { controller: "notes", action: "print" }, "/notes/print"]], + + ["/notes/index/1",[ { controller: "notes" }, { controller: "notes", action: "index", id: "1" }, "/notes/index/1"]], + ["/notes/index/1",[ { controller: "notes" }, { controller: "notes", id: "1", action: "index" }, "/notes/index/1"]], + ["/notes/index/1",[ { action: "index" }, { controller: "notes", id: "1", action: "index" }, "/notes/index/1"]], + ["/notes/index/1",[ {}, { controller: "notes", id: "1", action: "index" }, "/notes/index/1"]], + ["/notes/show/1",[ {}, { controller: "notes", action: "show", id: "1" }, "/notes/show/1"]], + ["/posts",[ { controller: "posts" }, { controller: "notes", action: "show", id: "1" }, "/notes/show/1"]], + ["/notes/list",[ { action: "list" }, { controller: "notes", action: "show", id: "1" }, "/notes/show/1"]], + + ["/posts/ping",[ { controller: "posts", action: "ping" }]], + ["/posts/show/1",[ { controller: "posts", action: "show", id: "1" }]], + ["/posts/show/1",[ { controller: "posts", action: "show", id: "1", format: "" }]], + ["/posts",[ { controller: "posts" }]], + ["/posts",[ { controller: "posts", action: "index" }]], + ["/posts/create",[ { action: "create" }, { day: nil, month: nil, controller: "posts", action: "show_date" }, "/blog"]], + ["/posts?foo=bar",[ { controller: "posts", foo: "bar" }]], + ["/posts?foo%5B%5D=bar&foo%5B%5D=baz", [{ controller: "posts", foo: ["bar", "baz"] }]], + ["/posts?page=2", [{ controller: "posts", page: 2 }]], + ["/posts?q%5Bfoo%5D%5Ba%5D=b", [{ controller: "posts", q: { foo: { a: "b" } } }]], + + ["/news.rss", [{ controller: "news", action: "index", format: "rss" }]], ].each_with_index do |(url, params), i| if params.length > 1 hash, path_params, route = *params hash[:only_path] = true define_method("test_#{url.gsub(/\W/, '_')}_#{i}") do - get URI('http://test.host' + route.to_s) + get URI("http://test.host" + route.to_s) assert_equal path_params, controller.request.path_parameters assert_equal url, controller.url_for(hash), params.inspect end diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index b4d2088c0a..8d7190365d 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module AbstractController module Testing @@ -7,7 +7,7 @@ module AbstractController include ActionDispatch::Routing::RouteSet.new.tap { |r| r.draw { ActiveSupport::Deprecation.silence { - get ':controller(/:action(/:id(.:format)))' + get ":controller(/:action(/:id(.:format)))" } } }.url_helpers @@ -21,23 +21,23 @@ module AbstractController klass = Class.new { include ActionDispatch::Routing::RouteSet.new.tap { |r| r.draw { - get "/foo/(:bar/(:baz))/:zot", :as => 'fun', - :controller => :articles, - :action => :index + get "/foo/(:bar/(:baz))/:zot", as: "fun", + controller: :articles, + action: :index } }.url_helpers - self.default_url_options[:host] = 'example.com' + self.default_url_options[:host] = "example.com" } - path = klass.new.fun_path({:controller => :articles, - :baz => "baz", - :zot => "zot"}) + path = klass.new.fun_path(controller: :articles, + baz: "baz", + zot: "zot") # :bar key isn't provided - assert_equal '/foo/zot', path + assert_equal "/foo/zot", path end def add_host!(app = W) - app.default_url_options[:host] = 'www.basecamphq.com' + app.default_url_options[:host] = "www.basecamphq.com" end def add_port! @@ -45,166 +45,166 @@ module AbstractController end def add_numeric_host! - W.default_url_options[:host] = '127.0.0.1' + W.default_url_options[:host] = "127.0.0.1" end def test_exception_is_thrown_without_host assert_raise ArgumentError do - W.new.url_for :controller => 'c', :action => 'a', :id => 'i' + W.new.url_for controller: "c", action: "a", id: "i" end end def test_anchor - assert_equal('/c/a#anchor', - W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => 'anchor') + assert_equal("/c/a#anchor", + W.new.url_for(only_path: true, controller: "c", action: "a", anchor: "anchor") ) end def test_nil_anchor assert_equal( - '/c/a', - W.new.url_for(only_path: true, controller: 'c', action: 'a', anchor: nil) + "/c/a", + W.new.url_for(only_path: true, controller: "c", action: "a", anchor: nil) ) end def test_false_anchor assert_equal( - '/c/a', - W.new.url_for(only_path: true, controller: 'c', action: 'a', anchor: false) + "/c/a", + W.new.url_for(only_path: true, controller: "c", action: "a", anchor: false) ) end def test_anchor_should_call_to_param - assert_equal('/c/a#anchor', - W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('anchor')) + assert_equal("/c/a#anchor", + W.new.url_for(only_path: true, controller: "c", action: "a", anchor: Struct.new(:to_param).new("anchor")) ) end def test_anchor_should_escape_unsafe_pchar - assert_equal('/c/a#%23anchor', - W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('#anchor')) + assert_equal("/c/a#%23anchor", + W.new.url_for(only_path: true, controller: "c", action: "a", anchor: Struct.new(:to_param).new("#anchor")) ) end def test_anchor_should_not_escape_safe_pchar - assert_equal('/c/a#name=user&email=user@domain.com', - W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('name=user&email=user@domain.com')) + assert_equal("/c/a#name=user&email=user@domain.com", + W.new.url_for(only_path: true, controller: "c", action: "a", anchor: Struct.new(:to_param).new("name=user&email=user@domain.com")) ) end def test_default_host add_host! - assert_equal('http://www.basecamphq.com/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://www.basecamphq.com/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i") ) end def test_host_may_be_overridden add_host! - assert_equal('http://37signals.basecamphq.com/c/a/i', - W.new.url_for(:host => '37signals.basecamphq.com', :controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://37signals.basecamphq.com/c/a/i", + W.new.url_for(host: "37signals.basecamphq.com", controller: "c", action: "a", id: "i") ) end def test_subdomain_may_be_changed add_host! - assert_equal('http://api.basecamphq.com/c/a/i', - W.new.url_for(:subdomain => 'api', :controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://api.basecamphq.com/c/a/i", + W.new.url_for(subdomain: "api", controller: "c", action: "a", id: "i") ) end def test_subdomain_may_be_object - model = Class.new { def self.to_param; 'api'; end } + model = Class.new { def self.to_param; "api"; end } add_host! - assert_equal('http://api.basecamphq.com/c/a/i', - W.new.url_for(:subdomain => model, :controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://api.basecamphq.com/c/a/i", + W.new.url_for(subdomain: model, controller: "c", action: "a", id: "i") ) end def test_subdomain_may_be_removed add_host! - assert_equal('http://basecamphq.com/c/a/i', - W.new.url_for(:subdomain => false, :controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://basecamphq.com/c/a/i", + W.new.url_for(subdomain: false, controller: "c", action: "a", id: "i") ) end def test_subdomain_may_be_removed_with_blank_string - W.default_url_options[:host] = 'api.basecamphq.com' - assert_equal('http://basecamphq.com/c/a/i', - W.new.url_for(:subdomain => '', :controller => 'c', :action => 'a', :id => 'i') + W.default_url_options[:host] = "api.basecamphq.com" + assert_equal("http://basecamphq.com/c/a/i", + W.new.url_for(subdomain: "", controller: "c", action: "a", id: "i") ) end def test_multiple_subdomains_may_be_removed - W.default_url_options[:host] = 'mobile.www.api.basecamphq.com' - assert_equal('http://basecamphq.com/c/a/i', - W.new.url_for(:subdomain => false, :controller => 'c', :action => 'a', :id => 'i') + W.default_url_options[:host] = "mobile.www.api.basecamphq.com" + assert_equal("http://basecamphq.com/c/a/i", + W.new.url_for(subdomain: false, controller: "c", action: "a", id: "i") ) end def test_subdomain_may_be_accepted_with_numeric_host add_numeric_host! - assert_equal('http://127.0.0.1/c/a/i', - W.new.url_for(:subdomain => 'api', :controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://127.0.0.1/c/a/i", + W.new.url_for(subdomain: "api", controller: "c", action: "a", id: "i") ) end def test_domain_may_be_changed add_host! - assert_equal('http://www.37signals.com/c/a/i', - W.new.url_for(:domain => '37signals.com', :controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://www.37signals.com/c/a/i", + W.new.url_for(domain: "37signals.com", controller: "c", action: "a", id: "i") ) end def test_tld_length_may_be_changed add_host! - assert_equal('http://mobile.www.basecamphq.com/c/a/i', - W.new.url_for(:subdomain => 'mobile', :tld_length => 2, :controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://mobile.www.basecamphq.com/c/a/i", + W.new.url_for(subdomain: "mobile", tld_length: 2, controller: "c", action: "a", id: "i") ) end def test_port add_host! - assert_equal('http://www.basecamphq.com:3000/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :port => 3000) + assert_equal("http://www.basecamphq.com:3000/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", port: 3000) ) end def test_default_port add_host! add_port! - assert_equal('http://www.basecamphq.com:3000/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i') + assert_equal("http://www.basecamphq.com:3000/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i") ) end def test_protocol add_host! - assert_equal('https://www.basecamphq.com/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https') + assert_equal("https://www.basecamphq.com/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "https") ) end def test_protocol_with_and_without_separators add_host! - assert_equal('https://www.basecamphq.com/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https') + assert_equal("https://www.basecamphq.com/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "https") ) - assert_equal('https://www.basecamphq.com/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https:') + assert_equal("https://www.basecamphq.com/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "https:") ) - assert_equal('https://www.basecamphq.com/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https://') + assert_equal("https://www.basecamphq.com/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "https://") ) end def test_without_protocol add_host! - assert_equal('//www.basecamphq.com/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => '//') + assert_equal("//www.basecamphq.com/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "//") ) - assert_equal('//www.basecamphq.com/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => false) + assert_equal("//www.basecamphq.com/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: false) ) end @@ -212,74 +212,74 @@ module AbstractController add_host! add_port! - assert_equal('//www.basecamphq.com:3000/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => '//') + assert_equal("//www.basecamphq.com:3000/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "//") ) - assert_equal('//www.basecamphq.com:3000/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => false) + assert_equal("//www.basecamphq.com:3000/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: false) ) end def test_trailing_slash add_host! - options = {:controller => 'foo', :trailing_slash => true, :action => 'bar', :id => '33'} - assert_equal('http://www.basecamphq.com/foo/bar/33/', W.new.url_for(options) ) + options = { controller: "foo", trailing_slash: true, action: "bar", id: "33" } + assert_equal("http://www.basecamphq.com/foo/bar/33/", W.new.url_for(options) ) end def test_trailing_slash_with_protocol add_host! - options = { :trailing_slash => true,:protocol => 'https', :controller => 'foo', :action => 'bar', :id => '33'} - assert_equal('https://www.basecamphq.com/foo/bar/33/', W.new.url_for(options) ) - assert_equal 'https://www.basecamphq.com/foo/bar/33/?query=string', W.new.url_for(options.merge({:query => 'string'})) + options = { trailing_slash: true,protocol: "https", controller: "foo", action: "bar", id: "33" } + assert_equal("https://www.basecamphq.com/foo/bar/33/", W.new.url_for(options) ) + assert_equal "https://www.basecamphq.com/foo/bar/33/?query=string", W.new.url_for(options.merge(query: "string")) end def test_trailing_slash_with_only_path - options = {:controller => 'foo', :trailing_slash => true} - assert_equal '/foo/', W.new.url_for(options.merge({:only_path => true})) - options.update({:action => 'bar', :id => '33'}) - assert_equal '/foo/bar/33/', W.new.url_for(options.merge({:only_path => true})) - assert_equal '/foo/bar/33/?query=string', W.new.url_for(options.merge({:query => 'string',:only_path => true})) + options = { controller: "foo", trailing_slash: true } + assert_equal "/foo/", W.new.url_for(options.merge(only_path: true)) + options.update(action: "bar", id: "33") + assert_equal "/foo/bar/33/", W.new.url_for(options.merge(only_path: true)) + assert_equal "/foo/bar/33/?query=string", W.new.url_for(options.merge(query: "string",only_path: true)) end def test_trailing_slash_with_anchor - options = {:trailing_slash => true, :controller => 'foo', :action => 'bar', :id => '33', :only_path => true, :anchor=> 'chapter7'} - assert_equal '/foo/bar/33/#chapter7', W.new.url_for(options) - assert_equal '/foo/bar/33/?query=string#chapter7', W.new.url_for(options.merge({:query => 'string'})) + options = { trailing_slash: true, controller: "foo", action: "bar", id: "33", only_path: true, anchor: "chapter7" } + assert_equal "/foo/bar/33/#chapter7", W.new.url_for(options) + assert_equal "/foo/bar/33/?query=string#chapter7", W.new.url_for(options.merge(query: "string")) end def test_trailing_slash_with_params - url = W.new.url_for(:trailing_slash => true, :only_path => true, :controller => 'cont', :action => 'act', :p1 => 'cafe', :p2 => 'link') + url = W.new.url_for(trailing_slash: true, only_path: true, controller: "cont", action: "act", p1: "cafe", p2: "link") params = extract_params(url) - assert_equal({p1: 'cafe'}.to_query, params[0]) - assert_equal({p2: 'link'}.to_query, params[1]) + assert_equal({ p1: "cafe" }.to_query, params[0]) + assert_equal({ p2: "link" }.to_query, params[1]) end def test_relative_url_root_is_respected add_host! - assert_equal('https://www.basecamphq.com/subdir/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https', :script_name => '/subdir') + assert_equal("https://www.basecamphq.com/subdir/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "https", script_name: "/subdir") ) end def test_relative_url_root_is_respected_with_environment_variable # `config.relative_url_root` is set by ENV['RAILS_RELATIVE_URL_ROOT'] w = Class.new { - config = ActionDispatch::Routing::RouteSet::Config.new '/subdir' + config = ActionDispatch::Routing::RouteSet::Config.new "/subdir" r = ActionDispatch::Routing::RouteSet.new(config) - r.draw { ActiveSupport::Deprecation.silence { get ':controller(/:action(/:id(.:format)))' } } + r.draw { ActiveSupport::Deprecation.silence { get ":controller(/:action(/:id(.:format)))" } } include r.url_helpers } add_host!(w) - assert_equal('https://www.basecamphq.com/subdir/c/a/i', - w.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https') + assert_equal("https://www.basecamphq.com/subdir/c/a/i", + w.new.url_for(controller: "c", action: "a", id: "i", protocol: "https") ) end def test_named_routes with_routing do |set| set.draw do - get 'this/is/verbose', :to => 'home#index', :as => :no_args - get 'home/sweet/home/:user', :to => 'home#index', :as => :home + get "this/is/verbose", to: "home#index", as: :no_args + get "home/sweet/home/:user", to: "home#index", as: :home end # We need to create a new class in order to install the new named route. @@ -287,43 +287,43 @@ module AbstractController controller = kls.new assert controller.respond_to?(:home_url) - assert_equal 'http://www.basecamphq.com/home/sweet/home/again', - controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again') + assert_equal "http://www.basecamphq.com/home/sweet/home/again", + controller.send(:home_url, host: "www.basecamphq.com", user: "again") - assert_equal("/home/sweet/home/alabama", controller.send(:home_path, :user => 'alabama', :host => 'unused')) - assert_equal("http://www.basecamphq.com/home/sweet/home/alabama", controller.send(:home_url, :user => 'alabama', :host => 'www.basecamphq.com')) - assert_equal("http://www.basecamphq.com/this/is/verbose", controller.send(:no_args_url, :host=>'www.basecamphq.com')) + assert_equal("/home/sweet/home/alabama", controller.send(:home_path, user: "alabama", host: "unused")) + assert_equal("http://www.basecamphq.com/home/sweet/home/alabama", controller.send(:home_url, user: "alabama", host: "www.basecamphq.com")) + assert_equal("http://www.basecamphq.com/this/is/verbose", controller.send(:no_args_url, host: "www.basecamphq.com")) end end def test_relative_url_root_is_respected_for_named_routes with_routing do |set| set.draw do - get '/home/sweet/home/:user', :to => 'home#index', :as => :home + get "/home/sweet/home/:user", to: "home#index", as: :home end kls = Class.new { include set.url_helpers } controller = kls.new - assert_equal 'http://www.basecamphq.com/subdir/home/sweet/home/again', - controller.send(:home_url, :host => 'www.basecamphq.com', :user => 'again', :script_name => "/subdir") + assert_equal "http://www.basecamphq.com/subdir/home/sweet/home/again", + controller.send(:home_url, host: "www.basecamphq.com", user: "again", script_name: "/subdir") end end def test_using_nil_script_name_properly_concats_with_original_script_name add_host! - assert_equal('https://www.basecamphq.com/subdir/c/a/i', - W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https', :script_name => nil, :original_script_name => '/subdir') + assert_equal("https://www.basecamphq.com/subdir/c/a/i", + W.new.url_for(controller: "c", action: "a", id: "i", protocol: "https", script_name: nil, original_script_name: "/subdir") ) end def test_only_path with_routing do |set| set.draw do - get 'home/sweet/home/:user', :to => 'home#index', :as => :home + get "home/sweet/home/:user", to: "home#index", as: :home ActiveSupport::Deprecation.silence do - get ':controller/:action/:id' + get ":controller/:action/:id" end end @@ -331,83 +331,83 @@ module AbstractController kls = Class.new { include set.url_helpers } controller = kls.new assert_respond_to controller, :home_url - assert_equal '/brave/new/world', - controller.url_for(:controller => 'brave', :action => 'new', :id => 'world', :only_path => true) + assert_equal "/brave/new/world", + controller.url_for(controller: "brave", action: "new", id: "world", only_path: true) - assert_equal("/home/sweet/home/alabama", controller.home_path(:user => 'alabama', :host => 'unused')) - assert_equal("/home/sweet/home/alabama", controller.home_path('alabama')) + assert_equal("/home/sweet/home/alabama", controller.home_path(user: "alabama", host: "unused")) + assert_equal("/home/sweet/home/alabama", controller.home_path("alabama")) end end def test_one_parameter - assert_equal('/c/a?param=val', - W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :param => 'val') + assert_equal("/c/a?param=val", + W.new.url_for(only_path: true, controller: "c", action: "a", param: "val") ) end def test_two_parameters - url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :p1 => 'X1', :p2 => 'Y2') + url = W.new.url_for(only_path: true, controller: "c", action: "a", p1: "X1", p2: "Y2") params = extract_params(url) - assert_equal({p1: 'X1'}.to_query, params[0]) - assert_equal({p2: 'Y2'}.to_query, params[1]) + assert_equal({ p1: "X1" }.to_query, params[0]) + assert_equal({ p2: "Y2" }.to_query, params[1]) end def test_hash_parameter - url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:name => 'Bob', :category => 'prof'}) + url = W.new.url_for(only_path: true, controller: "c", action: "a", query: { name: "Bob", category: "prof" }) params = extract_params(url) - assert_equal({'query[category]' => 'prof'}.to_query, params[0]) - assert_equal({'query[name]' => 'Bob'}.to_query, params[1]) + assert_equal({ "query[category]" => "prof" }.to_query, params[0]) + assert_equal({ "query[name]" => "Bob" }.to_query, params[1]) end def test_array_parameter - url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => ['Bob', 'prof']) + url = W.new.url_for(only_path: true, controller: "c", action: "a", query: ["Bob", "prof"]) params = extract_params(url) - assert_equal({'query[]' => 'Bob'}.to_query, params[0]) - assert_equal({'query[]' => 'prof'}.to_query, params[1]) + assert_equal({ "query[]" => "Bob" }.to_query, params[0]) + assert_equal({ "query[]" => "prof" }.to_query, params[1]) end def test_hash_recursive_parameters - url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:person => {:name => 'Bob', :position => 'prof'}, :hobby => 'piercing'}) + url = W.new.url_for(only_path: true, controller: "c", action: "a", query: { person: { name: "Bob", position: "prof" }, hobby: "piercing" }) params = extract_params(url) - assert_equal({'query[hobby]' => 'piercing'}.to_query, params[0]) - assert_equal({'query[person][name]' => 'Bob' }.to_query, params[1]) - assert_equal({'query[person][position]' => 'prof' }.to_query, params[2]) + assert_equal({ "query[hobby]" => "piercing" }.to_query, params[0]) + assert_equal({ "query[person][name]" => "Bob" }.to_query, params[1]) + assert_equal({ "query[person][position]" => "prof" }.to_query, params[2]) end def test_hash_recursive_and_array_parameters - url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :id => 101, :query => {:person => {:name => 'Bob', :position => ['prof', 'art director']}, :hobby => 'piercing'}) + url = W.new.url_for(only_path: true, controller: "c", action: "a", id: 101, query: { person: { name: "Bob", position: ["prof", "art director"] }, hobby: "piercing" }) assert_match(%r(^/c/a/101), url) params = extract_params(url) - assert_equal({'query[hobby]' => 'piercing' }.to_query, params[0]) - assert_equal({'query[person][name]' => 'Bob' }.to_query, params[1]) - assert_equal({'query[person][position][]' => 'art director'}.to_query, params[2]) - assert_equal({'query[person][position][]' => 'prof' }.to_query, params[3]) + assert_equal({ "query[hobby]" => "piercing" }.to_query, params[0]) + assert_equal({ "query[person][name]" => "Bob" }.to_query, params[1]) + assert_equal({ "query[person][position][]" => "art director" }.to_query, params[2]) + assert_equal({ "query[person][position][]" => "prof" }.to_query, params[3]) end def test_url_action_controller_parameters add_host! assert_raise(ArgumentError) do - W.new.url_for(ActionController::Parameters.new(:controller => 'c', :action => 'a', protocol: 'javascript', f: '%0Aeval(name)')) + W.new.url_for(ActionController::Parameters.new(controller: "c", action: "a", protocol: "javascript", f: "%0Aeval(name)")) end end def test_path_generation_for_symbol_parameter_keys - assert_generates("/image", :controller=> :image) + assert_generates("/image", controller: :image) end def test_named_routes_with_nil_keys with_routing do |set| set.draw do - get 'posts.:format', :to => 'posts#index', :as => :posts - get '/', :to => 'posts#index', :as => :main + get "posts.:format", to: "posts#index", as: :posts + get "/", to: "posts#index", as: :main end # We need to create a new class in order to install the new named route. kls = Class.new { include set.url_helpers } - kls.default_url_options[:host] = 'www.basecamphq.com' + kls.default_url_options[:host] = "www.basecamphq.com" controller = kls.new - params = {:action => :index, :controller => :posts, :format => :xml} + params = { action: :index, controller: :posts, format: :xml } assert_equal("http://www.basecamphq.com/posts.xml", controller.send(:url_for, params)) params[:format] = nil assert_equal("http://www.basecamphq.com/", controller.send(:url_for, params)) @@ -418,7 +418,7 @@ module AbstractController first_class = Class.new { include ActionController::UrlFor } second_class = Class.new { include ActionController::UrlFor } - first_host, second_host = 'firsthost.com', 'secondhost.com' + first_host, second_host = "firsthost.com", "secondhost.com" first_class.default_url_options[:host] = first_host second_class.default_url_options[:host] = second_host @@ -428,25 +428,25 @@ module AbstractController end def test_with_stringified_keys - assert_equal("/c", W.new.url_for('controller' => 'c', 'only_path' => true)) - assert_equal("/c/a", W.new.url_for('controller' => 'c', 'action' => 'a', 'only_path' => true)) + assert_equal("/c", W.new.url_for("controller" => "c", "only_path" => true)) + assert_equal("/c/a", W.new.url_for("controller" => "c", "action" => "a", "only_path" => true)) end def test_with_hash_with_indifferent_access - W.default_url_options[:controller] = 'd' + W.default_url_options[:controller] = "d" W.default_url_options[:only_path] = false - assert_equal("/c", W.new.url_for(ActiveSupport::HashWithIndifferentAccess.new('controller' => 'c', 'only_path' => true))) + assert_equal("/c", W.new.url_for(ActiveSupport::HashWithIndifferentAccess.new("controller" => "c", "only_path" => true))) - W.default_url_options[:action] = 'b' - assert_equal("/c/a", W.new.url_for(ActiveSupport::HashWithIndifferentAccess.new('controller' => 'c', 'action' => 'a', 'only_path' => true))) + W.default_url_options[:action] = "b" + assert_equal("/c/a", W.new.url_for(ActiveSupport::HashWithIndifferentAccess.new("controller" => "c", "action" => "a", "only_path" => true))) end def test_url_params_with_nil_to_param_are_not_in_url - assert_equal("/c/a", W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :id => Struct.new(:to_param).new(nil))) + assert_equal("/c/a", W.new.url_for(only_path: true, controller: "c", action: "a", id: Struct.new(:to_param).new(nil))) end def test_false_url_params_are_included_in_query - assert_equal("/c/a?show=false", W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :show => false)) + assert_equal("/c/a?show=false", W.new.url_for(only_path: true, controller: "c", action: "a", show: false)) end def test_url_generation_with_array_and_hash @@ -458,11 +458,11 @@ module AbstractController end kls = Class.new { include set.url_helpers } - kls.default_url_options[:host] = 'www.basecamphq.com' + kls.default_url_options[:host] = "www.basecamphq.com" controller = kls.new assert_equal("http://www.basecamphq.com/admin/posts/new?param=value", - controller.send(:url_for, [:new, :admin, :post, { param: 'value' }]) + controller.send(:url_for, [:new, :admin, :post, { param: "value" }]) ) end end @@ -476,9 +476,9 @@ module AbstractController end kls = Class.new { include set.url_helpers } - kls.default_url_options[:host] = 'www.basecamphq.com' + kls.default_url_options[:host] = "www.basecamphq.com" - original_components = [:new, :admin, :post, { param: 'value' }] + original_components = [:new, :admin, :post, { param: "value" }] components = original_components.dup kls.new.url_for(components) @@ -489,7 +489,7 @@ module AbstractController private def extract_params(url) - url.split('?', 2).last.split('&').sort + url.split("?", 2).last.split("&").sort end end end diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb index bc0d215530..a055e6d177 100644 --- a/actionpack/test/controller/url_rewriter_test.rb +++ b/actionpack/test/controller/url_rewriter_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' -require 'controller/fake_controllers' +require "abstract_unit" +require "controller/fake_controllers" class UrlRewriterTests < ActionController::TestCase class Rewriter def initialize(request) @options = { - :host => request.host_with_port, - :protocol => request.protocol + host: request.host_with_port, + protocol: request.protocol } end @@ -21,71 +21,70 @@ class UrlRewriterTests < ActionController::TestCase @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| r.draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))' + get ":controller(/:action(/:id))" end end end end def test_port - assert_equal('http://test.host:1271/c/a/i', - @rewriter.rewrite(@routes, :controller => 'c', :action => 'a', :id => 'i', :port => 1271) + assert_equal("http://test.host:1271/c/a/i", + @rewriter.rewrite(@routes, controller: "c", action: "a", id: "i", port: 1271) ) end def test_protocol_with_and_without_separator - assert_equal('https://test.host/c/a/i', - @rewriter.rewrite(@routes, :protocol => 'https', :controller => 'c', :action => 'a', :id => 'i') + assert_equal("https://test.host/c/a/i", + @rewriter.rewrite(@routes, protocol: "https", controller: "c", action: "a", id: "i") ) - assert_equal('https://test.host/c/a/i', - @rewriter.rewrite(@routes, :protocol => 'https://', :controller => 'c', :action => 'a', :id => 'i') + assert_equal("https://test.host/c/a/i", + @rewriter.rewrite(@routes, protocol: "https://", controller: "c", action: "a", id: "i") ) end def test_user_name_and_password assert_equal( - 'http://david:secret@test.host/c/a/i', - @rewriter.rewrite(@routes, :user => "david", :password => "secret", :controller => 'c', :action => 'a', :id => 'i') + "http://david:secret@test.host/c/a/i", + @rewriter.rewrite(@routes, user: "david", password: "secret", controller: "c", action: "a", id: "i") ) end def test_user_name_and_password_with_escape_codes assert_equal( - 'http://openid.aol.com%2Fnextangler:one+two%3F@test.host/c/a/i', - @rewriter.rewrite(@routes, :user => "openid.aol.com/nextangler", :password => "one two?", :controller => 'c', :action => 'a', :id => 'i') + "http://openid.aol.com%2Fnextangler:one+two%3F@test.host/c/a/i", + @rewriter.rewrite(@routes, user: "openid.aol.com/nextangler", password: "one two?", controller: "c", action: "a", id: "i") ) end def test_anchor assert_equal( - 'http://test.host/c/a/i#anchor', - @rewriter.rewrite(@routes, :controller => 'c', :action => 'a', :id => 'i', :anchor => 'anchor') + "http://test.host/c/a/i#anchor", + @rewriter.rewrite(@routes, controller: "c", action: "a", id: "i", anchor: "anchor") ) end def test_anchor_should_call_to_param assert_equal( - 'http://test.host/c/a/i#anchor', - @rewriter.rewrite(@routes, :controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anchor')) + "http://test.host/c/a/i#anchor", + @rewriter.rewrite(@routes, controller: "c", action: "a", id: "i", anchor: Struct.new(:to_param).new("anchor")) ) end def test_anchor_should_be_uri_escaped assert_equal( - 'http://test.host/c/a/i#anc/hor', - @rewriter.rewrite(@routes, :controller => 'c', :action => 'a', :id => 'i', :anchor => Struct.new(:to_param).new('anc/hor')) + "http://test.host/c/a/i#anc/hor", + @rewriter.rewrite(@routes, controller: "c", action: "a", id: "i", anchor: Struct.new(:to_param).new("anc/hor")) ) end def test_trailing_slash - options = {:controller => 'foo', :action => 'bar', :id => '3', :only_path => true} - assert_equal '/foo/bar/3', @rewriter.rewrite(@routes, options) - assert_equal '/foo/bar/3?query=string', @rewriter.rewrite(@routes, options.merge({:query => 'string'})) - options.update({:trailing_slash => true}) - assert_equal '/foo/bar/3/', @rewriter.rewrite(@routes, options) - options.update({:query => 'string'}) - assert_equal '/foo/bar/3/?query=string', @rewriter.rewrite(@routes, options) + options = { controller: "foo", action: "bar", id: "3", only_path: true } + assert_equal "/foo/bar/3", @rewriter.rewrite(@routes, options) + assert_equal "/foo/bar/3?query=string", @rewriter.rewrite(@routes, options.merge(query: "string")) + options.update(trailing_slash: true) + assert_equal "/foo/bar/3/", @rewriter.rewrite(@routes, options) + options.update(query: "string") + assert_equal "/foo/bar/3/?query=string", @rewriter.rewrite(@routes, options) end end - diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index daf17558aa..6f97a4b62e 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/json/decoding' +require "abstract_unit" +require "active_support/json/decoding" class WebServiceTest < ActionDispatch::IntegrationTest class TestController < ActionController::Base @@ -7,7 +7,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest if params[:full] render plain: dump_params_keys else - render plain: (params.keys - ['controller', 'action']).sort.join(", ") + render plain: (params.keys - ["controller", "action"]).sort.join(", ") end end @@ -35,7 +35,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest def test_check_parameters with_test_route_set do get "/" - assert_equal '', @controller.response.body + assert_equal "", @controller.response.body end end @@ -43,11 +43,11 @@ class WebServiceTest < ActionDispatch::IntegrationTest with_test_route_set do post "/", params: '{"entry":{"summary":"content..."}}', - headers: { 'CONTENT_TYPE' => 'application/json' } + headers: { "CONTENT_TYPE" => "application/json" } - assert_equal 'entry', @controller.response.body + assert_equal "entry", @controller.response.body assert @controller.params.has_key?(:entry) - assert_equal 'content...', @controller.params["entry"]['summary'] + assert_equal "content...", @controller.params["entry"]["summary"] end end @@ -55,34 +55,34 @@ class WebServiceTest < ActionDispatch::IntegrationTest with_test_route_set do put "/", params: '{"entry":{"summary":"content..."}}', - headers: { 'CONTENT_TYPE' => 'application/json' } + headers: { "CONTENT_TYPE" => "application/json" } - assert_equal 'entry', @controller.response.body + assert_equal "entry", @controller.response.body assert @controller.params.has_key?(:entry) - assert_equal 'content...', @controller.params["entry"]['summary'] + assert_equal "content...", @controller.params["entry"]["summary"] end end def test_register_and_use_json_simple with_test_route_set do - with_params_parsers Mime[:json] => Proc.new { |data| ActiveSupport::JSON.decode(data)['request'].with_indifferent_access } do + with_params_parsers Mime[:json] => Proc.new { |data| ActiveSupport::JSON.decode(data)["request"].with_indifferent_access } do post "/", params: '{"request":{"summary":"content...","title":"JSON"}}', - headers: { 'CONTENT_TYPE' => 'application/json' } + headers: { "CONTENT_TYPE" => "application/json" } - assert_equal 'summary, title', @controller.response.body + assert_equal "summary, title", @controller.response.body assert @controller.params.has_key?(:summary) assert @controller.params.has_key?(:title) - assert_equal 'content...', @controller.params["summary"] - assert_equal 'JSON', @controller.params["title"] + assert_equal "content...", @controller.params["summary"] + assert_equal "JSON", @controller.params["title"] end end end def test_use_json_with_empty_request with_test_route_set do - assert_nothing_raised { post "/", headers: { 'CONTENT_TYPE' => 'application/json' } } - assert_equal '', @controller.response.body + assert_nothing_raised { post "/", headers: { "CONTENT_TYPE" => "application/json" } } + assert_equal "", @controller.response.body end end @@ -90,9 +90,9 @@ class WebServiceTest < ActionDispatch::IntegrationTest with_test_route_set do post "/?full=1", params: '{"first-key":{"sub-key":"..."}}', - headers: { 'CONTENT_TYPE' => 'application/json' } - assert_equal 'action, controller, first-key(sub-key), full', @controller.response.body - assert_equal "...", @controller.params['first-key']['sub-key'] + headers: { "CONTENT_TYPE" => "application/json" } + assert_equal "action, controller, first-key(sub-key), full", @controller.response.body + assert_equal "...", @controller.params["first-key"]["sub-key"] end end @@ -102,8 +102,8 @@ class WebServiceTest < ActionDispatch::IntegrationTest { json: Proc.new { |data| raise Interrupt } } end - def content_length; get_header('rack.input').length; end - end.new({ 'rack.input' => StringIO.new('{"title":"JSON"}}'), 'CONTENT_TYPE' => 'application/json' }) + def content_length; get_header("rack.input").length; end + end.new("rack.input" => StringIO.new('{"title":"JSON"}}'), "CONTENT_TYPE" => "application/json") assert_raises(Interrupt) do req.request_parameters @@ -125,7 +125,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest def with_test_route_set with_routing do |set| set.draw do - match '/', :to => 'web_service_test/test#assign_parameters', :via => :all + match "/", to: "web_service_test/test#assign_parameters", via: :all end yield end diff --git a/actionpack/test/dispatch/callbacks_test.rb b/actionpack/test/dispatch/callbacks_test.rb index 7b707df7f6..57e21a22c6 100644 --- a/actionpack/test/dispatch/callbacks_test.rb +++ b/actionpack/test/dispatch/callbacks_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class DispatcherTest < ActiveSupport::TestCase class Foo @@ -7,7 +7,7 @@ class DispatcherTest < ActiveSupport::TestCase class DummyApp def call(env) - [200, {}, 'response'] + [200, {}, "response"] end end @@ -57,8 +57,7 @@ class DispatcherTest < ActiveSupport::TestCase def dispatch(&block) ActionDispatch::Callbacks.new(block || DummyApp.new).call( - {'rack.input' => StringIO.new('')} + "rack.input" => StringIO.new("") ) end - end diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index c7194cde4a..6dcd62572a 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'openssl' -require 'active_support/key_generator' -require 'active_support/message_verifier' +require "abstract_unit" +require "openssl" +require "active_support/key_generator" +require "active_support/message_verifier" class CookieJarTest < ActiveSupport::TestCase attr_reader :request @@ -12,26 +12,26 @@ class CookieJarTest < ActiveSupport::TestCase def test_fetch x = Object.new - assert_not request.cookie_jar.key?('zzzzzz') - assert_equal x, request.cookie_jar.fetch('zzzzzz', x) - assert_not request.cookie_jar.key?('zzzzzz') + assert_not request.cookie_jar.key?("zzzzzz") + assert_equal x, request.cookie_jar.fetch("zzzzzz", x) + assert_not request.cookie_jar.key?("zzzzzz") end def test_fetch_exists x = Object.new - request.cookie_jar['foo'] = 'bar' - assert_equal 'bar', request.cookie_jar.fetch('foo', x) + request.cookie_jar["foo"] = "bar" + assert_equal "bar", request.cookie_jar.fetch("foo", x) end def test_fetch_block x = Object.new - assert_not request.cookie_jar.key?('zzzzzz') - assert_equal x, request.cookie_jar.fetch('zzzzzz') { x } + assert_not request.cookie_jar.key?("zzzzzz") + assert_equal x, request.cookie_jar.fetch("zzzzzz") { x } end def test_key_is_to_s - request.cookie_jar['foo'] = 'bar' - assert_equal 'bar', request.cookie_jar.fetch(:foo) + request.cookie_jar["foo"] = "bar" + assert_equal "bar", request.cookie_jar.fetch(:foo) end def test_fetch_type_error @@ -41,19 +41,19 @@ class CookieJarTest < ActiveSupport::TestCase end def test_each - request.cookie_jar['foo'] = :bar + request.cookie_jar["foo"] = :bar list = [] request.cookie_jar.each do |k,v| list << [k, v] end - assert_equal [['foo', :bar]], list + assert_equal [["foo", :bar]], list end def test_enumerable - request.cookie_jar['foo'] = :bar + request.cookie_jar["foo"] = :bar actual = request.cookie_jar.map { |k,v| [k.to_s, v.to_s] } - assert_equal [['foo', 'bar']], actual + assert_equal [["foo", "bar"]], actual end def test_key_methods @@ -68,7 +68,7 @@ class CookieJarTest < ActiveSupport::TestCase def test_write_doesnt_set_a_nil_header headers = {} request.cookie_jar.write(headers) - assert !headers.include?('Set-Cookie') + assert_not_includes headers, "Set-Cookie" end end @@ -100,7 +100,7 @@ class CookiesTest < ActionController::TestCase end def authenticate_for_fourteen_days_with_symbols - cookies[:user_name] = { :value => "david", :expires => Time.utc(2005, 10, 10,5) } + cookies[:user_name] = { value: "david", expires: Time.utc(2005, 10, 10,5) } head :ok end @@ -123,17 +123,17 @@ class CookiesTest < ActionController::TestCase alias delete_cookie logout def delete_cookie_with_path - cookies.delete("user_name", :path => '/beaten') + cookies.delete("user_name", path: "/beaten") head :ok end def authenticate_with_http_only - cookies["user_name"] = { :value => "david", :httponly => true } + cookies["user_name"] = { value: "david", httponly: true } head :ok end def authenticate_with_secure - cookies["user_name"] = { :value => "david", :secure => true } + cookies["user_name"] = { value: "david", secure: true } head :ok end @@ -153,7 +153,7 @@ class CookiesTest < ActionController::TestCase end def set_encrypted_cookie - cookies.encrypted[:foo] = 'bar' + cookies.encrypted[:foo] = "bar" head :ok end @@ -173,7 +173,7 @@ class CookiesTest < ActionController::TestCase end def set_wrapped_encrypted_cookie - cookies.encrypted[:foo] = JSONWrapper.new('bar') + cookies.encrypted[:foo] = JSONWrapper.new("bar") head :ok end @@ -183,12 +183,12 @@ class CookiesTest < ActionController::TestCase end def set_invalid_encrypted_cookie - cookies[:invalid_cookie] = 'invalid--9170e00a57cfc27083363b5c75b835e477bd90cf' + cookies[:invalid_cookie] = "invalid--9170e00a57cfc27083363b5c75b835e477bd90cf" head :ok end def raise_data_overflow - cookies.signed[:foo] = 'bye!' * 1024 + cookies.signed[:foo] = "bye!" * 1024 head :ok end @@ -205,47 +205,47 @@ class CookiesTest < ActionController::TestCase def delete_and_set_cookie cookies.delete :user_name - cookies[:user_name] = { :value => "david", :expires => Time.utc(2005, 10, 10,5) } + cookies[:user_name] = { value: "david", expires: Time.utc(2005, 10, 10,5) } head :ok end def set_cookie_with_domain - cookies[:user_name] = {:value => "rizwanreza", :domain => :all} + cookies[:user_name] = { value: "rizwanreza", domain: :all } head :ok end def set_cookie_with_domain_all_as_string - cookies[:user_name] = {:value => "rizwanreza", :domain => 'all'} + cookies[:user_name] = { value: "rizwanreza", domain: "all" } head :ok end def delete_cookie_with_domain - cookies.delete(:user_name, :domain => :all) + cookies.delete(:user_name, domain: :all) head :ok end def delete_cookie_with_domain_all_as_string - cookies.delete(:user_name, :domain => 'all') + cookies.delete(:user_name, domain: "all") head :ok end def set_cookie_with_domain_and_tld - cookies[:user_name] = {:value => "rizwanreza", :domain => :all, :tld_length => 2} + cookies[:user_name] = { value: "rizwanreza", domain: :all, tld_length: 2 } head :ok end def delete_cookie_with_domain_and_tld - cookies.delete(:user_name, :domain => :all, :tld_length => 2) + cookies.delete(:user_name, domain: :all, tld_length: 2) head :ok end def set_cookie_with_domains - cookies[:user_name] = {:value => "rizwanreza", :domain => %w(example1.com example2.com .example3.com)} + cookies[:user_name] = { value: "rizwanreza", domain: %w(example1.com example2.com .example3.com) } head :ok end def delete_cookie_with_domains - cookies.delete(:user_name, :domain => %w(example1.com example2.com .example3.com)) + cookies.delete(:user_name, domain: %w(example1.com example2.com .example3.com)) head :ok end @@ -255,7 +255,7 @@ class CookiesTest < ActionController::TestCase end def string_key - cookies['user_name'] = "dhh" + cookies["user_name"] = "dhh" head :ok end @@ -265,7 +265,7 @@ class CookiesTest < ActionController::TestCase end def string_key_mock - cookies['user_name'] = "david" if cookies['user_name'] == "andrew" + cookies["user_name"] = "david" if cookies["user_name"] == "andrew" head :ok end @@ -276,7 +276,7 @@ class CookiesTest < ActionController::TestCase tests TestController - SALT = 'b3c631c314c0bbca50c1b2843150fe33' + SALT = "b3c631c314c0bbca50c1b2843150fe33" def setup super @@ -293,57 +293,57 @@ class CookiesTest < ActionController::TestCase def test_setting_cookie get :authenticate assert_cookie_header "user_name=david; path=/" - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) end def test_setting_the_same_value_to_cookie - request.cookies[:user_name] = 'david' + request.cookies[:user_name] = "david" get :authenticate assert_predicate response.cookies, :empty? end def test_setting_the_same_value_to_permanent_cookie - request.cookies[:user_name] = 'Jamie' + request.cookies[:user_name] = "Jamie" get :set_permanent_cookie - assert_equal({'user_name' => 'Jamie'}, response.cookies) + assert_equal({ "user_name" => "Jamie" }, response.cookies) end def test_setting_with_escapable_characters get :set_with_with_escapable_characters assert_cookie_header "that+%26+guy=foo+%26+bar+%3D%3E+baz; path=/" - assert_equal({"that & guy" => "foo & bar => baz"}, @response.cookies) + assert_equal({ "that & guy" => "foo & bar => baz" }, @response.cookies) end def test_setting_cookie_for_fourteen_days get :authenticate_for_fourteen_days assert_cookie_header "user_name=david; path=/; expires=Mon, 10 Oct 2005 05:00:00 -0000" - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) end def test_setting_cookie_for_fourteen_days_with_symbols get :authenticate_for_fourteen_days_with_symbols assert_cookie_header "user_name=david; path=/; expires=Mon, 10 Oct 2005 05:00:00 -0000" - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) end def test_setting_cookie_with_http_only get :authenticate_with_http_only assert_cookie_header "user_name=david; path=/; HttpOnly" - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) end def test_setting_cookie_with_secure @request.env["HTTPS"] = "on" get :authenticate_with_secure assert_cookie_header "user_name=david; path=/; secure" - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) end def test_setting_cookie_with_secure_when_always_write_cookie_is_true old_cookie, @request.cookie_jar.always_write_cookie = @request.cookie_jar.always_write_cookie, true get :authenticate_with_secure assert_cookie_header "user_name=david; path=/; secure" - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) ensure @request.cookie_jar.always_write_cookie = old_cookie end @@ -351,14 +351,14 @@ class CookiesTest < ActionController::TestCase def test_not_setting_cookie_with_secure get :authenticate_with_secure assert_not_cookie_header "user_name=david; path=/; secure" - assert_not_equal({"user_name" => "david"}, @response.cookies) + assert_not_equal({ "user_name" => "david" }, @response.cookies) end def test_multiple_cookies get :set_multiple_cookies assert_equal 2, @response.cookies.size assert_cookie_header "user_name=david; path=/; expires=Mon, 10 Oct 2005 05:00:00 -0000\nlogin=XJ-122; path=/" - assert_equal({"login" => "XJ-122", "user_name" => "david"}, @response.cookies) + assert_equal({ "login" => "XJ-122", "user_name" => "david" }, @response.cookies) end def test_setting_test_cookie @@ -366,14 +366,14 @@ class CookiesTest < ActionController::TestCase end def test_expiring_cookie - request.cookies[:user_name] = 'Joe' + request.cookies[:user_name] = "Joe" get :logout assert_cookie_header "user_name=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000" - assert_equal({"user_name" => nil}, @response.cookies) + assert_equal({ "user_name" => nil }, @response.cookies) end def test_delete_cookie_with_path - request.cookies[:user_name] = 'Joe' + request.cookies[:user_name] = "Joe" get :delete_cookie_with_path assert_cookie_header "user_name=; path=/beaten; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000" end @@ -385,16 +385,16 @@ class CookiesTest < ActionController::TestCase end def test_deleted_cookie_predicate - cookies[:user_name] = 'Joe' + cookies[:user_name] = "Joe" cookies.delete("user_name") assert cookies.deleted?("user_name") assert_equal false, cookies.deleted?("another") end def test_deleted_cookie_predicate_with_mismatching_options - cookies[:user_name] = 'Joe' - cookies.delete("user_name", :path => "/path") - assert_equal false, cookies.deleted?("user_name", :path => "/different") + cookies[:user_name] = "Joe" + cookies.delete("user_name", path: "/path") + assert_equal false, cookies.deleted?("user_name", path: "/different") end def test_cookies_persist_throughout_request @@ -410,7 +410,7 @@ class CookiesTest < ActionController::TestCase def test_read_permanent_cookie get :set_permanent_cookie - assert_equal 'Jamie', @controller.send(:cookies).permanent[:user_name] + assert_equal "Jamie", @controller.send(:cookies).permanent[:user_name] end def test_signed_cookie_using_default_digest @@ -423,12 +423,12 @@ class CookiesTest < ActionController::TestCase signed_cookie_salt = @request.env["action_dispatch.signed_cookie_salt"] secret = key_generator.generate_key(signed_cookie_salt) - verifier = ActiveSupport::MessageVerifier.new(secret, serializer: Marshal, digest: 'SHA1') + verifier = ActiveSupport::MessageVerifier.new(secret, serializer: Marshal, digest: "SHA1") assert_equal verifier.generate(45), cookies[:user_id] end def test_signed_cookie_using_custom_digest - @request.env["action_dispatch.cookies_digest"] = 'SHA256' + @request.env["action_dispatch.cookies_digest"] = "SHA256" get :set_signed_cookie cookies = @controller.send :cookies assert_not_equal 45, cookies[:user_id] @@ -438,7 +438,7 @@ class CookiesTest < ActionController::TestCase signed_cookie_salt = @request.env["action_dispatch.signed_cookie_salt"] secret = key_generator.generate_key(signed_cookie_salt) - verifier = ActiveSupport::MessageVerifier.new(secret, serializer: Marshal, digest: 'SHA256') + verifier = ActiveSupport::MessageVerifier.new(secret, serializer: Marshal, digest: "SHA256") assert_equal verifier.generate(45), cookies[:user_id] end @@ -469,15 +469,15 @@ class CookiesTest < ActionController::TestCase @request.env["action_dispatch.cookies_serializer"] = :json get :set_wrapped_signed_cookie cookies = @controller.send :cookies - assert_not_equal 'wrapped: 45', cookies[:user_id] - assert_equal 'wrapped: 45', cookies.signed[:user_id] + assert_not_equal "wrapped: 45", cookies[:user_id] + assert_equal "wrapped: 45", cookies.signed[:user_id] end def test_signed_cookie_using_custom_serializer @request.env["action_dispatch.cookies_serializer"] = CustomSerializer get :set_signed_cookie assert_not_equal 45, cookies[:user_id] - assert_equal '45 was dumped and loaded', cookies.signed[:user_id] + assert_equal "45 was dumped and loaded", cookies.signed[:user_id] end def test_signed_cookie_using_hybrid_serializer_can_migrate_marshal_dumped_value_to_json @@ -497,7 +497,7 @@ class CookiesTest < ActionController::TestCase assert_equal 45, cookies.signed[:user_id] verifier = ActiveSupport::MessageVerifier.new(secret, serializer: JSON) - assert_equal 45, verifier.verify(@response.cookies['user_id']) + assert_equal 45, verifier.verify(@response.cookies["user_id"]) end def test_signed_cookie_using_hybrid_serializer_can_read_from_json_dumped_value @@ -526,64 +526,64 @@ class CookiesTest < ActionController::TestCase def test_encrypted_cookie_using_default_serializer get :set_encrypted_cookie cookies = @controller.send :cookies - assert_not_equal 'bar', cookies[:foo] + assert_not_equal "bar", cookies[:foo] assert_raise TypeError do cookies.signed[:foo] end - assert_equal 'bar', cookies.encrypted[:foo] + assert_equal "bar", cookies.encrypted[:foo] end def test_encrypted_cookie_using_marshal_serializer @request.env["action_dispatch.cookies_serializer"] = :marshal get :set_encrypted_cookie cookies = @controller.send :cookies - assert_not_equal 'bar', cookies[:foo] + assert_not_equal "bar", cookies[:foo] assert_raises TypeError do cookies.signed[:foo] end - assert_equal 'bar', cookies.encrypted[:foo] + assert_equal "bar", cookies.encrypted[:foo] end def test_encrypted_cookie_using_json_serializer @request.env["action_dispatch.cookies_serializer"] = :json get :set_encrypted_cookie cookies = @controller.send :cookies - assert_not_equal 'bar', cookies[:foo] + assert_not_equal "bar", cookies[:foo] assert_raises ::JSON::ParserError do cookies.signed[:foo] end - assert_equal 'bar', cookies.encrypted[:foo] + assert_equal "bar", cookies.encrypted[:foo] end def test_wrapped_encrypted_cookie_using_json_serializer @request.env["action_dispatch.cookies_serializer"] = :json get :set_wrapped_encrypted_cookie cookies = @controller.send :cookies - assert_not_equal 'wrapped: bar', cookies[:foo] + assert_not_equal "wrapped: bar", cookies[:foo] assert_raises ::JSON::ParserError do cookies.signed[:foo] end - assert_equal 'wrapped: bar', cookies.encrypted[:foo] + assert_equal "wrapped: bar", cookies.encrypted[:foo] end def test_encrypted_cookie_using_custom_serializer @request.env["action_dispatch.cookies_serializer"] = CustomSerializer get :set_encrypted_cookie - assert_not_equal 'bar', cookies.encrypted[:foo] - assert_equal 'bar was dumped and loaded', cookies.encrypted[:foo] + assert_not_equal "bar", cookies.encrypted[:foo] + assert_equal "bar was dumped and loaded", cookies.encrypted[:foo] end def test_encrypted_cookie_using_custom_digest - @request.env["action_dispatch.cookies_digest"] = 'SHA256' + @request.env["action_dispatch.cookies_digest"] = "SHA256" get :set_encrypted_cookie cookies = @controller.send :cookies - assert_not_equal 'bar', cookies[:foo] - assert_equal 'bar', cookies.encrypted[:foo] + assert_not_equal "bar", cookies[:foo] + assert_equal "bar", cookies.encrypted[:foo] sign_secret = @request.env["action_dispatch.key_generator"].generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"]) - sha1_verifier = ActiveSupport::MessageVerifier.new(sign_secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer, digest: 'SHA1') - sha256_verifier = ActiveSupport::MessageVerifier.new(sign_secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer, digest: 'SHA256') + sha1_verifier = ActiveSupport::MessageVerifier.new(sign_secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer, digest: "SHA1") + sha256_verifier = ActiveSupport::MessageVerifier.new(sign_secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer, digest: "SHA256") assert_raises(ActiveSupport::MessageVerifier::InvalidSignature) do sha1_verifier.verify(cookies[:foo]) @@ -603,7 +603,7 @@ class CookiesTest < ActionController::TestCase secret = key_generator.generate_key(encrypted_cookie_salt) sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt) - marshal_value = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: Marshal).encrypt_and_sign("bar") + marshal_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: Marshal).encrypt_and_sign("bar") @request.headers["Cookie"] = "foo=#{marshal_value}" get :get_encrypted_cookie @@ -612,7 +612,7 @@ class CookiesTest < ActionController::TestCase assert_not_equal "bar", cookies[:foo] assert_equal "bar", cookies.encrypted[:foo] - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON) assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"]) end @@ -624,7 +624,7 @@ class CookiesTest < ActionController::TestCase encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"] secret = key_generator.generate_key(encrypted_cookie_salt) sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt) - json_value = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON).encrypt_and_sign("bar") + json_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON).encrypt_and_sign("bar") @request.headers["Cookie"] = "foo=#{json_value}" get :get_encrypted_cookie @@ -636,6 +636,19 @@ class CookiesTest < ActionController::TestCase assert_nil @response.cookies["foo"] end + def test_compat_encrypted_cookie_using_64_byte_key + # Cookie generated with 64 bytes secret + message = ["566d4e75536d686e633246564e6b493062557079626c566d51574d30515430394c53315665564a694e4563786555744f57537454576b396a5a31566a626e52525054303d2d2d34663234333330623130623261306163363562316266323335396164666364613564643134623131"].pack("H*") + @request.headers["Cookie"] = "foo=#{message}" + + get :get_encrypted_cookie + + cookies = @controller.send :cookies + assert_not_equal "bar", cookies[:foo] + assert_equal "bar", cookies.encrypted[:foo] + assert_nil @response.cookies["foo"] + end + def test_accessing_nonexistent_encrypted_cookie_should_not_raise_invalid_message get :set_encrypted_cookie assert_nil @controller.send(:cookies).encrypted[:non_existent_attribute] @@ -653,10 +666,10 @@ class CookiesTest < ActionController::TestCase end def test_delete_and_set_cookie - request.cookies[:user_name] = 'Joe' + request.cookies[:user_name] = "Joe" get :delete_and_set_cookie assert_cookie_header "user_name=david; path=/; expires=Mon, 10 Oct 2005 05:00:00 -0000" - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) end def test_raise_data_overflow @@ -687,7 +700,7 @@ class CookiesTest < ActionController::TestCase get :set_signed_cookie } - assert_raise(ArgumentError, ''.inspect) { + assert_raise(ArgumentError, "".inspect) { @request.env["action_dispatch.key_generator"] = ActiveSupport::LegacyKeyGenerator.new("") get :set_signed_cookie } @@ -789,18 +802,18 @@ class CookiesTest < ActionController::TestCase @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee" @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9" - legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate('bar') + legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate("bar") @request.headers["Cookie"] = "foo=#{legacy_value}" get :get_encrypted_cookie - assert_equal 'bar', @controller.send(:cookies).encrypted[:foo] + assert_equal "bar", @controller.send(:cookies).encrypted[:foo] key_generator = @request.env["action_dispatch.key_generator"] secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"]) sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"]) - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) - assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"]) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret) + assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"]) end def test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_cookie_jar_if_both_secret_token_and_secret_key_base_are_set @@ -828,18 +841,18 @@ class CookiesTest < ActionController::TestCase @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee" @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9" - legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate('bar') + legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate("bar") @request.headers["Cookie"] = "foo=#{legacy_value}" get :get_encrypted_cookie - assert_equal 'bar', @controller.send(:cookies).encrypted[:foo] + assert_equal "bar", @controller.send(:cookies).encrypted[:foo] key_generator = @request.env["action_dispatch.key_generator"] secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"]) sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"]) - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON) - assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"]) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON) + assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"]) end def test_legacy_json_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_hybrid_jar_if_both_secret_token_and_secret_key_base_are_set @@ -867,18 +880,18 @@ class CookiesTest < ActionController::TestCase @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee" @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9" - legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate('bar') + legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate("bar") @request.headers["Cookie"] = "foo=#{legacy_value}" get :get_encrypted_cookie - assert_equal 'bar', @controller.send(:cookies).encrypted[:foo] + assert_equal "bar", @controller.send(:cookies).encrypted[:foo] key_generator = @request.env["action_dispatch.key_generator"] secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"]) sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"]) - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON) - assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"]) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON) + assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"]) end def test_legacy_marshal_signed_cookie_is_read_and_transparently_upgraded_by_signed_json_hybrid_jar_if_both_secret_token_and_secret_key_base_are_set @@ -906,18 +919,18 @@ class CookiesTest < ActionController::TestCase @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee" @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9" - legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate('bar') + legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate("bar") @request.headers["Cookie"] = "foo=#{legacy_value}" get :get_encrypted_cookie - assert_equal 'bar', @controller.send(:cookies).encrypted[:foo] + assert_equal "bar", @controller.send(:cookies).encrypted[:foo] key_generator = @request.env["action_dispatch.key_generator"] secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"]) sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"]) - encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON) - assert_equal 'bar', encryptor.decrypt_and_verify(@response.cookies["foo"]) + encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON) + assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"]) end def test_legacy_signed_cookie_is_treated_as_nil_by_signed_cookie_jar_if_tampered @@ -998,7 +1011,7 @@ class CookiesTest < ActionController::TestCase end def test_deleting_cookie_with_all_domain_option - request.cookies[:user_name] = 'Joe' + request.cookies[:user_name] = "Joe" get :delete_cookie_with_domain assert_response :success assert_cookie_header "user_name=; domain=.nextangle.com; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000" @@ -1032,7 +1045,7 @@ class CookiesTest < ActionController::TestCase end def test_deleting_cookie_with_all_domain_option_and_tld_length - request.cookies[:user_name] = 'Joe' + request.cookies[:user_name] = "Joe" get :delete_cookie_with_domain_and_tld assert_response :success assert_cookie_header "user_name=; domain=.nextangle.com; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000" @@ -1061,7 +1074,7 @@ class CookiesTest < ActionController::TestCase def test_deletings_cookie_with_several_preset_domains_using_one_of_these_domains @request.host = "example2.com" - request.cookies[:user_name] = 'Joe' + request.cookies[:user_name] = "Joe" get :delete_cookie_with_domains assert_response :success assert_cookie_header "user_name=; domain=example2.com; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000" @@ -1069,7 +1082,7 @@ class CookiesTest < ActionController::TestCase def test_deletings_cookie_with_several_preset_domains_using_other_domain @request.host = "other-domain.com" - request.cookies[:user_name] = 'Joe' + request.cookies[:user_name] = "Joe" get :delete_cookie_with_domains assert_response :success assert_cookie_header "user_name=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000" @@ -1078,20 +1091,20 @@ class CookiesTest < ActionController::TestCase def test_cookies_hash_is_indifferent_access get :symbol_key assert_equal "david", cookies[:user_name] - assert_equal "david", cookies['user_name'] + assert_equal "david", cookies["user_name"] get :string_key assert_equal "dhh", cookies[:user_name] - assert_equal "dhh", cookies['user_name'] + assert_equal "dhh", cookies["user_name"] end def test_setting_request_cookies_is_indifferent_access cookies.clear cookies[:user_name] = "andrew" get :string_key_mock - assert_equal "david", cookies['user_name'] + assert_equal "david", cookies["user_name"] cookies.clear - cookies['user_name'] = "andrew" + cookies["user_name"] = "andrew" get :symbol_key_mock assert_equal "david", cookies[:user_name] end @@ -1102,11 +1115,11 @@ class CookiesTest < ActionController::TestCase assert_equal "david", cookies[:user_name] get :noop - assert !@response.headers.include?("Set-Cookie") + assert_not_includes @response.headers, "Set-Cookie" assert_equal "david", cookies[:user_name] get :noop - assert !@response.headers.include?("Set-Cookie") + assert_not_includes @response.headers, "Set-Cookie" assert_equal "david", cookies[:user_name] end @@ -1123,57 +1136,57 @@ class CookiesTest < ActionController::TestCase end def test_can_set_http_cookie_header - @request.env['HTTP_COOKIE'] = 'user_name=david' + @request.env["HTTP_COOKIE"] = "user_name=david" get :noop - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] get :noop - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] - @request.env['HTTP_COOKIE'] = 'user_name=andrew' + @request.env["HTTP_COOKIE"] = "user_name=andrew" get :noop - assert_equal 'andrew', cookies['user_name'] - assert_equal 'andrew', cookies[:user_name] + assert_equal "andrew", cookies["user_name"] + assert_equal "andrew", cookies[:user_name] end def test_can_set_request_cookies - @request.cookies['user_name'] = 'david' + @request.cookies["user_name"] = "david" get :noop - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] get :noop - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] - @request.cookies[:user_name] = 'andrew' + @request.cookies[:user_name] = "andrew" get :noop - assert_equal 'andrew', cookies['user_name'] - assert_equal 'andrew', cookies[:user_name] + assert_equal "andrew", cookies["user_name"] + assert_equal "andrew", cookies[:user_name] end def test_cookies_precedence_over_http_cookie - @request.env['HTTP_COOKIE'] = 'user_name=andrew' + @request.env["HTTP_COOKIE"] = "user_name=andrew" get :authenticate - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] get :noop - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] end def test_cookies_precedence_over_request_cookies - @request.cookies['user_name'] = 'andrew' + @request.cookies["user_name"] = "andrew" get :authenticate - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] get :noop - assert_equal 'david', cookies['user_name'] - assert_equal 'david', cookies[:user_name] + assert_equal "david", cookies["user_name"] + assert_equal "david", cookies[:user_name] end private diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index 5a39db145e..2c5e09e283 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -1,7 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" class DebugExceptionsTest < ActionDispatch::IntegrationTest - class Boomer attr_accessor :closed @@ -20,11 +19,11 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest end def method_that_raises - raise StandardError.new 'error in framework' + raise StandardError.new "error in framework" end def call(env) - env['action_dispatch.show_detailed_exceptions'] = @detailed + env["action_dispatch.show_detailed_exceptions"] = @detailed req = ActionDispatch::Request.new(env) case req.path when %r{/pass} @@ -45,10 +44,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest begin raise AbstractController::ActionNotFound.new rescue - raise ActionView::Template::Error.new('template') + raise ActionView::Template::Error.new("template") end when %r{/missing_template} - raise ActionView::MissingTemplate.new(%w(foo), 'foo/index', %w(foo), false, 'mailer') + raise ActionView::MissingTemplate.new(%w(foo), "foo/index", %w(foo), false, "mailer") when %r{/bad_request} raise ActionController::BadRequest when %r{/missing_keys} @@ -56,10 +55,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest when %r{/parameter_missing} raise ActionController::ParameterMissing, :missing_param_key when %r{/original_syntax_error} - eval 'broke_syntax =' # `eval` need for raise native SyntaxError at runtime + eval "broke_syntax =" # `eval` need for raise native SyntaxError at runtime when %r{/syntax_error_into_view} begin - eval 'broke_syntax =' + eval "broke_syntax =" rescue Exception template = ActionView::Template.new(File.read(__FILE__), __FILE__, @@ -79,85 +78,85 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest ProductionApp = ActionDispatch::DebugExceptions.new(Boomer.new(false), RoutesApp) DevelopmentApp = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp) - test 'skip diagnosis if not showing detailed exceptions' do + test "skip diagnosis if not showing detailed exceptions" do @app = ProductionApp assert_raise RuntimeError do - get "/", headers: { 'action_dispatch.show_exceptions' => true } + get "/", headers: { "action_dispatch.show_exceptions" => true } end end - test 'skip diagnosis if not showing exceptions' do + test "skip diagnosis if not showing exceptions" do @app = DevelopmentApp assert_raise RuntimeError do - get "/", headers: { 'action_dispatch.show_exceptions' => false } + get "/", headers: { "action_dispatch.show_exceptions" => false } end end - test 'raise an exception on cascade pass' do + test "raise an exception on cascade pass" do @app = ProductionApp assert_raise ActionController::RoutingError do - get "/pass", headers: { 'action_dispatch.show_exceptions' => true } + get "/pass", headers: { "action_dispatch.show_exceptions" => true } end end - test 'closes the response body on cascade pass' do + test "closes the response body on cascade pass" do boomer = Boomer.new(false) @app = ActionDispatch::DebugExceptions.new(boomer) assert_raise ActionController::RoutingError do - get "/pass", headers: { 'action_dispatch.show_exceptions' => true } + get "/pass", headers: { "action_dispatch.show_exceptions" => true } end assert boomer.closed, "Expected to close the response body" end - test 'displays routes in a table when a RoutingError occurs' do + test "displays routes in a table when a RoutingError occurs" do @app = DevelopmentApp - get "/pass", headers: { 'action_dispatch.show_exceptions' => true } + get "/pass", headers: { "action_dispatch.show_exceptions" => true } routing_table = body[/route_table.*<.table>/m] - assert_match '/:controller(/:action)(.:format)', routing_table - assert_match ':controller#:action', routing_table - assert_no_match '<|>', routing_table, "there should not be escaped html in the output" + assert_match "/:controller(/:action)(.:format)", routing_table + assert_match ":controller#:action", routing_table + assert_no_match "<|>", routing_table, "there should not be escaped html in the output" end - test 'displays request and response info when a RoutingError occurs' do + test "displays request and response info when a RoutingError occurs" do @app = DevelopmentApp - get "/pass", headers: { 'action_dispatch.show_exceptions' => true } + get "/pass", headers: { "action_dispatch.show_exceptions" => true } - assert_select 'h2', /Request/ - assert_select 'h2', /Response/ + assert_select "h2", /Request/ + assert_select "h2", /Response/ end test "rescue with diagnostics message" do @app = DevelopmentApp - get "/", headers: { 'action_dispatch.show_exceptions' => true } + get "/", headers: { "action_dispatch.show_exceptions" => true } assert_response 500 assert_match(/puke/, body) - get "/not_found", headers: { 'action_dispatch.show_exceptions' => true } + get "/not_found", headers: { "action_dispatch.show_exceptions" => true } assert_response 404 assert_match(/#{AbstractController::ActionNotFound.name}/, body) - get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true } + get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => true } assert_response 405 assert_match(/ActionController::MethodNotAllowed/, body) - get "/unknown_http_method", headers: { 'action_dispatch.show_exceptions' => true } + get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => true } assert_response 405 assert_match(/ActionController::UnknownHttpMethod/, body) - get "/bad_request", headers: { 'action_dispatch.show_exceptions' => true } + get "/bad_request", headers: { "action_dispatch.show_exceptions" => true } assert_response 400 assert_match(/ActionController::BadRequest/, body) - get "/parameter_missing", headers: { 'action_dispatch.show_exceptions' => true } + get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true } assert_response 400 assert_match(/ActionController::ParameterMissing/, body) end test "rescue with text error for xhr request" do @app = DevelopmentApp - xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'} + xhr_request_env = { "action_dispatch.show_exceptions" => true, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" } get "/", headers: xhr_request_env assert_response 500 @@ -166,12 +165,12 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest assert_equal "text/plain", response.content_type assert_match(/RuntimeError\npuke/, body) - Rails.stub :root, Pathname.new('.') do + Rails.stub :root, Pathname.new(".") do get "/", headers: xhr_request_env assert_response 500 - assert_match 'Extracted source (around line #', body - assert_select 'pre', { count: 0 }, body + assert_match "Extracted source (around line #", body + assert_select "pre", { count: 0 }, body end get "/not_found", headers: xhr_request_env @@ -208,38 +207,38 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "rescue with JSON error for JSON API request" do @app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, :api) - get "/", headers: { 'action_dispatch.show_exceptions' => true }, as: :json + get "/", headers: { "action_dispatch.show_exceptions" => true }, as: :json assert_response 500 assert_no_match(/<header>/, body) assert_no_match(/<body>/, body) assert_equal "application/json", response.content_type assert_match(/RuntimeError: puke/, body) - get "/not_found", headers: { 'action_dispatch.show_exceptions' => true }, as: :json + get "/not_found", headers: { "action_dispatch.show_exceptions" => true }, as: :json assert_response 404 assert_no_match(/<body>/, body) assert_equal "application/json", response.content_type assert_match(/#{AbstractController::ActionNotFound.name}/, body) - get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true }, as: :json + get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => true }, as: :json assert_response 405 assert_no_match(/<body>/, body) assert_equal "application/json", response.content_type assert_match(/ActionController::MethodNotAllowed/, body) - get "/unknown_http_method", headers: { 'action_dispatch.show_exceptions' => true }, as: :json + get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => true }, as: :json assert_response 405 assert_no_match(/<body>/, body) assert_equal "application/json", response.content_type assert_match(/ActionController::UnknownHttpMethod/, body) - get "/bad_request", headers: { 'action_dispatch.show_exceptions' => true }, as: :json + get "/bad_request", headers: { "action_dispatch.show_exceptions" => true }, as: :json assert_response 400 assert_no_match(/<body>/, body) assert_equal "application/json", response.content_type assert_match(/ActionController::BadRequest/, body) - get "/parameter_missing", headers: { 'action_dispatch.show_exceptions' => true }, as: :json + get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true }, as: :json assert_response 400 assert_no_match(/<body>/, body) assert_equal "application/json", response.content_type @@ -249,7 +248,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "rescue with HTML format for HTML API request" do @app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, :api) - get "/index.html", headers: { 'action_dispatch.show_exceptions' => true } + get "/index.html", headers: { "action_dispatch.show_exceptions" => true } assert_response 500 assert_match(/<header>/, body) assert_match(/<body>/, body) @@ -260,7 +259,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "rescue with XML format for XML API requests" do @app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, :api) - get "/index.xml", headers: { 'action_dispatch.show_exceptions' => true } + get "/index.xml", headers: { "action_dispatch.show_exceptions" => true } assert_response 500 assert_equal "application/xml", response.content_type assert_match(/RuntimeError: puke/, body) @@ -268,14 +267,14 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "rescue with JSON format as fallback if API request format is not supported" do begin - Mime::Type.register 'text/wibble', :wibble + Mime::Type.register "text/wibble", :wibble ActionDispatch::IntegrationTest.register_encoder(:wibble, param_encoder: -> params { params }) @app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, :api) - get "/index", headers: { 'action_dispatch.show_exceptions' => true }, as: :wibble + get "/index", headers: { "action_dispatch.show_exceptions" => true }, as: :wibble assert_response 500 assert_equal "application/json", response.content_type assert_match(/RuntimeError: puke/, body) @@ -288,8 +287,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "does not show filtered parameters" do @app = DevelopmentApp - get "/", params: { "foo"=>"bar" }, headers: { 'action_dispatch.show_exceptions' => true, - 'action_dispatch.parameter_filter' => [:foo] } + get "/", params: { "foo"=>"bar" }, headers: { "action_dispatch.show_exceptions" => true, + "action_dispatch.parameter_filter" => [:foo] } assert_response 500 assert_match(""foo"=>"[FILTERED]"", body) end @@ -297,7 +296,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "show registered original exception for wrapped exceptions" do @app = DevelopmentApp - get "/not_found_original_exception", headers: { 'action_dispatch.show_exceptions' => true } + get "/not_found_original_exception", headers: { "action_dispatch.show_exceptions" => true } assert_response 404 assert_match(/AbstractController::ActionNotFound/, body) end @@ -305,7 +304,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "named urls missing keys raise 500 level error" do @app = DevelopmentApp - get "/missing_keys", headers: { 'action_dispatch.show_exceptions' => true } + get "/missing_keys", headers: { "action_dispatch.show_exceptions" => true } assert_response 500 assert_match(/ActionController::UrlGenerationError/, body) @@ -314,11 +313,11 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "show the controller name in the diagnostics template when controller name is present" do @app = DevelopmentApp get("/runtime_error", headers: { - 'action_dispatch.show_exceptions' => true, - 'action_dispatch.request.parameters' => { - 'action' => 'show', - 'id' => 'unknown', - 'controller' => 'featured_tile' + "action_dispatch.show_exceptions" => true, + "action_dispatch.request.parameters" => { + "action" => "show", + "id" => "unknown", + "controller" => "featured_tile" } }) assert_response 500 @@ -329,18 +328,18 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest @app = DevelopmentApp params = { - 'id' => 'unknown', - 'someparam' => { - 'foo' => 'bar', - 'abc' => 'goo' + "id" => "unknown", + "someparam" => { + "foo" => "bar", + "abc" => "goo" } } get("/runtime_error", headers: { - 'action_dispatch.show_exceptions' => true, - 'action_dispatch.request.parameters' => { - 'action' => 'show', - 'controller' => 'featured_tile' + "action_dispatch.show_exceptions" => true, + "action_dispatch.request.parameters" => { + "action" => "show", + "controller" => "featured_tile" }.merge(params) }) assert_response 500 @@ -351,52 +350,75 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test "sets the HTTP charset parameter" do @app = DevelopmentApp - get "/", headers: { 'action_dispatch.show_exceptions' => true } + get "/", headers: { "action_dispatch.show_exceptions" => true } assert_equal "text/html; charset=utf-8", response.headers["Content-Type"] end - test 'uses logger from env' do + test "uses logger from env" do @app = DevelopmentApp output = StringIO.new - get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => Logger.new(output) } + get "/", headers: { "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => Logger.new(output) } assert_match(/puke/, output.rewind && output.read) end - test 'uses backtrace cleaner from env' do + test "logs only what is necessary" do + @app = DevelopmentApp + io = StringIO.new + logger = ActiveSupport::Logger.new(io) + + _old, ActionView::Base.logger = ActionView::Base.logger, logger + begin + get "/", headers: { "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => logger } + ensure + ActionView::Base.logger = _old + end + + output = io.rewind && io.read + lines = output.lines + + # Other than the first three... + assert_equal([" \n", "RuntimeError (puke!):\n", " \n"], lines.slice!(0, 3)) + lines.each do |line| + # .. all the remaining lines should be from the backtrace + assert_match(/:\d+:in /, line) + end + end + + test "uses backtrace cleaner from env" do @app = DevelopmentApp backtrace_cleaner = ActiveSupport::BacktraceCleaner.new - backtrace_cleaner.stub :clean, ['passed backtrace cleaner'] do - get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => backtrace_cleaner } + backtrace_cleaner.stub :clean, ["passed backtrace cleaner"] do + get "/", headers: { "action_dispatch.show_exceptions" => true, "action_dispatch.backtrace_cleaner" => backtrace_cleaner } assert_match(/passed backtrace cleaner/, body) end end - test 'logs exception backtrace when all lines silenced' do + test "logs exception backtrace when all lines silenced" do output = StringIO.new backtrace_cleaner = ActiveSupport::BacktraceCleaner.new backtrace_cleaner.add_silencer { true } - env = {'action_dispatch.show_exceptions' => true, - 'action_dispatch.logger' => Logger.new(output), - 'action_dispatch.backtrace_cleaner' => backtrace_cleaner} + env = { "action_dispatch.show_exceptions" => true, + "action_dispatch.logger" => Logger.new(output), + "action_dispatch.backtrace_cleaner" => backtrace_cleaner } get "/", headers: env assert_operator((output.rewind && output.read).lines.count, :>, 10) end - test 'display backtrace when error type is SyntaxError' do + test "display backtrace when error type is SyntaxError" do @app = DevelopmentApp - get '/original_syntax_error', headers: { 'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new } + get "/original_syntax_error", headers: { "action_dispatch.backtrace_cleaner" => ActiveSupport::BacktraceCleaner.new } assert_response 500 - assert_select '#Application-Trace' do - assert_select 'pre code', /syntax error, unexpected/ + assert_select "#Application-Trace" do + assert_select "pre code", /syntax error, unexpected/ end end - test 'display backtrace on template missing errors' do + test "display backtrace on template missing errors" do @app = DevelopmentApp get "/missing_template" @@ -405,56 +427,56 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest assert_select "#container h2", /^Missing template/ - assert_select '#Application-Trace' - assert_select '#Framework-Trace' - assert_select '#Full-Trace' + assert_select "#Application-Trace" + assert_select "#Framework-Trace" + assert_select "#Full-Trace" - assert_select 'h2', /Request/ + assert_select "h2", /Request/ end - test 'display backtrace when error type is SyntaxError wrapped by ActionView::Template::Error' do + test "display backtrace when error type is SyntaxError wrapped by ActionView::Template::Error" do @app = DevelopmentApp - get '/syntax_error_into_view', headers: { 'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new } + get "/syntax_error_into_view", headers: { "action_dispatch.backtrace_cleaner" => ActiveSupport::BacktraceCleaner.new } assert_response 500 - assert_select '#Application-Trace' do - assert_select 'pre code', /syntax error, unexpected/ + assert_select "#Application-Trace" do + assert_select "pre code", /syntax error, unexpected/ end end - test 'debug exceptions app shows user code that caused the error in source view' do + test "debug exceptions app shows user code that caused the error in source view" do @app = DevelopmentApp - Rails.stub :root, Pathname.new('.') do + Rails.stub :root, Pathname.new(".") do cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc| bc.add_silencer { |line| line =~ /method_that_raises/ } bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} } end - get '/framework_raises', headers: { 'action_dispatch.backtrace_cleaner' => cleaner } + get "/framework_raises", headers: { "action_dispatch.backtrace_cleaner" => cleaner } # Assert correct error assert_response 500 - assert_select 'h2', /error in framework/ + assert_select "h2", /error in framework/ # assert source view line is the call to method_that_raises - assert_select 'div.source:not(.hidden)' do - assert_select 'pre .line.active', /method_that_raises/ + assert_select "div.source:not(.hidden)" do + assert_select "pre .line.active", /method_that_raises/ end # assert first source view (hidden) that throws the error - assert_select 'div.source:first' do - assert_select 'pre .line.active', /raise StandardError\.new/ + assert_select "div.source:first" do + assert_select "pre .line.active", /raise StandardError\.new/ end # assert application trace refers to line that calls method_that_raises is first - assert_select '#Application-Trace' do - assert_select 'pre code a:first', %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call} + assert_select "#Application-Trace" do + assert_select "pre code a:first", %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call} end # assert framework trace that threw the error is first - assert_select '#Framework-Trace' do - assert_select 'pre code a:first', /method_that_raises/ + assert_select "#Framework-Trace" do + assert_select "pre code a:first", /method_that_raises/ end end end diff --git a/actionpack/test/dispatch/exception_wrapper_test.rb b/actionpack/test/dispatch/exception_wrapper_test.rb index dfbb91c0ca..316661a116 100644 --- a/actionpack/test/dispatch/exception_wrapper_test.rb +++ b/actionpack/test/dispatch/exception_wrapper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch class ExceptionWrapperTest < ActionDispatch::IntegrationTest @@ -21,43 +21,49 @@ module ActionDispatch @cleaner.add_silencer { |line| line !~ /^lib/ } end - test '#source_extracts fetches source fragments for every backtrace entry' do + test "#source_extracts fetches source fragments for every backtrace entry" do exception = TestError.new("lib/file.rb:42:in `index'") wrapper = ExceptionWrapper.new(nil, exception) - assert_called_with(wrapper, :source_fragment, ['lib/file.rb', 42], returns: 'foo') do - assert_equal [ code: 'foo', line_number: 42 ], wrapper.source_extracts + assert_called_with(wrapper, :source_fragment, ["lib/file.rb", 42], returns: "foo") do + assert_equal [ code: "foo", line_number: 42 ], wrapper.source_extracts end end - test '#source_extracts works with Windows paths' do + test "#source_extracts works with Windows paths" do exc = TestError.new("c:/path/to/rails/app/controller.rb:27:in 'index':") wrapper = ExceptionWrapper.new(nil, exc) - assert_called_with(wrapper, :source_fragment, ['c:/path/to/rails/app/controller.rb', 27], returns: 'nothing') do - assert_equal [ code: 'nothing', line_number: 27 ], wrapper.source_extracts + assert_called_with(wrapper, :source_fragment, ["c:/path/to/rails/app/controller.rb", 27], returns: "nothing") do + assert_equal [ code: "nothing", line_number: 27 ], wrapper.source_extracts end end - test '#source_extracts works with non standard backtrace' do - exc = TestError.new('invalid') + test "#source_extracts works with non standard backtrace" do + exc = TestError.new("invalid") wrapper = ExceptionWrapper.new(nil, exc) - assert_called_with(wrapper, :source_fragment, ['invalid', 0], returns: 'nothing') do - assert_equal [ code: 'nothing', line_number: 0 ], wrapper.source_extracts + assert_called_with(wrapper, :source_fragment, ["invalid", 0], returns: "nothing") do + assert_equal [ code: "nothing", line_number: 0 ], wrapper.source_extracts end end - test '#application_trace returns traces only from the application' do + test "#application_trace returns traces only from the application" do exception = TestError.new(caller.prepend("lib/file.rb:42:in `index'")) wrapper = ExceptionWrapper.new(@cleaner, exception) assert_equal [ "lib/file.rb:42:in `index'" ], wrapper.application_trace end - test '#application_trace cannot be nil' do + test "#status_code returns 400 for Rack::Utils::ParameterTypeError" do + exception = Rack::Utils::ParameterTypeError.new + wrapper = ExceptionWrapper.new(@cleaner, exception) + assert_equal 400, wrapper.status_code + end + + test "#application_trace cannot be nil" do nil_backtrace_wrapper = ExceptionWrapper.new(@cleaner, BadlyDefinedError.new) nil_cleaner_wrapper = ExceptionWrapper.new(nil, BadlyDefinedError.new) @@ -65,14 +71,14 @@ module ActionDispatch assert_equal [], nil_cleaner_wrapper.application_trace end - test '#framework_trace returns traces outside the application' do + test "#framework_trace returns traces outside the application" do exception = TestError.new(caller.prepend("lib/file.rb:42:in `index'")) wrapper = ExceptionWrapper.new(@cleaner, exception) assert_equal caller, wrapper.framework_trace end - test '#framework_trace cannot be nil' do + test "#framework_trace cannot be nil" do nil_backtrace_wrapper = ExceptionWrapper.new(@cleaner, BadlyDefinedError.new) nil_cleaner_wrapper = ExceptionWrapper.new(nil, BadlyDefinedError.new) @@ -80,14 +86,14 @@ module ActionDispatch assert_equal [], nil_cleaner_wrapper.framework_trace end - test '#full_trace returns application and framework traces' do + test "#full_trace returns application and framework traces" do exception = TestError.new(caller.prepend("lib/file.rb:42:in `index'")) wrapper = ExceptionWrapper.new(@cleaner, exception) assert_equal exception.backtrace, wrapper.full_trace end - test '#full_trace cannot be nil' do + test "#full_trace cannot be nil" do nil_backtrace_wrapper = ExceptionWrapper.new(@cleaner, BadlyDefinedError.new) nil_cleaner_wrapper = ExceptionWrapper.new(nil, BadlyDefinedError.new) @@ -95,14 +101,14 @@ module ActionDispatch assert_equal [], nil_cleaner_wrapper.full_trace end - test '#traces returns every trace by category enumerated with an index' do + test "#traces returns every trace by category enumerated with an index" do exception = TestError.new("lib/file.rb:42:in `index'", "/gems/rack.rb:43:in `index'") wrapper = ExceptionWrapper.new(@cleaner, exception) assert_equal({ - 'Application Trace' => [ id: 0, trace: "lib/file.rb:42:in `index'" ], - 'Framework Trace' => [ id: 1, trace: "/gems/rack.rb:43:in `index'" ], - 'Full Trace' => [ + "Application Trace" => [ id: 0, trace: "lib/file.rb:42:in `index'" ], + "Framework Trace" => [ id: 1, trace: "/gems/rack.rb:43:in `index'" ], + "Full Trace" => [ { id: 0, trace: "lib/file.rb:42:in `index'" }, { id: 1, trace: "/gems/rack.rb:43:in `index'" } ] diff --git a/actionpack/test/dispatch/executor_test.rb b/actionpack/test/dispatch/executor_test.rb index 28bb232ecd..0b4e0849c3 100644 --- a/actionpack/test/dispatch/executor_test.rb +++ b/actionpack/test/dispatch/executor_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ExecutorTest < ActiveSupport::TestCase class MyBody < Array @@ -119,8 +119,8 @@ class ExecutorTest < ActiveSupport::TestCase private def call_and_return_body(&block) - app = middleware(block || proc { [200, {}, 'response'] }) - _, _, body = app.call({'rack.input' => StringIO.new('')}) + app = middleware(block || proc { [200, {}, "response"] }) + _, _, body = app.call("rack.input" => StringIO.new("")) body end diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb index 7f1ef121b7..6febd5cb68 100644 --- a/actionpack/test/dispatch/header_test.rb +++ b/actionpack/test/dispatch/header_test.rb @@ -18,14 +18,14 @@ class HeaderTest < ActiveSupport::TestCase "HTTP_REFERER" => "/some/page", "Host" => "http://test.com") - assert_equal({"Content-Type" => "application/json", + assert_equal({ "Content-Type" => "application/json", "HTTP_REFERER" => "/some/page", - "Host" => "http://test.com"}, headers.env) + "Host" => "http://test.com" }, headers.env) end test "#env returns the headers as env variables" do - assert_equal({"CONTENT_TYPE" => "text/plain", - "HTTP_REFERER" => "/some/page"}, @headers.env) + assert_equal({ "CONTENT_TYPE" => "text/plain", + "HTTP_REFERER" => "/some/page" }, @headers.env) end test "#each iterates through the env variables" do @@ -44,20 +44,20 @@ class HeaderTest < ActiveSupport::TestCase test "add to multivalued headers" do # Sets header when not present - @headers.add 'Foo', '1' - assert_equal '1', @headers['Foo'] + @headers.add "Foo", "1" + assert_equal "1", @headers["Foo"] # Ignores nil values - @headers.add 'Foo', nil - assert_equal '1', @headers['Foo'] + @headers.add "Foo", nil + assert_equal "1", @headers["Foo"] # Converts value to string - @headers.add 'Foo', 1 - assert_equal '1,1', @headers['Foo'] + @headers.add "Foo", 1 + assert_equal "1,1", @headers["Foo"] # Case-insensitive - @headers.add 'fOo', 2 - assert_equal '1,1,2', @headers['foO'] + @headers.add "fOo", 2 + assert_equal "1,1,2", @headers["foO"] end test "headers can contain numbers" do @@ -76,9 +76,9 @@ class HeaderTest < ActiveSupport::TestCase test "key?" do assert @headers.key?("CONTENT_TYPE") - assert @headers.include?("CONTENT_TYPE") + assert_includes @headers, "CONTENT_TYPE" assert @headers.key?("Content-Type") - assert @headers.include?("Content-Type") + assert_includes @headers, "Content-Type" end test "fetch with block" do @@ -105,28 +105,28 @@ class HeaderTest < ActiveSupport::TestCase test "#merge! headers with mutation" do @headers.merge!("Host" => "http://example.test", "Content-Type" => "text/html") - assert_equal({"HTTP_HOST" => "http://example.test", + assert_equal({ "HTTP_HOST" => "http://example.test", "CONTENT_TYPE" => "text/html", - "HTTP_REFERER" => "/some/page"}, @headers.env) + "HTTP_REFERER" => "/some/page" }, @headers.env) end test "#merge! env with mutation" do @headers.merge!("HTTP_HOST" => "http://first.com", "CONTENT_TYPE" => "text/html") - assert_equal({"HTTP_HOST" => "http://first.com", + assert_equal({ "HTTP_HOST" => "http://first.com", "CONTENT_TYPE" => "text/html", - "HTTP_REFERER" => "/some/page"}, @headers.env) + "HTTP_REFERER" => "/some/page" }, @headers.env) end test "merge without mutation" do combined = @headers.merge("HTTP_HOST" => "http://example.com", "CONTENT_TYPE" => "text/html") - assert_equal({"HTTP_HOST" => "http://example.com", + assert_equal({ "HTTP_HOST" => "http://example.com", "CONTENT_TYPE" => "text/html", - "HTTP_REFERER" => "/some/page"}, combined.env) + "HTTP_REFERER" => "/some/page" }, combined.env) - assert_equal({"CONTENT_TYPE" => "text/plain", - "HTTP_REFERER" => "/some/page"}, @headers.env) + assert_equal({ "CONTENT_TYPE" => "text/plain", + "HTTP_REFERER" => "/some/page" }, @headers.env) end test "env variables with . are not modified" do @@ -151,11 +151,17 @@ class HeaderTest < ActiveSupport::TestCase end test "headers directly modifies the passed environment" do - env = {"HTTP_REFERER" => "/"} + env = { "HTTP_REFERER" => "/" } headers = make_headers(env) - headers['Referer'] = "http://example.com/" + headers["Referer"] = "http://example.com/" headers.merge! "CONTENT_TYPE" => "text/plain" - assert_equal({"HTTP_REFERER"=>"http://example.com/", - "CONTENT_TYPE"=>"text/plain"}, env) + assert_equal({ "HTTP_REFERER"=>"http://example.com/", + "CONTENT_TYPE"=>"text/plain" }, env) + end + + test "fetch exception" do + assert_raises KeyError do + @headers.fetch(:some_key_that_doesnt_exist) + end end end diff --git a/actionpack/test/dispatch/live_response_test.rb b/actionpack/test/dispatch/live_response_test.rb index de57c4be1d..d10fc7d575 100644 --- a/actionpack/test/dispatch/live_response_test.rb +++ b/actionpack/test/dispatch/live_response_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'concurrent/atomic/count_down_latch' +require "abstract_unit" +require "concurrent/atomic/count_down_latch" module ActionController module Live @@ -10,7 +10,7 @@ module ActionController end def test_header_merge - header = @response.header.merge('Foo' => 'Bar') + header = @response.header.merge("Foo" => "Bar") assert_kind_of(ActionController::Live::Response::Header, header) assert_not_equal header, @response.header end @@ -18,7 +18,7 @@ module ActionController def test_initialize_with_default_headers r = Class.new(Live::Response) do def self.default_headers - { 'omg' => 'g' } + { "omg" => "g" } end end @@ -30,38 +30,38 @@ module ActionController latch = Concurrent::CountDownLatch.new t = Thread.new { - @response.stream.write 'foo' + @response.stream.write "foo" latch.wait @response.stream.close } @response.await_commit @response.each do |part| - assert_equal 'foo', part + assert_equal "foo", part latch.count_down end assert t.join end def test_setting_body_populates_buffer - @response.body = 'omg' + @response.body = "omg" @response.close - assert_equal ['omg'], @response.body_parts + assert_equal ["omg"], @response.body_parts end def test_cache_control_is_set - @response.stream.write 'omg' - assert_equal 'no-cache', @response.headers['Cache-Control'] + @response.stream.write "omg" + assert_equal "no-cache", @response.headers["Cache-Control"] end def test_content_length_is_removed - @response.headers['Content-Length'] = "1234" - @response.stream.write 'omg' - assert_nil @response.headers['Content-Length'] + @response.headers["Content-Length"] = "1234" + @response.stream.write "omg" + assert_nil @response.headers["Content-Length"] end def test_headers_cannot_be_written_after_webserver_reads - @response.stream.write 'omg' + @response.stream.write "omg" latch = Concurrent::CountDownLatch.new t = Thread.new { @@ -73,10 +73,10 @@ module ActionController latch.wait assert @response.headers.frozen? e = assert_raises(ActionDispatch::IllegalStateError) do - @response.headers['Content-Length'] = "zomg" + @response.headers["Content-Length"] = "zomg" end - assert_equal 'header already sent', e.message + assert_equal "header already sent", e.message @response.stream.close t.join end @@ -87,9 +87,9 @@ module ActionController @response.each { |x| } e = assert_raises(ActionDispatch::IllegalStateError) do - @response.headers['Content-Length'] = "zomg" + @response.headers["Content-Length"] = "zomg" end - assert_equal 'header already sent', e.message + assert_equal "header already sent", e.message end end end diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb index 69098326b9..1596d23b1e 100644 --- a/actionpack/test/dispatch/mapper_test.rb +++ b/actionpack/test/dispatch/mapper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Routing @@ -50,15 +50,15 @@ module ActionDispatch fakeset = FakeSet.new mapper = Mapper.new fakeset assert_raises(ArgumentError) do - mapper.match '/', :to => 'posts#index', :as => :main + mapper.match "/", to: "posts#index", as: :main end end def test_unscoped_formatted fakeset = FakeSet.new mapper = Mapper.new fakeset - mapper.get '/foo', :to => 'posts#index', :as => :main, :format => true - assert_equal({:controller=>"posts", :action=>"index"}, + mapper.get "/foo", to: "posts#index", as: :main, format: true + assert_equal({ controller: "posts", action: "index" }, fakeset.defaults.first) assert_equal "/foo.:format", fakeset.asts.first.to_s end @@ -67,9 +67,9 @@ module ActionDispatch fakeset = FakeSet.new mapper = Mapper.new fakeset mapper.scope(format: true) do - mapper.get '/foo', :to => 'posts#index', :as => :main + mapper.get "/foo", to: "posts#index", as: :main end - assert_equal({:controller=>"posts", :action=>"index"}, + assert_equal({ controller: "posts", action: "index" }, fakeset.defaults.first) assert_equal "/foo.:format", fakeset.asts.first.to_s end @@ -78,18 +78,18 @@ module ActionDispatch fakeset = FakeSet.new mapper = Mapper.new fakeset mapper.scope(omg: :awesome) do - mapper.get '/', :to => 'posts#index', :as => :main + mapper.get "/", to: "posts#index", as: :main end - assert_equal({:omg=>:awesome, :controller=>"posts", :action=>"index"}, + assert_equal({ omg: :awesome, controller: "posts", action: "index" }, fakeset.defaults.first) assert_equal("GET", fakeset.routes.first.verb) end def test_mapping_requirements - options = { } + options = {} scope = Mapper::Scope.new({}) - ast = Journey::Parser.parse '/store/:name(*rest)' - m = Mapper::Mapping.build(scope, FakeSet.new, ast, 'foo', 'bar', nil, [:get], nil, {}, true, options) + ast = Journey::Parser.parse "/store/:name(*rest)" + m = Mapper::Mapping.build(scope, FakeSet.new, ast, "foo", "bar", nil, [:get], nil, {}, true, options) assert_equal(/.+?/, m.requirements[:rest]) end @@ -97,16 +97,28 @@ module ActionDispatch fakeset = FakeSet.new mapper = Mapper.new fakeset mapper.scope(via: :put) do - mapper.match '/', :to => 'posts#index', :as => :main + mapper.match "/", to: "posts#index", as: :main end assert_equal("PUT", fakeset.routes.first.verb) end + def test_to_scope + fakeset = FakeSet.new + mapper = Mapper.new fakeset + mapper.scope(to: "posts#index") do + mapper.get :all + mapper.post :most + end + + assert_equal "posts#index", fakeset.routes.to_a[0].defaults[:to] + assert_equal "posts#index", fakeset.routes.to_a[1].defaults[:to] + end + def test_map_slash fakeset = FakeSet.new mapper = Mapper.new fakeset - mapper.get '/', :to => 'posts#index', :as => :main - assert_equal '/', fakeset.asts.first.to_s + mapper.get "/", to: "posts#index", as: :main + assert_equal "/", fakeset.asts.first.to_s end def test_map_more_slashes @@ -114,31 +126,31 @@ module ActionDispatch mapper = Mapper.new fakeset # FIXME: is this a desired behavior? - mapper.get '/one/two/', :to => 'posts#index', :as => :main - assert_equal '/one/two(.:format)', fakeset.asts.first.to_s + mapper.get "/one/two/", to: "posts#index", as: :main + assert_equal "/one/two(.:format)", fakeset.asts.first.to_s end def test_map_wildcard fakeset = FakeSet.new mapper = Mapper.new fakeset - mapper.get '/*path', :to => 'pages#show' - assert_equal '/*path(.:format)', fakeset.asts.first.to_s + mapper.get "/*path", to: "pages#show" + assert_equal "/*path(.:format)", fakeset.asts.first.to_s assert_equal(/.+?/, fakeset.requirements.first[:path]) end def test_map_wildcard_with_other_element fakeset = FakeSet.new mapper = Mapper.new fakeset - mapper.get '/*path/foo/:bar', :to => 'pages#show' - assert_equal '/*path/foo/:bar(.:format)', fakeset.asts.first.to_s + mapper.get "/*path/foo/:bar", to: "pages#show" + assert_equal "/*path/foo/:bar(.:format)", fakeset.asts.first.to_s assert_equal(/.+?/, fakeset.requirements.first[:path]) end def test_map_wildcard_with_multiple_wildcard fakeset = FakeSet.new mapper = Mapper.new fakeset - mapper.get '/*foo/*bar', :to => 'pages#show' - assert_equal '/*foo/*bar(.:format)', fakeset.asts.first.to_s + mapper.get "/*foo/*bar", to: "pages#show" + assert_equal "/*foo/*bar(.:format)", fakeset.asts.first.to_s assert_equal(/.+?/, fakeset.requirements.first[:foo]) assert_equal(/.+?/, fakeset.requirements.first[:bar]) end @@ -146,16 +158,16 @@ module ActionDispatch def test_map_wildcard_with_format_false fakeset = FakeSet.new mapper = Mapper.new fakeset - mapper.get '/*path', :to => 'pages#show', :format => false - assert_equal '/*path', fakeset.asts.first.to_s + mapper.get "/*path", to: "pages#show", format: false + assert_equal "/*path", fakeset.asts.first.to_s assert_nil fakeset.requirements.first[:path] end def test_map_wildcard_with_format_true fakeset = FakeSet.new mapper = Mapper.new fakeset - mapper.get '/*path', :to => 'pages#show', :format => true - assert_equal '/*path.:format', fakeset.asts.first.to_s + mapper.get "/*path", to: "pages#show", format: true + assert_equal "/*path.:format", fakeset.asts.first.to_s end def test_raising_error_when_path_is_not_passed diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb index a8c8e0784f..481aa22b10 100644 --- a/actionpack/test/dispatch/middleware_stack_test.rb +++ b/actionpack/test/dispatch/middleware_stack_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class MiddlewareStackTest < ActiveSupport::TestCase class FooMiddleware; end @@ -18,14 +18,6 @@ class MiddlewareStackTest < ActiveSupport::TestCase @stack.use BarMiddleware end - def test_delete_with_string_is_deprecated - assert_deprecated do - assert_difference "@stack.size", -1 do - @stack.delete FooMiddleware.name - end - end - end - def test_delete_works assert_difference "@stack.size", -1 do @stack.delete FooMiddleware @@ -39,30 +31,12 @@ class MiddlewareStackTest < ActiveSupport::TestCase assert_equal BazMiddleware, @stack.last.klass end - test "use should push middleware as a string onto the stack" do - assert_deprecated do - assert_difference "@stack.size" do - @stack.use "MiddlewareStackTest::BazMiddleware" - end - assert_equal BazMiddleware, @stack.last.klass - end - end - - test "use should push middleware as a symbol onto the stack" do - assert_deprecated do - assert_difference "@stack.size" do - @stack.use :"MiddlewareStackTest::BazMiddleware" - end - assert_equal BazMiddleware, @stack.last.klass - end - end - test "use should push middleware class with arguments onto the stack" do assert_difference "@stack.size" do - @stack.use BazMiddleware, true, :foo => "bar" + @stack.use BazMiddleware, true, foo: "bar" end assert_equal BazMiddleware, @stack.last.klass - assert_equal([true, {:foo => "bar"}], @stack.last.args) + assert_equal([true, { foo: "bar" }], @stack.last.args) end test "use should push middleware class with block arguments onto the stack" do @@ -102,15 +76,13 @@ class MiddlewareStackTest < ActiveSupport::TestCase test "swaps one middleware out for same middleware class" do assert_equal FooMiddleware, @stack[0].klass - @stack.swap(FooMiddleware, FooMiddleware, Proc.new { |env| [500, {}, ['error!']] }) + @stack.swap(FooMiddleware, FooMiddleware, Proc.new { |env| [500, {}, ["error!"]] }) assert_equal FooMiddleware, @stack[0].klass end test "unshift adds a new middleware at the beginning of the stack" do - assert_deprecated do - @stack.unshift :"MiddlewareStackTest::BazMiddleware" - assert_equal BazMiddleware, @stack.first.klass - end + @stack.unshift MiddlewareStackTest::BazMiddleware + assert_equal BazMiddleware, @stack.first.klass end test "raise an error on invalid index" do @@ -123,15 +95,6 @@ class MiddlewareStackTest < ActiveSupport::TestCase end end - test "lazy evaluates middleware class" do - assert_deprecated do - assert_difference "@stack.size" do - @stack.use "MiddlewareStackTest::BazMiddleware" - end - assert_equal BazMiddleware, @stack.last.klass - end - end - test "can check if Middleware are equal - Class" do assert_equal @stack.last, BarMiddleware end diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 672b272590..e558efb88d 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' +require "abstract_unit" class MimeTypeTest < ActiveSupport::TestCase test "parse single" do Mime::LOOKUP.each_key do |mime_type| - unless mime_type == 'image/*' + unless mime_type == "image/*" assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type) end end @@ -15,7 +15,7 @@ class MimeTypeTest < ActiveSupport::TestCase begin mime = Mime::Type.register("text/x-mobile", :mobile) assert_equal mime, Mime[:mobile] - assert_equal mime, Mime::Type.lookup('text/x-mobile') + assert_equal mime, Mime::Type.lookup("text/x-mobile") assert_equal mime, Mime::Type.lookup_by_extension(:mobile) Mime::Type.unregister(:mobile) @@ -44,25 +44,25 @@ class MimeTypeTest < ActiveSupport::TestCase accept = "text/*" expect = [Mime[:html], Mime[:text], Mime[:js], Mime[:css], Mime[:ics], Mime[:csv], Mime[:vcf], Mime[:xml], Mime[:yaml], Mime[:json]] parsed = Mime::Type.parse(accept) - assert_equal expect, parsed + assert_equal expect.map(&:to_s).sort!, parsed.map(&:to_s).sort! end test "parse application with trailing star" do accept = "application/*" expect = [Mime[:html], Mime[:js], Mime[:xml], Mime[:rss], Mime[:atom], Mime[:yaml], Mime[:url_encoded_form], Mime[:json], Mime[:pdf], Mime[:zip], Mime[:gzip]] parsed = Mime::Type.parse(accept) - assert_equal expect, parsed + assert_equal expect.map(&:to_s).sort!, parsed.map(&:to_s).sort! end test "parse without q" do accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,application/pdf,*/*" - expect = [Mime[:html], Mime[:xml], Mime[:yaml], Mime[:png], Mime[:text], Mime[:pdf], '*/*'] + expect = [Mime[:html], Mime[:xml], Mime[:yaml], Mime[:png], Mime[:text], Mime[:pdf], "*/*"] assert_equal expect.map(&:to_s), Mime::Type.parse(accept).map(&:to_s) end test "parse with q" do accept = "text/xml,application/xhtml+xml,text/yaml; q=0.3,application/xml,text/html; q=0.8,image/png,text/plain; q=0.5,application/pdf,*/*; q=0.2" - expect = [Mime[:html], Mime[:xml], Mime[:png], Mime[:pdf], Mime[:text], Mime[:yaml], '*/*'] + expect = [Mime[:html], Mime[:xml], Mime[:png], Mime[:pdf], Mime[:text], Mime[:yaml], "*/*"] assert_equal expect.map(&:to_s), Mime::Type.parse(accept).map(&:to_s) end @@ -81,7 +81,7 @@ class MimeTypeTest < ActiveSupport::TestCase # Accept header send with user HTTP_USER_AGENT: Sunrise/0.42j (Windows XP) test "parse broken acceptlines" do accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/*,,*/*;q=0.5" - expect = [Mime[:html], Mime[:xml], "image/*", Mime[:text], '*/*'] + expect = [Mime[:html], Mime[:xml], "image/*", Mime[:text], "*/*"] assert_equal expect.map(&:to_s), Mime::Type.parse(accept).map(&:to_s) end @@ -89,7 +89,7 @@ class MimeTypeTest < ActiveSupport::TestCase # (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1) test "parse other broken acceptlines" do accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, , pronto/1.00.00, sslvpn/1.00.00.00, */*" - expect = ['image/gif', 'image/x-xbitmap', 'image/jpeg','image/pjpeg', 'application/x-shockwave-flash', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/msword', 'pronto/1.00.00', 'sslvpn/1.00.00.00', '*/*'] + expect = ["image/gif", "image/x-xbitmap", "image/jpeg","image/pjpeg", "application/x-shockwave-flash", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/msword", "pronto/1.00.00", "sslvpn/1.00.00.00", "*/*"] assert_equal expect.map(&:to_s), Mime::Type.parse(accept).map(&:to_s) end @@ -141,14 +141,14 @@ class MimeTypeTest < ActiveSupport::TestCase test "register alias" do begin Mime::Type.register_alias "application/xhtml+xml", :foobar - assert_equal Mime[:html], Mime::EXTENSION_LOOKUP['foobar'] + assert_equal Mime[:html], Mime::EXTENSION_LOOKUP["foobar"] ensure Mime::Type.unregister(:foobar) end end test "type should be equal to symbol" do - assert_equal Mime[:html], 'application/xhtml+xml' + assert_equal Mime[:html], "application/xhtml+xml" assert_equal Mime[:html], :html end @@ -167,18 +167,6 @@ class MimeTypeTest < ActiveSupport::TestCase end end - test "deprecated lookup" do - assert_deprecated do - Mime::HTML - end - end - - test "deprecated const_defined?" do - assert_deprecated do - Mime.const_defined? :HTML - end - end - test "references gives preference to symbols before strings" do assert_equal :html, Mime[:html].ref another = Mime::Type.lookup("foo/bar") @@ -192,6 +180,6 @@ class MimeTypeTest < ActiveSupport::TestCase assert Mime[:js] !~ "text/html" assert !(Mime[:js] !~ "text/javascript") assert !(Mime[:js] !~ "application/javascript") - assert Mime[:html] =~ 'application/xhtml+xml' + assert Mime[:html] =~ "application/xhtml+xml" end end diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb index d027f09762..a7d5ba2345 100644 --- a/actionpack/test/dispatch/mount_test.rb +++ b/actionpack/test/dispatch/mount_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'rails/engine' +require "abstract_unit" +require "rails/engine" class TestRoutingMount < ActionDispatch::IntegrationTest Router = ActionDispatch::Routing::RouteSet.new @@ -15,30 +15,30 @@ class TestRoutingMount < ActionDispatch::IntegrationTest def self.routes; Object.new; end def self.call(env) - [200, {"Content-Type" => "text/html"}, ["OK"]] + [200, { "Content-Type" => "text/html" }, ["OK"]] end end Router.draw do SprocketsApp = lambda { |env| - [200, {"Content-Type" => "text/html"}, ["#{env["SCRIPT_NAME"]} -- #{env["PATH_INFO"]}"]] + [200, { "Content-Type" => "text/html" }, ["#{env["SCRIPT_NAME"]} -- #{env["PATH_INFO"]}"]] } - mount SprocketsApp, :at => "/sprockets" + mount SprocketsApp, at: "/sprockets" mount SprocketsApp => "/shorthand" - mount SinatraLikeApp, :at => "/fakeengine", :as => :fake - mount SinatraLikeApp, :at => "/getfake", :via => :get + mount SinatraLikeApp, at: "/fakeengine", as: :fake + mount SinatraLikeApp, at: "/getfake", via: :get scope "/its_a" do - mount SprocketsApp, :at => "/sprocket" + mount SprocketsApp, at: "/sprocket" end resources :users do - mount AppWithRoutes, :at => "/fakeengine", :as => :fake_mounted_at_resource + mount AppWithRoutes, at: "/fakeengine", as: :fake_mounted_at_resource end - mount SprocketsApp, :at => "/", :via => :get + mount SprocketsApp, at: "/", via: :get end APP = RoutedRackApp.new Router @@ -64,7 +64,7 @@ class TestRoutingMount < ActionDispatch::IntegrationTest end def test_mounting_works_with_nested_script_name - get "/foo/sprockets/omg", headers: { 'SCRIPT_NAME' => '/foo', 'PATH_INFO' => '/sprockets/omg' } + get "/foo/sprockets/omg", headers: { "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/sprockets/omg" } assert_equal "/foo/sprockets -- /omg", response.body end diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb index b8f0ffb64a..bb2fc53add 100644 --- a/actionpack/test/dispatch/prefix_generation_test.rb +++ b/actionpack/test/dispatch/prefix_generation_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'rack/test' -require 'rails/engine' +require "abstract_unit" +require "rack/test" +require "rails/engine" module TestGenerationPrefix class Post @@ -26,42 +26,42 @@ module TestGenerationPrefix class BlogEngine < Rails::Engine routes.draw do - get "/posts/:id", :to => "inside_engine_generating#show", :as => :post - get "/posts", :to => "inside_engine_generating#index", :as => :posts - get "/url_to_application", :to => "inside_engine_generating#url_to_application" - get "/polymorphic_path_for_engine", :to => "inside_engine_generating#polymorphic_path_for_engine" - get "/conflicting_url", :to => "inside_engine_generating#conflicting" - get "/foo", :to => "never#invoked", :as => :named_helper_that_should_be_invoked_only_in_respond_to_test - - get "/relative_path_root", :to => redirect("") - get "/relative_path_redirect", :to => redirect("foo") - get "/relative_option_root", :to => redirect(:path => "") - get "/relative_option_redirect", :to => redirect(:path => "foo") - get "/relative_custom_root", :to => redirect { |params, request| "" } - get "/relative_custom_redirect", :to => redirect { |params, request| "foo" } - - get "/absolute_path_root", :to => redirect("/") - get "/absolute_path_redirect", :to => redirect("/foo") - get "/absolute_option_root", :to => redirect(:path => "/") - get "/absolute_option_redirect", :to => redirect(:path => "/foo") - get "/absolute_custom_root", :to => redirect { |params, request| "/" } - get "/absolute_custom_redirect", :to => redirect { |params, request| "/foo" } + get "/posts/:id", to: "inside_engine_generating#show", as: :post + get "/posts", to: "inside_engine_generating#index", as: :posts + get "/url_to_application", to: "inside_engine_generating#url_to_application" + get "/polymorphic_path_for_engine", to: "inside_engine_generating#polymorphic_path_for_engine" + get "/conflicting_url", to: "inside_engine_generating#conflicting" + get "/foo", to: "never#invoked", as: :named_helper_that_should_be_invoked_only_in_respond_to_test + + get "/relative_path_root", to: redirect("") + get "/relative_path_redirect", to: redirect("foo") + get "/relative_option_root", to: redirect(path: "") + get "/relative_option_redirect", to: redirect(path: "foo") + get "/relative_custom_root", to: redirect { |params, request| "" } + get "/relative_custom_redirect", to: redirect { |params, request| "foo" } + + get "/absolute_path_root", to: redirect("/") + get "/absolute_path_redirect", to: redirect("/foo") + get "/absolute_option_root", to: redirect(path: "/") + get "/absolute_option_redirect", to: redirect(path: "/foo") + get "/absolute_custom_root", to: redirect { |params, request| "/" } + get "/absolute_custom_redirect", to: redirect { |params, request| "/foo" } end end class RailsApplication < Rails::Engine routes.draw do - scope "/:omg", :omg => "awesome" do + scope "/:omg", omg: "awesome" do mount BlogEngine => "/blog", :as => "blog_engine" end - get "/posts/:id", :to => "outside_engine_generating#post", :as => :post - get "/generate", :to => "outside_engine_generating#index" - get "/polymorphic_path_for_app", :to => "outside_engine_generating#polymorphic_path_for_app" - get "/polymorphic_path_for_engine", :to => "outside_engine_generating#polymorphic_path_for_engine" - get "/polymorphic_with_url_for", :to => "outside_engine_generating#polymorphic_with_url_for" - get "/conflicting_url", :to => "outside_engine_generating#conflicting" - get "/ivar_usage", :to => "outside_engine_generating#ivar_usage" - root :to => "outside_engine_generating#index" + get "/posts/:id", to: "outside_engine_generating#post", as: :post + get "/generate", to: "outside_engine_generating#index" + get "/polymorphic_path_for_app", to: "outside_engine_generating#polymorphic_path_for_app" + get "/polymorphic_path_for_engine", to: "outside_engine_generating#polymorphic_path_for_engine" + get "/polymorphic_with_url_for", to: "outside_engine_generating#polymorphic_with_url_for" + get "/conflicting_url", to: "outside_engine_generating#conflicting" + get "/ivar_usage", to: "outside_engine_generating#ivar_usage" + root to: "outside_engine_generating#index" end end @@ -81,9 +81,9 @@ module TestGenerationPrefix end def url_to_application - path = main_app.url_for(:controller => "outside_engine_generating", - :action => "index", - :only_path => true) + path = main_app.url_for(controller: "outside_engine_generating", + action: "index", + only_path: true) render plain: path end @@ -238,7 +238,7 @@ module TestGenerationPrefix end test "[APP] generating engine's route includes default_url_options[:script_name]" do - RailsApplication.routes.default_url_options = {:script_name => "/something"} + RailsApplication.routes.default_url_options = { script_name: "/something" } get "/generate" assert_equal "/something/awesome/blog/posts/1", last_response.body end @@ -269,16 +269,16 @@ module TestGenerationPrefix end test "[OBJECT] generating engine's route includes prefix" do - assert_equal "/awesome/blog/posts/1", engine_object.post_path(:id => 1) + assert_equal "/awesome/blog/posts/1", engine_object.post_path(id: 1) end test "[OBJECT] generating engine's route includes dynamic prefix" do - assert_equal "/pure-awesomeness/blog/posts/3", engine_object.post_path(:id => 3, :omg => "pure-awesomeness") + assert_equal "/pure-awesomeness/blog/posts/3", engine_object.post_path(id: 3, omg: "pure-awesomeness") end test "[OBJECT] generating engine's route includes default_url_options[:script_name]" do - RailsApplication.routes.default_url_options = {:script_name => "/something"} - assert_equal "/something/pure-awesomeness/blog/posts/3", engine_object.post_path(:id => 3, :omg => "pure-awesomeness") + RailsApplication.routes.default_url_options = { script_name: "/something" } + assert_equal "/something/pure-awesomeness/blog/posts/3", engine_object.post_path(id: 3, omg: "pure-awesomeness") end test "[OBJECT] generating application's route" do @@ -286,7 +286,7 @@ module TestGenerationPrefix end test "[OBJECT] generating application's route includes default_url_options[:script_name]" do - RailsApplication.routes.default_url_options = {:script_name => "/something"} + RailsApplication.routes.default_url_options = { script_name: "/something" } assert_equal "/something/", app_object.root_path end @@ -296,11 +296,11 @@ module TestGenerationPrefix end test "[OBJECT] generating engine's route with url_for" do - path = engine_object.url_for(:controller => "inside_engine_generating", - :action => "show", - :only_path => true, - :omg => "omg", - :id => 1) + path = engine_object.url_for(controller: "inside_engine_generating", + action: "show", + only_path: true, + omg: "omg", + id: 1) assert_equal "/omg/blog/posts/1", path end @@ -308,7 +308,7 @@ module TestGenerationPrefix path = engine_object.posts_path assert_equal "/awesome/blog/posts", path - path = engine_object.posts_url(:host => "example.com") + path = engine_object.posts_url(host: "example.com") assert_equal "http://example.com/awesome/blog/posts", path end @@ -316,7 +316,7 @@ module TestGenerationPrefix path = engine_object.polymorphic_path(Post.new) assert_equal "/awesome/blog/posts/1", path - path = engine_object.polymorphic_url(Post.new, :host => "www.example.com") + path = engine_object.polymorphic_url(Post.new, host: "www.example.com") assert_equal "http://www.example.com/awesome/blog/posts/1", path end @@ -340,21 +340,21 @@ module TestGenerationPrefix @routes ||= begin routes = ActionDispatch::Routing::RouteSet.new routes.draw do - get "/posts/:id", :to => "posts#show", :as => :post - - get "/relative_path_root", :to => redirect("") - get "/relative_path_redirect", :to => redirect("foo") - get "/relative_option_root", :to => redirect(:path => "") - get "/relative_option_redirect", :to => redirect(:path => "foo") - get "/relative_custom_root", :to => redirect { |params, request| "" } - get "/relative_custom_redirect", :to => redirect { |params, request| "foo" } - - get "/absolute_path_root", :to => redirect("/") - get "/absolute_path_redirect", :to => redirect("/foo") - get "/absolute_option_root", :to => redirect(:path => "/") - get "/absolute_option_redirect", :to => redirect(:path => "/foo") - get "/absolute_custom_root", :to => redirect { |params, request| "/" } - get "/absolute_custom_redirect", :to => redirect { |params, request| "/foo" } + get "/posts/:id", to: "posts#show", as: :post + + get "/relative_path_root", to: redirect("") + get "/relative_path_redirect", to: redirect("foo") + get "/relative_option_root", to: redirect(path: "") + get "/relative_option_redirect", to: redirect(path: "foo") + get "/relative_custom_root", to: redirect { |params, request| "" } + get "/relative_custom_redirect", to: redirect { |params, request| "foo" } + + get "/absolute_path_root", to: redirect("/") + get "/absolute_path_redirect", to: redirect("/foo") + get "/absolute_option_root", to: redirect(path: "/") + get "/absolute_option_redirect", to: redirect(path: "/foo") + get "/absolute_custom_root", to: redirect { |params, request| "/" } + get "/absolute_custom_redirect", to: redirect { |params, request| "/foo" } end routes @@ -362,7 +362,7 @@ module TestGenerationPrefix end def self.call(env) - env['action_dispatch.routes'] = routes + env["action_dispatch.routes"] = routes routes.call(env) end end diff --git a/actionpack/test/dispatch/rack_cache_test.rb b/actionpack/test/dispatch/rack_cache_test.rb index 79d8a64d29..d7bb90abbf 100644 --- a/actionpack/test/dispatch/rack_cache_test.rb +++ b/actionpack/test/dispatch/rack_cache_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_dispatch/http/rack_cache' +require "abstract_unit" +require "action_dispatch/http/rack_cache" class RackCacheMetaStoreTest < ActiveSupport::TestCase class ReadWriteHash < ::Hash @@ -12,7 +12,7 @@ class RackCacheMetaStoreTest < ActiveSupport::TestCase end test "stuff is deep duped" do - @store.write(:foo, { :bar => :original }) + @store.write(:foo, bar: :original) hash = @store.read(:foo) hash[:bar] = :changed hash = @store.read(:foo) diff --git a/actionpack/test/dispatch/reloader_test.rb b/actionpack/test/dispatch/reloader_test.rb index fe8a4a3a17..e74b8e40fd 100644 --- a/actionpack/test/dispatch/reloader_test.rb +++ b/actionpack/test/dispatch/reloader_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ReloaderTest < ActiveSupport::TestCase Reloader = ActionDispatch::Reloader @@ -166,7 +166,7 @@ class ReloaderTest < ActiveSupport::TestCase i = 10 assert_deprecated do Reloader.to_prepare { i += 1 } - Reloader.to_prepare(:prepend => true) { i = 0 } + Reloader.to_prepare(prepend: true) { i = 0 } end assert_deprecated do @@ -196,8 +196,8 @@ class ReloaderTest < ActiveSupport::TestCase x = Class.new(ActiveSupport::Reloader) x.check = lambda { true } - @response ||= 'response' - @reloader ||= Reloader.new(block || proc {[200, {}, @response]}, x) - @reloader.call({'rack.input' => StringIO.new('')})[2] + @response ||= "response" + @reloader ||= Reloader.new(block || proc { [200, {}, @response] }, x) + @reloader.call("rack.input" => StringIO.new(""))[2] end end diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index a07138b55e..10234a4815 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class JsonParamsParsingTest < ActionDispatch::IntegrationTest class TestController < ActionController::Base @@ -18,44 +18,44 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest test "parses json params for application json" do assert_parses( - {"person" => {"name" => "David"}}, - "{\"person\": {\"name\": \"David\"}}", { 'CONTENT_TYPE' => 'application/json' } + { "person" => { "name" => "David" } }, + "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/json" ) end test "parses boolean and number json params for application json" do assert_parses( - {"item" => {"enabled" => false, "count" => 10}}, - "{\"item\": {\"enabled\": false, \"count\": 10}}", { 'CONTENT_TYPE' => 'application/json' } + { "item" => { "enabled" => false, "count" => 10 } }, + "{\"item\": {\"enabled\": false, \"count\": 10}}", "CONTENT_TYPE" => "application/json" ) end test "parses json params for application jsonrequest" do assert_parses( - {"person" => {"name" => "David"}}, - "{\"person\": {\"name\": \"David\"}}", { 'CONTENT_TYPE' => 'application/jsonrequest' } + { "person" => { "name" => "David" } }, + "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/jsonrequest" ) end test "does not parse unregistered media types such as application/vnd.api+json" do assert_parses( {}, - "{\"person\": {\"name\": \"David\"}}", { 'CONTENT_TYPE' => 'application/vnd.api+json' } + "{\"person\": {\"name\": \"David\"}}", "CONTENT_TYPE" => "application/vnd.api+json" ) end test "nils are stripped from collections" do assert_parses( - {"person" => []}, - "{\"person\":[null]}", { 'CONTENT_TYPE' => 'application/json' } + { "person" => [] }, + "{\"person\":[null]}", "CONTENT_TYPE" => "application/json" ) assert_parses( - {"person" => ['foo']}, - "{\"person\":[\"foo\",null]}", { 'CONTENT_TYPE' => 'application/json' } + { "person" => ["foo"] }, + "{\"person\":[\"foo\",null]}", "CONTENT_TYPE" => "application/json" ) assert_parses( - {"person" => []}, - "{\"person\":[null, null]}", { 'CONTENT_TYPE' => 'application/json' } + { "person" => [] }, + "{\"person\":[null, null]}", "CONTENT_TYPE" => "application/json" ) end @@ -63,7 +63,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest with_test_routing do output = StringIO.new json = "[\"person]\": {\"name\": \"David\"}}" - post "/parse", params: json, headers: { 'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => ActiveSupport::Logger.new(output) } + post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => ActiveSupport::Logger.new(output) } assert_response :bad_request output.rewind && err = output.read assert err =~ /Error occurred while parsing request parameters/ @@ -75,7 +75,9 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest begin $stderr = StringIO.new # suppress the log json = "[\"person]\": {\"name\": \"David\"}}" - exception = assert_raise(ActionDispatch::ParamsParser::ParseError) { post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => false} } + exception = assert_raise(ActionDispatch::Http::Parameters::ParseError) do + post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => false } + end assert_equal JSON::ParserError, exception.cause.class assert_equal exception.cause.message, exception.message ensure @@ -84,9 +86,9 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest end end - test 'raw_post is not empty for JSON request' do + test "raw_post is not empty for JSON request" do with_test_routing do - post '/parse', params: '{"posts": [{"title": "Post Title"}]}', headers: { 'CONTENT_TYPE' => 'application/json' } + post "/parse", params: '{"posts": [{"title": "Post Title"}]}', headers: { "CONTENT_TYPE" => "application/json" } assert_equal '{"posts": [{"title": "Post Title"}]}', request.raw_post end end @@ -104,7 +106,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - post ':action', :to => ::JsonParamsParsingTest::TestController + post ":action", to: ::JsonParamsParsingTest::TestController end end yield @@ -114,7 +116,7 @@ end class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest class UsersController < ActionController::Base - wrap_parameters :format => :json + wrap_parameters format: :json class << self attr_accessor :last_request_parameters, :last_parameters @@ -133,32 +135,32 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest test "parses json params for application json" do assert_parses( - {"user" => {"username" => "sikachu"}, "username" => "sikachu"}, - "{\"username\": \"sikachu\"}", { 'CONTENT_TYPE' => 'application/json' } + { "user" => { "username" => "sikachu" }, "username" => "sikachu" }, + "{\"username\": \"sikachu\"}", "CONTENT_TYPE" => "application/json" ) end test "parses json params for application jsonrequest" do assert_parses( - {"user" => {"username" => "sikachu"}, "username" => "sikachu"}, - "{\"username\": \"sikachu\"}", { 'CONTENT_TYPE' => 'application/jsonrequest' } + { "user" => { "username" => "sikachu" }, "username" => "sikachu" }, + "{\"username\": \"sikachu\"}", "CONTENT_TYPE" => "application/jsonrequest" ) end test "parses json with non-object JSON content" do assert_parses( - {"user" => {"_json" => "string content" }, "_json" => "string content" }, - "\"string content\"", { 'CONTENT_TYPE' => 'application/json' } + { "user" => { "_json" => "string content" }, "_json" => "string content" }, + "\"string content\"", "CONTENT_TYPE" => "application/json" ) end test "parses json params after custom json mime type registered" do begin Mime::Type.unregister :json - Mime::Type.register "application/json", :json, %w(application/vnd.api+json) + Mime::Type.register "application/json", :json, %w(application/vnd.rails+json) assert_parses( - {"user" => {"username" => "meinac"}, "username" => "meinac"}, - "{\"username\": \"meinac\"}", { 'CONTENT_TYPE' => 'application/json' } + { "user" => { "username" => "meinac" }, "username" => "meinac" }, + "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/json" ) ensure Mime::Type.unregister :json @@ -169,10 +171,10 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest test "parses json params after custom json mime type registered with synonym" do begin Mime::Type.unregister :json - Mime::Type.register "application/json", :json, %w(application/vnd.api+json) + Mime::Type.register "application/json", :json, %w(application/vnd.rails+json) assert_parses( - {"user" => {"username" => "meinac"}, "username" => "meinac"}, - "{\"username\": \"meinac\"}", { 'CONTENT_TYPE' => 'application/vnd.api+json' } + { "user" => { "username" => "meinac" }, "username" => "meinac" }, + "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/vnd.rails+json" ) ensure Mime::Type.unregister :json @@ -186,7 +188,7 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest post "/parse", params: actual, headers: headers assert_response :ok assert_equal(expected, UsersController.last_request_parameters) - assert_equal(expected.merge({"action" => "parse"}), UsersController.last_parameters) + assert_equal(expected.merge("action" => "parse"), UsersController.last_parameters) end end @@ -194,7 +196,7 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - post ':action', :to => controller + post ":action", to: controller end end yield diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index bab4413b2a..eb4bb14ed1 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class MultipartParamsParsingTest < ActionDispatch::IntegrationTest class TestController < ActionController::Base @@ -21,136 +21,136 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest end end - FIXTURE_PATH = File.dirname(__FILE__) + '/../../fixtures/multipart' + FIXTURE_PATH = File.dirname(__FILE__) + "/../../fixtures/multipart" def teardown TestController.last_request_parameters = nil end test "parses single parameter" do - assert_equal({ 'foo' => 'bar' }, parse_multipart('single_parameter')) + assert_equal({ "foo" => "bar" }, parse_multipart("single_parameter")) end test "parses bracketed parameters" do - assert_equal({ 'foo' => { 'baz' => 'bar'}}, parse_multipart('bracketed_param')) + assert_equal({ "foo" => { "baz" => "bar" } }, parse_multipart("bracketed_param")) end test "parse single utf8 parameter" do - assert_equal({ 'Iñtërnâtiônà lizætiøn_name' => 'Iñtërnâtiônà lizætiøn_value'}, - parse_multipart('single_utf8_param'), "request.request_parameters") + assert_equal({ "Iñtërnâtiônà lizætiøn_name" => "Iñtërnâtiônà lizætiøn_value" }, + parse_multipart("single_utf8_param"), "request.request_parameters") assert_equal( - 'Iñtërnâtiônà lizætiøn_value', - TestController.last_parameters['Iñtërnâtiônà lizætiøn_name'], "request.parameters") + "Iñtërnâtiônà lizætiøn_value", + TestController.last_parameters["Iñtërnâtiônà lizætiøn_name"], "request.parameters") end test "parse bracketed utf8 parameter" do - assert_equal({ 'Iñtërnâtiônà lizætiøn_name' => { - 'Iñtërnâtiônà lizætiøn_nested_name' => 'Iñtërnâtiônà lizætiøn_value'} }, - parse_multipart('bracketed_utf8_param'), "request.request_parameters") + assert_equal({ "Iñtërnâtiônà lizætiøn_name" => { + "Iñtërnâtiônà lizætiøn_nested_name" => "Iñtërnâtiônà lizætiøn_value" } }, + parse_multipart("bracketed_utf8_param"), "request.request_parameters") assert_equal( - {'Iñtërnâtiônà lizætiøn_nested_name' => 'Iñtërnâtiônà lizætiøn_value'}, - TestController.last_parameters['Iñtërnâtiônà lizætiøn_name'], "request.parameters") + { "Iñtërnâtiônà lizætiøn_nested_name" => "Iñtërnâtiônà lizætiøn_value" }, + TestController.last_parameters["Iñtërnâtiônà lizætiøn_name"], "request.parameters") end test "parses text file" do - params = parse_multipart('text_file') + params = parse_multipart("text_file") assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] + assert_equal "bar", params["foo"] - file = params['file'] - assert_equal 'file.txt', file.original_filename + file = params["file"] + assert_equal "file.txt", file.original_filename assert_equal "text/plain", file.content_type - assert_equal 'contents', file.read + assert_equal "contents", file.read end test "parses utf8 filename with percent character" do - params = parse_multipart('utf8_filename') + params = parse_multipart("utf8_filename") assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] + assert_equal "bar", params["foo"] - file = params['file'] - assert_equal 'ファイル%å.txt', file.original_filename + file = params["file"] + assert_equal "ファイル%å.txt", file.original_filename assert_equal "text/plain", file.content_type - assert_equal 'contents', file.read + assert_equal "contents", file.read end test "parses boundary problem file" do - params = parse_multipart('boundary_problem_file') + params = parse_multipart("boundary_problem_file") assert_equal %w(file foo), params.keys.sort - file = params['file'] - foo = params['foo'] + file = params["file"] + foo = params["foo"] - assert_equal 'file.txt', file.original_filename + assert_equal "file.txt", file.original_filename assert_equal "text/plain", file.content_type - assert_equal 'bar', foo + assert_equal "bar", foo end test "parses large text file" do - params = parse_multipart('large_text_file') + params = parse_multipart("large_text_file") assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] + assert_equal "bar", params["foo"] - file = params['file'] + file = params["file"] - assert_equal 'file.txt', file.original_filename + assert_equal "file.txt", file.original_filename assert_equal "text/plain", file.content_type - assert_equal(('a' * 20480), file.read) + assert_equal(("a" * 20480), file.read) end test "parses binary file" do - params = parse_multipart('binary_file') + params = parse_multipart("binary_file") assert_equal %w(file flowers foo), params.keys.sort - assert_equal 'bar', params['foo'] + assert_equal "bar", params["foo"] - file = params['file'] - assert_equal 'file.csv', file.original_filename + file = params["file"] + assert_equal "file.csv", file.original_filename assert_nil file.content_type - assert_equal 'contents', file.read + assert_equal "contents", file.read - file = params['flowers'] - assert_equal 'flowers.jpg', file.original_filename + file = params["flowers"] + assert_equal "flowers.jpg", file.original_filename assert_equal "image/jpeg", file.content_type assert_equal 19512, file.size end test "parses mixed files" do - params = parse_multipart('mixed_files') + params = parse_multipart("mixed_files") assert_equal %w(files foo), params.keys.sort - assert_equal 'bar', params['foo'] + assert_equal "bar", params["foo"] # Rack doesn't handle multipart/mixed for us. - files = params['files'] + files = params["files"] assert_equal 19756, files.bytesize end test "does not create tempfile if no file has been selected" do - params = parse_multipart('none') + params = parse_multipart("none") assert_equal %w(submit-name), params.keys.sort - assert_equal 'Larry', params['submit-name'] - assert_equal nil, params['files'] + assert_equal "Larry", params["submit-name"] + assert_equal nil, params["files"] end test "parses empty upload file" do - params = parse_multipart('empty') + params = parse_multipart("empty") assert_equal %w(files submit-name), params.keys.sort - assert_equal 'Larry', params['submit-name'] - assert params['files'] - assert_equal "", params['files'].read + assert_equal "Larry", params["submit-name"] + assert params["files"] + assert_equal "", params["files"].read end test "uploads and reads binary file" do with_test_routing do - fixture = FIXTURE_PATH + "/mona_lisa.jpg" - params = { :uploaded_data => fixture_file_upload(fixture, "image/jpg") } - post '/read', params: params + fixture = FIXTURE_PATH + "/ruby_on_rails.jpg" + params = { uploaded_data: fixture_file_upload(fixture, "image/jpg") } + post "/read", params: params end end test "uploads and reads file" do with_test_routing do - post '/read', params: { uploaded_data: fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") } + post "/read", params: { uploaded_data: fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") } assert_equal "File: Hello", response.body end end @@ -160,7 +160,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':action', controller: 'multipart_params_parsing_test/test' + get ":action", controller: "multipart_params_parsing_test/test" end end headers = { "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" } @@ -171,7 +171,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest private def fixture(name) - File.open(File.join(FIXTURE_PATH, name), 'rb') do |file| + File.open(File.join(FIXTURE_PATH, name), "rb") do |file| { "rack.input" => file.read, "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x", "CONTENT_LENGTH" => file.stat.size.to_s } @@ -191,7 +191,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - post ':action', :controller => 'multipart_params_parsing_test/test' + post ":action", controller: "multipart_params_parsing_test/test" end end yield diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb index f04022a544..5c992be216 100644 --- a/actionpack/test/dispatch/request/query_string_parsing_test.rb +++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class QueryStringParsingTest < ActionDispatch::IntegrationTest class TestController < ActionController::Base @@ -29,92 +29,92 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest test "query string" do assert_parses( - {"action" => "create_customer", "full_name" => "David Heinemeier Hansson", "customerId" => "1"}, + { "action" => "create_customer", "full_name" => "David Heinemeier Hansson", "customerId" => "1" }, "action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1" ) end test "deep query string" do assert_parses( - {'x' => {'y' => {'z' => '10'}}}, + { "x" => { "y" => { "z" => "10" } } }, "x[y][z]=10" ) end test "deep query string with array" do - assert_parses({'x' => {'y' => {'z' => ['10']}}}, 'x[y][z][]=10') - assert_parses({'x' => {'y' => {'z' => ['10', '5']}}}, 'x[y][z][]=10&x[y][z][]=5') + assert_parses({ "x" => { "y" => { "z" => ["10"] } } }, "x[y][z][]=10") + assert_parses({ "x" => { "y" => { "z" => ["10", "5"] } } }, "x[y][z][]=10&x[y][z][]=5") end test "deep query string with array of hash" do - assert_parses({'x' => {'y' => [{'z' => '10'}]}}, 'x[y][][z]=10') - assert_parses({'x' => {'y' => [{'z' => '10', 'w' => '10'}]}}, 'x[y][][z]=10&x[y][][w]=10') - assert_parses({'x' => {'y' => [{'z' => '10', 'v' => {'w' => '10'}}]}}, 'x[y][][z]=10&x[y][][v][w]=10') + assert_parses({ "x" => { "y" => [{ "z" => "10" }] } }, "x[y][][z]=10") + assert_parses({ "x" => { "y" => [{ "z" => "10", "w" => "10" }] } }, "x[y][][z]=10&x[y][][w]=10") + assert_parses({ "x" => { "y" => [{ "z" => "10", "v" => { "w" => "10" } }] } }, "x[y][][z]=10&x[y][][v][w]=10") end test "deep query string with array of hashes with one pair" do - assert_parses({'x' => {'y' => [{'z' => '10'}, {'z' => '20'}]}}, 'x[y][][z]=10&x[y][][z]=20') + assert_parses({ "x" => { "y" => [{ "z" => "10" }, { "z" => "20" }] } }, "x[y][][z]=10&x[y][][z]=20") end test "deep query string with array of hashes with multiple pairs" do assert_parses( - {'x' => {'y' => [{'z' => '10', 'w' => 'a'}, {'z' => '20', 'w' => 'b'}]}}, - 'x[y][][z]=10&x[y][][w]=a&x[y][][z]=20&x[y][][w]=b' + { "x" => { "y" => [{ "z" => "10", "w" => "a" }, { "z" => "20", "w" => "b" }] } }, + "x[y][][z]=10&x[y][][w]=a&x[y][][z]=20&x[y][][w]=b" ) end test "query string with nil" do assert_parses( - { "action" => "create_customer", "full_name" => ''}, + { "action" => "create_customer", "full_name" => "" }, "action=create_customer&full_name=" ) end test "query string with array" do assert_parses( - { "action" => "create_customer", "selected" => ["1", "2", "3"]}, + { "action" => "create_customer", "selected" => ["1", "2", "3"] }, "action=create_customer&selected[]=1&selected[]=2&selected[]=3" ) end test "query string with amps" do assert_parses( - { "action" => "create_customer", "name" => "Don't & Does"}, + { "action" => "create_customer", "name" => "Don't & Does" }, "action=create_customer&name=Don%27t+%26+Does" ) end test "query string with many equal" do assert_parses( - { "action" => "create_customer", "full_name" => "abc=def=ghi"}, + { "action" => "create_customer", "full_name" => "abc=def=ghi" }, "action=create_customer&full_name=abc=def=ghi" ) end test "query string without equal" do - assert_parses({"action" => nil}, "action") - assert_parses({"action" => {"foo" => nil}}, "action[foo]") - assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar]") - assert_parses({"action" => {"foo" => { "bar" => [] }}}, "action[foo][bar][]") - assert_parses({"action" => {"foo" => [] }}, "action[foo][]") - assert_parses({"action"=>{"foo"=>[{"bar"=>nil}]}}, "action[foo][][bar]") + assert_parses({ "action" => nil }, "action") + assert_parses({ "action" => { "foo" => nil } }, "action[foo]") + assert_parses({ "action" => { "foo" => { "bar" => nil } } }, "action[foo][bar]") + assert_parses({ "action" => { "foo" => { "bar" => [] } } }, "action[foo][bar][]") + assert_parses({ "action" => { "foo" => [] } }, "action[foo][]") + assert_parses({ "action"=>{ "foo"=>[{ "bar"=>nil }] } }, "action[foo][][bar]") end def test_array_parses_without_nil - assert_parses({"action" => ['1']}, "action[]=1&action[]") + assert_parses({ "action" => ["1"] }, "action[]=1&action[]") end test "perform_deep_munge" do old_perform_deep_munge = ActionDispatch::Request::Utils.perform_deep_munge ActionDispatch::Request::Utils.perform_deep_munge = false begin - assert_parses({"action" => nil}, "action") - assert_parses({"action" => {"foo" => nil}}, "action[foo]") - assert_parses({"action" => {"foo" => {"bar" => nil}}}, "action[foo][bar]") - assert_parses({"action" => {"foo" => {"bar" => [nil]}}}, "action[foo][bar][]") - assert_parses({"action" => {"foo" => [nil]}}, "action[foo][]") - assert_parses({"action" => {"foo" => [{"bar" => nil}]}}, "action[foo][][bar]") - assert_parses({"action" => ['1',nil]}, "action[]=1&action[]") + assert_parses({ "action" => nil }, "action") + assert_parses({ "action" => { "foo" => nil } }, "action[foo]") + assert_parses({ "action" => { "foo" => { "bar" => nil } } }, "action[foo][bar]") + assert_parses({ "action" => { "foo" => { "bar" => [nil] } } }, "action[foo][bar][]") + assert_parses({ "action" => { "foo" => [nil] } }, "action[foo][]") + assert_parses({ "action" => { "foo" => [{ "bar" => nil }] } }, "action[foo][][bar]") + assert_parses({ "action" => ["1",nil] }, "action[]=1&action[]") ensure ActionDispatch::Request::Utils.perform_deep_munge = old_perform_deep_munge end @@ -129,14 +129,14 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest test "query string with many ampersands" do assert_parses( - { "action" => "create_customer", "full_name" => "David Heinemeier Hansson"}, + { "action" => "create_customer", "full_name" => "David Heinemeier Hansson" }, "&action=create_customer&&&full_name=David%20Heinemeier%20Hansson" ) end test "unbalanced query string with array" do assert_parses( - {'location' => ["1", "2"], 'age_group' => ["2"]}, + { "location" => ["1", "2"], "age_group" => ["2"] }, "location[]=1&location[]=2&age_group[]=2" ) end @@ -145,7 +145,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':action', :to => ::QueryStringParsingTest::TestController + get ":action", to: ::QueryStringParsingTest::TestController end end @@ -159,7 +159,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':action', :to => ::QueryStringParsingTest::TestController + get ":action", to: ::QueryStringParsingTest::TestController end end @app = self.class.build_app(set) do |middleware| diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb index e022e7e21e..311b80ea0a 100644 --- a/actionpack/test/dispatch/request/session_test.rb +++ b/actionpack/test/dispatch/request/session_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_dispatch/middleware/session/abstract_store' +require "abstract_unit" +require "action_dispatch/middleware/session/abstract_store" module ActionDispatch class Request @@ -17,18 +17,18 @@ module ActionDispatch def test_to_hash s = Session.create(store, req, {}) - s['foo'] = 'bar' - assert_equal 'bar', s['foo'] - assert_equal({'foo' => 'bar'}, s.to_hash) + s["foo"] = "bar" + assert_equal "bar", s["foo"] + assert_equal({ "foo" => "bar" }, s.to_hash) end def test_create_merges_old s = Session.create(store, req, {}) - s['foo'] = 'bar' + s["foo"] = "bar" s1 = Session.create(store, req, {}) assert_not_equal s, s1 - assert_equal 'bar', s1['foo'] + assert_equal "bar", s1["foo"] end def test_find @@ -40,7 +40,7 @@ module ActionDispatch def test_destroy s = Session.create(store, req, {}) - s['rails'] = 'ftw' + s["rails"] = "ftw" s.destroy @@ -49,22 +49,22 @@ module ActionDispatch def test_keys s = Session.create(store, req, {}) - s['rails'] = 'ftw' - s['adequate'] = 'awesome' + s["rails"] = "ftw" + s["adequate"] = "awesome" assert_equal %w[rails adequate], s.keys end def test_values s = Session.create(store, req, {}) - s['rails'] = 'ftw' - s['adequate'] = 'awesome' + s["rails"] = "ftw" + s["adequate"] = "awesome" assert_equal %w[ftw awesome], s.values end def test_clear s = Session.create(store, req, {}) - s['rails'] = 'ftw' - s['adequate'] = 'awesome' + s["rails"] = "ftw" + s["adequate"] = "awesome" s.clear assert_empty(s.values) @@ -72,19 +72,19 @@ module ActionDispatch def test_update s = Session.create(store, req, {}) - s['rails'] = 'ftw' + s["rails"] = "ftw" - s.update(:rails => 'awesome') + s.update(rails: "awesome") - assert_equal(['rails'], s.keys) - assert_equal('awesome', s['rails']) + assert_equal(["rails"], s.keys) + assert_equal("awesome", s["rails"]) end def test_delete s = Session.create(store, req, {}) - s['rails'] = 'ftw' + s["rails"] = "ftw" - s.delete('rails') + s.delete("rails") assert_empty(s.keys) end @@ -92,13 +92,13 @@ module ActionDispatch def test_fetch session = Session.create(store, req, {}) - session['one'] = '1' - assert_equal '1', session.fetch(:one) + session["one"] = "1" + assert_equal "1", session.fetch(:one) - assert_equal '2', session.fetch(:two, '2') + assert_equal "2", session.fetch(:two, "2") assert_nil session.fetch(:two, nil) - assert_equal 'three', session.fetch(:three) {|el| el.to_s } + assert_equal "three", session.fetch(:three) { |el| el.to_s } assert_raise KeyError do session.fetch(:three) @@ -106,27 +106,27 @@ module ActionDispatch end private - def store - Class.new { - def load_session(env); [1, {}]; end - def session_exists?(env); true; end - def delete_session(env, id, options); 123; end - }.new - end + def store + Class.new { + def load_session(env); [1, {}]; end + def session_exists?(env); true; end + def delete_session(env, id, options); 123; end + }.new + end end class SessionIntegrationTest < ActionDispatch::IntegrationTest class MySessionApp def call(env) request = Rack::Request.new(env) - request.session['hello'] = 'Hello from MySessionApp!' - [ 200, {}, ['Hello from MySessionApp!'] ] + request.session["hello"] = "Hello from MySessionApp!" + [ 200, {}, ["Hello from MySessionApp!"] ] end end Router = ActionDispatch::Routing::RouteSet.new Router.draw do - get '/mysessionapp' => MySessionApp.new + get "/mysessionapp" => MySessionApp.new end def app @@ -134,10 +134,10 @@ module ActionDispatch end def test_session_follows_rack_api_contract_1 - get '/mysessionapp' + get "/mysessionapp" assert_response :ok - assert_equal 'Hello from MySessionApp!', @response.body - assert_equal 'Hello from MySessionApp!', session['hello'] + assert_equal "Hello from MySessionApp!", @response.body + assert_equal "Hello from MySessionApp!", session["hello"] end end end diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index b9f8c52378..5c7558e48d 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest class TestController < ActionController::Base @@ -18,7 +18,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest test "parses unbalanced query string with array" do query = "location[]=1&location[]=2&age_group[]=2" - expected = { 'location' => ["1", "2"], 'age_group' => ["2"] } + expected = { "location" => ["1", "2"], "age_group" => ["2"] } assert_parses expected, query end @@ -141,7 +141,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - post ':action', to: ::UrlEncodedParamsParsingTest::TestController + post ":action", to: ::UrlEncodedParamsParsingTest::TestController end end yield diff --git a/actionpack/test/dispatch/request_id_test.rb b/actionpack/test/dispatch/request_id_test.rb index 00d8caf8f4..4fcd45acf5 100644 --- a/actionpack/test/dispatch/request_id_test.rb +++ b/actionpack/test/dispatch/request_id_test.rb @@ -1,16 +1,16 @@ -require 'abstract_unit' +require "abstract_unit" class RequestIdTest < ActiveSupport::TestCase test "passing on the request id from the outside" do - assert_equal "external-uu-rid", stub_request('HTTP_X_REQUEST_ID' => 'external-uu-rid').request_id + assert_equal "external-uu-rid", stub_request("HTTP_X_REQUEST_ID" => "external-uu-rid").request_id end test "ensure that only alphanumeric uurids are accepted" do - assert_equal "X-Hacked-HeaderStuff", stub_request('HTTP_X_REQUEST_ID' => '; X-Hacked-Header: Stuff').request_id + assert_equal "X-Hacked-HeaderStuff", stub_request("HTTP_X_REQUEST_ID" => "; X-Hacked-Header: Stuff").request_id end test "ensure that 255 char limit on the request id is being enforced" do - assert_equal "X" * 255, stub_request('HTTP_X_REQUEST_ID' => 'X' * 500).request_id + assert_equal "X" * 255, stub_request("HTTP_X_REQUEST_ID" => "X" * 500).request_id end test "generating a request id when none is supplied" do @@ -18,15 +18,15 @@ class RequestIdTest < ActiveSupport::TestCase end test "uuid alias" do - assert_equal "external-uu-rid", stub_request('HTTP_X_REQUEST_ID' => 'external-uu-rid').uuid + assert_equal "external-uu-rid", stub_request("HTTP_X_REQUEST_ID" => "external-uu-rid").uuid end private - def stub_request(env = {}) - ActionDispatch::RequestId.new(lambda { |environment| [ 200, environment, [] ] }).call(env) - ActionDispatch::Request.new(env) - end + def stub_request(env = {}) + ActionDispatch::RequestId.new(lambda { |environment| [ 200, environment, [] ] }).call(env) + ActionDispatch::Request.new(env) + end end class RequestIdResponseTest < ActionDispatch::IntegrationTest @@ -38,32 +38,31 @@ class RequestIdResponseTest < ActionDispatch::IntegrationTest test "request id is passed all the way to the response" do with_test_route_set do - get '/' + get "/" assert_match(/\w+/, @response.headers["X-Request-Id"]) end end test "request id given on request is passed all the way to the response" do with_test_route_set do - get '/', headers: { 'HTTP_X_REQUEST_ID' => 'X' * 500 } + get "/", headers: { "HTTP_X_REQUEST_ID" => "X" * 500 } assert_equal "X" * 255, @response.headers["X-Request-Id"] end end - private - def with_test_route_set - with_routing do |set| - set.draw do - get '/', :to => ::RequestIdResponseTest::TestController.action(:index) - end + def with_test_route_set + with_routing do |set| + set.draw do + get "/", to: ::RequestIdResponseTest::TestController.action(:index) + end - @app = self.class.build_app(set) do |middleware| - middleware.use ActionDispatch::RequestId - end + @app = self.class.build_app(set) do |middleware| + middleware.use ActionDispatch::RequestId + end - yield + yield + end end - end end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 8a5d85ab84..13a87b8976 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class BaseRequestTest < ActiveSupport::TestCase def setup @@ -14,7 +14,7 @@ class BaseRequestTest < ActiveSupport::TestCase end def url_for(options = {}) - options = { host: 'www.example.com' }.merge!(options) + options = { host: "www.example.com" }.merge!(options) ActionDispatch::Http::URL.url_for(options) end @@ -22,7 +22,7 @@ class BaseRequestTest < ActiveSupport::TestCase def stub_request(env = {}) ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true @trusted_proxies ||= nil - ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies) + ip_app = ActionDispatch::RemoteIp.new(Proc.new {}, ip_spoofing_check, @trusted_proxies) ActionDispatch::Http::URL.tld_length = env.delete(:tld_length) if env.key?(:tld_length) ip_app.call(env) @@ -34,78 +34,78 @@ end class RequestUrlFor < BaseRequestTest test "url_for class method" do - e = assert_raise(ArgumentError) { url_for(:host => nil) } + e = assert_raise(ArgumentError) { url_for(host: nil) } assert_match(/Please provide the :host parameter/, e.message) - assert_equal '/books', url_for(:only_path => true, :path => '/books') - - assert_equal 'http://www.example.com/books/?q=code', url_for(trailing_slash: true, path: '/books?q=code') - assert_equal 'http://www.example.com/books/?spareslashes=////', url_for(trailing_slash: true, path: '/books?spareslashes=////') - - assert_equal 'http://www.example.com', url_for - assert_equal 'http://api.example.com', url_for(:subdomain => 'api') - assert_equal 'http://example.com', url_for(:subdomain => false) - assert_equal 'http://www.ror.com', url_for(:domain => 'ror.com') - assert_equal 'http://api.ror.co.uk', url_for(:host => 'www.ror.co.uk', :subdomain => 'api', :tld_length => 2) - assert_equal 'http://www.example.com:8080', url_for(:port => 8080) - assert_equal 'https://www.example.com', url_for(:protocol => 'https') - assert_equal 'http://www.example.com/docs', url_for(:path => '/docs') - assert_equal 'http://www.example.com#signup', url_for(:anchor => 'signup') - assert_equal 'http://www.example.com/', url_for(:trailing_slash => true) - assert_equal 'http://dhh:supersecret@www.example.com', url_for(:user => 'dhh', :password => 'supersecret') - assert_equal 'http://www.example.com?search=books', url_for(:params => { :search => 'books' }) - assert_equal 'http://www.example.com?params=', url_for(:params => '') - assert_equal 'http://www.example.com?params=1', url_for(:params => 1) + assert_equal "/books", url_for(only_path: true, path: "/books") + + assert_equal "http://www.example.com/books/?q=code", url_for(trailing_slash: true, path: "/books?q=code") + assert_equal "http://www.example.com/books/?spareslashes=////", url_for(trailing_slash: true, path: "/books?spareslashes=////") + + assert_equal "http://www.example.com", url_for + assert_equal "http://api.example.com", url_for(subdomain: "api") + assert_equal "http://example.com", url_for(subdomain: false) + assert_equal "http://www.ror.com", url_for(domain: "ror.com") + assert_equal "http://api.ror.co.uk", url_for(host: "www.ror.co.uk", subdomain: "api", tld_length: 2) + assert_equal "http://www.example.com:8080", url_for(port: 8080) + assert_equal "https://www.example.com", url_for(protocol: "https") + assert_equal "http://www.example.com/docs", url_for(path: "/docs") + assert_equal "http://www.example.com#signup", url_for(anchor: "signup") + assert_equal "http://www.example.com/", url_for(trailing_slash: true) + assert_equal "http://dhh:supersecret@www.example.com", url_for(user: "dhh", password: "supersecret") + assert_equal "http://www.example.com?search=books", url_for(params: { search: "books" }) + assert_equal "http://www.example.com?params=", url_for(params: "") + assert_equal "http://www.example.com?params=1", url_for(params: 1) end end class RequestIP < BaseRequestTest test "remote ip" do - request = stub_request 'REMOTE_ADDR' => '1.2.3.4' - assert_equal '1.2.3.4', request.remote_ip + request = stub_request "REMOTE_ADDR" => "1.2.3.4" + assert_equal "1.2.3.4", request.remote_ip - request = stub_request 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "REMOTE_ADDR" => "1.2.3.4,3.4.5.6" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'REMOTE_ADDR' => '1.2.3.4', - 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "REMOTE_ADDR" => "1.2.3.4", + "HTTP_X_FORWARDED_FOR" => "3.4.5.6" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'REMOTE_ADDR' => '127.0.0.1', - 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "REMOTE_ADDR" => "127.0.0.1", + "HTTP_X_FORWARDED_FOR" => "3.4.5.6" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,unknown' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,unknown" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,172.16.0.1' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,172.16.0.1" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,192.168.0.1' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,192.168.0.1" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,10.0.0.1' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,10.0.0.1" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 10.0.0.1, 10.0.0.1' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6, 10.0.0.1, 10.0.0.1" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,127.0.0.1' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,127.0.0.1" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1' + request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,192.168.0.1" assert_equal nil, request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 172.31.4.4, 10.0.0.1' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 172.31.4.4, 10.0.0.1" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address' + request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address" assert_equal nil, request.remote_ip end test "remote ip spoof detection" do - request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', - 'HTTP_CLIENT_IP' => '2.2.2.2' + request = stub_request "HTTP_X_FORWARDED_FOR" => "1.1.1.1", + "HTTP_CLIENT_IP" => "2.2.2.2" e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) { request.remote_ip } @@ -115,60 +115,60 @@ class RequestIP < BaseRequestTest end test "remote ip with spoof detection disabled" do - request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', - 'HTTP_CLIENT_IP' => '2.2.2.2', + request = stub_request "HTTP_X_FORWARDED_FOR" => "1.1.1.1", + "HTTP_CLIENT_IP" => "2.2.2.2", :ip_spoofing_check => false - assert_equal '1.1.1.1', request.remote_ip + assert_equal "1.1.1.1", request.remote_ip end test "remote ip spoof protection ignores private addresses" do - request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.17.19.51', - 'HTTP_CLIENT_IP' => '172.17.19.51', - 'REMOTE_ADDR' => '1.1.1.1', - 'HTTP_X_BLUECOAT_VIA' => 'de462e07a2db325e' - assert_equal '1.1.1.1', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "172.17.19.51", + "HTTP_CLIENT_IP" => "172.17.19.51", + "REMOTE_ADDR" => "1.1.1.1", + "HTTP_X_BLUECOAT_VIA" => "de462e07a2db325e" + assert_equal "1.1.1.1", request.remote_ip end test "remote ip v6" do - request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334' - assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip - request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334' - assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + request = stub_request "REMOTE_ADDR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334" + assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip - request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', - 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' - assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329" + assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip - request = stub_request 'REMOTE_ADDR' => '::1', - 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' - assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + request = stub_request "REMOTE_ADDR" => "::1", + "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329" + assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,unknown' - assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,unknown" + assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1' - assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1" + assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, ::1' - assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, ::1" + assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,::1' + request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,::1" assert_equal nil, request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::, fc01::, fdff' - assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::, fc01::, fdff" + assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'FE00::, FDFF::' - assert_equal 'FE00::', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "FE00::, FDFF::" + assert_equal "FE00::", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address' + request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address" assert_equal nil, request.remote_ip end test "remote ip v6 spoof detection" do - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', - 'HTTP_CLIENT_IP' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", + "HTTP_CLIENT_IP" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334" e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) { request.remote_ip } @@ -178,139 +178,139 @@ class RequestIP < BaseRequestTest end test "remote ip v6 spoof detection disabled" do - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', - 'HTTP_CLIENT_IP' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', + request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", + "HTTP_CLIENT_IP" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334", :ip_spoofing_check => false - assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip + assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip end test "remote ip with user specified trusted proxies String" do @trusted_proxies = "67.205.106.73" - request = stub_request 'REMOTE_ADDR' => '3.4.5.6', - 'HTTP_X_FORWARDED_FOR' => '67.205.106.73' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "REMOTE_ADDR" => "3.4.5.6", + "HTTP_X_FORWARDED_FOR" => "67.205.106.73" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'REMOTE_ADDR' => '172.16.0.1,67.205.106.73', - 'HTTP_X_FORWARDED_FOR' => '67.205.106.73' - assert_equal '67.205.106.73', request.remote_ip + request = stub_request "REMOTE_ADDR" => "172.16.0.1,67.205.106.73", + "HTTP_X_FORWARDED_FOR" => "67.205.106.73" + assert_equal "67.205.106.73", request.remote_ip - request = stub_request 'REMOTE_ADDR' => '67.205.106.73,3.4.5.6', - 'HTTP_X_FORWARDED_FOR' => '67.205.106.73' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "REMOTE_ADDR" => "67.205.106.73,3.4.5.6", + "HTTP_X_FORWARDED_FOR" => "67.205.106.73" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '67.205.106.73,unknown' + request = stub_request "HTTP_X_FORWARDED_FOR" => "67.205.106.73,unknown" assert_equal nil, request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73" + assert_equal "3.4.5.6", request.remote_ip end test "remote ip v6 with user specified trusted proxies String" do - @trusted_proxies = 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' + @trusted_proxies = "fe80:0000:0000:0000:0202:b3ff:fe1e:8329" - request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', - 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' - assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329" + assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip - request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334', - 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' - assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + request = stub_request "REMOTE_ADDR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329" + assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip - request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1', - 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' - assert_equal '::1', request.remote_ip + request = stub_request "REMOTE_ADDR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1", + "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329" + assert_equal "::1", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329' + request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329" assert_equal nil, request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334' + request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334" assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip end test "remote ip with user specified trusted proxies Regexp" do @trusted_proxies = /^67\.205\.106\.73$/i - request = stub_request 'REMOTE_ADDR' => '67.205.106.73', - 'HTTP_X_FORWARDED_FOR' => '3.4.5.6' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "REMOTE_ADDR" => "67.205.106.73", + "HTTP_X_FORWARDED_FOR" => "3.4.5.6" + assert_equal "3.4.5.6", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 9.9.9.9, 3.4.5.6, 67.205.106.73' - assert_equal '3.4.5.6', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "10.0.0.1, 9.9.9.9, 3.4.5.6, 67.205.106.73" + assert_equal "3.4.5.6", request.remote_ip end test "remote ip v6 with user specified trusted proxies Regexp" do @trusted_proxies = /^fe80:0000:0000:0000:0202:b3ff:fe1e:8329$/i - request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334', - 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329' - assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329" + assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip - request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329' - assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip + request = stub_request "HTTP_X_FORWARDED_FOR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329" + assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip end test "remote ip middleware not present still returns an IP" do - request = stub_request('REMOTE_ADDR' => '127.0.0.1') - assert_equal '127.0.0.1', request.remote_ip + request = stub_request("REMOTE_ADDR" => "127.0.0.1") + assert_equal "127.0.0.1", request.remote_ip end end class RequestDomain < BaseRequestTest test "domains" do - request = stub_request 'HTTP_HOST' => "192.168.1.200" + request = stub_request "HTTP_HOST" => "192.168.1.200" assert_nil request.domain - request = stub_request 'HTTP_HOST' => "foo.192.168.1.200" + request = stub_request "HTTP_HOST" => "foo.192.168.1.200" assert_nil request.domain - request = stub_request 'HTTP_HOST' => "192.168.1.200.com" + request = stub_request "HTTP_HOST" => "192.168.1.200.com" assert_equal "200.com", request.domain - request = stub_request 'HTTP_HOST' => 'www.rubyonrails.org' + request = stub_request "HTTP_HOST" => "www.rubyonrails.org" assert_equal "rubyonrails.org", request.domain - request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk" + request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk" assert_equal "rubyonrails.co.uk", request.domain(2) - request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk", :tld_length => 2 + request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk", :tld_length => 2 assert_equal "rubyonrails.co.uk", request.domain end test "subdomains" do - request = stub_request 'HTTP_HOST' => "foobar.foobar.com" + request = stub_request "HTTP_HOST" => "foobar.foobar.com" assert_equal %w( foobar ), request.subdomains assert_equal "foobar", request.subdomain - request = stub_request 'HTTP_HOST' => "192.168.1.200" + request = stub_request "HTTP_HOST" => "192.168.1.200" assert_equal [], request.subdomains assert_equal "", request.subdomain - request = stub_request 'HTTP_HOST' => "foo.192.168.1.200" + request = stub_request "HTTP_HOST" => "foo.192.168.1.200" assert_equal [], request.subdomains assert_equal "", request.subdomain - request = stub_request 'HTTP_HOST' => "192.168.1.200.com" + request = stub_request "HTTP_HOST" => "192.168.1.200.com" assert_equal %w( 192 168 1 ), request.subdomains assert_equal "192.168.1", request.subdomain - request = stub_request 'HTTP_HOST' => nil + request = stub_request "HTTP_HOST" => nil assert_equal [], request.subdomains assert_equal "", request.subdomain - request = stub_request 'HTTP_HOST' => "www.rubyonrails.org" + request = stub_request "HTTP_HOST" => "www.rubyonrails.org" assert_equal %w( www ), request.subdomains assert_equal "www", request.subdomain - request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk" + request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk" assert_equal %w( www ), request.subdomains(2) assert_equal "www", request.subdomain(2) - request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk" + request = stub_request "HTTP_HOST" => "dev.www.rubyonrails.co.uk" assert_equal %w( dev www ), request.subdomains(2) assert_equal "dev.www", request.subdomain(2) - request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk", :tld_length => 2 + request = stub_request "HTTP_HOST" => "dev.www.rubyonrails.co.uk", :tld_length => 2 assert_equal %w( dev www ), request.subdomains assert_equal "dev.www", request.subdomain end @@ -321,7 +321,7 @@ class RequestPort < BaseRequestTest request = stub_request assert_equal 80, request.standard_port - request = stub_request 'HTTPS' => 'on' + request = stub_request "HTTPS" => "on" assert_equal 443, request.standard_port end @@ -330,97 +330,97 @@ class RequestPort < BaseRequestTest assert !request.ssl? assert request.standard_port? - request = stub_request 'HTTPS' => 'on' + request = stub_request "HTTPS" => "on" assert request.ssl? assert request.standard_port? - request = stub_request 'HTTP_HOST' => 'www.example.org:8080' + request = stub_request "HTTP_HOST" => "www.example.org:8080" assert !request.ssl? assert !request.standard_port? - request = stub_request 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on' + request = stub_request "HTTP_HOST" => "www.example.org:8443", "HTTPS" => "on" assert request.ssl? assert !request.standard_port? end test "optional port" do - request = stub_request 'HTTP_HOST' => 'www.example.org:80' + request = stub_request "HTTP_HOST" => "www.example.org:80" assert_equal nil, request.optional_port - request = stub_request 'HTTP_HOST' => 'www.example.org:8080' + request = stub_request "HTTP_HOST" => "www.example.org:8080" assert_equal 8080, request.optional_port end test "port string" do - request = stub_request 'HTTP_HOST' => 'www.example.org:80' - assert_equal '', request.port_string + request = stub_request "HTTP_HOST" => "www.example.org:80" + assert_equal "", request.port_string - request = stub_request 'HTTP_HOST' => 'www.example.org:8080' - assert_equal ':8080', request.port_string + request = stub_request "HTTP_HOST" => "www.example.org:8080" + assert_equal ":8080", request.port_string end test "server port" do - request = stub_request 'SERVER_PORT' => '8080' + request = stub_request "SERVER_PORT" => "8080" assert_equal 8080, request.server_port - request = stub_request 'SERVER_PORT' => '80' + request = stub_request "SERVER_PORT" => "80" assert_equal 80, request.server_port - request = stub_request 'SERVER_PORT' => '' + request = stub_request "SERVER_PORT" => "" assert_equal 0, request.server_port end end class RequestPath < BaseRequestTest test "full path" do - request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri', 'QUERY_STRING' => 'mapped=1' + request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/path/of/some/uri", "QUERY_STRING" => "mapped=1" assert_equal "/path/of/some/uri?mapped=1", request.fullpath assert_equal "/path/of/some/uri", request.path_info - request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri' + request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/path/of/some/uri" assert_equal "/path/of/some/uri", request.fullpath assert_equal "/path/of/some/uri", request.path_info - request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/' + request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/" assert_equal "/", request.fullpath assert_equal "/", request.path_info - request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/', 'QUERY_STRING' => 'm=b' + request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/", "QUERY_STRING" => "m=b" assert_equal "/?m=b", request.fullpath assert_equal "/", request.path_info - request = stub_request 'SCRIPT_NAME' => '/hieraki', 'PATH_INFO' => '/' + request = stub_request "SCRIPT_NAME" => "/hieraki", "PATH_INFO" => "/" assert_equal "/hieraki/", request.fullpath assert_equal "/", request.path_info - request = stub_request 'SCRIPT_NAME' => '/collaboration/hieraki', 'PATH_INFO' => '/books/edit/2' + request = stub_request "SCRIPT_NAME" => "/collaboration/hieraki", "PATH_INFO" => "/books/edit/2" assert_equal "/collaboration/hieraki/books/edit/2", request.fullpath assert_equal "/books/edit/2", request.path_info - request = stub_request 'SCRIPT_NAME' => '/path', 'PATH_INFO' => '/of/some/uri', 'QUERY_STRING' => 'mapped=1' + request = stub_request "SCRIPT_NAME" => "/path", "PATH_INFO" => "/of/some/uri", "QUERY_STRING" => "mapped=1" assert_equal "/path/of/some/uri?mapped=1", request.fullpath assert_equal "/of/some/uri", request.path_info end test "original_fullpath returns ORIGINAL_FULLPATH" do - request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar") + request = stub_request("ORIGINAL_FULLPATH" => "/foo?bar") path = request.original_fullpath assert_equal "/foo?bar", path end test "original_url returns url built using ORIGINAL_FULLPATH" do - request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar", - 'HTTP_HOST' => "example.org", - 'rack.url_scheme' => "http") + request = stub_request("ORIGINAL_FULLPATH" => "/foo?bar", + "HTTP_HOST" => "example.org", + "rack.url_scheme" => "http") url = request.original_url assert_equal "http://example.org/foo?bar", url end test "original_fullpath returns fullpath if ORIGINAL_FULLPATH is not present" do - request = stub_request('PATH_INFO' => "/foo", - 'QUERY_STRING' => "bar") + request = stub_request("PATH_INFO" => "/foo", + "QUERY_STRING" => "bar") path = request.original_fullpath assert_equal "/foo?bar", path @@ -429,77 +429,77 @@ end class RequestHost < BaseRequestTest test "host without specifying port" do - request = stub_request 'HTTP_HOST' => 'rubyonrails.org' + request = stub_request "HTTP_HOST" => "rubyonrails.org" assert_equal "rubyonrails.org", request.host_with_port end test "host with default port" do - request = stub_request 'HTTP_HOST' => 'rubyonrails.org:80' + request = stub_request "HTTP_HOST" => "rubyonrails.org:80" assert_equal "rubyonrails.org", request.host_with_port end test "host with non default port" do - request = stub_request 'HTTP_HOST' => 'rubyonrails.org:81' + request = stub_request "HTTP_HOST" => "rubyonrails.org:81" assert_equal "rubyonrails.org:81", request.host_with_port end test "raw without specifying port" do - request = stub_request 'HTTP_HOST' => 'rubyonrails.org' + request = stub_request "HTTP_HOST" => "rubyonrails.org" assert_equal "rubyonrails.org", request.raw_host_with_port end test "raw host with default port" do - request = stub_request 'HTTP_HOST' => 'rubyonrails.org:80' + request = stub_request "HTTP_HOST" => "rubyonrails.org:80" assert_equal "rubyonrails.org:80", request.raw_host_with_port end test "raw host with non default port" do - request = stub_request 'HTTP_HOST' => 'rubyonrails.org:81' + request = stub_request "HTTP_HOST" => "rubyonrails.org:81" assert_equal "rubyonrails.org:81", request.raw_host_with_port end test "proxy request" do - request = stub_request 'HTTP_HOST' => 'glu.ttono.us:80' + request = stub_request "HTTP_HOST" => "glu.ttono.us:80" assert_equal "glu.ttono.us", request.host_with_port end test "http host" do - request = stub_request 'HTTP_HOST' => "rubyonrails.org:8080" + request = stub_request "HTTP_HOST" => "rubyonrails.org:8080" assert_equal "rubyonrails.org", request.host assert_equal "rubyonrails.org:8080", request.host_with_port - request = stub_request 'HTTP_X_FORWARDED_HOST' => "www.firsthost.org, www.secondhost.org" + request = stub_request "HTTP_X_FORWARDED_HOST" => "www.firsthost.org, www.secondhost.org" assert_equal "www.secondhost.org", request.host - request = stub_request 'HTTP_X_FORWARDED_HOST' => "", 'HTTP_HOST' => "rubyonrails.org" + request = stub_request "HTTP_X_FORWARDED_HOST" => "", "HTTP_HOST" => "rubyonrails.org" assert_equal "rubyonrails.org", request.host end test "http host with default port overrides server port" do - request = stub_request 'HTTP_HOST' => "rubyonrails.org" + request = stub_request "HTTP_HOST" => "rubyonrails.org" assert_equal "rubyonrails.org", request.host_with_port end test "host with port if http standard port is specified" do - request = stub_request 'HTTP_X_FORWARDED_HOST' => "glu.ttono.us:80" + request = stub_request "HTTP_X_FORWARDED_HOST" => "glu.ttono.us:80" assert_equal "glu.ttono.us", request.host_with_port end test "host with port if https standard port is specified" do request = stub_request( - 'HTTP_X_FORWARDED_PROTO' => "https", - 'HTTP_X_FORWARDED_HOST' => "glu.ttono.us:443" + "HTTP_X_FORWARDED_PROTO" => "https", + "HTTP_X_FORWARDED_HOST" => "glu.ttono.us:443" ) assert_equal "glu.ttono.us", request.host_with_port end test "host if ipv6 reference" do - request = stub_request 'HTTP_HOST' => "[2001:1234:5678:9abc:def0::dead:beef]" + request = stub_request "HTTP_HOST" => "[2001:1234:5678:9abc:def0::dead:beef]" assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host end test "host if ipv6 reference with port" do - request = stub_request 'HTTP_HOST' => "[2001:1234:5678:9abc:def0::dead:beef]:8008" + request = stub_request "HTTP_HOST" => "[2001:1234:5678:9abc:def0::dead:beef]:8008" assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host end end @@ -590,28 +590,28 @@ end class RequestParamsParsing < BaseRequestTest test "doesnt break when content type has charset" do request = stub_request( - 'REQUEST_METHOD' => 'POST', - 'CONTENT_LENGTH' => "flamenco=love".length, - 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8', - 'rack.input' => StringIO.new("flamenco=love") + "REQUEST_METHOD" => "POST", + "CONTENT_LENGTH" => "flamenco=love".length, + "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8", + "rack.input" => StringIO.new("flamenco=love") ) - assert_equal({"flamenco"=> "love"}, request.request_parameters) + assert_equal({ "flamenco"=> "love" }, request.request_parameters) end test "doesnt interpret request uri as query string when missing" do - request = stub_request('REQUEST_URI' => 'foo') + request = stub_request("REQUEST_URI" => "foo") assert_equal({}, request.query_parameters) end end class RequestRewind < BaseRequestTest test "body should be rewound" do - data = 'rewind' + data = "rewind" env = { - 'rack.input' => StringIO.new(data), - 'CONTENT_LENGTH' => data.length, - 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8' + "rack.input" => StringIO.new(data), + "CONTENT_LENGTH" => data.length, + "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8" } # Read the request body by parsing params. @@ -624,18 +624,18 @@ class RequestRewind < BaseRequestTest test "raw_post rewinds rack.input if RAW_POST_DATA is nil" do request = stub_request( - 'rack.input' => StringIO.new("raw"), - 'CONTENT_LENGTH' => 3 + "rack.input" => StringIO.new("raw"), + "CONTENT_LENGTH" => 3 ) assert_equal "raw", request.raw_post - assert_equal "raw", request.env['rack.input'].read + assert_equal "raw", request.env["rack.input"].read end end class RequestProtocol < BaseRequestTest test "server software" do - assert_equal 'lighttpd', stub_request('SERVER_SOFTWARE' => 'lighttpd/1.4.5').server_software - assert_equal 'apache', stub_request('SERVER_SOFTWARE' => 'Apache3.422').server_software + assert_equal "lighttpd", stub_request("SERVER_SOFTWARE" => "lighttpd/1.4.5").server_software + assert_equal "apache", stub_request("SERVER_SOFTWARE" => "Apache3.422").server_software end test "xml http request" do @@ -644,35 +644,35 @@ class RequestProtocol < BaseRequestTest assert !request.xml_http_request? assert !request.xhr? - request = stub_request 'HTTP_X_REQUESTED_WITH' => 'DefinitelyNotAjax1.0' + request = stub_request "HTTP_X_REQUESTED_WITH" => "DefinitelyNotAjax1.0" assert !request.xml_http_request? assert !request.xhr? - request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest' + request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" assert request.xml_http_request? assert request.xhr? end test "reports ssl" do assert !stub_request.ssl? - assert stub_request('HTTPS' => 'on').ssl? + assert stub_request("HTTPS" => "on").ssl? end test "reports ssl when proxied via lighttpd" do - assert stub_request('HTTP_X_FORWARDED_PROTO' => 'https').ssl? + assert stub_request("HTTP_X_FORWARDED_PROTO" => "https").ssl? end test "scheme returns https when proxied" do - request = stub_request 'rack.url_scheme' => 'http' + request = stub_request "rack.url_scheme" => "http" assert !request.ssl? - assert_equal 'http', request.scheme + assert_equal "http", request.scheme request = stub_request( - 'rack.url_scheme' => 'http', - 'HTTP_X_FORWARDED_PROTO' => 'https' + "rack.url_scheme" => "http", + "HTTP_X_FORWARDED_PROTO" => "https" ) assert request.ssl? - assert_equal 'https', request.scheme + assert_equal "https", request.scheme end end @@ -681,7 +681,7 @@ class RequestMethod < BaseRequestTest overridden by middleware".squish do ActionDispatch::Request::HTTP_METHODS.each do |method| - request = stub_request('REQUEST_METHOD' => method) + request = stub_request("REQUEST_METHOD" => method) assert_equal method, request.method assert_equal method.underscore.to_sym, request.method_symbol @@ -689,36 +689,36 @@ class RequestMethod < BaseRequestTest end test "allow request method hacking" do - request = stub_request('REQUEST_METHOD' => 'POST') + request = stub_request("REQUEST_METHOD" => "POST") - assert_equal 'POST', request.request_method - assert_equal 'POST', request.env["REQUEST_METHOD"] + assert_equal "POST", request.request_method + assert_equal "POST", request.env["REQUEST_METHOD"] - request.request_method = 'GET' + request.request_method = "GET" - assert_equal 'GET', request.request_method - assert_equal 'GET', request.env["REQUEST_METHOD"] + assert_equal "GET", request.request_method + assert_equal "GET", request.env["REQUEST_METHOD"] assert request.get? end test "invalid http method raises exception" do assert_raise(ActionController::UnknownHttpMethod) do - stub_request('REQUEST_METHOD' => 'RANDOM_METHOD').request_method + stub_request("REQUEST_METHOD" => "RANDOM_METHOD").request_method end end test "method returns original value of environment request method on POST" do - request = stub_request('rack.methodoverride.original_method' => 'POST') - assert_equal 'POST', request.method + request = stub_request("rack.methodoverride.original_method" => "POST") + assert_equal "POST", request.method end test "method raises exception on invalid HTTP method" do assert_raise(ActionController::UnknownHttpMethod) do - stub_request('rack.methodoverride.original_method' => '_RANDOM_METHOD').method + stub_request("rack.methodoverride.original_method" => "_RANDOM_METHOD").method end assert_raise(ActionController::UnknownHttpMethod) do - stub_request('REQUEST_METHOD' => '_RANDOM_METHOD').method + stub_request("REQUEST_METHOD" => "_RANDOM_METHOD").method end end @@ -730,7 +730,7 @@ class RequestMethod < BaseRequestTest I18n.available_locales = [:nl] I18n.config.enforce_available_locales = true assert_raise(ActionController::UnknownHttpMethod) do - stub_request('REQUEST_METHOD' => '_RANDOM_METHOD').method + stub_request("REQUEST_METHOD" => "_RANDOM_METHOD").method end ensure I18n.available_locales = old_locales @@ -740,7 +740,7 @@ class RequestMethod < BaseRequestTest test "post masquerading as patch" do request = stub_request( - 'REQUEST_METHOD' => 'PATCH', + "REQUEST_METHOD" => "PATCH", "rack.methodoverride.original_method" => "POST" ) @@ -751,7 +751,7 @@ class RequestMethod < BaseRequestTest test "post masquerading as put" do request = stub_request( - 'REQUEST_METHOD' => 'PUT', + "REQUEST_METHOD" => "PUT", "rack.methodoverride.original_method" => "POST" ) assert_equal "POST", request.method @@ -784,29 +784,29 @@ end class RequestFormat < BaseRequestTest test "xml format" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :xml}) do + assert_called(request, :parameters, times: 2, returns: { format: :xml }) do assert_equal Mime[:xml], request.format end end test "xhtml format" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :xhtml}) do + assert_called(request, :parameters, times: 2, returns: { format: :xhtml }) do assert_equal Mime[:html], request.format end end test "txt format" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :txt}) do + assert_called(request, :parameters, times: 2, returns: { format: :txt }) do assert_equal Mime[:text], request.format end end test "XMLHttpRequest" do request = stub_request( - 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest', - 'HTTP_ACCEPT' => [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(",") + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest", + "HTTP_ACCEPT" => [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(",") ) assert_called(request, :parameters, times: 1, returns: {}) do @@ -817,56 +817,56 @@ class RequestFormat < BaseRequestTest test "can override format with parameter negative" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :txt}) do + assert_called(request, :parameters, times: 2, returns: { format: :txt }) do assert !request.format.xml? end end test "can override format with parameter positive" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :xml}) do + assert_called(request, :parameters, times: 2, returns: { format: :xml }) do assert request.format.xml? end end test "formats text/html with accept header" do - request = stub_request 'HTTP_ACCEPT' => 'text/html' + request = stub_request "HTTP_ACCEPT" => "text/html" assert_equal [Mime[:html]], request.formats end test "formats blank with accept header" do - request = stub_request 'HTTP_ACCEPT' => '' + request = stub_request "HTTP_ACCEPT" => "" assert_equal [Mime[:html]], request.formats end test "formats XMLHttpRequest with accept header" do - request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" assert_equal [Mime[:js]], request.formats end test "formats application/xml with accept header" do - request = stub_request('CONTENT_TYPE' => 'application/xml; charset=UTF-8', - 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest") + request = stub_request("CONTENT_TYPE" => "application/xml; charset=UTF-8", + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest") assert_equal [Mime[:xml]], request.formats end test "formats format:text with accept header" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :txt}) do + assert_called(request, :parameters, times: 2, returns: { format: :txt }) do assert_equal [Mime[:text]], request.formats end end test "formats format:unknown with accept header" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :unknown}) do + assert_called(request, :parameters, times: 2, returns: { format: :unknown }) do assert_instance_of Mime::NullType, request.format end end test "format is not nil with unknown format" do request = stub_request - assert_called(request, :parameters, times: 2, returns: {format: :hello}) do + assert_called(request, :parameters, times: 2, returns: { format: :hello }) do assert request.format.nil? assert_not request.format.html? assert_not request.format.xml? @@ -881,7 +881,7 @@ class RequestFormat < BaseRequestTest end test "formats with xhr request" do - request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [Mime[:js]], request.formats end @@ -892,36 +892,36 @@ class RequestFormat < BaseRequestTest ActionDispatch::Request.ignore_accept_header = true begin - request = stub_request 'HTTP_ACCEPT' => 'application/xml' + request = stub_request "HTTP_ACCEPT" => "application/xml" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [ Mime[:html] ], request.formats end - request = stub_request 'HTTP_ACCEPT' => 'koz-asked/something-crazy' + request = stub_request "HTTP_ACCEPT" => "koz-asked/something-crazy" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [ Mime[:html] ], request.formats end - request = stub_request 'HTTP_ACCEPT' => '*/*;q=0.1' + request = stub_request "HTTP_ACCEPT" => "*/*;q=0.1" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [ Mime[:html] ], request.formats end - request = stub_request 'HTTP_ACCEPT' => 'application/jxw' + request = stub_request "HTTP_ACCEPT" => "application/jxw" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [ Mime[:html] ], request.formats end - request = stub_request 'HTTP_ACCEPT' => 'application/xml', - 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request = stub_request "HTTP_ACCEPT" => "application/xml", + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [ Mime[:js] ], request.formats end - request = stub_request 'HTTP_ACCEPT' => 'application/xml', - 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" - assert_called(request, :parameters, times: 2, returns: {format: :json}) do + request = stub_request "HTTP_ACCEPT" => "application/xml", + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" + assert_called(request, :parameters, times: 2, returns: { format: :json }) do assert_equal [ Mime[:json] ], request.formats end ensure @@ -930,20 +930,20 @@ class RequestFormat < BaseRequestTest end test "format taken from the path extension" do - request = stub_request 'PATH_INFO' => '/foo.xml' + request = stub_request "PATH_INFO" => "/foo.xml" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [Mime[:xml]], request.formats end - request = stub_request 'PATH_INFO' => '/foo.123' + request = stub_request "PATH_INFO" => "/foo.123" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [Mime[:html]], request.formats end end test "formats from accept headers have higher precedence than path extension" do - request = stub_request 'HTTP_ACCEPT' => 'application/json', - 'PATH_INFO' => '/foo.xml' + request = stub_request "HTTP_ACCEPT" => "application/json", + "PATH_INFO" => "/foo.xml" assert_called(request, :parameters, times: 1, returns: {}) do assert_equal [Mime[:json]], request.formats @@ -953,7 +953,7 @@ end class RequestMimeType < BaseRequestTest test "content type" do - assert_equal Mime[:html], stub_request('CONTENT_TYPE' => 'text/html').content_mime_type + assert_equal Mime[:html], stub_request("CONTENT_TYPE" => "text/html").content_mime_type end test "no content type" do @@ -961,21 +961,21 @@ class RequestMimeType < BaseRequestTest end test "content type is XML" do - assert_equal Mime[:xml], stub_request('CONTENT_TYPE' => 'application/xml').content_mime_type + assert_equal Mime[:xml], stub_request("CONTENT_TYPE" => "application/xml").content_mime_type end test "content type with charset" do - assert_equal Mime[:xml], stub_request('CONTENT_TYPE' => 'application/xml; charset=UTF-8').content_mime_type + assert_equal Mime[:xml], stub_request("CONTENT_TYPE" => "application/xml; charset=UTF-8").content_mime_type end test "user agent" do - assert_equal 'TestAgent', stub_request('HTTP_USER_AGENT' => 'TestAgent').user_agent + assert_equal "TestAgent", stub_request("HTTP_USER_AGENT" => "TestAgent").user_agent end test "negotiate_mime" do request = stub_request( - 'HTTP_ACCEPT' => 'text/html', - 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + "HTTP_ACCEPT" => "text/html", + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" ) assert_equal nil, request.negotiate_mime([Mime[:xml], Mime[:json]]) @@ -985,8 +985,8 @@ class RequestMimeType < BaseRequestTest test "negotiate_mime with content_type" do request = stub_request( - 'CONTENT_TYPE' => 'application/xml; charset=UTF-8', - 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + "CONTENT_TYPE" => "application/xml; charset=UTF-8", + "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" ) assert_equal Mime[:xml], request.negotiate_mime([Mime[:xml], Mime[:csv]]) @@ -997,11 +997,11 @@ class RequestParameters < BaseRequestTest test "parameters" do request = stub_request - assert_called(request, :request_parameters, times: 2, returns: {"foo" => 1}) do - assert_called(request, :query_parameters, times: 2, returns: {"bar" => 2}) do - assert_equal({"foo" => 1, "bar" => 2}, request.parameters) - assert_equal({"foo" => 1}, request.request_parameters) - assert_equal({"bar" => 2}, request.query_parameters) + assert_called(request, :request_parameters, times: 2, returns: { "foo" => 1 }) do + assert_called(request, :query_parameters, times: 2, returns: { "bar" => 2 }) do + assert_equal({ "foo" => 1, "bar" => 2 }, request.parameters) + assert_equal({ "foo" => 1 }, request.request_parameters) + assert_equal({ "bar" => 2 }, request.query_parameters) end end end @@ -1018,17 +1018,13 @@ class RequestParameters < BaseRequestTest end test "path parameters with invalid UTF8 encoding" do - request = stub_request( - "action_dispatch.request.path_parameters" => { foo: "\xBE" } - ) + request = stub_request err = assert_raises(ActionController::BadRequest) do - request.check_path_parameters! + request.path_parameters = { foo: "\xBE" } end - assert_match "Invalid parameter encoding", err.message - assert_match "foo", err.message - assert_match "\\xBE", err.message + assert_equal "Invalid path parameters: Non UTF-8 value: \xBE", err.message end test "parameters not accessible after rack parse error of invalid UTF8 character" do @@ -1048,10 +1044,10 @@ class RequestParameters < BaseRequestTest test "parameters not accessible after rack parse error 1" do request = stub_request( - 'REQUEST_METHOD' => 'POST', - 'CONTENT_LENGTH' => "a%=".length, - 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8', - 'rack.input' => StringIO.new("a%=") + "REQUEST_METHOD" => "POST", + "CONTENT_LENGTH" => "a%=".length, + "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8", + "rack.input" => StringIO.new("a%=") ) assert_raises(ActionController::BadRequest) do @@ -1073,31 +1069,30 @@ class RequestParameters < BaseRequestTest end end - class RequestParameterFilter < BaseRequestTest test "process parameter filter" do test_hashes = [ - [{'foo'=>'bar'},{'foo'=>'bar'},%w'food'], - [{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'], - [{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'], - [{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'], - [{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'], - [{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana'], - [{'deep'=>{'cc'=>{'code'=>'bar','bar'=>'foo'},'ss'=>{'code'=>'bar'}}},{'deep'=>{'cc'=>{'code'=>'[FILTERED]','bar'=>'foo'},'ss'=>{'code'=>'bar'}}},%w'deep.cc.code'], - [{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]] + [{ "foo"=>"bar" },{ "foo"=>"bar" },%w'food'], + [{ "foo"=>"bar" },{ "foo"=>"[FILTERED]" },%w'foo'], + [{ "foo"=>"bar", "bar"=>"foo" },{ "foo"=>"[FILTERED]", "bar"=>"foo" },%w'foo baz'], + [{ "foo"=>"bar", "baz"=>"foo" },{ "foo"=>"[FILTERED]", "baz"=>"[FILTERED]" },%w'foo baz'], + [{ "bar"=>{ "foo"=>"bar","bar"=>"foo" } },{ "bar"=>{ "foo"=>"[FILTERED]","bar"=>"foo" } },%w'fo'], + [{ "foo"=>{ "foo"=>"bar","bar"=>"foo" } },{ "foo"=>"[FILTERED]" },%w'f banana'], + [{ "deep"=>{ "cc"=>{ "code"=>"bar","bar"=>"foo" },"ss"=>{ "code"=>"bar" } } },{ "deep"=>{ "cc"=>{ "code"=>"[FILTERED]","bar"=>"foo" },"ss"=>{ "code"=>"bar" } } },%w'deep.cc.code'], + [{ "baz"=>[{ "foo"=>"baz" }, "1"] }, { "baz"=>[{ "foo"=>"[FILTERED]" }, "1"] }, [/foo/]]] test_hashes.each do |before_filter, after_filter, filter_words| parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words) assert_equal after_filter, parameter_filter.filter(before_filter) - filter_words << 'blah' + filter_words << "blah" filter_words << lambda { |key, value| value.reverse! if key =~ /bargain/ } parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words) - before_filter['barg'] = {:bargain=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}} - after_filter['barg'] = {:bargain=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}} + before_filter["barg"] = { :bargain=>"gain", "blah"=>"bar", "bar"=>{ "bargain"=>{ "blah"=>"foo" } } } + after_filter["barg"] = { :bargain=>"niag", "blah"=>"[FILTERED]", "bar"=>{ "bargain"=>{ "blah"=>"[FILTERED]" } } } assert_equal after_filter, parameter_filter.filter(before_filter) end @@ -1105,12 +1100,12 @@ class RequestParameterFilter < BaseRequestTest test "filtered_parameters returns params filtered" do request = stub_request( - 'action_dispatch.request.parameters' => { - 'lifo' => 'Pratik', - 'amount' => '420', - 'step' => '1' + "action_dispatch.request.parameters" => { + "lifo" => "Pratik", + "amount" => "420", + "step" => "1" }, - 'action_dispatch.parameter_filter' => [:lifo, :amount] + "action_dispatch.parameter_filter" => [:lifo, :amount] ) params = request.filtered_parameters @@ -1121,12 +1116,12 @@ class RequestParameterFilter < BaseRequestTest test "filtered_env filters env as a whole" do request = stub_request( - 'action_dispatch.request.parameters' => { - 'amount' => '420', - 'step' => '1' + "action_dispatch.request.parameters" => { + "amount" => "420", + "step" => "1" }, "RAW_POST_DATA" => "yada yada", - 'action_dispatch.parameter_filter' => [:lifo, :amount] + "action_dispatch.parameter_filter" => [:lifo, :amount] ) request = stub_request(request.filtered_env) @@ -1138,9 +1133,9 @@ class RequestParameterFilter < BaseRequestTest test "filtered_path returns path with filtered query string" do %w(; &).each do |sep| request = stub_request( - 'QUERY_STRING' => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep), - 'PATH_INFO' => '/authenticate', - 'action_dispatch.parameter_filter' => [:secret, :api_key] + "QUERY_STRING" => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep), + "PATH_INFO" => "/authenticate", + "action_dispatch.parameter_filter" => [:secret, :api_key] ) path = request.filtered_path @@ -1150,9 +1145,9 @@ class RequestParameterFilter < BaseRequestTest test "filtered_path should not unescape a genuine '[FILTERED]' value" do request = stub_request( - 'QUERY_STRING' => "secret=bd4f21f&genuine=%5BFILTERED%5D", - 'PATH_INFO' => '/authenticate', - 'action_dispatch.parameter_filter' => [:secret] + "QUERY_STRING" => "secret=bd4f21f&genuine=%5BFILTERED%5D", + "PATH_INFO" => "/authenticate", + "action_dispatch.parameter_filter" => [:secret] ) path = request.filtered_path @@ -1161,9 +1156,9 @@ class RequestParameterFilter < BaseRequestTest test "filtered_path should preserve duplication of keys in query string" do request = stub_request( - 'QUERY_STRING' => "username=sikachu&secret=bd4f21f&username=fxn", - 'PATH_INFO' => '/authenticate', - 'action_dispatch.parameter_filter' => [:secret] + "QUERY_STRING" => "username=sikachu&secret=bd4f21f&username=fxn", + "PATH_INFO" => "/authenticate", + "action_dispatch.parameter_filter" => [:secret] ) path = request.filtered_path @@ -1172,9 +1167,9 @@ class RequestParameterFilter < BaseRequestTest test "filtered_path should ignore searchparts" do request = stub_request( - 'QUERY_STRING' => "secret", - 'PATH_INFO' => '/authenticate', - 'action_dispatch.parameter_filter' => [:secret] + "QUERY_STRING" => "secret", + "PATH_INFO" => "/authenticate", + "action_dispatch.parameter_filter" => [:secret] ) path = request.filtered_path @@ -1184,10 +1179,10 @@ end class RequestEtag < BaseRequestTest test "always matches *" do - request = stub_request('HTTP_IF_NONE_MATCH' => '*') + request = stub_request("HTTP_IF_NONE_MATCH" => "*") - assert_equal '*', request.if_none_match - assert_equal ['*'], request.if_none_match_etags + assert_equal "*", request.if_none_match + assert_equal ["*"], request.if_none_match_etags assert request.etag_matches?('"strong"') assert request.etag_matches?('W/"weak"') @@ -1206,7 +1201,7 @@ class RequestEtag < BaseRequestTest test "matches opaque ETag validators without unquoting" do header = '"the-etag"' - request = stub_request('HTTP_IF_NONE_MATCH' => header) + request = stub_request("HTTP_IF_NONE_MATCH" => header) assert_equal header, request.if_none_match assert_equal ['"the-etag"'], request.if_none_match_etags @@ -1217,8 +1212,8 @@ class RequestEtag < BaseRequestTest test "if_none_match_etags multiple" do header = 'etag1, etag2, "third etag", "etag4"' - expected = ['etag1', 'etag2', '"third etag"', '"etag4"'] - request = stub_request('HTTP_IF_NONE_MATCH' => header) + expected = ["etag1", "etag2", '"third etag"', '"etag4"'] + request = stub_request("HTTP_IF_NONE_MATCH" => header) assert_equal header, request.if_none_match assert_equal expected, request.if_none_match_etags @@ -1234,7 +1229,7 @@ class RequestVariant < BaseRequestTest @request = stub_request end - test 'setting variant to a symbol' do + test "setting variant to a symbol" do @request.variant = :phone assert @request.variant.phone? @@ -1243,7 +1238,7 @@ class RequestVariant < BaseRequestTest assert_not @request.variant.any?(:tablet, :desktop) end - test 'setting variant to an array of symbols' do + test "setting variant to an array of symbols" do @request.variant = [:phone, :tablet] assert @request.variant.phone? @@ -1253,7 +1248,7 @@ class RequestVariant < BaseRequestTest assert_not @request.variant.any?(:desktop, :watch) end - test 'clearing variant' do + test "clearing variant" do @request.variant = nil assert @request.variant.empty? @@ -1261,35 +1256,35 @@ class RequestVariant < BaseRequestTest assert_not @request.variant.any?(:phone, :tablet) end - test 'setting variant to a non-symbol value' do + test "setting variant to a non-symbol value" do assert_raise ArgumentError do - @request.variant = 'phone' + @request.variant = "phone" end end - test 'setting variant to an array containing a non-symbol value' do + test "setting variant to an array containing a non-symbol value" do assert_raise ArgumentError do - @request.variant = [:phone, 'tablet'] + @request.variant = [:phone, "tablet"] end end end class RequestFormData < BaseRequestTest - test 'media_type is from the FORM_DATA_MEDIA_TYPES array' do - assert stub_request('CONTENT_TYPE' => 'application/x-www-form-urlencoded').form_data? - assert stub_request('CONTENT_TYPE' => 'multipart/form-data').form_data? + test "media_type is from the FORM_DATA_MEDIA_TYPES array" do + assert stub_request("CONTENT_TYPE" => "application/x-www-form-urlencoded").form_data? + assert stub_request("CONTENT_TYPE" => "multipart/form-data").form_data? end - test 'media_type is not from the FORM_DATA_MEDIA_TYPES array' do - assert !stub_request('CONTENT_TYPE' => 'application/xml').form_data? - assert !stub_request('CONTENT_TYPE' => 'multipart/related').form_data? + test "media_type is not from the FORM_DATA_MEDIA_TYPES array" do + assert !stub_request("CONTENT_TYPE" => "application/xml").form_data? + assert !stub_request("CONTENT_TYPE" => "multipart/related").form_data? end - test 'no Content-Type header is provided and the request_method is POST' do - request = stub_request('REQUEST_METHOD' => 'POST') + test "no Content-Type header is provided and the request_method is POST" do + request = stub_request("REQUEST_METHOD" => "POST") - assert_equal '', request.media_type - assert_equal 'POST', request.request_method + assert_equal "", request.media_type + assert_equal "POST", request.request_method assert !request.form_data? end end diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index aa90433505..4e547ab7d5 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'timeout' -require 'rack/content_length' +require "abstract_unit" +require "timeout" +require "rack/content_length" class ResponseTest < ActiveSupport::TestCase def setup @@ -40,8 +40,8 @@ class ResponseTest < ActiveSupport::TestCase def test_each_isnt_called_if_str_body_is_written # Controller writes and reads response body each_counter = 0 - @response.body = Object.new.tap {|o| o.singleton_class.send(:define_method, :each) { |&block| each_counter += 1; block.call 'foo' } } - @response['X-Foo'] = @response.body + @response.body = Object.new.tap { |o| o.singleton_class.send(:define_method, :each) { |&block| each_counter += 1; block.call "foo" } } + @response["X-Foo"] = @response.body assert_equal 1, each_counter, "#each was not called once" @@ -49,7 +49,7 @@ class ResponseTest < ActiveSupport::TestCase status, headers, body = @response.to_a assert_equal 200, status - assert_equal "foo", headers['X-Foo'] + assert_equal "foo", headers["X-Foo"] assert_equal "foo", body.each.to_a.join # Show that #each was not called twice @@ -60,14 +60,14 @@ class ResponseTest < ActiveSupport::TestCase @response.body # set header after the action reads back @response.body - @response['x-header'] = "Best of all possible worlds." + @response["x-header"] = "Best of all possible worlds." # the response can be built. status, headers, body = @response.to_a assert_equal 200, status assert_equal "", body.body - assert_equal "Best of all possible worlds.", headers['x-header'] + assert_equal "Best of all possible worlds.", headers["x-header"] end def test_read_body_during_action @@ -99,15 +99,15 @@ class ResponseTest < ActiveSupport::TestCase end def test_response_charset_writer - @response.charset = 'utf-16' - assert_equal 'utf-16', @response.charset + @response.charset = "utf-16" + assert_equal "utf-16", @response.charset @response.charset = nil - assert_equal 'utf-8', @response.charset + assert_equal "utf-8", @response.charset end def test_setting_content_type_header_impacts_content_type_method - @response.headers['Content-Type'] = "application/aaron" - assert_equal 'application/aaron', @response.content_type + @response.headers["Content-Type"] = "application/aaron" + assert_equal "application/aaron", @response.content_type end test "simple output" do @@ -125,14 +125,14 @@ class ResponseTest < ActiveSupport::TestCase end test "status handled properly in initialize" do - assert_equal 200, ActionDispatch::Response.new('200 OK').status + assert_equal 200, ActionDispatch::Response.new("200 OK").status end def test_only_set_charset_still_defaults_to_text_html response = ActionDispatch::Response.new response.charset = "utf-16" _,headers,_ = response.to_a - assert_equal "text/html; charset=utf-16", headers['Content-Type'] + assert_equal "text/html; charset=utf-16", headers["Content-Type"] end test "utf8 output" do @@ -145,6 +145,26 @@ class ResponseTest < ActiveSupport::TestCase }, headers) end + test "content length" do + [100, 101, 102, 204].each do |c| + @response = ActionDispatch::Response.new + @response.status = c.to_s + @response.set_header "Content-Length", "0" + _, headers, _ = @response.to_a + assert !headers.has_key?("Content-Length"), "#{c} must not have a Content-Length header field" + end + end + + test "does not contain a message-body" do + [100, 101, 102, 204, 304].each do |c| + @response = ActionDispatch::Response.new + @response.status = c.to_s + @response.body = "Body must not be included" + _, _, body = @response.to_a + assert_empty body, "#{c} must not have a message-body but actually contains #{body}" + end + end + test "content type" do [204, 304].each do |c| @response = ActionDispatch::Response.new @@ -164,7 +184,7 @@ class ResponseTest < ActiveSupport::TestCase test "does not include Status header" do @response.status = "200 OK" _, headers, _ = @response.to_a - assert !headers.has_key?('Status') + assert !headers.has_key?("Status") end test "response code" do @@ -201,32 +221,32 @@ class ResponseTest < ActiveSupport::TestCase end test "cookies" do - @response.set_cookie("user_name", :value => "david", :path => "/") + @response.set_cookie("user_name", value: "david", path: "/") _status, headers, _body = @response.to_a assert_equal "user_name=david; path=/", headers["Set-Cookie"] - assert_equal({"user_name" => "david"}, @response.cookies) + assert_equal({ "user_name" => "david" }, @response.cookies) end test "multiple cookies" do - @response.set_cookie("user_name", :value => "david", :path => "/") - @response.set_cookie("login", :value => "foo&bar", :path => "/", :expires => Time.utc(2005, 10, 10,5)) + @response.set_cookie("user_name", value: "david", path: "/") + @response.set_cookie("login", value: "foo&bar", path: "/", expires: Time.utc(2005, 10, 10,5)) _status, headers, _body = @response.to_a assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10 Oct 2005 05:00:00 -0000", headers["Set-Cookie"] - assert_equal({"login" => "foo&bar", "user_name" => "david"}, @response.cookies) + assert_equal({ "login" => "foo&bar", "user_name" => "david" }, @response.cookies) end test "delete cookies" do - @response.set_cookie("user_name", :value => "david", :path => "/") - @response.set_cookie("login", :value => "foo&bar", :path => "/", :expires => Time.utc(2005, 10, 10,5)) + @response.set_cookie("user_name", value: "david", path: "/") + @response.set_cookie("login", value: "foo&bar", path: "/", expires: Time.utc(2005, 10, 10,5)) @response.delete_cookie("login") - assert_equal({"user_name" => "david", "login" => nil}, @response.cookies) + assert_equal({ "user_name" => "david", "login" => nil }, @response.cookies) end test "read ETag and Cache-Control" do resp = ActionDispatch::Response.new.tap { |response| response.cache_control[:public] = true - response.etag = '123' - response.body = 'Hello' + response.etag = "123" + response.body = "Hello" } resp.to_a @@ -234,17 +254,17 @@ class ResponseTest < ActiveSupport::TestCase assert resp.weak_etag? assert_not resp.strong_etag? assert_equal('W/"202cb962ac59075b964b07152d234b70"', resp.etag) - assert_equal({:public => true}, resp.cache_control) + assert_equal({ public: true }, resp.cache_control) - assert_equal('public', resp.headers['Cache-Control']) - assert_equal('W/"202cb962ac59075b964b07152d234b70"', resp.headers['ETag']) + assert_equal("public", resp.headers["Cache-Control"]) + assert_equal('W/"202cb962ac59075b964b07152d234b70"', resp.headers["ETag"]) end test "read strong ETag" do resp = ActionDispatch::Response.new.tap { |response| response.cache_control[:public] = true - response.strong_etag = '123' - response.body = 'Hello' + response.strong_etag = "123" + response.body = "Hello" } resp.to_a @@ -256,23 +276,23 @@ class ResponseTest < ActiveSupport::TestCase test "read charset and content type" do resp = ActionDispatch::Response.new.tap { |response| - response.charset = 'utf-16' + response.charset = "utf-16" response.content_type = Mime[:xml] - response.body = 'Hello' + response.body = "Hello" } resp.to_a - assert_equal('utf-16', resp.charset) + assert_equal("utf-16", resp.charset) assert_equal(Mime[:xml], resp.content_type) - assert_equal('application/xml; charset=utf-16', resp.headers['Content-Type']) + assert_equal("application/xml; charset=utf-16", resp.headers["Content-Type"]) end test "read content type with default charset utf-8" do original = ActionDispatch::Response.default_charset begin - resp = ActionDispatch::Response.new(200, { "Content-Type" => "text/xml" }) - assert_equal('utf-8', resp.charset) + resp = ActionDispatch::Response.new(200, "Content-Type" => "text/xml") + assert_equal("utf-8", resp.charset) ensure ActionDispatch::Response.default_charset = original end @@ -281,9 +301,9 @@ class ResponseTest < ActiveSupport::TestCase test "read content type with charset utf-16" do original = ActionDispatch::Response.default_charset begin - ActionDispatch::Response.default_charset = 'utf-16' - resp = ActionDispatch::Response.new(200, { "Content-Type" => "text/xml" }) - assert_equal('utf-16', resp.charset) + ActionDispatch::Response.default_charset = "utf-16" + resp = ActionDispatch::Response.new(200, "Content-Type" => "text/xml") + assert_equal("utf-16", resp.charset) ensure ActionDispatch::Response.default_charset = original end @@ -293,18 +313,18 @@ class ResponseTest < ActiveSupport::TestCase original_default_headers = ActionDispatch::Response.default_headers begin ActionDispatch::Response.default_headers = { - 'X-Frame-Options' => 'DENY', - 'X-Content-Type-Options' => 'nosniff', - 'X-XSS-Protection' => '1;' + "X-Frame-Options" => "DENY", + "X-Content-Type-Options" => "nosniff", + "X-XSS-Protection" => "1;" } resp = ActionDispatch::Response.create.tap { |response| - response.body = 'Hello' + response.body = "Hello" } resp.to_a - assert_equal('DENY', resp.headers['X-Frame-Options']) - assert_equal('nosniff', resp.headers['X-Content-Type-Options']) - assert_equal('1;', resp.headers['X-XSS-Protection']) + assert_equal("DENY", resp.headers["X-Frame-Options"]) + assert_equal("nosniff", resp.headers["X-Content-Type-Options"]) + assert_equal("1;", resp.headers["X-XSS-Protection"]) ensure ActionDispatch::Response.default_headers = original_default_headers end @@ -314,14 +334,14 @@ class ResponseTest < ActiveSupport::TestCase original_default_headers = ActionDispatch::Response.default_headers begin ActionDispatch::Response.default_headers = { - 'X-XX-XXXX' => 'Here is my phone number' + "X-XX-XXXX" => "Here is my phone number" } resp = ActionDispatch::Response.create.tap { |response| - response.body = 'Hello' + response.body = "Hello" } resp.to_a - assert_equal('Here is my phone number', resp.headers['X-XX-XXXX']) + assert_equal("Here is my phone number", resp.headers["X-XX-XXXX"]) ensure ActionDispatch::Response.default_headers = original_default_headers end @@ -333,13 +353,13 @@ class ResponseTest < ActiveSupport::TestCase end test "can be explicitly destructured into status, headers and an enumerable body" do - response = ActionDispatch::Response.new(404, { 'Content-Type' => 'text/plain' }, ['Not Found']) + response = ActionDispatch::Response.new(404, { "Content-Type" => "text/plain" }, ["Not Found"]) response.request = ActionDispatch::Request.empty status, headers, body = *response assert_equal 404, status - assert_equal({ 'Content-Type' => 'text/plain' }, headers) - assert_equal ['Not Found'], body.each.to_a + assert_equal({ "Content-Type" => "text/plain" }, headers) + assert_equal ["Not Found"], body.each.to_a end test "[response.to_a].flatten does not recurse infinitely" do @@ -352,74 +372,74 @@ class ResponseTest < ActiveSupport::TestCase end test "compatibility with Rack::ContentLength" do - @response.body = 'Hello' + @response.body = "Hello" app = lambda { |env| @response.to_a } env = Rack::MockRequest.env_for("/") status, headers, body = app.call(env) - assert_nil headers['Content-Length'] + assert_nil headers["Content-Length"] status, headers, body = Rack::ContentLength.new(app).call(env) - assert_equal '5', headers['Content-Length'] + assert_equal "5", headers["Content-Length"] end end class ResponseHeadersTest < ActiveSupport::TestCase def setup @response = ActionDispatch::Response.create - @response.set_header 'Foo', '1' + @response.set_header "Foo", "1" end - test 'has_header?' do - assert @response.has_header? 'Foo' - assert_not @response.has_header? 'foo' + test "has_header?" do + assert @response.has_header? "Foo" + assert_not @response.has_header? "foo" assert_not @response.has_header? nil end - test 'get_header' do - assert_equal '1', @response.get_header('Foo') - assert_nil @response.get_header('foo') + test "get_header" do + assert_equal "1", @response.get_header("Foo") + assert_nil @response.get_header("foo") assert_nil @response.get_header(nil) end - test 'set_header' do - assert_equal '2', @response.set_header('Foo', '2') - assert @response.has_header?('Foo') - assert_equal '2', @response.get_header('Foo') + test "set_header" do + assert_equal "2", @response.set_header("Foo", "2") + assert @response.has_header?("Foo") + assert_equal "2", @response.get_header("Foo") - assert_nil @response.set_header('Foo', nil) - assert @response.has_header?('Foo') - assert_nil @response.get_header('Foo') + assert_nil @response.set_header("Foo", nil) + assert @response.has_header?("Foo") + assert_nil @response.get_header("Foo") end - test 'delete_header' do + test "delete_header" do assert_nil @response.delete_header(nil) - assert_nil @response.delete_header('foo') - assert @response.has_header?('Foo') + assert_nil @response.delete_header("foo") + assert @response.has_header?("Foo") - assert_equal '1', @response.delete_header('Foo') - assert_not @response.has_header?('Foo') + assert_equal "1", @response.delete_header("Foo") + assert_not @response.has_header?("Foo") end - test 'add_header' do + test "add_header" do # Add a value to an existing header - assert_equal '1,2', @response.add_header('Foo', '2') - assert_equal '1,2', @response.get_header('Foo') + assert_equal "1,2", @response.add_header("Foo", "2") + assert_equal "1,2", @response.get_header("Foo") # Add nil to an existing header - assert_equal '1,2', @response.add_header('Foo', nil) - assert_equal '1,2', @response.get_header('Foo') + assert_equal "1,2", @response.add_header("Foo", nil) + assert_equal "1,2", @response.get_header("Foo") # Add nil to a nonexistent header - assert_nil @response.add_header('Bar', nil) - assert_not @response.has_header?('Bar') - assert_nil @response.get_header('Bar') + assert_nil @response.add_header("Bar", nil) + assert_not @response.has_header?("Bar") + assert_nil @response.get_header("Bar") # Add a value to a nonexistent header - assert_equal '1', @response.add_header('Bar', '1') - assert @response.has_header?('Bar') - assert_equal '1', @response.get_header('Bar') + assert_equal "1", @response.add_header("Bar", "1") + assert @response.has_header?("Bar") + assert_equal "1", @response.get_header("Bar") end end @@ -428,87 +448,87 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest @app = lambda { |env| ActionDispatch::Response.new.tap { |resp| resp.cache_control[:public] = true - resp.etag = '123' - resp.body = 'Hello' + resp.etag = "123" + resp.body = "Hello" resp.request = ActionDispatch::Request.empty }.to_a } - get '/' + get "/" assert_response :success - assert_equal('public', @response.headers['Cache-Control']) - assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.headers['ETag']) + assert_equal("public", @response.headers["Cache-Control"]) + assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.headers["ETag"]) assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.etag) - assert_equal({:public => true}, @response.cache_control) + assert_equal({ public: true }, @response.cache_control) end test "response cache control from rackish app" do @app = lambda { |env| [200, - {'ETag' => 'W/"202cb962ac59075b964b07152d234b70"', - 'Cache-Control' => 'public'}, ['Hello']] + { "ETag" => 'W/"202cb962ac59075b964b07152d234b70"', + "Cache-Control" => "public" }, ["Hello"]] } - get '/' + get "/" assert_response :success - assert_equal('public', @response.headers['Cache-Control']) - assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.headers['ETag']) + assert_equal("public", @response.headers["Cache-Control"]) + assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.headers["ETag"]) assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.etag) - assert_equal({:public => true}, @response.cache_control) + assert_equal({ public: true }, @response.cache_control) end test "response charset and content type from railsish app" do @app = lambda { |env| ActionDispatch::Response.new.tap { |resp| - resp.charset = 'utf-16' + resp.charset = "utf-16" resp.content_type = Mime[:xml] - resp.body = 'Hello' + resp.body = "Hello" resp.request = ActionDispatch::Request.empty }.to_a } - get '/' + get "/" assert_response :success - assert_equal('utf-16', @response.charset) + assert_equal("utf-16", @response.charset) assert_equal(Mime[:xml], @response.content_type) - assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type']) + assert_equal("application/xml; charset=utf-16", @response.headers["Content-Type"]) end test "response charset and content type from rackish app" do @app = lambda { |env| [200, - {'Content-Type' => 'application/xml; charset=utf-16'}, - ['Hello']] + { "Content-Type" => "application/xml; charset=utf-16" }, + ["Hello"]] } - get '/' + get "/" assert_response :success - assert_equal('utf-16', @response.charset) + assert_equal("utf-16", @response.charset) assert_equal(Mime[:xml], @response.content_type) - assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type']) + assert_equal("application/xml; charset=utf-16", @response.headers["Content-Type"]) end test "strong ETag validator" do @app = lambda { |env| ActionDispatch::Response.new.tap { |resp| - resp.strong_etag = '123' - resp.body = 'Hello' + resp.strong_etag = "123" + resp.body = "Hello" resp.request = ActionDispatch::Request.empty }.to_a } - get '/' + get "/" assert_response :ok - assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers['ETag']) + assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers["ETag"]) assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag) end end diff --git a/actionpack/test/dispatch/routing/concerns_test.rb b/actionpack/test/dispatch/routing/concerns_test.rb index 6934271846..2d71c37562 100644 --- a/actionpack/test/dispatch/routing/concerns_test.rb +++ b/actionpack/test/dispatch/routing/concerns_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ReviewsController < ResourcesController; end diff --git a/actionpack/test/dispatch/routing/inspector_test.rb b/actionpack/test/dispatch/routing/inspector_test.rb index 5aafcb23c2..a4babf8554 100644 --- a/actionpack/test/dispatch/routing/inspector_test.rb +++ b/actionpack/test/dispatch/routing/inspector_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'rails/engine' -require 'action_dispatch/routing/inspector' +require "abstract_unit" +require "rails/engine" +require "action_dispatch/routing/inspector" class MountedRackApp def self.call(env) @@ -30,11 +30,11 @@ module ActionDispatch end end engine.routes.draw do - get '/cart', :to => 'cart#show' + get "/cart", to: "cart#show" end output = draw do - get '/custom/assets', :to => 'custom_assets#show' + get "/custom/assets", to: "custom_assets#show" mount engine => "/blog", :as => "blog" end @@ -71,7 +71,7 @@ module ActionDispatch def test_cart_inspect output = draw do - get '/cart', :to => 'cart#show' + get "/cart", to: "cart#show" end assert_equal [ @@ -82,7 +82,7 @@ module ActionDispatch def test_articles_inspect_with_multiple_verbs output = draw do - match 'articles/:id', to: 'articles#update', via: [:put, :patch] + match "articles/:id", to: "articles#update", via: [:put, :patch] end assert_equal [ @@ -93,7 +93,7 @@ module ActionDispatch def test_inspect_shows_custom_assets output = draw do - get '/custom/assets', :to => 'custom_assets#show' + get "/custom/assets", to: "custom_assets#show" end assert_equal [ @@ -122,7 +122,7 @@ module ActionDispatch def test_inspect_routes_shows_root_route output = draw do - root :to => 'pages#main' + root to: "pages#main" end assert_equal [ @@ -134,7 +134,7 @@ module ActionDispatch def test_inspect_routes_shows_dynamic_action_route output = draw do ActiveSupport::Deprecation.silence do - get 'api/:action' => 'api' + get "api/:action" => "api" end end @@ -147,7 +147,7 @@ module ActionDispatch def test_inspect_routes_shows_controller_and_action_only_route output = draw do ActiveSupport::Deprecation.silence do - get ':controller/:action' + get ":controller/:action" end end @@ -160,7 +160,7 @@ module ActionDispatch def test_inspect_routes_shows_controller_and_action_route_with_constraints output = draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action(/:id))', :id => /\d+/ + get ":controller(/:action(/:id))", id: /\d+/ end end @@ -172,18 +172,18 @@ module ActionDispatch def test_rails_routes_shows_route_with_defaults output = draw do - get 'photos/:id' => 'photos#show', :defaults => {:format => 'jpg'} + get "photos/:id" => "photos#show", :defaults => { format: "jpg" } end assert_equal [ "Prefix Verb URI Pattern Controller#Action", - %Q[ GET /photos/:id(.:format) photos#show {:format=>"jpg"}] + ' GET /photos/:id(.:format) photos#show {:format=>"jpg"}' ], output end def test_rails_routes_shows_route_with_constraints output = draw do - get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/ + get "photos/:id" => "photos#show", :id => /[A-Z]\d{5}/ end assert_equal [ @@ -194,13 +194,13 @@ module ActionDispatch def test_rails_routes_shows_routes_with_dashes output = draw do - get 'about-us' => 'pages#about_us' - get 'our-work/latest' + get "about-us" => "pages#about_us" + get "our-work/latest" resources :photos, only: [:show] do - get 'user-favorites', on: :collection - get 'preview-photo', on: :member - get 'summary-text' + get "user-favorites", on: :collection + get "preview-photo", on: :member + get "summary-text" end end @@ -217,7 +217,7 @@ module ActionDispatch def test_rails_routes_shows_route_with_rack_app output = draw do - get 'foo/:id' => MountedRackApp, :id => /[A-Z]\d{5}/ + get "foo/:id" => MountedRackApp, :id => /[A-Z]\d{5}/ end assert_equal [ @@ -228,7 +228,7 @@ module ActionDispatch def test_rails_routes_shows_named_route_with_mounted_rack_app output = draw do - mount MountedRackApp => '/foo' + mount MountedRackApp => "/foo" end assert_equal [ @@ -239,7 +239,7 @@ module ActionDispatch def test_rails_routes_shows_overridden_named_route_with_mounted_rack_app_with_name output = draw do - mount MountedRackApp => '/foo', as: 'blog' + mount MountedRackApp => "/foo", as: "blog" end assert_equal [ @@ -256,8 +256,8 @@ module ActionDispatch end output = draw do - scope :constraint => constraint.new do - mount MountedRackApp => '/foo' + scope constraint: constraint.new do + mount MountedRackApp => "/foo" end end @@ -269,7 +269,7 @@ module ActionDispatch def test_rails_routes_dont_show_app_mounted_in_assets_prefix output = draw do - get '/sprockets' => MountedRackApp + get "/sprockets" => MountedRackApp end assert_no_match(/MountedRackApp/, output.first) assert_no_match(/\/sprockets/, output.first) @@ -277,8 +277,8 @@ module ActionDispatch def test_rails_routes_shows_route_defined_in_under_assets_prefix output = draw do - scope '/sprockets' do - get '/foo' => 'foo#bar' + scope "/sprockets" do + get "/foo" => "foo#bar" end end assert_equal [ @@ -289,9 +289,9 @@ module ActionDispatch def test_redirect output = draw do - get "/foo" => redirect("/foo/bar"), :constraints => { :subdomain => "admin" } + get "/foo" => redirect("/foo/bar"), :constraints => { subdomain: "admin" } get "/bar" => redirect(path: "/foo/bar", status: 307) - get "/foobar" => redirect{ "/foo/bar" } + get "/foobar" => redirect { "/foo/bar" } end assert_equal [ @@ -303,7 +303,7 @@ module ActionDispatch end def test_routes_can_be_filtered - output = draw('posts') do + output = draw("posts") do resources :articles resources :posts end @@ -320,7 +320,7 @@ module ActionDispatch end def test_routes_can_be_filtered_with_namespaced_controllers - output = draw('admin/posts') do + output = draw("admin/posts") do resources :articles namespace :admin do resources :posts @@ -338,11 +338,10 @@ module ActionDispatch " DELETE /admin/posts/:id(.:format) admin/posts#destroy"], output end - def test_regression_route_with_controller_regexp output = draw do ActiveSupport::Deprecation.silence do - get ':controller(/:action)', controller: /api\/[^\/]+/, format: false + get ":controller(/:action)", controller: /api\/[^\/]+/, format: false end end @@ -354,7 +353,7 @@ module ActionDispatch @set = ActionDispatch::Routing::RouteSet.new output = draw do - get '/cart', to: 'cart#show' + get "/cart", to: "cart#show" end assert_equal [ @@ -364,8 +363,8 @@ module ActionDispatch end def test_routes_with_undefined_filter - output = draw(controller: 'Rails::MissingController') do - get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/ + output = draw(controller: "Rails::MissingController") do + get "photos/:id" => "photos#show", :id => /[A-Z]\d{5}/ end assert_equal [ @@ -375,8 +374,8 @@ module ActionDispatch end def test_no_routes_matched_filter - output = draw('rails/dummy') do - get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/ + output = draw("rails/dummy") do + get "photos/:id" => "photos#show", :id => /[A-Z]\d{5}/ end assert_equal [ @@ -386,7 +385,7 @@ module ActionDispatch end def test_no_routes_were_defined - output = draw('Rails::DummyController') {} + output = draw("Rails::DummyController") {} assert_equal [ "You don't have any routes defined!", @@ -404,13 +403,13 @@ module ActionDispatch end end engine.routes.draw do - get '/cart', to: 'cart#show' - post '/cart', to: 'cart#create' - patch '/cart', to: 'cart#update' + get "/cart", to: "cart#show" + post "/cart", to: "cart#create" + patch "/cart", to: "cart#update" end output = draw do - get '/custom/assets', to: 'custom_assets#show' + get "/custom/assets", to: "custom_assets#show" mount engine => "/blog", as: "blog", internal: true end @@ -419,7 +418,6 @@ module ActionDispatch "custom_assets GET /custom/assets(.:format) custom_assets#show", ], output end - end end end diff --git a/actionpack/test/dispatch/routing/ipv6_redirect_test.rb b/actionpack/test/dispatch/routing/ipv6_redirect_test.rb index f1b2e8cfc7..4987ed84e4 100644 --- a/actionpack/test/dispatch/routing/ipv6_redirect_test.rb +++ b/actionpack/test/dispatch/routing/ipv6_redirect_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class IPv6IntegrationTest < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new @@ -7,17 +7,17 @@ class IPv6IntegrationTest < ActionDispatch::IntegrationTest class ::BadRouteRequestController < ActionController::Base include Routes.url_helpers def index - render :text => foo_path + render text: foo_path end def foo - redirect_to :action => :index + redirect_to action: :index end end Routes.draw do - get "/", :to => 'bad_route_request#index', :as => :index - get "/foo", :to => "bad_route_request#foo", :as => :foo + get "/", to: "bad_route_request#index", as: :index + get "/foo", to: "bad_route_request#foo", as: :foo end def _routes @@ -32,14 +32,13 @@ class IPv6IntegrationTest < ActionDispatch::IntegrationTest test "bad IPv6 redirection" do # def test_simple_redirect request_env = { - 'REMOTE_ADDR' => 'fd07:2fa:6cff:2112:225:90ff:fec7:22aa', - 'HTTP_HOST' => '[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]:3000', - 'SERVER_NAME' => '[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]', - 'SERVER_PORT' => 3000 } + "REMOTE_ADDR" => "fd07:2fa:6cff:2112:225:90ff:fec7:22aa", + "HTTP_HOST" => "[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]:3000", + "SERVER_NAME" => "[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]", + "SERVER_PORT" => 3000 } - get '/foo', env: request_env + get "/foo", env: request_env assert_response :redirect - assert_equal 'http://[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]:3000/', redirect_to_url + assert_equal "http://[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]:3000/", redirect_to_url end - end diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb index 9327fe12c6..ace35dda53 100644 --- a/actionpack/test/dispatch/routing/route_set_test.rb +++ b/actionpack/test/dispatch/routing/route_set_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Routing @@ -9,7 +9,7 @@ module ActionDispatch end def call(env) - [ 200, { 'Content-Type' => 'text/plain' }, [response] ] + [ 200, { "Content-Type" => "text/plain" }, [response] ] end end @@ -21,7 +21,7 @@ module ActionDispatch assert empty? draw do - get 'foo', to: SimpleApp.new('foo#index') + get "foo", to: SimpleApp.new("foo#index") end assert_not empty? @@ -29,101 +29,101 @@ module ActionDispatch test "url helpers are added when route is added" do draw do - get 'foo', to: SimpleApp.new('foo#index') + get "foo", to: SimpleApp.new("foo#index") end - assert_equal '/foo', url_helpers.foo_path + assert_equal "/foo", url_helpers.foo_path assert_raises NoMethodError do - assert_equal '/bar', url_helpers.bar_path + assert_equal "/bar", url_helpers.bar_path end draw do - get 'foo', to: SimpleApp.new('foo#index') - get 'bar', to: SimpleApp.new('bar#index') + get "foo", to: SimpleApp.new("foo#index") + get "bar", to: SimpleApp.new("bar#index") end - assert_equal '/foo', url_helpers.foo_path - assert_equal '/bar', url_helpers.bar_path + assert_equal "/foo", url_helpers.foo_path + assert_equal "/bar", url_helpers.bar_path end test "url helpers are updated when route is updated" do draw do - get 'bar', to: SimpleApp.new('bar#index'), as: :bar + get "bar", to: SimpleApp.new("bar#index"), as: :bar end - assert_equal '/bar', url_helpers.bar_path + assert_equal "/bar", url_helpers.bar_path draw do - get 'baz', to: SimpleApp.new('baz#index'), as: :bar + get "baz", to: SimpleApp.new("baz#index"), as: :bar end - assert_equal '/baz', url_helpers.bar_path + assert_equal "/baz", url_helpers.bar_path end test "url helpers are removed when route is removed" do draw do - get 'foo', to: SimpleApp.new('foo#index') - get 'bar', to: SimpleApp.new('bar#index') + get "foo", to: SimpleApp.new("foo#index") + get "bar", to: SimpleApp.new("bar#index") end - assert_equal '/foo', url_helpers.foo_path - assert_equal '/bar', url_helpers.bar_path + assert_equal "/foo", url_helpers.foo_path + assert_equal "/bar", url_helpers.bar_path draw do - get 'foo', to: SimpleApp.new('foo#index') + get "foo", to: SimpleApp.new("foo#index") end - assert_equal '/foo', url_helpers.foo_path + assert_equal "/foo", url_helpers.foo_path assert_raises NoMethodError do - assert_equal '/bar', url_helpers.bar_path + assert_equal "/bar", url_helpers.bar_path end end test "only_path: true with *_url and no :host option" do draw do - get 'foo', to: SimpleApp.new('foo#index') + get "foo", to: SimpleApp.new("foo#index") end - assert_equal '/foo', url_helpers.foo_url(only_path: true) + assert_equal "/foo", url_helpers.foo_url(only_path: true) end test "only_path: false with *_url and no :host option" do draw do - get 'foo', to: SimpleApp.new('foo#index') + get "foo", to: SimpleApp.new("foo#index") end assert_raises ArgumentError do - assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false) + assert_equal "http://example.com/foo", url_helpers.foo_url(only_path: false) end end test "only_path: false with *_url and local :host option" do draw do - get 'foo', to: SimpleApp.new('foo#index') + get "foo", to: SimpleApp.new("foo#index") end - assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false, host: 'example.com') + assert_equal "http://example.com/foo", url_helpers.foo_url(only_path: false, host: "example.com") end test "only_path: false with *_url and global :host option" do - @set.default_url_options = { host: 'example.com' } + @set.default_url_options = { host: "example.com" } draw do - get 'foo', to: SimpleApp.new('foo#index') + get "foo", to: SimpleApp.new("foo#index") end - assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false) + assert_equal "http://example.com/foo", url_helpers.foo_url(only_path: false) end test "explicit keys win over implicit keys" do draw do resources :foo do - resources :bar, to: SimpleApp.new('foo#show') + resources :bar, to: SimpleApp.new("foo#show") end end - assert_equal '/foo/1/bar/2', url_helpers.foo_bar_path(1, 2) - assert_equal '/foo/1/bar/2', url_helpers.foo_bar_path(2, foo_id: 1) + assert_equal "/foo/1/bar/2", url_helpers.foo_bar_path(1, 2) + assert_equal "/foo/1/bar/2", url_helpers.foo_bar_path(2, foo_id: 1) end test "having an optional scope with resources" do @@ -133,9 +133,9 @@ module ActionDispatch end end - assert_equal '/users/1', url_helpers.user_path(1) - assert_equal '/users/1', url_helpers.user_path(1, foo: nil) - assert_equal '/a/users/1', url_helpers.user_path(1, foo: 'a') + assert_equal "/users/1", url_helpers.user_path(1) + assert_equal "/users/1", url_helpers.user_path(1, foo: nil) + assert_equal "/a/users/1", url_helpers.user_path(1, foo: "a") end private diff --git a/actionpack/test/dispatch/routing_assertions_test.rb b/actionpack/test/dispatch/routing_assertions_test.rb index 56ea644f22..917ce7e668 100644 --- a/actionpack/test/dispatch/routing_assertions_test.rb +++ b/actionpack/test/dispatch/routing_assertions_test.rb @@ -1,130 +1,129 @@ -require 'abstract_unit' -require 'controller/fake_controllers' +require "abstract_unit" +require "controller/fake_controllers" class SecureArticlesController < ArticlesController; end class BlockArticlesController < ArticlesController; end class QueryArticlesController < ArticlesController; end class RoutingAssertionsTest < ActionController::TestCase - def setup @routes = ActionDispatch::Routing::RouteSet.new @routes.draw do resources :articles - scope 'secure', :constraints => { :protocol => 'https://' } do - resources :articles, :controller => 'secure_articles' + scope "secure", constraints: { protocol: "https://" } do + resources :articles, controller: "secure_articles" end - scope 'block', :constraints => lambda { |r| r.ssl? } do - resources :articles, :controller => 'block_articles' + scope "block", constraints: lambda { |r| r.ssl? } do + resources :articles, controller: "block_articles" end - scope 'query', :constraints => lambda { |r| r.params[:use_query] == 'true' } do - resources :articles, :controller => 'query_articles' + scope "query", constraints: lambda { |r| r.params[:use_query] == "true" } do + resources :articles, controller: "query_articles" end end end def test_assert_generates - assert_generates('/articles', { :controller => 'articles', :action => 'index' }) - assert_generates('/articles/1', { :controller => 'articles', :action => 'show', :id => '1' }) + assert_generates("/articles", controller: "articles", action: "index") + assert_generates("/articles/1", controller: "articles", action: "show", id: "1") end def test_assert_generates_with_defaults - assert_generates('/articles/1/edit', { :controller => 'articles', :action => 'edit' }, { :id => '1' }) + assert_generates("/articles/1/edit", { controller: "articles", action: "edit" }, id: "1") end def test_assert_generates_with_extras - assert_generates('/articles', { :controller => 'articles', :action => 'index', :page => '1' }, {}, { :page => '1' }) + assert_generates("/articles", { controller: "articles", action: "index", page: "1" }, {}, page: "1") end def test_assert_recognizes - assert_recognizes({ :controller => 'articles', :action => 'index' }, '/articles') - assert_recognizes({ :controller => 'articles', :action => 'show', :id => '1' }, '/articles/1') + assert_recognizes({ controller: "articles", action: "index" }, "/articles") + assert_recognizes({ controller: "articles", action: "show", id: "1" }, "/articles/1") end def test_assert_recognizes_with_extras - assert_recognizes({ :controller => 'articles', :action => 'index', :page => '1' }, '/articles', { :page => '1' }) + assert_recognizes({ controller: "articles", action: "index", page: "1" }, "/articles", page: "1") end def test_assert_recognizes_with_method - assert_recognizes({ :controller => 'articles', :action => 'create' }, { :path => '/articles', :method => :post }) - assert_recognizes({ :controller => 'articles', :action => 'update', :id => '1' }, { :path => '/articles/1', :method => :put }) + assert_recognizes({ controller: "articles", action: "create" }, path: "/articles", method: :post) + assert_recognizes({ controller: "articles", action: "update", id: "1" }, path: "/articles/1", method: :put) end def test_assert_recognizes_with_hash_constraint assert_raise(Assertion) do - assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'http://test.host/secure/articles') + assert_recognizes({ controller: "secure_articles", action: "index" }, "http://test.host/secure/articles") end - assert_recognizes({ :controller => 'secure_articles', :action => 'index', :protocol => 'https://' }, 'https://test.host/secure/articles') + assert_recognizes({ controller: "secure_articles", action: "index", protocol: "https://" }, "https://test.host/secure/articles") end def test_assert_recognizes_with_block_constraint assert_raise(Assertion) do - assert_recognizes({ :controller => 'block_articles', :action => 'index' }, 'http://test.host/block/articles') + assert_recognizes({ controller: "block_articles", action: "index" }, "http://test.host/block/articles") end - assert_recognizes({ :controller => 'block_articles', :action => 'index' }, 'https://test.host/block/articles') + assert_recognizes({ controller: "block_articles", action: "index" }, "https://test.host/block/articles") end def test_assert_recognizes_with_query_constraint assert_raise(Assertion) do - assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'false' }, '/query/articles', { :use_query => 'false' }) + assert_recognizes({ controller: "query_articles", action: "index", use_query: "false" }, "/query/articles", use_query: "false") end - assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'true' }, '/query/articles', { :use_query => 'true' }) + assert_recognizes({ controller: "query_articles", action: "index", use_query: "true" }, "/query/articles", use_query: "true") end def test_assert_recognizes_raises_message err = assert_raise(Assertion) do - assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'http://test.host/secure/articles', {}, "This is a really bad msg") + assert_recognizes({ controller: "secure_articles", action: "index" }, "http://test.host/secure/articles", {}, "This is a really bad msg") end assert_match err.message, "This is a really bad msg" end def test_assert_routing - assert_routing('/articles', :controller => 'articles', :action => 'index') + assert_routing("/articles", controller: "articles", action: "index") end def test_assert_routing_raises_message err = assert_raise(Assertion) do - assert_routing('/thisIsNotARoute', { :controller => 'articles', :action => 'edit', :id => '1' }, { :id => '1' }, {}, "This is a really bad msg") + assert_routing("/thisIsNotARoute", { controller: "articles", action: "edit", id: "1" }, { id: "1" }, {}, "This is a really bad msg") end assert_match err.message, "This is a really bad msg" end def test_assert_routing_with_defaults - assert_routing('/articles/1/edit', { :controller => 'articles', :action => 'edit', :id => '1' }, { :id => '1' }) + assert_routing("/articles/1/edit", { controller: "articles", action: "edit", id: "1" }, id: "1") end def test_assert_routing_with_extras - assert_routing('/articles', { :controller => 'articles', :action => 'index', :page => '1' }, { }, { :page => '1' }) + assert_routing("/articles", { controller: "articles", action: "index", page: "1" }, {}, page: "1") end def test_assert_routing_with_hash_constraint assert_raise(Assertion) do - assert_routing('http://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' }) + assert_routing("http://test.host/secure/articles", controller: "secure_articles", action: "index") end - assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index', :protocol => 'https://' }) + assert_routing("https://test.host/secure/articles", controller: "secure_articles", action: "index", protocol: "https://") end def test_assert_routing_with_block_constraint assert_raise(Assertion) do - assert_routing('http://test.host/block/articles', { :controller => 'block_articles', :action => 'index' }) + assert_routing("http://test.host/block/articles", controller: "block_articles", action: "index") end - assert_routing('https://test.host/block/articles', { :controller => 'block_articles', :action => 'index' }) + assert_routing("https://test.host/block/articles", controller: "block_articles", action: "index") end def test_with_routing with_routing do |routes| routes.draw do - resources :articles, :path => 'artikel' + resources :articles, path: "artikel" end - assert_routing('/artikel', :controller => 'articles', :action => 'index') + assert_routing("/artikel", controller: "articles", action: "index") assert_raise(Assertion) do - assert_routing('/articles', { :controller => 'articles', :action => 'index' }) + assert_routing("/articles", controller: "articles", action: "index") end end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 75fdc9469f..c01065932a 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -1,10 +1,10 @@ -require 'erb' -require 'abstract_unit' -require 'controller/fake_controllers' +require "erb" +require "abstract_unit" +require "controller/fake_controllers" class TestRoutingMapper < ActionDispatch::IntegrationTest SprocketsApp = lambda { |env| - [200, {"Content-Type" => "text/html"}, ["javascripts"]] + [200, { "Content-Type" => "text/html" }, ["javascripts"]] } class IpRestrictor @@ -28,87 +28,87 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_logout draw do controller :sessions do - delete 'logout' => :destroy + delete "logout" => :destroy end end - delete '/logout' - assert_equal 'sessions#destroy', @response.body + delete "/logout" + assert_equal "sessions#destroy", @response.body - assert_equal '/logout', logout_path - assert_equal '/logout', url_for(:controller => 'sessions', :action => 'destroy', :only_path => true) + assert_equal "/logout", logout_path + assert_equal "/logout", url_for(controller: "sessions", action: "destroy", only_path: true) end def test_login draw do - default_url_options :host => "rubyonrails.org" + default_url_options host: "rubyonrails.org" controller :sessions do - get 'login' => :new - post 'login' => :create + get "login" => :new + post "login" => :create end end - get '/login' - assert_equal 'sessions#new', @response.body - assert_equal '/login', login_path + get "/login" + assert_equal "sessions#new", @response.body + assert_equal "/login", login_path - post '/login' - assert_equal 'sessions#create', @response.body + post "/login" + assert_equal "sessions#create", @response.body - assert_equal '/login', url_for(:controller => 'sessions', :action => 'create', :only_path => true) - assert_equal '/login', url_for(:controller => 'sessions', :action => 'new', :only_path => true) + assert_equal "/login", url_for(controller: "sessions", action: "create", only_path: true) + assert_equal "/login", url_for(controller: "sessions", action: "new", only_path: true) - assert_equal 'http://rubyonrails.org/login', url_for(:controller => 'sessions', :action => 'create') - assert_equal 'http://rubyonrails.org/login', login_url + assert_equal "http://rubyonrails.org/login", url_for(controller: "sessions", action: "create") + assert_equal "http://rubyonrails.org/login", login_url end def test_login_redirect draw do - get 'account/login', :to => redirect("/login") + get "account/login", to: redirect("/login") end - get '/account/login' - verify_redirect 'http://www.example.com/login' + get "/account/login" + verify_redirect "http://www.example.com/login" end def test_logout_redirect_without_to draw do - get 'account/logout' => redirect("/logout"), :as => :logout_redirect + get "account/logout" => redirect("/logout"), :as => :logout_redirect end - assert_equal '/account/logout', logout_redirect_path - get '/account/logout' - verify_redirect 'http://www.example.com/logout' + assert_equal "/account/logout", logout_redirect_path + get "/account/logout" + verify_redirect "http://www.example.com/logout" end def test_namespace_redirect draw do namespace :private do - root :to => redirect('/private/index') - get "index", :to => 'private#index' + root to: redirect("/private/index") + get "index", to: "private#index" end end - get '/private' - verify_redirect 'http://www.example.com/private/index' + get "/private" + verify_redirect "http://www.example.com/private/index" end def test_redirect_with_failing_constraint draw do - get 'hi', to: redirect("/foo"), constraints: ::TestRoutingMapper::GrumpyRestrictor + get "hi", to: redirect("/foo"), constraints: ::TestRoutingMapper::GrumpyRestrictor end - get '/hi' + get "/hi" assert_equal 404, status end def test_redirect_with_passing_constraint draw do - get 'hi', to: redirect("/foo"), constraints: ->(req) { true } + get "hi", to: redirect("/foo"), constraints: ->(req) { true } end - get '/hi' + get "/hi" assert_equal 301, status end @@ -117,7 +117,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest draw do namespace :admin do ActiveSupport::Deprecation.silence do - get '/:controller(/:action(/:id(.:format)))' + get "/:controller(/:action(/:id(.:format)))" end end end @@ -128,12 +128,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest draw do namespace :admin do ActiveSupport::Deprecation.silence do - get 'hello/:controllers/:action' + get "hello/:controllers/:action" end end end - get '/admin/hello/foo/new' - assert_equal 'foo', @request.params["controllers"] + get "/admin/hello/foo/new" + assert_equal "foo", @request.params["controllers"] end def test_session_singleton_resource @@ -144,30 +144,30 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/session' - assert_equal 'sessions#create', @response.body - assert_equal '/session', session_path + get "/session" + assert_equal "sessions#create", @response.body + assert_equal "/session", session_path - post '/session' - assert_equal 'sessions#create', @response.body + post "/session" + assert_equal "sessions#create", @response.body - put '/session' - assert_equal 'sessions#update', @response.body + put "/session" + assert_equal "sessions#update", @response.body - delete '/session' - assert_equal 'sessions#destroy', @response.body + delete "/session" + assert_equal "sessions#destroy", @response.body - get '/session/new' - assert_equal 'sessions#new', @response.body - assert_equal '/session/new', new_session_path + get "/session/new" + assert_equal "sessions#new", @response.body + assert_equal "/session/new", new_session_path - get '/session/edit' - assert_equal 'sessions#edit', @response.body - assert_equal '/session/edit', edit_session_path + get "/session/edit" + assert_equal "sessions#edit", @response.body + assert_equal "/session/edit", edit_session_path - post '/session/reset' - assert_equal 'sessions#reset', @response.body - assert_equal '/session/reset', reset_session_path + post "/session/reset" + assert_equal "sessions#reset", @response.body + assert_equal "/session/reset", reset_session_path end def test_session_singleton_resource_for_api_app @@ -184,28 +184,28 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest @app = RoutedRackApp.new routes end - get '/session' - assert_equal 'sessions#create', @response.body - assert_equal '/session', session_path + get "/session" + assert_equal "sessions#create", @response.body + assert_equal "/session", session_path - post '/session' - assert_equal 'sessions#create', @response.body + post "/session" + assert_equal "sessions#create", @response.body - put '/session' - assert_equal 'sessions#update', @response.body + put "/session" + assert_equal "sessions#update", @response.body - delete '/session' - assert_equal 'sessions#destroy', @response.body + delete "/session" + assert_equal "sessions#destroy", @response.body - post '/session/reset' - assert_equal 'sessions#reset', @response.body - assert_equal '/session/reset', reset_session_path + post "/session/reset" + assert_equal "sessions#reset", @response.body + assert_equal "/session/reset", reset_session_path - get '/session/new' - assert_equal 'Not Found', @response.body + get "/session/new" + assert_equal "Not Found", @response.body - get '/session/edit' - assert_equal 'Not Found', @response.body + get "/session/edit" + assert_equal "Not Found", @response.body end def test_session_info_nested_singleton_resource @@ -215,9 +215,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/session/info' - assert_equal 'infos#show', @response.body - assert_equal '/session/info', session_info_path + get "/session/info" + assert_equal "infos#show", @response.body + assert_equal "/session/info", session_info_path end def test_member_on_resource @@ -229,241 +229,243 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/session/crush' - assert_equal 'sessions#crush', @response.body - assert_equal '/session/crush', crush_session_path + get "/session/crush" + assert_equal "sessions#crush", @response.body + assert_equal "/session/crush", crush_session_path end def test_redirect_modulo draw do - get 'account/modulo/:name', :to => redirect("/%{name}s") + get "account/modulo/:name", to: redirect("/%{name}s") end - get '/account/modulo/name' - verify_redirect 'http://www.example.com/names' + get "/account/modulo/name" + verify_redirect "http://www.example.com/names" end def test_redirect_proc draw do - get 'account/proc/:name', :to => redirect {|params, req| "/#{params[:name].pluralize}" } + get "account/proc/:name", to: redirect { |params, req| "/#{params[:name].pluralize}" } end - get '/account/proc/person' - verify_redirect 'http://www.example.com/people' + get "/account/proc/person" + verify_redirect "http://www.example.com/people" end def test_redirect_proc_with_request draw do - get 'account/proc_req' => redirect {|params, req| "/#{req.method}" } + get "account/proc_req" => redirect { |params, req| "/#{req.method}" } end - get '/account/proc_req' - verify_redirect 'http://www.example.com/GET' + get "/account/proc_req" + verify_redirect "http://www.example.com/GET" end def test_redirect_hash_with_subdomain draw do - get 'mobile', :to => redirect(:subdomain => 'mobile') + get "mobile", to: redirect(subdomain: "mobile") end - get '/mobile' - verify_redirect 'http://mobile.example.com/mobile' + get "/mobile" + verify_redirect "http://mobile.example.com/mobile" end def test_redirect_hash_with_domain_and_path draw do - get 'documentation', :to => redirect(:domain => 'example-documentation.com', :path => '') + get "documentation", to: redirect(domain: "example-documentation.com", path: "") end - get '/documentation' - verify_redirect 'http://www.example-documentation.com' + get "/documentation" + verify_redirect "http://www.example-documentation.com" end def test_redirect_hash_with_path draw do - get 'new_documentation', :to => redirect(:path => '/documentation/new') + get "new_documentation", to: redirect(path: "/documentation/new") end - get '/new_documentation' - verify_redirect 'http://www.example.com/documentation/new' + get "/new_documentation" + verify_redirect "http://www.example.com/documentation/new" end def test_redirect_hash_with_host draw do - get 'super_new_documentation', :to => redirect(:host => 'super-docs.com') + get "super_new_documentation", to: redirect(host: "super-docs.com") end - get '/super_new_documentation?section=top' - verify_redirect 'http://super-docs.com/super_new_documentation?section=top' + get "/super_new_documentation?section=top" + verify_redirect "http://super-docs.com/super_new_documentation?section=top" end def test_redirect_hash_path_substitution draw do - get 'stores/:name', :to => redirect(:subdomain => 'stores', :path => '/%{name}') + get "stores/:name", to: redirect(subdomain: "stores", path: "/%{name}") end - get '/stores/iernest' - verify_redirect 'http://stores.example.com/iernest' + get "/stores/iernest" + verify_redirect "http://stores.example.com/iernest" end def test_redirect_hash_path_substitution_with_catch_all draw do - get 'stores/:name(*rest)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{rest}') + get "stores/:name(*rest)", to: redirect(subdomain: "stores", path: "/%{name}%{rest}") end - get '/stores/iernest/products' - verify_redirect 'http://stores.example.com/iernest/products' + get "/stores/iernest/products" + verify_redirect "http://stores.example.com/iernest/products" end def test_redirect_class draw do - get 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector) + get "youtube_favorites/:youtube_id/:name", to: redirect(YoutubeFavoritesRedirector) end - get '/youtube_favorites/oHg5SJYRHA0/rick-rolld' - verify_redirect 'http://www.youtube.com/watch?v=oHg5SJYRHA0' + get "/youtube_favorites/oHg5SJYRHA0/rick-rolld" + verify_redirect "http://www.youtube.com/watch?v=oHg5SJYRHA0" end def test_openid draw do - match 'openid/login', :via => [:get, :post], :to => "openid#login" + match "openid/login", via: [:get, :post], to: "openid#login" end - get '/openid/login' - assert_equal 'openid#login', @response.body + get "/openid/login" + assert_equal "openid#login", @response.body - post '/openid/login' - assert_equal 'openid#login', @response.body + post "/openid/login" + assert_equal "openid#login", @response.body end def test_bookmarks draw do - scope "bookmark", :controller => "bookmarks", :as => :bookmark do - get :new, :path => "build" - post :create, :path => "create", :as => "" + scope "bookmark", controller: "bookmarks", as: :bookmark do + get :new, path: "build" + post :create, path: "create", as: "" put :update - get :remove, :action => :destroy, :as => :remove + get :remove, action: :destroy, as: :remove end end - get '/bookmark/build' - assert_equal 'bookmarks#new', @response.body - assert_equal '/bookmark/build', bookmark_new_path + get "/bookmark/build" + assert_equal "bookmarks#new", @response.body + assert_equal "/bookmark/build", bookmark_new_path - post '/bookmark/create' - assert_equal 'bookmarks#create', @response.body - assert_equal '/bookmark/create', bookmark_path + post "/bookmark/create" + assert_equal "bookmarks#create", @response.body + assert_equal "/bookmark/create", bookmark_path - put '/bookmark/update' - assert_equal 'bookmarks#update', @response.body - assert_equal '/bookmark/update', bookmark_update_path + put "/bookmark/update" + assert_equal "bookmarks#update", @response.body + assert_equal "/bookmark/update", bookmark_update_path - get '/bookmark/remove' - assert_equal 'bookmarks#destroy', @response.body - assert_equal '/bookmark/remove', bookmark_remove_path + get "/bookmark/remove" + assert_equal "bookmarks#destroy", @response.body + assert_equal "/bookmark/remove", bookmark_remove_path end def test_pagemarks - tc = self draw do - scope "pagemark", :controller => "pagemarks", :as => :pagemark do - tc.assert_deprecated do - get "new", :path => "build" - end - post "create", :as => "" + scope "pagemark", controller: "pagemarks", as: :pagemark do + get "build", action: "new", as: "new" + post "create", as: "" put "update" - get "remove", :action => :destroy, :as => :remove + get "remove", action: :destroy, as: :remove + get "", action: :show, as: :show end end - get '/pagemark/build' - assert_equal 'pagemarks#new', @response.body - assert_equal '/pagemark/build', pagemark_new_path + get "/pagemark/build" + assert_equal "pagemarks#new", @response.body + assert_equal "/pagemark/build", pagemark_new_path + + post "/pagemark/create" + assert_equal "pagemarks#create", @response.body + assert_equal "/pagemark/create", pagemark_path - post '/pagemark/create' - assert_equal 'pagemarks#create', @response.body - assert_equal '/pagemark/create', pagemark_path + put "/pagemark/update" + assert_equal "pagemarks#update", @response.body + assert_equal "/pagemark/update", pagemark_update_path - put '/pagemark/update' - assert_equal 'pagemarks#update', @response.body - assert_equal '/pagemark/update', pagemark_update_path + get "/pagemark/remove" + assert_equal "pagemarks#destroy", @response.body + assert_equal "/pagemark/remove", pagemark_remove_path - get '/pagemark/remove' - assert_equal 'pagemarks#destroy', @response.body - assert_equal '/pagemark/remove', pagemark_remove_path + get "/pagemark" + assert_equal "pagemarks#show", @response.body + assert_equal "/pagemark", pagemark_show_path end def test_admin draw do - constraints(:ip => /192\.168\.1\.\d\d\d/) do - get 'admin' => "queenbee#index" + constraints(ip: /192\.168\.1\.\d\d\d/) do + get "admin" => "queenbee#index" end constraints ::TestRoutingMapper::IpRestrictor do - get 'admin/accounts' => "queenbee#accounts" + get "admin/accounts" => "queenbee#accounts" end - get 'admin/passwords' => "queenbee#passwords", :constraints => ::TestRoutingMapper::IpRestrictor + get "admin/passwords" => "queenbee#passwords", :constraints => ::TestRoutingMapper::IpRestrictor end - get '/admin', headers: { 'REMOTE_ADDR' => '192.168.1.100' } - assert_equal 'queenbee#index', @response.body + get "/admin", headers: { "REMOTE_ADDR" => "192.168.1.100" } + assert_equal "queenbee#index", @response.body - get '/admin', headers: { 'REMOTE_ADDR' => '10.0.0.100' } - assert_equal 'pass', @response.headers['X-Cascade'] + get "/admin", headers: { "REMOTE_ADDR" => "10.0.0.100" } + assert_equal "pass", @response.headers["X-Cascade"] - get '/admin/accounts', headers: { 'REMOTE_ADDR' => '192.168.1.100' } - assert_equal 'queenbee#accounts', @response.body + get "/admin/accounts", headers: { "REMOTE_ADDR" => "192.168.1.100" } + assert_equal "queenbee#accounts", @response.body - get '/admin/accounts', headers: { 'REMOTE_ADDR' => '10.0.0.100' } - assert_equal 'pass', @response.headers['X-Cascade'] + get "/admin/accounts", headers: { "REMOTE_ADDR" => "10.0.0.100" } + assert_equal "pass", @response.headers["X-Cascade"] - get '/admin/passwords', headers: { 'REMOTE_ADDR' => '192.168.1.100' } - assert_equal 'queenbee#passwords', @response.body + get "/admin/passwords", headers: { "REMOTE_ADDR" => "192.168.1.100" } + assert_equal "queenbee#passwords", @response.body - get '/admin/passwords', headers: { 'REMOTE_ADDR' => '10.0.0.100' } - assert_equal 'pass', @response.headers['X-Cascade'] + get "/admin/passwords", headers: { "REMOTE_ADDR" => "10.0.0.100" } + assert_equal "pass", @response.headers["X-Cascade"] end def test_global draw do controller(:global) do - get 'global/hide_notice' - get 'global/export', :action => :export, :as => :export_request - get '/export/:id/:file', :action => :export, :as => :export_download, :constraints => { :file => /.*/ } + get "global/hide_notice" + get "global/export", action: :export, as: :export_request + get "/export/:id/:file", action: :export, as: :export_download, constraints: { file: /.*/ } ActiveSupport::Deprecation.silence do - get 'global/:action' + get "global/:action" end end end - get '/global/dashboard' - assert_equal 'global#dashboard', @response.body + get "/global/dashboard" + assert_equal "global#dashboard", @response.body - get '/global/export' - assert_equal 'global#export', @response.body + get "/global/export" + assert_equal "global#export", @response.body - get '/global/hide_notice' - assert_equal 'global#hide_notice', @response.body + get "/global/hide_notice" + assert_equal "global#hide_notice", @response.body - get '/export/123/foo.txt' - assert_equal 'global#export', @response.body + get "/export/123/foo.txt" + assert_equal "global#export", @response.body - assert_equal '/global/export', export_request_path - assert_equal '/global/hide_notice', global_hide_notice_path - assert_equal '/export/123/foo.txt', export_download_path(:id => 123, :file => 'foo.txt') + assert_equal "/global/export", export_request_path + assert_equal "/global/hide_notice", global_hide_notice_path + assert_equal "/export/123/foo.txt", export_download_path(id: 123, file: "foo.txt") end def test_local draw do ActiveSupport::Deprecation.silence do - get "/local/:action", :controller => "local" + get "/local/:action", controller: "local" end end - get '/local/dashboard' - assert_equal 'local#dashboard', @response.body + get "/local/dashboard" + assert_equal "local#dashboard", @response.body end # tests the use of dup in url_for @@ -473,7 +475,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end # without dup, additional (and possibly unwanted) values will be present in the options (eg. :host) - original_options = {:controller => 'projects', :action => 'status'} + original_options = { controller: "projects", action: "status" } options = original_options.dup url_for options @@ -487,23 +489,23 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "/projects/status(.:format)" end - controller = '/projects' - options = {:controller => controller, :action => 'status', :only_path => true} + controller = "/projects" + options = { controller: controller, action: "status", only_path: true } url = url_for(options) - assert_equal '/projects/status', url - assert_equal '/projects', controller + assert_equal "/projects/status", url + assert_equal "/projects", controller end # tests the arguments modification free version of define_hash_access def test_named_route_with_no_side_effects draw do resources :customers do - get "profile", :on => :member + get "profile", on: :member end end - original_options = { :host => 'test.host' } + original_options = { host: "test.host" } options = original_options.dup profile_customer_url("customer_model", options) @@ -517,45 +519,45 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "/projects/status(.:format)" end - assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true) - assert_equal '/projects/status.json', url_for(:controller => 'projects', :action => 'status', :format => 'json', :only_path => true) + assert_equal "/projects/status", url_for(controller: "projects", action: "status", only_path: true) + assert_equal "/projects/status.json", url_for(controller: "projects", action: "status", format: "json", only_path: true) end def test_projects draw do - resources :projects, :controller => :project + resources :projects, controller: :project end - get '/projects' - assert_equal 'project#index', @response.body - assert_equal '/projects', projects_path + get "/projects" + assert_equal "project#index", @response.body + assert_equal "/projects", projects_path - post '/projects' - assert_equal 'project#create', @response.body + post "/projects" + assert_equal "project#create", @response.body - get '/projects.xml' - assert_equal 'project#index', @response.body - assert_equal '/projects.xml', projects_path(:format => 'xml') + get "/projects.xml" + assert_equal "project#index", @response.body + assert_equal "/projects.xml", projects_path(format: "xml") - get '/projects/new' - assert_equal 'project#new', @response.body - assert_equal '/projects/new', new_project_path + get "/projects/new" + assert_equal "project#new", @response.body + assert_equal "/projects/new", new_project_path - get '/projects/new.xml' - assert_equal 'project#new', @response.body - assert_equal '/projects/new.xml', new_project_path(:format => 'xml') + get "/projects/new.xml" + assert_equal "project#new", @response.body + assert_equal "/projects/new.xml", new_project_path(format: "xml") - get '/projects/1' - assert_equal 'project#show', @response.body - assert_equal '/projects/1', project_path(:id => '1') + get "/projects/1" + assert_equal "project#show", @response.body + assert_equal "/projects/1", project_path(id: "1") - get '/projects/1.xml' - assert_equal 'project#show', @response.body - assert_equal '/projects/1.xml', project_path(:id => '1', :format => 'xml') + get "/projects/1.xml" + assert_equal "project#show", @response.body + assert_equal "/projects/1.xml", project_path(id: "1", format: "xml") - get '/projects/1/edit' - assert_equal 'project#edit', @response.body - assert_equal '/projects/1/edit', edit_project_path(:id => '1') + get "/projects/1/edit" + assert_equal "project#edit", @response.body + assert_equal "/projects/1/edit", edit_project_path(id: "1") end def test_projects_for_api_app @@ -569,166 +571,166 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest @app = RoutedRackApp.new routes end - get '/projects' - assert_equal 'project#index', @response.body - assert_equal '/projects', projects_path + get "/projects" + assert_equal "project#index", @response.body + assert_equal "/projects", projects_path - post '/projects' - assert_equal 'project#create', @response.body + post "/projects" + assert_equal "project#create", @response.body - get '/projects.xml' - assert_equal 'project#index', @response.body - assert_equal '/projects.xml', projects_path(format: 'xml') + get "/projects.xml" + assert_equal "project#index", @response.body + assert_equal "/projects.xml", projects_path(format: "xml") - get '/projects/1' - assert_equal 'project#show', @response.body - assert_equal '/projects/1', project_path(id: '1') + get "/projects/1" + assert_equal "project#show", @response.body + assert_equal "/projects/1", project_path(id: "1") - get '/projects/1.xml' - assert_equal 'project#show', @response.body - assert_equal '/projects/1.xml', project_path(id: '1', format: 'xml') + get "/projects/1.xml" + assert_equal "project#show", @response.body + assert_equal "/projects/1.xml", project_path(id: "1", format: "xml") - get '/projects/1/edit' - assert_equal 'Not Found', @response.body + get "/projects/1/edit" + assert_equal "Not Found", @response.body end def test_projects_with_post_action_and_new_path_on_collection draw do - resources :projects, :controller => :project do - post 'new', :action => 'new', :on => :collection, :as => :new + resources :projects, controller: :project do + post "new", action: "new", on: :collection, as: :new end end - post '/projects/new' + post "/projects/new" assert_equal "project#new", @response.body assert_equal "/projects/new", new_projects_path end def test_projects_involvements draw do - resources :projects, :controller => :project do + resources :projects, controller: :project do resources :involvements, :attachments end end - get '/projects/1/involvements' - assert_equal 'involvements#index', @response.body - assert_equal '/projects/1/involvements', project_involvements_path(:project_id => '1') + get "/projects/1/involvements" + assert_equal "involvements#index", @response.body + assert_equal "/projects/1/involvements", project_involvements_path(project_id: "1") - get '/projects/1/involvements/new' - assert_equal 'involvements#new', @response.body - assert_equal '/projects/1/involvements/new', new_project_involvement_path(:project_id => '1') + get "/projects/1/involvements/new" + assert_equal "involvements#new", @response.body + assert_equal "/projects/1/involvements/new", new_project_involvement_path(project_id: "1") - get '/projects/1/involvements/1' - assert_equal 'involvements#show', @response.body - assert_equal '/projects/1/involvements/1', project_involvement_path(:project_id => '1', :id => '1') + get "/projects/1/involvements/1" + assert_equal "involvements#show", @response.body + assert_equal "/projects/1/involvements/1", project_involvement_path(project_id: "1", id: "1") - put '/projects/1/involvements/1' - assert_equal 'involvements#update', @response.body + put "/projects/1/involvements/1" + assert_equal "involvements#update", @response.body - delete '/projects/1/involvements/1' - assert_equal 'involvements#destroy', @response.body + delete "/projects/1/involvements/1" + assert_equal "involvements#destroy", @response.body - get '/projects/1/involvements/1/edit' - assert_equal 'involvements#edit', @response.body - assert_equal '/projects/1/involvements/1/edit', edit_project_involvement_path(:project_id => '1', :id => '1') + get "/projects/1/involvements/1/edit" + assert_equal "involvements#edit", @response.body + assert_equal "/projects/1/involvements/1/edit", edit_project_involvement_path(project_id: "1", id: "1") end def test_projects_attachments draw do - resources :projects, :controller => :project do + resources :projects, controller: :project do resources :involvements, :attachments end end - get '/projects/1/attachments' - assert_equal 'attachments#index', @response.body - assert_equal '/projects/1/attachments', project_attachments_path(:project_id => '1') + get "/projects/1/attachments" + assert_equal "attachments#index", @response.body + assert_equal "/projects/1/attachments", project_attachments_path(project_id: "1") end def test_projects_participants draw do - resources :projects, :controller => :project do + resources :projects, controller: :project do resources :participants do - put :update_all, :on => :collection + put :update_all, on: :collection end end end - get '/projects/1/participants' - assert_equal 'participants#index', @response.body - assert_equal '/projects/1/participants', project_participants_path(:project_id => '1') + get "/projects/1/participants" + assert_equal "participants#index", @response.body + assert_equal "/projects/1/participants", project_participants_path(project_id: "1") - put '/projects/1/participants/update_all' - assert_equal 'participants#update_all', @response.body - assert_equal '/projects/1/participants/update_all', update_all_project_participants_path(:project_id => '1') + put "/projects/1/participants/update_all" + assert_equal "participants#update_all", @response.body + assert_equal "/projects/1/participants/update_all", update_all_project_participants_path(project_id: "1") end def test_projects_companies draw do - resources :projects, :controller => :project do + resources :projects, controller: :project do resources :companies do resources :people - resource :avatar, :controller => :avatar + resource :avatar, controller: :avatar end end end - get '/projects/1/companies' - assert_equal 'companies#index', @response.body - assert_equal '/projects/1/companies', project_companies_path(:project_id => '1') + get "/projects/1/companies" + assert_equal "companies#index", @response.body + assert_equal "/projects/1/companies", project_companies_path(project_id: "1") - get '/projects/1/companies/1/people' - assert_equal 'people#index', @response.body - assert_equal '/projects/1/companies/1/people', project_company_people_path(:project_id => '1', :company_id => '1') + get "/projects/1/companies/1/people" + assert_equal "people#index", @response.body + assert_equal "/projects/1/companies/1/people", project_company_people_path(project_id: "1", company_id: "1") - get '/projects/1/companies/1/avatar' - assert_equal 'avatar#show', @response.body - assert_equal '/projects/1/companies/1/avatar', project_company_avatar_path(:project_id => '1', :company_id => '1') + get "/projects/1/companies/1/avatar" + assert_equal "avatar#show", @response.body + assert_equal "/projects/1/companies/1/avatar", project_company_avatar_path(project_id: "1", company_id: "1") end def test_project_manager draw do resources :projects do - resource :manager, :as => :super_manager do + resource :manager, as: :super_manager do post :fire end end end - get '/projects/1/manager' - assert_equal 'managers#show', @response.body - assert_equal '/projects/1/manager', project_super_manager_path(:project_id => '1') + get "/projects/1/manager" + assert_equal "managers#show", @response.body + assert_equal "/projects/1/manager", project_super_manager_path(project_id: "1") - get '/projects/1/manager/new' - assert_equal 'managers#new', @response.body - assert_equal '/projects/1/manager/new', new_project_super_manager_path(:project_id => '1') + get "/projects/1/manager/new" + assert_equal "managers#new", @response.body + assert_equal "/projects/1/manager/new", new_project_super_manager_path(project_id: "1") - post '/projects/1/manager/fire' - assert_equal 'managers#fire', @response.body - assert_equal '/projects/1/manager/fire', fire_project_super_manager_path(:project_id => '1') + post "/projects/1/manager/fire" + assert_equal "managers#fire", @response.body + assert_equal "/projects/1/manager/fire", fire_project_super_manager_path(project_id: "1") end def test_project_images draw do resources :projects do - resources :images, :as => :funny_images do - post :revise, :on => :member + resources :images, as: :funny_images do + post :revise, on: :member end end end - get '/projects/1/images' - assert_equal 'images#index', @response.body - assert_equal '/projects/1/images', project_funny_images_path(:project_id => '1') + get "/projects/1/images" + assert_equal "images#index", @response.body + assert_equal "/projects/1/images", project_funny_images_path(project_id: "1") - get '/projects/1/images/new' - assert_equal 'images#new', @response.body - assert_equal '/projects/1/images/new', new_project_funny_image_path(:project_id => '1') + get "/projects/1/images/new" + assert_equal "images#new", @response.body + assert_equal "/projects/1/images/new", new_project_funny_image_path(project_id: "1") - post '/projects/1/images/1/revise' - assert_equal 'images#revise', @response.body - assert_equal '/projects/1/images/1/revise', revise_project_funny_image_path(:project_id => '1', :id => '1') + post "/projects/1/images/1/revise" + assert_equal "images#revise", @response.body + assert_equal "/projects/1/images/1/revise", revise_project_funny_image_path(project_id: "1", id: "1") end def test_projects_people @@ -749,181 +751,181 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/projects/1/people' - assert_equal 'people#index', @response.body - assert_equal '/projects/1/people', project_people_path(:project_id => '1') + get "/projects/1/people" + assert_equal "people#index", @response.body + assert_equal "/projects/1/people", project_people_path(project_id: "1") - get '/projects/1/people/1' - assert_equal 'people#show', @response.body - assert_equal '/projects/1/people/1', project_person_path(:project_id => '1', :id => '1') + get "/projects/1/people/1" + assert_equal "people#show", @response.body + assert_equal "/projects/1/people/1", project_person_path(project_id: "1", id: "1") - get '/projects/1/people/1/7a2dec8/avatar' - assert_equal 'avatars#show', @response.body - assert_equal '/projects/1/people/1/7a2dec8/avatar', project_person_avatar_path(:project_id => '1', :person_id => '1', :access_token => '7a2dec8') + get "/projects/1/people/1/7a2dec8/avatar" + assert_equal "avatars#show", @response.body + assert_equal "/projects/1/people/1/7a2dec8/avatar", project_person_avatar_path(project_id: "1", person_id: "1", access_token: "7a2dec8") - put '/projects/1/people/1/accessible_projects' - assert_equal 'people#accessible_projects', @response.body - assert_equal '/projects/1/people/1/accessible_projects', accessible_projects_project_person_path(:project_id => '1', :id => '1') + put "/projects/1/people/1/accessible_projects" + assert_equal "people#accessible_projects", @response.body + assert_equal "/projects/1/people/1/accessible_projects", accessible_projects_project_person_path(project_id: "1", id: "1") - post '/projects/1/people/1/resend' - assert_equal 'people#resend', @response.body - assert_equal '/projects/1/people/1/resend', resend_project_person_path(:project_id => '1', :id => '1') + post "/projects/1/people/1/resend" + assert_equal "people#resend", @response.body + assert_equal "/projects/1/people/1/resend", resend_project_person_path(project_id: "1", id: "1") - post '/projects/1/people/1/generate_new_password' - assert_equal 'people#generate_new_password', @response.body - assert_equal '/projects/1/people/1/generate_new_password', generate_new_password_project_person_path(:project_id => '1', :id => '1') + post "/projects/1/people/1/generate_new_password" + assert_equal "people#generate_new_password", @response.body + assert_equal "/projects/1/people/1/generate_new_password", generate_new_password_project_person_path(project_id: "1", id: "1") end def test_projects_with_resources_path_names draw do - resources_path_names :correlation_indexes => "info_about_correlation_indexes" + resources_path_names correlation_indexes: "info_about_correlation_indexes" resources :projects do - get :correlation_indexes, :on => :collection + get :correlation_indexes, on: :collection end end - get '/projects/info_about_correlation_indexes' - assert_equal 'projects#correlation_indexes', @response.body - assert_equal '/projects/info_about_correlation_indexes', correlation_indexes_projects_path + get "/projects/info_about_correlation_indexes" + assert_equal "projects#correlation_indexes", @response.body + assert_equal "/projects/info_about_correlation_indexes", correlation_indexes_projects_path end def test_projects_posts draw do resources :projects do resources :posts do - get :archive, :toggle_view, :on => :collection - post :preview, :on => :member + get :archive, :toggle_view, on: :collection + post :preview, on: :member resource :subscription resources :comments do - post :preview, :on => :collection + post :preview, on: :collection end end end end - get '/projects/1/posts' - assert_equal 'posts#index', @response.body - assert_equal '/projects/1/posts', project_posts_path(:project_id => '1') + get "/projects/1/posts" + assert_equal "posts#index", @response.body + assert_equal "/projects/1/posts", project_posts_path(project_id: "1") - get '/projects/1/posts/archive' - assert_equal 'posts#archive', @response.body - assert_equal '/projects/1/posts/archive', archive_project_posts_path(:project_id => '1') + get "/projects/1/posts/archive" + assert_equal "posts#archive", @response.body + assert_equal "/projects/1/posts/archive", archive_project_posts_path(project_id: "1") - get '/projects/1/posts/toggle_view' - assert_equal 'posts#toggle_view', @response.body - assert_equal '/projects/1/posts/toggle_view', toggle_view_project_posts_path(:project_id => '1') + get "/projects/1/posts/toggle_view" + assert_equal "posts#toggle_view", @response.body + assert_equal "/projects/1/posts/toggle_view", toggle_view_project_posts_path(project_id: "1") - post '/projects/1/posts/1/preview' - assert_equal 'posts#preview', @response.body - assert_equal '/projects/1/posts/1/preview', preview_project_post_path(:project_id => '1', :id => '1') + post "/projects/1/posts/1/preview" + assert_equal "posts#preview", @response.body + assert_equal "/projects/1/posts/1/preview", preview_project_post_path(project_id: "1", id: "1") - get '/projects/1/posts/1/subscription' - assert_equal 'subscriptions#show', @response.body - assert_equal '/projects/1/posts/1/subscription', project_post_subscription_path(:project_id => '1', :post_id => '1') + get "/projects/1/posts/1/subscription" + assert_equal "subscriptions#show", @response.body + assert_equal "/projects/1/posts/1/subscription", project_post_subscription_path(project_id: "1", post_id: "1") - get '/projects/1/posts/1/comments' - assert_equal 'comments#index', @response.body - assert_equal '/projects/1/posts/1/comments', project_post_comments_path(:project_id => '1', :post_id => '1') + get "/projects/1/posts/1/comments" + assert_equal "comments#index", @response.body + assert_equal "/projects/1/posts/1/comments", project_post_comments_path(project_id: "1", post_id: "1") - post '/projects/1/posts/1/comments/preview' - assert_equal 'comments#preview', @response.body - assert_equal '/projects/1/posts/1/comments/preview', preview_project_post_comments_path(:project_id => '1', :post_id => '1') + post "/projects/1/posts/1/comments/preview" + assert_equal "comments#preview", @response.body + assert_equal "/projects/1/posts/1/comments/preview", preview_project_post_comments_path(project_id: "1", post_id: "1") end def test_replies draw do resources :replies do member do - put :answer, :action => :mark_as_answer - delete :answer, :action => :unmark_as_answer + put :answer, action: :mark_as_answer + delete :answer, action: :unmark_as_answer end end end - put '/replies/1/answer' - assert_equal 'replies#mark_as_answer', @response.body + put "/replies/1/answer" + assert_equal "replies#mark_as_answer", @response.body - delete '/replies/1/answer' - assert_equal 'replies#unmark_as_answer', @response.body + delete "/replies/1/answer" + assert_equal "replies#unmark_as_answer", @response.body end def test_resource_routes_with_only_and_except draw do - resources :posts, :only => [:index, :show] do - resources :comments, :except => :destroy + resources :posts, only: [:index, :show] do + resources :comments, except: :destroy end end - get '/posts' - assert_equal 'posts#index', @response.body - assert_equal '/posts', posts_path + get "/posts" + assert_equal "posts#index", @response.body + assert_equal "/posts", posts_path - get '/posts/1' - assert_equal 'posts#show', @response.body - assert_equal '/posts/1', post_path(:id => 1) + get "/posts/1" + assert_equal "posts#show", @response.body + assert_equal "/posts/1", post_path(id: 1) - get '/posts/1/comments' - assert_equal 'comments#index', @response.body - assert_equal '/posts/1/comments', post_comments_path(:post_id => 1) + get "/posts/1/comments" + assert_equal "comments#index", @response.body + assert_equal "/posts/1/comments", post_comments_path(post_id: 1) - post '/posts' - assert_equal 'pass', @response.headers['X-Cascade'] - put '/posts/1' - assert_equal 'pass', @response.headers['X-Cascade'] - delete '/posts/1' - assert_equal 'pass', @response.headers['X-Cascade'] - delete '/posts/1/comments' - assert_equal 'pass', @response.headers['X-Cascade'] + post "/posts" + assert_equal "pass", @response.headers["X-Cascade"] + put "/posts/1" + assert_equal "pass", @response.headers["X-Cascade"] + delete "/posts/1" + assert_equal "pass", @response.headers["X-Cascade"] + delete "/posts/1/comments" + assert_equal "pass", @response.headers["X-Cascade"] end def test_resource_routes_only_create_update_destroy draw do - resource :past, :only => :destroy - resource :present, :only => :update - resource :future, :only => :create + resource :past, only: :destroy + resource :present, only: :update + resource :future, only: :create end - delete '/past' - assert_equal 'pasts#destroy', @response.body - assert_equal '/past', past_path + delete "/past" + assert_equal "pasts#destroy", @response.body + assert_equal "/past", past_path - patch '/present' - assert_equal 'presents#update', @response.body - assert_equal '/present', present_path + patch "/present" + assert_equal "presents#update", @response.body + assert_equal "/present", present_path - put '/present' - assert_equal 'presents#update', @response.body - assert_equal '/present', present_path + put "/present" + assert_equal "presents#update", @response.body + assert_equal "/present", present_path - post '/future' - assert_equal 'futures#create', @response.body - assert_equal '/future', future_path + post "/future" + assert_equal "futures#create", @response.body + assert_equal "/future", future_path end def test_resources_routes_only_create_update_destroy draw do - resources :relationships, :only => [:create, :destroy] - resources :friendships, :only => [:update] + resources :relationships, only: [:create, :destroy] + resources :friendships, only: [:update] end - post '/relationships' - assert_equal 'relationships#create', @response.body - assert_equal '/relationships', relationships_path + post "/relationships" + assert_equal "relationships#create", @response.body + assert_equal "/relationships", relationships_path - delete '/relationships/1' - assert_equal 'relationships#destroy', @response.body - assert_equal '/relationships/1', relationship_path(1) + delete "/relationships/1" + assert_equal "relationships#destroy", @response.body + assert_equal "/relationships/1", relationship_path(1) - patch '/friendships/1' - assert_equal 'friendships#update', @response.body - assert_equal '/friendships/1', friendship_path(1) + patch "/friendships/1" + assert_equal "friendships#update", @response.body + assert_equal "/friendships/1", friendship_path(1) - put '/friendships/1' - assert_equal 'friendships#update', @response.body - assert_equal '/friendships/1', friendship_path(1) + put "/friendships/1" + assert_equal "friendships#update", @response.body + assert_equal "/friendships/1", friendship_path(1) end def test_resource_with_slugs_in_ids @@ -931,153 +933,153 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :posts end - get '/posts/rails-rocks' - assert_equal 'posts#show', @response.body - assert_equal '/posts/rails-rocks', post_path(:id => 'rails-rocks') + get "/posts/rails-rocks" + assert_equal "posts#show", @response.body + assert_equal "/posts/rails-rocks", post_path(id: "rails-rocks") end def test_resources_for_uncountable_names draw do resources :sheep do - get "_it", :on => :member + get "_it", on: :member end end - assert_equal '/sheep', sheep_index_path - assert_equal '/sheep/1', sheep_path(1) - assert_equal '/sheep/new', new_sheep_path - assert_equal '/sheep/1/edit', edit_sheep_path(1) - assert_equal '/sheep/1/_it', _it_sheep_path(1) + assert_equal "/sheep", sheep_index_path + assert_equal "/sheep/1", sheep_path(1) + assert_equal "/sheep/new", new_sheep_path + assert_equal "/sheep/1/edit", edit_sheep_path(1) + assert_equal "/sheep/1/_it", _it_sheep_path(1) end def test_resource_does_not_modify_passed_options - options = {:id => /.+?/, :format => /json|xml/} + options = { id: /.+?/, format: /json|xml/ } draw { resource :user, options } - assert_equal({:id => /.+?/, :format => /json|xml/}, options) + assert_equal({ id: /.+?/, format: /json|xml/ }, options) end def test_resources_does_not_modify_passed_options - options = {:id => /.+?/, :format => /json|xml/} + options = { id: /.+?/, format: /json|xml/ } draw { resources :users, options } - assert_equal({:id => /.+?/, :format => /json|xml/}, options) + assert_equal({ id: /.+?/, format: /json|xml/ }, options) end def test_path_names draw do - scope 'pt', :as => 'pt' do - resources :projects, :path_names => { :edit => 'editar', :new => 'novo' }, :path => 'projetos' - resource :admin, :path_names => { :new => 'novo', :activate => 'ativar' }, :path => 'administrador' do - put :activate, :on => :member + scope "pt", as: "pt" do + resources :projects, path_names: { edit: "editar", new: "novo" }, path: "projetos" + resource :admin, path_names: { new: "novo", activate: "ativar" }, path: "administrador" do + put :activate, on: :member end end end - get '/pt/projetos' - assert_equal 'projects#index', @response.body - assert_equal '/pt/projetos', pt_projects_path + get "/pt/projetos" + assert_equal "projects#index", @response.body + assert_equal "/pt/projetos", pt_projects_path - get '/pt/projetos/1/editar' - assert_equal 'projects#edit', @response.body - assert_equal '/pt/projetos/1/editar', edit_pt_project_path(1) + get "/pt/projetos/1/editar" + assert_equal "projects#edit", @response.body + assert_equal "/pt/projetos/1/editar", edit_pt_project_path(1) - get '/pt/administrador' - assert_equal 'admins#show', @response.body - assert_equal '/pt/administrador', pt_admin_path + get "/pt/administrador" + assert_equal "admins#show", @response.body + assert_equal "/pt/administrador", pt_admin_path - get '/pt/administrador/novo' - assert_equal 'admins#new', @response.body - assert_equal '/pt/administrador/novo', new_pt_admin_path + get "/pt/administrador/novo" + assert_equal "admins#new", @response.body + assert_equal "/pt/administrador/novo", new_pt_admin_path - put '/pt/administrador/ativar' - assert_equal 'admins#activate', @response.body - assert_equal '/pt/administrador/ativar', activate_pt_admin_path + put "/pt/administrador/ativar" + assert_equal "admins#activate", @response.body + assert_equal "/pt/administrador/ativar", activate_pt_admin_path end def test_path_option_override draw do - scope 'pt', :as => 'pt' do - resources :projects, :path_names => { :new => 'novo' }, :path => 'projetos' do - put :close, :on => :member, :path => 'fechar' - get :open, :on => :new, :path => 'abrir' + scope "pt", as: "pt" do + resources :projects, path_names: { new: "novo" }, path: "projetos" do + put :close, on: :member, path: "fechar" + get :open, on: :new, path: "abrir" end end end - get '/pt/projetos/novo/abrir' - assert_equal 'projects#open', @response.body - assert_equal '/pt/projetos/novo/abrir', open_new_pt_project_path + get "/pt/projetos/novo/abrir" + assert_equal "projects#open", @response.body + assert_equal "/pt/projetos/novo/abrir", open_new_pt_project_path - put '/pt/projetos/1/fechar' - assert_equal 'projects#close', @response.body - assert_equal '/pt/projetos/1/fechar', close_pt_project_path(1) + put "/pt/projetos/1/fechar" + assert_equal "projects#close", @response.body + assert_equal "/pt/projetos/1/fechar", close_pt_project_path(1) end def test_sprockets draw do - get 'sprockets.js' => ::TestRoutingMapper::SprocketsApp + get "sprockets.js" => ::TestRoutingMapper::SprocketsApp end - get '/sprockets.js' - assert_equal 'javascripts', @response.body + get "/sprockets.js" + assert_equal "javascripts", @response.body end def test_update_person_route draw do - get 'people/:id/update', :to => 'people#update', :as => :update_person + get "people/:id/update", to: "people#update", as: :update_person end - get '/people/1/update' - assert_equal 'people#update', @response.body + get "/people/1/update" + assert_equal "people#update", @response.body - assert_equal '/people/1/update', update_person_path(:id => 1) + assert_equal "/people/1/update", update_person_path(id: 1) end def test_update_project_person draw do - get '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person + get "/projects/:project_id/people/:id/update", to: "people#update", as: :update_project_person end - get '/projects/1/people/2/update' - assert_equal 'people#update', @response.body + get "/projects/1/people/2/update" + assert_equal "people#update", @response.body - assert_equal '/projects/1/people/2/update', update_project_person_path(:project_id => 1, :id => 2) + assert_equal "/projects/1/people/2/update", update_project_person_path(project_id: 1, id: 2) end def test_forum_products draw do namespace :forum do - resources :products, :path => '' do + resources :products, path: "" do resources :questions end end end - get '/forum' - assert_equal 'forum/products#index', @response.body - assert_equal '/forum', forum_products_path + get "/forum" + assert_equal "forum/products#index", @response.body + assert_equal "/forum", forum_products_path - get '/forum/basecamp' - assert_equal 'forum/products#show', @response.body - assert_equal '/forum/basecamp', forum_product_path(:id => 'basecamp') + get "/forum/basecamp" + assert_equal "forum/products#show", @response.body + assert_equal "/forum/basecamp", forum_product_path(id: "basecamp") - get '/forum/basecamp/questions' - assert_equal 'forum/questions#index', @response.body - assert_equal '/forum/basecamp/questions', forum_product_questions_path(:product_id => 'basecamp') + get "/forum/basecamp/questions" + assert_equal "forum/questions#index", @response.body + assert_equal "/forum/basecamp/questions", forum_product_questions_path(product_id: "basecamp") - get '/forum/basecamp/questions/1' - assert_equal 'forum/questions#show', @response.body - assert_equal '/forum/basecamp/questions/1', forum_product_question_path(:product_id => 'basecamp', :id => 1) + get "/forum/basecamp/questions/1" + assert_equal "forum/questions#show", @response.body + assert_equal "/forum/basecamp/questions/1", forum_product_question_path(product_id: "basecamp", id: 1) end def test_articles_perma draw do - get 'articles/:year/:month/:day/:title', :to => "articles#show", :as => :article + get "articles/:year/:month/:day/:title", to: "articles#show", as: :article end - get '/articles/2009/08/18/rails-3' - assert_equal 'articles#show', @response.body + get "/articles/2009/08/18/rails-3" + assert_equal "articles#show", @response.body - assert_equal '/articles/2009/8/18/rails-3', article_path(:year => 2009, :month => 8, :day => 18, :title => 'rails-3') + assert_equal "/articles/2009/8/18/rails-3", article_path(year: 2009, month: 8, day: 18, title: "rails-3") end def test_account_namespace @@ -1087,17 +1089,17 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/account/subscription' - assert_equal 'account/subscriptions#show', @response.body - assert_equal '/account/subscription', account_subscription_path + get "/account/subscription" + assert_equal "account/subscriptions#show", @response.body + assert_equal "/account/subscription", account_subscription_path - get '/account/credit' - assert_equal 'account/credits#show', @response.body - assert_equal '/account/credit', account_credit_path + get "/account/credit" + assert_equal "account/credits#show", @response.body + assert_equal "/account/credit", account_credit_path - get '/account/credit_card' - assert_equal 'account/credit_cards#show', @response.body - assert_equal '/account/credit_card', account_credit_card_path + get "/account/credit_card" + assert_equal "account/credit_cards#show", @response.body + assert_equal "/account/credit_card", account_credit_card_path end def test_nested_namespace @@ -1109,9 +1111,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/account/admin/subscription' - assert_equal 'account/admin/subscriptions#show', @response.body - assert_equal '/account/admin/subscription', account_admin_subscription_path + get "/account/admin/subscription" + assert_equal "account/admin/subscriptions#show", @response.body + assert_equal "/account/admin/subscription", account_admin_subscription_path end def test_namespace_nested_in_resources @@ -1127,155 +1129,155 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/clients/1/google/account' - assert_equal '/clients/1/google/account', client_google_account_path(1) - assert_equal 'google/accounts#show', @response.body + get "/clients/1/google/account" + assert_equal "/clients/1/google/account", client_google_account_path(1) + assert_equal "google/accounts#show", @response.body - get '/clients/1/google/account/secret/info' - assert_equal '/clients/1/google/account/secret/info', client_google_account_secret_info_path(1) - assert_equal 'google/secret/infos#show', @response.body + get "/clients/1/google/account/secret/info" + assert_equal "/clients/1/google/account/secret/info", client_google_account_secret_info_path(1) + assert_equal "google/secret/infos#show", @response.body end def test_namespace_with_options draw do - namespace :users, :path => 'usuarios' do - root :to => 'home#index' + namespace :users, path: "usuarios" do + root to: "home#index" end end - get '/usuarios' - assert_equal '/usuarios', users_root_path - assert_equal 'users/home#index', @response.body + get "/usuarios" + assert_equal "/usuarios", users_root_path + assert_equal "users/home#index", @response.body end def test_namespaced_shallow_routes_with_module_option draw do - namespace :foo, module: 'bar' do + namespace :foo, module: "bar" do resources :posts, only: [:index, :show] do resources :comments, only: [:index, :show], shallow: true end end end - get '/foo/posts' - assert_equal '/foo/posts', foo_posts_path - assert_equal 'bar/posts#index', @response.body + get "/foo/posts" + assert_equal "/foo/posts", foo_posts_path + assert_equal "bar/posts#index", @response.body - get '/foo/posts/1' - assert_equal '/foo/posts/1', foo_post_path('1') - assert_equal 'bar/posts#show', @response.body + get "/foo/posts/1" + assert_equal "/foo/posts/1", foo_post_path("1") + assert_equal "bar/posts#show", @response.body - get '/foo/posts/1/comments' - assert_equal '/foo/posts/1/comments', foo_post_comments_path('1') - assert_equal 'bar/comments#index', @response.body + get "/foo/posts/1/comments" + assert_equal "/foo/posts/1/comments", foo_post_comments_path("1") + assert_equal "bar/comments#index", @response.body - get '/foo/comments/2' - assert_equal '/foo/comments/2', foo_comment_path('2') - assert_equal 'bar/comments#show', @response.body + get "/foo/comments/2" + assert_equal "/foo/comments/2", foo_comment_path("2") + assert_equal "bar/comments#show", @response.body end def test_namespaced_shallow_routes_with_path_option draw do - namespace :foo, path: 'bar' do + namespace :foo, path: "bar" do resources :posts, only: [:index, :show] do resources :comments, only: [:index, :show], shallow: true end end end - get '/bar/posts' - assert_equal '/bar/posts', foo_posts_path - assert_equal 'foo/posts#index', @response.body + get "/bar/posts" + assert_equal "/bar/posts", foo_posts_path + assert_equal "foo/posts#index", @response.body - get '/bar/posts/1' - assert_equal '/bar/posts/1', foo_post_path('1') - assert_equal 'foo/posts#show', @response.body + get "/bar/posts/1" + assert_equal "/bar/posts/1", foo_post_path("1") + assert_equal "foo/posts#show", @response.body - get '/bar/posts/1/comments' - assert_equal '/bar/posts/1/comments', foo_post_comments_path('1') - assert_equal 'foo/comments#index', @response.body + get "/bar/posts/1/comments" + assert_equal "/bar/posts/1/comments", foo_post_comments_path("1") + assert_equal "foo/comments#index", @response.body - get '/bar/comments/2' - assert_equal '/bar/comments/2', foo_comment_path('2') - assert_equal 'foo/comments#show', @response.body + get "/bar/comments/2" + assert_equal "/bar/comments/2", foo_comment_path("2") + assert_equal "foo/comments#show", @response.body end def test_namespaced_shallow_routes_with_as_option draw do - namespace :foo, as: 'bar' do + namespace :foo, as: "bar" do resources :posts, only: [:index, :show] do resources :comments, only: [:index, :show], shallow: true end end end - get '/foo/posts' - assert_equal '/foo/posts', bar_posts_path - assert_equal 'foo/posts#index', @response.body + get "/foo/posts" + assert_equal "/foo/posts", bar_posts_path + assert_equal "foo/posts#index", @response.body - get '/foo/posts/1' - assert_equal '/foo/posts/1', bar_post_path('1') - assert_equal 'foo/posts#show', @response.body + get "/foo/posts/1" + assert_equal "/foo/posts/1", bar_post_path("1") + assert_equal "foo/posts#show", @response.body - get '/foo/posts/1/comments' - assert_equal '/foo/posts/1/comments', bar_post_comments_path('1') - assert_equal 'foo/comments#index', @response.body + get "/foo/posts/1/comments" + assert_equal "/foo/posts/1/comments", bar_post_comments_path("1") + assert_equal "foo/comments#index", @response.body - get '/foo/comments/2' - assert_equal '/foo/comments/2', bar_comment_path('2') - assert_equal 'foo/comments#show', @response.body + get "/foo/comments/2" + assert_equal "/foo/comments/2", bar_comment_path("2") + assert_equal "foo/comments#show", @response.body end def test_namespaced_shallow_routes_with_shallow_path_option draw do - namespace :foo, shallow_path: 'bar' do + namespace :foo, shallow_path: "bar" do resources :posts, only: [:index, :show] do resources :comments, only: [:index, :show], shallow: true end end end - get '/foo/posts' - assert_equal '/foo/posts', foo_posts_path - assert_equal 'foo/posts#index', @response.body + get "/foo/posts" + assert_equal "/foo/posts", foo_posts_path + assert_equal "foo/posts#index", @response.body - get '/foo/posts/1' - assert_equal '/foo/posts/1', foo_post_path('1') - assert_equal 'foo/posts#show', @response.body + get "/foo/posts/1" + assert_equal "/foo/posts/1", foo_post_path("1") + assert_equal "foo/posts#show", @response.body - get '/foo/posts/1/comments' - assert_equal '/foo/posts/1/comments', foo_post_comments_path('1') - assert_equal 'foo/comments#index', @response.body + get "/foo/posts/1/comments" + assert_equal "/foo/posts/1/comments", foo_post_comments_path("1") + assert_equal "foo/comments#index", @response.body - get '/bar/comments/2' - assert_equal '/bar/comments/2', foo_comment_path('2') - assert_equal 'foo/comments#show', @response.body + get "/bar/comments/2" + assert_equal "/bar/comments/2", foo_comment_path("2") + assert_equal "foo/comments#show", @response.body end def test_namespaced_shallow_routes_with_shallow_prefix_option draw do - namespace :foo, shallow_prefix: 'bar' do + namespace :foo, shallow_prefix: "bar" do resources :posts, only: [:index, :show] do resources :comments, only: [:index, :show], shallow: true end end end - get '/foo/posts' - assert_equal '/foo/posts', foo_posts_path - assert_equal 'foo/posts#index', @response.body + get "/foo/posts" + assert_equal "/foo/posts", foo_posts_path + assert_equal "foo/posts#index", @response.body - get '/foo/posts/1' - assert_equal '/foo/posts/1', foo_post_path('1') - assert_equal 'foo/posts#show', @response.body + get "/foo/posts/1" + assert_equal "/foo/posts/1", foo_post_path("1") + assert_equal "foo/posts#show", @response.body - get '/foo/posts/1/comments' - assert_equal '/foo/posts/1/comments', foo_post_comments_path('1') - assert_equal 'foo/comments#index', @response.body + get "/foo/posts/1/comments" + assert_equal "/foo/posts/1/comments", foo_post_comments_path("1") + assert_equal "foo/comments#index", @response.body - get '/foo/comments/2' - assert_equal '/foo/comments/2', bar_comment_path('2') - assert_equal 'foo/comments#show', @response.body + get "/foo/comments/2" + assert_equal "/foo/comments/2", bar_comment_path("2") + assert_equal "foo/comments#show", @response.body end def test_namespace_containing_numbers @@ -1285,81 +1287,81 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/v2/subscriptions' - assert_equal 'v2/subscriptions#index', @response.body - assert_equal '/v2/subscriptions', v2_subscriptions_path + get "/v2/subscriptions" + assert_equal "v2/subscriptions#index", @response.body + assert_equal "/v2/subscriptions", v2_subscriptions_path end def test_articles_with_id draw do controller :articles do - scope '/articles', :as => 'article' do - scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do - get '/:id', :action => :with_id, :as => "" + scope "/articles", as: "article" do + scope path: "/:title", title: /[a-z]+/, as: :with_title do + get "/:id", action: :with_id, as: "" end end end end - get '/articles/rails/1' - assert_equal 'articles#with_id', @response.body + get "/articles/rails/1" + assert_equal "articles#with_id", @response.body - get '/articles/123/1' - assert_equal 'pass', @response.headers['X-Cascade'] + get "/articles/123/1" + assert_equal "pass", @response.headers["X-Cascade"] - assert_equal '/articles/rails/1', article_with_title_path(:title => 'rails', :id => 1) + assert_equal "/articles/rails/1", article_with_title_path(title: "rails", id: 1) end def test_access_token_rooms draw do - scope ':access_token', :constraints => { :access_token => /\w{5,5}/ } do + scope ":access_token", constraints: { access_token: /\w{5,5}/ } do resources :rooms end end - get '/12345/rooms' - assert_equal 'rooms#index', @response.body + get "/12345/rooms" + assert_equal "rooms#index", @response.body - get '/12345/rooms/1' - assert_equal 'rooms#show', @response.body + get "/12345/rooms/1" + assert_equal "rooms#show", @response.body - get '/12345/rooms/1/edit' - assert_equal 'rooms#edit', @response.body + get "/12345/rooms/1/edit" + assert_equal "rooms#edit", @response.body end def test_root draw do - root :to => 'projects#index' + root to: "projects#index" end - assert_equal '/', root_path - get '/' - assert_equal 'projects#index', @response.body + assert_equal "/", root_path + get "/" + assert_equal "projects#index", @response.body end def test_scoped_root draw do - scope '(:locale)', :locale => /en|pl/ do - root :to => 'projects#index' + scope "(:locale)", locale: /en|pl/ do + root to: "projects#index" end end - assert_equal '/en', root_path(:locale => 'en') - get '/en' - assert_equal 'projects#index', @response.body + assert_equal "/en", root_path(locale: "en") + get "/en" + assert_equal "projects#index", @response.body end def test_scoped_root_as_name draw do - scope '(:locale)', :locale => /en|pl/ do - root :to => 'projects#index', :as => 'projects' + scope "(:locale)", locale: /en|pl/ do + root to: "projects#index", as: "projects" end end - assert_equal '/en', projects_path(:locale => 'en') - assert_equal '/', projects_path - get '/en' - assert_equal 'projects#index', @response.body + assert_equal "/en", projects_path(locale: "en") + assert_equal "/", projects_path + get "/en" + assert_equal "projects#index", @response.body end def test_scope_with_format_option @@ -1377,10 +1379,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal "/scoped/index", no_format_scoped_path assert_equal "/scoped/index?format=html", no_format_scoped_path(format: "html") - get '/scoped/index' + get "/scoped/index" assert_equal "scoped#index", @response.body - get '/scoped/index.html' + get "/scoped/index.html" assert_equal "Not Found", @response.body end @@ -1415,63 +1417,63 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_index draw do - get '/info' => 'projects#info', :as => 'info' + get "/info" => "projects#info", :as => "info" end - assert_equal '/info', info_path - get '/info' - assert_equal 'projects#info', @response.body + assert_equal "/info", info_path + get "/info" + assert_equal "projects#info", @response.body end def test_match_with_many_paths_containing_a_slash draw do - get 'get/first', 'get/second', 'get/third', :to => 'get#show' + get "get/first", "get/second", "get/third", to: "get#show" end - get '/get/first' - assert_equal 'get#show', @response.body + get "/get/first" + assert_equal "get#show", @response.body - get '/get/second' - assert_equal 'get#show', @response.body + get "/get/second" + assert_equal "get#show", @response.body - get '/get/third' - assert_equal 'get#show', @response.body + get "/get/third" + assert_equal "get#show", @response.body end def test_match_shorthand_with_no_scope draw do - get 'account/overview' + get "account/overview" end - assert_equal '/account/overview', account_overview_path - get '/account/overview' - assert_equal 'account#overview', @response.body + assert_equal "/account/overview", account_overview_path + get "/account/overview" + assert_equal "account#overview", @response.body end def test_match_shorthand_inside_namespace draw do namespace :account do - get 'shorthand' + get "shorthand" end end - assert_equal '/account/shorthand', account_shorthand_path - get '/account/shorthand' - assert_equal 'account#shorthand', @response.body + assert_equal "/account/shorthand", account_shorthand_path + get "/account/shorthand" + assert_equal "account#shorthand", @response.body end def test_match_shorthand_with_multiple_paths_inside_namespace draw do namespace :proposals do - put 'activate', 'inactivate' + put "activate", "inactivate" end end - put '/proposals/activate' - assert_equal 'proposals#activate', @response.body + put "/proposals/activate" + assert_equal "proposals#activate", @response.body - put '/proposals/inactivate' - assert_equal 'proposals#inactivate', @response.body + put "/proposals/inactivate" + assert_equal "proposals#inactivate", @response.body end def test_match_shorthand_inside_namespace_with_controller @@ -1481,130 +1483,130 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - assert_equal '/api/products/list', api_products_list_path - get '/api/products/list' - assert_equal 'api/products#list', @response.body + assert_equal "/api/products/list", api_products_list_path + get "/api/products/list" + assert_equal "api/products#list", @response.body end def test_match_shorthand_inside_scope_with_variables_with_controller draw do - scope ':locale' do - match 'questions/new', via: [:get] + scope ":locale" do + match "questions/new", via: [:get] end end - get '/de/questions/new' - assert_equal 'questions#new', @response.body - assert_equal 'de', @request.params[:locale] + get "/de/questions/new" + assert_equal "questions#new", @response.body + assert_equal "de", @request.params[:locale] end def test_match_shorthand_inside_nested_namespaces_and_scopes_with_controller draw do namespace :api do namespace :v3 do - scope ':locale' do + scope ":locale" do get "products/list" end end end end - get '/api/v3/en/products/list' - assert_equal 'api/v3/products#list', @response.body + get "/api/v3/en/products/list" + assert_equal "api/v3/products#list", @response.body end def test_not_matching_shorthand_with_dynamic_parameters draw do ActiveSupport::Deprecation.silence do - get ':controller/:action/admin' + get ":controller/:action/admin" end end - get '/finances/overview/admin' - assert_equal 'finances#overview', @response.body + get "/finances/overview/admin" + assert_equal "finances#overview", @response.body end def test_controller_option_with_nesting_and_leading_slash draw do - scope '/job', controller: 'job' do - scope ':id', action: 'manage_applicant' do + scope "/job", controller: "job" do + scope ":id", action: "manage_applicant" do get "/active" end end end - get '/job/5/active' - assert_equal 'job#manage_applicant', @response.body + get "/job/5/active" + assert_equal "job#manage_applicant", @response.body end def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper draw do resources :replies do collection do - get 'page/:page' => 'replies#index', :page => %r{\d+} - get ':page' => 'replies#index', :page => %r{\d+} + get "page/:page" => "replies#index", :page => %r{\d+} + get ":page" => "replies#index", :page => %r{\d+} end end end - assert_equal '/replies', replies_path + assert_equal "/replies", replies_path end def test_scoped_controller_with_namespace_and_action draw do namespace :account do ActiveSupport::Deprecation.silence do - get ':action/callback', :action => /twitter|github/, :controller => "callbacks", :as => :callback + get ":action/callback", action: /twitter|github/, controller: "callbacks", as: :callback end end end - assert_equal '/account/twitter/callback', account_callback_path("twitter") - get '/account/twitter/callback' - assert_equal 'account/callbacks#twitter', @response.body + assert_equal "/account/twitter/callback", account_callback_path("twitter") + get "/account/twitter/callback" + assert_equal "account/callbacks#twitter", @response.body - get '/account/whatever/callback' - assert_equal 'Not Found', @response.body + get "/account/whatever/callback" + assert_equal "Not Found", @response.body end def test_convention_match_nested_and_with_leading_slash draw do - get '/account/nested/overview' + get "/account/nested/overview" end - assert_equal '/account/nested/overview', account_nested_overview_path - get '/account/nested/overview' - assert_equal 'account/nested#overview', @response.body + assert_equal "/account/nested/overview", account_nested_overview_path + get "/account/nested/overview" + assert_equal "account/nested#overview", @response.body end def test_convention_with_explicit_end draw do - get 'sign_in' => "sessions#new" + get "sign_in" => "sessions#new" end - get '/sign_in' - assert_equal 'sessions#new', @response.body - assert_equal '/sign_in', sign_in_path + get "/sign_in" + assert_equal "sessions#new", @response.body + assert_equal "/sign_in", sign_in_path end def test_redirect_with_complete_url_and_status draw do - get 'account/google' => redirect('http://www.google.com/', :status => 302) + get "account/google" => redirect("http://www.google.com/", status: 302) end - get '/account/google' - verify_redirect 'http://www.google.com/', 302 + get "/account/google" + verify_redirect "http://www.google.com/", 302 end def test_redirect_with_port draw do - get 'account/login', :to => redirect("/login") + get "account/login", to: redirect("/login") end - previous_host, self.host = self.host, 'www.example.com:3000' + previous_host, self.host = self.host, "www.example.com:3000" - get '/account/login' - verify_redirect 'http://www.example.com:3000/login' + get "/account/login" + verify_redirect "http://www.example.com:3000/login" ensure self.host = previous_host end @@ -1612,240 +1614,276 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_normalize_namespaced_matches draw do namespace :account do - get 'description', :action => :description, :as => "description" + get "description", action: :description, as: "description" end end - assert_equal '/account/description', account_description_path + assert_equal "/account/description", account_description_path - get '/account/description' - assert_equal 'account#description', @response.body + get "/account/description" + assert_equal "account#description", @response.body end def test_namespaced_roots draw do namespace :account do - root :to => "account#index" + root to: "account#index" end end - assert_equal '/account', account_root_path - get '/account' - assert_equal 'account/account#index', @response.body + assert_equal "/account", account_root_path + get "/account" + assert_equal "account/account#index", @response.body end def test_optional_scoped_root draw do - scope '(:locale)', :locale => /en|pl/ do - root :to => 'projects#index' + scope "(:locale)", locale: /en|pl/ do + root to: "projects#index" end end - assert_equal '/en', root_path("en") - get '/en' - assert_equal 'projects#index', @response.body + assert_equal "/en", root_path("en") + get "/en" + assert_equal "projects#index", @response.body end def test_optional_scoped_path draw do - scope '(:locale)', :locale => /en|pl/ do + scope "(:locale)", locale: /en|pl/ do resources :descriptions end end - assert_equal '/en/descriptions', descriptions_path("en") - assert_equal '/descriptions', descriptions_path(nil) - assert_equal '/en/descriptions/1', description_path("en", 1) - assert_equal '/descriptions/1', description_path(nil, 1) + assert_equal "/en/descriptions", descriptions_path("en") + assert_equal "/descriptions", descriptions_path(nil) + assert_equal "/en/descriptions/1", description_path("en", 1) + assert_equal "/descriptions/1", description_path(nil, 1) - get '/en/descriptions' - assert_equal 'descriptions#index', @response.body + get "/en/descriptions" + assert_equal "descriptions#index", @response.body - get '/descriptions' - assert_equal 'descriptions#index', @response.body + get "/descriptions" + assert_equal "descriptions#index", @response.body - get '/en/descriptions/1' - assert_equal 'descriptions#show', @response.body + get "/en/descriptions/1" + assert_equal "descriptions#show", @response.body - get '/descriptions/1' - assert_equal 'descriptions#show', @response.body + get "/descriptions/1" + assert_equal "descriptions#show", @response.body end def test_nested_optional_scoped_path draw do namespace :admin do - scope '(:locale)', :locale => /en|pl/ do + scope "(:locale)", locale: /en|pl/ do resources :descriptions end end end - assert_equal '/admin/en/descriptions', admin_descriptions_path("en") - assert_equal '/admin/descriptions', admin_descriptions_path(nil) - assert_equal '/admin/en/descriptions/1', admin_description_path("en", 1) - assert_equal '/admin/descriptions/1', admin_description_path(nil, 1) + assert_equal "/admin/en/descriptions", admin_descriptions_path("en") + assert_equal "/admin/descriptions", admin_descriptions_path(nil) + assert_equal "/admin/en/descriptions/1", admin_description_path("en", 1) + assert_equal "/admin/descriptions/1", admin_description_path(nil, 1) - get '/admin/en/descriptions' - assert_equal 'admin/descriptions#index', @response.body + get "/admin/en/descriptions" + assert_equal "admin/descriptions#index", @response.body - get '/admin/descriptions' - assert_equal 'admin/descriptions#index', @response.body + get "/admin/descriptions" + assert_equal "admin/descriptions#index", @response.body - get '/admin/en/descriptions/1' - assert_equal 'admin/descriptions#show', @response.body + get "/admin/en/descriptions/1" + assert_equal "admin/descriptions#show", @response.body - get '/admin/descriptions/1' - assert_equal 'admin/descriptions#show', @response.body + get "/admin/descriptions/1" + assert_equal "admin/descriptions#show", @response.body end def test_nested_optional_path_shorthand draw do - scope '(:locale)', :locale => /en|pl/ do + scope "(:locale)", locale: /en|pl/ do get "registrations/new" end end - get '/registrations/new' + get "/registrations/new" assert_nil @request.params[:locale] - get '/en/registrations/new' - assert_equal 'en', @request.params[:locale] + get "/en/registrations/new" + assert_equal "en", @request.params[:locale] end def test_default_string_params draw do - get 'inline_pages/(:id)', :to => 'pages#show', :id => 'home' - get 'default_pages/(:id)', :to => 'pages#show', :defaults => { :id => 'home' } + get "inline_pages/(:id)", to: "pages#show", id: "home" + get "default_pages/(:id)", to: "pages#show", defaults: { id: "home" } - defaults :id => 'home' do - get 'scoped_pages/(:id)', :to => 'pages#show' + defaults id: "home" do + get "scoped_pages/(:id)", to: "pages#show" end end - get '/inline_pages' - assert_equal 'home', @request.params[:id] + get "/inline_pages" + assert_equal "home", @request.params[:id] - get '/default_pages' - assert_equal 'home', @request.params[:id] + get "/default_pages" + assert_equal "home", @request.params[:id] - get '/scoped_pages' - assert_equal 'home', @request.params[:id] + get "/scoped_pages" + assert_equal "home", @request.params[:id] end def test_default_integer_params draw do - get 'inline_pages/(:page)', to: 'pages#show', page: 1 - get 'default_pages/(:page)', to: 'pages#show', defaults: { page: 1 } + get "inline_pages/(:page)", to: "pages#show", page: 1 + get "default_pages/(:page)", to: "pages#show", defaults: { page: 1 } defaults page: 1 do - get 'scoped_pages/(:page)', to: 'pages#show' + get "scoped_pages/(:page)", to: "pages#show" end end - get '/inline_pages' + get "/inline_pages" assert_equal 1, @request.params[:page] - get '/default_pages' + get "/default_pages" assert_equal 1, @request.params[:page] - get '/scoped_pages' + get "/scoped_pages" assert_equal 1, @request.params[:page] end + def test_keyed_default_string_params_with_match + draw do + match "/", to: "pages#show", via: :get, defaults: { id: "home" } + end + + get "/" + assert_equal "home", @request.params[:id] + end + + def test_default_string_params_with_match + draw do + match "/", to: "pages#show", via: :get, id: "home" + end + + get "/" + assert_equal "home", @request.params[:id] + end + + def test_keyed_default_string_params_with_root + draw do + root to: "pages#show", defaults: { id: "home" } + end + + get "/" + assert_equal "home", @request.params[:id] + end + + def test_default_string_params_with_root + draw do + root to: "pages#show", id: "home" + end + + get "/" + assert_equal "home", @request.params[:id] + end + def test_resource_constraints draw do - resources :products, :constraints => { :id => /\d{4}/ } do - root :to => "products#root" - get :favorite, :on => :collection + resources :products, constraints: { id: /\d{4}/ } do + root to: "products#root" + get :favorite, on: :collection resources :images end - resource :dashboard, :constraints => { :ip => /192\.168\.1\.\d{1,3}/ } + resource :dashboard, constraints: { ip: /192\.168\.1\.\d{1,3}/ } end - get '/products/1' - assert_equal 'pass', @response.headers['X-Cascade'] - get '/products' - assert_equal 'products#root', @response.body - get '/products/favorite' - assert_equal 'products#favorite', @response.body - get '/products/0001' - assert_equal 'products#show', @response.body + get "/products/1" + assert_equal "pass", @response.headers["X-Cascade"] + get "/products" + assert_equal "products#root", @response.body + get "/products/favorite" + assert_equal "products#favorite", @response.body + get "/products/0001" + assert_equal "products#show", @response.body - get '/products/1/images' - assert_equal 'pass', @response.headers['X-Cascade'] - get '/products/0001/images' - assert_equal 'images#index', @response.body - get '/products/0001/images/0001' - assert_equal 'images#show', @response.body + get "/products/1/images" + assert_equal "pass", @response.headers["X-Cascade"] + get "/products/0001/images" + assert_equal "images#index", @response.body + get "/products/0001/images/0001" + assert_equal "images#show", @response.body - get '/dashboard', headers: { 'REMOTE_ADDR' => '10.0.0.100' } - assert_equal 'pass', @response.headers['X-Cascade'] - get '/dashboard', headers: { 'REMOTE_ADDR' => '192.168.1.100' } - assert_equal 'dashboards#show', @response.body + get "/dashboard", headers: { "REMOTE_ADDR" => "10.0.0.100" } + assert_equal "pass", @response.headers["X-Cascade"] + get "/dashboard", headers: { "REMOTE_ADDR" => "192.168.1.100" } + assert_equal "dashboards#show", @response.body end def test_root_works_in_the_resources_scope draw do resources :products do - root :to => "products#root" + root to: "products#root" end end - get '/products' - assert_equal 'products#root', @response.body - assert_equal '/products', products_root_path + get "/products" + assert_equal "products#root", @response.body + assert_equal "/products", products_root_path end def test_module_scope draw do - resource :token, :module => :api + resource :token, module: :api end - get '/token' - assert_equal 'api/tokens#show', @response.body - assert_equal '/token', token_path + get "/token" + assert_equal "api/tokens#show", @response.body + assert_equal "/token", token_path end def test_path_scope draw do - scope :path => 'api' do + scope path: "api" do resource :me - get '/' => 'mes#index' + get "/" => "mes#index" end end - get '/api/me' - assert_equal 'mes#show', @response.body - assert_equal '/api/me', me_path + get "/api/me" + assert_equal "mes#show", @response.body + assert_equal "/api/me", me_path - get '/api' - assert_equal 'mes#index', @response.body + get "/api" + assert_equal "mes#index", @response.body end def test_symbol_scope draw do - scope :path => 'api' do + scope path: "api" do scope :v2 do - resource :me, as: 'v2_me' - get '/' => 'mes#index' + resource :me, as: "v2_me" + get "/" => "mes#index" end scope :v3, :admin do - resource :me, as: 'v3_me' + resource :me, as: "v3_me" end end end - get '/api/v2/me' - assert_equal 'mes#show', @response.body - assert_equal '/api/v2/me', v2_me_path + get "/api/v2/me" + assert_equal "mes#show", @response.body + assert_equal "/api/v2/me", v2_me_path - get '/api/v2' - assert_equal 'mes#index', @response.body + get "/api/v2" + assert_equal "mes#index", @response.body - get '/api/v3/admin/me' - assert_equal 'mes#show', @response.body + get "/api/v3/admin/me" + assert_equal "mes#show", @response.body end def test_url_generator_for_generic_route @@ -1855,31 +1893,31 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/whatever/foo/bar' - assert_equal 'foo#bar', @response.body + get "/whatever/foo/bar" + assert_equal "foo#bar", @response.body - assert_equal 'http://www.example.com/whatever/foo/bar/1', - url_for(:controller => "foo", :action => "bar", :id => 1) + assert_equal "http://www.example.com/whatever/foo/bar/1", + url_for(controller: "foo", action: "bar", id: 1) end def test_url_generator_for_namespaced_generic_route draw do ActiveSupport::Deprecation.silence do - get "whatever/:controller(/:action(/:id))", :id => /\d+/ + get "whatever/:controller(/:action(/:id))", id: /\d+/ end end - get '/whatever/foo/bar/show' - assert_equal 'foo/bar#show', @response.body + get "/whatever/foo/bar/show" + assert_equal "foo/bar#show", @response.body - get '/whatever/foo/bar/show/1' - assert_equal 'foo/bar#show', @response.body + get "/whatever/foo/bar/show/1" + assert_equal "foo/bar#show", @response.body - assert_equal 'http://www.example.com/whatever/foo/bar/show', - url_for(:controller => "foo/bar", :action => "show") + assert_equal "http://www.example.com/whatever/foo/bar/show", + url_for(controller: "foo/bar", action: "show") - assert_equal 'http://www.example.com/whatever/foo/bar/show/1', - url_for(:controller => "foo/bar", :action => "show", :id => '1') + assert_equal "http://www.example.com/whatever/foo/bar/show/1", + url_for(controller: "foo/bar", action: "show", id: "1") end def test_resource_new_actions @@ -1890,16 +1928,16 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - scope 'pt', :as => 'pt' do - resources :projects, :path_names => { :new => 'novo' }, :path => 'projetos' do - post :preview, :on => :new + scope "pt", as: "pt" do + resources :projects, path_names: { new: "novo" }, path: "projetos" do + post :preview, on: :new end - resource :admin, :path_names => { :new => 'novo' }, :path => 'administrador' do - post :preview, :on => :new + resource :admin, path_names: { new: "novo" }, path: "administrador" do + post :preview, on: :new end - resources :products, :path_names => { :new => 'novo' } do + resources :products, path_names: { new: "novo" } do new do post :preview end @@ -1913,58 +1951,58 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - assert_equal '/replies/new/preview', preview_new_reply_path - assert_equal '/pt/projetos/novo/preview', preview_new_pt_project_path - assert_equal '/pt/administrador/novo/preview', preview_new_pt_admin_path - assert_equal '/pt/products/novo/preview', preview_new_pt_product_path - assert_equal '/profile/new/preview', preview_new_profile_path + assert_equal "/replies/new/preview", preview_new_reply_path + assert_equal "/pt/projetos/novo/preview", preview_new_pt_project_path + assert_equal "/pt/administrador/novo/preview", preview_new_pt_admin_path + assert_equal "/pt/products/novo/preview", preview_new_pt_product_path + assert_equal "/profile/new/preview", preview_new_profile_path - post '/replies/new/preview' - assert_equal 'replies#preview', @response.body + post "/replies/new/preview" + assert_equal "replies#preview", @response.body - post '/pt/projetos/novo/preview' - assert_equal 'projects#preview', @response.body + post "/pt/projetos/novo/preview" + assert_equal "projects#preview", @response.body - post '/pt/administrador/novo/preview' - assert_equal 'admins#preview', @response.body + post "/pt/administrador/novo/preview" + assert_equal "admins#preview", @response.body - post '/pt/products/novo/preview' - assert_equal 'products#preview', @response.body + post "/pt/products/novo/preview" + assert_equal "products#preview", @response.body - post '/profile/new/preview' - assert_equal 'profiles#preview', @response.body + post "/profile/new/preview" + assert_equal "profiles#preview", @response.body end def test_resource_merges_options_from_scope draw do - scope :only => :show do + scope only: :show do resource :account end end assert_raise(NoMethodError) { new_account_path } - get '/account/new' + get "/account/new" assert_equal 404, status end def test_resources_merges_options_from_scope draw do - scope :only => [:index, :show] do + scope only: [:index, :show] do resources :products do resources :images end end end - assert_raise(NoMethodError) { edit_product_path('1') } + assert_raise(NoMethodError) { edit_product_path("1") } - get '/products/1/edit' + get "/products/1/edit" assert_equal 404, status - assert_raise(NoMethodError) { edit_product_image_path('1', '2') } + assert_raise(NoMethodError) { edit_product_image_path("1", "2") } - post '/products/1/images/2/edit' + post "/products/1/images/2/edit" assert_equal 404, status end @@ -1979,7 +2017,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - resources :threads, :shallow => true do + resources :threads, shallow: true do resource :owner resources :messages do resources :comments do @@ -1991,105 +2029,105 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/api/teams' - assert_equal 'api/teams#index', @response.body - assert_equal '/api/teams', api_teams_path + get "/api/teams" + assert_equal "api/teams#index", @response.body + assert_equal "/api/teams", api_teams_path - get '/api/teams/new' - assert_equal 'api/teams#new', @response.body - assert_equal '/api/teams/new', new_api_team_path + get "/api/teams/new" + assert_equal "api/teams#new", @response.body + assert_equal "/api/teams/new", new_api_team_path - get '/api/teams/1' - assert_equal 'api/teams#show', @response.body - assert_equal '/api/teams/1', api_team_path(:id => '1') + get "/api/teams/1" + assert_equal "api/teams#show", @response.body + assert_equal "/api/teams/1", api_team_path(id: "1") - get '/api/teams/1/edit' - assert_equal 'api/teams#edit', @response.body - assert_equal '/api/teams/1/edit', edit_api_team_path(:id => '1') + get "/api/teams/1/edit" + assert_equal "api/teams#edit", @response.body + assert_equal "/api/teams/1/edit", edit_api_team_path(id: "1") - get '/api/teams/1/players' - assert_equal 'api/players#index', @response.body - assert_equal '/api/teams/1/players', api_team_players_path(:team_id => '1') + get "/api/teams/1/players" + assert_equal "api/players#index", @response.body + assert_equal "/api/teams/1/players", api_team_players_path(team_id: "1") - get '/api/teams/1/players/new' - assert_equal 'api/players#new', @response.body - assert_equal '/api/teams/1/players/new', new_api_team_player_path(:team_id => '1') + get "/api/teams/1/players/new" + assert_equal "api/players#new", @response.body + assert_equal "/api/teams/1/players/new", new_api_team_player_path(team_id: "1") - get '/api/players/2' - assert_equal 'api/players#show', @response.body - assert_equal '/api/players/2', api_player_path(:id => '2') + get "/api/players/2" + assert_equal "api/players#show", @response.body + assert_equal "/api/players/2", api_player_path(id: "2") - get '/api/players/2/edit' - assert_equal 'api/players#edit', @response.body - assert_equal '/api/players/2/edit', edit_api_player_path(:id => '2') + get "/api/players/2/edit" + assert_equal "api/players#edit", @response.body + assert_equal "/api/players/2/edit", edit_api_player_path(id: "2") - get '/api/teams/1/captain' - assert_equal 'api/captains#show', @response.body - assert_equal '/api/teams/1/captain', api_team_captain_path(:team_id => '1') + get "/api/teams/1/captain" + assert_equal "api/captains#show", @response.body + assert_equal "/api/teams/1/captain", api_team_captain_path(team_id: "1") - get '/api/teams/1/captain/new' - assert_equal 'api/captains#new', @response.body - assert_equal '/api/teams/1/captain/new', new_api_team_captain_path(:team_id => '1') + get "/api/teams/1/captain/new" + assert_equal "api/captains#new", @response.body + assert_equal "/api/teams/1/captain/new", new_api_team_captain_path(team_id: "1") - get '/api/teams/1/captain/edit' - assert_equal 'api/captains#edit', @response.body - assert_equal '/api/teams/1/captain/edit', edit_api_team_captain_path(:team_id => '1') + get "/api/teams/1/captain/edit" + assert_equal "api/captains#edit", @response.body + assert_equal "/api/teams/1/captain/edit", edit_api_team_captain_path(team_id: "1") - get '/threads' - assert_equal 'threads#index', @response.body - assert_equal '/threads', threads_path + get "/threads" + assert_equal "threads#index", @response.body + assert_equal "/threads", threads_path - get '/threads/new' - assert_equal 'threads#new', @response.body - assert_equal '/threads/new', new_thread_path + get "/threads/new" + assert_equal "threads#new", @response.body + assert_equal "/threads/new", new_thread_path - get '/threads/1' - assert_equal 'threads#show', @response.body - assert_equal '/threads/1', thread_path(:id => '1') + get "/threads/1" + assert_equal "threads#show", @response.body + assert_equal "/threads/1", thread_path(id: "1") - get '/threads/1/edit' - assert_equal 'threads#edit', @response.body - assert_equal '/threads/1/edit', edit_thread_path(:id => '1') + get "/threads/1/edit" + assert_equal "threads#edit", @response.body + assert_equal "/threads/1/edit", edit_thread_path(id: "1") - get '/threads/1/owner' - assert_equal 'owners#show', @response.body - assert_equal '/threads/1/owner', thread_owner_path(:thread_id => '1') + get "/threads/1/owner" + assert_equal "owners#show", @response.body + assert_equal "/threads/1/owner", thread_owner_path(thread_id: "1") - get '/threads/1/messages' - assert_equal 'messages#index', @response.body - assert_equal '/threads/1/messages', thread_messages_path(:thread_id => '1') + get "/threads/1/messages" + assert_equal "messages#index", @response.body + assert_equal "/threads/1/messages", thread_messages_path(thread_id: "1") - get '/threads/1/messages/new' - assert_equal 'messages#new', @response.body - assert_equal '/threads/1/messages/new', new_thread_message_path(:thread_id => '1') + get "/threads/1/messages/new" + assert_equal "messages#new", @response.body + assert_equal "/threads/1/messages/new", new_thread_message_path(thread_id: "1") - get '/messages/2' - assert_equal 'messages#show', @response.body - assert_equal '/messages/2', message_path(:id => '2') + get "/messages/2" + assert_equal "messages#show", @response.body + assert_equal "/messages/2", message_path(id: "2") - get '/messages/2/edit' - assert_equal 'messages#edit', @response.body - assert_equal '/messages/2/edit', edit_message_path(:id => '2') + get "/messages/2/edit" + assert_equal "messages#edit", @response.body + assert_equal "/messages/2/edit", edit_message_path(id: "2") - get '/messages/2/comments' - assert_equal 'comments#index', @response.body - assert_equal '/messages/2/comments', message_comments_path(:message_id => '2') + get "/messages/2/comments" + assert_equal "comments#index", @response.body + assert_equal "/messages/2/comments", message_comments_path(message_id: "2") - get '/messages/2/comments/new' - assert_equal 'comments#new', @response.body - assert_equal '/messages/2/comments/new', new_message_comment_path(:message_id => '2') + get "/messages/2/comments/new" + assert_equal "comments#new", @response.body + assert_equal "/messages/2/comments/new", new_message_comment_path(message_id: "2") - get '/comments/3' - assert_equal 'comments#show', @response.body - assert_equal '/comments/3', comment_path(:id => '3') + get "/comments/3" + assert_equal "comments#show", @response.body + assert_equal "/comments/3", comment_path(id: "3") - get '/comments/3/edit' - assert_equal 'comments#edit', @response.body - assert_equal '/comments/3/edit', edit_comment_path(:id => '3') + get "/comments/3/edit" + assert_equal "comments#edit", @response.body + assert_equal "/comments/3/edit", edit_comment_path(id: "3") - post '/comments/3/preview' - assert_equal 'comments#preview', @response.body - assert_equal '/comments/3/preview', preview_comment_path(:id => '3') + post "/comments/3/preview" + assert_equal "comments#preview", @response.body + assert_equal "/comments/3/preview", preview_comment_path(id: "3") end def test_shallow_nested_resources_inside_resource @@ -2099,33 +2137,33 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/membership/cards' - assert_equal 'cards#index', @response.body - assert_equal '/membership/cards', membership_cards_path + get "/membership/cards" + assert_equal "cards#index", @response.body + assert_equal "/membership/cards", membership_cards_path - get '/membership/cards/new' - assert_equal 'cards#new', @response.body - assert_equal '/membership/cards/new', new_membership_card_path + get "/membership/cards/new" + assert_equal "cards#new", @response.body + assert_equal "/membership/cards/new", new_membership_card_path - post '/membership/cards' - assert_equal 'cards#create', @response.body + post "/membership/cards" + assert_equal "cards#create", @response.body - get '/cards/1' - assert_equal 'cards#show', @response.body - assert_equal '/cards/1', card_path('1') + get "/cards/1" + assert_equal "cards#show", @response.body + assert_equal "/cards/1", card_path("1") - get '/cards/1/edit' - assert_equal 'cards#edit', @response.body - assert_equal '/cards/1/edit', edit_card_path('1') + get "/cards/1/edit" + assert_equal "cards#edit", @response.body + assert_equal "/cards/1/edit", edit_card_path("1") - put '/cards/1' - assert_equal 'cards#update', @response.body + put "/cards/1" + assert_equal "cards#update", @response.body - patch '/cards/1' - assert_equal 'cards#update', @response.body + patch "/cards/1" + assert_equal "cards#update", @response.body - delete '/cards/1' - assert_equal 'cards#destroy', @response.body + delete "/cards/1" + assert_equal "cards#destroy", @response.body end def test_shallow_deeply_nested_resources @@ -2137,13 +2175,13 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/comments/1' - assert_equal 'comments#show', @response.body + get "/comments/1" + assert_equal "comments#show", @response.body - assert_equal '/comments/1', comment_path('1') - assert_equal '/blogs/new', new_blog_path - assert_equal '/blogs/1/posts/new', new_blog_post_path(:blog_id => 1) - assert_equal '/blogs/1/posts/2/comments/new', new_blog_post_comment_path(:blog_id => 1, :post_id => 2) + assert_equal "/comments/1", comment_path("1") + assert_equal "/blogs/new", new_blog_path + assert_equal "/blogs/1/posts/new", new_blog_post_path(blog_id: 1) + assert_equal "/blogs/1/posts/2/comments/new", new_blog_post_comment_path(blog_id: 1, post_id: 2) end def test_direct_children_of_shallow_resources @@ -2155,22 +2193,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - post '/posts/1/comments' - assert_equal 'comments#create', @response.body - assert_equal '/posts/1/comments', post_comments_path('1') + post "/posts/1/comments" + assert_equal "comments#create", @response.body + assert_equal "/posts/1/comments", post_comments_path("1") - get '/posts/2/comments/new' - assert_equal 'comments#new', @response.body - assert_equal '/posts/2/comments/new', new_post_comment_path('2') + get "/posts/2/comments/new" + assert_equal "comments#new", @response.body + assert_equal "/posts/2/comments/new", new_post_comment_path("2") - get '/posts/1/comments' - assert_equal 'comments#index', @response.body - assert_equal '/posts/1/comments', post_comments_path('1') + get "/posts/1/comments" + assert_equal "comments#index", @response.body + assert_equal "/posts/1/comments", post_comments_path("1") end def test_shallow_nested_resources_within_scope draw do - scope '/hello' do + scope "/hello" do shallow do resources :notes do resources :trackbacks @@ -2179,120 +2217,120 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/hello/notes/1/trackbacks' - assert_equal 'trackbacks#index', @response.body - assert_equal '/hello/notes/1/trackbacks', note_trackbacks_path(:note_id => 1) + get "/hello/notes/1/trackbacks" + assert_equal "trackbacks#index", @response.body + assert_equal "/hello/notes/1/trackbacks", note_trackbacks_path(note_id: 1) - get '/hello/notes/1/edit' - assert_equal 'notes#edit', @response.body - assert_equal '/hello/notes/1/edit', edit_note_path(:id => '1') + get "/hello/notes/1/edit" + assert_equal "notes#edit", @response.body + assert_equal "/hello/notes/1/edit", edit_note_path(id: "1") - get '/hello/notes/1/trackbacks/new' - assert_equal 'trackbacks#new', @response.body - assert_equal '/hello/notes/1/trackbacks/new', new_note_trackback_path(:note_id => 1) + get "/hello/notes/1/trackbacks/new" + assert_equal "trackbacks#new", @response.body + assert_equal "/hello/notes/1/trackbacks/new", new_note_trackback_path(note_id: 1) - get '/hello/trackbacks/1' - assert_equal 'trackbacks#show', @response.body - assert_equal '/hello/trackbacks/1', trackback_path(:id => '1') + get "/hello/trackbacks/1" + assert_equal "trackbacks#show", @response.body + assert_equal "/hello/trackbacks/1", trackback_path(id: "1") - get '/hello/trackbacks/1/edit' - assert_equal 'trackbacks#edit', @response.body - assert_equal '/hello/trackbacks/1/edit', edit_trackback_path(:id => '1') + get "/hello/trackbacks/1/edit" + assert_equal "trackbacks#edit", @response.body + assert_equal "/hello/trackbacks/1/edit", edit_trackback_path(id: "1") - put '/hello/trackbacks/1' - assert_equal 'trackbacks#update', @response.body + put "/hello/trackbacks/1" + assert_equal "trackbacks#update", @response.body - post '/hello/notes/1/trackbacks' - assert_equal 'trackbacks#create', @response.body + post "/hello/notes/1/trackbacks" + assert_equal "trackbacks#create", @response.body - delete '/hello/trackbacks/1' - assert_equal 'trackbacks#destroy', @response.body + delete "/hello/trackbacks/1" + assert_equal "trackbacks#destroy", @response.body - get '/hello/notes' - assert_equal 'notes#index', @response.body + get "/hello/notes" + assert_equal "notes#index", @response.body - post '/hello/notes' - assert_equal 'notes#create', @response.body + post "/hello/notes" + assert_equal "notes#create", @response.body - get '/hello/notes/new' - assert_equal 'notes#new', @response.body - assert_equal '/hello/notes/new', new_note_path + get "/hello/notes/new" + assert_equal "notes#new", @response.body + assert_equal "/hello/notes/new", new_note_path - get '/hello/notes/1' - assert_equal 'notes#show', @response.body - assert_equal '/hello/notes/1', note_path(:id => 1) + get "/hello/notes/1" + assert_equal "notes#show", @response.body + assert_equal "/hello/notes/1", note_path(id: 1) - put '/hello/notes/1' - assert_equal 'notes#update', @response.body + put "/hello/notes/1" + assert_equal "notes#update", @response.body - delete '/hello/notes/1' - assert_equal 'notes#destroy', @response.body + delete "/hello/notes/1" + assert_equal "notes#destroy", @response.body end def test_shallow_option_nested_resources_within_scope draw do - scope '/hello' do - resources :notes, :shallow => true do + scope "/hello" do + resources :notes, shallow: true do resources :trackbacks end end end - get '/hello/notes/1/trackbacks' - assert_equal 'trackbacks#index', @response.body - assert_equal '/hello/notes/1/trackbacks', note_trackbacks_path(:note_id => 1) + get "/hello/notes/1/trackbacks" + assert_equal "trackbacks#index", @response.body + assert_equal "/hello/notes/1/trackbacks", note_trackbacks_path(note_id: 1) - get '/hello/notes/1/edit' - assert_equal 'notes#edit', @response.body - assert_equal '/hello/notes/1/edit', edit_note_path(:id => '1') + get "/hello/notes/1/edit" + assert_equal "notes#edit", @response.body + assert_equal "/hello/notes/1/edit", edit_note_path(id: "1") - get '/hello/notes/1/trackbacks/new' - assert_equal 'trackbacks#new', @response.body - assert_equal '/hello/notes/1/trackbacks/new', new_note_trackback_path(:note_id => 1) + get "/hello/notes/1/trackbacks/new" + assert_equal "trackbacks#new", @response.body + assert_equal "/hello/notes/1/trackbacks/new", new_note_trackback_path(note_id: 1) - get '/hello/trackbacks/1' - assert_equal 'trackbacks#show', @response.body - assert_equal '/hello/trackbacks/1', trackback_path(:id => '1') + get "/hello/trackbacks/1" + assert_equal "trackbacks#show", @response.body + assert_equal "/hello/trackbacks/1", trackback_path(id: "1") - get '/hello/trackbacks/1/edit' - assert_equal 'trackbacks#edit', @response.body - assert_equal '/hello/trackbacks/1/edit', edit_trackback_path(:id => '1') + get "/hello/trackbacks/1/edit" + assert_equal "trackbacks#edit", @response.body + assert_equal "/hello/trackbacks/1/edit", edit_trackback_path(id: "1") - put '/hello/trackbacks/1' - assert_equal 'trackbacks#update', @response.body + put "/hello/trackbacks/1" + assert_equal "trackbacks#update", @response.body - post '/hello/notes/1/trackbacks' - assert_equal 'trackbacks#create', @response.body + post "/hello/notes/1/trackbacks" + assert_equal "trackbacks#create", @response.body - delete '/hello/trackbacks/1' - assert_equal 'trackbacks#destroy', @response.body + delete "/hello/trackbacks/1" + assert_equal "trackbacks#destroy", @response.body - get '/hello/notes' - assert_equal 'notes#index', @response.body + get "/hello/notes" + assert_equal "notes#index", @response.body - post '/hello/notes' - assert_equal 'notes#create', @response.body + post "/hello/notes" + assert_equal "notes#create", @response.body - get '/hello/notes/new' - assert_equal 'notes#new', @response.body - assert_equal '/hello/notes/new', new_note_path + get "/hello/notes/new" + assert_equal "notes#new", @response.body + assert_equal "/hello/notes/new", new_note_path - get '/hello/notes/1' - assert_equal 'notes#show', @response.body - assert_equal '/hello/notes/1', note_path(:id => 1) + get "/hello/notes/1" + assert_equal "notes#show", @response.body + assert_equal "/hello/notes/1", note_path(id: 1) - put '/hello/notes/1' - assert_equal 'notes#update', @response.body + put "/hello/notes/1" + assert_equal "notes#update", @response.body - delete '/hello/notes/1' - assert_equal 'notes#destroy', @response.body + delete "/hello/notes/1" + assert_equal "notes#destroy", @response.body end def test_custom_resource_routes_are_scoped draw do resources :customers do - get :recent, :on => :collection - get "profile", :on => :member + get :recent, on: :collection + get "profile", on: :member get "secret/profile" => "customers#secret", :on => :member post "preview" => "customers#preview", :as => :another_preview, :on => :new resource :avatar do @@ -2300,11 +2338,11 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end resources :invoices do get "outstanding" => "invoices#outstanding", :on => :collection - get "overdue", :action => :overdue, :on => :collection + get "overdue", action: :overdue, on: :collection get "print" => "invoices#print", :as => :print, :on => :member post "preview" => "invoices#preview", :as => :preview, :on => :new end - resources :notes, :shallow => true do + resources :notes, shallow: true do get "preview" => "notes#preview", :as => :preview, :on => :new get "print" => "notes#print", :as => :print, :on => :member end @@ -2319,79 +2357,79 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - assert_equal '/customers/recent', recent_customers_path - assert_equal '/customers/1/profile', profile_customer_path(:id => '1') - assert_equal '/customers/1/secret/profile', secret_profile_customer_path(:id => '1') - assert_equal '/customers/new/preview', another_preview_new_customer_path - assert_equal '/customers/1/avatar/thumbnail.jpg', thumbnail_customer_avatar_path(:customer_id => '1', :format => :jpg) - assert_equal '/customers/1/invoices/outstanding', outstanding_customer_invoices_path(:customer_id => '1') - assert_equal '/customers/1/invoices/2/print', print_customer_invoice_path(:customer_id => '1', :id => '2') - assert_equal '/customers/1/invoices/new/preview', preview_new_customer_invoice_path(:customer_id => '1') - assert_equal '/customers/1/notes/new/preview', preview_new_customer_note_path(:customer_id => '1') - assert_equal '/notes/1/print', print_note_path(:id => '1') - assert_equal '/api/customers/recent', recent_api_customers_path - assert_equal '/api/customers/1/profile', profile_api_customer_path(:id => '1') - assert_equal '/api/customers/new/preview', preview_new_api_customer_path + assert_equal "/customers/recent", recent_customers_path + assert_equal "/customers/1/profile", profile_customer_path(id: "1") + assert_equal "/customers/1/secret/profile", secret_profile_customer_path(id: "1") + assert_equal "/customers/new/preview", another_preview_new_customer_path + assert_equal "/customers/1/avatar/thumbnail.jpg", thumbnail_customer_avatar_path(customer_id: "1", format: :jpg) + assert_equal "/customers/1/invoices/outstanding", outstanding_customer_invoices_path(customer_id: "1") + assert_equal "/customers/1/invoices/2/print", print_customer_invoice_path(customer_id: "1", id: "2") + assert_equal "/customers/1/invoices/new/preview", preview_new_customer_invoice_path(customer_id: "1") + assert_equal "/customers/1/notes/new/preview", preview_new_customer_note_path(customer_id: "1") + assert_equal "/notes/1/print", print_note_path(id: "1") + assert_equal "/api/customers/recent", recent_api_customers_path + assert_equal "/api/customers/1/profile", profile_api_customer_path(id: "1") + assert_equal "/api/customers/new/preview", preview_new_api_customer_path - get '/customers/1/invoices/overdue' - assert_equal 'invoices#overdue', @response.body + get "/customers/1/invoices/overdue" + assert_equal "invoices#overdue", @response.body - get '/customers/1/secret/profile' - assert_equal 'customers#secret', @response.body + get "/customers/1/secret/profile" + assert_equal "customers#secret", @response.body end def test_shallow_nested_routes_ignore_module draw do - scope :module => :api do - resources :errors, :shallow => true do + scope module: :api do + resources :errors, shallow: true do resources :notices end end end - get '/errors/1/notices' - assert_equal 'api/notices#index', @response.body - assert_equal '/errors/1/notices', error_notices_path(:error_id => '1') + get "/errors/1/notices" + assert_equal "api/notices#index", @response.body + assert_equal "/errors/1/notices", error_notices_path(error_id: "1") - get '/notices/1' - assert_equal 'api/notices#show', @response.body - assert_equal '/notices/1', notice_path(:id => '1') + get "/notices/1" + assert_equal "api/notices#show", @response.body + assert_equal "/notices/1", notice_path(id: "1") end def test_non_greedy_regexp draw do namespace :api do - scope(':version', :version => /.+/) do - resources :users, :id => /.+?/, :format => /json|xml/ + scope(":version", version: /.+/) do + resources :users, id: /.+?/, format: /json|xml/ end end end - get '/api/1.0/users' - assert_equal 'api/users#index', @response.body - assert_equal '/api/1.0/users', api_users_path(:version => '1.0') + get "/api/1.0/users" + assert_equal "api/users#index", @response.body + assert_equal "/api/1.0/users", api_users_path(version: "1.0") - get '/api/1.0/users.json' - assert_equal 'api/users#index', @response.body + get "/api/1.0/users.json" + assert_equal "api/users#index", @response.body assert_equal true, @request.format.json? - assert_equal '/api/1.0/users.json', api_users_path(:version => '1.0', :format => :json) + assert_equal "/api/1.0/users.json", api_users_path(version: "1.0", format: :json) - get '/api/1.0/users/first.last' - assert_equal 'api/users#show', @response.body - assert_equal 'first.last', @request.params[:id] - assert_equal '/api/1.0/users/first.last', api_user_path(:version => '1.0', :id => 'first.last') + get "/api/1.0/users/first.last" + assert_equal "api/users#show", @response.body + assert_equal "first.last", @request.params[:id] + assert_equal "/api/1.0/users/first.last", api_user_path(version: "1.0", id: "first.last") - get '/api/1.0/users/first.last.xml' - assert_equal 'api/users#show', @response.body - assert_equal 'first.last', @request.params[:id] + get "/api/1.0/users/first.last.xml" + assert_equal "api/users#show", @response.body + assert_equal "first.last", @request.params[:id] assert_equal true, @request.format.xml? - assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml) + assert_equal "/api/1.0/users/first.last.xml", api_user_path(version: "1.0", id: "first.last", format: :xml) end def test_match_without_via assert_raises(ArgumentError) do draw do - match '/foo/bar', :to => 'files#show' + match "/foo/bar", to: "files#show" end end end @@ -2399,17 +2437,17 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_match_with_empty_via assert_raises(ArgumentError) do draw do - match '/foo/bar', :to => 'files#show', :via => [] + match "/foo/bar", to: "files#show", via: [] end end end def test_glob_parameter_accepts_regexp draw do - get '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ + get "/:locale/*file.:format", to: "files#show", file: /path\/to\/existing\/file/ end - get '/en/path/to/existing/file.html' + get "/en/path/to/existing/file.html" assert_equal 200, @response.status end @@ -2418,8 +2456,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :content end - get '/content' - assert_equal 'content#index', @response.body + get "/content" + assert_equal "content#index", @response.body end def test_url_generator_for_optional_prefix_dynamic_segment @@ -2427,15 +2465,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "(/:username)/followers" => "followers#index" end - get '/bob/followers' - assert_equal 'followers#index', @response.body - assert_equal 'http://www.example.com/bob/followers', - url_for(:controller => "followers", :action => "index", :username => "bob") + get "/bob/followers" + assert_equal "followers#index", @response.body + assert_equal "http://www.example.com/bob/followers", + url_for(controller: "followers", action: "index", username: "bob") - get '/followers' - assert_equal 'followers#index', @response.body - assert_equal 'http://www.example.com/followers', - url_for(:controller => "followers", :action => "index", :username => nil) + get "/followers" + assert_equal "followers#index", @response.body + assert_equal "http://www.example.com/followers", + url_for(controller: "followers", action: "index", username: nil) end def test_url_generator_for_optional_suffix_static_and_dynamic_segment @@ -2443,15 +2481,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "/groups(/user/:username)" => "groups#index" end - get '/groups/user/bob' - assert_equal 'groups#index', @response.body - assert_equal 'http://www.example.com/groups/user/bob', - url_for(:controller => "groups", :action => "index", :username => "bob") + get "/groups/user/bob" + assert_equal "groups#index", @response.body + assert_equal "http://www.example.com/groups/user/bob", + url_for(controller: "groups", action: "index", username: "bob") - get '/groups' - assert_equal 'groups#index', @response.body - assert_equal 'http://www.example.com/groups', - url_for(:controller => "groups", :action => "index", :username => nil) + get "/groups" + assert_equal "groups#index", @response.body + assert_equal "http://www.example.com/groups", + url_for(controller: "groups", action: "index", username: nil) end def test_url_generator_for_optional_prefix_static_and_dynamic_segment @@ -2459,66 +2497,66 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "(/user/:username)/photos" => "photos#index" end - get '/user/bob/photos' - assert_equal 'photos#index', @response.body - assert_equal 'http://www.example.com/user/bob/photos', - url_for(:controller => "photos", :action => "index", :username => "bob") + get "/user/bob/photos" + assert_equal "photos#index", @response.body + assert_equal "http://www.example.com/user/bob/photos", + url_for(controller: "photos", action: "index", username: "bob") - get '/photos' - assert_equal 'photos#index', @response.body - assert_equal 'http://www.example.com/photos', - url_for(:controller => "photos", :action => "index", :username => nil) + get "/photos" + assert_equal "photos#index", @response.body + assert_equal "http://www.example.com/photos", + url_for(controller: "photos", action: "index", username: nil) end def test_url_recognition_for_optional_static_segments draw do - scope '(groups)' do - scope '(discussions)' do + scope "(groups)" do + scope "(discussions)" do resources :messages end end end - get '/groups/discussions/messages' - assert_equal 'messages#index', @response.body + get "/groups/discussions/messages" + assert_equal "messages#index", @response.body - get '/groups/discussions/messages/1' - assert_equal 'messages#show', @response.body + get "/groups/discussions/messages/1" + assert_equal "messages#show", @response.body - get '/groups/messages' - assert_equal 'messages#index', @response.body + get "/groups/messages" + assert_equal "messages#index", @response.body - get '/groups/messages/1' - assert_equal 'messages#show', @response.body + get "/groups/messages/1" + assert_equal "messages#show", @response.body - get '/discussions/messages' - assert_equal 'messages#index', @response.body + get "/discussions/messages" + assert_equal "messages#index", @response.body - get '/discussions/messages/1' - assert_equal 'messages#show', @response.body + get "/discussions/messages/1" + assert_equal "messages#show", @response.body - get '/messages' - assert_equal 'messages#index', @response.body + get "/messages" + assert_equal "messages#index", @response.body - get '/messages/1' - assert_equal 'messages#show', @response.body + get "/messages/1" + assert_equal "messages#show", @response.body end def test_router_removes_invalid_conditions draw do - scope :constraints => { :id => /\d+/ } do - get '/tickets', :to => 'tickets#index', :as => :tickets + scope constraints: { id: /\d+/ } do + get "/tickets", to: "tickets#index", as: :tickets end end - get '/tickets' - assert_equal 'tickets#index', @response.body - assert_equal '/tickets', tickets_path + get "/tickets" + assert_equal "tickets#index", @response.body + assert_equal "/tickets", tickets_path end def test_constraints_are_merged_from_scope draw do - scope :constraints => { :id => /\d{4}/ } do + scope constraints: { id: /\d{4}/ } do resources :movies do resources :reviews resource :trailer @@ -2526,42 +2564,42 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/movies/0001' - assert_equal 'movies#show', @response.body - assert_equal '/movies/0001', movie_path(:id => '0001') + get "/movies/0001" + assert_equal "movies#show", @response.body + assert_equal "/movies/0001", movie_path(id: "0001") - get '/movies/00001' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::UrlGenerationError){ movie_path(:id => '00001') } + get "/movies/00001" + assert_equal "Not Found", @response.body + assert_raises(ActionController::UrlGenerationError) { movie_path(id: "00001") } - get '/movies/0001/reviews' - assert_equal 'reviews#index', @response.body - assert_equal '/movies/0001/reviews', movie_reviews_path(:movie_id => '0001') + get "/movies/0001/reviews" + assert_equal "reviews#index", @response.body + assert_equal "/movies/0001/reviews", movie_reviews_path(movie_id: "0001") - get '/movies/00001/reviews' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::UrlGenerationError){ movie_reviews_path(:movie_id => '00001') } + get "/movies/00001/reviews" + assert_equal "Not Found", @response.body + assert_raises(ActionController::UrlGenerationError) { movie_reviews_path(movie_id: "00001") } - get '/movies/0001/reviews/0001' - assert_equal 'reviews#show', @response.body - assert_equal '/movies/0001/reviews/0001', movie_review_path(:movie_id => '0001', :id => '0001') + get "/movies/0001/reviews/0001" + assert_equal "reviews#show", @response.body + assert_equal "/movies/0001/reviews/0001", movie_review_path(movie_id: "0001", id: "0001") - get '/movies/00001/reviews/0001' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::UrlGenerationError){ movie_path(:movie_id => '00001', :id => '00001') } + get "/movies/00001/reviews/0001" + assert_equal "Not Found", @response.body + assert_raises(ActionController::UrlGenerationError) { movie_path(movie_id: "00001", id: "00001") } - get '/movies/0001/trailer' - assert_equal 'trailers#show', @response.body - assert_equal '/movies/0001/trailer', movie_trailer_path(:movie_id => '0001') + get "/movies/0001/trailer" + assert_equal "trailers#show", @response.body + assert_equal "/movies/0001/trailer", movie_trailer_path(movie_id: "0001") - get '/movies/00001/trailer' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::UrlGenerationError){ movie_trailer_path(:movie_id => '00001') } + get "/movies/00001/trailer" + assert_equal "Not Found", @response.body + assert_raises(ActionController::UrlGenerationError) { movie_trailer_path(movie_id: "00001") } end def test_only_should_be_read_from_scope draw do - scope :only => [:index, :show] do + scope only: [:index, :show] do namespace :only do resources :clubs do resources :players @@ -2571,34 +2609,34 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/only/clubs' - assert_equal 'only/clubs#index', @response.body - assert_equal '/only/clubs', only_clubs_path + get "/only/clubs" + assert_equal "only/clubs#index", @response.body + assert_equal "/only/clubs", only_clubs_path - get '/only/clubs/1/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_only_club_path(:id => '1') } + get "/only/clubs/1/edit" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { edit_only_club_path(id: "1") } - get '/only/clubs/1/players' - assert_equal 'only/players#index', @response.body - assert_equal '/only/clubs/1/players', only_club_players_path(:club_id => '1') + get "/only/clubs/1/players" + assert_equal "only/players#index", @response.body + assert_equal "/only/clubs/1/players", only_club_players_path(club_id: "1") - get '/only/clubs/1/players/2/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_only_club_player_path(:club_id => '1', :id => '2') } + get "/only/clubs/1/players/2/edit" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { edit_only_club_player_path(club_id: "1", id: "2") } - get '/only/clubs/1/chairman' - assert_equal 'only/chairmen#show', @response.body - assert_equal '/only/clubs/1/chairman', only_club_chairman_path(:club_id => '1') + get "/only/clubs/1/chairman" + assert_equal "only/chairmen#show", @response.body + assert_equal "/only/clubs/1/chairman", only_club_chairman_path(club_id: "1") - get '/only/clubs/1/chairman/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_only_club_chairman_path(:club_id => '1') } + get "/only/clubs/1/chairman/edit" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { edit_only_club_chairman_path(club_id: "1") } end def test_except_should_be_read_from_scope draw do - scope :except => [:new, :create, :edit, :update, :destroy] do + scope except: [:new, :create, :edit, :update, :destroy] do namespace :except do resources :clubs do resources :players @@ -2608,54 +2646,54 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/except/clubs' - assert_equal 'except/clubs#index', @response.body - assert_equal '/except/clubs', except_clubs_path + get "/except/clubs" + assert_equal "except/clubs#index", @response.body + assert_equal "/except/clubs", except_clubs_path - get '/except/clubs/1/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_except_club_path(:id => '1') } + get "/except/clubs/1/edit" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { edit_except_club_path(id: "1") } - get '/except/clubs/1/players' - assert_equal 'except/players#index', @response.body - assert_equal '/except/clubs/1/players', except_club_players_path(:club_id => '1') + get "/except/clubs/1/players" + assert_equal "except/players#index", @response.body + assert_equal "/except/clubs/1/players", except_club_players_path(club_id: "1") - get '/except/clubs/1/players/2/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_except_club_player_path(:club_id => '1', :id => '2') } + get "/except/clubs/1/players/2/edit" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { edit_except_club_player_path(club_id: "1", id: "2") } - get '/except/clubs/1/chairman' - assert_equal 'except/chairmen#show', @response.body - assert_equal '/except/clubs/1/chairman', except_club_chairman_path(:club_id => '1') + get "/except/clubs/1/chairman" + assert_equal "except/chairmen#show", @response.body + assert_equal "/except/clubs/1/chairman", except_club_chairman_path(club_id: "1") - get '/except/clubs/1/chairman/edit' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_except_club_chairman_path(:club_id => '1') } + get "/except/clubs/1/chairman/edit" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { edit_except_club_chairman_path(club_id: "1") } end def test_only_option_should_override_scope draw do - scope :only => :show do + scope only: :show do namespace :only do - resources :sectors, :only => :index + resources :sectors, only: :index end end end - get '/only/sectors' - assert_equal 'only/sectors#index', @response.body - assert_equal '/only/sectors', only_sectors_path + get "/only/sectors" + assert_equal "only/sectors#index", @response.body + assert_equal "/only/sectors", only_sectors_path - get '/only/sectors/1' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_path(:id => '1') } + get "/only/sectors/1" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { only_sector_path(id: "1") } end def test_only_option_should_not_inherit draw do - scope :only => :show do + scope only: :show do namespace :only do - resources :sectors, :only => :index do + resources :sectors, only: :index do resources :companies resource :leader end @@ -2663,38 +2701,38 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/only/sectors/1/companies/2' - assert_equal 'only/companies#show', @response.body - assert_equal '/only/sectors/1/companies/2', only_sector_company_path(:sector_id => '1', :id => '2') + get "/only/sectors/1/companies/2" + assert_equal "only/companies#show", @response.body + assert_equal "/only/sectors/1/companies/2", only_sector_company_path(sector_id: "1", id: "2") - get '/only/sectors/1/leader' - assert_equal 'only/leaders#show', @response.body - assert_equal '/only/sectors/1/leader', only_sector_leader_path(:sector_id => '1') + get "/only/sectors/1/leader" + assert_equal "only/leaders#show", @response.body + assert_equal "/only/sectors/1/leader", only_sector_leader_path(sector_id: "1") end def test_except_option_should_override_scope draw do - scope :except => :index do + scope except: :index do namespace :except do - resources :sectors, :except => [:show, :update, :destroy] + resources :sectors, except: [:show, :update, :destroy] end end end - get '/except/sectors' - assert_equal 'except/sectors#index', @response.body - assert_equal '/except/sectors', except_sectors_path + get "/except/sectors" + assert_equal "except/sectors#index", @response.body + assert_equal "/except/sectors", except_sectors_path - get '/except/sectors/1' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_path(:id => '1') } + get "/except/sectors/1" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { except_sector_path(id: "1") } end def test_except_option_should_not_inherit draw do - scope :except => :index do + scope except: :index do namespace :except do - resources :sectors, :except => [:show, :update, :destroy] do + resources :sectors, except: [:show, :update, :destroy] do resources :companies resource :leader end @@ -2702,62 +2740,62 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/except/sectors/1/companies/2' - assert_equal 'except/companies#show', @response.body - assert_equal '/except/sectors/1/companies/2', except_sector_company_path(:sector_id => '1', :id => '2') + get "/except/sectors/1/companies/2" + assert_equal "except/companies#show", @response.body + assert_equal "/except/sectors/1/companies/2", except_sector_company_path(sector_id: "1", id: "2") - get '/except/sectors/1/leader' - assert_equal 'except/leaders#show', @response.body - assert_equal '/except/sectors/1/leader', except_sector_leader_path(:sector_id => '1') + get "/except/sectors/1/leader" + assert_equal "except/leaders#show", @response.body + assert_equal "/except/sectors/1/leader", except_sector_leader_path(sector_id: "1") end def test_except_option_should_override_scoped_only draw do - scope :only => :show do + scope only: :show do namespace :only do - resources :sectors, :only => :index do - resources :managers, :except => [:show, :update, :destroy] + resources :sectors, only: :index do + resources :managers, except: [:show, :update, :destroy] end end end end - get '/only/sectors/1/managers' - assert_equal 'only/managers#index', @response.body - assert_equal '/only/sectors/1/managers', only_sector_managers_path(:sector_id => '1') + get "/only/sectors/1/managers" + assert_equal "only/managers#index", @response.body + assert_equal "/only/sectors/1/managers", only_sector_managers_path(sector_id: "1") - get '/only/sectors/1/managers/2' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_manager_path(:sector_id => '1', :id => '2') } + get "/only/sectors/1/managers/2" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { only_sector_manager_path(sector_id: "1", id: "2") } end def test_only_option_should_override_scoped_except draw do - scope :except => :index do + scope except: :index do namespace :except do - resources :sectors, :except => [:show, :update, :destroy] do - resources :managers, :only => :index + resources :sectors, except: [:show, :update, :destroy] do + resources :managers, only: :index end end end end - get '/except/sectors/1/managers' - assert_equal 'except/managers#index', @response.body - assert_equal '/except/sectors/1/managers', except_sector_managers_path(:sector_id => '1') + get "/except/sectors/1/managers" + assert_equal "except/managers#index", @response.body + assert_equal "/except/sectors/1/managers", except_sector_managers_path(sector_id: "1") - get '/except/sectors/1/managers/2' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_manager_path(:sector_id => '1', :id => '2') } + get "/except/sectors/1/managers/2" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { except_sector_manager_path(sector_id: "1", id: "2") } end def test_only_scope_should_override_parent_scope draw do - scope :only => :show do + scope only: :show do namespace :only do - resources :sectors, :only => :index do + resources :sectors, only: :index do resources :companies do - scope :only => :index do + scope only: :index do resources :divisions end end @@ -2766,22 +2804,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/only/sectors/1/companies/2/divisions' - assert_equal 'only/divisions#index', @response.body - assert_equal '/only/sectors/1/companies/2/divisions', only_sector_company_divisions_path(:sector_id => '1', :company_id => '2') + get "/only/sectors/1/companies/2/divisions" + assert_equal "only/divisions#index", @response.body + assert_equal "/only/sectors/1/companies/2/divisions", only_sector_company_divisions_path(sector_id: "1", company_id: "2") - get '/only/sectors/1/companies/2/divisions/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } + get "/only/sectors/1/companies/2/divisions/3" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { only_sector_company_division_path(sector_id: "1", company_id: "2", id: "3") } end def test_except_scope_should_override_parent_scope draw do - scope :except => :index do + scope except: :index do namespace :except do - resources :sectors, :except => [:show, :update, :destroy] do + resources :sectors, except: [:show, :update, :destroy] do resources :companies do - scope :except => [:show, :update, :destroy] do + scope except: [:show, :update, :destroy] do resources :divisions end end @@ -2790,22 +2828,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/except/sectors/1/companies/2/divisions' - assert_equal 'except/divisions#index', @response.body - assert_equal '/except/sectors/1/companies/2/divisions', except_sector_company_divisions_path(:sector_id => '1', :company_id => '2') + get "/except/sectors/1/companies/2/divisions" + assert_equal "except/divisions#index", @response.body + assert_equal "/except/sectors/1/companies/2/divisions", except_sector_company_divisions_path(sector_id: "1", company_id: "2") - get '/except/sectors/1/companies/2/divisions/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } + get "/except/sectors/1/companies/2/divisions/3" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { except_sector_company_division_path(sector_id: "1", company_id: "2", id: "3") } end def test_except_scope_should_override_parent_only_scope draw do - scope :only => :show do + scope only: :show do namespace :only do - resources :sectors, :only => :index do + resources :sectors, only: :index do resources :companies do - scope :except => [:show, :update, :destroy] do + scope except: [:show, :update, :destroy] do resources :departments end end @@ -2814,22 +2852,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/only/sectors/1/companies/2/departments' - assert_equal 'only/departments#index', @response.body - assert_equal '/only/sectors/1/companies/2/departments', only_sector_company_departments_path(:sector_id => '1', :company_id => '2') + get "/only/sectors/1/companies/2/departments" + assert_equal "only/departments#index", @response.body + assert_equal "/only/sectors/1/companies/2/departments", only_sector_company_departments_path(sector_id: "1", company_id: "2") - get '/only/sectors/1/companies/2/departments/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { only_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } + get "/only/sectors/1/companies/2/departments/3" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { only_sector_company_department_path(sector_id: "1", company_id: "2", id: "3") } end def test_only_scope_should_override_parent_except_scope draw do - scope :except => :index do + scope except: :index do namespace :except do - resources :sectors, :except => [:show, :update, :destroy] do + resources :sectors, except: [:show, :update, :destroy] do resources :companies do - scope :only => :index do + scope only: :index do resources :departments end end @@ -2838,13 +2876,13 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/except/sectors/1/companies/2/departments' - assert_equal 'except/departments#index', @response.body - assert_equal '/except/sectors/1/companies/2/departments', except_sector_company_departments_path(:sector_id => '1', :company_id => '2') + get "/except/sectors/1/companies/2/departments" + assert_equal "except/departments#index", @response.body + assert_equal "/except/sectors/1/companies/2/departments", except_sector_company_departments_path(sector_id: "1", company_id: "2") - get '/except/sectors/1/companies/2/departments/3' - assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { except_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } + get "/except/sectors/1/companies/2/departments/3" + assert_equal "Not Found", @response.body + assert_raise(NoMethodError) { except_sector_company_department_path(sector_id: "1", company_id: "2", id: "3") } end def test_resources_are_not_pluralized @@ -2854,30 +2892,30 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/transport/taxis' - assert_equal 'transport/taxis#index', @response.body - assert_equal '/transport/taxis', transport_taxis_path + get "/transport/taxis" + assert_equal "transport/taxis#index", @response.body + assert_equal "/transport/taxis", transport_taxis_path - get '/transport/taxis/new' - assert_equal 'transport/taxis#new', @response.body - assert_equal '/transport/taxis/new', new_transport_taxi_path + get "/transport/taxis/new" + assert_equal "transport/taxis#new", @response.body + assert_equal "/transport/taxis/new", new_transport_taxi_path - post '/transport/taxis' - assert_equal 'transport/taxis#create', @response.body + post "/transport/taxis" + assert_equal "transport/taxis#create", @response.body - get '/transport/taxis/1' - assert_equal 'transport/taxis#show', @response.body - assert_equal '/transport/taxis/1', transport_taxi_path(:id => '1') + get "/transport/taxis/1" + assert_equal "transport/taxis#show", @response.body + assert_equal "/transport/taxis/1", transport_taxi_path(id: "1") - get '/transport/taxis/1/edit' - assert_equal 'transport/taxis#edit', @response.body - assert_equal '/transport/taxis/1/edit', edit_transport_taxi_path(:id => '1') + get "/transport/taxis/1/edit" + assert_equal "transport/taxis#edit", @response.body + assert_equal "/transport/taxis/1/edit", edit_transport_taxi_path(id: "1") - put '/transport/taxis/1' - assert_equal 'transport/taxis#update', @response.body + put "/transport/taxis/1" + assert_equal "transport/taxis#update", @response.body - delete '/transport/taxis/1' - assert_equal 'transport/taxis#destroy', @response.body + delete "/transport/taxis/1" + assert_equal "transport/taxis#destroy", @response.body end def test_singleton_resources_are_not_singularized @@ -2887,169 +2925,169 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/medical/taxis/new' - assert_equal 'medical/taxis#new', @response.body - assert_equal '/medical/taxis/new', new_medical_taxis_path + get "/medical/taxis/new" + assert_equal "medical/taxis#new", @response.body + assert_equal "/medical/taxis/new", new_medical_taxis_path - post '/medical/taxis' - assert_equal 'medical/taxis#create', @response.body + post "/medical/taxis" + assert_equal "medical/taxis#create", @response.body - get '/medical/taxis' - assert_equal 'medical/taxis#show', @response.body - assert_equal '/medical/taxis', medical_taxis_path + get "/medical/taxis" + assert_equal "medical/taxis#show", @response.body + assert_equal "/medical/taxis", medical_taxis_path - get '/medical/taxis/edit' - assert_equal 'medical/taxis#edit', @response.body - assert_equal '/medical/taxis/edit', edit_medical_taxis_path + get "/medical/taxis/edit" + assert_equal "medical/taxis#edit", @response.body + assert_equal "/medical/taxis/edit", edit_medical_taxis_path - put '/medical/taxis' - assert_equal 'medical/taxis#update', @response.body + put "/medical/taxis" + assert_equal "medical/taxis#update", @response.body - delete '/medical/taxis' - assert_equal 'medical/taxis#destroy', @response.body + delete "/medical/taxis" + assert_equal "medical/taxis#destroy", @response.body end def test_greedy_resource_id_regexp_doesnt_match_edit_and_custom_action draw do - resources :sections, :id => /.+/ do - get :preview, :on => :member + resources :sections, id: /.+/ do + get :preview, on: :member end end - get '/sections/1/edit' - assert_equal 'sections#edit', @response.body - assert_equal '/sections/1/edit', edit_section_path(:id => '1') + get "/sections/1/edit" + assert_equal "sections#edit", @response.body + assert_equal "/sections/1/edit", edit_section_path(id: "1") - get '/sections/1/preview' - assert_equal 'sections#preview', @response.body - assert_equal '/sections/1/preview', preview_section_path(:id => '1') + get "/sections/1/preview" + assert_equal "sections#preview", @response.body + assert_equal "/sections/1/preview", preview_section_path(id: "1") end def test_resource_constraints_are_pushed_to_scope draw do namespace :wiki do - resources :articles, :id => /[^\/]+/ do - resources :comments, :only => [:create, :new] + resources :articles, id: /[^\/]+/ do + resources :comments, only: [:create, :new] end end end - get '/wiki/articles/Ruby_on_Rails_3.0' - assert_equal 'wiki/articles#show', @response.body - assert_equal '/wiki/articles/Ruby_on_Rails_3.0', wiki_article_path(:id => 'Ruby_on_Rails_3.0') + get "/wiki/articles/Ruby_on_Rails_3.0" + assert_equal "wiki/articles#show", @response.body + assert_equal "/wiki/articles/Ruby_on_Rails_3.0", wiki_article_path(id: "Ruby_on_Rails_3.0") - get '/wiki/articles/Ruby_on_Rails_3.0/comments/new' - assert_equal 'wiki/comments#new', @response.body - assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments/new', new_wiki_article_comment_path(:article_id => 'Ruby_on_Rails_3.0') + get "/wiki/articles/Ruby_on_Rails_3.0/comments/new" + assert_equal "wiki/comments#new", @response.body + assert_equal "/wiki/articles/Ruby_on_Rails_3.0/comments/new", new_wiki_article_comment_path(article_id: "Ruby_on_Rails_3.0") - post '/wiki/articles/Ruby_on_Rails_3.0/comments' - assert_equal 'wiki/comments#create', @response.body - assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments', wiki_article_comments_path(:article_id => 'Ruby_on_Rails_3.0') + post "/wiki/articles/Ruby_on_Rails_3.0/comments" + assert_equal "wiki/comments#create", @response.body + assert_equal "/wiki/articles/Ruby_on_Rails_3.0/comments", wiki_article_comments_path(article_id: "Ruby_on_Rails_3.0") end def test_resources_path_can_be_a_symbol draw do - resources :wiki_pages, :path => :pages - resource :wiki_account, :path => :my_account + resources :wiki_pages, path: :pages + resource :wiki_account, path: :my_account end - get '/pages' - assert_equal 'wiki_pages#index', @response.body - assert_equal '/pages', wiki_pages_path + get "/pages" + assert_equal "wiki_pages#index", @response.body + assert_equal "/pages", wiki_pages_path - get '/pages/Ruby_on_Rails' - assert_equal 'wiki_pages#show', @response.body - assert_equal '/pages/Ruby_on_Rails', wiki_page_path(:id => 'Ruby_on_Rails') + get "/pages/Ruby_on_Rails" + assert_equal "wiki_pages#show", @response.body + assert_equal "/pages/Ruby_on_Rails", wiki_page_path(id: "Ruby_on_Rails") - get '/my_account' - assert_equal 'wiki_accounts#show', @response.body - assert_equal '/my_account', wiki_account_path + get "/my_account" + assert_equal "wiki_accounts#show", @response.body + assert_equal "/my_account", wiki_account_path end def test_redirect_https draw do - get 'secure', :to => redirect("/secure/login") + get "secure", to: redirect("/secure/login") end with_https do - get '/secure' - verify_redirect 'https://www.example.com/secure/login' + get "/secure" + verify_redirect "https://www.example.com/secure/login" end end def test_path_parameters_is_not_stale draw do - scope '/countries/:country', :constraints => lambda { |params, req| %w(all France).include?(params[:country]) } do - get '/', :to => 'countries#index' - get '/cities', :to => 'countries#cities' + scope "/countries/:country", constraints: lambda { |params, req| %w(all France).include?(params[:country]) } do + get "/", to: "countries#index" + get "/cities", to: "countries#cities" end - get '/countries/:country/(*other)', :to => redirect{ |params, req| params[:other] ? "/countries/all/#{params[:other]}" : '/countries/all' } + get "/countries/:country/(*other)", to: redirect { |params, req| params[:other] ? "/countries/all/#{params[:other]}" : "/countries/all" } end - get '/countries/France' - assert_equal 'countries#index', @response.body + get "/countries/France" + assert_equal "countries#index", @response.body - get '/countries/France/cities' - assert_equal 'countries#cities', @response.body + get "/countries/France/cities" + assert_equal "countries#cities", @response.body - get '/countries/UK' - verify_redirect 'http://www.example.com/countries/all' + get "/countries/UK" + verify_redirect "http://www.example.com/countries/all" - get '/countries/UK/cities' - verify_redirect 'http://www.example.com/countries/all/cities' + get "/countries/UK/cities" + verify_redirect "http://www.example.com/countries/all/cities" end def test_constraints_block_not_carried_to_following_routes draw do - scope '/italians' do - get '/writers', :to => 'italians#writers', :constraints => ::TestRoutingMapper::IpRestrictor - get '/sculptors', :to => 'italians#sculptors' - get '/painters/:painter', :to => 'italians#painters', :constraints => {:painter => /michelangelo/} + scope "/italians" do + get "/writers", to: "italians#writers", constraints: ::TestRoutingMapper::IpRestrictor + get "/sculptors", to: "italians#sculptors" + get "/painters/:painter", to: "italians#painters", constraints: { painter: /michelangelo/ } end end - get '/italians/writers' - assert_equal 'Not Found', @response.body + get "/italians/writers" + assert_equal "Not Found", @response.body - get '/italians/sculptors' - assert_equal 'italians#sculptors', @response.body + get "/italians/sculptors" + assert_equal "italians#sculptors", @response.body - get '/italians/painters/botticelli' - assert_equal 'Not Found', @response.body + get "/italians/painters/botticelli" + assert_equal "Not Found", @response.body - get '/italians/painters/michelangelo' - assert_equal 'italians#painters', @response.body + get "/italians/painters/michelangelo" + assert_equal "italians#painters", @response.body end def test_custom_resource_actions_defined_using_string draw do resources :customers do resources :invoices do - get "aged/:months", :on => :collection, :action => :aged, :as => :aged + get "aged/:months", on: :collection, action: :aged, as: :aged end - get "inactive", :on => :collection - post "deactivate", :on => :member - get "old", :on => :collection, :as => :stale + get "inactive", on: :collection + post "deactivate", on: :member + get "old", on: :collection, as: :stale end end - get '/customers/inactive' - assert_equal 'customers#inactive', @response.body - assert_equal '/customers/inactive', inactive_customers_path + get "/customers/inactive" + assert_equal "customers#inactive", @response.body + assert_equal "/customers/inactive", inactive_customers_path - post '/customers/1/deactivate' - assert_equal 'customers#deactivate', @response.body - assert_equal '/customers/1/deactivate', deactivate_customer_path(:id => '1') + post "/customers/1/deactivate" + assert_equal "customers#deactivate", @response.body + assert_equal "/customers/1/deactivate", deactivate_customer_path(id: "1") - get '/customers/old' - assert_equal 'customers#old', @response.body - assert_equal '/customers/old', stale_customers_path + get "/customers/old" + assert_equal "customers#old", @response.body + assert_equal "/customers/old", stale_customers_path - get '/customers/1/invoices/aged/3' - assert_equal 'invoices#aged', @response.body - assert_equal '/customers/1/invoices/aged/3', aged_customer_invoices_path(:customer_id => '1', :months => '3') + get "/customers/1/invoices/aged/3" + assert_equal "invoices#aged", @response.body + assert_equal "/customers/1/invoices/aged/3", aged_customer_invoices_path(customer_id: "1", months: "3") end def test_route_defined_in_resources_scope_level @@ -3059,43 +3097,43 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/customers/1/export' - assert_equal 'customers#export', @response.body - assert_equal '/customers/1/export', customer_export_path(:customer_id => '1') + get "/customers/1/export" + assert_equal "customers#export", @response.body + assert_equal "/customers/1/export", customer_export_path(customer_id: "1") end def test_named_character_classes_in_regexp_constraints draw do - get '/purchases/:token/:filename', - :to => 'purchases#fetch', - :token => /[[:alnum:]]{10}/, - :filename => /(.+)/, - :as => :purchase + get "/purchases/:token/:filename", + to: "purchases#fetch", + token: /[[:alnum:]]{10}/, + filename: /(.+)/, + as: :purchase end - get '/purchases/315004be7e/Ruby_on_Rails_3.pdf' - assert_equal 'purchases#fetch', @response.body - assert_equal '/purchases/315004be7e/Ruby_on_Rails_3.pdf', purchase_path(:token => '315004be7e', :filename => 'Ruby_on_Rails_3.pdf') + get "/purchases/315004be7e/Ruby_on_Rails_3.pdf" + assert_equal "purchases#fetch", @response.body + assert_equal "/purchases/315004be7e/Ruby_on_Rails_3.pdf", purchase_path(token: "315004be7e", filename: "Ruby_on_Rails_3.pdf") end def test_nested_resource_constraints draw do - resources :lists, :id => /([A-Za-z0-9]{25})|default/ do - resources :todos, :id => /\d+/ + resources :lists, id: /([A-Za-z0-9]{25})|default/ do + resources :todos, id: /\d+/ end end - get '/lists/01234012340123401234fffff' - assert_equal 'lists#show', @response.body - assert_equal '/lists/01234012340123401234fffff', list_path(:id => '01234012340123401234fffff') + get "/lists/01234012340123401234fffff" + assert_equal "lists#show", @response.body + assert_equal "/lists/01234012340123401234fffff", list_path(id: "01234012340123401234fffff") - get '/lists/01234012340123401234fffff/todos/1' - assert_equal 'todos#show', @response.body - assert_equal '/lists/01234012340123401234fffff/todos/1', list_todo_path(:list_id => '01234012340123401234fffff', :id => '1') + get "/lists/01234012340123401234fffff/todos/1" + assert_equal "todos#show", @response.body + assert_equal "/lists/01234012340123401234fffff/todos/1", list_todo_path(list_id: "01234012340123401234fffff", id: "1") - get '/lists/2/todos/1' - assert_equal 'Not Found', @response.body - assert_raises(ActionController::UrlGenerationError){ list_todo_path(:list_id => '2', :id => '1') } + get "/lists/2/todos/1" + assert_equal "Not Found", @response.body + assert_raises(ActionController::UrlGenerationError) { list_todo_path(list_id: "2", id: "1") } end def test_redirect_argument_error @@ -3118,10 +3156,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_explicitly_avoiding_the_named_route draw do - scope :as => "routes" do - get "/c/:id", :as => :collision, :to => "collision#show" - get "/collision", :to => "collision#show" - get "/no_collision", :to => "collision#show", :as => nil + scope as: "routes" do + get "/c/:id", as: :collision, to: "collision#show" + get "/collision", to: "collision#show" + get "/no_collision", to: "collision#show", as: nil end end @@ -3130,49 +3168,49 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_controller_name_with_leading_slash_raise_error assert_raise(ArgumentError) do - draw { get '/feeds/:service', :to => '/feeds#show' } + draw { get "/feeds/:service", to: "/feeds#show" } end assert_raise(ArgumentError) do - draw { get '/feeds/:service', :controller => '/feeds', :action => 'show' } + draw { get "/feeds/:service", controller: "/feeds", action: "show" } end assert_raise(ArgumentError) do - draw { get '/api/feeds/:service', :to => '/api/feeds#show' } + draw { get "/api/feeds/:service", to: "/api/feeds#show" } end assert_raise(ArgumentError) do - draw { resources :feeds, :controller => '/feeds' } + draw { resources :feeds, controller: "/feeds" } end end def test_invalid_route_name_raises_error assert_raise(ArgumentError) do - draw { get '/products', :to => 'products#index', :as => 'products ' } + draw { get "/products", to: "products#index", as: "products " } end assert_raise(ArgumentError) do - draw { get '/products', :to => 'products#index', :as => ' products' } + draw { get "/products", to: "products#index", as: " products" } end assert_raise(ArgumentError) do - draw { get '/products', :to => 'products#index', :as => 'products!' } + draw { get "/products", to: "products#index", as: "products!" } end assert_raise(ArgumentError) do - draw { get '/products', :to => 'products#index', :as => 'products index' } + draw { get "/products", to: "products#index", as: "products index" } end assert_raise(ArgumentError) do - draw { get '/products', :to => 'products#index', :as => '1products' } + draw { get "/products", to: "products#index", as: "1products" } end end def test_duplicate_route_name_raises_error assert_raise(ArgumentError) do draw do - get '/collision', :to => 'collision#show', :as => 'collision' - get '/duplicate', :to => 'duplicate#show', :as => 'collision' + get "/collision", to: "collision#show", as: "collision" + get "/duplicate", to: "duplicate#show", as: "collision" end end end @@ -3181,15 +3219,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_raise(ArgumentError) do draw do resources :collisions - get '/collision', :to => 'collision#show', :as => 'collision' + get "/collision", to: "collision#show", as: "collision" end end end def test_nested_route_in_nested_resource draw do - resources :posts, :only => [:index, :show] do - resources :comments, :except => :destroy do + resources :posts, only: [:index, :show] do + resources :comments, except: :destroy do get "views" => "comments#views", :as => :views end end @@ -3197,124 +3235,124 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "/posts/1/comments/2/views" assert_equal "comments#views", @response.body - assert_equal "/posts/1/comments/2/views", post_comment_views_path(:post_id => '1', :comment_id => '2') + assert_equal "/posts/1/comments/2/views", post_comment_views_path(post_id: "1", comment_id: "2") end def test_root_in_deeply_nested_scope draw do - resources :posts, :only => [:index, :show] do + resources :posts, only: [:index, :show] do namespace :admin do - root :to => "index#index" + root to: "index#index" end end end get "/posts/1/admin" assert_equal "admin/index#index", @response.body - assert_equal "/posts/1/admin", post_admin_root_path(:post_id => '1') + assert_equal "/posts/1/admin", post_admin_root_path(post_id: "1") end def test_custom_param draw do - resources :profiles, :param => :username do - get :details, :on => :member + resources :profiles, param: :username do + get :details, on: :member resources :messages end end - get '/profiles/bob' - assert_equal 'profiles#show', @response.body - assert_equal 'bob', @request.params[:username] + get "/profiles/bob" + assert_equal "profiles#show", @response.body + assert_equal "bob", @request.params[:username] - get '/profiles/bob/details' - assert_equal 'bob', @request.params[:username] + get "/profiles/bob/details" + assert_equal "bob", @request.params[:username] - get '/profiles/bob/messages/34' - assert_equal 'bob', @request.params[:profile_username] - assert_equal '34', @request.params[:id] + get "/profiles/bob/messages/34" + assert_equal "bob", @request.params[:profile_username] + assert_equal "34", @request.params[:id] end def test_custom_param_constraint draw do - resources :profiles, :param => :username, :username => /[a-z]+/ do - get :details, :on => :member + resources :profiles, param: :username, username: /[a-z]+/ do + get :details, on: :member resources :messages end end - get '/profiles/bob1' + get "/profiles/bob1" assert_equal 404, @response.status - get '/profiles/bob1/details' + get "/profiles/bob1/details" assert_equal 404, @response.status - get '/profiles/bob1/messages/34' + get "/profiles/bob1/messages/34" assert_equal 404, @response.status end def test_shallow_custom_param draw do resources :orders do - constraints :download => /[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}/ do - resources :downloads, :param => :download, :shallow => true + constraints download: /[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}/ do + resources :downloads, param: :download, shallow: true end end end - get '/downloads/0c0c0b68-d24b-11e1-a861-001ff3fffe6f.zip' - assert_equal 'downloads#show', @response.body - assert_equal '0c0c0b68-d24b-11e1-a861-001ff3fffe6f', @request.params[:download] + get "/downloads/0c0c0b68-d24b-11e1-a861-001ff3fffe6f.zip" + assert_equal "downloads#show", @response.body + assert_equal "0c0c0b68-d24b-11e1-a861-001ff3fffe6f", @request.params[:download] end def test_action_from_path_is_not_frozen draw do - get 'search' => 'search' + get "search" => "search" end - get '/search' + get "/search" assert !@request.params[:action].frozen? end def test_multiple_positional_args_with_the_same_name draw do - get '/downloads/:id/:id.tar' => 'downloads#show', as: :download, format: false + get "/downloads/:id/:id.tar" => "downloads#show", as: :download, format: false end expected_params = { - controller: 'downloads', - action: 'show', - id: '1' + controller: "downloads", + action: "show", + id: "1" } - get '/downloads/1/1.tar' - assert_equal 'downloads#show', @response.body + get "/downloads/1/1.tar" + assert_equal "downloads#show", @response.body assert_equal expected_params, @request.path_parameters - assert_equal '/downloads/1/1.tar', download_path('1') - assert_equal '/downloads/1/1.tar', download_path('1', '1') + assert_equal "/downloads/1/1.tar", download_path("1") + assert_equal "/downloads/1/1.tar", download_path("1", "1") end def test_absolute_controller_namespace draw do namespace :foo do - get '/', to: '/bar#index', as: 'root' + get "/", to: "/bar#index", as: "root" end end - get '/foo' - assert_equal 'bar#index', @response.body - assert_equal '/foo', foo_root_path + get "/foo" + assert_equal "bar#index", @response.body + assert_equal "/foo", foo_root_path end def test_namespace_as_controller draw do namespace :foo do - get '/', to: '/bar#index', as: 'root' + get "/", to: "/bar#index", as: "root" end end - get '/foo' - assert_equal 'bar#index', @response.body - assert_equal '/foo', foo_root_path + get "/foo" + assert_equal "bar#index", @response.body + assert_equal "/foo", foo_root_path end def test_trailing_slash @@ -3322,63 +3360,63 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :streams end - get '/streams' - assert @response.ok?, 'route without trailing slash should work' + get "/streams" + assert @response.ok?, "route without trailing slash should work" - get '/streams/' - assert @response.ok?, 'route with trailing slash should work' + get "/streams/" + assert @response.ok?, "route with trailing slash should work" - get '/streams?foobar' - assert @response.ok?, 'route without trailing slash and with QUERY_STRING should work' + get "/streams?foobar" + assert @response.ok?, "route without trailing slash and with QUERY_STRING should work" - get '/streams/?foobar' - assert @response.ok?, 'route with trailing slash and with QUERY_STRING should work' + get "/streams/?foobar" + assert @response.ok?, "route with trailing slash and with QUERY_STRING should work" end def test_route_with_dashes_in_path draw do - get '/contact-us', to: 'pages#contact_us' + get "/contact-us", to: "pages#contact_us" end - get '/contact-us' - assert_equal 'pages#contact_us', @response.body - assert_equal '/contact-us', contact_us_path + get "/contact-us" + assert_equal "pages#contact_us", @response.body + assert_equal "/contact-us", contact_us_path end def test_shorthand_route_with_dashes_in_path draw do - get '/about-us/index' + get "/about-us/index" end - get '/about-us/index' - assert_equal 'about_us#index', @response.body - assert_equal '/about-us/index', about_us_index_path + get "/about-us/index" + assert_equal "about_us#index", @response.body + assert_equal "/about-us/index", about_us_index_path end def test_resource_routes_with_dashes_in_path draw do resources :photos, only: [:show] do - get 'user-favorites', on: :collection - get 'preview-photo', on: :member - get 'summary-text' + get "user-favorites", on: :collection + get "preview-photo", on: :member + get "summary-text" end end - get '/photos/user-favorites' - assert_equal 'photos#user_favorites', @response.body - assert_equal '/photos/user-favorites', user_favorites_photos_path + get "/photos/user-favorites" + assert_equal "photos#user_favorites", @response.body + assert_equal "/photos/user-favorites", user_favorites_photos_path - get '/photos/1/preview-photo' - assert_equal 'photos#preview_photo', @response.body - assert_equal '/photos/1/preview-photo', preview_photo_photo_path('1') + get "/photos/1/preview-photo" + assert_equal "photos#preview_photo", @response.body + assert_equal "/photos/1/preview-photo", preview_photo_photo_path("1") - get '/photos/1/summary-text' - assert_equal 'photos#summary_text', @response.body - assert_equal '/photos/1/summary-text', photo_summary_text_path('1') + get "/photos/1/summary-text" + assert_equal "photos#summary_text", @response.body + assert_equal "/photos/1/summary-text", photo_summary_text_path("1") - get '/photos/1' - assert_equal 'photos#show', @response.body - assert_equal '/photos/1', photo_path('1') + get "/photos/1" + assert_equal "photos#show", @response.body + assert_equal "/photos/1", photo_path("1") end def test_shallow_path_inside_namespace_is_not_added_twice @@ -3392,208 +3430,208 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - get '/admin/posts/1/comments' - assert_equal 'admin/comments#index', @response.body - assert_equal '/admin/posts/1/comments', admin_post_comments_path('1') + get "/admin/posts/1/comments" + assert_equal "admin/comments#index", @response.body + assert_equal "/admin/posts/1/comments", admin_post_comments_path("1") end def test_mix_string_to_controller_action draw do - get '/projects', controller: 'project_files', - action: 'index', - to: 'comments#index' + get "/projects", controller: "project_files", + action: "index", + to: "comments#index" end - get '/projects' - assert_equal 'comments#index', @response.body + get "/projects" + assert_equal "comments#index", @response.body end def test_mix_string_to_controller draw do - get '/projects', controller: 'project_files', - to: 'comments#index' + get "/projects", controller: "project_files", + to: "comments#index" end - get '/projects' - assert_equal 'comments#index', @response.body + get "/projects" + assert_equal "comments#index", @response.body end def test_mix_string_to_action draw do - get '/projects', action: 'index', - to: 'comments#index' + get "/projects", action: "index", + to: "comments#index" end - get '/projects' - assert_equal 'comments#index', @response.body + get "/projects" + assert_equal "comments#index", @response.body end def test_shallow_path_and_prefix_are_not_added_to_non_shallow_routes draw do - scope shallow_path: 'projects', shallow_prefix: 'project' do + scope shallow_path: "projects", shallow_prefix: "project" do resources :projects do - resources :files, controller: 'project_files', shallow: true + resources :files, controller: "project_files", shallow: true end end end - get '/projects' - assert_equal 'projects#index', @response.body - assert_equal '/projects', projects_path + get "/projects" + assert_equal "projects#index", @response.body + assert_equal "/projects", projects_path - get '/projects/new' - assert_equal 'projects#new', @response.body - assert_equal '/projects/new', new_project_path + get "/projects/new" + assert_equal "projects#new", @response.body + assert_equal "/projects/new", new_project_path - post '/projects' - assert_equal 'projects#create', @response.body + post "/projects" + assert_equal "projects#create", @response.body - get '/projects/1' - assert_equal 'projects#show', @response.body - assert_equal '/projects/1', project_path('1') + get "/projects/1" + assert_equal "projects#show", @response.body + assert_equal "/projects/1", project_path("1") - get '/projects/1/edit' - assert_equal 'projects#edit', @response.body - assert_equal '/projects/1/edit', edit_project_path('1') + get "/projects/1/edit" + assert_equal "projects#edit", @response.body + assert_equal "/projects/1/edit", edit_project_path("1") - patch '/projects/1' - assert_equal 'projects#update', @response.body + patch "/projects/1" + assert_equal "projects#update", @response.body - delete '/projects/1' - assert_equal 'projects#destroy', @response.body + delete "/projects/1" + assert_equal "projects#destroy", @response.body - get '/projects/1/files' - assert_equal 'project_files#index', @response.body - assert_equal '/projects/1/files', project_files_path('1') + get "/projects/1/files" + assert_equal "project_files#index", @response.body + assert_equal "/projects/1/files", project_files_path("1") - get '/projects/1/files/new' - assert_equal 'project_files#new', @response.body - assert_equal '/projects/1/files/new', new_project_file_path('1') + get "/projects/1/files/new" + assert_equal "project_files#new", @response.body + assert_equal "/projects/1/files/new", new_project_file_path("1") - post '/projects/1/files' - assert_equal 'project_files#create', @response.body + post "/projects/1/files" + assert_equal "project_files#create", @response.body - get '/projects/files/2' - assert_equal 'project_files#show', @response.body - assert_equal '/projects/files/2', project_file_path('2') + get "/projects/files/2" + assert_equal "project_files#show", @response.body + assert_equal "/projects/files/2", project_file_path("2") - get '/projects/files/2/edit' - assert_equal 'project_files#edit', @response.body - assert_equal '/projects/files/2/edit', edit_project_file_path('2') + get "/projects/files/2/edit" + assert_equal "project_files#edit", @response.body + assert_equal "/projects/files/2/edit", edit_project_file_path("2") - patch '/projects/files/2' - assert_equal 'project_files#update', @response.body + patch "/projects/files/2" + assert_equal "project_files#update", @response.body - delete '/projects/files/2' - assert_equal 'project_files#destroy', @response.body + delete "/projects/files/2" + assert_equal "project_files#destroy", @response.body end def test_scope_path_is_copied_to_shallow_path draw do - scope path: 'foo' do + scope path: "foo" do resources :posts do resources :comments, shallow: true end end end - assert_equal '/foo/comments/1', comment_path('1') + assert_equal "/foo/comments/1", comment_path("1") end def test_scope_as_is_copied_to_shallow_prefix draw do - scope as: 'foo' do + scope as: "foo" do resources :posts do resources :comments, shallow: true end end end - assert_equal '/comments/1', foo_comment_path('1') + assert_equal "/comments/1", foo_comment_path("1") end def test_scope_shallow_prefix_is_not_overwritten_by_as draw do - scope as: 'foo', shallow_prefix: 'bar' do + scope as: "foo", shallow_prefix: "bar" do resources :posts do resources :comments, shallow: true end end end - assert_equal '/comments/1', bar_comment_path('1') + assert_equal "/comments/1", bar_comment_path("1") end def test_scope_shallow_path_is_not_overwritten_by_path draw do - scope path: 'foo', shallow_path: 'bar' do + scope path: "foo", shallow_path: "bar" do resources :posts do resources :comments, shallow: true end end end - assert_equal '/bar/comments/1', comment_path('1') + assert_equal "/bar/comments/1", comment_path("1") end def test_resource_where_as_is_empty draw do - resource :post, as: '' + resource :post, as: "" - scope 'post', as: 'post' do - resource :comment, as: '' + scope "post", as: "post" do + resource :comment, as: "" end end - assert_equal '/post/new', new_path - assert_equal '/post/comment/new', new_post_path + assert_equal "/post/new", new_path + assert_equal "/post/comment/new", new_post_path end def test_resources_where_as_is_empty draw do - resources :posts, as: '' + resources :posts, as: "" - scope 'posts', as: 'posts' do - resources :comments, as: '' + scope "posts", as: "posts" do + resources :comments, as: "" end end - assert_equal '/posts/new', new_path - assert_equal '/posts/comments/new', new_posts_path + assert_equal "/posts/new", new_path + assert_equal "/posts/comments/new", new_posts_path end def test_scope_where_as_is_empty draw do - scope 'post', as: '' do + scope "post", as: "" do resource :user resources :comments end end - assert_equal '/post/user/new', new_user_path - assert_equal '/post/comments/new', new_comment_path + assert_equal "/post/user/new", new_user_path + assert_equal "/post/comments/new", new_comment_path end def test_head_fetch_with_mount_on_root draw do - get '/home' => 'test#index' - mount lambda { |env| [200, {}, [env['REQUEST_METHOD']]] }, at: '/' + get "/home" => "test#index" + mount lambda { |env| [200, {}, [env["REQUEST_METHOD"]]] }, at: "/" end # HEAD request should match `get /home` rather than the # lower-precedence Rack app mounted at `/`. - head '/home' + head "/home" assert_response :ok - assert_equal 'test#index', @response.body + assert_equal "test#index", @response.body # But the Rack app can still respond to its own HEAD requests. - head '/foobar' + head "/foobar" assert_response :ok - assert_equal 'HEAD', @response.body + assert_equal "HEAD", @response.body end def test_passing_action_parameters_to_url_helpers_raises_error_if_parameters_are_not_permitted draw do - root :to => 'projects#index' + root to: "projects#index" end - params = ActionController::Parameters.new(id: '1') + params = ActionController::Parameters.new(id: "1") assert_raises ArgumentError do root_path(params) @@ -3602,18 +3640,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_passing_action_parameters_to_url_helpers_is_allowed_if_parameters_are_permitted draw do - root :to => 'projects#index' + root to: "projects#index" end - params = ActionController::Parameters.new(id: '1') + params = ActionController::Parameters.new(id: "1") params.permit! - assert_equal '/?id=1', root_path(params) + assert_equal "/?id=1", root_path(params) end def test_dynamic_controller_segments_are_deprecated assert_deprecated do draw do - get '/:controller', action: 'index' + get "/:controller", action: "index" end end end @@ -3621,16 +3659,58 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_dynamic_action_segments_are_deprecated assert_deprecated do draw do - get '/pages/:action', controller: 'pages' + get "/pages/:action", controller: "pages" + end + end + end + + def test_multiple_roots + draw do + namespace :foo do + root "pages#index", constraints: { host: "www.example.com" } + root "admin/pages#index", constraints: { host: "admin.example.com" } + end + + root "pages#index", constraints: { host: "www.example.com" } + root "admin/pages#index", constraints: { host: "admin.example.com" } + end + + get "http://www.example.com/foo" + assert_equal "foo/pages#index", @response.body + + get "http://admin.example.com/foo" + assert_equal "foo/admin/pages#index", @response.body + + get "http://www.example.com/" + assert_equal "pages#index", @response.body + + get "http://admin.example.com/" + assert_equal "admin/pages#index", @response.body + end + + def test_multiple_namespaced_roots + draw do + namespace :foo do + root "test#index" + end + + root "test#index" + + namespace :bar do + root "test#index" end end + + assert_equal "/foo", foo_root_path + assert_equal "/", root_path + assert_equal "/bar", bar_root_path end private def draw(&block) self.class.stub_controllers do |routes| - routes.default_url_options = { host: 'www.example.com' } + routes.default_url_options = { host: "www.example.com" } routes.draw(&block) @app = RoutedRackApp.new routes end @@ -3658,7 +3738,7 @@ private def verify_redirect(url, status=301) assert_equal status, @response.status - assert_equal url, @response.headers['Location'] + assert_equal url, @response.headers["Location"] assert_equal expected_redirect_body(url), @response.body end @@ -3695,13 +3775,13 @@ class TestAltApp < ActionDispatch::IntegrationTest class XHeader def call(env) - [200, {"Content-Type" => "text/html"}, ["XHeader"]] + [200, { "Content-Type" => "text/html" }, ["XHeader"]] end end class AltApp def call(env) - [200, {"Content-Type" => "text/html"}, ["Alternative App"]] + [200, { "Content-Type" => "text/html" }, ["Alternative App"]] end end @@ -3711,7 +3791,7 @@ class TestAltApp < ActionDispatch::IntegrationTest end }.new AltRoutes.draw do - get "/" => TestAltApp::XHeader.new, :constraints => {:x_header => /HEADER/} + get "/" => TestAltApp::XHeader.new, :constraints => { x_header: /HEADER/ } get "/" => TestAltApp::AltApp.new end @@ -3739,7 +3819,7 @@ end class TestAppendingRoutes < ActionDispatch::IntegrationTest def simple_app(resp) - lambda { |e| [ 200, { 'Content-Type' => 'text/plain' }, [resp] ] } + lambda { |e| [ 200, { "Content-Type" => "text/plain" }, [resp] ] } end def setup @@ -3747,28 +3827,28 @@ class TestAppendingRoutes < ActionDispatch::IntegrationTest s = self routes = ActionDispatch::Routing::RouteSet.new routes.append do - get '/hello' => s.simple_app('fail') - get '/goodbye' => s.simple_app('goodbye') + get "/hello" => s.simple_app("fail") + get "/goodbye" => s.simple_app("goodbye") end routes.draw do - get '/hello' => s.simple_app('hello') + get "/hello" => s.simple_app("hello") end @app = self.class.build_app routes end def test_goodbye_should_be_available - get '/goodbye' - assert_equal 'goodbye', @response.body + get "/goodbye" + assert_equal "goodbye", @response.body end def test_hello_should_not_be_overwritten - get '/hello' - assert_equal 'hello', @response.body + get "/hello" + assert_equal "hello", @response.body end def test_missing_routes_are_still_missing - get '/random' + get "/random" assert_equal 404, @response.status end end @@ -3791,7 +3871,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest def test_missing_controller ex = assert_raises(ArgumentError) { draw do - get '/foo/bar', :action => :index + get "/foo/bar", action: :index end } assert_match(/Missing :controller/, ex.message) @@ -3800,7 +3880,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest def test_missing_controller_with_to ex = assert_raises(ArgumentError) { draw do - get '/foo/bar', :to => 'foo' + get "/foo/bar", to: "foo" end } assert_match(/Missing :controller/, ex.message) @@ -3809,7 +3889,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest def test_missing_action_on_hash ex = assert_raises(ArgumentError) { draw do - get '/foo/bar', :to => 'foo#' + get "/foo/bar", to: "foo#" end } assert_match(/Missing :action/, ex.message) @@ -3818,20 +3898,20 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest def test_valid_controller_options_inside_namespace draw do namespace :admin do - resources :storage_files, :controller => "storage_files" + resources :storage_files, controller: "storage_files" end end - get '/admin/storage_files' + get "/admin/storage_files" assert_equal "admin/storage_files#index", @response.body end def test_resources_with_valid_namespaced_controller_option draw do - resources :storage_files, :controller => 'admin/storage_files' + resources :storage_files, controller: "admin/storage_files" end - get '/storage_files' + get "/storage_files" assert_equal "admin/storage_files#index", @response.body end @@ -3839,7 +3919,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest e = assert_raise(ArgumentError) do draw do namespace :admin do - resources :storage_files, :controller => "StorageFiles" + resources :storage_files, controller: "StorageFiles" end end end @@ -3850,7 +3930,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest def test_warn_with_ruby_constant_syntax_namespaced_controller_option e = assert_raise(ArgumentError) do draw do - resources :storage_files, :controller => 'Admin::StorageFiles' + resources :storage_files, controller: "Admin::StorageFiles" end end @@ -3860,7 +3940,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest def test_warn_with_ruby_constant_syntax_no_colons e = assert_raise(ArgumentError) do draw do - resources :storage_files, :controller => 'Admin' + resources :storage_files, controller: "Admin" end end @@ -3878,7 +3958,7 @@ class TestDefaultScope < ActionDispatch::IntegrationTest end DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new - DefaultScopeRoutes.default_scope = {:module => :blog} + DefaultScopeRoutes.default_scope = { module: :blog } DefaultScopeRoutes.draw do resources :posts end @@ -3892,7 +3972,7 @@ class TestDefaultScope < ActionDispatch::IntegrationTest include DefaultScopeRoutes.url_helpers def test_default_scope - get '/posts' + get "/posts" assert_equal "blog/posts#index", @response.body end end @@ -3908,7 +3988,7 @@ class TestHttpMethods < ActionDispatch::IntegrationTest RFC5789 = %w(PATCH) def simple_app(response) - lambda { |env| [ 200, { 'Content-Type' => 'text/plain' }, [response] ] } + lambda { |env| [ 200, { "Content-Type" => "text/plain" }, [response] ] } end attr_reader :app @@ -3920,14 +4000,14 @@ class TestHttpMethods < ActionDispatch::IntegrationTest routes.draw do (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method| - match '/' => s.simple_app(method), :via => method.underscore.to_sym + match "/" => s.simple_app(method), :via => method.underscore.to_sym end end end (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method| test "request method #{method.underscore} can be matched" do - get '/', headers: { 'REQUEST_METHOD' => method } + get "/", headers: { "REQUEST_METHOD" => method } assert_equal method, @response.body end end @@ -3936,14 +4016,14 @@ end class TestUriPathEscaping < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - get '/:segment' => lambda { |env| - path_params = env['action_dispatch.request.path_parameters'] - [200, { 'Content-Type' => 'text/plain' }, [path_params[:segment]]] + get "/:segment" => lambda { |env| + path_params = env["action_dispatch.request.path_parameters"] + [200, { "Content-Type" => "text/plain" }, [path_params[:segment]]] }, :as => :segment - get '/*splat' => lambda { |env| - path_params = env['action_dispatch.request.path_parameters'] - [200, { 'Content-Type' => 'text/plain' }, [path_params[:splat]]] + get "/*splat" => lambda { |env| + path_params = env["action_dispatch.request.path_parameters"] + [200, { "Content-Type" => "text/plain" }, [path_params[:splat]]] }, :as => :splat end end @@ -3952,22 +4032,22 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest APP = build_app Routes def app; APP end - test 'escapes slash in generated path segment' do - assert_equal '/a%20b%2Fc+d', segment_path(:segment => 'a b/c+d') + test "escapes slash in generated path segment" do + assert_equal "/a%20b%2Fc+d", segment_path(segment: "a b/c+d") end - test 'unescapes recognized path segment' do - get '/a%20b%2Fc+d' - assert_equal 'a b/c+d', @response.body + test "unescapes recognized path segment" do + get "/a%20b%2Fc+d" + assert_equal "a b/c+d", @response.body end - test 'does not escape slash in generated path splat' do - assert_equal '/a%20b/c+d', splat_path(:splat => 'a b/c+d') + test "does not escape slash in generated path splat" do + assert_equal "/a%20b/c+d", splat_path(splat: "a b/c+d") end - test 'unescapes recognized path splat' do - get '/a%20b/c+d' - assert_equal 'a b/c+d', @response.body + test "unescapes recognized path splat" do + get "/a%20b/c+d" + assert_equal "a b/c+d", @response.body end end @@ -3975,7 +4055,7 @@ class TestUnicodePaths < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do get "/ã»ã’" => lambda { |env| - [200, { 'Content-Type' => 'text/plain' }, []] + [200, { "Content-Type" => "text/plain" }, []] }, :as => :unicode_path end end @@ -3984,7 +4064,7 @@ class TestUnicodePaths < ActionDispatch::IntegrationTest APP = build_app Routes def app; APP end - test 'recognizes unicode path' do + test "recognizes unicode path" do get "/#{Rack::Utils.escape("ã»ã’")}" assert_equal "200", @response.code end @@ -4008,7 +4088,7 @@ class TestMultipleNestedController < ActionDispatch::IntegrationTest include Routes.url_helpers def index - render :inline => "<%= url_for :controller => '/pooh', :action => 'index' %>" + render inline: "<%= url_for :controller => '/pooh', :action => 'index' %>" end end end @@ -4026,7 +4106,7 @@ end class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } get "/~user" => ok get "/young-and-fine" => ok @@ -4037,25 +4117,24 @@ class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest APP = build_app Routes def app; APP end - test 'recognizes tilde path' do + test "recognizes tilde path" do get "/~user" assert_equal "200", @response.code end - test 'recognizes minus path' do + test "recognizes minus path" do get "/young-and-fine" assert_equal "200", @response.code end - end class TestRedirectInterpolation < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } get "/foo/:id" => redirect("/foo/bar/%{id}") - get "/bar/:id" => redirect(:path => "/foo/bar/%{id}") + get "/bar/:id" => redirect(path: "/foo/bar/%{id}") get "/baz/:id" => redirect("/baz?id=%{id}&foo=?&bar=1#id-%{id}") get "/foo/bar/:id" => ok get "/baz" => ok @@ -4086,7 +4165,7 @@ class TestRedirectInterpolation < ActionDispatch::IntegrationTest private def verify_redirect(url, status=301) assert_equal status, @response.status - assert_equal url, @response.headers['Location'] + assert_equal url, @response.headers["Location"] assert_equal expected_redirect_body(url), @response.body end @@ -4098,9 +4177,9 @@ end class TestConstraintsAccessingParameters < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } - get "/:foo" => ok, :constraints => lambda { |r| r.params[:foo] == 'foo' } + get "/:foo" => ok, :constraints => lambda { |r| r.params[:foo] == "foo" } get "/:bar" => ok end end @@ -4118,9 +4197,9 @@ end class TestGlobRoutingMapper < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } - get "/*id" => redirect("/not_cars"), :constraints => {id: /dummy/} + get "/*id" => redirect("/not_cars"), :constraints => { id: /dummy/ } get "/cars" => ok end end @@ -4132,7 +4211,7 @@ class TestGlobRoutingMapper < ActionDispatch::IntegrationTest def test_glob_constraint get "/dummy" assert_equal "301", @response.code - assert_equal "/not_cars", @response.header['Location'].match('/[^/]+$')[0] + assert_equal "/not_cars", @response.header["Location"].match("/[^/]+$")[0] end def test_glob_constraint_skip_route @@ -4148,17 +4227,17 @@ end class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } - get '/foo' => ok, as: :foo + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } + get "/foo" => ok, as: :foo ActiveSupport::Deprecation.silence do - get '/post(/:action(/:id))' => ok, as: :posts + get "/post(/:action(/:id))" => ok, as: :posts end - get '/:foo/:foo_type/bars/:id' => ok, as: :bar - get '/projects/:id.:format' => ok, as: :project - get '/pages/:id' => ok, as: :page - get '/wiki/*page' => ok, as: :wiki + get "/:foo/:foo_type/bars/:id" => ok, as: :bar + get "/projects/:id.:format" => ok, as: :project + get "/pages/:id" => ok, as: :page + get "/wiki/*page" => ok, as: :wiki end end @@ -4166,51 +4245,51 @@ class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest APP = build_app Routes def app; APP end - test 'enabled when not mounted and default_url_options is empty' do + test "enabled when not mounted and default_url_options is empty" do assert Routes.url_helpers.optimize_routes_generation? end - test 'named route called as singleton method' do - assert_equal '/foo', Routes.url_helpers.foo_path + test "named route called as singleton method" do + assert_equal "/foo", Routes.url_helpers.foo_path end - test 'named route called on included module' do - assert_equal '/foo', foo_path + test "named route called on included module" do + assert_equal "/foo", foo_path end - test 'nested optional segments are removed' do - assert_equal '/post', Routes.url_helpers.posts_path - assert_equal '/post', posts_path + test "nested optional segments are removed" do + assert_equal "/post", Routes.url_helpers.posts_path + assert_equal "/post", posts_path end - test 'segments with same prefix are replaced correctly' do - assert_equal '/foo/baz/bars/1', Routes.url_helpers.bar_path('foo', 'baz', '1') - assert_equal '/foo/baz/bars/1', bar_path('foo', 'baz', '1') + test "segments with same prefix are replaced correctly" do + assert_equal "/foo/baz/bars/1", Routes.url_helpers.bar_path("foo", "baz", "1") + assert_equal "/foo/baz/bars/1", bar_path("foo", "baz", "1") end - test 'segments separated with a period are replaced correctly' do - assert_equal '/projects/1.json', Routes.url_helpers.project_path(1, :json) - assert_equal '/projects/1.json', project_path(1, :json) + test "segments separated with a period are replaced correctly" do + assert_equal "/projects/1.json", Routes.url_helpers.project_path(1, :json) + assert_equal "/projects/1.json", project_path(1, :json) end - test 'segments with question marks are escaped' do - assert_equal '/pages/foo%3Fbar', Routes.url_helpers.page_path('foo?bar') - assert_equal '/pages/foo%3Fbar', page_path('foo?bar') + test "segments with question marks are escaped" do + assert_equal "/pages/foo%3Fbar", Routes.url_helpers.page_path("foo?bar") + assert_equal "/pages/foo%3Fbar", page_path("foo?bar") end - test 'segments with slashes are escaped' do - assert_equal '/pages/foo%2Fbar', Routes.url_helpers.page_path('foo/bar') - assert_equal '/pages/foo%2Fbar', page_path('foo/bar') + test "segments with slashes are escaped" do + assert_equal "/pages/foo%2Fbar", Routes.url_helpers.page_path("foo/bar") + assert_equal "/pages/foo%2Fbar", page_path("foo/bar") end - test 'glob segments with question marks are escaped' do - assert_equal '/wiki/foo%3Fbar', Routes.url_helpers.wiki_path('foo?bar') - assert_equal '/wiki/foo%3Fbar', wiki_path('foo?bar') + test "glob segments with question marks are escaped" do + assert_equal "/wiki/foo%3Fbar", Routes.url_helpers.wiki_path("foo?bar") + assert_equal "/wiki/foo%3Fbar", wiki_path("foo?bar") end - test 'glob segments with slashes are not escaped' do - assert_equal '/wiki/foo/bar', Routes.url_helpers.wiki_path('foo/bar') - assert_equal '/wiki/foo/bar', wiki_path('foo/bar') + test "glob segments with slashes are not escaped" do + assert_equal "/wiki/foo/bar", Routes.url_helpers.wiki_path("foo/bar") + assert_equal "/wiki/foo/bar", wiki_path("foo/bar") end end @@ -4229,9 +4308,9 @@ class TestNamedRouteUrlHelpers < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - scope :module => "test_named_route_url_helpers" do - get "/categories/:id" => 'categories#show', :as => :category - get "/products/:id" => 'products#show', :as => :product + scope module: "test_named_route_url_helpers" do + get "/categories/:id" => "categories#show", :as => :category + get "/products/:id" => "products#show", :as => :product end end end @@ -4253,21 +4332,21 @@ end class TestUrlConstraints < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } - constraints :subdomain => 'admin' do - get '/' => ok, :as => :admin_root + constraints subdomain: "admin" do + get "/" => ok, :as => :admin_root end - scope :constraints => { :protocol => 'https://' } do - get '/' => ok, :as => :secure_root + scope constraints: { protocol: "https://" } do + get "/" => ok, :as => :secure_root end - get '/' => ok, :as => :alternate_root, :constraints => { :port => 8080 } + get "/" => ok, :as => :alternate_root, :constraints => { port: 8080 } - get '/search' => ok, :constraints => { :subdomain => false } + get "/search" => ok, :constraints => { subdomain: false } - get '/logs' => ok, :constraints => { :subdomain => true } + get "/logs" => ok, :constraints => { subdomain: true } end end @@ -4276,41 +4355,41 @@ class TestUrlConstraints < ActionDispatch::IntegrationTest def app; APP end test "constraints are copied to defaults when using constraints method" do - assert_equal 'http://admin.example.com/', admin_root_url + assert_equal "http://admin.example.com/", admin_root_url - get 'http://admin.example.com/' + get "http://admin.example.com/" assert_response :success end test "constraints are copied to defaults when using scope constraints hash" do - assert_equal 'https://www.example.com/', secure_root_url + assert_equal "https://www.example.com/", secure_root_url - get 'https://www.example.com/' + get "https://www.example.com/" assert_response :success end test "constraints are copied to defaults when using route constraints hash" do - assert_equal 'http://www.example.com:8080/', alternate_root_url + assert_equal "http://www.example.com:8080/", alternate_root_url - get 'http://www.example.com:8080/' + get "http://www.example.com:8080/" assert_response :success end test "false constraint expressions check for absence of values" do - get 'http://example.com/search' + get "http://example.com/search" assert_response :success - assert_equal 'http://example.com/search', search_url + assert_equal "http://example.com/search", search_url - get 'http://api.example.com/search' + get "http://api.example.com/search" assert_response :not_found end test "true constraint expressions check for presence of values" do - get 'http://api.example.com/logs' + get "http://api.example.com/logs" assert_response :success - assert_equal 'http://api.example.com/logs', logs_url + assert_equal "http://api.example.com/logs", logs_url - get 'http://example.com/logs' + get "http://example.com/logs" assert_response :not_found end end @@ -4324,15 +4403,16 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest test "invalid UTF-8 encoding returns a 400 Bad Request" do with_routing do |set| - ActiveSupport::Deprecation.silence do - set.draw do - get "/bar/:id", :to => redirect("/foo/show/%{id}") - get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show" + set.draw do + get "/bar/:id", to: redirect("/foo/show/%{id}") + get "/foo/show(/:id)", to: "test_invalid_urls/foo#show" - ActiveSupport::Deprecation.silence do - get "/foo(/:action(/:id))", :controller => "test_invalid_urls/foo" - get "/:controller(/:action(/:id))" - end + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } + get "/foobar/:id", to: ok + + ActiveSupport::Deprecation.silence do + get "/foo(/:action(/:id))", controller: "test_invalid_urls/foo" + get "/:controller(/:action(/:id))" end end @@ -4347,6 +4427,9 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest get "/bar/%E2%EF%BF%BD%A6" assert_response :bad_request + + get "/foobar/%E2%EF%BF%BD%A6" + assert_response :bad_request end end end @@ -4355,7 +4438,7 @@ class TestOptionalRootSegments < ActionDispatch::IntegrationTest stub_controllers do |routes| Routes = routes Routes.draw do - get '/(page/:page)', :to => 'pages#index', :as => :root + get "/(page/:page)", to: "pages#index", as: :root end end @@ -4367,27 +4450,27 @@ class TestOptionalRootSegments < ActionDispatch::IntegrationTest include Routes.url_helpers def test_optional_root_segments - get '/' - assert_equal 'pages#index', @response.body - assert_equal '/', root_path + get "/" + assert_equal "pages#index", @response.body + assert_equal "/", root_path - get '/page/1' - assert_equal 'pages#index', @response.body - assert_equal '1', @request.params[:page] - assert_equal '/page/1', root_path('1') - assert_equal '/page/1', root_path(:page => '1') + get "/page/1" + assert_equal "pages#index", @response.body + assert_equal "1", @request.params[:page] + assert_equal "/page/1", root_path("1") + assert_equal "/page/1", root_path(page: "1") end end class TestPortConstraints < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } - get '/integer', to: ok, constraints: { :port => 8080 } - get '/string', to: ok, constraints: { :port => '8080' } - get '/array', to: ok, constraints: { :port => [8080] } - get '/regexp', to: ok, constraints: { :port => /8080/ } + get "/integer", to: ok, constraints: { port: 8080 } + get "/string", to: ok, constraints: { port: "8080" } + get "/array", to: ok, constraints: { port: [8080] } + get "/regexp", to: ok, constraints: { port: /8080/ } end end @@ -4396,34 +4479,34 @@ class TestPortConstraints < ActionDispatch::IntegrationTest def app; APP end def test_integer_port_constraints - get 'http://www.example.com/integer' + get "http://www.example.com/integer" assert_response :not_found - get 'http://www.example.com:8080/integer' + get "http://www.example.com:8080/integer" assert_response :success end def test_string_port_constraints - get 'http://www.example.com/string' + get "http://www.example.com/string" assert_response :not_found - get 'http://www.example.com:8080/string' + get "http://www.example.com:8080/string" assert_response :success end def test_array_port_constraints - get 'http://www.example.com/array' + get "http://www.example.com/array" assert_response :not_found - get 'http://www.example.com:8080/array' + get "http://www.example.com:8080/array" assert_response :success end def test_regexp_port_constraints - get 'http://www.example.com/regexp' + get "http://www.example.com/regexp" assert_response :not_found - get 'http://www.example.com:8080/regexp' + get "http://www.example.com:8080/regexp" assert_response :success end end @@ -4431,12 +4514,12 @@ end class TestFormatConstraints < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } - get '/string', to: ok, constraints: { format: 'json' } - get '/regexp', to: ok, constraints: { format: /json/ } - get '/json_only', to: ok, format: true, constraints: { format: /json/ } - get '/xml_only', to: ok, format: 'xml' + get "/string", to: ok, constraints: { format: "json" } + get "/regexp", to: ok, constraints: { format: /json/ } + get "/json_only", to: ok, format: true, constraints: { format: /json/ } + get "/xml_only", to: ok, format: "xml" end end @@ -4445,46 +4528,46 @@ class TestFormatConstraints < ActionDispatch::IntegrationTest def app; APP end def test_string_format_constraints - get 'http://www.example.com/string' + get "http://www.example.com/string" assert_response :success - get 'http://www.example.com/string.json' + get "http://www.example.com/string.json" assert_response :success - get 'http://www.example.com/string.html' + get "http://www.example.com/string.html" assert_response :not_found end def test_regexp_format_constraints - get 'http://www.example.com/regexp' + get "http://www.example.com/regexp" assert_response :success - get 'http://www.example.com/regexp.json' + get "http://www.example.com/regexp.json" assert_response :success - get 'http://www.example.com/regexp.html' + get "http://www.example.com/regexp.html" assert_response :not_found end def test_enforce_with_format_true_with_constraint - get 'http://www.example.com/json_only.json' + get "http://www.example.com/json_only.json" assert_response :success - get 'http://www.example.com/json_only.html' + get "http://www.example.com/json_only.html" assert_response :not_found - get 'http://www.example.com/json_only' + get "http://www.example.com/json_only" assert_response :not_found end def test_enforce_with_string - get 'http://www.example.com/xml_only.xml' + get "http://www.example.com/xml_only.xml" assert_response :success - get 'http://www.example.com/xml_only' + get "http://www.example.com/xml_only" assert_response :success - get 'http://www.example.com/xml_only.json' + get "http://www.example.com/xml_only.json" assert_response :not_found end end @@ -4493,8 +4576,8 @@ class TestCallableConstraintValidation < ActionDispatch::IntegrationTest def test_constraint_with_object_not_callable assert_raises(ArgumentError) do ActionDispatch::Routing::RouteSet.new.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } - get '/test', to: ok, constraints: Object.new + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } + get "/test", to: ok, constraints: Object.new end end end @@ -4504,8 +4587,8 @@ class TestRouteDefaults < ActionDispatch::IntegrationTest stub_controllers do |routes| Routes = routes Routes.draw do - resources :posts, bucket_type: 'post' - resources :projects, defaults: { bucket_type: 'project' } + resources :posts, bucket_type: "post" + resources :projects, defaults: { bucket_type: "project" } end end @@ -4518,14 +4601,14 @@ class TestRouteDefaults < ActionDispatch::IntegrationTest def test_route_options_are_required_for_url_for assert_raises(ActionController::UrlGenerationError) do - assert_equal '/posts/1', url_for(controller: 'posts', action: 'show', id: 1, only_path: true) + assert_equal "/posts/1", url_for(controller: "posts", action: "show", id: 1, only_path: true) end - assert_equal '/posts/1', url_for(controller: 'posts', action: 'show', id: 1, bucket_type: 'post', only_path: true) + assert_equal "/posts/1", url_for(controller: "posts", action: "show", id: 1, bucket_type: "post", only_path: true) end def test_route_defaults_are_not_required_for_url_for - assert_equal '/projects/1', url_for(controller: 'projects', action: 'show', id: 1, only_path: true) + assert_equal "/projects/1", url_for(controller: "projects", action: "show", id: 1, only_path: true) end end @@ -4533,9 +4616,9 @@ class TestRackAppRouteGeneration < ActionDispatch::IntegrationTest stub_controllers do |routes| Routes = routes Routes.draw do - rack_app = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } - mount rack_app, at: '/account', as: 'account' - mount rack_app, at: '/:locale/account', as: 'localized_account' + rack_app = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } + mount rack_app, at: "/account", as: "account" + mount rack_app, at: "/:locale/account", as: "localized_account" end end @@ -4548,11 +4631,11 @@ class TestRackAppRouteGeneration < ActionDispatch::IntegrationTest def test_mounted_application_doesnt_match_unnamed_route assert_raise(ActionController::UrlGenerationError) do - assert_equal '/account?controller=products', url_for(controller: 'products', action: 'index', only_path: true) + assert_equal "/account?controller=products", url_for(controller: "products", action: "index", only_path: true) end assert_raise(ActionController::UrlGenerationError) do - assert_equal '/de/account?controller=products', url_for(controller: 'products', action: 'index', :locale => 'de', only_path: true) + assert_equal "/de/account?controller=products", url_for(controller: "products", action: "index", locale: "de", only_path: true) end end end @@ -4561,8 +4644,8 @@ class TestRedirectRouteGeneration < ActionDispatch::IntegrationTest stub_controllers do |routes| Routes = routes Routes.draw do - get '/account', to: redirect('/myaccount'), as: 'account' - get '/:locale/account', to: redirect('/%{locale}/myaccount'), as: 'localized_account' + get "/account", to: redirect("/myaccount"), as: "account" + get "/:locale/account", to: redirect("/%{locale}/myaccount"), as: "localized_account" end end @@ -4575,11 +4658,11 @@ class TestRedirectRouteGeneration < ActionDispatch::IntegrationTest def test_redirect_doesnt_match_unnamed_route assert_raise(ActionController::UrlGenerationError) do - assert_equal '/account?controller=products', url_for(controller: 'products', action: 'index', only_path: true) + assert_equal "/account?controller=products", url_for(controller: "products", action: "index", only_path: true) end assert_raise(ActionController::UrlGenerationError) do - assert_equal '/de/account?controller=products', url_for(controller: 'products', action: 'index', :locale => 'de', only_path: true) + assert_equal "/de/account?controller=products", url_for(controller: "products", action: "index", locale: "de", only_path: true) end end end @@ -4587,7 +4670,7 @@ end class TestUrlGenerationErrors < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - get "/products/:id" => 'products#show', :as => :product + get "/products/:id" => "products#show", :as => :product end end @@ -4596,29 +4679,32 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest include Routes.url_helpers - test "url helpers raise a helpful error message when generation fails" do - url, missing = { action: 'show', controller: 'products', id: nil }, [:id] - message = "No route matches #{url.inspect} missing required keys: #{missing.inspect}" + test "url helpers raise a 'missing keys' error for a nil param with optimized helpers" do + url, missing = { action: "show", controller: "products", id: nil }, [:id] + message = "No route matches #{url.inspect}, missing required keys: #{missing.inspect}" - # Optimized url helper - error = assert_raises(ActionController::UrlGenerationError){ product_path(nil) } + error = assert_raises(ActionController::UrlGenerationError) { product_path(nil) } assert_equal message, error.message + end - # Non-optimized url helper - error = assert_raises(ActionController::UrlGenerationError, message){ product_path(id: nil) } + test "url helpers raise a 'constraint failure' error for a nil param with non-optimized helpers" do + url, missing = { action: "show", controller: "products", id: nil }, [:id] + message = "No route matches #{url.inspect}, possible unmatched constraints: #{missing.inspect}" + + error = assert_raises(ActionController::UrlGenerationError, message) { product_path(id: nil) } assert_equal message, error.message end - test "url helpers raise message with mixed parameters when generation fails " do - url, missing = { action: 'show', controller: 'products', id: nil, "id"=>"url-tested"}, [:id] - message = "No route matches #{url.inspect} missing required keys: #{missing.inspect}" + test "url helpers raise message with mixed parameters when generation fails" do + url, missing = { action: "show", controller: "products", id: nil, "id"=>"url-tested" }, [:id] + message = "No route matches #{url.inspect}, possible unmatched constraints: #{missing.inspect}" # Optimized url helper - error = assert_raises(ActionController::UrlGenerationError){ product_path(nil, 'id'=>'url-tested') } + error = assert_raises(ActionController::UrlGenerationError) { product_path(nil, "id"=>"url-tested") } assert_equal message, error.message # Non-optimized url helper - error = assert_raises(ActionController::UrlGenerationError, message){ product_path(id: nil, 'id'=>'url-tested') } + error = assert_raises(ActionController::UrlGenerationError, message) { product_path(id: nil, "id"=>"url-tested") } assert_equal message, error.message end end @@ -4632,9 +4718,9 @@ class TestDefaultUrlOptions < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new Routes.draw do - default_url_options locale: 'en' - scope ':locale', format: false do - get '/posts/:year/:month/:day', to: 'posts#archive', as: 'archived_posts' + default_url_options locale: "en" + scope ":locale", format: false do + get "/posts/:year/:month/:day", to: "posts#archive", as: "archived_posts" end end @@ -4647,7 +4733,7 @@ class TestDefaultUrlOptions < ActionDispatch::IntegrationTest include Routes.url_helpers def test_positional_args_with_format_false - assert_equal '/en/posts/2014/12/13', archived_posts_path(2014, 12, 13) + assert_equal "/en/posts/2014/12/13", archived_posts_path(2014, 12, 13) end end @@ -4665,7 +4751,7 @@ class TestErrorsInController < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new Routes.draw do ActiveSupport::Deprecation.silence do - get '/:controller(/:action)' + get "/:controller(/:action)" end end @@ -4676,20 +4762,20 @@ class TestErrorsInController < ActionDispatch::IntegrationTest end def test_legit_no_method_errors_are_not_caught - get '/posts/foo' + get "/posts/foo" assert_equal 500, response.status end def test_legit_name_errors_are_not_caught - get '/posts/bar' + get "/posts/bar" assert_equal 500, response.status end def test_legit_routing_not_found_responses - get '/posts/baz' + get "/posts/baz" assert_equal 404, response.status - get '/i_do_not_exist' + get "/i_do_not_exist" assert_equal 404, response.status end end @@ -4697,17 +4783,17 @@ end class TestPartialDynamicPathSegments < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new Routes.draw do - ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] } + ok = lambda { |env| [200, { "Content-Type" => "text/plain" }, []] } - get '/songs/song-:song', to: ok - get '/songs/:song-song', to: ok - get '/:artist/song-:song', to: ok - get '/:artist/:song-song', to: ok + get "/songs/song-:song", to: ok + get "/songs/:song-song", to: ok + get "/:artist/song-:song", to: ok + get "/:artist/:song-song", to: ok - get '/optional/songs(/song-:song)', to: ok - get '/optional/songs(/:song-song)', to: ok - get '/optional/:artist(/song-:song)', to: ok - get '/optional/:artist(/:song-song)', to: ok + get "/optional/songs(/song-:song)", to: ok + get "/optional/songs(/:song-song)", to: ok + get "/optional/:artist(/song-:song)", to: ok + get "/optional/:artist(/:song-song)", to: ok end APP = build_app Routes @@ -4717,57 +4803,59 @@ class TestPartialDynamicPathSegments < ActionDispatch::IntegrationTest end def test_paths_with_partial_dynamic_segments_are_recognised - get '/david-bowie/changes-song' + get "/david-bowie/changes-song" assert_equal 200, response.status - assert_params artist: 'david-bowie', song: 'changes' + assert_params artist: "david-bowie", song: "changes" - get '/david-bowie/song-changes' + get "/david-bowie/song-changes" assert_equal 200, response.status - assert_params artist: 'david-bowie', song: 'changes' + assert_params artist: "david-bowie", song: "changes" - get '/songs/song-changes' + get "/songs/song-changes" assert_equal 200, response.status - assert_params song: 'changes' + assert_params song: "changes" - get '/songs/changes-song' + get "/songs/changes-song" assert_equal 200, response.status - assert_params song: 'changes' + assert_params song: "changes" - get '/optional/songs/song-changes' + get "/optional/songs/song-changes" assert_equal 200, response.status - assert_params song: 'changes' + assert_params song: "changes" - get '/optional/songs/changes-song' + get "/optional/songs/changes-song" assert_equal 200, response.status - assert_params song: 'changes' + assert_params song: "changes" - get '/optional/david-bowie/changes-song' + get "/optional/david-bowie/changes-song" assert_equal 200, response.status - assert_params artist: 'david-bowie', song: 'changes' + assert_params artist: "david-bowie", song: "changes" - get '/optional/david-bowie/song-changes' + get "/optional/david-bowie/song-changes" assert_equal 200, response.status - assert_params artist: 'david-bowie', song: 'changes' + assert_params artist: "david-bowie", song: "changes" end private - def assert_params(params) - assert_equal(params, request.path_parameters) - end + def assert_params(params) + assert_equal(params, request.path_parameters) + end end class TestPathParameters < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - scope module: 'test_path_parameters' do - scope ':locale', locale: /en|ar/ do - root to: 'home#index' - get '/about', to: 'pages#about' + scope module: "test_path_parameters" do + scope ":locale", locale: /en|ar/ do + root to: "home#index" + get "/about", to: "pages#about" end end - get ':controller(/:action/(:id))' + ActiveSupport::Deprecation.silence do + get ":controller(/:action/(:id))" + end end end @@ -4791,7 +4879,7 @@ class TestPathParameters < ActionDispatch::IntegrationTest def app; APP end def test_path_parameters_are_not_mutated - get '/en/about' + get "/en/about" assert_equal "/ar | /ar/about", @response.body end end @@ -4799,7 +4887,7 @@ end class TestInternalRoutingParams < ActionDispatch::IntegrationTest Routes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw do - get '/test_internal/:internal' => 'internal#internal' + get "/test_internal/:internal" => "internal#internal" end end @@ -4816,11 +4904,11 @@ class TestInternalRoutingParams < ActionDispatch::IntegrationTest end def test_paths_with_partial_dynamic_segments_are_recognised - get '/test_internal/123' + get "/test_internal/123" assert_equal 200, response.status assert_equal( - { controller: 'internal', action: 'internal', internal: '123' }, + { controller: "internal", action: "internal", internal: "123" }, request.path_parameters ) end diff --git a/actionpack/test/dispatch/runner_test.rb b/actionpack/test/dispatch/runner_test.rb new file mode 100644 index 0000000000..969933c9ed --- /dev/null +++ b/actionpack/test/dispatch/runner_test.rb @@ -0,0 +1,18 @@ +require "abstract_unit" + +class RunnerTest < ActiveSupport::TestCase + test "runner preserves the setting of integration_session" do + runner = Class.new do + def before_setup + + end + end.new + + runner.extend(ActionDispatch::Integration::Runner) + runner.integration_session.host! "lvh.me" + + runner.before_setup + + assert_equal "lvh.me", runner.integration_session.host + end +end diff --git a/actionpack/test/dispatch/session/abstract_store_test.rb b/actionpack/test/dispatch/session/abstract_store_test.rb index d38d1bbce6..fd4d359cf8 100644 --- a/actionpack/test/dispatch/session/abstract_store_test.rb +++ b/actionpack/test/dispatch/session/abstract_store_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_dispatch/middleware/session/abstract_store' +require "abstract_unit" +require "action_dispatch/middleware/session/abstract_store" module ActionDispatch module Session @@ -37,7 +37,7 @@ module ActionDispatch assert @env session = Request::Session.find ActionDispatch::Request.new @env - session['foo'] = 'bar' + session["foo"] = "bar" as.call(@env) session1 = Request::Session.find ActionDispatch::Request.new @env @@ -47,10 +47,10 @@ module ActionDispatch end private - def app(&block) - @env = nil - lambda { |env| @env = env } - end + def app(&block) + @env = nil + lambda { |env| @env = env } + end end end end diff --git a/actionpack/test/dispatch/session/cache_store_test.rb b/actionpack/test/dispatch/session/cache_store_test.rb index 769de1a1e0..a60629a7ee 100644 --- a/actionpack/test/dispatch/session/cache_store_test.rb +++ b/actionpack/test/dispatch/session/cache_store_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'fixtures/session_autoload_test/session_autoload_test/foo' +require "abstract_unit" +require "fixtures/session_autoload_test/session_autoload_test/foo" class CacheStoreTest < ActionDispatch::IntegrationTest class TestController < ActionController::Base @@ -35,11 +35,11 @@ class CacheStoreTest < ActionDispatch::IntegrationTest def test_setting_and_getting_session_value with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] + assert cookies["_session_id"] - get '/get_session_value' + get "/get_session_value" assert_response :success assert_equal 'foo: "bar"', response.body end @@ -47,56 +47,56 @@ class CacheStoreTest < ActionDispatch::IntegrationTest def test_getting_nil_session_value with_test_route_set do - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body + assert_equal "foo: nil", response.body end end def test_getting_session_value_after_session_reset with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] - session_cookie = cookies.send(:hash_for)['_session_id'] + assert cookies["_session_id"] + session_cookie = cookies.send(:hash_for)["_session_id"] - get '/call_reset_session' + get "/call_reset_session" assert_response :success - assert_not_equal [], headers['Set-Cookie'] + assert_not_equal [], headers["Set-Cookie"] cookies << session_cookie # replace our new session_id with our old, pre-reset session_id - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from cache" + assert_equal "foo: nil", response.body, "data for this session should have been obliterated from cache" end end def test_getting_from_nonexistent_session with_test_route_set do - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body - assert_nil cookies['_session_id'], "should only create session on write, not read" + assert_equal "foo: nil", response.body + assert_nil cookies["_session_id"], "should only create session on write, not read" end end def test_setting_session_value_after_session_reset with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] - session_id = cookies['_session_id'] + assert cookies["_session_id"] + session_id = cookies["_session_id"] - get '/call_reset_session' + get "/call_reset_session" assert_response :success - assert_not_equal [], headers['Set-Cookie'] + assert_not_equal [], headers["Set-Cookie"] - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body + assert_equal "foo: nil", response.body - get '/get_session_id' + get "/get_session_id" assert_response :success assert_not_equal session_id, response.body end @@ -104,12 +104,12 @@ class CacheStoreTest < ActionDispatch::IntegrationTest def test_getting_session_id with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] - session_id = cookies['_session_id'] + assert cookies["_session_id"] + session_id = cookies["_session_id"] - get '/get_session_id' + get "/get_session_id" assert_response :success assert_equal session_id, response.body, "should be able to read session id without accessing the session hash" end @@ -118,16 +118,16 @@ class CacheStoreTest < ActionDispatch::IntegrationTest def test_deserializes_unloaded_class with_test_route_set do with_autoload_path "session_autoload_test" do - get '/set_serialized_session_value' + get "/set_serialized_session_value" assert_response :success - assert cookies['_session_id'] + assert cookies["_session_id"] end with_autoload_path "session_autoload_test" do - get '/get_session_id' + get "/get_session_id" assert_response :success end with_autoload_path "session_autoload_test" do - get '/get_session_value' + get "/get_session_value" assert_response :success assert_equal 'foo: #<SessionAutoloadTest::Foo bar:"baz">', response.body, "should auto-load unloaded class" end @@ -136,27 +136,27 @@ class CacheStoreTest < ActionDispatch::IntegrationTest def test_doesnt_write_session_cookie_if_session_id_is_already_exists with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] + assert cookies["_session_id"] - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists" + assert_equal nil, headers["Set-Cookie"], "should not resend the cookie again if session_id cookie is already exists" end end def test_prevents_session_fixation with_test_route_set do - assert_equal nil, @cache.read('_session_id:0xhax') + assert_equal nil, @cache.read("_session_id:0xhax") - cookies['_session_id'] = '0xhax' - get '/set_session_value' + cookies["_session_id"] = "0xhax" + get "/set_session_value" assert_response :success - assert_not_equal '0xhax', cookies['_session_id'] - assert_equal nil, @cache.read('_session_id:0xhax') - assert_equal({'foo' => 'bar'}, @cache.read("_session_id:#{cookies['_session_id']}")) + assert_not_equal "0xhax", cookies["_session_id"] + assert_equal nil, @cache.read("_session_id:0xhax") + assert_equal({ "foo" => "bar" }, @cache.read("_session_id:#{cookies['_session_id']}")) end end @@ -165,13 +165,13 @@ class CacheStoreTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':action', :to => ::CacheStoreTest::TestController + get ":action", to: ::CacheStoreTest::TestController end end @app = self.class.build_app(set) do |middleware| @cache = ActiveSupport::Cache::MemoryStore.new - middleware.use ActionDispatch::Session::CacheStore, :key => '_session_id', :cache => @cache + middleware.use ActionDispatch::Session::CacheStore, key: "_session_id", cache: @cache middleware.delete ActionDispatch::ShowExceptions end diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index 09cb1d925f..013d289c6d 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -1,14 +1,14 @@ -require 'abstract_unit' -require 'stringio' -require 'active_support/key_generator' +require "abstract_unit" +require "stringio" +require "active_support/key_generator" class CookieStoreTest < ActionDispatch::IntegrationTest - SessionKey = '_myapp_session' - SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33' + SessionKey = "_myapp_session" + SessionSecret = "b3c631c314c0bbca50c1b2843150fe33" Generator = ActiveSupport::LegacyKeyGenerator.new(SessionSecret) - Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, :digest => 'SHA1') - SignedBar = Verifier.generate(:foo => "bar", :session_id => SecureRandom.hex(16)) + Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, digest: "SHA1") + SignedBar = Verifier.generate(foo: "bar", session_id: SecureRandom.hex(16)) class TestController < ActionController::Base def no_session_access @@ -48,7 +48,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest end def raise_data_overflow - session[:foo] = 'bye!' * 1024 + session[:foo] = "bye!" * 1024 head :ok end @@ -65,17 +65,17 @@ class CookieStoreTest < ActionDispatch::IntegrationTest def test_setting_session_value with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly", - headers['Set-Cookie'] + headers["Set-Cookie"] end end def test_getting_session_value with_test_route_set do cookies[SessionKey] = SignedBar - get '/get_session_value' + get "/get_session_value" assert_response :success assert_equal 'foo: "bar"', response.body end @@ -84,12 +84,12 @@ class CookieStoreTest < ActionDispatch::IntegrationTest def test_getting_session_id with_test_route_set do cookies[SessionKey] = SignedBar - get '/persistent_session_id' + get "/persistent_session_id" assert_response :success assert_equal 32, response.body.size session_id = response.body - get '/get_session_id' + get "/get_session_id" assert_response :success assert_equal "id: #{session_id}", response.body, "should be able to read session id without accessing the session hash" end @@ -98,37 +98,37 @@ class CookieStoreTest < ActionDispatch::IntegrationTest def test_disregards_tampered_sessions with_test_route_set do cookies[SessionKey] = "BAh7BjoIZm9vIghiYXI%3D--123456780" - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body + assert_equal "foo: nil", response.body end end def test_does_not_set_secure_cookies_over_http - with_test_route_set(:secure => true) do - get '/set_session_value' + with_test_route_set(secure: true) do + get "/set_session_value" assert_response :success - assert_equal nil, headers['Set-Cookie'] + assert_equal nil, headers["Set-Cookie"] end end def test_properly_renew_cookies with_test_route_set do - get '/set_session_value' - get '/persistent_session_id' + get "/set_session_value" + get "/persistent_session_id" session_id = response.body - get '/renew_session_id' - get '/persistent_session_id' + get "/renew_session_id" + get "/persistent_session_id" assert_not_equal response.body, session_id end end def test_does_set_secure_cookies_over_https - with_test_route_set(:secure => true) do - get '/set_session_value', headers: { 'HTTPS' => 'on' } + with_test_route_set(secure: true) do + get "/set_session_value", headers: { "HTTPS" => "on" } assert_response :success assert_equal "_myapp_session=#{response.body}; path=/; secure; HttpOnly", - headers['Set-Cookie'] + headers["Set-Cookie"] end end @@ -139,9 +139,9 @@ class CookieStoreTest < ActionDispatch::IntegrationTest with_test_route_set do with_autoload_path "session_autoload_test" do cookies[SessionKey] = SignedSerializedCookie - get '/get_session_id' + get "/get_session_id" assert_response :success - assert_equal 'id: ce8b0752a6ab7c7af3cdb8a80e6b9e46', response.body, "should auto-load unloaded class" + assert_equal "id: ce8b0752a6ab7c7af3cdb8a80e6b9e46", response.body, "should auto-load unloaded class" end end end @@ -150,7 +150,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest with_test_route_set do with_autoload_path "session_autoload_test" do cookies[SessionKey] = SignedSerializedCookie - get '/get_session_value' + get "/get_session_value" assert_response :success assert_equal 'foo: #<SessionAutoloadTest::Foo bar:"baz">', response.body, "should auto-load unloaded class" end @@ -160,16 +160,16 @@ class CookieStoreTest < ActionDispatch::IntegrationTest def test_close_raises_when_data_overflows with_test_route_set do assert_raise(ActionDispatch::Cookies::CookieOverflow) { - get '/raise_data_overflow' + get "/raise_data_overflow" } end end def test_doesnt_write_session_cookie_if_session_is_not_accessed with_test_route_set do - get '/no_session_access' + get "/no_session_access" assert_response :success - assert_equal nil, headers['Set-Cookie'] + assert_equal nil, headers["Set-Cookie"] end end @@ -177,82 +177,82 @@ class CookieStoreTest < ActionDispatch::IntegrationTest with_test_route_set do cookies[SessionKey] = "BAh7BjoIZm9vIghiYXI%3D--" + "fef868465920f415f2c0652d6910d3af288a0367" - get '/no_session_access' + get "/no_session_access" assert_response :success - assert_equal nil, headers['Set-Cookie'] + assert_equal nil, headers["Set-Cookie"] end end def test_setting_session_value_after_session_reset with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success session_payload = response.body assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly", - headers['Set-Cookie'] + headers["Set-Cookie"] - get '/call_reset_session' + get "/call_reset_session" assert_response :success - assert_not_equal [], headers['Set-Cookie'] + assert_not_equal [], headers["Set-Cookie"] assert_not_nil session_payload assert_not_equal session_payload, cookies[SessionKey] - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body + assert_equal "foo: nil", response.body end end def test_class_type_after_session_reset with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly", - headers['Set-Cookie'] + headers["Set-Cookie"] - get '/get_class_after_reset_session' + get "/get_class_after_reset_session" assert_response :success - assert_not_equal [], headers['Set-Cookie'] - assert_equal 'class: ActionDispatch::Request::Session', response.body + assert_not_equal [], headers["Set-Cookie"] + assert_equal "class: ActionDispatch::Request::Session", response.body end end def test_getting_from_nonexistent_session with_test_route_set do - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body - assert_nil headers['Set-Cookie'], "should only create session on write, not read" + assert_equal "foo: nil", response.body + assert_nil headers["Set-Cookie"], "should only create session on write, not read" end end def test_setting_session_value_after_session_clear with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly", - headers['Set-Cookie'] + headers["Set-Cookie"] - get '/call_session_clear' + get "/call_session_clear" assert_response :success - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body + assert_equal "foo: nil", response.body end end def test_persistent_session_id with_test_route_set do cookies[SessionKey] = SignedBar - get '/persistent_session_id' + get "/persistent_session_id" assert_response :success assert_equal 32, response.body.size session_id = response.body - get '/persistent_session_id' + get "/persistent_session_id" assert_equal session_id, response.body reset! - get '/persistent_session_id' + get "/persistent_session_id" assert_not_equal session_id, response.body end end @@ -271,7 +271,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest end def test_session_store_with_expire_after - with_test_route_set(:expire_after => 5.hours) do + with_test_route_set(expire_after: 5.hours) do # First request accesses the session time = Time.local(2008, 4, 24) cookie_body = nil @@ -281,12 +281,12 @@ class CookieStoreTest < ActionDispatch::IntegrationTest cookies[SessionKey] = SignedBar - get '/set_session_value' + get "/set_session_value" assert_response :success cookie_body = response.body assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly", - headers['Set-Cookie'] + headers["Set-Cookie"] end # Second request does not access the session @@ -294,41 +294,41 @@ class CookieStoreTest < ActionDispatch::IntegrationTest Time.stub :now, time do expected_expiry = (time + 5.hours).gmtime.strftime("%a, %d %b %Y %H:%M:%S -0000") - get '/no_session_access' + get "/no_session_access" assert_response :success assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly", - headers['Set-Cookie'] + headers["Set-Cookie"] end end end def test_session_store_with_explicit_domain - with_test_route_set(:domain => "example.es") do - get '/set_session_value' - assert_match(/domain=example\.es/, headers['Set-Cookie']) - headers['Set-Cookie'] + with_test_route_set(domain: "example.es") do + get "/set_session_value" + assert_match(/domain=example\.es/, headers["Set-Cookie"]) + headers["Set-Cookie"] end end def test_session_store_without_domain with_test_route_set do - get '/set_session_value' - assert_no_match(/domain\=/, headers['Set-Cookie']) + get "/set_session_value" + assert_no_match(/domain\=/, headers["Set-Cookie"]) end end def test_session_store_with_nil_domain - with_test_route_set(:domain => nil) do - get '/set_session_value' - assert_no_match(/domain\=/, headers['Set-Cookie']) + with_test_route_set(domain: nil) do + get "/set_session_value" + assert_no_match(/domain\=/, headers["Set-Cookie"]) end end def test_session_store_with_all_domains - with_test_route_set(:domain => :all) do - get '/set_session_value' - assert_match(/domain=\.example\.com/, headers['Set-Cookie']) + with_test_route_set(domain: :all) do + get "/set_session_value" + assert_match(/domain=\.example\.com/, headers["Set-Cookie"]) end end @@ -346,11 +346,11 @@ class CookieStoreTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':action', :to => ::CookieStoreTest::TestController + get ":action", to: ::CookieStoreTest::TestController end end - options = { :key => SessionKey }.merge!(options) + options = { key: SessionKey }.merge!(options) @app = self.class.build_app(set) do |middleware| middleware.use ActionDispatch::Session::CookieStore, options @@ -360,5 +360,4 @@ class CookieStoreTest < ActionDispatch::IntegrationTest yield end end - end diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb index 18cb227dad..c2d0719b4e 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'securerandom' +require "abstract_unit" +require "securerandom" # You need to start a memcached server inorder to run these tests class MemCacheStoreTest < ActionDispatch::IntegrationTest @@ -35,17 +35,17 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest end begin - require 'dalli' - ss = Dalli::Client.new('localhost:11211').stats - raise Dalli::DalliError unless ss['localhost:11211'] + require "dalli" + ss = Dalli::Client.new("localhost:11211").stats + raise Dalli::DalliError unless ss["localhost:11211"] def test_setting_and_getting_session_value with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] + assert cookies["_session_id"] - get '/get_session_value' + get "/get_session_value" assert_response :success assert_equal 'foo: "bar"', response.body end @@ -55,9 +55,9 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_getting_nil_session_value with_test_route_set do - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body + assert_equal "foo: nil", response.body end rescue Dalli::RingError => ex skip ex.message, ex.backtrace @@ -65,20 +65,20 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_getting_session_value_after_session_reset with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] - session_cookie = cookies.send(:hash_for)['_session_id'] + assert cookies["_session_id"] + session_cookie = cookies.send(:hash_for)["_session_id"] - get '/call_reset_session' + get "/call_reset_session" assert_response :success - assert_not_equal [], headers['Set-Cookie'] + assert_not_equal [], headers["Set-Cookie"] cookies << session_cookie # replace our new session_id with our old, pre-reset session_id - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached" + assert_equal "foo: nil", response.body, "data for this session should have been obliterated from memcached" end rescue Dalli::RingError => ex skip ex.message, ex.backtrace @@ -86,10 +86,10 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_getting_from_nonexistent_session with_test_route_set do - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body - assert_nil cookies['_session_id'], "should only create session on write, not read" + assert_equal "foo: nil", response.body + assert_nil cookies["_session_id"], "should only create session on write, not read" end rescue Dalli::RingError => ex skip ex.message, ex.backtrace @@ -97,20 +97,20 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_setting_session_value_after_session_reset with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] - session_id = cookies['_session_id'] + assert cookies["_session_id"] + session_id = cookies["_session_id"] - get '/call_reset_session' + get "/call_reset_session" assert_response :success - assert_not_equal [], headers['Set-Cookie'] + assert_not_equal [], headers["Set-Cookie"] - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body + assert_equal "foo: nil", response.body - get '/get_session_id' + get "/get_session_id" assert_response :success assert_not_equal session_id, response.body end @@ -120,12 +120,12 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_getting_session_id with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] - session_id = cookies['_session_id'] + assert cookies["_session_id"] + session_id = cookies["_session_id"] - get '/get_session_id' + get "/get_session_id" assert_response :success assert_equal session_id, response.body, "should be able to read session id without accessing the session hash" end @@ -136,12 +136,12 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_deserializes_unloaded_class with_test_route_set do with_autoload_path "session_autoload_test" do - get '/set_serialized_session_value' + get "/set_serialized_session_value" assert_response :success - assert cookies['_session_id'] + assert cookies["_session_id"] end with_autoload_path "session_autoload_test" do - get '/get_session_id' + get "/get_session_id" assert_response :success end end @@ -151,13 +151,13 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_doesnt_write_session_cookie_if_session_id_is_already_exists with_test_route_set do - get '/set_session_value' + get "/set_session_value" assert_response :success - assert cookies['_session_id'] + assert cookies["_session_id"] - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists" + assert_equal nil, headers["Set-Cookie"], "should not resend the cookie again if session_id cookie is already exists" end rescue Dalli::RingError => ex skip ex.message, ex.backtrace @@ -165,16 +165,16 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest def test_prevents_session_fixation with_test_route_set do - get '/get_session_value' + get "/get_session_value" assert_response :success - assert_equal 'foo: nil', response.body - session_id = cookies['_session_id'] + assert_equal "foo: nil", response.body + session_id = cookies["_session_id"] reset! - get '/set_session_value', params: { _session_id: session_id } + get "/set_session_value", params: { _session_id: session_id } assert_response :success - assert_not_equal session_id, cookies['_session_id'] + assert_not_equal session_id, cookies["_session_id"] end rescue Dalli::RingError => ex skip ex.message, ex.backtrace @@ -188,12 +188,12 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest with_routing do |set| set.draw do ActiveSupport::Deprecation.silence do - get ':action', :to => ::MemCacheStoreTest::TestController + get ":action", to: ::MemCacheStoreTest::TestController end end @app = self.class.build_app(set) do |middleware| - middleware.use ActionDispatch::Session::MemCacheStore, :key => '_session_id', :namespace => "mem_cache_store_test:#{SecureRandom.hex(10)}" + middleware.use ActionDispatch::Session::MemCacheStore, key: "_session_id", namespace: "mem_cache_store_test:#{SecureRandom.hex(10)}" middleware.delete ActionDispatch::ShowExceptions end diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb index 3e61d123e3..0bf3a8b3ee 100644 --- a/actionpack/test/dispatch/session/test_session_test.rb +++ b/actionpack/test/dispatch/session/test_session_test.rb @@ -1,63 +1,63 @@ -require 'abstract_unit' -require 'stringio' +require "abstract_unit" +require "stringio" class ActionController::TestSessionTest < ActiveSupport::TestCase def test_initialize_with_values - session = ActionController::TestSession.new(one: 'one', two: 'two') - assert_equal('one', session[:one]) - assert_equal('two', session[:two]) + session = ActionController::TestSession.new(one: "one", two: "two") + assert_equal("one", session[:one]) + assert_equal("two", session[:two]) end def test_setting_session_item_sets_item session = ActionController::TestSession.new - session[:key] = 'value' - assert_equal('value', session[:key]) + session[:key] = "value" + assert_equal("value", session[:key]) end def test_calling_delete_removes_item_and_returns_its_value session = ActionController::TestSession.new - session[:key] = 'value' - assert_equal('value', session[:key]) - assert_equal('value', session.delete(:key)) + session[:key] = "value" + assert_equal("value", session[:key]) + assert_equal("value", session.delete(:key)) assert_nil(session[:key]) end def test_calling_update_with_params_passes_to_attributes session = ActionController::TestSession.new - session.update('key' => 'value') - assert_equal('value', session[:key]) + session.update("key" => "value") + assert_equal("value", session[:key]) end def test_clear_empties_session - session = ActionController::TestSession.new(one: 'one', two: 'two') + session = ActionController::TestSession.new(one: "one", two: "two") session.clear assert_nil(session[:one]) assert_nil(session[:two]) end def test_keys_and_values - session = ActionController::TestSession.new(one: '1', two: '2') + session = ActionController::TestSession.new(one: "1", two: "2") assert_equal %w(one two), session.keys assert_equal %w(1 2), session.values end def test_fetch_returns_default - session = ActionController::TestSession.new(one: '1') - assert_equal('2', session.fetch(:two, '2')) + session = ActionController::TestSession.new(one: "1") + assert_equal("2", session.fetch(:two, "2")) end def test_fetch_on_symbol_returns_value - session = ActionController::TestSession.new(one: '1') - assert_equal('1', session.fetch(:one)) + session = ActionController::TestSession.new(one: "1") + assert_equal("1", session.fetch(:one)) end def test_fetch_on_string_returns_value - session = ActionController::TestSession.new(one: '1') - assert_equal('1', session.fetch('one')) + session = ActionController::TestSession.new(one: "1") + assert_equal("1", session.fetch("one")) end def test_fetch_returns_block_value - session = ActionController::TestSession.new(one: '1') - assert_equal(2, session.fetch('2') { |key| key.to_i }) + session = ActionController::TestSession.new(one: "1") + assert_equal(2, session.fetch("2") { |key| key.to_i }) end end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 14894d4b82..3513534d72 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -1,7 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" class ShowExceptionsTest < ActionDispatch::IntegrationTest - class Boomer def call(env) req = ActionDispatch::Request.new(env) @@ -12,17 +11,17 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest begin raise StandardError.new rescue - raise ActionDispatch::ParamsParser::ParseError + raise ActionDispatch::Http::Parameters::ParseError end when "/method_not_allowed" - raise ActionController::MethodNotAllowed, 'PUT' + raise ActionController::MethodNotAllowed, "PUT" when "/unknown_http_method" raise ActionController::UnknownHttpMethod when "/not_found_original_exception" begin raise AbstractController::ActionNotFound.new rescue - raise ActionView::Template::Error.new('template') + raise ActionView::Template::Error.new("template") end else raise "puke!" @@ -35,30 +34,30 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest test "skip exceptions app if not showing exceptions" do @app = ProductionApp assert_raise RuntimeError do - get "/", headers: { 'action_dispatch.show_exceptions' => false } + get "/", headers: { "action_dispatch.show_exceptions" => false } end end test "rescue with error page" do @app = ProductionApp - get "/", headers: { 'action_dispatch.show_exceptions' => true } + get "/", headers: { "action_dispatch.show_exceptions" => true } assert_response 500 assert_equal "500 error fixture\n", body - get "/bad_params", headers: { 'action_dispatch.show_exceptions' => true } + get "/bad_params", headers: { "action_dispatch.show_exceptions" => true } assert_response 400 assert_equal "400 error fixture\n", body - get "/not_found", headers: { 'action_dispatch.show_exceptions' => true } + get "/not_found", headers: { "action_dispatch.show_exceptions" => true } assert_response 404 assert_equal "404 error fixture\n", body - get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true } + get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => true } assert_response 405 assert_equal "", body - get "/unknown_http_method", headers: { 'action_dispatch.show_exceptions' => true } + get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => true } assert_response 405 assert_equal "", body end @@ -69,11 +68,11 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest begin @app = ProductionApp - get "/", headers: { 'action_dispatch.show_exceptions' => true } + get "/", headers: { "action_dispatch.show_exceptions" => true } assert_response 500 assert_equal "500 localized error fixture\n", body - get "/not_found", headers: { 'action_dispatch.show_exceptions' => true } + get "/not_found", headers: { "action_dispatch.show_exceptions" => true } assert_response 404 assert_equal "404 error fixture\n", body ensure @@ -84,14 +83,14 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest test "sets the HTTP charset parameter" do @app = ProductionApp - get "/", headers: { 'action_dispatch.show_exceptions' => true } + get "/", headers: { "action_dispatch.show_exceptions" => true } assert_equal "text/html; charset=utf-8", response.headers["Content-Type"] end test "show registered original exception for wrapped exceptions" do @app = ProductionApp - get "/not_found_original_exception", headers: { 'action_dispatch.show_exceptions' => true } + get "/not_found_original_exception", headers: { "action_dispatch.show_exceptions" => true } assert_response 404 assert_match(/404 error/, body) end @@ -105,7 +104,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest end @app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app) - get "/not_found_original_exception", headers: { 'action_dispatch.show_exceptions' => true } + get "/not_found_original_exception", headers: { "action_dispatch.show_exceptions" => true } assert_response 404 assert_equal "YOU FAILED", body end @@ -116,7 +115,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest end @app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app) - get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true } + get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => true } assert_response 405 assert_equal "", body end @@ -124,12 +123,12 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest test "bad params exception is returned in the correct format" do @app = ProductionApp - get "/bad_params", headers: { 'action_dispatch.show_exceptions' => true } + get "/bad_params", headers: { "action_dispatch.show_exceptions" => true } assert_equal "text/html; charset=utf-8", response.headers["Content-Type"] assert_response 400 assert_match(/400 error/, body) - get "/bad_params.json", headers: { 'action_dispatch.show_exceptions' => true } + get "/bad_params.json", headers: { "action_dispatch.show_exceptions" => true } assert_equal "application/json; charset=utf-8", response.headers["Content-Type"] assert_response 400 assert_equal("{\"status\":400,\"error\":\"Bad Request\"}", body) diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb index 668b2b6cfe..e29ffa750c 100644 --- a/actionpack/test/dispatch/ssl_test.rb +++ b/actionpack/test/dispatch/ssl_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' +require "abstract_unit" class SSLTest < ActionDispatch::IntegrationTest - HEADERS = Rack::Utils::HeaderHash.new 'Content-Type' => 'text/html' + HEADERS = Rack::Utils::HeaderHash.new "Content-Type" => "text/html" attr_accessor :app @@ -12,26 +12,16 @@ class SSLTest < ActionDispatch::IntegrationTest end class RedirectSSLTest < SSLTest - - def assert_not_redirected(url, headers: {}, redirect: {}, deprecated_host: nil, - deprecated_port: nil) - - self.app = build_app ssl_options: { redirect: redirect, - host: deprecated_host, port: deprecated_port - } - + def assert_not_redirected(url, headers: {}, redirect: {}) + self.app = build_app ssl_options: { redirect: redirect } get url, headers: headers assert_response :ok end - def assert_redirected(redirect: {}, deprecated_host: nil, deprecated_port: nil, - from: 'http://a/b?c=d', to: from.sub('http', 'https')) - + def assert_redirected(redirect: {}, from: "http://a/b?c=d", to: from.sub("http", "https")) redirect = { status: 301, body: [] }.merge(redirect) - self.app = build_app ssl_options: { redirect: redirect, - host: deprecated_host, port: deprecated_port - } + self.app = build_app ssl_options: { redirect: redirect } get from assert_response redirect[:status] || 301 @@ -39,130 +29,124 @@ class RedirectSSLTest < SSLTest assert_equal redirect[:body].join, @response.body end - test 'exclude can avoid redirect' do - excluding = { exclude: -> request { request.path =~ /healthcheck/ } } + def assert_post_redirected(redirect: {}, from: "http://a/b?c=d", + to: from.sub("http", "https")) + + self.app = build_app ssl_options: { redirect: redirect } - assert_not_redirected 'http://example.org/healthcheck', redirect: excluding - assert_redirected from: 'http://example.org/', redirect: excluding + post from + assert_response redirect[:status] || 307 + assert_redirected_to to end - test 'https is not redirected' do - assert_not_redirected 'https://example.org' + test "exclude can avoid redirect" do + excluding = { exclude: -> request { request.path =~ /healthcheck/ } } + + assert_not_redirected "http://example.org/healthcheck", redirect: excluding + assert_redirected from: "http://example.org/", redirect: excluding end - test 'proxied https is not redirected' do - assert_not_redirected 'http://example.org', headers: { 'HTTP_X_FORWARDED_PROTO' => 'https' } + test "https is not redirected" do + assert_not_redirected "https://example.org" end - test 'http is redirected to https' do - assert_redirected + test "proxied https is not redirected" do + assert_not_redirected "http://example.org", headers: { "HTTP_X_FORWARDED_PROTO" => "https" } end - test 'redirect with non-301 status' do - assert_redirected redirect: { status: 307 } + test "http is redirected to https" do + assert_redirected end - test 'redirect with custom body' do - assert_redirected redirect: { body: ['foo'] } + test "http POST is redirected to https with status 307" do + assert_post_redirected end - test 'redirect to specific host' do - assert_redirected redirect: { host: 'ssl' }, to: 'https://ssl/b?c=d' + test "redirect with non-301 status" do + assert_redirected redirect: { status: 307 } end - test 'redirect to default port' do - assert_redirected redirect: { port: 443 } + test "redirect with custom body" do + assert_redirected redirect: { body: ["foo"] } end - test 'redirect to non-default port' do - assert_redirected redirect: { port: 8443 }, to: 'https://a:8443/b?c=d' + test "redirect to specific host" do + assert_redirected redirect: { host: "ssl" }, to: "https://ssl/b?c=d" end - test 'redirect to different host and non-default port' do - assert_redirected redirect: { host: 'ssl', port: 8443 }, to: 'https://ssl:8443/b?c=d' + test "redirect to default port" do + assert_redirected redirect: { port: 443 } end - test 'redirect to different host including port' do - assert_redirected redirect: { host: 'ssl:443' }, to: 'https://ssl:443/b?c=d' + test "redirect to non-default port" do + assert_redirected redirect: { port: 8443 }, to: "https://a:8443/b?c=d" end - test ':host is deprecated, moved within redirect: { host: … }' do - assert_deprecated do - assert_redirected deprecated_host: 'foo', to: 'https://foo/b?c=d' - end + test "redirect to different host and non-default port" do + assert_redirected redirect: { host: "ssl", port: 8443 }, to: "https://ssl:8443/b?c=d" end - test ':port is deprecated, moved within redirect: { port: … }' do - assert_deprecated do - assert_redirected deprecated_port: 1, to: 'https://a:1/b?c=d' - end + test "redirect to different host including port" do + assert_redirected redirect: { host: "ssl:443" }, to: "https://ssl:443/b?c=d" end - test 'no redirect with redirect set to false' do - assert_not_redirected 'http://example.org', redirect: false + test "no redirect with redirect set to false" do + assert_not_redirected "http://example.org", redirect: false end end class StrictTransportSecurityTest < SSLTest - EXPECTED = 'max-age=15552000' - EXPECTED_WITH_SUBDOMAINS = 'max-age=15552000; includeSubDomains' + EXPECTED = "max-age=15552000" + EXPECTED_WITH_SUBDOMAINS = "max-age=15552000; includeSubDomains" - def assert_hsts(expected, url: 'https://example.org', hsts: { subdomains: true }, headers: {}) + def assert_hsts(expected, url: "https://example.org", hsts: { subdomains: true }, headers: {}) self.app = build_app ssl_options: { hsts: hsts }, headers: headers get url - assert_equal expected, response.headers['Strict-Transport-Security'] + assert_equal expected, response.headers["Strict-Transport-Security"] end - test 'enabled by default' do + test "enabled by default" do assert_hsts EXPECTED_WITH_SUBDOMAINS end - test 'not sent with http:// responses' do - assert_hsts nil, url: 'http://example.org' + test "not sent with http:// responses" do + assert_hsts nil, url: "http://example.org" end - test 'defers to app-provided header' do - assert_hsts 'app-provided', headers: { 'Strict-Transport-Security' => 'app-provided' } + test "defers to app-provided header" do + assert_hsts "app-provided", headers: { "Strict-Transport-Security" => "app-provided" } end - test 'hsts: true enables default settings' do - assert_hsts EXPECTED, hsts: true + test "hsts: true enables default settings" do + assert_hsts EXPECTED_WITH_SUBDOMAINS, hsts: true end - test 'hsts: false sets max-age to zero, clearing browser HSTS settings' do - assert_hsts 'max-age=0', hsts: false + test "hsts: false sets max-age to zero, clearing browser HSTS settings" do + assert_hsts "max-age=0; includeSubDomains", hsts: false end - test ':expires sets max-age' do - assert_deprecated do - assert_hsts 'max-age=500', hsts: { expires: 500 } - end + test ":expires sets max-age" do + assert_hsts "max-age=500; includeSubDomains", hsts: { expires: 500 } end - test ':expires supports AS::Duration arguments' do - assert_deprecated do - assert_hsts 'max-age=31557600', hsts: { expires: 1.year } - end + test ":expires supports AS::Duration arguments" do + assert_hsts "max-age=31557600; includeSubDomains", hsts: { expires: 1.year } end - test 'include subdomains' do + test "include subdomains" do assert_hsts "#{EXPECTED}; includeSubDomains", hsts: { subdomains: true } end - test 'exclude subdomains' do + test "exclude subdomains" do assert_hsts EXPECTED, hsts: { subdomains: false } end - test 'opt in to browser preload lists' do - assert_deprecated do - assert_hsts "#{EXPECTED}; preload", hsts: { preload: true } - end + test "opt in to browser preload lists" do + assert_hsts "#{EXPECTED_WITH_SUBDOMAINS}; preload", hsts: { preload: true } end - test 'opt out of browser preload lists' do - assert_deprecated do - assert_hsts EXPECTED, hsts: { preload: false } - end + test "opt out of browser preload lists" do + assert_hsts EXPECTED_WITH_SUBDOMAINS, hsts: { preload: false } end end @@ -171,60 +155,60 @@ class SecureCookiesTest < SSLTest def get(**options) self.app = build_app(**options) - super 'https://example.org' + super "https://example.org" end def assert_cookies(*expected) - assert_equal expected, response.headers['Set-Cookie'].split("\n") + assert_equal expected, response.headers["Set-Cookie"].split("\n") end def test_flag_cookies_as_secure - get headers: { 'Set-Cookie' => DEFAULT } - assert_cookies 'id=1; path=/; secure', 'token=abc; path=/; secure; HttpOnly' + get headers: { "Set-Cookie" => DEFAULT } + assert_cookies "id=1; path=/; secure", "token=abc; path=/; secure; HttpOnly" end def test_flag_cookies_as_secure_at_end_of_line - get headers: { 'Set-Cookie' => 'problem=def; path=/; HttpOnly; secure' } - assert_cookies 'problem=def; path=/; HttpOnly; secure' + get headers: { "Set-Cookie" => "problem=def; path=/; HttpOnly; secure" } + assert_cookies "problem=def; path=/; HttpOnly; secure" end def test_flag_cookies_as_secure_with_more_spaces_before - get headers: { 'Set-Cookie' => 'problem=def; path=/; HttpOnly; secure' } - assert_cookies 'problem=def; path=/; HttpOnly; secure' + get headers: { "Set-Cookie" => "problem=def; path=/; HttpOnly; secure" } + assert_cookies "problem=def; path=/; HttpOnly; secure" end def test_flag_cookies_as_secure_with_more_spaces_after - get headers: { 'Set-Cookie' => 'problem=def; path=/; secure; HttpOnly' } - assert_cookies 'problem=def; path=/; secure; HttpOnly' + get headers: { "Set-Cookie" => "problem=def; path=/; secure; HttpOnly" } + assert_cookies "problem=def; path=/; secure; HttpOnly" end def test_flag_cookies_as_secure_with_has_not_spaces_before - get headers: { 'Set-Cookie' => 'problem=def; path=/;secure; HttpOnly' } - assert_cookies 'problem=def; path=/;secure; HttpOnly' + get headers: { "Set-Cookie" => "problem=def; path=/;secure; HttpOnly" } + assert_cookies "problem=def; path=/;secure; HttpOnly" end def test_flag_cookies_as_secure_with_has_not_spaces_after - get headers: { 'Set-Cookie' => 'problem=def; path=/; secure;HttpOnly' } - assert_cookies 'problem=def; path=/; secure;HttpOnly' + get headers: { "Set-Cookie" => "problem=def; path=/; secure;HttpOnly" } + assert_cookies "problem=def; path=/; secure;HttpOnly" end def test_flag_cookies_as_secure_with_ignore_case - get headers: { 'Set-Cookie' => 'problem=def; path=/; Secure; HttpOnly' } - assert_cookies 'problem=def; path=/; Secure; HttpOnly' + get headers: { "Set-Cookie" => "problem=def; path=/; Secure; HttpOnly" } + assert_cookies "problem=def; path=/; Secure; HttpOnly" end def test_cookies_as_not_secure_with_secure_cookies_disabled - get headers: { 'Set-Cookie' => DEFAULT }, ssl_options: { secure_cookies: false } + get headers: { "Set-Cookie" => DEFAULT }, ssl_options: { secure_cookies: false } assert_cookies(*DEFAULT.split("\n")) end def test_no_cookies get - assert_nil response.headers['Set-Cookie'] + assert_nil response.headers["Set-Cookie"] end def test_keeps_original_headers_behavior - get headers: { 'Connection' => %w[close] } - assert_equal 'close', response.headers['Connection'] + get headers: { "Connection" => %w[close] } + assert_equal "close", response.headers["Connection"] end end diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb index ea8b5e904e..aca70e180c 100644 --- a/actionpack/test/dispatch/static_test.rb +++ b/actionpack/test/dispatch/static_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'zlib' +require "abstract_unit" +require "zlib" module StaticTests DummyApp = lambda { |env| - [200, {"Content-Type" => "text/plain"}, ["Hello, World!"]] + [200, { "Content-Type" => "text/plain" }, ["Hello, World!"]] } def setup @@ -29,7 +29,7 @@ module StaticTests end def test_handles_urls_with_ascii_8bit - assert_equal "Hello, World!", get("/doorkeeper%E3E4".force_encoding('ASCII-8BIT')).body + assert_equal "Hello, World!", get("/doorkeeper%E3E4".force_encoding("ASCII-8BIT")).body end def test_handles_urls_with_ascii_8bit_on_win_31j @@ -37,23 +37,13 @@ module StaticTests Encoding.default_internal = "Windows-31J" Encoding.default_external = "Windows-31J" end - assert_equal "Hello, World!", get("/doorkeeper%E3E4".force_encoding('ASCII-8BIT')).body + assert_equal "Hello, World!", get("/doorkeeper%E3E4".force_encoding("ASCII-8BIT")).body end def test_handles_urls_with_null_byte assert_equal "Hello, World!", get("/doorkeeper%00").body end - def test_sets_cache_control - app = assert_deprecated do - ActionDispatch::Static.new(DummyApp, @root, "public, max-age=60") - end - response = Rack::MockRequest.new(app).request("GET", "/index.html") - - assert_html "/index.html", response - assert_equal "public, max-age=60", response.headers["Cache-Control"] - end - def test_serves_static_index_at_root assert_html "/index.html", get("/index.html") assert_html "/index.html", get("/index") @@ -82,7 +72,6 @@ module StaticTests assert_html "means hello in Japanese\n", get("/foo/#{Rack::Utils.escape("ã“ã‚“ã«ã¡ã¯.html")}") end - def test_serves_static_file_with_exclamation_mark_in_filename with_static_file "/foo/foo!bar.html" do |file| assert_html file, get("/foo/foo%21bar.html") @@ -148,65 +137,74 @@ module StaticTests def test_serves_gzip_files_when_header_set file_name = "/gzip/application-a71b3024f80aea3181c09774ca17e712.js" - response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'gzip') + response = get(file_name, "HTTP_ACCEPT_ENCODING" => "gzip") assert_gzip file_name, response - assert_equal 'application/javascript', response.headers['Content-Type'] - assert_equal 'Accept-Encoding', response.headers["Vary"] - assert_equal 'gzip', response.headers["Content-Encoding"] + assert_equal "application/javascript", response.headers["Content-Type"] + assert_equal "Accept-Encoding", response.headers["Vary"] + assert_equal "gzip", response.headers["Content-Encoding"] - response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'Gzip') + response = get(file_name, "HTTP_ACCEPT_ENCODING" => "Gzip") assert_gzip file_name, response - response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'GZIP') + response = get(file_name, "HTTP_ACCEPT_ENCODING" => "GZIP") assert_gzip file_name, response - response = get(file_name, 'HTTP_ACCEPT_ENCODING' => '') - assert_not_equal 'gzip', response.headers["Content-Encoding"] + response = get(file_name, "HTTP_ACCEPT_ENCODING" => "compress;q=0.5, gzip;q=1.0") + assert_gzip file_name, response + + response = get(file_name, "HTTP_ACCEPT_ENCODING" => "") + assert_not_equal "gzip", response.headers["Content-Encoding"] end def test_does_not_modify_path_info file_name = "/gzip/application-a71b3024f80aea3181c09774ca17e712.js" - env = {'PATH_INFO' => file_name, 'HTTP_ACCEPT_ENCODING' => 'gzip', "REQUEST_METHOD" => 'POST'} + env = { "PATH_INFO" => file_name, "HTTP_ACCEPT_ENCODING" => "gzip", "REQUEST_METHOD" => "POST" } @app.call(env) - assert_equal file_name, env['PATH_INFO'] + assert_equal file_name, env["PATH_INFO"] end def test_serves_gzip_with_propper_content_type_fallback file_name = "/gzip/foo.zoo" - response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'gzip') + response = get(file_name, "HTTP_ACCEPT_ENCODING" => "gzip") assert_gzip file_name, response default_response = get(file_name) # no gzip - assert_equal default_response.headers['Content-Type'], response.headers['Content-Type'] + assert_equal default_response.headers["Content-Type"], response.headers["Content-Type"] end def test_serves_gzip_files_with_not_modified file_name = "/gzip/application-a71b3024f80aea3181c09774ca17e712.js" last_modified = File.mtime(File.join(@root, "#{file_name}.gz")) - response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'gzip', 'HTTP_IF_MODIFIED_SINCE' => last_modified.httpdate) + response = get(file_name, "HTTP_ACCEPT_ENCODING" => "gzip", "HTTP_IF_MODIFIED_SINCE" => last_modified.httpdate) assert_equal 304, response.status - assert_equal nil, response.headers['Content-Type'] - assert_equal nil, response.headers['Content-Encoding'] - assert_equal nil, response.headers['Vary'] + assert_equal nil, response.headers["Content-Type"] + assert_equal nil, response.headers["Content-Encoding"] + assert_equal nil, response.headers["Vary"] end def test_serves_files_with_headers headers = { - "Access-Control-Allow-Origin" => 'http://rubyonrails.org', - "Cache-Control" => 'public, max-age=60', + "Access-Control-Allow-Origin" => "http://rubyonrails.org", + "Cache-Control" => "public, max-age=60", "X-Custom-Header" => "I'm a teapot" } app = ActionDispatch::Static.new(DummyApp, @root, headers: headers) response = Rack::MockRequest.new(app).request("GET", "/foo/bar.html") - assert_equal 'http://rubyonrails.org', response.headers["Access-Control-Allow-Origin"] - assert_equal 'public, max-age=60', response.headers["Cache-Control"] + assert_equal "http://rubyonrails.org", response.headers["Access-Control-Allow-Origin"] + assert_equal "public, max-age=60", response.headers["Cache-Control"] assert_equal "I'm a teapot", response.headers["X-Custom-Header"] end + def test_ignores_unknown_http_methods + app = ActionDispatch::Static.new(DummyApp, @root) + + assert_nothing_raised { Rack::MockRequest.new(app).request("BAD_METHOD", "/foo/bar.html") } + end + # Windows doesn't allow \ / : * ? " < > | in filenames - unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + unless RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ def test_serves_static_file_with_colon with_static_file "/foo/foo:bar.html" do |file| assert_html file, get("/foo/foo%3Abar.html") @@ -258,7 +256,7 @@ class StaticTest < ActiveSupport::TestCase def setup super @root = "#{FIXTURE_LOAD_PATH}/public" - @app = ActionDispatch::Static.new(DummyApp, @root, headers: {'Cache-Control' => "public, max-age=60"}) + @app = ActionDispatch::Static.new(DummyApp, @root, headers: { "Cache-Control" => "public, max-age=60" }) end def public_path @@ -268,8 +266,8 @@ class StaticTest < ActiveSupport::TestCase include StaticTests def test_custom_handler_called_when_file_is_outside_root - filename = 'shared.html.erb' - assert File.exist?(File.join(@root, '..', filename)) + filename = "shared.html.erb" + assert File.exist?(File.join(@root, "..", filename)) env = { "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/..%2F#{filename}", @@ -294,14 +292,13 @@ class StaticTest < ActiveSupport::TestCase assert_html "/foo/other-index.html", get("/foo/") assert_html "/foo/other-index.html", get("/foo") end - end class StaticEncodingTest < StaticTest def setup super @root = "#{FIXTURE_LOAD_PATH}/公共" - @app = ActionDispatch::Static.new(DummyApp, @root, headers: {'Cache-Control' => "public, max-age=60"}) + @app = ActionDispatch::Static.new(DummyApp, @root, headers: { "Cache-Control" => "public, max-age=60" }) end def public_path diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb index 3c19cbd68a..b479af781d 100644 --- a/actionpack/test/dispatch/test_request_test.rb +++ b/actionpack/test/dispatch/test_request_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TestRequestTest < ActiveSupport::TestCase test "sane defaults" do @@ -33,24 +33,24 @@ class TestRequestTest < ActiveSupport::TestCase assert_equal nil, req.env["HTTP_COOKIE"] req.cookie_jar["user_name"] = "david" - assert_cookies({"user_name" => "david"}, req.cookie_jar) + assert_cookies({ "user_name" => "david" }, req.cookie_jar) req.cookie_jar["login"] = "XJ-122" - assert_cookies({"user_name" => "david", "login" => "XJ-122"}, req.cookie_jar) + assert_cookies({ "user_name" => "david", "login" => "XJ-122" }, req.cookie_jar) assert_nothing_raised do req.cookie_jar["login"] = nil - assert_cookies({"user_name" => "david", "login" => nil}, req.cookie_jar) + assert_cookies({ "user_name" => "david", "login" => nil }, req.cookie_jar) end req.cookie_jar.delete(:login) - assert_cookies({"user_name" => "david"}, req.cookie_jar) + assert_cookies({ "user_name" => "david" }, req.cookie_jar) req.cookie_jar.clear assert_cookies({}, req.cookie_jar) - req.cookie_jar.update(:user_name => "david") - assert_cookies({"user_name" => "david"}, req.cookie_jar) + req.cookie_jar.update(user_name: "david") + assert_cookies({ "user_name" => "david" }, req.cookie_jar) end test "does not complain when there is no application config" do @@ -60,59 +60,66 @@ class TestRequestTest < ActiveSupport::TestCase test "default remote address is 0.0.0.0" do req = ActionDispatch::TestRequest.create({}) - assert_equal '0.0.0.0', req.remote_addr + assert_equal "0.0.0.0", req.remote_addr end test "allows remote address to be overridden" do - req = ActionDispatch::TestRequest.create('REMOTE_ADDR' => '127.0.0.1') - assert_equal '127.0.0.1', req.remote_addr + req = ActionDispatch::TestRequest.create("REMOTE_ADDR" => "127.0.0.1") + assert_equal "127.0.0.1", req.remote_addr end test "default host is test.host" do req = ActionDispatch::TestRequest.create({}) - assert_equal 'test.host', req.host + assert_equal "test.host", req.host end test "allows host to be overridden" do - req = ActionDispatch::TestRequest.create('HTTP_HOST' => 'www.example.com') - assert_equal 'www.example.com', req.host + req = ActionDispatch::TestRequest.create("HTTP_HOST" => "www.example.com") + assert_equal "www.example.com", req.host end test "default user agent is 'Rails Testing'" do req = ActionDispatch::TestRequest.create({}) - assert_equal 'Rails Testing', req.user_agent + assert_equal "Rails Testing", req.user_agent end test "allows user agent to be overridden" do - req = ActionDispatch::TestRequest.create('HTTP_USER_AGENT' => 'GoogleBot') - assert_equal 'GoogleBot', req.user_agent + req = ActionDispatch::TestRequest.create("HTTP_USER_AGENT" => "GoogleBot") + assert_equal "GoogleBot", req.user_agent + end + + test "request_method getter and setter" do + req = ActionDispatch::TestRequest.create + req.request_method # to reproduce bug caused by memoization + req.request_method = "POST" + assert_equal "POST", req.request_method end test "setter methods" do req = ActionDispatch::TestRequest.create({}) - get = 'GET' + get = "GET" [ - 'request_method=', 'host=', 'request_uri=', 'path=', 'if_modified_since=', 'if_none_match=', - 'remote_addr=', 'user_agent=', 'accept=' + "request_method=", "host=", "request_uri=", "path=", "if_modified_since=", "if_none_match=", + "remote_addr=", "user_agent=", "accept=" ].each do |method| req.send(method, get) end req.port = 8080 - req.accept = 'hello goodbye' - - assert_equal(get, req.get_header('REQUEST_METHOD')) - assert_equal(get, req.get_header('HTTP_HOST')) - assert_equal(8080, req.get_header('SERVER_PORT')) - assert_equal(get, req.get_header('REQUEST_URI')) - assert_equal(get, req.get_header('PATH_INFO')) - assert_equal(get, req.get_header('HTTP_IF_MODIFIED_SINCE')) - assert_equal(get, req.get_header('HTTP_IF_NONE_MATCH')) - assert_equal(get, req.get_header('REMOTE_ADDR')) - assert_equal(get, req.get_header('HTTP_USER_AGENT')) - assert_nil(req.get_header('action_dispatch.request.accepts')) - assert_equal('hello goodbye', req.get_header('HTTP_ACCEPT')) + req.accept = "hello goodbye" + + assert_equal(get, req.get_header("REQUEST_METHOD")) + assert_equal(get, req.get_header("HTTP_HOST")) + assert_equal(8080, req.get_header("SERVER_PORT")) + assert_equal(get, req.get_header("REQUEST_URI")) + assert_equal(get, req.get_header("PATH_INFO")) + assert_equal(get, req.get_header("HTTP_IF_MODIFIED_SINCE")) + assert_equal(get, req.get_header("HTTP_IF_NONE_MATCH")) + assert_equal(get, req.get_header("REMOTE_ADDR")) + assert_equal(get, req.get_header("HTTP_USER_AGENT")) + assert_nil(req.get_header("action_dispatch.request.accepts")) + assert_equal("hello goodbye", req.get_header("HTTP_ACCEPT")) end private diff --git a/actionpack/test/dispatch/test_response_test.rb b/actionpack/test/dispatch/test_response_test.rb index a4f9d56a6a..98eafb5119 100644 --- a/actionpack/test/dispatch/test_response_test.rb +++ b/actionpack/test/dispatch/test_response_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TestResponseTest < ActiveSupport::TestCase def assert_response_code_range(range, predicate) @@ -17,4 +17,12 @@ class TestResponseTest < ActiveSupport::TestCase assert_response_code_range 500..599, :server_error? assert_response_code_range 400..499, :client_error? end + + test "response parsing" do + response = ActionDispatch::TestResponse.create(200, {}, "") + assert_equal response.body, response.parsed_body + + response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '{ "foo": "fighters" }') + assert_equal({ "foo" => "fighters" }, response.parsed_body) + end end diff --git a/actionpack/test/dispatch/uploaded_file_test.rb b/actionpack/test/dispatch/uploaded_file_test.rb index 55ebbd5143..60d0246a68 100644 --- a/actionpack/test/dispatch/uploaded_file_test.rb +++ b/actionpack/test/dispatch/uploaded_file_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch class UploadedFileTest < ActiveSupport::TestCase @@ -9,81 +9,81 @@ module ActionDispatch end def test_original_filename - uf = Http::UploadedFile.new(:filename => 'foo', :tempfile => Object.new) - assert_equal 'foo', uf.original_filename + uf = Http::UploadedFile.new(filename: "foo", tempfile: Object.new) + assert_equal "foo", uf.original_filename end def test_filename_should_be_in_utf_8 - uf = Http::UploadedFile.new(:filename => 'foo', :tempfile => Object.new) + uf = Http::UploadedFile.new(filename: "foo", tempfile: Object.new) assert_equal "UTF-8", uf.original_filename.encoding.to_s end def test_filename_should_always_be_in_utf_8 - uf = Http::UploadedFile.new(:filename => 'foo'.encode(Encoding::SHIFT_JIS), - :tempfile => Object.new) + uf = Http::UploadedFile.new(filename: "foo".encode(Encoding::SHIFT_JIS), + tempfile: Object.new) assert_equal "UTF-8", uf.original_filename.encoding.to_s end def test_content_type - uf = Http::UploadedFile.new(:type => 'foo', :tempfile => Object.new) - assert_equal 'foo', uf.content_type + uf = Http::UploadedFile.new(type: "foo", tempfile: Object.new) + assert_equal "foo", uf.content_type end def test_headers - uf = Http::UploadedFile.new(:head => 'foo', :tempfile => Object.new) - assert_equal 'foo', uf.headers + uf = Http::UploadedFile.new(head: "foo", tempfile: Object.new) + assert_equal "foo", uf.headers end def test_tempfile - uf = Http::UploadedFile.new(:tempfile => 'foo') - assert_equal 'foo', uf.tempfile + uf = Http::UploadedFile.new(tempfile: "foo") + assert_equal "foo", uf.tempfile end def test_to_io_returns_the_tempfile tf = Object.new - uf = Http::UploadedFile.new(:tempfile => tf) + uf = Http::UploadedFile.new(tempfile: tf) assert_equal tf, uf.to_io end def test_delegates_path_to_tempfile - tf = Class.new { def path; 'thunderhorse' end } - uf = Http::UploadedFile.new(:tempfile => tf.new) - assert_equal 'thunderhorse', uf.path + tf = Class.new { def path; "thunderhorse" end } + uf = Http::UploadedFile.new(tempfile: tf.new) + assert_equal "thunderhorse", uf.path end def test_delegates_open_to_tempfile - tf = Class.new { def open; 'thunderhorse' end } - uf = Http::UploadedFile.new(:tempfile => tf.new) - assert_equal 'thunderhorse', uf.open + tf = Class.new { def open; "thunderhorse" end } + uf = Http::UploadedFile.new(tempfile: tf.new) + assert_equal "thunderhorse", uf.open end def test_delegates_close_to_tempfile - tf = Class.new { def close(unlink_now=false); 'thunderhorse' end } - uf = Http::UploadedFile.new(:tempfile => tf.new) - assert_equal 'thunderhorse', uf.close + tf = Class.new { def close(unlink_now=false); "thunderhorse" end } + uf = Http::UploadedFile.new(tempfile: tf.new) + assert_equal "thunderhorse", uf.close end def test_close_accepts_parameter tf = Class.new { def close(unlink_now=false); "thunderhorse: #{unlink_now}" end } - uf = Http::UploadedFile.new(:tempfile => tf.new) - assert_equal 'thunderhorse: true', uf.close(true) + uf = Http::UploadedFile.new(tempfile: tf.new) + assert_equal "thunderhorse: true", uf.close(true) end def test_delegates_read_to_tempfile - tf = Class.new { def read(length=nil, buffer=nil); 'thunderhorse' end } - uf = Http::UploadedFile.new(:tempfile => tf.new) - assert_equal 'thunderhorse', uf.read + tf = Class.new { def read(length=nil, buffer=nil); "thunderhorse" end } + uf = Http::UploadedFile.new(tempfile: tf.new) + assert_equal "thunderhorse", uf.read end def test_delegates_read_to_tempfile_with_params tf = Class.new { def read(length=nil, buffer=nil); [length, buffer] end } - uf = Http::UploadedFile.new(:tempfile => tf.new) + uf = Http::UploadedFile.new(tempfile: tf.new) assert_equal %w{ thunder horse }, uf.read(*%w{ thunder horse }) end def test_delegate_respects_respond_to? tf = Class.new { def read; yield end; private :read } - uf = Http::UploadedFile.new(:tempfile => tf.new) + uf = Http::UploadedFile.new(tempfile: tf.new) assert_raises(NoMethodError) do uf.read end @@ -91,15 +91,15 @@ module ActionDispatch def test_delegate_eof_to_tempfile tf = Class.new { def eof?; true end; } - uf = Http::UploadedFile.new(:tempfile => tf.new) + uf = Http::UploadedFile.new(tempfile: tf.new) assert uf.eof? end def test_respond_to? tf = Class.new { def read; yield end } - uf = Http::UploadedFile.new(:tempfile => tf.new) - assert uf.respond_to?(:headers), 'responds to headers' - assert uf.respond_to?(:read), 'responds to read' + uf = Http::UploadedFile.new(tempfile: tf.new) + assert uf.respond_to?(:headers), "responds to headers" + assert uf.respond_to?(:read), "responds to read" end end end diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index 8c9782bb90..5d81fd6834 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module TestUrlGeneration class WithMountPoint < ActionDispatch::IntegrationTest @@ -13,11 +13,11 @@ module TestUrlGeneration end Routes.draw do - get "/foo", :to => "my_route_generating#index", :as => :foo + get "/foo", to: "my_route_generating#index", as: :foo resources :bars - mount MyRouteGeneratingController.action(:index), at: '/bar' + mount MyRouteGeneratingController.action(:index), at: "/bar" end APP = build_app Routes @@ -35,22 +35,22 @@ module TestUrlGeneration end test "accepting a :script_name option" do - assert_equal "/bar/foo", foo_path(:script_name => "/bar") + assert_equal "/bar/foo", foo_path(script_name: "/bar") end test "the request's SCRIPT_NAME takes precedence over the route" do - get "/foo", headers: { 'SCRIPT_NAME' => "/new", 'action_dispatch.routes' => Routes } + get "/foo", headers: { "SCRIPT_NAME" => "/new", "action_dispatch.routes" => Routes } assert_equal "/new/foo", response.body end test "the request's SCRIPT_NAME wraps the mounted app's" do - get '/new/bar/foo', headers: { 'SCRIPT_NAME' => '/new', 'PATH_INFO' => '/bar/foo', 'action_dispatch.routes' => Routes } + get "/new/bar/foo", headers: { "SCRIPT_NAME" => "/new", "PATH_INFO" => "/bar/foo", "action_dispatch.routes" => Routes } assert_equal "/new/bar/foo", response.body end test "handling http protocol with https set" do https! - assert_equal "http://www.example.com/foo", foo_url(:protocol => "http") + assert_equal "http://www.example.com/foo", foo_url(protocol: "http") end test "extracting protocol from host when protocol not present" do @@ -117,25 +117,23 @@ module TestUrlGeneration test "generating URLs with trailing slashes" do assert_equal "/bars.json", bars_path( trailing_slash: true, - format: 'json' + format: "json" ) end test "generating URLS with querystring and trailing slashes" do assert_equal "/bars.json?a=b", bars_path( trailing_slash: true, - a: 'b', - format: 'json' + a: "b", + format: "json" ) end test "generating URLS with empty querystring" do assert_equal "/bars.json", bars_path( a: {}, - format: 'json' + format: "json" ) end - end end - diff --git a/actionpack/test/fixtures/company.rb b/actionpack/test/fixtures/company.rb index f3ac3642fa..9f527acdd8 100644 --- a/actionpack/test/fixtures/company.rb +++ b/actionpack/test/fixtures/company.rb @@ -4,6 +4,6 @@ class Company < ActiveRecord::Base validates_presence_of :name def validate - errors.add('rating', 'rating should not be 2') if rating == 2 + errors.add("rating", "rating should not be 2") if rating == 2 end end diff --git a/actionpack/test/fixtures/helpers/fun/games_helper.rb b/actionpack/test/fixtures/helpers/fun/games_helper.rb index 3b7adce086..2d5e50f5a5 100644 --- a/actionpack/test/fixtures/helpers/fun/games_helper.rb +++ b/actionpack/test/fixtures/helpers/fun/games_helper.rb @@ -2,4 +2,4 @@ module Fun module GamesHelper def stratego() "Iz guuut!" end end -end
\ No newline at end of file +end diff --git a/actionpack/test/fixtures/helpers/fun/pdf_helper.rb b/actionpack/test/fixtures/helpers/fun/pdf_helper.rb index 0171be8500..16057fd466 100644 --- a/actionpack/test/fixtures/helpers/fun/pdf_helper.rb +++ b/actionpack/test/fixtures/helpers/fun/pdf_helper.rb @@ -1,5 +1,5 @@ module Fun module PdfHelper - def foobar() 'baz' end + def foobar() "baz" end end end diff --git a/actionpack/test/fixtures/helpers/just_me_helper.rb b/actionpack/test/fixtures/helpers/just_me_helper.rb index b140a7b9b4..9b43fc6d49 100644 --- a/actionpack/test/fixtures/helpers/just_me_helper.rb +++ b/actionpack/test/fixtures/helpers/just_me_helper.rb @@ -1,3 +1,3 @@ module JustMeHelper def me() "mine!" end -end
\ No newline at end of file +end diff --git a/actionpack/test/fixtures/helpers/me_too_helper.rb b/actionpack/test/fixtures/helpers/me_too_helper.rb index ce56042143..8e312e7cd0 100644 --- a/actionpack/test/fixtures/helpers/me_too_helper.rb +++ b/actionpack/test/fixtures/helpers/me_too_helper.rb @@ -1,3 +1,3 @@ module MeTooHelper def me() "me too!" end -end
\ No newline at end of file +end diff --git a/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb index 7d2326e04d..64aa1a0476 100644 --- a/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb +++ b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb @@ -2,4 +2,3 @@ module Admin module UsersHelpeR end end - diff --git a/actionpack/test/fixtures/load_me.rb b/actionpack/test/fixtures/load_me.rb new file mode 100644 index 0000000000..e516512a4e --- /dev/null +++ b/actionpack/test/fixtures/load_me.rb @@ -0,0 +1,2 @@ +class LoadMe +end diff --git a/actionpack/test/fixtures/multipart/mona_lisa.jpg b/actionpack/test/fixtures/multipart/mona_lisa.jpg Binary files differdeleted file mode 100644 index 5cf3bef3d0..0000000000 --- a/actionpack/test/fixtures/multipart/mona_lisa.jpg +++ /dev/null diff --git a/actionpack/test/fixtures/multipart/ruby_on_rails.jpg b/actionpack/test/fixtures/multipart/ruby_on_rails.jpg Binary files differnew file mode 100644 index 0000000000..ed284ea0ba --- /dev/null +++ b/actionpack/test/fixtures/multipart/ruby_on_rails.jpg diff --git a/actionpack/test/fixtures/namespaced/implicit_render_test/hello_world.erb b/actionpack/test/fixtures/namespaced/implicit_render_test/hello_world.erb new file mode 100644 index 0000000000..cd0875583a --- /dev/null +++ b/actionpack/test/fixtures/namespaced/implicit_render_test/hello_world.erb @@ -0,0 +1 @@ +Hello world! diff --git a/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb b/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb index 4ee7a24561..cd0be6d1b5 100644 --- a/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb +++ b/actionpack/test/fixtures/session_autoload_test/session_autoload_test/foo.rb @@ -1,6 +1,6 @@ module SessionAutoloadTest class Foo - def initialize(bar='baz') + def initialize(bar="baz") @bar = bar end def inspect diff --git a/actionpack/test/fixtures/test/with_implicit_template.erb b/actionpack/test/fixtures/test/with_implicit_template.erb new file mode 100644 index 0000000000..474488cd13 --- /dev/null +++ b/actionpack/test/fixtures/test/with_implicit_template.erb @@ -0,0 +1 @@ +Hello explicitly! diff --git a/actionpack/test/journey/gtg/builder_test.rb b/actionpack/test/journey/gtg/builder_test.rb index c1da374007..2b314cdd4e 100644 --- a/actionpack/test/journey/gtg/builder_test.rb +++ b/actionpack/test/journey/gtg/builder_test.rb @@ -1,28 +1,28 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey module GTG class TestBuilder < ActiveSupport::TestCase def test_following_states_multi - table = tt ['a|a'] - assert_equal 1, table.move([0], 'a').length + table = tt ["a|a"] + assert_equal 1, table.move([0], "a").length end def test_following_states_multi_regexp - table = tt [':a|b'] - assert_equal 1, table.move([0], 'fooo').length - assert_equal 2, table.move([0], 'b').length + table = tt [":a|b"] + assert_equal 1, table.move([0], "fooo").length + assert_equal 2, table.move([0], "b").length end def test_multi_path - table = tt ['/:a/d', '/b/c'] + table = tt ["/:a/d", "/b/c"] [ - [1, '/'], - [2, 'b'], - [2, '/'], - [1, 'c'], + [1, "/"], + [2, "b"], + [2, "/"], + [1, "c"], ].inject([0]) { |state, (exp, sym)| new = table.move(state, sym) assert_equal exp, new.length @@ -40,7 +40,7 @@ module ActionDispatch sim = NFA::Simulator.new table - match = sim.match '/articles/new' + match = sim.match "/articles/new" assert_equal 2, match.memos.length end @@ -54,25 +54,25 @@ module ActionDispatch sim = NFA::Simulator.new table - match = sim.match '/articles/new' + match = sim.match "/articles/new" assert_equal 2, match.memos.length end private - def ast strings - parser = Journey::Parser.new - asts = strings.map { |string| - memo = Object.new - ast = parser.parse string - ast.each { |n| n.memo = memo } - ast - } - Nodes::Or.new asts - end + def ast(strings) + parser = Journey::Parser.new + asts = strings.map { |string| + memo = Object.new + ast = parser.parse string + ast.each { |n| n.memo = memo } + ast + } + Nodes::Or.new asts + end - def tt strings - Builder.new(ast(strings)).transition_table - end + def tt(strings) + Builder.new(ast(strings)).transition_table + end end end end diff --git a/actionpack/test/journey/gtg/transition_table_test.rb b/actionpack/test/journey/gtg/transition_table_test.rb index b968780d8d..4c8b5032eb 100644 --- a/actionpack/test/journey/gtg/transition_table_test.rb +++ b/actionpack/test/journey/gtg/transition_table_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/json/decoding' +require "abstract_unit" +require "active_support/json/decoding" module ActionDispatch module Journey @@ -14,9 +14,9 @@ module ActionDispatch } json = ActiveSupport::JSON.decode table.to_json - assert json['regexp_states'] - assert json['string_states'] - assert json['accepting'] + assert json["regexp_states"] + assert json["string_states"] + assert json["accepting"] end if system("dot -V 2>/dev/null") @@ -34,26 +34,26 @@ module ActionDispatch end def test_simulate_gt - sim = simulator_for ['/foo', '/bar'] - assert_match sim, '/foo' + sim = simulator_for ["/foo", "/bar"] + assert_match sim, "/foo" end def test_simulate_gt_regexp - sim = simulator_for [':foo'] - assert_match sim, 'foo' + sim = simulator_for [":foo"] + assert_match sim, "foo" end def test_simulate_gt_regexp_mix - sim = simulator_for ['/get', '/:method/foo'] - assert_match sim, '/get' - assert_match sim, '/get/foo' + sim = simulator_for ["/get", "/:method/foo"] + assert_match sim, "/get" + assert_match sim, "/get/foo" end def test_simulate_optional - sim = simulator_for ['/foo(/bar)'] - assert_match sim, '/foo' - assert_match sim, '/foo/bar' - assert_no_match sim, '/foo/' + sim = simulator_for ["/foo(/bar)"] + assert_match sim, "/foo" + assert_match sim, "/foo/bar" + assert_no_match sim, "/foo/" end def test_match_data @@ -65,10 +65,10 @@ module ActionDispatch sim = GTG::Simulator.new tt - match = sim.match '/get' + match = sim.match "/get" assert_equal [paths.first], match.memos - match = sim.match '/get/foo' + match = sim.match "/get/foo" assert_equal [paths.last], match.memos end @@ -86,29 +86,29 @@ module ActionDispatch builder = GTG::Builder.new ast sim = GTG::Simulator.new builder.transition_table - match = sim.match '/articles/new' + match = sim.match "/articles/new" assert_equal [paths[1], paths[3]], match.memos end private - def asts paths - parser = Journey::Parser.new - paths.map { |x| - ast = parser.parse x - ast.each { |n| n.memo = ast} - ast - } - end + def asts(paths) + parser = Journey::Parser.new + paths.map { |x| + ast = parser.parse x + ast.each { |n| n.memo = ast } + ast + } + end - def tt paths - x = asts paths - builder = GTG::Builder.new Nodes::Or.new x - builder.transition_table - end + def tt(paths) + x = asts paths + builder = GTG::Builder.new Nodes::Or.new x + builder.transition_table + end - def simulator_for paths - GTG::Simulator.new tt(paths) - end + def simulator_for(paths) + GTG::Simulator.new tt(paths) + end end end end diff --git a/actionpack/test/journey/nfa/simulator_test.rb b/actionpack/test/journey/nfa/simulator_test.rb index 673a491fe5..183c892a53 100644 --- a/actionpack/test/journey/nfa/simulator_test.rb +++ b/actionpack/test/journey/nfa/simulator_test.rb @@ -1,47 +1,47 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey module NFA class TestSimulator < ActiveSupport::TestCase def test_simulate_simple - sim = simulator_for ['/foo'] - assert_match sim, '/foo' + sim = simulator_for ["/foo"] + assert_match sim, "/foo" end def test_simulate_simple_no_match - sim = simulator_for ['/foo'] - assert_no_match sim, 'foo' + sim = simulator_for ["/foo"] + assert_no_match sim, "foo" end def test_simulate_simple_no_match_too_long - sim = simulator_for ['/foo'] - assert_no_match sim, '/foo/bar' + sim = simulator_for ["/foo"] + assert_no_match sim, "/foo/bar" end def test_simulate_simple_no_match_wrong_string - sim = simulator_for ['/foo'] - assert_no_match sim, '/bar' + sim = simulator_for ["/foo"] + assert_no_match sim, "/bar" end def test_simulate_regex - sim = simulator_for ['/:foo/bar'] - assert_match sim, '/bar/bar' - assert_match sim, '/foo/bar' + sim = simulator_for ["/:foo/bar"] + assert_match sim, "/bar/bar" + assert_match sim, "/foo/bar" end def test_simulate_or - sim = simulator_for ['/foo', '/bar'] - assert_match sim, '/bar' - assert_match sim, '/foo' - assert_no_match sim, '/baz' + sim = simulator_for ["/foo", "/bar"] + assert_match sim, "/bar" + assert_match sim, "/foo" + assert_no_match sim, "/baz" end def test_simulate_optional - sim = simulator_for ['/foo(/bar)'] - assert_match sim, '/foo' - assert_match sim, '/foo/bar' - assert_no_match sim, '/foo/' + sim = simulator_for ["/foo(/bar)"] + assert_match sim, "/foo" + assert_match sim, "/foo/bar" + assert_no_match sim, "/foo/" end def test_matchdata_has_memos @@ -49,7 +49,7 @@ module ActionDispatch parser = Journey::Parser.new asts = paths.map { |x| ast = parser.parse x - ast.each { |n| n.memo = ast} + ast.each { |n| n.memo = ast } ast } @@ -59,17 +59,17 @@ module ActionDispatch sim = Simulator.new builder.transition_table - md = sim.match '/foo' + md = sim.match "/foo" assert_equal [expected], md.memos end def test_matchdata_memos_on_merge parser = Journey::Parser.new routes = [ - '/articles(.:format)', - '/articles/new(.:format)', - '/articles/:id/edit(.:format)', - '/articles/:id(.:format)', + "/articles(.:format)", + "/articles/new(.:format)", + "/articles/:id/edit(.:format)", + "/articles/:id(.:format)", ].map { |path| ast = parser.parse path ast.each { |n| n.memo = ast } @@ -82,11 +82,11 @@ module ActionDispatch nfa = Journey::NFA::Builder.new ast sim = Simulator.new nfa.transition_table - md = sim.match '/articles' + md = sim.match "/articles" assert_equal [asts.first], md.memos end - def simulator_for paths + def simulator_for(paths) parser = Journey::Parser.new asts = paths.map { |x| parser.parse x } builder = Builder.new Nodes::Or.new asts diff --git a/actionpack/test/journey/nfa/transition_table_test.rb b/actionpack/test/journey/nfa/transition_table_test.rb index 1248082c03..f3cf36a064 100644 --- a/actionpack/test/journey/nfa/transition_table_test.rb +++ b/actionpack/test/journey/nfa/transition_table_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey @@ -9,63 +9,63 @@ module ActionDispatch end def test_eclosure - table = tt '/' + table = tt "/" assert_equal [0], table.eclosure(0) - table = tt ':a|:b' + table = tt ":a|:b" assert_equal 3, table.eclosure(0).length - table = tt '(:a|:b)' + table = tt "(:a|:b)" assert_equal 5, table.eclosure(0).length assert_equal 5, table.eclosure([0]).length end def test_following_states_one - table = tt '/' + table = tt "/" - assert_equal [1], table.following_states(0, '/') - assert_equal [1], table.following_states([0], '/') + assert_equal [1], table.following_states(0, "/") + assert_equal [1], table.following_states([0], "/") end def test_following_states_group - table = tt 'a|b' + table = tt "a|b" states = table.eclosure 0 - assert_equal 1, table.following_states(states, 'a').length - assert_equal 1, table.following_states(states, 'b').length + assert_equal 1, table.following_states(states, "a").length + assert_equal 1, table.following_states(states, "b").length end def test_following_states_multi - table = tt 'a|a' + table = tt "a|a" states = table.eclosure 0 - assert_equal 2, table.following_states(states, 'a').length - assert_equal 0, table.following_states(states, 'b').length + assert_equal 2, table.following_states(states, "a").length + assert_equal 0, table.following_states(states, "b").length end def test_following_states_regexp - table = tt 'a|:a' + table = tt "a|:a" states = table.eclosure 0 - assert_equal 1, table.following_states(states, 'a').length + assert_equal 1, table.following_states(states, "a").length assert_equal 1, table.following_states(states, /[^\.\/\?]+/).length - assert_equal 0, table.following_states(states, 'b').length + assert_equal 0, table.following_states(states, "b").length end def test_alphabet - table = tt 'a|:a' - assert_equal [/[^\.\/\?]+/, 'a'], table.alphabet + table = tt "a|:a" + assert_equal [/[^\.\/\?]+/, "a"], table.alphabet - table = tt 'a|a' - assert_equal ['a'], table.alphabet + table = tt "a|a" + assert_equal ["a"], table.alphabet end private - def tt string - ast = @parser.parse string - builder = Builder.new ast - builder.transition_table - end + def tt(string) + ast = @parser.parse string + builder = Builder.new ast + builder.transition_table + end end end end diff --git a/actionpack/test/journey/nodes/symbol_test.rb b/actionpack/test/journey/nodes/symbol_test.rb index adf85b860c..baf60f40b8 100644 --- a/actionpack/test/journey/nodes/symbol_test.rb +++ b/actionpack/test/journey/nodes/symbol_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey diff --git a/actionpack/test/journey/path/pattern_test.rb b/actionpack/test/journey/path/pattern_test.rb index 72858f5eda..d61a8c023a 100644 --- a/actionpack/test/journey/path/pattern_test.rb +++ b/actionpack/test/journey/path/pattern_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey @@ -8,22 +8,22 @@ module ActionDispatch x = /.+/ { - '/:controller(/:action)' => %r{\A/(#{x})(?:/([^/.?]+))?\Z}, - '/:controller/foo' => %r{\A/(#{x})/foo\Z}, - '/:controller/:action' => %r{\A/(#{x})/([^/.?]+)\Z}, - '/:controller' => %r{\A/(#{x})\Z}, - '/:controller(/:action(/:id))' => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z}, - '/:controller/:action.xml' => %r{\A/(#{x})/([^/.?]+)\.xml\Z}, - '/:controller.:format' => %r{\A/(#{x})\.([^/.?]+)\Z}, - '/:controller(.:format)' => %r{\A/(#{x})(?:\.([^/.?]+))?\Z}, - '/:controller/*foo' => %r{\A/(#{x})/(.+)\Z}, - '/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar\Z}, - '/:foo|*bar' => %r{\A/(?:([^/.?]+)|(.+))\Z}, + "/:controller(/:action)" => %r{\A/(#{x})(?:/([^/.?]+))?\Z}, + "/:controller/foo" => %r{\A/(#{x})/foo\Z}, + "/:controller/:action" => %r{\A/(#{x})/([^/.?]+)\Z}, + "/:controller" => %r{\A/(#{x})\Z}, + "/:controller(/:action(/:id))" => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z}, + "/:controller/:action.xml" => %r{\A/(#{x})/([^/.?]+)\.xml\Z}, + "/:controller.:format" => %r{\A/(#{x})\.([^/.?]+)\Z}, + "/:controller(.:format)" => %r{\A/(#{x})(?:\.([^/.?]+))?\Z}, + "/:controller/*foo" => %r{\A/(#{x})/(.+)\Z}, + "/:controller/*foo/bar" => %r{\A/(#{x})/(.+)/bar\Z}, + "/:foo|*bar" => %r{\A/(?:([^/.?]+)|(.+))\Z}, }.each do |path, expected| define_method(:"test_to_regexp_#{path}") do path = Pattern.build( path, - { :controller => /.+/ }, + { controller: /.+/ }, SEPARATORS, true ) @@ -32,22 +32,22 @@ module ActionDispatch end { - '/:controller(/:action)' => %r{\A/(#{x})(?:/([^/.?]+))?}, - '/:controller/foo' => %r{\A/(#{x})/foo}, - '/:controller/:action' => %r{\A/(#{x})/([^/.?]+)}, - '/:controller' => %r{\A/(#{x})}, - '/:controller(/:action(/:id))' => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?}, - '/:controller/:action.xml' => %r{\A/(#{x})/([^/.?]+)\.xml}, - '/:controller.:format' => %r{\A/(#{x})\.([^/.?]+)}, - '/:controller(.:format)' => %r{\A/(#{x})(?:\.([^/.?]+))?}, - '/:controller/*foo' => %r{\A/(#{x})/(.+)}, - '/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar}, - '/:foo|*bar' => %r{\A/(?:([^/.?]+)|(.+))}, + "/:controller(/:action)" => %r{\A/(#{x})(?:/([^/.?]+))?}, + "/:controller/foo" => %r{\A/(#{x})/foo}, + "/:controller/:action" => %r{\A/(#{x})/([^/.?]+)}, + "/:controller" => %r{\A/(#{x})}, + "/:controller(/:action(/:id))" => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?}, + "/:controller/:action.xml" => %r{\A/(#{x})/([^/.?]+)\.xml}, + "/:controller.:format" => %r{\A/(#{x})\.([^/.?]+)}, + "/:controller(.:format)" => %r{\A/(#{x})(?:\.([^/.?]+))?}, + "/:controller/*foo" => %r{\A/(#{x})/(.+)}, + "/:controller/*foo/bar" => %r{\A/(#{x})/(.+)/bar}, + "/:foo|*bar" => %r{\A/(?:([^/.?]+)|(.+))}, }.each do |path, expected| define_method(:"test_to_non_anchored_regexp_#{path}") do path = Pattern.build( path, - { :controller => /.+/ }, + { controller: /.+/ }, SEPARATORS, false ) @@ -56,21 +56,21 @@ module ActionDispatch end { - '/:controller(/:action)' => %w{ controller action }, - '/:controller/foo' => %w{ controller }, - '/:controller/:action' => %w{ controller action }, - '/:controller' => %w{ controller }, - '/:controller(/:action(/:id))' => %w{ controller action id }, - '/:controller/:action.xml' => %w{ controller action }, - '/:controller.:format' => %w{ controller format }, - '/:controller(.:format)' => %w{ controller format }, - '/:controller/*foo' => %w{ controller foo }, - '/:controller/*foo/bar' => %w{ controller foo }, + "/:controller(/:action)" => %w{ controller action }, + "/:controller/foo" => %w{ controller }, + "/:controller/:action" => %w{ controller action }, + "/:controller" => %w{ controller }, + "/:controller(/:action(/:id))" => %w{ controller action id }, + "/:controller/:action.xml" => %w{ controller action }, + "/:controller.:format" => %w{ controller format }, + "/:controller(.:format)" => %w{ controller format }, + "/:controller/*foo" => %w{ controller foo }, + "/:controller/*foo/bar" => %w{ controller foo }, }.each do |path, expected| define_method(:"test_names_#{path}") do path = Pattern.build( path, - { :controller => /.+/ }, + { controller: /.+/ }, SEPARATORS, true ) @@ -80,8 +80,8 @@ module ActionDispatch def test_to_regexp_with_extended_group path = Pattern.build( - '/page/:name', - { :name => / + "/page/:name", + { name: / #ROFL (tender|love #MAO @@ -89,16 +89,16 @@ module ActionDispatch SEPARATORS, true ) - assert_match(path, '/page/tender') - assert_match(path, '/page/love') - assert_no_match(path, '/page/loving') + assert_match(path, "/page/tender") + assert_match(path, "/page/love") + assert_no_match(path, "/page/loving") end def test_optional_names [ - ['/:foo(/:bar(/:baz))', %w{ bar baz }], - ['/:foo(/:bar)', %w{ bar }], - ['/:foo(/:bar)/:lol(/:baz)', %w{ bar baz }], + ["/:foo(/:bar(/:baz))", %w{ bar baz }], + ["/:foo(/:bar)", %w{ bar }], + ["/:foo(/:bar)/:lol(/:baz)", %w{ bar baz }], ].each do |pattern, list| path = Pattern.from_string pattern assert_equal list.sort, path.optional_names.sort @@ -107,31 +107,31 @@ module ActionDispatch def test_to_regexp_match_non_optional path = Pattern.build( - '/:name', - { :name => /\d+/ }, + "/:name", + { name: /\d+/ }, SEPARATORS, true ) - assert_match(path, '/123') - assert_no_match(path, '/') + assert_match(path, "/123") + assert_no_match(path, "/") end def test_to_regexp_with_group path = Pattern.build( - '/page/:name', - { :name => /(tender|love)/ }, + "/page/:name", + { name: /(tender|love)/ }, SEPARATORS, true ) - assert_match(path, '/page/tender') - assert_match(path, '/page/love') - assert_no_match(path, '/page/loving') + assert_match(path, "/page/tender") + assert_match(path, "/page/love") + assert_no_match(path, "/page/loving") end def test_ast_sets_regular_expressions - requirements = { :name => /(tender|love)/, :value => /./ } + requirements = { name: /(tender|love)/, value: /./ } path = Pattern.build( - '/page/:name/:value', + "/page/:name/:value", requirements, SEPARATORS, true @@ -146,26 +146,26 @@ module ActionDispatch def test_match_data_with_group path = Pattern.build( - '/page/:name', - { :name => /(tender|love)/ }, + "/page/:name", + { name: /(tender|love)/ }, SEPARATORS, true ) - match = path.match '/page/tender' - assert_equal 'tender', match[1] + match = path.match "/page/tender" + assert_equal "tender", match[1] assert_equal 2, match.length end def test_match_data_with_multi_group path = Pattern.build( - '/page/:name/:id', - { :name => /t(((ender|love)))()/ }, + "/page/:name/:id", + { name: /t(((ender|love)))()/ }, SEPARATORS, true ) - match = path.match '/page/tender/10' - assert_equal 'tender', match[1] - assert_equal '10', match[2] + match = path.match "/page/tender/10" + assert_equal "tender", match[1] + assert_equal "10", match[2] assert_equal 3, match.length assert_equal %w{ tender 10 }, match.captures end @@ -173,8 +173,8 @@ module ActionDispatch def test_star_with_custom_re z = /\d+/ path = Pattern.build( - '/page/*foo', - { :foo => z }, + "/page/*foo", + { foo: z }, SEPARATORS, true ) @@ -183,76 +183,76 @@ module ActionDispatch def test_insensitive_regexp_with_group path = Pattern.build( - '/page/:name/aaron', - { :name => /(tender|love)/i }, + "/page/:name/aaron", + { name: /(tender|love)/i }, SEPARATORS, true ) - assert_match(path, '/page/TENDER/aaron') - assert_match(path, '/page/loVE/aaron') - assert_no_match(path, '/page/loVE/AAron') + assert_match(path, "/page/TENDER/aaron") + assert_match(path, "/page/loVE/aaron") + assert_no_match(path, "/page/loVE/AAron") end def test_to_regexp_with_strexp - path = Pattern.build('/:controller', { }, SEPARATORS, true) + path = Pattern.build("/:controller", {}, SEPARATORS, true) x = %r{\A/([^/.?]+)\Z} assert_equal(x.source, path.source) end def test_to_regexp_defaults - path = Pattern.from_string '/:controller(/:action(/:id))' + path = Pattern.from_string "/:controller(/:action(/:id))" expected = %r{\A/([^/.?]+)(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z} assert_equal expected, path.to_regexp end def test_failed_match - path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' - uri = 'content' + path = Pattern.from_string "/:controller(/:action(/:id(.:format)))" + uri = "content" assert_not path =~ uri end def test_match_controller - path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' - uri = '/content' + path = Pattern.from_string "/:controller(/:action(/:id(.:format)))" + uri = "/content" match = path =~ uri assert_equal %w{ controller action id format }, match.names - assert_equal 'content', match[1] + assert_equal "content", match[1] assert_nil match[2] assert_nil match[3] assert_nil match[4] end def test_match_controller_action - path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' - uri = '/content/list' + path = Pattern.from_string "/:controller(/:action(/:id(.:format)))" + uri = "/content/list" match = path =~ uri assert_equal %w{ controller action id format }, match.names - assert_equal 'content', match[1] - assert_equal 'list', match[2] + assert_equal "content", match[1] + assert_equal "list", match[2] assert_nil match[3] assert_nil match[4] end def test_match_controller_action_id - path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' - uri = '/content/list/10' + path = Pattern.from_string "/:controller(/:action(/:id(.:format)))" + uri = "/content/list/10" match = path =~ uri assert_equal %w{ controller action id format }, match.names - assert_equal 'content', match[1] - assert_equal 'list', match[2] - assert_equal '10', match[3] + assert_equal "content", match[1] + assert_equal "list", match[2] + assert_equal "10", match[3] assert_nil match[4] end def test_match_literal path = Path::Pattern.from_string "/books(/:action(.:format))" - uri = '/books' + uri = "/books" match = path =~ uri assert_equal %w{ action format }, match.names assert_nil match[1] @@ -262,21 +262,21 @@ module ActionDispatch def test_match_literal_with_action path = Path::Pattern.from_string "/books(/:action(.:format))" - uri = '/books/list' + uri = "/books/list" match = path =~ uri assert_equal %w{ action format }, match.names - assert_equal 'list', match[1] + assert_equal "list", match[1] assert_nil match[2] end def test_match_literal_with_action_and_format path = Path::Pattern.from_string "/books(/:action(.:format))" - uri = '/books/list.rss' + uri = "/books/list.rss" match = path =~ uri assert_equal %w{ action format }, match.names - assert_equal 'list', match[1] - assert_equal 'rss', match[2] + assert_equal "list", match[1] + assert_equal "rss", match[2] end end end diff --git a/actionpack/test/journey/route/definition/parser_test.rb b/actionpack/test/journey/route/definition/parser_test.rb index d7d7172a40..8c6e3c0371 100644 --- a/actionpack/test/journey/route/definition/parser_test.rb +++ b/actionpack/test/journey/route/definition/parser_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey @@ -9,88 +9,88 @@ module ActionDispatch end def test_slash - assert_equal :SLASH, @parser.parse('/').type - assert_round_trip '/' + assert_equal :SLASH, @parser.parse("/").type + assert_round_trip "/" end def test_segment - assert_round_trip '/foo' + assert_round_trip "/foo" end def test_segments - assert_round_trip '/foo/bar' + assert_round_trip "/foo/bar" end def test_segment_symbol - assert_round_trip '/foo/:id' + assert_round_trip "/foo/:id" end def test_symbol - assert_round_trip '/:foo' + assert_round_trip "/:foo" end def test_group - assert_round_trip '(/:foo)' + assert_round_trip "(/:foo)" end def test_groups - assert_round_trip '(/:foo)(/:bar)' + assert_round_trip "(/:foo)(/:bar)" end def test_nested_groups - assert_round_trip '(/:foo(/:bar))' + assert_round_trip "(/:foo(/:bar))" end def test_dot_symbol - assert_round_trip('.:format') + assert_round_trip(".:format") end def test_dot_literal - assert_round_trip('.xml') + assert_round_trip(".xml") end def test_segment_dot - assert_round_trip('/foo.:bar') + assert_round_trip("/foo.:bar") end def test_segment_group_dot - assert_round_trip('/foo(.:bar)') + assert_round_trip("/foo(.:bar)") end def test_segment_group - assert_round_trip('/foo(/:action)') + assert_round_trip("/foo(/:action)") end def test_segment_groups - assert_round_trip('/foo(/:action)(/:bar)') + assert_round_trip("/foo(/:action)(/:bar)") end def test_segment_nested_groups - assert_round_trip('/foo(/:action(/:bar))') + assert_round_trip("/foo(/:action(/:bar))") end def test_group_followed_by_path - assert_round_trip('/foo(/:action)/:bar') + assert_round_trip("/foo(/:action)/:bar") end def test_star - assert_round_trip('*foo') - assert_round_trip('/*foo') - assert_round_trip('/bar/*foo') - assert_round_trip('/bar/(*foo)') + assert_round_trip("*foo") + assert_round_trip("/*foo") + assert_round_trip("/bar/*foo") + assert_round_trip("/bar/(*foo)") end def test_or - assert_round_trip('a|b') - assert_round_trip('a|b|c') - assert_round_trip('(a|b)|c') - assert_round_trip('a|(b|c)') - assert_round_trip('*a|(b|c)') - assert_round_trip('*a|:b|c') + assert_round_trip("a|b") + assert_round_trip("a|b|c") + assert_round_trip("(a|b)|c") + assert_round_trip("a|(b|c)") + assert_round_trip("*a|(b|c)") + assert_round_trip("*a|:b|c") end def test_arbitrary - assert_round_trip('/bar/*foo#') + assert_round_trip("/bar/*foo#") end def test_literal_dot_paren @@ -101,7 +101,7 @@ module ActionDispatch assert_round_trip "/(:locale)(.:format)" end - def assert_round_trip str + def assert_round_trip(str) assert_equal str, @parser.parse(str).to_s end end diff --git a/actionpack/test/journey/route/definition/scanner_test.rb b/actionpack/test/journey/route/definition/scanner_test.rb index 7a510f1e07..98578ddbf1 100644 --- a/actionpack/test/journey/route/definition/scanner_test.rb +++ b/actionpack/test/journey/route/definition/scanner_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey @@ -11,44 +11,44 @@ module ActionDispatch # /page/:id(/:action)(.:format) def test_tokens [ - ['/', [[:SLASH, '/']]], - ['*omg', [[:STAR, '*omg']]], - ['/page', [[:SLASH, '/'], [:LITERAL, 'page']]], - ['/page!', [[:SLASH, '/'], [:LITERAL, 'page!']]], - ['/page$', [[:SLASH, '/'], [:LITERAL, 'page$']]], - ['/page&', [[:SLASH, '/'], [:LITERAL, 'page&']]], - ["/page'", [[:SLASH, '/'], [:LITERAL, "page'"]]], - ['/page*', [[:SLASH, '/'], [:LITERAL, 'page*']]], - ['/page+', [[:SLASH, '/'], [:LITERAL, 'page+']]], - ['/page,', [[:SLASH, '/'], [:LITERAL, 'page,']]], - ['/page;', [[:SLASH, '/'], [:LITERAL, 'page;']]], - ['/page=', [[:SLASH, '/'], [:LITERAL, 'page=']]], - ['/page@', [[:SLASH, '/'], [:LITERAL, 'page@']]], - ['/page\:', [[:SLASH, '/'], [:LITERAL, 'page:']]], - ['/page\(', [[:SLASH, '/'], [:LITERAL, 'page(']]], - ['/page\)', [[:SLASH, '/'], [:LITERAL, 'page)']]], - ['/~page', [[:SLASH, '/'], [:LITERAL, '~page']]], - ['/pa-ge', [[:SLASH, '/'], [:LITERAL, 'pa-ge']]], - ['/:page', [[:SLASH, '/'], [:SYMBOL, ':page']]], - ['/(:page)', [ - [:SLASH, '/'], - [:LPAREN, '('], - [:SYMBOL, ':page'], - [:RPAREN, ')'], + ["/", [[:SLASH, "/"]]], + ["*omg", [[:STAR, "*omg"]]], + ["/page", [[:SLASH, "/"], [:LITERAL, "page"]]], + ["/page!", [[:SLASH, "/"], [:LITERAL, "page!"]]], + ["/page$", [[:SLASH, "/"], [:LITERAL, "page$"]]], + ["/page&", [[:SLASH, "/"], [:LITERAL, "page&"]]], + ["/page'", [[:SLASH, "/"], [:LITERAL, "page'"]]], + ["/page*", [[:SLASH, "/"], [:LITERAL, "page*"]]], + ["/page+", [[:SLASH, "/"], [:LITERAL, "page+"]]], + ["/page,", [[:SLASH, "/"], [:LITERAL, "page,"]]], + ["/page;", [[:SLASH, "/"], [:LITERAL, "page;"]]], + ["/page=", [[:SLASH, "/"], [:LITERAL, "page="]]], + ["/page@", [[:SLASH, "/"], [:LITERAL, "page@"]]], + ['/page\:', [[:SLASH, "/"], [:LITERAL, "page:"]]], + ['/page\(', [[:SLASH, "/"], [:LITERAL, "page("]]], + ['/page\)', [[:SLASH, "/"], [:LITERAL, "page)"]]], + ["/~page", [[:SLASH, "/"], [:LITERAL, "~page"]]], + ["/pa-ge", [[:SLASH, "/"], [:LITERAL, "pa-ge"]]], + ["/:page", [[:SLASH, "/"], [:SYMBOL, ":page"]]], + ["/(:page)", [ + [:SLASH, "/"], + [:LPAREN, "("], + [:SYMBOL, ":page"], + [:RPAREN, ")"], ]], - ['(/:action)', [ - [:LPAREN, '('], - [:SLASH, '/'], - [:SYMBOL, ':action'], - [:RPAREN, ')'], + ["(/:action)", [ + [:LPAREN, "("], + [:SLASH, "/"], + [:SYMBOL, ":action"], + [:RPAREN, ")"], ]], - ['(())', [[:LPAREN, '('], - [:LPAREN, '('], [:RPAREN, ')'], [:RPAREN, ')']]], - ['(.:format)', [ - [:LPAREN, '('], - [:DOT, '.'], - [:SYMBOL, ':format'], - [:RPAREN, ')'], + ["(())", [[:LPAREN, "("], + [:LPAREN, "("], [:RPAREN, ")"], [:RPAREN, ")"]]], + ["(.:format)", [ + [:LPAREN, "("], + [:DOT, "."], + [:SYMBOL, ":format"], + [:RPAREN, ")"], ]], ].each do |str, expected| @scanner.scan_setup str @@ -56,7 +56,7 @@ module ActionDispatch end end - def assert_tokens tokens, scanner + def assert_tokens(tokens, scanner) toks = [] while tok = scanner.next_token toks << tok diff --git a/actionpack/test/journey/route_test.rb b/actionpack/test/journey/route_test.rb index 22c3b8113d..b6414fd101 100644 --- a/actionpack/test/journey/route_test.rb +++ b/actionpack/test/journey/route_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey class TestRoute < ActiveSupport::TestCase def test_initialize app = Object.new - path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))' + path = Path::Pattern.from_string "/:controller(/:action(/:id(.:format)))" defaults = {} route = Route.build("name", app, path, {}, [], defaults) @@ -16,7 +16,7 @@ module ActionDispatch def test_route_adds_itself_as_memo app = Object.new - path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))' + path = Path::Pattern.from_string "/:controller(/:action(/:id(.:format)))" defaults = {} route = Route.build("name", app, path, {}, [], defaults) @@ -26,71 +26,69 @@ module ActionDispatch end def test_path_requirements_override_defaults - path = Path::Pattern.build(':name', { name: /love/ }, '/', true) - defaults = { name: 'tender' } - route = Route.build('name', nil, path, {}, [], defaults) + path = Path::Pattern.build(":name", { name: /love/ }, "/", true) + defaults = { name: "tender" } + route = Route.build("name", nil, path, {}, [], defaults) assert_equal(/love/, route.requirements[:name]) end def test_ip_address - path = Path::Pattern.from_string '/messages/:id(.:format)' - route = Route.build("name", nil, path, {:ip => '192.168.1.1'}, [], - { :controller => 'foo', :action => 'bar' }) - assert_equal '192.168.1.1', route.ip + path = Path::Pattern.from_string "/messages/:id(.:format)" + route = Route.build("name", nil, path, { ip: "192.168.1.1" }, [], + controller: "foo", action: "bar") + assert_equal "192.168.1.1", route.ip end def test_default_ip - path = Path::Pattern.from_string '/messages/:id(.:format)' + path = Path::Pattern.from_string "/messages/:id(.:format)" route = Route.build("name", nil, path, {}, [], - { :controller => 'foo', :action => 'bar' }) + controller: "foo", action: "bar") assert_equal(//, route.ip) end def test_format_with_star - path = Path::Pattern.from_string '/:controller/*extra' + path = Path::Pattern.from_string "/:controller/*extra" route = Route.build("name", nil, path, {}, [], - { :controller => 'foo', :action => 'bar' }) - assert_equal '/foo/himom', route.format({ - :controller => 'foo', - :extra => 'himom', - }) + controller: "foo", action: "bar") + assert_equal "/foo/himom", route.format( + controller: "foo", + extra: "himom") end def test_connects_all_match - path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))' - route = Route.build("name", nil, path, {:action => 'bar'}, [], { :controller => 'foo' }) - - assert_equal '/foo/bar/10', route.format({ - :controller => 'foo', - :action => 'bar', - :id => 10 - }) + path = Path::Pattern.from_string "/:controller(/:action(/:id(.:format)))" + route = Route.build("name", nil, path, { action: "bar" }, [], controller: "foo") + + assert_equal "/foo/bar/10", route.format( + controller: "foo", + action: "bar", + id: 10) end def test_extras_are_not_included_if_optional - path = Path::Pattern.from_string '/page/:id(/:action)' - route = Route.build("name", nil, path, { }, [], { :action => 'show' }) + path = Path::Pattern.from_string "/page/:id(/:action)" + route = Route.build("name", nil, path, {}, [], action: "show") - assert_equal '/page/10', route.format({ :id => 10 }) + assert_equal "/page/10", route.format(id: 10) end def test_extras_are_not_included_if_optional_with_parameter - path = Path::Pattern.from_string '(/sections/:section)/pages/:id' - route = Route.build("name", nil, path, { }, [], { :action => 'show' }) + path = Path::Pattern.from_string "(/sections/:section)/pages/:id" + route = Route.build("name", nil, path, {}, [], action: "show") - assert_equal '/pages/10', route.format({:id => 10}) + assert_equal "/pages/10", route.format(id: 10) end def test_extras_are_not_included_if_optional_parameter_is_nil - path = Path::Pattern.from_string '(/sections/:section)/pages/:id' - route = Route.build("name", nil, path, { }, [], { :action => 'show' }) + path = Path::Pattern.from_string "(/sections/:section)/pages/:id" + route = Route.build("name", nil, path, {}, [], action: "show") - assert_equal '/pages/10', route.format({:id => 10, :section => nil}) + assert_equal "/pages/10", route.format(id: 10, section: nil) end def test_score constraints = {} - defaults = {:controller=>"pages", :action=>"show"} + defaults = { controller: "pages", action: "show" } path = Path::Pattern.from_string "/page/:id(/:action)(.:format)" specific = Route.build "name", nil, path, constraints, [:controller, :action], defaults @@ -98,7 +96,7 @@ module ActionDispatch path = Path::Pattern.from_string "/:controller(/:action(/:id))(.:format)" generic = Route.build "name", nil, path, constraints, [], {} - knowledge = {:id=>20, :controller=>"pages", :action=>"show"} + knowledge = { id: 20, controller: "pages", action: "show" } routes = [specific, generic] diff --git a/actionpack/test/journey/router/utils_test.rb b/actionpack/test/journey/router/utils_test.rb index 2b505f081e..b77bf6628a 100644 --- a/actionpack/test/journey/router/utils_test.rb +++ b/actionpack/test/journey/router/utils_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb index 75caf56d32..7b5916eb72 100644 --- a/actionpack/test/journey/router_test.rb +++ b/actionpack/test/journey/router_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey @@ -15,9 +15,9 @@ module ActionDispatch end def test_dashes - get '/foo-bar-baz', to: 'foo#bar' + get "/foo-bar-baz", to: "foo#bar" - env = rails_env 'PATH_INFO' => '/foo-bar-baz' + env = rails_env "PATH_INFO" => "/foo-bar-baz" called = false router.recognize(env) do |r, params| called = true @@ -26,10 +26,10 @@ module ActionDispatch end def test_unicode - get '/ã»ã’', to: 'foo#bar' + get "/ã»ã’", to: "foo#bar" #match the escaped version of /ã»ã’ - env = rails_env 'PATH_INFO' => '/%E3%81%BB%E3%81%92' + env = rails_env "PATH_INFO" => "/%E3%81%BB%E3%81%92" called = false router.recognize(env) do |r, params| called = true @@ -38,10 +38,10 @@ module ActionDispatch end def test_regexp_first_precedence - get "/whois/:domain", :domain => /\w+\.[\w\.]+/, to: "foo#bar" + get "/whois/:domain", domain: /\w+\.[\w\.]+/, to: "foo#bar" get "/whois/:id(.:format)", to: "foo#baz" - env = rails_env 'PATH_INFO' => '/whois/example.com' + env = rails_env "PATH_INFO" => "/whois/example.com" list = [] router.recognize(env) do |r, params| @@ -51,47 +51,47 @@ module ActionDispatch r = list.first - assert_equal '/whois/:domain(.:format)', r.path.spec.to_s + assert_equal "/whois/:domain(.:format)", r.path.spec.to_s end def test_required_parts_verified_are_anchored - get "/foo/:id", :id => /\d/, anchor: false, to: "foo#bar" + get "/foo/:id", id: /\d/, anchor: false, to: "foo#bar" assert_raises(ActionController::UrlGenerationError) do - @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => '10' }, { }) + @formatter.generate(nil, { controller: "foo", action: "bar", id: "10" }, {}) end end def test_required_parts_are_verified_when_building - get "/foo/:id", :id => /\d+/, anchor: false, to: "foo#bar" + get "/foo/:id", id: /\d+/, anchor: false, to: "foo#bar" - path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => '10' }, { }) - assert_equal '/foo/10', path + path, _ = @formatter.generate(nil, { controller: "foo", action: "bar", id: "10" }, {}) + assert_equal "/foo/10", path assert_raises(ActionController::UrlGenerationError) do - @formatter.generate(nil, { :id => 'aa' }, { }) + @formatter.generate(nil, { id: "aa" }, {}) end end def test_only_required_parts_are_verified - get "/foo(/:id)", :id => /\d/, :to => "foo#bar" + get "/foo(/:id)", id: /\d/, to: "foo#bar" - path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => '10' }, { }) - assert_equal '/foo/10', path + path, _ = @formatter.generate(nil, { controller: "foo", action: "bar", id: "10" }, {}) + assert_equal "/foo/10", path - path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar" }, { }) - assert_equal '/foo', path + path, _ = @formatter.generate(nil, { controller: "foo", action: "bar" }, {}) + assert_equal "/foo", path - path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :id => 'aa' }, { }) - assert_equal '/foo/aa', path + path, _ = @formatter.generate(nil, { controller: "foo", action: "bar", id: "aa" }, {}) + assert_equal "/foo/aa", path end def test_knows_what_parts_are_missing_from_named_route route_name = "gorby_thunderhorse" - get "/foo/:id", :as => route_name, :id => /\d+/, :to => "foo#bar" + get "/foo/:id", as: route_name, id: /\d+/, to: "foo#bar" error = assert_raises(ActionController::UrlGenerationError) do - @formatter.generate(route_name, { }, { }) + @formatter.generate(route_name, {}, {}) end assert_match(/missing required keys: \[:id\]/, error.message) @@ -101,7 +101,7 @@ module ActionDispatch route_name = "gorby_thunderhorse" error = assert_raises(ActionController::UrlGenerationError) do - @formatter.generate(route_name, { }, { }) + @formatter.generate(route_name, {}, {}) end assert_no_match(/missing required keys: \[\]/, error.message) @@ -109,58 +109,58 @@ module ActionDispatch def test_X_Cascade get "/messages(.:format)", to: "foo#bar" - resp = router.serve(rails_env({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' })) - assert_equal ['Not Found'], resp.last - assert_equal 'pass', resp[1]['X-Cascade'] + resp = router.serve(rails_env("REQUEST_METHOD" => "GET", "PATH_INFO" => "/lol")) + assert_equal ["Not Found"], resp.last + assert_equal "pass", resp[1]["X-Cascade"] assert_equal 404, resp.first end def test_clear_trailing_slash_from_script_name_on_root_unanchored_routes - app = lambda { |env| [200, {}, ['success!']] } - get '/weblog', :to => app + app = lambda { |env| [200, {}, ["success!"]] } + get "/weblog", to: app - env = rack_env('SCRIPT_NAME' => '', 'PATH_INFO' => '/weblog') + env = rack_env("SCRIPT_NAME" => "", "PATH_INFO" => "/weblog") resp = route_set.call env - assert_equal ['success!'], resp.last - assert_equal '', env['SCRIPT_NAME'] + assert_equal ["success!"], resp.last + assert_equal "", env["SCRIPT_NAME"] end def test_defaults_merge_correctly - get '/foo(/:id)', to: "foo#bar", id: nil + get "/foo(/:id)", to: "foo#bar", id: nil - env = rails_env 'PATH_INFO' => '/foo/10' + env = rails_env "PATH_INFO" => "/foo/10" router.recognize(env) do |r, params| - assert_equal({:id => '10', :controller => "foo", :action => "bar"}, params) + assert_equal({ id: "10", controller: "foo", action: "bar" }, params) end - env = rails_env 'PATH_INFO' => '/foo' + env = rails_env "PATH_INFO" => "/foo" router.recognize(env) do |r, params| - assert_equal({:id => nil, :controller => "foo", :action => "bar"}, params) + assert_equal({ id: nil, controller: "foo", action: "bar" }, params) end end def test_recognize_with_unbound_regexp get "/foo", anchor: false, to: "foo#bar" - env = rails_env 'PATH_INFO' => '/foo/bar' + env = rails_env "PATH_INFO" => "/foo/bar" router.recognize(env) { |*_| } - assert_equal '/foo', env.env['SCRIPT_NAME'] - assert_equal '/bar', env.env['PATH_INFO'] + assert_equal "/foo", env.env["SCRIPT_NAME"] + assert_equal "/bar", env.env["PATH_INFO"] end def test_bound_regexp_keeps_path_info get "/foo", to: "foo#bar" - env = rails_env 'PATH_INFO' => '/foo' + env = rails_env "PATH_INFO" => "/foo" - before = env.env['SCRIPT_NAME'] + before = env.env["SCRIPT_NAME"] router.recognize(env) { |*_| } - assert_equal before, env.env['SCRIPT_NAME'] - assert_equal '/foo', env.env['PATH_INFO'] + assert_equal before, env.env["SCRIPT_NAME"] + assert_equal "/foo", env.env["PATH_INFO"] end def test_path_not_found @@ -172,7 +172,7 @@ module ActionDispatch ].each do |path| get path, to: "foo#bar" end - env = rails_env 'PATH_INFO' => '/messages/unknown/path' + env = rails_env "PATH_INFO" => "/messages/unknown/path" yielded = false router.recognize(env) do |*whatever| @@ -184,33 +184,33 @@ module ActionDispatch def test_required_part_in_recall get "/messages/:a/:b", to: "foo#bar" - path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar", :a => 'a' }, { :b => 'b' }) + path, _ = @formatter.generate(nil, { controller: "foo", action: "bar", a: "a" }, b: "b") assert_equal "/messages/a/b", path end def test_splat_in_recall get "/*path", to: "foo#bar" - path, _ = @formatter.generate(nil, { :controller => "foo", :action => "bar" }, { :path => 'b' }) + path, _ = @formatter.generate(nil, { controller: "foo", action: "bar" }, path: "b") assert_equal "/b", path end def test_recall_should_be_used_when_scoring - get "/messages/:action(/:id(.:format))", to: 'foo#bar' - get "/messages/:id(.:format)", to: 'bar#baz' + get "/messages/:action(/:id(.:format))", to: "foo#bar" + get "/messages/:id(.:format)", to: "bar#baz" - path, _ = @formatter.generate(nil, { :controller => "foo", :id => 10 }, { :action => 'index' }) + path, _ = @formatter.generate(nil, { controller: "foo", id: 10 }, action: "index") assert_equal "/messages/index/10", path end def test_nil_path_parts_are_ignored get "/:controller(/:action(.:format))", to: "tasks#lol" - params = { :controller => "tasks", :format => nil } - extras = { :action => 'lol' } + params = { controller: "tasks", format: nil } + extras = { action: "lol" } path, _ = @formatter.generate(nil, params, extras) - assert_equal '/tasks', path + assert_equal "/tasks", path end def test_generate_slash @@ -219,11 +219,11 @@ module ActionDispatch get "/", Hash[params] path, _ = @formatter.generate(nil, Hash[params], {}) - assert_equal '/', path + assert_equal "/", path end def test_generate_calls_param_proc - get '/:controller(/:action)', to: "foo#bar" + get "/:controller(/:action)", to: "foo#bar" parameterized = [] params = [ [:controller, "tasks"], @@ -239,65 +239,65 @@ module ActionDispatch end def test_generate_id - get '/:controller(/:action)', to: 'foo#bar' + get "/:controller(/:action)", to: "foo#bar" path, params = @formatter.generate( - nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {}) - assert_equal '/tasks/show', path - assert_equal({:id => 1}, params) + nil, { id: 1, controller: "tasks", action: "show" }, {}) + assert_equal "/tasks/show", path + assert_equal({ id: 1 }, params) end def test_generate_escapes - get '/:controller(/:action)', to: "foo#bar" + get "/:controller(/:action)", to: "foo#bar" path, _ = @formatter.generate(nil, - { :controller => "tasks", - :action => "a/b c+d", + { controller: "tasks", + action: "a/b c+d", }, {}) - assert_equal '/tasks/a%2Fb%20c+d', path + assert_equal "/tasks/a%2Fb%20c+d", path end def test_generate_escapes_with_namespaced_controller - get '/:controller(/:action)', to: "foo#bar" + get "/:controller(/:action)", to: "foo#bar" path, _ = @formatter.generate( - nil, { :controller => "admin/tasks", - :action => "a/b c+d", + nil, { controller: "admin/tasks", + action: "a/b c+d", }, {}) - assert_equal '/admin/tasks/a%2Fb%20c+d', path + assert_equal "/admin/tasks/a%2Fb%20c+d", path end def test_generate_extra_params - get '/:controller(/:action)', to: "foo#bar" + get "/:controller(/:action)", to: "foo#bar" path, params = @formatter.generate( - nil, { :id => 1, - :controller => "tasks", - :action => "show", - :relative_url_root => nil + nil, { id: 1, + controller: "tasks", + action: "show", + relative_url_root: nil }, {}) - assert_equal '/tasks/show', path - assert_equal({:id => 1, :relative_url_root => nil}, params) + assert_equal "/tasks/show", path + assert_equal({ id: 1, relative_url_root: nil }, params) end def test_generate_missing_keys_no_matches_different_format_keys - get '/:controller/:action/:name', to: "foo#bar" + get "/:controller/:action/:name", to: "foo#bar" primarty_parameters = { - :id => 1, - :controller => "tasks", - :action => "show", - :relative_url_root => nil + id: 1, + controller: "tasks", + action: "show", + relative_url_root: nil } redirection_parameters = { - 'action'=>'show', + "action"=>"show", } - missing_key = 'name' + missing_key = "name" missing_parameters ={ missing_key => "task_1" } request_parameters = primarty_parameters.merge(redirection_parameters).merge(missing_parameters) - message = "No route matches #{Hash[request_parameters.sort_by{|k,v|k.to_s}].inspect} missing required keys: #{[missing_key.to_sym].inspect}" + message = "No route matches #{Hash[request_parameters.sort_by { |k,v|k.to_s }].inspect}, missing required keys: #{[missing_key.to_sym].inspect}" error = assert_raises(ActionController::UrlGenerationError) do @formatter.generate( @@ -307,42 +307,42 @@ module ActionDispatch end def test_generate_uses_recall_if_needed - get '/:controller(/:action(/:id))', to: "foo#bar" + get "/:controller(/:action(/:id))", to: "foo#bar" path, params = @formatter.generate( nil, - {:controller =>"tasks", :id => 10}, - {:action =>"index"}) - assert_equal '/tasks/index/10', path + { controller: "tasks", id: 10 }, + action: "index") + assert_equal "/tasks/index/10", path assert_equal({}, params) end def test_generate_with_name - get '/:controller(/:action)', to: 'foo#bar', as: 'tasks' + get "/:controller(/:action)", to: "foo#bar", as: "tasks" path, params = @formatter.generate( "tasks", - {:controller=>"tasks"}, - {:controller=>"tasks", :action=>"index"}) - assert_equal '/tasks', path + { controller: "tasks" }, + controller: "tasks", action: "index") + assert_equal "/tasks", path assert_equal({}, params) end { - '/content' => { :controller => 'content' }, - '/content/list' => { :controller => 'content', :action => 'list' }, - '/content/show/10' => { :controller => 'content', :action => 'show', :id => "10" }, + "/content" => { controller: "content" }, + "/content/list" => { controller: "content", action: "list" }, + "/content/show/10" => { controller: "content", action: "show", id: "10" }, }.each do |request_path, expected| define_method("test_recognize_#{expected.keys.map(&:to_s).join('_')}") do - get "/:controller(/:action(/:id))", to: 'foo#bar' + get "/:controller(/:action(/:id))", to: "foo#bar" route = @routes.first - env = rails_env 'PATH_INFO' => request_path + env = rails_env "PATH_INFO" => request_path called = false router.recognize(env) do |r, params| assert_equal route, r - assert_equal({ :action => "bar" }.merge(expected), params) + assert_equal({ action: "bar" }.merge(expected), params) called = true end @@ -351,19 +351,19 @@ module ActionDispatch end { - :segment => ['/a%2Fb%20c+d/splat', { :segment => 'a/b c+d', :splat => 'splat' }], - :splat => ['/segment/a/b%20c+d', { :segment => 'segment', :splat => 'a/b c+d' }] + segment: ["/a%2Fb%20c+d/splat", { segment: "a/b c+d", splat: "splat" }], + splat: ["/segment/a/b%20c+d", { segment: "segment", splat: "a/b c+d" }] }.each do |name, (request_path, expected)| define_method("test_recognize_#{name}") do - get '/:segment/*splat', to: 'foo#bar' + get "/:segment/*splat", to: "foo#bar" - env = rails_env 'PATH_INFO' => request_path + env = rails_env "PATH_INFO" => request_path called = false route = @routes.first router.recognize(env) do |r, params| assert_equal route, r - assert_equal(expected.merge(:controller=>"foo", :action=>"bar"), params) + assert_equal(expected.merge(controller: "foo", action: "bar"), params) called = true end @@ -372,15 +372,15 @@ module ActionDispatch end def test_namespaced_controller - get "/:controller(/:action(/:id))", { :controller => /.+?/ } + get "/:controller(/:action(/:id))", controller: /.+?/ route = @routes.first - env = rails_env 'PATH_INFO' => '/admin/users/show/10' + env = rails_env "PATH_INFO" => "/admin/users/show/10" called = false expected = { - :controller => 'admin/users', - :action => 'show', - :id => '10' + controller: "admin/users", + action: "show", + id: "10" } router.recognize(env) do |r, params| @@ -395,8 +395,8 @@ module ActionDispatch get "/books(/:action(.:format))", controller: "books" route = @routes.first - env = rails_env 'PATH_INFO' => '/books/list.rss' - expected = { :controller => 'books', :action => 'list', :format => 'rss' } + env = rails_env "PATH_INFO" => "/books/list.rss" + expected = { controller: "books", action: "list", format: "rss" } called = false router.recognize(env) do |r, params| assert_equal route, r @@ -408,11 +408,11 @@ module ActionDispatch end def test_recognize_head_route - match "/books(/:action(.:format))", via: 'head', to: 'foo#bar' + match "/books(/:action(.:format))", via: "head", to: "foo#bar" env = rails_env( - 'PATH_INFO' => '/books/list.rss', - 'REQUEST_METHOD' => 'HEAD' + "PATH_INFO" => "/books/list.rss", + "REQUEST_METHOD" => "HEAD" ) called = false @@ -424,9 +424,9 @@ module ActionDispatch end def test_recognize_head_request_as_get_route - get "/books(/:action(.:format))", to: 'foo#bar' + get "/books(/:action(.:format))", to: "foo#bar" - env = rails_env 'PATH_INFO' => '/books/list.rss', + env = rails_env "PATH_INFO" => "/books/list.rss", "REQUEST_METHOD" => "HEAD" called = false @@ -440,7 +440,7 @@ module ActionDispatch def test_recognize_cares_about_get_verbs match "/books(/:action(.:format))", to: "foo#bar", via: :get - env = rails_env 'PATH_INFO' => '/books/list.rss', + env = rails_env "PATH_INFO" => "/books/list.rss", "REQUEST_METHOD" => "POST" called = false @@ -454,7 +454,7 @@ module ActionDispatch def test_recognize_cares_about_post_verbs match "/books(/:action(.:format))", to: "foo#bar", via: :post - env = rails_env 'PATH_INFO' => '/books/list.rss', + env = rails_env "PATH_INFO" => "/books/list.rss", "REQUEST_METHOD" => "POST" called = false @@ -469,7 +469,7 @@ module ActionDispatch match "/books(/:action(.:format))", to: "foo#bar", via: [:post, :get] %w( POST GET ).each do |verb| - env = rails_env 'PATH_INFO' => '/books/list.rss', + env = rails_env "PATH_INFO" => "/books/list.rss", "REQUEST_METHOD" => verb called = false @@ -480,8 +480,8 @@ module ActionDispatch assert called end - env = rails_env 'PATH_INFO' => '/books/list.rss', - "REQUEST_METHOD" => 'PUT' + env = rails_env "PATH_INFO" => "/books/list.rss", + "REQUEST_METHOD" => "PUT" called = false router.recognize(env) do |r, params| @@ -493,41 +493,41 @@ module ActionDispatch private - def get *args - ActiveSupport::Deprecation.silence do - mapper.get(*args) + def get(*args) + ActiveSupport::Deprecation.silence do + mapper.get(*args) + end end - end - def match *args - ActiveSupport::Deprecation.silence do - mapper.match(*args) + def match(*args) + ActiveSupport::Deprecation.silence do + mapper.match(*args) + end end - end - def rails_env env, klass = ActionDispatch::Request - klass.new(rack_env(env)) - end - - def rack_env env - { - "rack.version" => [1, 1], - "rack.input" => StringIO.new, - "rack.errors" => StringIO.new, - "rack.multithread" => true, - "rack.multiprocess" => true, - "rack.run_once" => false, - "REQUEST_METHOD" => "GET", - "SERVER_NAME" => "example.org", - "SERVER_PORT" => "80", - "QUERY_STRING" => "", - "PATH_INFO" => "/content", - "rack.url_scheme" => "http", - "HTTPS" => "off", - "SCRIPT_NAME" => "", - "CONTENT_LENGTH" => "0" - }.merge env - end + def rails_env(env, klass = ActionDispatch::Request) + klass.new(rack_env(env)) + end + + def rack_env(env) + { + "rack.version" => [1, 1], + "rack.input" => StringIO.new, + "rack.errors" => StringIO.new, + "rack.multithread" => true, + "rack.multiprocess" => true, + "rack.run_once" => false, + "REQUEST_METHOD" => "GET", + "SERVER_NAME" => "example.org", + "SERVER_PORT" => "80", + "QUERY_STRING" => "", + "PATH_INFO" => "/content", + "rack.url_scheme" => "http", + "HTTPS" => "off", + "SCRIPT_NAME" => "", + "CONTENT_LENGTH" => "0" + }.merge env + end end end end diff --git a/actionpack/test/journey/routes_test.rb b/actionpack/test/journey/routes_test.rb index f8293dfc5f..ca735ea022 100644 --- a/actionpack/test/journey/routes_test.rb +++ b/actionpack/test/journey/routes_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Journey @@ -14,7 +14,7 @@ module ActionDispatch end def test_clear - mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron' + mapper.get "/foo(/:id)", to: "foo#bar", as: "aaron" assert_not_predicate routes, :empty? assert_equal 1, routes.length @@ -24,35 +24,35 @@ module ActionDispatch end def test_ast - mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron' + mapper.get "/foo(/:id)", to: "foo#bar", as: "aaron" ast = routes.ast - mapper.get "/foo(/:id)", to: "foo#bar", as: 'gorby' + mapper.get "/foo(/:id)", to: "foo#bar", as: "gorby" assert_not_equal ast, routes.ast end def test_simulator_changes - mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron' + mapper.get "/foo(/:id)", to: "foo#bar", as: "aaron" sim = routes.simulator - mapper.get "/foo(/:id)", to: "foo#bar", as: 'gorby' + mapper.get "/foo(/:id)", to: "foo#bar", as: "gorby" assert_not_equal sim, routes.simulator end def test_partition_route - mapper.get "/foo(/:id)", to: "foo#bar", as: 'aaron' + mapper.get "/foo(/:id)", to: "foo#bar", as: "aaron" assert_equal 1, @routes.anchored_routes.length assert_predicate @routes.custom_routes, :empty? - mapper.get "/hello/:who", to: "foo#bar", as: 'bar', who: /\d/ + mapper.get "/hello/:who", to: "foo#bar", as: "bar", who: /\d/ assert_equal 1, @routes.custom_routes.length assert_equal 1, @routes.anchored_routes.length end def test_first_name_wins - mapper.get "/hello", to: "foo#bar", as: 'aaron' + mapper.get "/hello", to: "foo#bar", as: "aaron" assert_raise(ArgumentError) do - mapper.get "/aaron", to: "foo#bar", as: 'aaron' + mapper.get "/aaron", to: "foo#bar", as: "aaron" end end end diff --git a/actionpack/test/routing/helper_test.rb b/actionpack/test/routing/helper_test.rb index 0028aaa629..0debacedf7 100644 --- a/actionpack/test/routing/helper_test.rb +++ b/actionpack/test/routing/helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionDispatch module Routing diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 9d669c7cd8..67bd9b5c8f 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,5 +1,106 @@ +* Removed deprecated `#original_exception` in `ActionView::Template::Error`. + + *Rafael Mendonça França* + +* Render now accepts any keys for locals, including reserved words + + Only locals with valid variable names get set directly. Others + will still be available in local_assigns. + + Example of render with reserved words: + + ```erb + <%= render "example", class: "text-center", message: "Hello world!" %> + + <!-- _example.html.erb: --> + <%= tag.div class: local_assigns[:class] do %> + <p><%= message %></p> + <% end %> + ``` + + *Peter Schilling*, *Matthew Draper* + +* Show cache hits and misses when rendering partials. + + Partials using the `cache` helper will show whether a render hit or missed + the cache: + + ``` + Rendered messages/_message.html.erb in 1.2 ms [cache hit] + Rendered recordings/threads/_thread.html.erb in 1.5 ms [cache miss] + ``` + + This removes the need for the old fragment cache logging: + + ``` + Read fragment views/v1/2914079/v1/2914079/recordings/70182313-20160225015037000000/d0bdf2974e1ef6d31685c3b392ad0b74 (0.6ms) + Rendered messages/_message.html.erb in 1.2 ms [cache hit] + Write fragment views/v1/2914079/v1/2914079/recordings/70182313-20160225015037000000/3b4e249ac9d168c617e32e84b99218b5 (1.1ms) + Rendered recordings/threads/_thread.html.erb in 1.5 ms [cache miss] + ``` + + Though that full output can be reenabled with + `config.action_controller.enable_fragment_cache_logging = true`. + + *Stan Lo* + +* Changed partial rendering with a collection to allow collections which + implement `to_a`. + + Extracting the collection option had an optimization to avoid unnecessary + queries of ActiveRecord Relations by calling `#to_ary` on the given + collection. Instances of `Enumerator` or `Enumerable` are valid + collections, but they do not implement `#to_ary`. By changing this to + `#to_a`, they will now be extracted and rendered as expected. + + *Steven Harman* + +* New syntax for tag helpers. Avoid positional parameters and support HTML5 by default. + Example usage of tag helpers before: + + ```ruby + tag(:br, nil, true) + content_tag(:div, content_tag(:p, "Hello world!"), class: "strong") + + <%= content_tag :div, class: "strong" do -%> + Hello world! + <% end -%> + ``` + + Example usage of tag helpers after: + + ```ruby + tag.br + tag.div tag.p("Hello world!"), class: "strong" + + <%= tag.div class: "strong" do %> + Hello world! + <% end %> + ``` + + *Marek Kirejczyk*, *Kasper Timm Hansen* + +* Change `datetime_field` and `datetime_field_tag` to generate `datetime-local` fields. + + As a new specification of the HTML 5 the text field type `datetime` will no longer exist + and it is recommended to use `datetime-local`. + Ref: https://html.spec.whatwg.org/multipage/forms.html#local-date-and-time-state-(type=datetime-local) + + *Herminio Torres* + +* Raw template handler (which is also the default template handler in Rails 5) now outputs + HTML-safe strings. + + In Rails 5 the default template handler was changed to the raw template handler. Because + the ERB template handler escaped strings by default this broke some applications that + expected plain JS or HTML files to be rendered unescaped. This fixes the issue caused + by changing the default handler by changing the Raw template handler to output HTML-safe + strings. + + *Eileen M. Uchitelle* + * `select_tag`'s `include_blank` option for generation for blank option tag, now adds an empty space label, - when the value as well as content for option tag are empty, so that we confirm with html specification. + when the value as well as content for option tag are empty, so that we conform with html specification. Ref: https://www.w3.org/TR/html5/forms.html#the-option-element. Generation of option before: diff --git a/actionview/Rakefile b/actionview/Rakefile index f0f9bda3e4..6c3fc59b0a 100644 --- a/actionview/Rakefile +++ b/actionview/Rakefile @@ -1,43 +1,43 @@ -require 'rake/testtask' +require "rake/testtask" desc "Default Task" -task :default => :test +task default: :test task :package # Run the unit tests desc "Run all unit tests" -task :test => ["test:template", "test:integration:action_pack", "test:integration:active_record"] +task test: ["test:template", "test:integration:action_pack", "test:integration:active_record"] namespace :test do task :isolated do Dir.glob("test/{actionpack,activerecord,template}/**/*_test.rb").all? do |file| - sh(Gem.ruby, '-w', '-Ilib:test', file) - end or raise "Failures" + sh(Gem.ruby, "-w", "-Ilib:test", file) + end || raise("Failures") end Rake::TestTask.new(:template) do |t| - t.libs << 'test' - t.test_files = Dir.glob('test/template/**/*_test.rb') + t.libs << "test" + t.test_files = Dir.glob("test/template/**/*_test.rb") t.warning = true t.verbose = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) end namespace :integration do - desc 'ActiveRecord Integration Tests' + desc "ActiveRecord Integration Tests" Rake::TestTask.new(:active_record) do |t| - t.libs << 'test' + t.libs << "test" t.test_files = Dir.glob("test/activerecord/*_test.rb") t.warning = true t.verbose = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) end - desc 'ActionPack Integration Tests' + desc "ActionPack Integration Tests" Rake::TestTask.new(:action_pack) do |t| - t.libs << 'test' + t.libs << "test" t.test_files = Dir.glob("test/actionpack/**/*_test.rb") t.warning = true t.verbose = true @@ -47,7 +47,7 @@ namespace :test do end task :lines do - load File.expand_path('..', File.dirname(__FILE__)) + '/tools/line_statistics' + load File.expand_path("..", File.dirname(__FILE__)) + "/tools/line_statistics" files = FileList["lib/**/*.rb"] CodeTools::LineStatistics.new(files).print_loc end diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec index 75c5045ec0..7bfdfbe29a 100644 --- a/actionview/actionview.gemspec +++ b/actionview/actionview.gemspec @@ -2,30 +2,30 @@ version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'actionview' + s.name = "actionview" s.version = version - s.summary = 'Rendering framework putting the V in MVC (part of Rails).' - s.description = 'Simple, battle-tested conventions and helpers for building web pages.' + s.summary = "Rendering framework putting the V in MVC (part of Rails)." + s.description = "Simple, battle-tested conventions and helpers for building web pages." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*'] - s.require_path = 'lib' - s.requirements << 'none' + s.files = Dir["CHANGELOG.md", "README.rdoc", "MIT-LICENSE", "lib/**/*"] + s.require_path = "lib" + s.requirements << "none" - s.add_dependency 'activesupport', version + s.add_dependency "activesupport", version - s.add_dependency 'builder', '~> 3.1' - s.add_dependency 'erubis', '~> 2.7.0' - s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.2' - s.add_dependency 'rails-dom-testing', '~> 2.0' + s.add_dependency "builder", "~> 3.1" + s.add_dependency "erubis", "~> 2.7.0" + s.add_dependency "rails-html-sanitizer", "~> 1.0", ">= 1.0.2" + s.add_dependency "rails-dom-testing", "~> 2.0" - s.add_development_dependency 'actionpack', version - s.add_development_dependency 'activemodel', version + s.add_development_dependency "actionpack", version + s.add_development_dependency "activemodel", version end diff --git a/actionview/bin/test b/actionview/bin/test index 404cabba51..84a05bba08 100755 --- a/actionview/bin/test +++ b/actionview/bin/test @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -COMPONENT_ROOT = File.expand_path("../../", __FILE__) + +COMPONENT_ROOT = File.expand_path("..", __dir__) require File.expand_path("../tools/test", COMPONENT_ROOT) + exit Minitest.run(ARGV) diff --git a/actionview/lib/action_view.rb b/actionview/lib/action_view.rb index 0a87500a52..ba6755be82 100644 --- a/actionview/lib/action_view.rb +++ b/actionview/lib/action_view.rb @@ -21,9 +21,9 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'active_support' -require 'active_support/rails' -require 'action_view/version' +require "active_support" +require "active_support/rails" +require "action_view/version" module ActionView extend ActiveSupport::Autoload @@ -89,7 +89,7 @@ module ActionView end end -require 'active_support/core_ext/string/output_safety' +require "active_support/core_ext/string/output_safety" ActiveSupport.on_load(:i18n) do I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml" diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb index ad1cb1a4be..b7c05fdb88 100644 --- a/actionview/lib/action_view/base.rb +++ b/actionview/lib/action_view/base.rb @@ -1,11 +1,11 @@ -require 'active_support/core_ext/module/attr_internal' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/ordered_options' -require 'action_view/log_subscriber' -require 'action_view/helpers' -require 'action_view/context' -require 'action_view/template' -require 'action_view/lookup_context' +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/ordered_options" +require "action_view/log_subscriber" +require "action_view/helpers" +require "action_view/context" +require "action_view/template" +require "action_view/lookup_context" module ActionView #:nodoc: # = Action View Base @@ -17,7 +17,7 @@ module ActionView #:nodoc: # # == ERB # - # You trigger ERB by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the + # You trigger ERB by using embeddings such as <tt><% %></tt>, <tt><% -%></tt>, and <tt><%= %></tt>. The <tt><%= %></tt> tag set is used when you want output. Consider the # following loop for names: # # <b>Names of all the people</b> @@ -25,7 +25,7 @@ module ActionView #:nodoc: # Name: <%= person.name %><br/> # <% end %> # - # The loop is setup in regular embedding tags <% %> and the name is written using the output embedding tag <%= %>. Note that this + # The loop is setup in regular embedding tags <tt><% %></tt>, and the name is written using the output embedding tag <tt><%= %></tt>. Note that this # is not just a usage suggestion. Regular output functions like print or puts won't work with ERB templates. So this would be wrong: # # <%# WRONG %> @@ -33,9 +33,9 @@ module ActionView #:nodoc: # # If you absolutely must write from within a function use +concat+. # - # When on a line that only contains whitespaces except for the tag, <% %> suppress leading and trailing whitespace, - # including the trailing newline. <% %> and <%- -%> are the same. - # Note however that <%= %> and <%= -%> are different: only the latter removes trailing whitespaces. + # When on a line that only contains whitespaces except for the tag, <tt><% %></tt> suppresses leading and trailing whitespace, + # including the trailing newline. <tt><% %></tt> and <tt><%- -%></tt> are the same. + # Note however that <tt><%= %></tt> and <tt><%= -%></tt> are different: only the latter removes trailing whitespaces. # # === Using sub templates # @@ -110,7 +110,7 @@ module ActionView #:nodoc: # <p>A product of Danish Design during the Winter of '79...</p> # </div> # - # A full-length RSS example actually used on Basecamp: + # Here is a full-length RSS example actually used on Basecamp: # # xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do # xml.channel do @@ -141,7 +141,7 @@ module ActionView #:nodoc: # Specify the proc used to decorate input tags that refer to attributes with errors. cattr_accessor :field_error_proc - @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe } + @@field_error_proc = Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe } # How to complete the streaming when an exception occurs. # This is our best guess: first try to close the attribute, then the tag. @@ -169,7 +169,7 @@ module ActionView #:nodoc: class_attribute :logger class << self - delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB' + delegate :erb_trim_mode=, to: "ActionView::Template::Handlers::ERB" def cache_template_loading ActionView::Resolver.caching? @@ -187,8 +187,8 @@ module ActionView #:nodoc: attr_accessor :view_renderer attr_internal :config, :assigns - delegate :lookup_context, :to => :view_renderer - delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, :to => :lookup_context + delegate :lookup_context, to: :view_renderer + delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, to: :lookup_context def assign(new_assigns) # :nodoc: @_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) } diff --git a/actionview/lib/action_view/buffers.rb b/actionview/lib/action_view/buffers.rb index be5d86b1dc..089daa6d60 100644 --- a/actionview/lib/action_view/buffers.rb +++ b/actionview/lib/action_view/buffers.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/output_safety' +require "active_support/core_ext/string/output_safety" module ActionView class OutputBuffer < ActiveSupport::SafeBuffer #:nodoc: diff --git a/actionview/lib/action_view/dependency_tracker.rb b/actionview/lib/action_view/dependency_tracker.rb index 7731773040..451eeec9d6 100644 --- a/actionview/lib/action_view/dependency_tracker.rb +++ b/actionview/lib/action_view/dependency_tracker.rb @@ -1,5 +1,5 @@ -require 'concurrent/map' -require 'action_view/path_set' +require "concurrent/map" +require "action_view/path_set" module ActionView class DependencyTracker # :nodoc: @@ -105,7 +105,6 @@ module ActionView attr_reader :name, :template private :name, :template - private def source template.source @@ -142,7 +141,7 @@ module ActionView def add_static_dependency(dependencies, dependency) if dependency - if dependency.include?('/') + if dependency.include?("/") dependencies << dependency else dependencies << "#{directory}/#{dependency}" @@ -163,7 +162,7 @@ module ActionView def explicit_dependencies dependencies = source.scan(EXPLICIT_DEPENDENCY).flatten.uniq - wildcards, explicits = dependencies.partition { |dependency| dependency[-1] == '*' } + wildcards, explicits = dependencies.partition { |dependency| dependency[-1] == "*" } (explicits + resolve_directories(wildcards)).uniq end diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index f3c29d663c..0658d8601d 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -1,21 +1,26 @@ -require 'concurrent/map' -require 'action_view/dependency_tracker' -require 'monitor' +require "concurrent/map" +require "action_view/dependency_tracker" +require "monitor" module ActionView class Digestor @@digest_mutex = Mutex.new + module PerExecutionDigestCacheExpiry + def self.before(target) + ActionView::LookupContext::DetailsKey.clear + end + end + class << self # Supported options: # # * <tt>name</tt> - Template name # * <tt>finder</tt> - An instance of <tt>ActionView::LookupContext</tt> # * <tt>dependencies</tt> - An array of dependent views - # * <tt>partial</tt> - Specifies whether the template is a partial def digest(name:, finder:, dependencies: []) dependencies ||= [] - cache_key = [ name, finder.rendered_format, dependencies ].flatten.compact.join('.') + cache_key = [ name, finder.rendered_format, dependencies ].flatten.compact.join(".") # this is a correctly done double-checked locking idiom # (Concurrent::Map's lookups have volatile semantics) @@ -42,8 +47,7 @@ module ActionView options = {} options[:formats] = [finder.rendered_format] if finder.rendered_format - if finder.disable_cache { finder.exists?(logical_name, [], partial, [], options) } - template = finder.disable_cache { finder.find(logical_name, [], partial, [], options) } + if template = finder.disable_cache { finder.find_all(logical_name, [], partial, [], options).first } finder.rendered_format ||= template.formats.first if node = seen[template.identifier] # handle cycles in the tree @@ -105,7 +109,7 @@ module ActionView class Partial < Node; end class Missing < Node - def digest(finder, _ = []) '' end + def digest(finder, _ = []) "" end end class Injected < Node diff --git a/actionview/lib/action_view/flows.rb b/actionview/lib/action_view/flows.rb index 4b912f0b2b..16874c1194 100644 --- a/actionview/lib/action_view/flows.rb +++ b/actionview/lib/action_view/flows.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/output_safety' +require "active_support/core_ext/string/output_safety" module ActionView class OutputFlow #:nodoc: @@ -23,7 +23,6 @@ module ActionView @content[key] << value end alias_method :append!, :append - end class StreamingFlow < OutputFlow #:nodoc: @@ -68,8 +67,8 @@ module ActionView private - def inside_fiber? - Fiber.current.object_id != @root - end + def inside_fiber? + Fiber.current.object_id != @root + end end end diff --git a/actionview/lib/action_view/helpers.rb b/actionview/lib/action_view/helpers.rb index 787e9d67b2..c1b4b4f84b 100644 --- a/actionview/lib/action_view/helpers.rb +++ b/actionview/lib/action_view/helpers.rb @@ -1,4 +1,4 @@ -require 'active_support/benchmarkable' +require "active_support/benchmarkable" module ActionView #:nodoc: module Helpers #:nodoc: diff --git a/actionview/lib/action_view/helpers/active_model_helper.rb b/actionview/lib/action_view/helpers/active_model_helper.rb index d5222e3616..4bb5788a16 100644 --- a/actionview/lib/action_view/helpers/active_model_helper.rb +++ b/actionview/lib/action_view/helpers/active_model_helper.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/enumerable' +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/enumerable" module ActionView # = Active Model Helpers @@ -37,13 +37,13 @@ module ActionView private - def object_has_errors? - object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present? - end + def object_has_errors? + object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present? + end - def tag_generate_errors?(options) - options['type'] != 'hidden' - end + def tag_generate_errors?(options) + options["type"] != "hidden" + end end end end diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb index 413c35954c..b1563ac490 100644 --- a/actionview/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb @@ -1,7 +1,8 @@ -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/hash/keys' -require 'action_view/helpers/asset_url_helper' -require 'action_view/helpers/tag_helper' +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/regexp" +require "action_view/helpers/asset_url_helper" +require "action_view/helpers/tag_helper" module ActionView # = Action View Asset Tag Helpers @@ -55,7 +56,7 @@ module ActionView # # => <script src="http://www.example.com/xmlhr.js"></script> def javascript_include_tag(*sources) options = sources.extract_options!.stringify_keys - path_options = options.extract!('protocol', 'extname', 'host').symbolize_keys + path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys sources.uniq.map { |source| tag_options = { "src" => path_to_javascript(source, path_options) @@ -91,8 +92,7 @@ module ActionView # # <link href="/css/stylish.css" media="screen" rel="stylesheet" /> def stylesheet_link_tag(*sources) options = sources.extract_options!.stringify_keys - path_options = options.extract!('protocol', 'host').symbolize_keys - + path_options = options.extract!("protocol", "host", "skip_pipeline").symbolize_keys sources.uniq.map { |source| tag_options = { "rel" => "stylesheet", @@ -138,7 +138,7 @@ module ActionView "rel" => tag_options[:rel] || "alternate", "type" => tag_options[:type] || Template::Types[type].to_s, "title" => tag_options[:title] || type.to_s.upcase, - "href" => url_options.is_a?(Hash) ? url_for(url_options.merge(:only_path => false)) : url_options + "href" => url_options.is_a?(Hash) ? url_for(url_options.merge(only_path: false)) : url_options ) end @@ -169,11 +169,11 @@ module ActionView # # favicon_link_tag 'mb-icon.png', rel: 'apple-touch-icon', type: 'image/png' # # => <link href="/assets/mb-icon.png" rel="apple-touch-icon" type="image/png" /> - def favicon_link_tag(source='favicon.ico', options={}) - tag('link', { - :rel => 'shortcut icon', - :type => 'image/x-icon', - :href => path_to_image(source) + def favicon_link_tag(source="favicon.ico", options={}) + tag("link", { + rel: "shortcut icon", + type: "image/x-icon", + href: path_to_image(source, skip_pipeline: options.delete(:skip_pipeline)) }.merge!(options.symbolize_keys)) end @@ -211,10 +211,10 @@ module ActionView options = options.symbolize_keys check_for_image_tag_errors(options) - src = options[:src] = path_to_image(source) + src = options[:src] = path_to_image(source, skip_pipeline: options.delete(:skip_pipeline)) - unless src =~ /^(?:cid|data):/ || src.blank? - options[:alt] = options.fetch(:alt){ image_alt(src) } + unless src.start_with?("cid:") || src.start_with?("data:") || src.blank? + options[:alt] = options.fetch(:alt) { image_alt(src) } end options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size] @@ -239,7 +239,7 @@ module ActionView # image_alt('underscored_file_name.png') # # => Underscored file name def image_alt(src) - File.basename(src, '.*'.freeze).sub(/-[[:xdigit:]]{32,64}\z/, ''.freeze).tr('-_'.freeze, ' '.freeze).capitalize + File.basename(src, ".*".freeze).sub(/-[[:xdigit:]]{32,64}\z/, "".freeze).tr("-_".freeze, " ".freeze).capitalize end # Returns an HTML video tag for the +sources+. If +sources+ is a string, @@ -257,6 +257,8 @@ module ActionView # * <tt>:size</tt> - Supplied as "{Width}x{Height}" or "{Number}", so "30x45" becomes # width="30" and height="45", and "50" becomes width="50" and height="50". # <tt>:size</tt> will be ignored if the value is not in the correct format. + # * <tt>:poster_skip_pipeline</tt> will bypass the asset pipeline when using + # the <tt>:poster</tt> option instead using an asset in the public folder. # # ==== Examples # @@ -264,10 +266,12 @@ module ActionView # # => <video src="/videos/trailer"></video> # video_tag("trailer.ogg") # # => <video src="/videos/trailer.ogg"></video> - # video_tag("trailer.ogg", controls: true, autobuffer: true) - # # => <video autobuffer="autobuffer" controls="controls" src="/videos/trailer.ogg" ></video> + # video_tag("trailer.ogg", controls: true, preload: 'none') + # # => <video preload="none" controls="controls" src="/videos/trailer.ogg" ></video> # video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png") # # => <video src="/videos/trailer.m4v" width="16" height="10" poster="/assets/screenshot.png"></video> + # video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png", poster_skip_pipeline: true) + # # => <video src="/videos/trailer.m4v" width="16" height="10" poster="screenshot.png"></video> # video_tag("/trailers/hd.avi", size: "16x16") # # => <video src="/trailers/hd.avi" width="16" height="16"></video> # video_tag("/trailers/hd.avi", size: "16") @@ -281,9 +285,12 @@ module ActionView # video_tag(["trailer.ogg", "trailer.flv"], size: "160x120") # # => <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> def video_tag(*sources) - multiple_sources_tag('video', sources) do |options| - options[:poster] = path_to_image(options[:poster]) if options[:poster] - options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size] + options = sources.extract_options!.symbolize_keys + public_poster_folder = options.delete(:poster_skip_pipeline) + sources << options + multiple_sources_tag_builder("video", sources) do |tag_options| + tag_options[:poster] = path_to_image(tag_options[:poster], skip_pipeline: public_poster_folder) if tag_options[:poster] + tag_options[:width], tag_options[:height] = extract_dimensions(tag_options.delete(:size)) if tag_options[:size] end end @@ -300,31 +307,32 @@ module ActionView # audio_tag("sound.wav", "sound.mid") # # => <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio> def audio_tag(*sources) - multiple_sources_tag('audio', sources) + multiple_sources_tag_builder("audio", sources) end private - def multiple_sources_tag(type, sources) - options = sources.extract_options!.symbolize_keys + def multiple_sources_tag_builder(type, sources) + options = sources.extract_options!.symbolize_keys + skip_pipeline = options.delete(:skip_pipeline) sources.flatten! yield options if block_given? if sources.size > 1 content_tag(type, options) do - safe_join sources.map { |source| tag("source", :src => send("path_to_#{type}", source)) } + safe_join sources.map { |source| tag("source", src: send("path_to_#{type}", source, skip_pipeline: skip_pipeline)) } end else - options[:src] = send("path_to_#{type}", sources.first) + options[:src] = send("path_to_#{type}", sources.first, skip_pipeline: skip_pipeline) content_tag(type, nil, options) end end def extract_dimensions(size) size = size.to_s - if size =~ %r{\A\d+x\d+\z} - size.split('x') - elsif size =~ %r{\A\d+\z} + if /\A\d+x\d+\z/.match?(size) + size.split("x") + elsif /\A\d+\z/.match?(size) [size, size] end end diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb index 717b326740..e0de2ff4d6 100644 --- a/actionview/lib/action_view/helpers/asset_url_helper.rb +++ b/actionview/lib/action_view/helpers/asset_url_helper.rb @@ -1,4 +1,5 @@ -require 'zlib' +require "zlib" +require "active_support/core_ext/regexp" module ActionView # = Action View Asset URL Helpers @@ -36,7 +37,7 @@ module ActionView # some asset downloads to wait for previous assets to finish before they can # begin. You can use the <tt>%d</tt> wildcard in the +asset_host+ to # distribute the requests over four hosts. For example, - # <tt>assets%d.example.com<tt> will spread the asset requests over + # <tt>assets%d.example.com</tt> will spread the asset requests over # "assets0.example.com", ..., "assets3.example.com". # # image_tag("rails.png") @@ -117,31 +118,86 @@ module ActionView module AssetUrlHelper URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}i - # Computes the path to asset in public directory. If :type - # options is set, a file extension will be appended and scoped - # to the corresponding public directory. + # This is the entry point for all assets. + # When using the asset pipeline (i.e. sprockets and sprockets-rails), the + # behavior is "enhanced". You can bypass the asset pipeline by passing in + # <tt>skip_pipeline: true</tt> to the options. # # All other asset *_path helpers delegate through this method. # - # asset_path "application.js" # => /assets/application.js - # asset_path "application", type: :javascript # => /assets/application.js - # asset_path "application", type: :stylesheet # => /assets/application.css - # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js + # === With the asset pipeline + # + # All options passed to +asset_path+ will be passed to +compute_asset_path+ + # which is implemented by sprockets-rails. + # + # asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js" + # + # === Without the asset pipeline (<tt>skip_pipeline: true</tt>) + # + # Accepts a <tt>type</tt> option that can specify the asset's extension. No error + # checking is done to verify the source passed into +asset_path+ is valid + # and that the file exists on disk. + # + # asset_path("application.js", skip_pipeline: true) # => "application.js" + # asset_path("filedoesnotexist.png", skip_pipeline: true) # => "filedoesnotexist.png" + # asset_path("application", type: :javascript, skip_pipeline: true) # => "/javascripts/application.js" + # asset_path("application", type: :stylesheet, skip_pipeline: true) # => "/stylesheets/application.css" + # + # === Options applying to all assets + # + # Below lists scenarios that apply to +asset_path+ whether or not you're + # using the asset pipeline. + # + # - All fully qualified urls are returned immediately. This bypasses the + # asset pipeline and all other behavior described. + # + # asset_path("http://www.example.com/js/xmlhr.js") # => "http://www.example.com/js/xmlhr.js" + # + # - All assets that begin with a forward slash are assumed to be full + # urls and will not be expanded. This will bypass the asset pipeline. + # + # asset_path("/foo.png") # => "/foo.png" + # + # - All blank strings will be returned immediately. This bypasses the + # asset pipeline and all other behavior described. + # + # asset_path("") # => "" + # + # - If <tt>config.relative_url_root</tt> is specified, all assets will have that + # root prepended. + # + # Rails.application.config.relative_url_root = "bar" + # asset_path("foo.js", skip_pipeline: true) # => "bar/foo.js" + # + # - A different asset host can be specified via <tt>config.action_controller.asset_host</tt> + # this is commonly used in conjunction with a CDN. + # + # Rails.application.config.action_controller.asset_host = "assets.example.com" + # asset_path("foo.js", skip_pipeline: true) # => "http://assets.example.com/foo.js" + # + # - An extension name can be specified manually with <tt>extname</tt>. + # + # asset_path("foo", skip_pipeline: true, extname: ".js") # => "/foo.js" + # asset_path("foo.css", skip_pipeline: true, extname: ".js") # => "/foo.css.js" def asset_path(source, options = {}) raise ArgumentError, "nil is not a valid asset source" if source.nil? source = source.to_s - return "" unless source.present? - return source if source =~ URI_REGEXP + return "" if source.blank? + return source if URI_REGEXP.match?(source) - tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, ''.freeze) + tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, "".freeze) if extname = compute_asset_extname(source, options) source = "#{source}#{extname}" end if source[0] != ?/ - source = compute_asset_path(source, options) + if options[:skip_pipeline] + source = public_compute_asset_path(source, options) + else + source = compute_asset_path(source, options) + end end relative_url_root = defined?(config.relative_url_root) && config.relative_url_root @@ -168,13 +224,13 @@ module ActionView # asset_url "application.js", host: "http://cdn.example.com" # => http://cdn.example.com/assets/application.js # def asset_url(source, options = {}) - path_to_asset(source, options.merge(:protocol => :request)) + path_to_asset(source, options.merge(protocol: :request)) end alias_method :url_to_asset, :asset_url # aliased to avoid conflicts with an asset_url named route ASSET_EXTENSIONS = { - javascript: '.js', - stylesheet: '.css' + javascript: ".js", + stylesheet: ".css" } # Compute extname to append to asset path. Returns nil if @@ -187,12 +243,12 @@ module ActionView # Maps asset types to public directory. ASSET_PUBLIC_DIRECTORIES = { - audio: '/audios', - font: '/fonts', - image: '/images', - javascript: '/javascripts', - stylesheet: '/stylesheets', - video: '/videos' + audio: "/audios", + font: "/fonts", + image: "/images", + javascript: "/javascripts", + stylesheet: "/stylesheets", + video: "/videos" } # Computes asset path to public directory. Plugins and @@ -202,6 +258,7 @@ module ActionView dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || "" File.join(dir, source) end + alias :public_compute_asset_path :compute_asset_path # Pick an asset host for this source. Returns +nil+ if no host is set, # the host if no wildcard is set, the host interpolated with the @@ -213,19 +270,21 @@ module ActionView host = options[:host] host ||= config.asset_host if defined? config.asset_host - if host.respond_to?(:call) - arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity - args = [source] - args << request if request && (arity > 1 || arity < 0) - host = host.call(*args) - elsif host =~ /%d/ - host = host % (Zlib.crc32(source) % 4) + if host + if host.respond_to?(:call) + arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity + args = [source] + args << request if request && (arity > 1 || arity < 0) + host = host.call(*args) + elsif host.include?("%d") + host = host % (Zlib.crc32(source) % 4) + end end host ||= request.base_url if request && options[:protocol] == :request return unless host - if host =~ URI_REGEXP + if URI_REGEXP.match?(host) host else protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative) @@ -251,7 +310,7 @@ module ActionView # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js def javascript_path(source, options = {}) - path_to_asset(source, {type: :javascript}.merge!(options)) + path_to_asset(source, { type: :javascript }.merge!(options)) end alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route @@ -263,7 +322,7 @@ module ActionView # javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/dir/xmlhr.js # def javascript_url(source, options = {}) - url_to_asset(source, {type: :javascript}.merge!(options)) + url_to_asset(source, { type: :javascript }.merge!(options)) end alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route @@ -278,7 +337,7 @@ module ActionView # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css def stylesheet_path(source, options = {}) - path_to_asset(source, {type: :stylesheet}.merge!(options)) + path_to_asset(source, { type: :stylesheet }.merge!(options)) end alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route @@ -290,7 +349,7 @@ module ActionView # stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/css/style.css # def stylesheet_url(source, options = {}) - url_to_asset(source, {type: :stylesheet}.merge!(options)) + url_to_asset(source, { type: :stylesheet }.merge!(options)) end alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route @@ -308,7 +367,7 @@ module ActionView # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and # plugin authors are encouraged to do so. def image_path(source, options = {}) - path_to_asset(source, {type: :image}.merge!(options)) + path_to_asset(source, { type: :image }.merge!(options)) end alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route @@ -320,7 +379,7 @@ module ActionView # image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/edit.png # def image_url(source, options = {}) - url_to_asset(source, {type: :image}.merge!(options)) + url_to_asset(source, { type: :image }.merge!(options)) end alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route @@ -334,7 +393,7 @@ module ActionView # video_path("/trailers/hd.avi") # => /trailers/hd.avi # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi def video_path(source, options = {}) - path_to_asset(source, {type: :video}.merge!(options)) + path_to_asset(source, { type: :video }.merge!(options)) end alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route @@ -346,7 +405,7 @@ module ActionView # video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/hd.avi # def video_url(source, options = {}) - url_to_asset(source, {type: :video}.merge!(options)) + url_to_asset(source, { type: :video }.merge!(options)) end alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route @@ -360,7 +419,7 @@ module ActionView # audio_path("/sounds/horse.wav") # => /sounds/horse.wav # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav def audio_path(source, options = {}) - path_to_asset(source, {type: :audio}.merge!(options)) + path_to_asset(source, { type: :audio }.merge!(options)) end alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route @@ -372,7 +431,7 @@ module ActionView # audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/horse.wav # def audio_url(source, options = {}) - url_to_asset(source, {type: :audio}.merge!(options)) + url_to_asset(source, { type: :audio }.merge!(options)) end alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route @@ -385,7 +444,7 @@ module ActionView # font_path("/dir/font.ttf") # => /dir/font.ttf # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf def font_path(source, options = {}) - path_to_asset(source, {type: :font}.merge!(options)) + path_to_asset(source, { type: :font }.merge!(options)) end alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route @@ -397,7 +456,7 @@ module ActionView # font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/font.ttf # def font_url(source, options = {}) - url_to_asset(source, {type: :font}.merge!(options)) + url_to_asset(source, { type: :font }.merge!(options)) end alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route end diff --git a/actionview/lib/action_view/helpers/atom_feed_helper.rb b/actionview/lib/action_view/helpers/atom_feed_helper.rb index c875f5870f..09d243c46d 100644 --- a/actionview/lib/action_view/helpers/atom_feed_helper.rb +++ b/actionview/lib/action_view/helpers/atom_feed_helper.rb @@ -1,4 +1,4 @@ -require 'set' +require "set" module ActionView # = Action View Atom Feed Helpers @@ -112,13 +112,13 @@ module ActionView end end - feed_opts = {"xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom'} - feed_opts.merge!(options).reject!{|k,v| !k.to_s.match(/^xml/)} + feed_opts = { "xml:lang" => options[:language] || "en-US", "xmlns" => "http://www.w3.org/2005/Atom" } + feed_opts.merge!(options).reject! { |k,v| !k.to_s.match(/^xml/) } xml.feed(feed_opts) do xml.id(options[:id] || "tag:#{request.host},#{options[:schema_date]}:#{request.fullpath.split(".")[0]}") - xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:root_url] || (request.protocol + request.host_with_port)) - xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url) + xml.link(rel: "alternate", type: "text/html", href: options[:root_url] || (request.protocol + request.host_with_port)) + xml.link(rel: "self", type: "application/atom+xml", href: options[:url] || request.url) yield AtomFeedBuilder.new(xml, self, options) end @@ -138,7 +138,7 @@ module ActionView def method_missing(method, *arguments, &block) if xhtml_block?(method, arguments) @xml.__send__(method, *arguments) do - @xml.div(:xmlns => 'http://www.w3.org/1999/xhtml') do |xhtml| + @xml.div(xmlns: "http://www.w3.org/1999/xhtml") do |xhtml| block.call(xhtml) end end @@ -153,7 +153,7 @@ module ActionView def xhtml_block?(method, arguments) if XHTML_TAG_NAMES.include?(method.to_s) last = arguments.last - last.is_a?(Hash) && last[:type].to_s == 'xhtml' + last.is_a?(Hash) && last[:type].to_s == "xhtml" end end end @@ -189,16 +189,15 @@ module ActionView @xml.updated((options[:updated] || record.updated_at).xmlschema) end - type = options.fetch(:type, 'text/html') + type = options.fetch(:type, "text/html") url = options.fetch(:url) { @view.polymorphic_url(record) } - @xml.link(:rel => 'alternate', :type => type, :href => url) if url + @xml.link(rel: "alternate", type: type, href: url) if url yield AtomBuilder.new(@xml) end end end - end end end diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb index 4eaaa239e2..5258a01144 100644 --- a/actionview/lib/action_view/helpers/cache_helper.rb +++ b/actionview/lib/action_view/helpers/cache_helper.rb @@ -69,11 +69,11 @@ module ActionView # render 'comments/comments' # render('comments/comments') # - # render "header" => render("comments/header") + # render "header" translates to render("comments/header") # - # render(@topic) => render("topics/topic") - # render(topics) => render("topics/topic") - # render(message.topics) => render("topics/topic") + # render(@topic) translates to render("topics/topic") + # render(topics) translates to render("topics/topic") + # render(message.topics) translates to render("topics/topic") # # It's not possible to derive all render calls like that, though. # Here are a few examples of things that can't be derived: @@ -130,9 +130,10 @@ module ActionView # # When rendering a collection of objects that each use the same partial, a `cached` # option can be passed. + # # For collections rendered such: # - # <%= render partial: 'notifications/notification', collection: @notifications, cached: true %> + # <%= render partial: 'projects/project', collection: @projects, cached: true %> # # The `cached: true` will make Action View's rendering read several templates # from cache at once instead of one call per template. @@ -142,13 +143,21 @@ module ActionView # Works great alongside individual template fragment caching. # For instance if the template the collection renders is cached like: # - # # notifications/_notification.html.erb - # <% cache notification do %> + # # projects/_project.html.erb + # <% cache project do %> # <%# ... %> # <% end %> # # Any collection renders will find those cached templates when attempting # to read multiple templates at once. + # + # If your collection cache depends on multiple sources (try to avoid this to keep things simple), + # you can name all these dependencies as part of a block that returns an array: + # + # <%= render partial: 'projects/project', collection: @projects, cached: -> project { [ project, current_user ] } %> + # + # This will include both records as part of the cache key and updating either of them will + # expire the cache. def cache(name = {}, options = {}, &block) if controller.respond_to?(:perform_caching) && controller.perform_caching name_options = options.slice(:skip_digest, :virtual_path) @@ -202,6 +211,8 @@ module ActionView end end + attr_reader :cache_hit # :nodoc: + private def fragment_name_with_digest(name, virtual_path) #:nodoc: @@ -215,9 +226,14 @@ module ActionView end end - # TODO: Create an object that has caching read/write on it def fragment_for(name = {}, options = nil, &block) #:nodoc: - read_fragment_for(name, options) || write_fragment_for(name, options, &block) + if content = read_fragment_for(name, options) + @cache_hit = true + content + else + @cache_hit = false + write_fragment_for(name, options, &block) + end end def read_fragment_for(name, options) #:nodoc: diff --git a/actionview/lib/action_view/helpers/capture_helper.rb b/actionview/lib/action_view/helpers/capture_helper.rb index df8d0affd0..719592b5c5 100644 --- a/actionview/lib/action_view/helpers/capture_helper.rb +++ b/actionview/lib/action_view/helpers/capture_helper.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/output_safety' +require "active_support/core_ext/string/output_safety" module ActionView # = Action View Capture Helper @@ -37,7 +37,7 @@ module ActionView def capture(*args) value = nil buffer = with_output_buffer { value = yield(*args) } - if string = buffer.presence || value and string.is_a?(String) + if (string = buffer.presence || value) && string.is_a?(String) ERB::Util.html_escape string end end diff --git a/actionview/lib/action_view/helpers/controller_helper.rb b/actionview/lib/action_view/helpers/controller_helper.rb index 3569fba8c6..e86cdca4e4 100644 --- a/actionview/lib/action_view/helpers/controller_helper.rb +++ b/actionview/lib/action_view/helpers/controller_helper.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/module/attr_internal' +require "active_support/core_ext/module/attr_internal" module ActionView module Helpers @@ -8,7 +8,7 @@ module ActionView attr_internal :controller, :request delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers, - :flash, :action_name, :controller_name, :controller_path, :to => :controller + :flash, :action_name, :controller_name, :controller_path, to: :controller def assign_controller(controller) if @_controller = controller diff --git a/actionview/lib/action_view/helpers/csrf_helper.rb b/actionview/lib/action_view/helpers/csrf_helper.rb index 5af92c4ff2..2a15d2aa5a 100644 --- a/actionview/lib/action_view/helpers/csrf_helper.rb +++ b/actionview/lib/action_view/helpers/csrf_helper.rb @@ -14,14 +14,14 @@ module ActionView # # You don't need to use these tags for regular forms as they generate their own hidden fields. # - # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the + # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the # "X-CSRF-Token" HTTP header. If you are using jQuery with jquery-rails this happens automatically. # def csrf_meta_tags if protect_against_forgery? [ - tag('meta', :name => 'csrf-param', :content => request_forgery_protection_token), - tag('meta', :name => 'csrf-token', :content => form_authenticity_token) + tag("meta", name: "csrf-param", content: request_forgery_protection_token), + tag("meta", name: "csrf-token", content: form_authenticity_token) ].join("\n").html_safe end end diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb index 04dcf01bb7..ea7259a25d 100644 --- a/actionview/lib/action_view/helpers/date_helper.rb +++ b/actionview/lib/action_view/helpers/date_helper.rb @@ -1,10 +1,10 @@ -require 'date' -require 'action_view/helpers/tag_helper' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/date/conversions' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/object/acts_like' -require 'active_support/core_ext/object/with_options' +require "date" +require "action_view/helpers/tag_helper" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/date/conversions" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/object/with_options" module ActionView module Helpers @@ -101,60 +101,60 @@ module ActionView distance_in_minutes = ((to_time - from_time)/60.0).round distance_in_seconds = (to_time - from_time).round - I18n.with_options :locale => options[:locale], :scope => options[:scope] do |locale| + I18n.with_options locale: options[:locale], scope: options[:scope] do |locale| case distance_in_minutes - when 0..1 - return distance_in_minutes == 0 ? - locale.t(:less_than_x_minutes, :count => 1) : - locale.t(:x_minutes, :count => distance_in_minutes) unless options[:include_seconds] - - case distance_in_seconds - when 0..4 then locale.t :less_than_x_seconds, :count => 5 - when 5..9 then locale.t :less_than_x_seconds, :count => 10 - when 10..19 then locale.t :less_than_x_seconds, :count => 20 - when 20..39 then locale.t :half_a_minute - when 40..59 then locale.t :less_than_x_minutes, :count => 1 - else locale.t :x_minutes, :count => 1 - end - - when 2...45 then locale.t :x_minutes, :count => distance_in_minutes - when 45...90 then locale.t :about_x_hours, :count => 1 + when 0..1 + return distance_in_minutes == 0 ? + locale.t(:less_than_x_minutes, count: 1) : + locale.t(:x_minutes, count: distance_in_minutes) unless options[:include_seconds] + + case distance_in_seconds + when 0..4 then locale.t :less_than_x_seconds, count: 5 + when 5..9 then locale.t :less_than_x_seconds, count: 10 + when 10..19 then locale.t :less_than_x_seconds, count: 20 + when 20..39 then locale.t :half_a_minute + when 40..59 then locale.t :less_than_x_minutes, count: 1 + else locale.t :x_minutes, count: 1 + end + + when 2...45 then locale.t :x_minutes, count: distance_in_minutes + when 45...90 then locale.t :about_x_hours, count: 1 # 90 mins up to 24 hours - when 90...1440 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round + when 90...1440 then locale.t :about_x_hours, count: (distance_in_minutes.to_f / 60.0).round # 24 hours up to 42 hours - when 1440...2520 then locale.t :x_days, :count => 1 + when 1440...2520 then locale.t :x_days, count: 1 # 42 hours up to 30 days - when 2520...43200 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round + when 2520...43200 then locale.t :x_days, count: (distance_in_minutes.to_f / 1440.0).round # 30 days up to 60 days - when 43200...86400 then locale.t :about_x_months, :count => (distance_in_minutes.to_f / 43200.0).round + when 43200...86400 then locale.t :about_x_months, count: (distance_in_minutes.to_f / 43200.0).round # 60 days up to 365 days - when 86400...525600 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round + when 86400...525600 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round + else + if from_time.acts_like?(:time) && to_time.acts_like?(:time) + fyear = from_time.year + fyear += 1 if from_time.month >= 3 + tyear = to_time.year + tyear -= 1 if to_time.month < 3 + leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count { |x| Date.leap?(x) } + minute_offset_for_leap_year = leap_years * 1440 + # Discount the leap year days when calculating year distance. + # e.g. if there are 20 leap year days between 2 dates having the same day + # and month then the based on 365 days calculation + # the distance in years will come out to over 80 years when in written + # English it would read better as about 80 years. + minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year else - if from_time.acts_like?(:time) && to_time.acts_like?(:time) - fyear = from_time.year - fyear += 1 if from_time.month >= 3 - tyear = to_time.year - tyear -= 1 if to_time.month < 3 - leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)} - minute_offset_for_leap_year = leap_years * 1440 - # Discount the leap year days when calculating year distance. - # e.g. if there are 20 leap year days between 2 dates having the same day - # and month then the based on 365 days calculation - # the distance in years will come out to over 80 years when in written - # English it would read better as about 80 years. - minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year - else - minutes_with_offset = distance_in_minutes - end - remainder = (minutes_with_offset % MINUTES_IN_YEAR) - distance_in_years = (minutes_with_offset.div MINUTES_IN_YEAR) - if remainder < MINUTES_IN_QUARTER_YEAR - locale.t(:about_x_years, :count => distance_in_years) - elsif remainder < MINUTES_IN_THREE_QUARTERS_YEAR - locale.t(:over_x_years, :count => distance_in_years) - else - locale.t(:almost_x_years, :count => distance_in_years + 1) - end + minutes_with_offset = distance_in_minutes + end + remainder = (minutes_with_offset % MINUTES_IN_YEAR) + distance_in_years = (minutes_with_offset.div MINUTES_IN_YEAR) + if remainder < MINUTES_IN_QUARTER_YEAR + locale.t(:about_x_years, count: distance_in_years) + elsif remainder < MINUTES_IN_THREE_QUARTERS_YEAR + locale.t(:over_x_years, count: distance_in_years) + else + locale.t(:almost_x_years, count: distance_in_years + 1) + end end end end @@ -267,7 +267,7 @@ module ActionView # date_select("article", "written_on", default: 3.days.from_now) # # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute - # # which is set in the form with todays date, regardless of the value in the Active Record object. + # # which is set in the form with today's date, regardless of the value in the Active Record object. # date_select("article", "written_on", selected: Date.today) # # # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute @@ -303,7 +303,7 @@ module ActionView # # the sunrise attribute. # time_select("article", "start_time", include_seconds: true) # - # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45. + # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30, and 45. # time_select 'game', 'game_time', {minute_step: 15} # # # Creates a time select tag with a custom prompt. Use <tt>prompt: true</tt> for generic prompts. @@ -682,19 +682,19 @@ module ActionView def time_tag(date_or_time, *args, &block) options = args.extract_options! format = options.delete(:format) || :long - content = args.first || I18n.l(date_or_time, :format => format) + content = args.first || I18n.l(date_or_time, format: format) datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601 - content_tag("time".freeze, content, options.reverse_merge(:datetime => datetime), &block) + content_tag("time".freeze, content, options.reverse_merge(datetime: datetime), &block) end end class DateTimeSelector #:nodoc: include ActionView::Helpers::TagHelper - DEFAULT_PREFIX = 'date'.freeze + DEFAULT_PREFIX = "date".freeze POSITION = { - :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 + year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6 }.freeze AMPM_TRANSLATION = Hash[ @@ -710,8 +710,8 @@ module ActionView @options = options.dup @html_options = html_options.dup @datetime = datetime - @options[:datetime_separator] ||= ' — ' - @options[:time_separator] ||= ' : ' + @options[:datetime_separator] ||= " — " + @options[:time_separator] ||= " : " end def select_datetime @@ -781,7 +781,7 @@ module ActionView if @options[:use_hidden] || @options[:discard_minute] build_hidden(:minute, min) else - build_options_and_select(:minute, min, :step => @options[:minute_step]) + build_options_and_select(:minute, min, step: @options[:minute_step]) end end @@ -801,7 +801,7 @@ module ActionView if @options[:use_hidden] || @options[:discard_day] build_hidden(:day, day || 1) else - build_options_and_select(:day, day, :start => 1, :end => 31, :leading_zeros => false, :use_two_digit_numbers => @options[:use_two_digit_numbers]) + build_options_and_select(:day, day, start: 1, end: 31, leading_zeros: false, use_two_digit_numbers: @options[:use_two_digit_numbers]) end end @@ -811,7 +811,7 @@ module ActionView else month_options = [] 1.upto(12) do |month_number| - options = { :value => month_number } + options = { value: month_number } options[:selected] = "selected" if month == month_number month_options << content_tag("option".freeze, month_name(month_number), options) + "\n" end @@ -821,7 +821,7 @@ module ActionView def select_year if !@datetime || @datetime == 0 - val = '1' + val = "1" middle_year = Date.today.year else val = middle_year = year @@ -861,7 +861,7 @@ module ActionView # valid. Otherwise, February 31st or February 29th, 2011 can be selected, which are invalid. def set_day_if_discarded if @datetime && @options[:discard_day] - @datetime = @datetime.change(:day => 1) + @datetime = @datetime.change(day: 1) end end @@ -886,7 +886,7 @@ module ActionView # "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] def translated_month_names key = @options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names' - I18n.translate(key, :locale => @options[:locale]) + I18n.translate(key, locale: @options[:locale]) end # Looks up month names by number (1-based): @@ -914,11 +914,11 @@ module ActionView if @options[:use_month_numbers] number elsif @options[:use_two_digit_numbers] - '%02d' % number + "%02d" % number elsif @options[:add_month_numbers] "#{number} - #{month_names[number]}" elsif format_string = @options[:month_format_string] - format_string % {number: number, name: month_names[number]} + format_string % { number: number, name: month_names[number] } else month_names[number] end @@ -929,7 +929,7 @@ module ActionView end def translated_date_order - date_order = I18n.translate(:'date.order', :locale => @options[:locale], :default => []) + date_order = I18n.translate(:'date.order', locale: @options[:locale], default: []) date_order = date_order.map(&:to_sym) forbidden_elements = date_order - [:year, :month, :day] @@ -976,7 +976,7 @@ module ActionView select_options = [] start.step(stop, step) do |i| value = leading_zeros ? sprintf("%02d", i) : i - tag_options = { :value => value } + tag_options = { value: value } tag_options[:selected] = "selected" if selected == i text = options[:use_two_digit_numbers] ? sprintf("%02d", i) : value text = options[:ampm] ? AMPM_TRANSLATION[i] : text @@ -993,14 +993,14 @@ module ActionView # </select>" def build_select(type, select_options_as_html) select_options = { - :id => input_id_from_type(type), - :name => input_name_from_type(type) + id: input_id_from_type(type), + name: input_name_from_type(type) }.merge!(@html_options) - select_options[:disabled] = 'disabled' if @options[:disabled] + select_options[:disabled] = "disabled" if @options[:disabled] select_options[:class] = css_class_attribute(type, select_options[:class], @options[:with_css_classes]) if @options[:with_css_classes] select_html = "\n" - select_html << content_tag("option".freeze, '', :value => '') + "\n" if @options[:include_blank] + select_html << content_tag("option".freeze, "", value: "") + "\n" if @options[:include_blank] select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt] select_html << select_options_as_html @@ -1011,31 +1011,33 @@ module ActionView # css_class_attribute(:year, 'date optional', { year: 'my-year' }) # => "date optional my-year" def css_class_attribute(type, html_options_class, options) # :nodoc: - css_class = case options - when Hash - options[type.to_sym] - else - type - end - - [html_options_class, css_class].compact.join(' ') + css_class = \ + case options + when Hash + options[type.to_sym] + else + type + end + + [html_options_class, css_class].compact.join(" ") end # Builds a prompt option tag with supplied options or from default options. # prompt_option_tag(:month, prompt: 'Select month') # => "<option value="">Select month</option>" def prompt_option_tag(type, options) - prompt = case options + prompt = \ + case options when Hash - default_options = {:year => false, :month => false, :day => false, :hour => false, :minute => false, :second => false} + default_options = { year: false, month: false, day: false, hour: false, minute: false, second: false } default_options.merge!(options)[type.to_sym] when String options else - I18n.translate(:"datetime.prompts.#{type}", :locale => @options[:locale]) - end + I18n.translate(:"datetime.prompts.#{type}", locale: @options[:locale]) + end - prompt ? content_tag("option".freeze, prompt, :value => '') : '' + prompt ? content_tag("option".freeze, prompt, value: "") : "" end # Builds hidden input tag for date part and value. @@ -1043,12 +1045,12 @@ module ActionView # => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />" def build_hidden(type, value) select_options = { - :type => "hidden", - :id => input_id_from_type(type), - :name => input_name_from_type(type), - :value => value + type: "hidden", + id: input_id_from_type(type), + name: input_name_from_type(type), + value: value }.merge!(@html_options.slice(:disabled)) - select_options[:disabled] = 'disabled' if @options[:disabled] + select_options[:disabled] = "disabled" if @options[:disabled] tag(:input, select_options) + "\n".html_safe end @@ -1059,7 +1061,7 @@ module ActionView prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX prefix += "[#{@options[:index]}]" if @options.has_key?(:index) - field_name = @options[:field_name] || type + field_name = @options[:field_name] || type.to_s if @options[:include_position] field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)" end @@ -1070,8 +1072,8 @@ module ActionView # Returns the id attribute for the input tag. # => "post_written_on_1i" def input_id_from_type(type) - id = input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '') - id = @options[:namespace] + '_' + id if @options[:namespace] + id = input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, "_").gsub(/[\]\)]/, "") + id = @options[:namespace] + "_" + id if @options[:namespace] id end @@ -1079,7 +1081,7 @@ module ActionView # Given an ordering of datetime components, create the selection HTML # and join them with their appropriate separators. def build_selects_from_types(order) - select = '' + select = "" first_visible = order.find { |type| !@options[:"discard_#{type}"] } order.reverse_each do |type| separator = separator(type) unless type == first_visible # don't add before first visible field @@ -1093,12 +1095,12 @@ module ActionView return "" if @options[:use_hidden] case type - when :year, :month, :day - @options[:"discard_#{type}"] ? "" : @options[:date_separator] - when :hour - (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator] - when :minute, :second - @options[:"discard_#{type}"] ? "" : @options[:time_separator] + when :year, :month, :day + @options[:"discard_#{type}"] ? "" : @options[:date_separator] + when :hour + (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator] + when :minute, :second + @options[:"discard_#{type}"] ? "" : @options[:time_separator] end end end diff --git a/actionview/lib/action_view/helpers/debug_helper.rb b/actionview/lib/action_view/helpers/debug_helper.rb index e9dccbad1c..f61ca2c9c2 100644 --- a/actionview/lib/action_view/helpers/debug_helper.rb +++ b/actionview/lib/action_view/helpers/debug_helper.rb @@ -4,7 +4,6 @@ module ActionView # Provides a set of methods for making it easier to debug Rails objects. module Helpers module DebugHelper - include TagHelper # Returns a YAML representation of +object+ wrapped with <pre> and </pre>. @@ -25,10 +24,10 @@ module ActionView def debug(object) Marshal::dump(object) object = ERB::Util.html_escape(object.to_yaml) - content_tag(:pre, object, :class => "debug_dump") + content_tag(:pre, object, class: "debug_dump") rescue # errors from Marshal or YAML # Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback - content_tag(:code, object.inspect, :class => "debug_dump") + content_tag(:code, object.inspect, class: "debug_dump") end end end diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index be5010cd9c..124a14f1d9 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -1,14 +1,14 @@ -require 'cgi' -require 'action_view/helpers/date_helper' -require 'action_view/helpers/tag_helper' -require 'action_view/helpers/form_tag_helper' -require 'action_view/helpers/active_model_helper' -require 'action_view/model_naming' -require 'action_view/record_identifier' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/string/inflections' +require "cgi" +require "action_view/helpers/date_helper" +require "action_view/helpers/tag_helper" +require "action_view/helpers/form_tag_helper" +require "action_view/helpers/active_model_helper" +require "action_view/model_naming" +require "action_view/record_identifier" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/string/inflections" module ActionView # = Action View Form Helpers @@ -467,10 +467,10 @@ module ActionView ) options[:url] ||= if options.key?(:format) - polymorphic_path(record, format: options.delete(:format)) - else - polymorphic_path(record, {}) - end + polymorphic_path(record, format: options.delete(:format)) + else + polymorphic_path(record, {}) + end end private :apply_form_for_options! @@ -860,24 +860,6 @@ module ActionView # # file_field(:attachment, :file, class: 'file_input') # # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" /> - # - # ==== Gotcha - # - # The HTML specification says that when a file field is empty, web browsers - # do not send any value to the server. Unfortunately this introduces a - # gotcha: if a +User+ model has an +avatar+ field, and no file is selected, - # then the +avatar+ parameter is empty. Thus, any mass-assignment idiom like - # - # @user.update(params[:user]) - # - # wouldn't update the +avatar+ field. - # - # To prevent this, the helper generates an auxiliary hidden field before - # every file field. The hidden field has the same name as the file one and - # a blank value. - # - # In case you don't want the helper to generate this hidden field you can - # specify the <tt>include_hidden: false</tt> option. def file_field(object_name, method, options = {}) Tags::FileField.new(object_name, method, self, options).render end @@ -983,6 +965,7 @@ module ActionView # # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" /> # # <input type="radio" id="post_category_java" name="post[category]" value="java" /> # + # # Let's say that @user.receive_newsletter returns "no": # radio_button("user", "receive_newsletter", "yes") # radio_button("user", "receive_newsletter", "no") # # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" /> @@ -1092,42 +1075,9 @@ module ActionView Tags::TimeField.new(object_name, method, self, options).render end - # Returns a text_field of type "datetime". - # - # datetime_field("user", "born_on") - # # => <input id="user_born_on" name="user[born_on]" type="datetime" /> - # - # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T.%L%z" - # on the object's value, which makes it behave as expected for instances - # of DateTime and ActiveSupport::TimeWithZone. - # - # @user.born_on = Date.new(1984, 1, 12) - # datetime_field("user", "born_on") - # # => <input id="user_born_on" name="user[born_on]" type="datetime" value="1984-01-12T00:00:00.000+0000" /> - # - # You can create values for the "min" and "max" attributes by passing - # instances of Date or Time to the options hash. - # - # datetime_field("user", "born_on", min: Date.today) - # # => <input id="user_born_on" name="user[born_on]" type="datetime" min="2014-05-20T00:00:00.000+0000" /> - # - # Alternatively, you can pass a String formatted as an ISO8601 datetime - # with UTC offset as the values for "min" and "max." - # - # datetime_field("user", "born_on", min: "2014-05-20T00:00:00+0000") - # # => <input id="user_born_on" name="user[born_on]" type="datetime" min="2014-05-20T00:00:00.000+0000" /> - # - def datetime_field(object_name, method, options = {}) - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - datetime_field is deprecated and will be removed in Rails 5.1. - Use datetime_local_field instead. - MESSAGE - Tags::DatetimeField.new(object_name, method, self, options).render - end - # Returns a text_field of type "datetime-local". # - # datetime_local_field("user", "born_on") + # datetime_field("user", "born_on") # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" /> # # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T" @@ -1135,25 +1085,27 @@ module ActionView # of DateTime and ActiveSupport::TimeWithZone. # # @user.born_on = Date.new(1984, 1, 12) - # datetime_local_field("user", "born_on") + # datetime_field("user", "born_on") # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" value="1984-01-12T00:00:00" /> # # You can create values for the "min" and "max" attributes by passing # instances of Date or Time to the options hash. # - # datetime_local_field("user", "born_on", min: Date.today) + # datetime_field("user", "born_on", min: Date.today) # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" min="2014-05-20T00:00:00.000" /> # # Alternatively, you can pass a String formatted as an ISO8601 datetime as # the values for "min" and "max." # - # datetime_local_field("user", "born_on", min: "2014-05-20T00:00:00") + # datetime_field("user", "born_on", min: "2014-05-20T00:00:00") # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" min="2014-05-20T00:00:00.000" /> # - def datetime_local_field(object_name, method, options = {}) + def datetime_field(object_name, method, options = {}) Tags::DatetimeLocalField.new(object_name, method, self, options).render end + alias datetime_local_field datetime_field + # Returns a text_field of type "month". # # month_field("user", "born_on") @@ -1319,7 +1271,7 @@ module ActionView end def self._to_partial_path - @_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/, '') + @_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/, "") end def to_partial_path @@ -1335,7 +1287,7 @@ module ActionView @object_name, @object, @template, @options = object_name, object, template, options @default_options = @options ? @options.slice(:index, :namespace) : {} if @object_name.to_s.match(/\[\]$/) - if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:to_param) + if (object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")) && object.respond_to?(:to_param) @auto_index = object.to_param else raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}" @@ -1622,13 +1574,13 @@ module ActionView end record_name = if index - "#{object_name}[#{index}][#{record_name}]" - elsif record_name.to_s.end_with?('[]') - record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]") - "#{object_name}#{record_name}" - else - "#{object_name}[#{record_name}]" - end + "#{object_name}[#{index}][#{record_name}]" + elsif record_name.to_s.end_with?("[]") + record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]") + "#{object_name}#{record_name}" + else + "#{object_name}[#{record_name}]" + end fields_options[:child_index] = index @template.fields_for(record_name, record_object, fields_options, &block) @@ -1760,7 +1712,7 @@ module ActionView # # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" /> # # <input type="radio" id="post_category_java" name="post[category]" value="java" /> # - # # Let's say that @user.category returns "no": + # # Let's say that @user.receive_newsletter returns "no": # radio_button("receive_newsletter", "yes") # radio_button("receive_newsletter", "no") # # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" /> diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index b277efd7b6..07d4310a4e 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -1,9 +1,9 @@ -require 'cgi' -require 'erb' -require 'action_view/helpers/form_helper' -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/array/wrap' +require "cgi" +require "erb" +require "action_view/helpers/form_helper" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/array/wrap" module ActionView # = Action View Form Option Helpers @@ -363,7 +363,7 @@ module ActionView html_attributes[:disabled] ||= disabled && option_value_selected?(value, disabled) html_attributes[:value] = value - content_tag_string(:option, text, html_attributes) + tag_builder.content_tag_string(:option, text, html_attributes) end.join("\n").html_safe end @@ -578,7 +578,7 @@ module ActionView end zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected) - zone_options.safe_concat content_tag("option".freeze, '-------------', value: '', disabled: true) + zone_options.safe_concat content_tag("option".freeze, "-------------", value: "", disabled: true) zone_options.safe_concat "\n" zones = zones - priority_zones @@ -651,12 +651,12 @@ module ActionView # The HTML specification says when nothing is select on a collection of radio buttons # web browsers do not send any value to server. # Unfortunately this introduces a gotcha: - # if a +User+ model has a +category_id+ field, and in the form none category is selected no +category_id+ parameter is sent. So, - # any strong parameters idiom like + # if a +User+ model has a +category_id+ field and in the form no category is selected, no +category_id+ parameter is sent. So, + # any strong parameters idiom like: # # params.require(:user).permit(...) # - # will raise an error since no +{user: ...}+ will be present. + # will raise an error since no <tt>{user: ...}</tt> will be present. # # To prevent this the helper generates an auxiliary hidden field before # every collection of radio buttons. The hidden field has the same name as collection radio button and blank value. @@ -800,7 +800,7 @@ module ActionView end def prompt_text(prompt) - prompt.kind_of?(String) ? prompt : I18n.translate('helpers.select.prompt', default: 'Please select') + prompt.kind_of?(String) ? prompt : I18n.translate("helpers.select.prompt", default: "Please select") end end diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index 82f2fd30c7..7bd473507b 100644 --- a/actionview/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -1,7 +1,7 @@ -require 'cgi' -require 'action_view/helpers/tag_helper' -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/module/attribute_accessors' +require "cgi" +require "action_view/helpers/tag_helper" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/module/attribute_accessors" module ActionView # = Action View Form Tag Helpers @@ -134,11 +134,11 @@ module ActionView if options.include?(:include_blank) include_blank = options.delete(:include_blank) - options_for_blank_options_tag = { value: '' } + options_for_blank_options_tag = { value: "" } if include_blank == true - include_blank = '' - options_for_blank_options_tag[:label] = ' ' + include_blank = "" + options_for_blank_options_tag[:label] = " " end if include_blank @@ -147,7 +147,7 @@ module ActionView end if prompt = options.delete(:prompt) - option_tags = content_tag("option".freeze, prompt, value: '').safe_concat(option_tags) + option_tags = content_tag("option".freeze, prompt, value: "").safe_concat(option_tags) end content_tag "select".freeze, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys) @@ -518,12 +518,12 @@ module ActionView options ||= {} end - options = { 'name' => 'button', 'type' => 'submit' }.merge!(options.stringify_keys) + options = { "name" => "button", "type" => "submit" }.merge!(options.stringify_keys) if block_given? content_tag :button, options, &block else - content_tag :button, content_or_options || 'Button', options + content_tag :button, content_or_options || "Button", options end end @@ -685,7 +685,7 @@ module ActionView text_field_tag(name, value, options.merge(type: :time)) end - # Creates a text field of type "datetime". + # Creates a text field of type "datetime-local". # # === Options # * <tt>:min</tt> - The minimum acceptable value. @@ -693,23 +693,10 @@ module ActionView # * <tt>:step</tt> - The acceptable value granularity. # * Otherwise accepts the same options as text_field_tag. def datetime_field_tag(name, value = nil, options = {}) - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - datetime_field_tag is deprecated and will be removed in Rails 5.1. - Use datetime_local_field_tag instead. - MESSAGE - text_field_tag(name, value, options.merge(type: :datetime)) + text_field_tag(name, value, options.merge(type: "datetime-local")) end - # Creates a text field of type "datetime-local". - # - # === Options - # * <tt>:min</tt> - The minimum acceptable value. - # * <tt>:max</tt> - The maximum acceptable value. - # * <tt>:step</tt> - The acceptable value granularity. - # * Otherwise accepts the same options as text_field_tag. - def datetime_local_field_tag(name, value = nil, options = {}) - text_field_tag(name, value, options.merge(type: 'datetime-local')) - end + alias datetime_local_field_tag datetime_field_tag # Creates a text field of type "month". # @@ -870,11 +857,12 @@ module ActionView authenticity_token = html_options.delete("authenticity_token") method = html_options.delete("method").to_s.downcase - method_tag = case method - when 'get' + method_tag = \ + case method + when "get" html_options["method"] = "get" - '' - when 'post', '' + "" + when "post", "" html_options["method"] = "post" token_tag(authenticity_token, form_options: { action: html_options["action"], @@ -886,7 +874,7 @@ module ActionView action: html_options["action"], method: method }) - end + end if html_options.delete("enforce_utf8") { true } utf8_enforcer_tag + method_tag @@ -908,7 +896,7 @@ module ActionView # see http://www.w3.org/TR/html4/types.html#type-name def sanitize_to_id(name) - name.to_s.delete(']').tr('^-a-zA-Z0-9:.', "_") + name.to_s.delete("]").tr("^-a-zA-Z0-9:.", "_") end end end diff --git a/actionview/lib/action_view/helpers/javascript_helper.rb b/actionview/lib/action_view/helpers/javascript_helper.rb index ed7e882c94..22e1e74ad6 100644 --- a/actionview/lib/action_view/helpers/javascript_helper.rb +++ b/actionview/lib/action_view/helpers/javascript_helper.rb @@ -1,11 +1,11 @@ -require 'action_view/helpers/tag_helper' +require "action_view/helpers/tag_helper" module ActionView module Helpers module JavaScriptHelper JS_ESCAPE_MAP = { '\\' => '\\\\', - '</' => '<\/', + "</" => '<\/', "\r\n" => '\n', "\n" => '\n', "\r" => '\n', @@ -13,8 +13,8 @@ module ActionView "'" => "\\'" } - JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '
' - JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '
' + JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = "
" + JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = "
" # Escapes carriage returns and single and double quotes for JavaScript segments. # @@ -24,10 +24,10 @@ module ActionView # $('some_element').replaceWith('<%= j render 'some/element_template' %>'); def escape_javascript(javascript) if javascript - result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] } + result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) { |match| JS_ESCAPE_MAP[match] } javascript.html_safe? ? result.html_safe : result else - '' + "" end end diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb index 23081c5f07..75b898c3e9 100644 --- a/actionview/lib/action_view/helpers/number_helper.rb +++ b/actionview/lib/action_view/helpers/number_helper.rb @@ -1,11 +1,10 @@ -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/string/output_safety' -require 'active_support/number_helper' +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/string/output_safety" +require "active_support/number_helper" module ActionView # = Action View Number Helpers module Helpers #:nodoc: - # Provides methods for converting numbers into formatted strings. # Methods are provided for phone numbers, currency, percentage, # precision, positional notation, file size and pretty printing. @@ -13,7 +12,6 @@ module ActionView # Most methods expect a +number+ argument, and will return it # unchanged if can't be converted into a valid number. module NumberHelper - # Raised when argument +number+ param given to the helpers is invalid and # the option :raise is set to +true+. class InvalidNumberError < StandardError @@ -393,53 +391,53 @@ module ActionView private - def delegate_number_helper_method(method, number, options) - return unless number - options = escape_unsafe_options(options.symbolize_keys) + def delegate_number_helper_method(method, number, options) + return unless number + options = escape_unsafe_options(options.symbolize_keys) - wrap_with_output_safety_handling(number, options.delete(:raise)) { - ActiveSupport::NumberHelper.public_send(method, number, options) - } - end + wrap_with_output_safety_handling(number, options.delete(:raise)) { + ActiveSupport::NumberHelper.public_send(method, number, options) + } + end - def escape_unsafe_options(options) - options[:format] = ERB::Util.html_escape(options[:format]) if options[:format] - options[:negative_format] = ERB::Util.html_escape(options[:negative_format]) if options[:negative_format] - options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator] - options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter] - options[:unit] = ERB::Util.html_escape(options[:unit]) if options[:unit] && !options[:unit].html_safe? - options[:units] = escape_units(options[:units]) if options[:units] && Hash === options[:units] - options - end + def escape_unsafe_options(options) + options[:format] = ERB::Util.html_escape(options[:format]) if options[:format] + options[:negative_format] = ERB::Util.html_escape(options[:negative_format]) if options[:negative_format] + options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator] + options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter] + options[:unit] = ERB::Util.html_escape(options[:unit]) if options[:unit] && !options[:unit].html_safe? + options[:units] = escape_units(options[:units]) if options[:units] && Hash === options[:units] + options + end - def escape_units(units) - Hash[units.map do |k, v| - [k, ERB::Util.html_escape(v)] - end] - end + def escape_units(units) + Hash[units.map do |k, v| + [k, ERB::Util.html_escape(v)] + end] + end - def wrap_with_output_safety_handling(number, raise_on_invalid, &block) - valid_float = valid_float?(number) - raise InvalidNumberError, number if raise_on_invalid && !valid_float + def wrap_with_output_safety_handling(number, raise_on_invalid, &block) + valid_float = valid_float?(number) + raise InvalidNumberError, number if raise_on_invalid && !valid_float - formatted_number = yield + formatted_number = yield - if valid_float || number.html_safe? - formatted_number.html_safe - else - formatted_number + if valid_float || number.html_safe? + formatted_number.html_safe + else + formatted_number + end end - end - def valid_float?(number) - !parse_float(number, false).nil? - end + def valid_float?(number) + !parse_float(number, false).nil? + end - def parse_float(number, raise_error) - Float(number) - rescue ArgumentError, TypeError - raise InvalidNumberError, number if raise_error - end + def parse_float(number, raise_error) + Float(number) + rescue ArgumentError, TypeError + raise InvalidNumberError, number if raise_error + end end end end diff --git a/actionview/lib/action_view/helpers/output_safety_helper.rb b/actionview/lib/action_view/helpers/output_safety_helper.rb index d4b55423a8..8e63e59fac 100644 --- a/actionview/lib/action_view/helpers/output_safety_helper.rb +++ b/actionview/lib/action_view/helpers/output_safety_helper.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/output_safety' +require "active_support/core_ext/string/output_safety" module ActionView #:nodoc: # = Action View Raw Output Helper @@ -42,9 +42,9 @@ module ActionView #:nodoc: options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) default_connectors = { - :words_connector => ', ', - :two_words_connector => ' and ', - :last_word_connector => ', and ' + words_connector: ", ", + two_words_connector: " and ", + last_word_connector: ", and " } if defined?(I18n) i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {}) @@ -54,7 +54,7 @@ module ActionView #:nodoc: case array.length when 0 - ''.html_safe + "".html_safe when 1 ERB::Util.html_escape(array[0]) when 2 diff --git a/actionview/lib/action_view/helpers/rendering_helper.rb b/actionview/lib/action_view/helpers/rendering_helper.rb index c98f2d74a8..7d7f2393ff 100644 --- a/actionview/lib/action_view/helpers/rendering_helper.rb +++ b/actionview/lib/action_view/helpers/rendering_helper.rb @@ -27,12 +27,12 @@ module ActionView case options when Hash if block_given? - view_renderer.render_partial(self, options.merge(:partial => options[:layout]), &block) + view_renderer.render_partial(self, options.merge(partial: options[:layout]), &block) else view_renderer.render(self, options) end else - view_renderer.render_partial(self, :partial => options, :locals => locals, &block) + view_renderer.render_partial(self, partial: options, locals: locals, &block) end end diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb index f9784c3483..3d6ff598ee 100644 --- a/actionview/lib/action_view/helpers/sanitize_helper.rb +++ b/actionview/lib/action_view/helpers/sanitize_helper.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/object/try' -require 'rails-html-sanitizer' +require "active_support/core_ext/object/try" +require "rails-html-sanitizer" module ActionView # = Action View Sanitize Helpers diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb index 42e7358a1d..b625c1a194 100644 --- a/actionview/lib/action_view/helpers/tag_helper.rb +++ b/actionview/lib/action_view/helpers/tag_helper.rb @@ -1,39 +1,208 @@ -require 'active_support/core_ext/string/output_safety' -require 'set' +# frozen-string-literal: true + +require "active_support/core_ext/string/output_safety" +require "set" module ActionView # = Action View Tag Helpers module Helpers #:nodoc: - # Provides methods to generate HTML tags programmatically when you can't use - # a Builder. By default, they output XHTML compliant tags. + # Provides methods to generate HTML tags programmatically both as a modern + # HTML5 compliant builder style and legacy XHTML compliant tags. module TagHelper extend ActiveSupport::Concern include CaptureHelper include OutputSafetyHelper - BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer - autoplay controls loop selected hidden scoped async - defer reversed ismap seamless muted required - autofocus novalidate formnovalidate open pubdate - itemscope allowfullscreen default inert sortable - truespeed typemustmatch).to_set + BOOLEAN_ATTRIBUTES = %w(allowfullscreen async autofocus autoplay checked + compact controls declare default defaultchecked + defaultmuted defaultselected defer disabled + enabled formnovalidate hidden indeterminate inert + ismap itemscope loop multiple muted nohref + noresize noshade novalidate nowrap open + pauseonexit readonly required reversed scoped + seamless selected sortable truespeed typemustmatch + visible).to_set BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym)) - TAG_PREFIXES = ['aria', 'data', :aria, :data].to_set + TAG_PREFIXES = ["aria", "data", :aria, :data].to_set - PRE_CONTENT_STRINGS = Hash.new { "".freeze } + PRE_CONTENT_STRINGS = Hash.new { "" } PRE_CONTENT_STRINGS[:textarea] = "\n" PRE_CONTENT_STRINGS["textarea"] = "\n" + class TagBuilder #:nodoc: + include CaptureHelper + include OutputSafetyHelper + + VOID_ELEMENTS = %i(area base br col embed hr img input keygen link meta param source track wbr).to_set + + def initialize(view_context) + @view_context = view_context + end + + def tag_string(name, content = nil, escape_attributes: true, **options, &block) + content = @view_context.capture(self, &block) if block_given? + if VOID_ELEMENTS.include?(name) && content.nil? + "<#{name.to_s.dasherize}#{tag_options(options, escape_attributes)}>".html_safe + else + content_tag_string(name.to_s.dasherize, content || "", options, escape_attributes) + end + end + + def content_tag_string(name, content, options, escape = true) + tag_options = tag_options(options, escape) if options + content = ERB::Util.unwrapped_html_escape(content) if escape + "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe + end + + def tag_options(options, escape = true) + return if options.blank? + output = "".dup + sep = " " + options.each_pair do |key, value| + if TAG_PREFIXES.include?(key) && value.is_a?(Hash) + value.each_pair do |k, v| + next if v.nil? + output << sep + output << prefix_tag_option(key, k, v, escape) + end + elsif BOOLEAN_ATTRIBUTES.include?(key) + if value + output << sep + output << boolean_tag_option(key) + end + elsif !value.nil? + output << sep + output << tag_option(key, value, escape) + end + end + output unless output.empty? + end + + def boolean_tag_option(key) + %(#{key}="#{key}") + end + + def tag_option(key, value, escape) + if value.is_a?(Array) + value = escape ? safe_join(value, " ".freeze) : value.join(" ".freeze) + else + value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s + end + %(#{key}="#{value.gsub('"'.freeze, '"'.freeze)}") + end + + private + def prefix_tag_option(prefix, key, value, escape) + key = "#{prefix}-#{key.to_s.dasherize}" + unless value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(BigDecimal) + value = value.to_json + end + tag_option(key, value, escape) + end + + def respond_to_missing?(*args) + true + end + + def method_missing(called, *args, &block) + tag_string(called, *args, &block) + end + end - # Returns an empty HTML tag of type +name+ which by default is XHTML + # Returns an HTML tag. + # + # === Building HTML tags + # + # Builds HTML5 compliant tags with a tag proxy. Every tag can be built with: + # + # tag.<tag name>(optional content, options) + # + # where tag name can be e.g. br, div, section, article, or any tag really. + # + # ==== Passing content + # + # Tags can pass content to embed within it: + # + # tag.h1 'All titles fit to print' # => <h1>All titles fit to print</h1> + # + # tag.div tag.p('Hello world!') # => <div><p>Hello world!</p></div> + # + # Content can also be captured with a block, which is useful in templates: + # + # <%= tag.p do %> + # The next great American novel starts here. + # <% end %> + # # => <p>The next great American novel starts here.</p> + # + # ==== Options + # + # Any passed options become attributes on the generated tag. + # You can only use symbols (not strings) for the attribute names. + # + # tag.section class: %w( kitties puppies ) + # # => <section class="kitties puppies"></section> + # + # tag.section id: dom_id(@post) + # # => <section id="<generated dom id>"></section> + # + # Pass +true+ for any attributes that can render with no values, like +disabled+ and +readonly+. + # + # tag.input type: 'text', disabled: true + # # => <input type="text" disabled="disabled"> + # + # HTML5 <tt>data-*</tt> attributes can be set with a single +data+ key + # pointing to a hash of sub-attributes. + # + # To play nicely with JavaScript conventions, sub-attributes are dasherized. + # + # tag.article data: { user_id: 123 } + # # => <article data-user-id="123"></article> + # + # Thus <tt>data-user-id</tt> can be accessed as <tt>dataset.userId</tt>. + # + # Data attribute values are encoded to JSON, with the exception of strings, symbols and + # BigDecimals. + # This may come in handy when using jQuery's HTML5-aware <tt>.data()</tt> + # from 1.4.3. + # + # tag.div data: { city_state: %w( Chigaco IL ) } + # # => <div data-city-state="["Chicago","IL"]"></div> + # + # The generated attributes are escaped by default. This can be disabled using + # +escape_attributes+. + # + # tag.img src: 'open & shut.png' + # # => <img src="open & shut.png"> + # + # tag.img src: 'open & shut.png', escape_attributes: false + # # => <img src="open & shut.png"> + # + # The tag builder respects + # {HTML5 void elements}[https://www.w3.org/TR/html5/syntax.html#void-elements] + # if no content is passed, and omits closing tags for those elements. + # + # # A standard element: + # tag.div # => <div></div> + # + # # A void element: + # tag.br # => <br> + # + # === Legacy syntax + # + # The following format is for legacy syntax support. It will be deprecated in future versions of Rails. + # + # tag(name, options = nil, open = false, escape = true) + # + # It returns an empty HTML tag of type +name+ which by default is XHTML # compliant. Set +open+ to true to create an open tag compatible # with HTML 4.0 and below. Add HTML attributes by passing an attributes # hash to +options+. Set +escape+ to false to disable attribute value # escaping. # - # ==== Options + # ==== Options (Legacy syntax) + # # You can use symbols or strings for the attribute names. # # Use +true+ with boolean attributes that can render with no value, like @@ -42,16 +211,8 @@ module ActionView # HTML5 <tt>data-*</tt> attributes can be set with a single +data+ key # pointing to a hash of sub-attributes. # - # To play nicely with JavaScript conventions sub-attributes are dasherized. - # For example, a key +user_id+ would render as <tt>data-user-id</tt> and - # thus accessed as <tt>dataset.userId</tt>. - # - # Values are encoded to JSON, with the exception of strings, symbols and - # BigDecimals. - # This may come in handy when using jQuery's HTML5-aware <tt>.data()</tt> - # from 1.4.3. + # ==== Examples (Legacy syntax) # - # ==== Examples # tag("br") # # => <br /> # @@ -72,8 +233,12 @@ module ActionView # # tag("div", data: {name: 'Stephen', city_state: %w(Chicago IL)}) # # => <div data-name="Stephen" data-city-state="["Chicago","IL"]" /> - def tag(name, options = nil, open = false, escape = true) - "<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe + def tag(name = nil, options = nil, open = false, escape = true) + if name.nil? + tag_builder + else + "<#{name}#{tag_builder.tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe + end end # Returns an HTML block tag of type +name+ surrounding the +content+. Add @@ -81,6 +246,7 @@ module ActionView # Instead of passing the content as an argument, you can also use a block # in which case, you pass your +options+ as the second parameter. # Set escape to false to disable attribute value escaping. + # Note: this is legacy syntax, see +tag+ method description for details. # # ==== Options # The +options+ hash can be used with attributes with no value like (<tt>disabled</tt> and @@ -104,9 +270,9 @@ module ActionView def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block) if block_given? options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash) - content_tag_string(name, capture(&block), options, escape) + tag_builder.content_tag_string(name, capture(&block), options, escape) else - content_tag_string(name, content_or_options_with_block, options, escape) + tag_builder.content_tag_string(name, content_or_options_with_block, options, escape) end end @@ -124,7 +290,7 @@ module ActionView # cdata_section("hello]]>world") # # => <![CDATA[hello]]]]><![CDATA[>world]]> def cdata_section(content) - splitted = content.to_s.gsub(/\]\]\>/, ']]]]><![CDATA[>') + splitted = content.to_s.gsub(/\]\]\>/, "]]]]><![CDATA[>") "<![CDATA[#{splitted}]]>".html_safe end @@ -140,56 +306,8 @@ module ActionView end private - - def content_tag_string(name, content, options, escape = true) - tag_options = tag_options(options, escape) if options - content = ERB::Util.unwrapped_html_escape(content) if escape - "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe - end - - def tag_options(options, escape = true) - return if options.blank? - output = "" - sep = " ".freeze - options.each_pair do |key, value| - if TAG_PREFIXES.include?(key) && value.is_a?(Hash) - value.each_pair do |k, v| - next if v.nil? - output << sep - output << prefix_tag_option(key, k, v, escape) - end - elsif BOOLEAN_ATTRIBUTES.include?(key) - if value - output << sep - output << boolean_tag_option(key) - end - elsif !value.nil? - output << sep - output << tag_option(key, value, escape) - end - end - output unless output.empty? - end - - def prefix_tag_option(prefix, key, value, escape) - key = "#{prefix}-#{key.to_s.dasherize}" - unless value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(BigDecimal) - value = value.to_json - end - tag_option(key, value, escape) - end - - def boolean_tag_option(key) - %(#{key}="#{key}") - end - - def tag_option(key, value, escape) - if value.is_a?(Array) - value = escape ? safe_join(value, " ".freeze) : value.join(" ".freeze) - else - value = escape ? ERB::Util.unwrapped_html_escape(value) : value - end - %(#{key}="#{value}") + def tag_builder + @tag_builder ||= TagBuilder.new(self) end end end diff --git a/actionview/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb index d57f26ba4f..e3e3c8b109 100644 --- a/actionview/lib/action_view/helpers/tags/base.rb +++ b/actionview/lib/action_view/helpers/tags/base.rb @@ -24,136 +24,136 @@ module ActionView private - def value(object) - object.public_send @method_name if object - end + def value(object) + object.public_send @method_name if object + end - def value_before_type_cast(object) - unless object.nil? - method_before_type_cast = @method_name + "_before_type_cast" + def value_before_type_cast(object) + unless object.nil? + method_before_type_cast = @method_name + "_before_type_cast" - if value_came_from_user?(object) && object.respond_to?(method_before_type_cast) - object.public_send(method_before_type_cast) - else - value(object) + if value_came_from_user?(object) && object.respond_to?(method_before_type_cast) + object.public_send(method_before_type_cast) + else + value(object) + end end end - end - def value_came_from_user?(object) - method_name = "#{@method_name}_came_from_user?" - !object.respond_to?(method_name) || object.public_send(method_name) - end + def value_came_from_user?(object) + method_name = "#{@method_name}_came_from_user?" + !object.respond_to?(method_name) || object.public_send(method_name) + end - def retrieve_object(object) - if object - object - elsif @template_object.instance_variable_defined?("@#{@object_name}") - @template_object.instance_variable_get("@#{@object_name}") + def retrieve_object(object) + if object + object + elsif @template_object.instance_variable_defined?("@#{@object_name}") + @template_object.instance_variable_get("@#{@object_name}") + end + rescue NameError + # As @object_name may contain the nested syntax (item[subobject]) we need to fallback to nil. + nil end - rescue NameError - # As @object_name may contain the nested syntax (item[subobject]) we need to fallback to nil. - nil - end - def retrieve_autoindex(pre_match) - object = self.object || @template_object.instance_variable_get("@#{pre_match}") - if object && object.respond_to?(:to_param) - object.to_param - else - raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}" + def retrieve_autoindex(pre_match) + object = self.object || @template_object.instance_variable_get("@#{pre_match}") + if object && object.respond_to?(:to_param) + object.to_param + else + raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}" + end end - end - def add_default_name_and_id_for_value(tag_value, options) - if tag_value.nil? - add_default_name_and_id(options) - else - specified_id = options["id"] - add_default_name_and_id(options) + def add_default_name_and_id_for_value(tag_value, options) + if tag_value.nil? + add_default_name_and_id(options) + else + specified_id = options["id"] + add_default_name_and_id(options) - if specified_id.blank? && options["id"].present? - options["id"] += "_#{sanitized_value(tag_value)}" + if specified_id.blank? && options["id"].present? + options["id"] += "_#{sanitized_value(tag_value)}" + end end end - end - def add_default_name_and_id(options) - index = name_and_id_index(options) - options["name"] = options.fetch("name"){ tag_name(options["multiple"], index) } - options["id"] = options.fetch("id"){ tag_id(index) } - if namespace = options.delete("namespace") - options['id'] = options['id'] ? "#{namespace}_#{options['id']}" : namespace + def add_default_name_and_id(options) + index = name_and_id_index(options) + options["name"] = options.fetch("name") { tag_name(options["multiple"], index) } + options["id"] = options.fetch("id") { tag_id(index) } + if namespace = options.delete("namespace") + options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace + end end - end - def tag_name(multiple = false, index = nil) - # a little duplication to construct less strings - if index - "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}" - else - "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}" + def tag_name(multiple = false, index = nil) + # a little duplication to construct less strings + if index + "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}" + else + "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}" + end end - end - def tag_id(index = nil) - # a little duplication to construct less strings - if index - "#{sanitized_object_name}_#{index}_#{sanitized_method_name}" - else - "#{sanitized_object_name}_#{sanitized_method_name}" + def tag_id(index = nil) + # a little duplication to construct less strings + if index + "#{sanitized_object_name}_#{index}_#{sanitized_method_name}" + else + "#{sanitized_object_name}_#{sanitized_method_name}" + end end - end - def sanitized_object_name - @sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "") - end + def sanitized_object_name + @sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "") + end - def sanitized_method_name - @sanitized_method_name ||= @method_name.sub(/\?$/,"") - end + def sanitized_method_name + @sanitized_method_name ||= @method_name.sub(/\?$/,"") + end - def sanitized_value(value) - value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase - end + def sanitized_value(value) + value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase + end - def select_content_tag(option_tags, options, html_options) - html_options = html_options.stringify_keys - add_default_name_and_id(html_options) + def select_content_tag(option_tags, options, html_options) + html_options = html_options.stringify_keys + add_default_name_and_id(html_options) - if placeholder_required?(html_options) - raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false - options[:include_blank] ||= true unless options[:prompt] - end + if placeholder_required?(html_options) + raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false + options[:include_blank] ||= true unless options[:prompt] + end - value = options.fetch(:selected) { value(object) } - select = content_tag("select", add_options(option_tags, options, value), html_options) + value = options.fetch(:selected) { value(object) } + select = content_tag("select", add_options(option_tags, options, value), html_options) - if html_options["multiple"] && options.fetch(:include_hidden, true) - tag("input", :disabled => html_options["disabled"], :name => html_options["name"], :type => "hidden", :value => "") + select - else - select + if html_options["multiple"] && options.fetch(:include_hidden, true) + tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "") + select + else + select + end end - end - def placeholder_required?(html_options) - # See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required - html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1 - end - - def add_options(option_tags, options, value = nil) - if options[:include_blank] - option_tags = content_tag_string('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags + def placeholder_required?(html_options) + # See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required + html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1 end - if value.blank? && options[:prompt] - option_tags = content_tag_string('option', prompt_text(options[:prompt]), :value => '') + "\n" + option_tags + + def add_options(option_tags, options, value = nil) + if options[:include_blank] + option_tags = tag_builder.content_tag_string("option", options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, value: "") + "\n" + option_tags + end + if value.blank? && options[:prompt] + option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), value: "") + "\n" + option_tags + end + option_tags end - option_tags - end - def name_and_id_index(options) - options.key?("index") ? options.delete("index") || "" : @auto_index - end + def name_and_id_index(options) + options.key?("index") ? options.delete("index") || "" : @auto_index + end end end end diff --git a/actionview/lib/action_view/helpers/tags/check_box.rb b/actionview/lib/action_view/helpers/tags/check_box.rb index 6d51f2629a..02f87fc89f 100644 --- a/actionview/lib/action_view/helpers/tags/check_box.rb +++ b/actionview/lib/action_view/helpers/tags/check_box.rb @@ -1,4 +1,4 @@ -require 'action_view/helpers/tags/checkable' +require "action_view/helpers/tags/checkable" module ActionView module Helpers @@ -38,26 +38,26 @@ module ActionView private - def checked?(value) - case value - when TrueClass, FalseClass - value == !!@checked_value - when NilClass - false - when String - value == @checked_value - else - if value.respond_to?(:include?) - value.include?(@checked_value) + def checked?(value) + case value + when TrueClass, FalseClass + value == !!@checked_value + when NilClass + false + when String + value == @checked_value else - value.to_i == @checked_value.to_i + if value.respond_to?(:include?) + value.include?(@checked_value) + else + value.to_i == @checked_value.to_i + end end end - end - def hidden_field_for_checkbox(options) - @unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe - end + def hidden_field_for_checkbox(options) + @unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe + end end end end diff --git a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb index 3dda47a458..2a6bf49567 100644 --- a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb +++ b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb @@ -1,4 +1,4 @@ -require 'action_view/helpers/tags/collection_helpers' +require "action_view/helpers/tags/collection_helpers" module ActionView module Helpers @@ -20,13 +20,13 @@ module ActionView private - def render_component(builder) - builder.check_box + builder.label - end + def render_component(builder) + builder.check_box + builder.label + end - def hidden_field_name #:nodoc: - "#{super}[]" - end + def hidden_field_name #:nodoc: + "#{super}[]" + end end end end diff --git a/actionview/lib/action_view/helpers/tags/collection_helpers.rb b/actionview/lib/action_view/helpers/tags/collection_helpers.rb index fb51460c8e..36575b2fd0 100644 --- a/actionview/lib/action_view/helpers/tags/collection_helpers.rb +++ b/actionview/lib/action_view/helpers/tags/collection_helpers.rb @@ -36,81 +36,81 @@ module ActionView private - def instantiate_builder(builder_class, item, value, text, html_options) - builder_class.new(@template_object, @object_name, @method_name, item, - sanitize_attribute_name(value), text, value, html_options) - end - - # Generate default options for collection helpers, such as :checked and - # :disabled. - def default_html_options_for_collection(item, value) #:nodoc: - html_options = @html_options.dup - - [:checked, :selected, :disabled, :readonly].each do |option| - current_value = @options[option] - next if current_value.nil? + def instantiate_builder(builder_class, item, value, text, html_options) + builder_class.new(@template_object, @object_name, @method_name, item, + sanitize_attribute_name(value), text, value, html_options) + end - accept = if current_value.respond_to?(:call) - current_value.call(item) - else - Array(current_value).map(&:to_s).include?(value.to_s) + # Generate default options for collection helpers, such as :checked and + # :disabled. + def default_html_options_for_collection(item, value) #:nodoc: + html_options = @html_options.dup + + [:checked, :selected, :disabled, :readonly].each do |option| + current_value = @options[option] + next if current_value.nil? + + accept = if current_value.respond_to?(:call) + current_value.call(item) + else + Array(current_value).map(&:to_s).include?(value.to_s) + end + + if accept + html_options[option] = true + elsif option == :checked + html_options[option] = false + end end - if accept - html_options[option] = true - elsif option == :checked - html_options[option] = false - end + html_options[:object] = @object + html_options end - html_options[:object] = @object - html_options - end + def sanitize_attribute_name(value) #:nodoc: + "#{sanitized_method_name}_#{sanitized_value(value)}" + end - def sanitize_attribute_name(value) #:nodoc: - "#{sanitized_method_name}_#{sanitized_value(value)}" - end + def render_collection #:nodoc: + @collection.map do |item| + value = value_for_collection(item, @value_method) + text = value_for_collection(item, @text_method) + default_html_options = default_html_options_for_collection(item, value) + additional_html_options = option_html_attributes(item) - def render_collection #:nodoc: - @collection.map do |item| - value = value_for_collection(item, @value_method) - text = value_for_collection(item, @text_method) - default_html_options = default_html_options_for_collection(item, value) - additional_html_options = option_html_attributes(item) + yield item, value, text, default_html_options.merge(additional_html_options) + end.join.html_safe + end - yield item, value, text, default_html_options.merge(additional_html_options) - end.join.html_safe - end + def render_collection_for(builder_class, &block) #:nodoc: + options = @options.stringify_keys + rendered_collection = render_collection do |item, value, text, default_html_options| + builder = instantiate_builder(builder_class, item, value, text, default_html_options) - def render_collection_for(builder_class, &block) #:nodoc: - options = @options.stringify_keys - rendered_collection = render_collection do |item, value, text, default_html_options| - builder = instantiate_builder(builder_class, item, value, text, default_html_options) + if block_given? + @template_object.capture(builder, &block) + else + render_component(builder) + end + end - if block_given? - @template_object.capture(builder, &block) + # Prepend a hidden field to make sure something will be sent back to the + # server if all radio buttons are unchecked. + if options.fetch("include_hidden", true) + hidden_field + rendered_collection else - render_component(builder) + rendered_collection end end - # Prepend a hidden field to make sure something will be sent back to the - # server if all radio buttons are unchecked. - if options.fetch('include_hidden', true) - hidden_field + rendered_collection - else - rendered_collection + def hidden_field #:nodoc: + hidden_name = @html_options[:name] || hidden_field_name + @template_object.hidden_field_tag(hidden_name, "", id: nil) end - end - def hidden_field #:nodoc: - hidden_name = @html_options[:name] || hidden_field_name - @template_object.hidden_field_tag(hidden_name, "", id: nil) - end - - def hidden_field_name #:nodoc: - "#{tag_name(false, @options[:index])}" - end + def hidden_field_name #:nodoc: + "#{tag_name(false, @options[:index])}" + end end end end diff --git a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb index 21aaf122f8..eed7941cd6 100644 --- a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb +++ b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb @@ -1,4 +1,4 @@ -require 'action_view/helpers/tags/collection_helpers' +require "action_view/helpers/tags/collection_helpers" module ActionView module Helpers diff --git a/actionview/lib/action_view/helpers/tags/collection_select.rb b/actionview/lib/action_view/helpers/tags/collection_select.rb index 6cb2b2e0d3..4365c714eb 100644 --- a/actionview/lib/action_view/helpers/tags/collection_select.rb +++ b/actionview/lib/action_view/helpers/tags/collection_select.rb @@ -13,8 +13,8 @@ module ActionView def render option_tags_options = { - :selected => @options.fetch(:selected) { value(@object) }, - :disabled => @options[:disabled] + selected: @options.fetch(:selected) { value(@object) }, + disabled: @options[:disabled] } select_content_tag( diff --git a/actionview/lib/action_view/helpers/tags/date_select.rb b/actionview/lib/action_view/helpers/tags/date_select.rb index 0c4ac40070..006605885a 100644 --- a/actionview/lib/action_view/helpers/tags/date_select.rb +++ b/actionview/lib/action_view/helpers/tags/date_select.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/time/calculations' +require "active_support/core_ext/time/calculations" module ActionView module Helpers @@ -22,50 +22,50 @@ module ActionView private - def select_type - self.class.select_type - end + def select_type + self.class.select_type + end - def datetime_selector(options, html_options) - datetime = options.fetch(:selected) { value(object) || default_datetime(options) } - @auto_index ||= nil + def datetime_selector(options, html_options) + datetime = options.fetch(:selected) { value(object) || default_datetime(options) } + @auto_index ||= nil - options = options.dup - options[:field_name] = @method_name - options[:include_position] = true - options[:prefix] ||= @object_name - options[:index] = @auto_index if @auto_index && !options.has_key?(:index) + options = options.dup + options[:field_name] = @method_name + options[:include_position] = true + options[:prefix] ||= @object_name + options[:index] = @auto_index if @auto_index && !options.has_key?(:index) - DateTimeSelector.new(datetime, options, html_options) - end + DateTimeSelector.new(datetime, options, html_options) + end - def default_datetime(options) - return if options[:include_blank] || options[:prompt] + def default_datetime(options) + return if options[:include_blank] || options[:prompt] - case options[:default] - when nil - Time.current - when Date, Time - options[:default] - else - default = options[:default].dup + case options[:default] + when nil + Time.current + when Date, Time + options[:default] + else + default = options[:default].dup - # Rename :minute and :second to :min and :sec - default[:min] ||= default[:minute] - default[:sec] ||= default[:second] + # Rename :minute and :second to :min and :sec + default[:min] ||= default[:minute] + default[:sec] ||= default[:second] - time = Time.current + time = Time.current - [:year, :month, :day, :hour, :min, :sec].each do |key| - default[key] ||= time.send(key) - end + [:year, :month, :day, :hour, :min, :sec].each do |key| + default[key] ||= time.send(key) + end - Time.utc( - default[:year], default[:month], default[:day], - default[:hour], default[:min], default[:sec] - ) + Time.utc( + default[:year], default[:month], default[:day], + default[:hour], default[:min], default[:sec] + ) + end end - end end end end diff --git a/actionview/lib/action_view/helpers/tags/datetime_field.rb b/actionview/lib/action_view/helpers/tags/datetime_field.rb index b2cee9d198..b3940c7e44 100644 --- a/actionview/lib/action_view/helpers/tags/datetime_field.rb +++ b/actionview/lib/action_view/helpers/tags/datetime_field.rb @@ -14,7 +14,7 @@ module ActionView private def format_date(value) - value.try(:strftime, "%Y-%m-%dT%T.%L%z") + raise NotImplementedError end def datetime_value(value) diff --git a/actionview/lib/action_view/helpers/tags/file_field.rb b/actionview/lib/action_view/helpers/tags/file_field.rb index e6a1d9c62d..476b820d84 100644 --- a/actionview/lib/action_view/helpers/tags/file_field.rb +++ b/actionview/lib/action_view/helpers/tags/file_field.rb @@ -2,21 +2,6 @@ module ActionView module Helpers module Tags # :nodoc: class FileField < TextField # :nodoc: - - def render - options = @options.stringify_keys - - if options.fetch("include_hidden", true) - add_default_name_and_id(options) - options[:type] = "file" - tag("input", name: options["name"], type: "hidden", value: "") + tag("input", options) - else - options.delete("include_hidden") - @options = options - - super - end - end end end end diff --git a/actionview/lib/action_view/helpers/tags/grouped_collection_select.rb b/actionview/lib/action_view/helpers/tags/grouped_collection_select.rb index 2ed4712dac..20e312dd0f 100644 --- a/actionview/lib/action_view/helpers/tags/grouped_collection_select.rb +++ b/actionview/lib/action_view/helpers/tags/grouped_collection_select.rb @@ -15,8 +15,8 @@ module ActionView def render option_tags_options = { - :selected => @options.fetch(:selected) { value(@object) }, - :disabled => @options[:disabled] + selected: @options.fetch(:selected) { value(@object) }, + disabled: @options[:disabled] } select_content_tag( diff --git a/actionview/lib/action_view/helpers/tags/password_field.rb b/actionview/lib/action_view/helpers/tags/password_field.rb index 6099fa6f19..444ef65074 100644 --- a/actionview/lib/action_view/helpers/tags/password_field.rb +++ b/actionview/lib/action_view/helpers/tags/password_field.rb @@ -3,7 +3,7 @@ module ActionView module Tags # :nodoc: class PasswordField < TextField # :nodoc: def render - @options = {:value => nil}.merge!(@options) + @options = { value: nil }.merge!(@options) super end end diff --git a/actionview/lib/action_view/helpers/tags/radio_button.rb b/actionview/lib/action_view/helpers/tags/radio_button.rb index 4849c537a5..43dbd32083 100644 --- a/actionview/lib/action_view/helpers/tags/radio_button.rb +++ b/actionview/lib/action_view/helpers/tags/radio_button.rb @@ -1,4 +1,4 @@ -require 'action_view/helpers/tags/checkable' +require "action_view/helpers/tags/checkable" module ActionView module Helpers @@ -22,9 +22,9 @@ module ActionView private - def checked?(value) - value.to_s == @tag_value.to_s - end + def checked?(value) + value.to_s == @tag_value.to_s + end end end end diff --git a/actionview/lib/action_view/helpers/tags/select.rb b/actionview/lib/action_view/helpers/tags/select.rb index 180900cc8d..667c7e945a 100644 --- a/actionview/lib/action_view/helpers/tags/select.rb +++ b/actionview/lib/action_view/helpers/tags/select.rb @@ -13,8 +13,8 @@ module ActionView def render option_tags_options = { - :selected => @options.fetch(:selected) { value(@object) }, - :disabled => @options[:disabled] + selected: @options.fetch(:selected) { value(@object) }, + disabled: @options[:disabled] } option_tags = if grouped_choices? @@ -28,13 +28,13 @@ module ActionView private - # Grouped choices look like this: - # - # [nil, []] - # { nil => [] } - def grouped_choices? - !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last - end + # Grouped choices look like this: + # + # [nil, []] + # { nil => [] } + def grouped_choices? + !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last + end end end end diff --git a/actionview/lib/action_view/helpers/tags/text_area.rb b/actionview/lib/action_view/helpers/tags/text_area.rb index 69038c1498..31e3a9e9b1 100644 --- a/actionview/lib/action_view/helpers/tags/text_area.rb +++ b/actionview/lib/action_view/helpers/tags/text_area.rb @@ -1,4 +1,4 @@ -require 'action_view/helpers/tags/placeholderable' +require "action_view/helpers/tags/placeholderable" module ActionView module Helpers diff --git a/actionview/lib/action_view/helpers/tags/text_field.rb b/actionview/lib/action_view/helpers/tags/text_field.rb index 5c576a20ca..4306c3543d 100644 --- a/actionview/lib/action_view/helpers/tags/text_field.rb +++ b/actionview/lib/action_view/helpers/tags/text_field.rb @@ -1,4 +1,4 @@ -require 'action_view/helpers/tags/placeholderable' +require "action_view/helpers/tags/placeholderable" module ActionView module Helpers @@ -23,9 +23,9 @@ module ActionView private - def field_type - self.class.field_type - end + def field_type + self.class.field_type + end end end end diff --git a/actionview/lib/action_view/helpers/tags/translator.rb b/actionview/lib/action_view/helpers/tags/translator.rb index 8b6655481d..62b1df81c6 100644 --- a/actionview/lib/action_view/helpers/tags/translator.rb +++ b/actionview/lib/action_view/helpers/tags/translator.rb @@ -16,24 +16,24 @@ module ActionView protected - attr_reader :object_name, :method_and_value, :scope, :model + attr_reader :object_name, :method_and_value, :scope, :model private - def i18n_default - if model - key = model.model_name.i18n_key - ["#{key}.#{method_and_value}".to_sym, ""] - else - "" + def i18n_default + if model + key = model.model_name.i18n_key + ["#{key}.#{method_and_value}".to_sym, ""] + else + "" + end end - end - def human_attribute_name - if model && model.class.respond_to?(:human_attribute_name) - model.class.human_attribute_name(method_and_value) + def human_attribute_name + if model && model.class.respond_to?(:human_attribute_name) + model.class.human_attribute_name(method_and_value) + end end - end end end end diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb index 58ce042f12..bd3371ccc8 100644 --- a/actionview/lib/action_view/helpers/text_helper.rb +++ b/actionview/lib/action_view/helpers/text_helper.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/string/filters' -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/string/filters" +require "active_support/core_ext/array/extract_options" module ActionView # = Action View Text Helpers @@ -135,7 +135,7 @@ module ActionView else match = Array(phrases).map do |p| Regexp === p ? p.to_s : Regexp.escape(p) - end.join('|') + end.join("|") if block_given? text.gsub(/(#{match})(?![^<]*?>)/i) { |found| yield found } @@ -225,14 +225,7 @@ module ActionView # # pluralize(2, 'Person', locale: :de) # # => 2 Personen - def pluralize(count, singular, deprecated_plural = nil, plural: nil, locale: I18n.locale) - if deprecated_plural - ActiveSupport::Deprecation.warn("Passing plural as a positional argument " \ - "is deprecated and will be removed in Rails 5.1. Use e.g. " \ - "pluralize(1, 'person', plural: 'people') instead.") - plural ||= deprecated_plural - end - + def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale) word = if (count == 1 || count =~ /^1(\.0+)?$/) singular else @@ -269,10 +262,11 @@ module ActionView end # Returns +text+ transformed into HTML using simple formatting rules. - # Two or more consecutive newlines(<tt>\n\n</tt>) are considered as a - # paragraph and wrapped in <tt><p></tt> tags. One newline (<tt>\n</tt>) is - # considered as a linebreak and a <tt><br /></tt> tag is appended. This - # method does not remove the newlines from the +text+. + # Two or more consecutive newlines(<tt>\n\n</tt> or <tt>\r\n\r\n</tt>) are + # considered a paragraph and wrapped in <tt><p></tt> tags. One newline + # (<tt>\n</tt> or <tt>\r\n</tt>) is considered a linebreak and a + # <tt><br /></tt> tag is appended. This method does not remove the + # newlines from the +text+. # # You can pass any HTML attributes into <tt>html_options</tt>. These # will be added to all created paragraphs. @@ -357,7 +351,7 @@ module ActionView # <% end %> def cycle(first_value, *values) options = values.extract_options! - name = options.fetch(:name, 'default') + name = options.fetch(:name, "default") values.unshift(*first_value) @@ -431,17 +425,17 @@ module ActionView private - def next_index - step_index(1) - end + def next_index + step_index(1) + end - def previous_index - step_index(-1) - end + def previous_index + step_index(-1) + end - def step_index(n) - (@index + n) % @values.size - end + def step_index(n) + (@index + n) % @values.size + end end private diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb index 152e1b1211..cbabaf5757 100644 --- a/actionview/lib/action_view/helpers/translation_helper.rb +++ b/actionview/lib/action_view/helpers/translation_helper.rb @@ -1,6 +1,7 @@ -require 'action_view/helpers/tag_helper' -require 'active_support/core_ext/string/access' -require 'i18n/exceptions' +require "action_view/helpers/tag_helper" +require "active_support/core_ext/string/access" +require "active_support/core_ext/regexp" +require "i18n/exceptions" module ActionView # = Action View Translation Helpers @@ -100,12 +101,12 @@ module ActionView interpolations = options.except(:default, :scope) if interpolations.any? - title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(', ') + title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(", ") end return title unless ActionView::Base.debug_missing_translation - content_tag('span', keys.last.to_s.titleize, class: 'translation_missing', title: title) + content_tag("span", keys.last.to_s.titleize, class: "translation_missing", title: title) end end alias :t :translate @@ -133,7 +134,7 @@ module ActionView end def html_safe_translation_key?(key) - key.to_s =~ /(\b|_|\.)html$/ + /(\b|_|\.)html$/.match?(key.to_s) end end end diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index 11c7daf4da..d410976bef 100644 --- a/actionview/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -1,7 +1,8 @@ -require 'action_view/helpers/javascript_helper' -require 'active_support/core_ext/array/access' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/string/output_safety' +require "action_view/helpers/javascript_helper" +require "active_support/core_ext/array/access" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/regexp" module ActionView # = Action View URL Helpers @@ -41,14 +42,14 @@ module ActionView end def _back_url # :nodoc: - _filtered_referrer || 'javascript:history.back()' + _filtered_referrer || "javascript:history.back()" end protected :_back_url def _filtered_referrer # :nodoc: if controller.respond_to?(:request) referrer = controller.request.env["HTTP_REFERER"] - if referrer && URI(referrer).scheme != 'javascript' + if referrer && URI(referrer).scheme != "javascript" referrer end end @@ -298,34 +299,34 @@ module ActionView html_options = html_options.stringify_keys url = options.is_a?(String) ? options : url_for(options) - remote = html_options.delete('remote') - params = html_options.delete('params') + remote = html_options.delete("remote") + params = html_options.delete("params") - method = html_options.delete('method').to_s - method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.freeze.html_safe + method = html_options.delete("method").to_s + method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".freeze.html_safe - form_method = method == 'get' ? 'get' : 'post' - form_options = html_options.delete('form') || {} - form_options[:class] ||= html_options.delete('form_class') || 'button_to' + form_method = method == "get" ? "get" : "post" + form_options = html_options.delete("form") || {} + form_options[:class] ||= html_options.delete("form_class") || "button_to" form_options[:method] = form_method form_options[:action] = url form_options[:'data-remote'] = true if remote - request_token_tag = if form_method == 'post' - request_method = method.empty? ? 'post' : method + request_token_tag = if form_method == "post" + request_method = method.empty? ? "post" : method token_tag(nil, form_options: { action: url, method: request_method }) else - ''.freeze + "".freeze end html_options = convert_options_to_data_attributes(options, html_options) - html_options['type'] = 'submit' + html_options["type"] = "submit" button = if block_given? - content_tag('button', html_options, &block) + content_tag("button", html_options, &block) else - html_options['value'] = name || url - tag('input', html_options) + html_options["value"] = name || url + tag("input", html_options) end inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag) @@ -334,7 +335,7 @@ module ActionView inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value]) end end - content_tag('form', inner_tags, form_options) + content_tag("form", inner_tags, form_options) end # Creates a link tag of the given +name+ using a URL created by the set of @@ -481,7 +482,7 @@ module ActionView option = html_options.delete(item).presence || next "#{item.dasherize}=#{ERB::Util.url_encode(option)}" }.compact - extras = extras.empty? ? ''.freeze : '?' + extras.join('&') + extras = extras.empty? ? "".freeze : "?" + extras.join("&") encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@") html_options["href"] = "mailto:#{encoded_email_address}#{extras}" @@ -548,7 +549,9 @@ module ActionView request_uri = url_string.index("?") ? request.fullpath : request.path request_uri = URI.parser.unescape(request_uri).force_encoding(Encoding::BINARY) - if url_string =~ /^\w+:\/\// + url_string.chomp!("/") if url_string.start_with?("/") && url_string != "/" + + if %r{^\w+://}.match?(url_string) url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}" else url_string == request_uri @@ -559,21 +562,21 @@ module ActionView def convert_options_to_data_attributes(options, html_options) if html_options html_options = html_options.stringify_keys - html_options['data-remote'] = 'true'.freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options) + html_options["data-remote"] = "true".freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options) - method = html_options.delete('method'.freeze) + method = html_options.delete("method".freeze) add_method_to_attributes!(html_options, method) if method html_options else - link_to_remote_options?(options) ? {'data-remote' => 'true'.freeze} : {} + link_to_remote_options?(options) ? { "data-remote" => "true".freeze } : {} end end def link_to_remote_options?(options) if options.is_a?(Hash) - options.delete('remote'.freeze) || options.delete(:remote) + options.delete("remote".freeze) || options.delete(:remote) end end @@ -589,12 +592,12 @@ module ActionView token ||= form_authenticity_token(form_options: form_options) tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token) else - ''.freeze + "".freeze end end def method_tag(method) - tag('input', type: 'hidden', name: '_method', value: method.to_s) + tag("input", type: "hidden", name: "_method", value: method.to_s) end # Returns an array of hashes each containing :name and :value keys @@ -614,6 +617,17 @@ module ActionView # to_form_params({ name: 'Denmark' }, 'country') # # => [{name: 'country[name]', value: 'Denmark'}] def to_form_params(attribute, namespace = nil) # :nodoc: + attribute = if attribute.respond_to?(:permitted?) + unless attribute.permitted? + raise ArgumentError, "Attempting to generate a buttom from non-sanitized request parameters!" \ + " Whitelist and sanitize passed parameters to be secure." + end + + attribute.to_h + else + attribute + end + params = [] case attribute when Hash diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb index a74a5e05f3..b083de1396 100644 --- a/actionview/lib/action_view/layouts.rb +++ b/actionview/lib/action_view/layouts.rb @@ -1,5 +1,6 @@ require "action_view/rendering" require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/regexp" module ActionView # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in @@ -204,7 +205,7 @@ module ActionView include ActionView::Rendering included do - class_attribute :_layout, :_layout_conditions, :instance_accessor => false + class_attribute :_layout, :_layout_conditions, instance_accessor: false self._layout = nil self._layout_conditions = {} _write_layout_method @@ -223,36 +224,39 @@ module ActionView module LayoutConditions # :nodoc: private - # Determines whether the current action has a layout definition by - # checking the action name against the :only and :except conditions - # set by the <tt>layout</tt> method. - # - # ==== Returns - # * <tt>Boolean</tt> - True if the action has a layout definition, false otherwise. - def _conditional_layout? - return unless super - - conditions = _layout_conditions - - if only = conditions[:only] - only.include?(action_name) - elsif except = conditions[:except] - !except.include?(action_name) - else - true + # Determines whether the current action has a layout definition by + # checking the action name against the :only and :except conditions + # set by the <tt>layout</tt> method. + # + # ==== Returns + # * <tt>Boolean</tt> - True if the action has a layout definition, false otherwise. + def _conditional_layout? + return unless super + + conditions = _layout_conditions + + if only = conditions[:only] + only.include?(action_name) + elsif except = conditions[:except] + !except.include?(action_name) + else + true + end end - end end # Specify the layout to use for this class. # # If the specified layout is a: # String:: the String is the template name - # Symbol:: call the method specified by the symbol, which will return the template name + # Symbol:: call the method specified by the symbol + # Proc:: call the passed Proc # false:: There is no layout # true:: raise an ArgumentError # nil:: Force default layout behavior with inheritance # + # Return value of Proc & Symbol arguments should be String, false, true or nil + # with the same meaning as described above. # ==== Parameters # * <tt>layout</tt> - The layout to use. # @@ -262,7 +266,7 @@ module ActionView def layout(layout, conditions = {}) include LayoutConditions unless conditions.empty? - conditions.each {|k, v| conditions[k] = Array(v).map(&:to_s) } + conditions.each { |k, v| conditions[k] = Array(v).map(&:to_s) } self._layout_conditions = conditions self._layout = layout @@ -276,7 +280,7 @@ module ActionView def _write_layout_method # :nodoc: remove_possible_method(:_layout) - prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"] + prefixes = /\blayouts/.match?(_implied_layout_name) ? [] : ["layouts"] default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}, false, [], { formats: formats }).first || super" name_clause = if name default_behavior @@ -286,7 +290,8 @@ module ActionView RUBY end - layout_definition = case _layout + layout_definition = \ + case _layout when String _layout.inspect when Symbol @@ -313,7 +318,7 @@ module ActionView raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil" when nil name_clause - end + end self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def _layout(formats) @@ -329,14 +334,14 @@ module ActionView private - # If no layout is supplied, look for a template named the return - # value of this method. - # - # ==== Returns - # * <tt>String</tt> - A template name - def _implied_layout_name # :nodoc: - controller_path - end + # If no layout is supplied, look for a template named the return + # value of this method. + # + # ==== Returns + # * <tt>String</tt> - A template name + def _implied_layout_name # :nodoc: + controller_path + end end def _normalize_options(options) # :nodoc: @@ -421,7 +426,7 @@ module ActionView end def _include_layout?(options) - (options.keys & [:body, :text, :plain, :html, :inline, :partial]).empty? || options.key?(:layout) + (options.keys & [:body, :plain, :html, :inline, :partial]).empty? || options.key?(:layout) end end end diff --git a/actionview/lib/action_view/log_subscriber.rb b/actionview/lib/action_view/log_subscriber.rb index 5a29c68214..c9f308c2a2 100644 --- a/actionview/lib/action_view/log_subscriber.rb +++ b/actionview/lib/action_view/log_subscriber.rb @@ -1,4 +1,4 @@ -require 'active_support/log_subscriber' +require "active_support/log_subscriber" module ActionView # = Action View Log Subscriber @@ -19,10 +19,19 @@ module ActionView message << " (#{event.duration.round(1)}ms)" end end - alias :render_partial :render_template + + def render_partial(event) + info do + message = " Rendered #{from_rails_root(event.payload[:identifier])}" + message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout] + message << " (#{event.duration.round(1)}ms)" + message << " #{cache_message(event.payload)}" if event.payload.key?(:cache_hit) + message + end + end def render_collection(event) - identifier = event.payload[:identifier] || 'templates' + identifier = event.payload[:identifier] || "templates" info do " Rendered collection of #{from_rails_root(identifier)}" \ @@ -44,7 +53,7 @@ module ActionView protected - EMPTY = '' + EMPTY = "" def from_rails_root(string) string = string.sub(rails_root, EMPTY) string.sub!(VIEWS_PATTERN, EMPTY) @@ -63,6 +72,14 @@ module ActionView end end + def cache_message(payload) + if payload[:cache_hit] + "[cache hit]" + else + "[cache miss]" + end + end + private def log_rendering_start(payload) diff --git a/actionview/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb index 9db1460ee7..9d6c762cc4 100644 --- a/actionview/lib/action_view/lookup_context.rb +++ b/actionview/lib/action_view/lookup_context.rb @@ -1,7 +1,7 @@ -require 'concurrent/map' -require 'active_support/core_ext/module/remove_method' -require 'active_support/core_ext/module/attribute_accessors' -require 'action_view/template/resolver' +require "concurrent/map" +require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/module/attribute_accessors" +require "action_view/template/resolver" module ActionView # = Action View Lookup Context @@ -21,7 +21,7 @@ module ActionView self.registered_details = [] def self.register_detail(name, &block) - self.registered_details << name + registered_details << name Accessors::DEFAULT_PROCS[name] = block Accessors.send :define_method, :"default_#{name}", &block @@ -202,13 +202,13 @@ module ActionView # name instead of the prefix. def normalize_name(name, prefixes) #:nodoc: prefixes = prefixes.presence - parts = name.to_s.split('/'.freeze) + parts = name.to_s.split("/".freeze) parts.shift if parts.first.empty? name = parts.pop return name, prefixes || [""] if parts.empty? - parts = parts.join('/'.freeze) + parts = parts.join("/".freeze) prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts] return name, prefixes diff --git a/actionview/lib/action_view/path_set.rb b/actionview/lib/action_view/path_set.rb index f68d2a77ed..6688519ffd 100644 --- a/actionview/lib/action_view/path_set.rb +++ b/actionview/lib/action_view/path_set.rb @@ -69,30 +69,30 @@ module ActionView #:nodoc: private - def _find_all(path, prefixes, args, outside_app) - prefixes = [prefixes] if String === prefixes - prefixes.each do |prefix| - paths.each do |resolver| - if outside_app - templates = resolver.find_all_anywhere(path, prefix, *args) - else - templates = resolver.find_all(path, prefix, *args) + def _find_all(path, prefixes, args, outside_app) + prefixes = [prefixes] if String === prefixes + prefixes.each do |prefix| + paths.each do |resolver| + if outside_app + templates = resolver.find_all_anywhere(path, prefix, *args) + else + templates = resolver.find_all(path, prefix, *args) + end + return templates unless templates.empty? end - return templates unless templates.empty? end + [] end - [] - end - def typecast(paths) - paths.map do |path| - case path - when Pathname, String - OptimizedFileSystemResolver.new path.to_s - else - path + def typecast(paths) + paths.map do |path| + case path + when Pathname, String + OptimizedFileSystemResolver.new path.to_s + else + path + end end end - end end end diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index dfb99f4ea9..42795ca2c7 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -40,7 +40,7 @@ module ActionView initializer "action_view.per_request_digest_cache" do |app| ActiveSupport.on_load(:action_view) do if app.config.consider_all_requests_local - app.executor.to_run { ActionView::LookupContext::DetailsKey.clear } + app.executor.to_run ActionView::Digestor::PerExecutionDigestCacheExpiry end end end diff --git a/actionview/lib/action_view/record_identifier.rb b/actionview/lib/action_view/record_identifier.rb index 4a2547b0fb..b39acfa0b5 100644 --- a/actionview/lib/action_view/record_identifier.rb +++ b/actionview/lib/action_view/record_identifier.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module' -require 'action_view/model_naming' +require "active_support/core_ext/module" +require "action_view/model_naming" module ActionView # RecordIdentifier encapsulates methods used by various ActionView helpers @@ -57,8 +57,8 @@ module ActionView include ModelNaming - JOIN = '_'.freeze - NEW = 'new'.freeze + JOIN = "_".freeze + NEW = "new".freeze # The DOM class convention is to use the singular form of an object or class. # diff --git a/actionview/lib/action_view/renderer/abstract_renderer.rb b/actionview/lib/action_view/renderer/abstract_renderer.rb index 1dddf53df0..3c85be49cd 100644 --- a/actionview/lib/action_view/renderer/abstract_renderer.rb +++ b/actionview/lib/action_view/renderer/abstract_renderer.rb @@ -15,7 +15,7 @@ module ActionView # that new object is called in turn. This abstracts the setup and rendering # into a separate classes for partials and templates. class AbstractRenderer #:nodoc: - delegate :find_template, :find_file, :template_exists?, :any_templates?, :with_fallbacks, :with_layout_format, :formats, :to => :@lookup_context + delegate :find_template, :find_file, :template_exists?, :any_templates?, :with_fallbacks, :with_layout_format, :formats, to: :@lookup_context def initialize(lookup_context) @lookup_context = lookup_context @@ -27,27 +27,27 @@ module ActionView protected - def extract_details(options) - @lookup_context.registered_details.each_with_object({}) do |key, details| - value = options[key] + def extract_details(options) + @lookup_context.registered_details.each_with_object({}) do |key, details| + value = options[key] - details[key] = Array(value) if value + details[key] = Array(value) if value + end end - end - def instrument(name, **options) - options[:identifier] ||= (@template && @template.identifier) || @path + def instrument(name, **options) + options[:identifier] ||= (@template && @template.identifier) || @path - ActiveSupport::Notifications.instrument("render_#{name}.action_view", options) do |payload| - yield payload + ActiveSupport::Notifications.instrument("render_#{name}.action_view", options) do |payload| + yield payload + end end - end - def prepend_formats(formats) - formats = Array(formats) - return if formats.empty? || @lookup_context.html_fallback_for_js + def prepend_formats(formats) + formats = Array(formats) + return if formats.empty? || @lookup_context.html_fallback_for_js - @lookup_context.formats = formats | @lookup_context.formats - end + @lookup_context.formats = formats | @lookup_context.formats + end end end diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb index 13b4ec6133..dfe38c488f 100644 --- a/actionview/lib/action_view/renderer/partial_renderer.rb +++ b/actionview/lib/action_view/renderer/partial_renderer.rb @@ -1,5 +1,6 @@ -require 'action_view/renderer/partial_renderer/collection_caching' -require 'concurrent/map' +require "concurrent/map" +require "active_support/core_ext/regexp" +require "action_view/renderer/partial_renderer/collection_caching" module ActionView class PartialIteration @@ -307,243 +308,244 @@ module ActionView if @collection render_collection else - instrument(:partial) do - render_partial - end + render_partial end end private - def render_collection - instrument(:collection, count: @collection.size) do |payload| - return nil if @collection.blank? + def render_collection + instrument(:collection, count: @collection.size) do |payload| + return nil if @collection.blank? - if @options.key?(:spacer_template) - spacer = find_template(@options[:spacer_template], @locals.keys).render(@view, @locals) - end + if @options.key?(:spacer_template) + spacer = find_template(@options[:spacer_template], @locals.keys).render(@view, @locals) + end - cache_collection_render(payload) do - @template ? collection_with_template : collection_without_template - end.join(spacer).html_safe + cache_collection_render(payload) do + @template ? collection_with_template : collection_without_template + end.join(spacer).html_safe + end end - end - def render_partial - view, locals, block = @view, @locals, @block - object, as = @object, @variable + def render_partial + instrument(:partial) do |payload| + view, locals, block = @view, @locals, @block + object, as = @object, @variable - if !block && (layout = @options[:layout]) - layout = find_template(layout.to_s, @template_keys) - end + if !block && (layout = @options[:layout]) + layout = find_template(layout.to_s, @template_keys) + end + + object = locals[as] if object.nil? # Respect object when object is false + locals[as] = object if @has_object - object = locals[as] if object.nil? # Respect object when object is false - locals[as] = object if @has_object + content = @template.render(view, locals) do |*name| + view._layout_for(*name, &block) + end - content = @template.render(view, locals) do |*name| - view._layout_for(*name, &block) + content = layout.render(view, locals) { content } if layout + payload[:cache_hit] = view.cache_hit + content + end end - content = layout.render(view, locals){ content } if layout - content - end + # Sets up instance variables needed for rendering a partial. This method + # finds the options and details and extracts them. The method also contains + # logic that handles the type of object passed in as the partial. + # + # If +options[:partial]+ is a string, then the +@path+ instance variable is + # set to that string. Otherwise, the +options[:partial]+ object must + # respond to +to_partial_path+ in order to setup the path. + def setup(context, options, block) + @view = context + @options = options + @block = block + + @locals = options[:locals] || {} + @details = extract_details(options) + + prepend_formats(options[:formats]) + + partial = options[:partial] + + if String === partial + @has_object = options.key?(:object) + @object = options[:object] + @collection = collection_from_options + @path = partial + else + @has_object = true + @object = partial + @collection = collection_from_object || collection_from_options + + if @collection + paths = @collection_data = @collection.map { |o| partial_path(o) } + @path = paths.uniq.one? ? paths.first : nil + else + @path = partial_path + end + end - # Sets up instance variables needed for rendering a partial. This method - # finds the options and details and extracts them. The method also contains - # logic that handles the type of object passed in as the partial. - # - # If +options[:partial]+ is a string, then the +@path+ instance variable is - # set to that string. Otherwise, the +options[:partial]+ object must - # respond to +to_partial_path+ in order to setup the path. - def setup(context, options, block) - @view = context - @options = options - @block = block - - @locals = options[:locals] || {} - @details = extract_details(options) - - prepend_formats(options[:formats]) - - partial = options[:partial] - - if String === partial - @has_object = options.key?(:object) - @object = options[:object] - @collection = collection_from_options - @path = partial - else - @has_object = true - @object = partial - @collection = collection_from_object || collection_from_options + if as = options[:as] + raise_invalid_option_as(as) unless /\A[a-z_]\w*\z/.match?(as.to_s) + as = as.to_sym + end - if @collection - paths = @collection_data = @collection.map { |o| partial_path(o) } - @path = paths.uniq.one? ? paths.first : nil + if @path + @variable, @variable_counter, @variable_iteration = retrieve_variable(@path, as) + @template_keys = retrieve_template_keys else - @path = partial_path + paths.map! { |path| retrieve_variable(path, as).unshift(path) } end - end - if as = options[:as] - raise_invalid_option_as(as) unless as.to_s =~ /\A[a-z_]\w*\z/ - as = as.to_sym + self end - if @path - @variable, @variable_counter, @variable_iteration = retrieve_variable(@path, as) - @template_keys = retrieve_template_keys - else - paths.map! { |path| retrieve_variable(path, as).unshift(path) } + def collection_from_options + if @options.key?(:collection) + collection = @options[:collection] + collection ? collection.to_a : [] + end end - self - end - - def collection_from_options - if @options.key?(:collection) - collection = @options[:collection] - collection.respond_to?(:to_ary) ? collection.to_ary : [] + def collection_from_object + @object.to_ary if @object.respond_to?(:to_ary) end - end - def collection_from_object - @object.to_ary if @object.respond_to?(:to_ary) - end - - def find_partial - find_template(@path, @template_keys) if @path - end + def find_partial + find_template(@path, @template_keys) if @path + end - def find_template(path, locals) - prefixes = path.include?(?/) ? [] : @lookup_context.prefixes - @lookup_context.find_template(path, prefixes, true, locals, @details) - end + def find_template(path, locals) + prefixes = path.include?(?/) ? [] : @lookup_context.prefixes + @lookup_context.find_template(path, prefixes, true, locals, @details) + end - def collection_with_template - view, locals, template = @view, @locals, @template - as, counter, iteration = @variable, @variable_counter, @variable_iteration + def collection_with_template + view, locals, template = @view, @locals, @template + as, counter, iteration = @variable, @variable_counter, @variable_iteration - if layout = @options[:layout] - layout = find_template(layout, @template_keys) - end + if layout = @options[:layout] + layout = find_template(layout, @template_keys) + end - partial_iteration = PartialIteration.new(@collection.size) - locals[iteration] = partial_iteration + partial_iteration = PartialIteration.new(@collection.size) + locals[iteration] = partial_iteration - @collection.map do |object| - locals[as] = object - locals[counter] = partial_iteration.index + @collection.map do |object| + locals[as] = object + locals[counter] = partial_iteration.index - content = template.render(view, locals) - content = layout.render(view, locals) { content } if layout - partial_iteration.iterate! - content + content = template.render(view, locals) + content = layout.render(view, locals) { content } if layout + partial_iteration.iterate! + content + end end - end - def collection_without_template - view, locals, collection_data = @view, @locals, @collection_data - cache = {} - keys = @locals.keys + def collection_without_template + view, locals, collection_data = @view, @locals, @collection_data + cache = {} + keys = @locals.keys - partial_iteration = PartialIteration.new(@collection.size) + partial_iteration = PartialIteration.new(@collection.size) - @collection.map do |object| - index = partial_iteration.index - path, as, counter, iteration = collection_data[index] + @collection.map do |object| + index = partial_iteration.index + path, as, counter, iteration = collection_data[index] - locals[as] = object - locals[counter] = index - locals[iteration] = partial_iteration + locals[as] = object + locals[counter] = index + locals[iteration] = partial_iteration - template = (cache[path] ||= find_template(path, keys + [as, counter])) - content = template.render(view, locals) - partial_iteration.iterate! - content + template = (cache[path] ||= find_template(path, keys + [as, counter])) + content = template.render(view, locals) + partial_iteration.iterate! + content + end end - end - # Obtains the path to where the object's partial is located. If the object - # responds to +to_partial_path+, then +to_partial_path+ will be called and - # will provide the path. If the object does not respond to +to_partial_path+, - # then an +ArgumentError+ is raised. - # - # If +prefix_partial_path_with_controller_namespace+ is true, then this - # method will prefix the partial paths with a namespace. - def partial_path(object = @object) - object = object.to_model if object.respond_to?(:to_model) - - path = if object.respond_to?(:to_partial_path) - object.to_partial_path - else - raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.") + # Obtains the path to where the object's partial is located. If the object + # responds to +to_partial_path+, then +to_partial_path+ will be called and + # will provide the path. If the object does not respond to +to_partial_path+, + # then an +ArgumentError+ is raised. + # + # If +prefix_partial_path_with_controller_namespace+ is true, then this + # method will prefix the partial paths with a namespace. + def partial_path(object = @object) + object = object.to_model if object.respond_to?(:to_model) + + path = if object.respond_to?(:to_partial_path) + object.to_partial_path + else + raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.") + end + + if @view.prefix_partial_path_with_controller_namespace + prefixed_partial_names[path] ||= merge_prefix_into_object_path(@context_prefix, path.dup) + else + path + end end - if @view.prefix_partial_path_with_controller_namespace - prefixed_partial_names[path] ||= merge_prefix_into_object_path(@context_prefix, path.dup) - else - path + def prefixed_partial_names + @prefixed_partial_names ||= PREFIXED_PARTIAL_NAMES[@context_prefix] end - end - def prefixed_partial_names - @prefixed_partial_names ||= PREFIXED_PARTIAL_NAMES[@context_prefix] - end + def merge_prefix_into_object_path(prefix, object_path) + if prefix.include?(?/) && object_path.include?(?/) + prefixes = [] + prefix_array = File.dirname(prefix).split("/") + object_path_array = object_path.split("/")[0..-3] # skip model dir & partial - def merge_prefix_into_object_path(prefix, object_path) - if prefix.include?(?/) && object_path.include?(?/) - prefixes = [] - prefix_array = File.dirname(prefix).split('/') - object_path_array = object_path.split('/')[0..-3] # skip model dir & partial + prefix_array.each_with_index do |dir, index| + break if dir == object_path_array[index] + prefixes << dir + end - prefix_array.each_with_index do |dir, index| - break if dir == object_path_array[index] - prefixes << dir + (prefixes << object_path).join("/") + else + object_path end - - (prefixes << object_path).join("/") - else - object_path end - end - def retrieve_template_keys - keys = @locals.keys - keys << @variable if @has_object || @collection - if @collection - keys << @variable_counter - keys << @variable_iteration + def retrieve_template_keys + keys = @locals.keys + keys << @variable if @has_object || @collection + if @collection + keys << @variable_counter + keys << @variable_iteration + end + keys end - keys - end - def retrieve_variable(path, as) - variable = as || begin - base = path[-1] == "/".freeze ? "".freeze : File.basename(path) - raise_invalid_identifier(path) unless base =~ /\A_?(.*?)(?:\.\w+)*\z/ - $1.to_sym - end - if @collection - variable_counter = :"#{variable}_counter" - variable_iteration = :"#{variable}_iteration" + def retrieve_variable(path, as) + variable = as || begin + base = path[-1] == "/".freeze ? "".freeze : File.basename(path) + raise_invalid_identifier(path) unless base =~ /\A_?(.*?)(?:\.\w+)*\z/ + $1.to_sym + end + if @collection + variable_counter = :"#{variable}_counter" + variable_iteration = :"#{variable}_iteration" + end + [variable, variable_counter, variable_iteration] end - [variable, variable_counter, variable_iteration] - end - IDENTIFIER_ERROR_MESSAGE = "The partial name (%s) is not a valid Ruby identifier; " + - "make sure your partial name starts with underscore." + IDENTIFIER_ERROR_MESSAGE = "The partial name (%s) is not a valid Ruby identifier; " + + "make sure your partial name starts with underscore." - OPTION_AS_ERROR_MESSAGE = "The value (%s) of the option `as` is not a valid Ruby identifier; " + - "make sure it starts with lowercase letter, " + - "and is followed by any combination of letters, numbers and underscores." + OPTION_AS_ERROR_MESSAGE = "The value (%s) of the option `as` is not a valid Ruby identifier; " + + "make sure it starts with lowercase letter, " + + "and is followed by any combination of letters, numbers and underscores." - def raise_invalid_identifier(path) - raise ArgumentError.new(IDENTIFIER_ERROR_MESSAGE % (path)) - end + def raise_invalid_identifier(path) + raise ArgumentError.new(IDENTIFIER_ERROR_MESSAGE % (path)) + end - def raise_invalid_option_as(as) - raise ArgumentError.new(OPTION_AS_ERROR_MESSAGE % (as)) - end + def raise_invalid_option_as(as) + raise ArgumentError.new(OPTION_AS_ERROR_MESSAGE % (as)) + end end end diff --git a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb index f7deba94ce..1fbe209200 100644 --- a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb +++ b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb @@ -25,9 +25,15 @@ module ActionView end end + def callable_cache_key? + @options[:cached].respond_to?(:call) + end + def collection_by_cache_keys + seed = callable_cache_key? ? @options[:cached] : ->(i) { i } + @collection.each_with_object({}) do |item, hash| - hash[expanded_cache_key(item)] = item + hash[expanded_cache_key(seed.call(item))] = item end end diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb index f38e2764d0..2434250b2d 100644 --- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb +++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb @@ -1,4 +1,4 @@ -require 'fiber' +require "fiber" module ActionView # == TODO @@ -27,17 +27,17 @@ module ActionView private - # This is the same logging logic as in ShowExceptions middleware. - # TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron. - def log_error(exception) #:nodoc: - logger = ActionView::Base.logger - return unless logger + # This is the same logging logic as in ShowExceptions middleware. + # TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron. + def log_error(exception) #:nodoc: + logger = ActionView::Base.logger + return unless logger - message = "\n#{exception.class} (#{exception.message}):\n" - message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) - message << " " << exception.backtrace.join("\n ") - logger.fatal("#{message}\n\n") - end + message = "\n#{exception.class} (#{exception.message}):\n" + message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) + message << " " << exception.backtrace.join("\n ") + logger.fatal("#{message}\n\n") + end end # For streaming, instead of rendering a given a template, we return a Body @@ -56,48 +56,48 @@ module ActionView private - def delayed_render(buffer, template, layout, view, locals) - # Wrap the given buffer in the StreamingBuffer and pass it to the - # underlying template handler. Now, every time something is concatenated - # to the buffer, it is not appended to an array, but streamed straight - # to the client. - output = ActionView::StreamingBuffer.new(buffer) - yielder = lambda { |*name| view._layout_for(*name) } - - instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do - fiber = Fiber.new do - if layout - layout.render(view, locals, output, &yielder) - else - # If you don't have a layout, just render the thing - # and concatenate the final result. This is the same - # as a layout with just <%= yield %> - output.safe_concat view._layout_for + def delayed_render(buffer, template, layout, view, locals) + # Wrap the given buffer in the StreamingBuffer and pass it to the + # underlying template handler. Now, every time something is concatenated + # to the buffer, it is not appended to an array, but streamed straight + # to the client. + output = ActionView::StreamingBuffer.new(buffer) + yielder = lambda { |*name| view._layout_for(*name) } + + instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do + fiber = Fiber.new do + if layout + layout.render(view, locals, output, &yielder) + else + # If you don't have a layout, just render the thing + # and concatenate the final result. This is the same + # as a layout with just <%= yield %> + output.safe_concat view._layout_for + end end - end - # Set the view flow to support streaming. It will be aware - # when to stop rendering the layout because it needs to search - # something in the template and vice-versa. - view.view_flow = StreamingFlow.new(view, fiber) + # Set the view flow to support streaming. It will be aware + # when to stop rendering the layout because it needs to search + # something in the template and vice-versa. + view.view_flow = StreamingFlow.new(view, fiber) - # Yo! Start the fiber! - fiber.resume + # Yo! Start the fiber! + fiber.resume - # If the fiber is still alive, it means we need something - # from the template, so start rendering it. If not, it means - # the layout exited without requiring anything from the template. - if fiber.alive? - content = template.render(view, locals, &yielder) + # If the fiber is still alive, it means we need something + # from the template, so start rendering it. If not, it means + # the layout exited without requiring anything from the template. + if fiber.alive? + content = template.render(view, locals, &yielder) - # Once rendering the template is done, sets its content in the :layout key. - view.view_flow.set(:layout, content) + # Once rendering the template is done, sets its content in the :layout key. + view.view_flow.set(:layout, content) - # In case the layout continues yielding, we need to resume - # the fiber until all yields are handled. - fiber.resume while fiber.alive? + # In case the layout continues yielding, we need to resume + # the fiber until all yields are handled. + fiber.resume while fiber.alive? + end end end - end end end diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb index 1d6afb90fe..f40bf8f6e2 100644 --- a/actionview/lib/action_view/renderer/template_renderer.rb +++ b/actionview/lib/action_view/renderer/template_renderer.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/try' +require "active_support/core_ext/object/try" module ActionView class TemplateRenderer < AbstractRenderer #:nodoc: @@ -16,87 +16,85 @@ module ActionView private - # Determine the template to be rendered using the given options. - def determine_template(options) - keys = options.has_key?(:locals) ? options[:locals].keys : [] + # Determine the template to be rendered using the given options. + def determine_template(options) + keys = options.has_key?(:locals) ? options[:locals].keys : [] - if options.key?(:body) - Template::Text.new(options[:body]) - elsif options.key?(:text) - Template::Text.new(options[:text], formats.first) - elsif options.key?(:plain) - Template::Text.new(options[:plain]) - elsif options.key?(:html) - Template::HTML.new(options[:html], formats.first) - elsif options.key?(:file) - with_fallbacks { find_file(options[:file], nil, false, keys, @details) } - elsif options.key?(:inline) - handler = Template.handler_for_extension(options[:type] || "erb") - Template.new(options[:inline], "inline template", handler, :locals => keys) - elsif options.key?(:template) - if options[:template].respond_to?(:render) - options[:template] + if options.key?(:body) + Template::Text.new(options[:body]) + elsif options.key?(:plain) + Template::Text.new(options[:plain]) + elsif options.key?(:html) + Template::HTML.new(options[:html], formats.first) + elsif options.key?(:file) + with_fallbacks { find_file(options[:file], nil, false, keys, @details) } + elsif options.key?(:inline) + handler = Template.handler_for_extension(options[:type] || "erb") + Template.new(options[:inline], "inline template", handler, locals: keys) + elsif options.key?(:template) + if options[:template].respond_to?(:render) + options[:template] + else + find_template(options[:template], options[:prefixes], false, keys, @details) + end else - find_template(options[:template], options[:prefixes], false, keys, @details) + raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option." end - else - raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html, :text or :body option." end - end - # Renders the given template. A string representing the layout can be - # supplied as well. - def render_template(template, layout_name = nil, locals = nil) #:nodoc: - view, locals = @view, locals || {} + # Renders the given template. A string representing the layout can be + # supplied as well. + def render_template(template, layout_name = nil, locals = nil) #:nodoc: + view, locals = @view, locals || {} - render_with_layout(layout_name, locals) do |layout| - instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do - template.render(view, locals) { |*name| view._layout_for(*name) } + render_with_layout(layout_name, locals) do |layout| + instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do + template.render(view, locals) { |*name| view._layout_for(*name) } + end end end - end - def render_with_layout(path, locals) #:nodoc: - layout = path && find_layout(path, locals.keys, [formats.first]) - content = yield(layout) + def render_with_layout(path, locals) #:nodoc: + layout = path && find_layout(path, locals.keys, [formats.first]) + content = yield(layout) - if layout - view = @view - view.view_flow.set(:layout, content) - layout.render(view, locals){ |*name| view._layout_for(*name) } - else - content + if layout + view = @view + view.view_flow.set(:layout, content) + layout.render(view, locals) { |*name| view._layout_for(*name) } + else + content + end end - end - # This is the method which actually finds the layout using details in the lookup - # context object. If no layout is found, it checks if at least a layout with - # the given name exists across all details before raising the error. - def find_layout(layout, keys, formats) - resolve_layout(layout, keys, formats) - end + # This is the method which actually finds the layout using details in the lookup + # context object. If no layout is found, it checks if at least a layout with + # the given name exists across all details before raising the error. + def find_layout(layout, keys, formats) + resolve_layout(layout, keys, formats) + end - def resolve_layout(layout, keys, formats) - details = @details.dup - details[:formats] = formats + def resolve_layout(layout, keys, formats) + details = @details.dup + details[:formats] = formats - case layout - when String - begin - if layout =~ /^\// - with_fallbacks { find_template(layout, nil, false, [], details) } - else - find_template(layout, nil, false, [], details) + case layout + when String + begin + if layout.start_with?("/") + with_fallbacks { find_template(layout, nil, false, [], details) } + else + find_template(layout, nil, false, [], details) + end + rescue ActionView::MissingTemplate + all_details = @details.merge(formats: @lookup_context.default_formats) + raise unless template_exists?(layout, nil, false, [], all_details) end - rescue ActionView::MissingTemplate - all_details = @details.merge(:formats => @lookup_context.default_formats) - raise unless template_exists?(layout, nil, false, [], all_details) + when Proc + resolve_layout(layout.call(formats), keys, formats) + else + layout end - when Proc - resolve_layout(layout.call(formats), keys, formats) - else - layout end - end end end diff --git a/actionview/lib/action_view/routing_url_for.rb b/actionview/lib/action_view/routing_url_for.rb index 45e78d1ad9..669cffab1a 100644 --- a/actionview/lib/action_view/routing_url_for.rb +++ b/actionview/lib/action_view/routing_url_for.rb @@ -1,8 +1,7 @@ -require 'action_dispatch/routing/polymorphic_routes' +require "action_dispatch/routing/polymorphic_routes" module ActionView module RoutingUrlFor - # Returns the URL for the set of +options+ provided. This takes the # same options as +url_for+ in Action Controller (see the # documentation for <tt>ActionController::Base#url_for</tt>). Note that by default diff --git a/actionview/lib/action_view/tasks/cache_digests.rake b/actionview/lib/action_view/tasks/cache_digests.rake index 045bdf5691..d30b3f7797 100644 --- a/actionview/lib/action_view/tasks/cache_digests.rake +++ b/actionview/lib/action_view/tasks/cache_digests.rake @@ -1,19 +1,19 @@ namespace :cache_digests do - desc 'Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)' - task :nested_dependencies => :environment do - abort 'You must provide TEMPLATE for the task to run' unless ENV['TEMPLATE'].present? + desc "Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)" + task nested_dependencies: :environment do + abort "You must provide TEMPLATE for the task to run" unless ENV["TEMPLATE"].present? puts JSON.pretty_generate ActionView::Digestor.tree(CacheDigests.template_name, CacheDigests.finder).children.map(&:to_dep_map) end - desc 'Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)' - task :dependencies => :environment do - abort 'You must provide TEMPLATE for the task to run' unless ENV['TEMPLATE'].present? + desc "Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)" + task dependencies: :environment do + abort "You must provide TEMPLATE for the task to run" unless ENV["TEMPLATE"].present? puts JSON.pretty_generate ActionView::Digestor.tree(CacheDigests.template_name, CacheDigests.finder).children.map(&:name) end class CacheDigests def self.template_name - ENV['TEMPLATE'].split('.', 2).first + ENV["TEMPLATE"].split(".", 2).first end def self.finder diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb index 169ee55fdc..c01dd1c028 100644 --- a/actionview/lib/action_view/template.rb +++ b/actionview/lib/action_view/template.rb @@ -1,6 +1,7 @@ -require 'active_support/core_ext/object/try' -require 'active_support/core_ext/kernel/singleton_class' -require 'thread' +require "active_support/core_ext/object/try" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/delegation" +require "thread" module ActionView # = Action View Template @@ -65,8 +66,7 @@ module ActionView # If you want to provide an alternate mechanism for # specifying encodings (like ERB does via <%# encoding: ... %>), # you may indicate that you will handle encodings yourself - # by implementing <tt>self.handles_encoding?</tt> - # on your handler. + # by implementing <tt>handles_encoding?</tt> on your handler. # # If you do, Rails will not try to encode the String # into the default_internal, passing you the unaltered @@ -153,7 +153,7 @@ module ActionView # we use a bang in this instrumentation because you don't want to # consume this in production. This is only slow if it's being listened to. def render(view, locals, buffer=nil, &block) - instrument("!render_template".freeze) do + instrument_render_template do compile!(view) view.send(method_name, locals, buffer, &block) end @@ -180,12 +180,12 @@ module ActionView name = pieces.pop partial = !!name.sub!(/^_/, "") lookup.disable_cache do - lookup.find_template(name, [ pieces.join('/') ], partial, @locals) + lookup.find_template(name, [ pieces.join("/") ], partial, @locals) end end def inspect - @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", ''.freeze) : identifier + @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", "".freeze) : identifier end # This method is responsible for properly setting the encoding of the @@ -204,7 +204,7 @@ module ActionView # Look for # encoding: *. If we find one, we'll encode the # String in that encoding, otherwise, we'll use the # default external encoding. - if source.sub!(/\A#{ENCODING_FLAG}/, '') + if source.sub!(/\A#{ENCODING_FLAG}/, "") encoding = magic_encoding = $1 else encoding = Encoding.default_external @@ -325,30 +325,39 @@ module ActionView end def locals_code #:nodoc: + # Only locals with valid variable names get set directly. Others will + # still be available in local_assigns. + locals = @locals.to_set - Module::DELEGATION_RESERVED_METHOD_NAMES + locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/) + # Double assign to suppress the dreaded 'assigned but unused variable' warning - @locals.each_with_object('') { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" } + locals.each_with_object("") { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" } end def method_name #:nodoc: @method_name ||= begin m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}" - m.tr!('-'.freeze, '_'.freeze) + m.tr!("-".freeze, "_".freeze) m end end def identifier_method_name #:nodoc: - inspect.tr('^a-z_'.freeze, '_'.freeze) + inspect.tr("^a-z_".freeze, "_".freeze) end def instrument(action, &block) - payload = { virtual_path: @virtual_path, identifier: @identifier } - case action - when "!render_template".freeze - ActiveSupport::Notifications.instrument("!render_template.action_view".freeze, payload, &block) - else - ActiveSupport::Notifications.instrument("#{action}.action_view".freeze, payload, &block) - end + ActiveSupport::Notifications.instrument("#{action}.action_view".freeze, instrument_payload, &block) + end + + private + + def instrument_render_template(&block) + ActiveSupport::Notifications.instrument("!render_template.action_view".freeze, instrument_payload, &block) + end + + def instrument_payload + { virtual_path: @virtual_path, identifier: @identifier } end end end diff --git a/actionview/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb index 3f38c3d2b9..4010677477 100644 --- a/actionview/lib/action_view/template/error.rb +++ b/actionview/lib/action_view/template/error.rb @@ -1,4 +1,5 @@ require "active_support/core_ext/enumerable" +require "active_support/core_ext/regexp" module ActionView # = Action View Errors @@ -35,10 +36,10 @@ module ActionView prefixes = Array(prefixes) template_type = if partial "partial" - elsif path =~ /layouts/i - 'layout' + elsif /layouts/i.match?(path) + "layout" else - 'template' + "template" end if partial && path.present? @@ -62,23 +63,13 @@ module ActionView # Override to prevent #cause resetting during re-raise. attr_reader :cause - def initialize(template, original_exception = nil) - if original_exception - ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ - "Exceptions will automatically capture the original exception.", caller) - end - + def initialize(template) super($!.message) set_backtrace($!.backtrace) @cause = $! @template, @sub_templates = template, nil end - def original_exception - ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) - cause - end - def file_name @template.identifier end @@ -130,7 +121,7 @@ module ActionView if line_number "on line ##{line_number} of " else - 'in ' + "in " end + file_name end diff --git a/actionview/lib/action_view/template/handlers.rb b/actionview/lib/action_view/template/handlers.rb index ad4c353608..f4301f6f07 100644 --- a/actionview/lib/action_view/template/handlers.rb +++ b/actionview/lib/action_view/template/handlers.rb @@ -2,10 +2,10 @@ module ActionView #:nodoc: # = Action View Template Handlers class Template module Handlers #:nodoc: - autoload :Raw, 'action_view/template/handlers/raw' - autoload :ERB, 'action_view/template/handlers/erb' - autoload :Html, 'action_view/template/handlers/html' - autoload :Builder, 'action_view/template/handlers/builder' + autoload :Raw, "action_view/template/handlers/raw" + autoload :ERB, "action_view/template/handlers/erb" + autoload :Html, "action_view/template/handlers/html" + autoload :Builder, "action_view/template/handlers/builder" def self.extended(base) base.register_default_template_handler :raw, Raw.new diff --git a/actionview/lib/action_view/template/handlers/builder.rb b/actionview/lib/action_view/template/handlers/builder.rb index d90b0c6378..e08a5b5db8 100644 --- a/actionview/lib/action_view/template/handlers/builder.rb +++ b/actionview/lib/action_view/template/handlers/builder.rb @@ -15,12 +15,12 @@ module ActionView protected - def require_engine - @required ||= begin - require "builder" - true + def require_engine + @required ||= begin + require "builder" + true + end end - end end end end diff --git a/actionview/lib/action_view/template/handlers/erb.rb b/actionview/lib/action_view/template/handlers/erb.rb index 85a100ed4c..6f07de1813 100644 --- a/actionview/lib/action_view/template/handlers/erb.rb +++ b/actionview/lib/action_view/template/handlers/erb.rb @@ -1,4 +1,5 @@ -require 'erubis' +require "erubis" +require "active_support/core_ext/regexp" module ActionView class Template @@ -28,7 +29,7 @@ module ActionView # We override to always treat <%== as escaped. def add_expr(src, code, indicator) case indicator - when '==' + when "==" add_expr_escaped(src, code) else super @@ -39,16 +40,16 @@ module ActionView def add_expr_literal(src, code) flush_newline_if_pending(src) - if code =~ BLOCK_EXPR - src << '@output_buffer.append= ' << code + if BLOCK_EXPR.match?(code) + src << "@output_buffer.append= " << code else - src << '@output_buffer.append=(' << code << ');' + src << "@output_buffer.append=(" << code << ");" end end def add_expr_escaped(src, code) flush_newline_if_pending(src) - if code =~ BLOCK_EXPR + if BLOCK_EXPR.match?(code) src << "@output_buffer.safe_expr_append= " << code else src << "@output_buffer.safe_expr_append=(" << code << ");" @@ -62,7 +63,7 @@ module ActionView def add_postamble(src) flush_newline_if_pending(src) - src << '@output_buffer.to_s' + src << "@output_buffer.to_s" end def flush_newline_if_pending(src) @@ -77,7 +78,7 @@ module ActionView # Specify trim mode for the ERB compiler. Defaults to '-'. # See ERB documentation for suitable values. class_attribute :erb_trim_mode - self.erb_trim_mode = '-' + self.erb_trim_mode = "-" # Default implementation used. class_attribute :erb_implementation @@ -108,7 +109,7 @@ module ActionView # expression template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT) - erb = template_source.gsub(ENCODING_TAG, '') + erb = template_source.gsub(ENCODING_TAG, "") encoding = $2 erb.force_encoding valid_encoding(template.source.dup, encoding) @@ -118,8 +119,8 @@ module ActionView self.class.erb_implementation.new( erb, - :escape => (self.class.escape_whitelist.include? template.type), - :trim => (self.class.erb_trim_mode == "-") + escape: (self.class.escape_whitelist.include? template.type), + trim: (self.class.erb_trim_mode == "-") ).src end diff --git a/actionview/lib/action_view/template/handlers/raw.rb b/actionview/lib/action_view/template/handlers/raw.rb index 760f517431..e7519e94f9 100644 --- a/actionview/lib/action_view/template/handlers/raw.rb +++ b/actionview/lib/action_view/template/handlers/raw.rb @@ -2,7 +2,7 @@ module ActionView module Template::Handlers class Raw def call(template) - "#{template.source.inspect};" + "#{template.source.inspect}.html_safe;" end end end diff --git a/actionview/lib/action_view/template/html.rb b/actionview/lib/action_view/template/html.rb index 0321f819b5..0ffae10432 100644 --- a/actionview/lib/action_view/template/html.rb +++ b/actionview/lib/action_view/template/html.rb @@ -11,12 +11,10 @@ module ActionView #:nodoc: end def identifier - 'html template' + "html template" end - def inspect - 'html template' - end + alias_method :inspect, :identifier def to_str ERB::Util.h(@string) diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index bf68e93c58..5a2948d5a9 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -37,15 +37,15 @@ module ActionView class Cache #:nodoc: class SmallCache < Concurrent::Map def initialize(options = {}) - super(options.merge(:initial_capacity => 2)) + super(options.merge(initial_capacity: 2)) end end # preallocate all the default blocks for performance/memory consumption reasons - PARTIAL_BLOCK = lambda {|cache, partial| cache[partial] = SmallCache.new} - PREFIX_BLOCK = lambda {|cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK)} - NAME_BLOCK = lambda {|cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK)} - KEY_BLOCK = lambda {|cache, key| cache[key] = SmallCache.new(&NAME_BLOCK)} + PARTIAL_BLOCK = lambda { |cache, partial| cache[partial] = SmallCache.new } + PREFIX_BLOCK = lambda { |cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK) } + NAME_BLOCK = lambda { |cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK) } + KEY_BLOCK = lambda { |cache, key| cache[key] = SmallCache.new(&NAME_BLOCK) } # usually a majority of template look ups return nothing, use this canonical preallocated array to save memory NO_TEMPLATES = [].freeze @@ -107,22 +107,22 @@ module ActionView private - def canonical_no_templates(templates) - templates.empty? ? NO_TEMPLATES : templates - end - - def templates_have_changed?(cached_templates, fresh_templates) - # if either the old or new template list is empty, we don't need to (and can't) - # compare modification times, and instead just check whether the lists are different - if cached_templates.blank? || fresh_templates.blank? - return fresh_templates.blank? != cached_templates.blank? + def canonical_no_templates(templates) + templates.empty? ? NO_TEMPLATES : templates end - cached_templates_max_updated_at = cached_templates.map(&:updated_at).max + def templates_have_changed?(cached_templates, fresh_templates) + # if either the old or new template list is empty, we don't need to (and can't) + # compare modification times, and instead just check whether the lists are different + if cached_templates.blank? || fresh_templates.blank? + return fresh_templates.blank? != cached_templates.blank? + end - # if a template has changed, it will be now be newer than all the cached templates - fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at } - end + cached_templates_max_updated_at = cached_templates.map(&:updated_at).max + + # if a template has changed, it will be now be newer than all the cached templates + fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at } + end end cattr_accessor :caching @@ -204,7 +204,7 @@ module ActionView # An abstract class that implements a Resolver with path semantics. class PathResolver < Resolver #:nodoc: - EXTENSIONS = { :locale => ".", :formats => ".", :variants => "+", :handlers => "." } + EXTENSIONS = { locale: ".", formats: ".", variants: "+", handlers: "." } DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}" def initialize(pattern=nil) @@ -214,93 +214,93 @@ module ActionView private - def find_templates(name, prefix, partial, details, outside_app_allowed = false) - path = Path.build(name, prefix, partial) - query(path, details, details[:formats], outside_app_allowed) - end + def find_templates(name, prefix, partial, details, outside_app_allowed = false) + path = Path.build(name, prefix, partial) + query(path, details, details[:formats], outside_app_allowed) + end - def query(path, details, formats, outside_app_allowed) - query = build_query(path, details) + def query(path, details, formats, outside_app_allowed) + query = build_query(path, details) - template_paths = find_template_paths(query) - template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed + template_paths = find_template_paths(query) + template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed - template_paths.map do |template| - handler, format, variant = extract_handler_and_format_and_variant(template, formats) - contents = File.binread(template) + template_paths.map do |template| + handler, format, variant = extract_handler_and_format_and_variant(template, formats) + contents = File.binread(template) - Template.new(contents, File.expand_path(template), handler, - :virtual_path => path.virtual, - :format => format, - :variant => variant, - :updated_at => mtime(template) - ) + Template.new(contents, File.expand_path(template), handler, + virtual_path: path.virtual, + format: format, + variant: variant, + updated_at: mtime(template) + ) + end end - end - def reject_files_external_to_app(files) - files.reject { |filename| !inside_path?(@path, filename) } - end + def reject_files_external_to_app(files) + files.reject { |filename| !inside_path?(@path, filename) } + end - def find_template_paths(query) - Dir[query].uniq.reject do |filename| - File.directory?(filename) || - # deals with case-insensitive file systems. - !File.fnmatch(query, filename, File::FNM_EXTGLOB) + def find_template_paths(query) + Dir[query].uniq.reject do |filename| + File.directory?(filename) || + # deals with case-insensitive file systems. + !File.fnmatch(query, filename, File::FNM_EXTGLOB) + end end - end - def inside_path?(path, filename) - filename = File.expand_path(filename) - path = File.join(path, '') - filename.start_with?(path) - end + def inside_path?(path, filename) + filename = File.expand_path(filename) + path = File.join(path, "") + filename.start_with?(path) + end - # Helper for building query glob string based on resolver's pattern. - def build_query(path, details) - query = @pattern.dup + # Helper for building query glob string based on resolver's pattern. + def build_query(path, details) + query = @pattern.dup - prefix = path.prefix.empty? ? '' : "#{escape_entry(path.prefix)}\\1" - query.gsub!(/:prefix(\/)?/, prefix) + prefix = path.prefix.empty? ? "" : "#{escape_entry(path.prefix)}\\1" + query.gsub!(/:prefix(\/)?/, prefix) - partial = escape_entry(path.partial? ? "_#{path.name}" : path.name) - query.gsub!(/:action/, partial) + partial = escape_entry(path.partial? ? "_#{path.name}" : path.name) + query.gsub!(/:action/, partial) - details.each do |ext, candidates| - if ext == :variants && candidates == :any - query.gsub!(/:#{ext}/, "*") - else - query.gsub!(/:#{ext}/, "{#{candidates.compact.uniq.join(',')}}") + details.each do |ext, candidates| + if ext == :variants && candidates == :any + query.gsub!(/:#{ext}/, "*") + else + query.gsub!(/:#{ext}/, "{#{candidates.compact.uniq.join(',')}}") + end end - end - File.expand_path(query, @path) - end + File.expand_path(query, @path) + end - def escape_entry(entry) - entry.gsub(/[*?{}\[\]]/, '\\\\\\&'.freeze) - end + def escape_entry(entry) + entry.gsub(/[*?{}\[\]]/, '\\\\\\&'.freeze) + end - # Returns the file mtime from the filesystem. - def mtime(p) - File.mtime(p) - end + # Returns the file mtime from the filesystem. + def mtime(p) + File.mtime(p) + end - # Extract handler, formats and variant from path. If a format cannot be found neither - # from the path, or the handler, we should return the array of formats given - # to the resolver. - def extract_handler_and_format_and_variant(path, default_formats) - pieces = File.basename(path).split('.'.freeze) - pieces.shift + # Extract handler, formats and variant from path. If a format cannot be found neither + # from the path, or the handler, we should return the array of formats given + # to the resolver. + def extract_handler_and_format_and_variant(path, default_formats) + pieces = File.basename(path).split(".".freeze) + pieces.shift - extension = pieces.pop + extension = pieces.pop - handler = Template.handler_for_extension(extension) - format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last - format &&= Template::Types[format] + handler = Template.handler_for_extension(extension) + format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last + format &&= Template::Types[format] - [handler, format, variant] - end + [handler, format, variant] + end end # A resolver that loads files from the filesystem. It allows setting your own diff --git a/actionview/lib/action_view/template/text.rb b/actionview/lib/action_view/template/text.rb index 04f5b8d17a..e8d4e18f04 100644 --- a/actionview/lib/action_view/template/text.rb +++ b/actionview/lib/action_view/template/text.rb @@ -11,12 +11,10 @@ module ActionView #:nodoc: end def identifier - 'text template' + "text template" end - def inspect - 'text template' - end + alias_method :inspect, :identifier def to_str @string diff --git a/actionview/lib/action_view/template/types.rb b/actionview/lib/action_view/template/types.rb index b32567cd66..21959a3798 100644 --- a/actionview/lib/action_view/template/types.rb +++ b/actionview/lib/action_view/template/types.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/module/attribute_accessors' +require "active_support/core_ext/module/attribute_accessors" module ActionView class Template diff --git a/actionview/lib/action_view/test_case.rb b/actionview/lib/action_view/test_case.rb index 120962b5aa..3eb1ac0826 100644 --- a/actionview/lib/action_view/test_case.rb +++ b/actionview/lib/action_view/test_case.rb @@ -1,9 +1,9 @@ -require 'active_support/core_ext/module/remove_method' -require 'action_controller' -require 'action_controller/test_case' -require 'action_view' +require "active_support/core_ext/module/remove_method" +require "action_controller" +require "action_controller/test_case" +require "action_view" -require 'rails-dom-testing' +require "rails-dom-testing" module ActionView # = Action View Test Case @@ -24,10 +24,10 @@ module ActionView def initialize super self.class.controller_path = "" - @request = ActionController::TestRequest.create + @request = ActionController::TestRequest.create(self.class) @response = ActionDispatch::TestResponse.new - @request.env.delete('PATH_INFO') + @request.env.delete("PATH_INFO") @params = ActionController::Parameters.new end end @@ -49,7 +49,7 @@ module ActionView include ActiveSupport::Testing::ConstantLookup - delegate :lookup_context, :to => :controller + delegate :lookup_context, to: :controller attr_accessor :controller, :output_buffer, :rendered module ClassMethods @@ -96,7 +96,6 @@ module ActionView helper(helper_class) if helper_class include _helpers end - end def setup_with_controller @@ -104,8 +103,8 @@ module ActionView @request = @controller.request # empty string ensures buffer has UTF-8 encoding as # new without arguments returns ASCII-8BIT encoded buffer like String#new - @output_buffer = ActiveSupport::SafeBuffer.new '' - @rendered = '' + @output_buffer = ActiveSupport::SafeBuffer.new "" + @rendered = "" make_test_case_available_to_view! say_no_to_protect_against_forgery! @@ -146,13 +145,14 @@ module ActionView def view_rendered?(view, expected_locals) locals_for(view).any? do |actual_locals| - expected_locals.all? {|key, value| value == actual_locals[key] } + expected_locals.all? { |key, value| value == actual_locals[key] } end end end included do setup :setup_with_controller + ActiveSupport.run_load_hooks(:action_view_test_case, self) end private diff --git a/actionview/lib/action_view/testing/resolvers.rb b/actionview/lib/action_view/testing/resolvers.rb index 2664aca991..5cb9f66529 100644 --- a/actionview/lib/action_view/testing/resolvers.rb +++ b/actionview/lib/action_view/testing/resolvers.rb @@ -1,4 +1,5 @@ -require 'action_view/template/resolver' +require "active_support/core_ext/regexp" +require "action_view/template/resolver" module ActionView #:nodoc: # Use FixtureResolver in your tests to simulate the presence of files on the @@ -14,7 +15,7 @@ module ActionView #:nodoc: end def to_s - @hash.keys.join(', ') + @hash.keys.join(", ") end private @@ -22,32 +23,31 @@ module ActionView #:nodoc: def query(path, exts, formats, _) query = "" EXTENSIONS.each_key do |ext| - query << '(' << exts[ext].map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)' + query << "(" << exts[ext].map { |e| e && Regexp.escape(".#{e}") }.join("|") << "|)" end query = /^(#{Regexp.escape(path)})#{query}$/ templates = [] @hash.each do |_path, array| source, updated_at = array - next unless _path =~ query + next unless query.match?(_path) handler, format, variant = extract_handler_and_format_and_variant(_path, formats) templates << Template.new(source, _path, handler, - :virtual_path => path.virtual, - :format => format, - :variant => variant, - :updated_at => updated_at + virtual_path: path.virtual, + format: format, + variant: variant, + updated_at: updated_at ) end - templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size } + templates.sort_by { |t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size } end end class NullResolver < PathResolver def query(path, exts, formats, _) handler, format, variant = extract_handler_and_format_and_variant(path, formats) - [ActionView::Template.new("Template generated by Null Resolver", path.virtual, handler, :virtual_path => path.virtual, :format => format, :variant => variant)] + [ActionView::Template.new("Template generated by Null Resolver", path.virtual, handler, virtual_path: path.virtual, format: format, variant: variant)] end end end - diff --git a/actionview/lib/action_view/version.rb b/actionview/lib/action_view/version.rb index f55d3fdaef..315404864d 100644 --- a/actionview/lib/action_view/version.rb +++ b/actionview/lib/action_view/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActionView # Returns the version of the currently loaded ActionView as a <tt>Gem::Version</tt> diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb index 717d6866c5..b5cde5b43f 100644 --- a/actionview/lib/action_view/view_paths.rb +++ b/actionview/lib/action_view/view_paths.rb @@ -9,7 +9,7 @@ module ActionView end delegate :template_exists?, :any_templates?, :view_paths, :formats, :formats=, - :locale, :locale=, :to => :lookup_context + :locale, :locale=, to: :lookup_context module ClassMethods def _prefixes # :nodoc: @@ -22,11 +22,11 @@ module ActionView private - # Override this method in your controller if you want to change paths prefixes for finding views. - # Prefixes defined here will still be added to parents' <tt>._prefixes</tt>. - def local_prefixes - [controller_path] - end + # Override this method in your controller if you want to change paths prefixes for finding views. + # Prefixes defined here will still be added to parents' <tt>._prefixes</tt>. + def local_prefixes + [controller_path] + end end # The prefixes used in render "foo" shortcuts. @@ -43,7 +43,7 @@ module ActionView end def details_for_lookup - { } + {} end def append_view_path(path) diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index 3256d8fc4d..88c7189d22 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -1,10 +1,10 @@ -$:.unshift(File.dirname(__FILE__) + '/lib') -$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') -$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') +$:.unshift(File.dirname(__FILE__) + "/lib") +$:.unshift(File.dirname(__FILE__) + "/fixtures/helpers") +$:.unshift(File.dirname(__FILE__) + "/fixtures/alternate_helpers") -ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp') +ENV["TMPDIR"] = File.join(File.dirname(__FILE__), "tmp") -require 'active_support/core_ext/kernel/reporting' +require "active_support/core_ext/kernel/reporting" # These are the normal settings that will be set up by Railties # TODO: Have these tests support other combinations of these values @@ -13,16 +13,16 @@ silence_warnings do Encoding.default_external = "UTF-8" end -require 'active_support/testing/autorun' -require 'active_support/testing/method_call_assertions' -require 'action_controller' -require 'action_view' -require 'action_view/testing/resolvers' -require 'active_support/dependencies' -require 'active_model' -require 'active_record' +require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" +require "action_controller" +require "action_view" +require "action_view/testing/resolvers" +require "active_support/dependencies" +require "active_model" +require "active_record" -require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late +require "pp" # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late module Rails class << self @@ -43,11 +43,11 @@ ActiveSupport::Deprecation.debug = true I18n.enforce_available_locales = false # Register danish language for testing -I18n.backend.store_translations 'da', {} -I18n.backend.store_translations 'pt-BR', {} +I18n.backend.store_translations "da", {} +I18n.backend.store_translations "pt-BR", {} ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort -FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') +FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), "fixtures") module RenderERBUtils def view @@ -95,11 +95,11 @@ module ActionDispatch ActiveSupport::Deprecation.silence do SharedTestRoutes.draw do - get ':controller(/:action)' + get ":controller(/:action)" end ActionDispatch::IntegrationTest.app.routes.draw do - get ':controller(/:action)' + get ":controller(/:action)" end end @@ -137,7 +137,7 @@ class BasicController config.assets_dir = public_dir config.javascripts_dir = "#{public_dir}/javascripts" config.stylesheets_dir = "#{public_dir}/stylesheets" - config.assets = ActiveSupport::InheritableOptions.new({ :prefix => "assets" }) + config.assets = ActiveSupport::InheritableOptions.new(prefix: "assets") config end end @@ -164,13 +164,13 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase # simply return the controller#action as Rack::Body. class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher protected - def controller_reference(controller_param) - controller_param - end + def controller_reference(controller_param) + controller_param + end - def dispatch(controller, action, env) - [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]] - end + def dispatch(controller, action, env) + [200, { "Content-Type" => "text/html" }, ["#{controller}##{action}"]] + end end def self.stub_controllers @@ -204,7 +204,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase ActiveSupport::Dependencies.autoload_paths << path yield ensure - ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path} + ActiveSupport::Dependencies.autoload_paths.reject! { |p| p == path } ActiveSupport::Dependencies.clear end end @@ -263,20 +263,20 @@ end module ActionDispatch class DebugExceptions private - remove_method :stderr_logger - # Silence logger - def stderr_logger - nil - end + remove_method :stderr_logger + # Silence logger + def stderr_logger + nil + end end end # Skips the current run on Rubinius using Minitest::Assertions#skip -def rubinius_skip(message = '') - skip message if RUBY_ENGINE == 'rbx' +def rubinius_skip(message = "") + skip message if RUBY_ENGINE == "rbx" end # Skips the current run on JRuby using Minitest::Assertions#skip -def jruby_skip(message = '') +def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end diff --git a/actionview/test/actionpack/abstract/abstract_controller_test.rb b/actionview/test/actionpack/abstract/abstract_controller_test.rb index 490932fef0..a2cd3deb58 100644 --- a/actionview/test/actionpack/abstract/abstract_controller_test.rb +++ b/actionview/test/actionpack/abstract/abstract_controller_test.rb @@ -1,9 +1,8 @@ -require 'abstract_unit' -require 'set' +require "abstract_unit" +require "set" module AbstractController module Testing - # Test basic dispatching. # ==== # * Call process @@ -38,7 +37,7 @@ module AbstractController def render(options = {}) if options.is_a?(String) - options = {:_template_name => options} + options = { _template_name: options } end super end @@ -65,11 +64,11 @@ module AbstractController end def rendering_to_body - self.response_body = render_to_body :template => "naked_render" + self.response_body = render_to_body template: "naked_render" end def rendering_to_string - self.response_body = render_to_string :template => "naked_render" + self.response_body = render_to_string template: "naked_render" end end @@ -114,13 +113,13 @@ module AbstractController # * self._prefix is used when defined class PrefixedViews < RenderingController private - def self.prefix - name.underscore - end + def self.prefix + name.underscore + end - def _prefixes - [self.class.prefix] - end + def _prefixes + [self.class.prefix] + end end class Me3 < PrefixedViews @@ -189,19 +188,19 @@ module AbstractController include ActionView::Layouts private - def self.layout(formats) - find_template(name.underscore, {:formats => formats}, :_prefixes => ["layouts"]) - rescue ActionView::MissingTemplate - begin - find_template("application", {:formats => formats}, :_prefixes => ["layouts"]) + def self.layout(formats) + find_template(name.underscore, { formats: formats }, _prefixes: ["layouts"]) rescue ActionView::MissingTemplate + begin + find_template("application", { formats: formats }, _prefixes: ["layouts"]) + rescue ActionView::MissingTemplate + end end - end - def render_to_body(options = {}) - options[:_layout] = options[:layout] || _default_layout({}) - super - end + def render_to_body(options = {}) + options[:_layout] = options[:layout] || _default_layout({}) + super + end end class Me4 < WithLayouts @@ -228,7 +227,7 @@ module AbstractController end class ActionMissingRespondToActionController < AbstractController::Base - # No actions + # No actions private def action_missing(action_name) self.response_body = "success" @@ -248,7 +247,6 @@ module AbstractController end class TestRespondToAction < ActiveSupport::TestCase - def assert_dispatch(klass, body = "success", action = :index) controller = klass.new controller.process(action) @@ -277,18 +275,16 @@ module AbstractController end class Me6 < AbstractController::Base - self.action_methods + action_methods def index end end class TestActionMethodsReloading < ActiveSupport::TestCase - test "action_methods should be reloaded after defining a new method" do assert_equal Set.new(["index"]), Me6.action_methods end end - end end diff --git a/actionview/test/actionpack/abstract/helper_test.rb b/actionview/test/actionpack/abstract/helper_test.rb index 7d346e917d..5a2f0839e5 100644 --- a/actionview/test/actionpack/abstract/helper_test.rb +++ b/actionview/test/actionpack/abstract/helper_test.rb @@ -1,17 +1,16 @@ -require 'abstract_unit' +require "abstract_unit" -ActionController::Base.helpers_path = File.expand_path('../../../fixtures/helpers', __FILE__) +ActionController::Base.helpers_path = File.expand_path("../../../fixtures/helpers", __FILE__) module AbstractController module Testing - class ControllerWithHelpers < AbstractController::Base include AbstractController::Helpers include AbstractController::Rendering include ActionView::Rendering def with_module - render :inline => "Module <%= included_method %>" + render inline: "Module <%= included_method %>" end end @@ -31,11 +30,11 @@ module AbstractController helper :abc def with_block - render :inline => "Hello <%= helpery_test %>" + render inline: "Hello <%= helpery_test %>" end def with_symbol - render :inline => "I respond to bare_a: <%= respond_to?(:bare_a) %>" + render inline: "I respond to bare_a: <%= respond_to?(:bare_a) %>" end end @@ -52,7 +51,7 @@ module AbstractController class AbstractInvalidHelpers < AbstractHelpers include ActionController::Helpers - path = File.expand_path('../../../fixtures/helpers_missing', __FILE__) + path = File.expand_path("../../../fixtures/helpers_missing", __FILE__) $:.unshift(path) self.helpers_path = path end diff --git a/actionview/test/actionpack/abstract/layouts_test.rb b/actionview/test/actionpack/abstract/layouts_test.rb index 78f6e78c61..4ece992597 100644 --- a/actionview/test/actionpack/abstract/layouts_test.rb +++ b/actionview/test/actionpack/abstract/layouts_test.rb @@ -1,8 +1,7 @@ -require 'abstract_unit' +require "abstract_unit" module AbstractControllerTests module Layouts - # Base controller for these tests class Base < AbstractController::Base include AbstractController::Rendering @@ -30,7 +29,7 @@ module AbstractControllerTests self.view_paths = [] def index - render :template => ActionView::Template::Text.new("Hello blank!") + render template: ActionView::Template::Text.new("Hello blank!") end end @@ -38,7 +37,7 @@ module AbstractControllerTests layout "hello_locals" def index - render :template => 'some/template', locals: { foo: "less than 3" } + render template: "some/template", locals: { foo: "less than 3" } end end @@ -46,7 +45,7 @@ module AbstractControllerTests layout "hello" def index - render :template => ActionView::Template::Text.new("Hello string!") + render template: ActionView::Template::Text.new("Hello string!") end def action_has_layout_false @@ -54,15 +53,15 @@ module AbstractControllerTests end def overwrite_default - render :template => ActionView::Template::Text.new("Hello string!"), :layout => :default + render template: ActionView::Template::Text.new("Hello string!"), layout: :default end def overwrite_false - render :template => ActionView::Template::Text.new("Hello string!"), :layout => false + render template: ActionView::Template::Text.new("Hello string!"), layout: false end def overwrite_string - render :template => ActionView::Template::Text.new("Hello string!"), :layout => "overwrite" + render template: ActionView::Template::Text.new("Hello string!"), layout: "overwrite" end def overwrite_skip @@ -92,7 +91,7 @@ module AbstractControllerTests layout proc { "overwrite" } def index - render :template => ActionView::Template::Text.new("Hello proc!") + render template: ActionView::Template::Text.new("Hello proc!") end end @@ -116,7 +115,7 @@ module AbstractControllerTests layout proc { "overwrite" } def index - render :template => ActionView::Template::Text.new("Hello zero arity proc!") + render template: ActionView::Template::Text.new("Hello zero arity proc!") end end @@ -129,7 +128,7 @@ module AbstractControllerTests } def index - render :template => ActionView::Template::Text.new("Hello again zero arity proc!") + render template: ActionView::Template::Text.new("Hello again zero arity proc!") end end @@ -137,7 +136,7 @@ module AbstractControllerTests layout :hello def index - render :template => ActionView::Template::Text.new("Hello symbol!") + render template: ActionView::Template::Text.new("Hello symbol!") end private def hello @@ -149,7 +148,7 @@ module AbstractControllerTests layout :nilz def index - render :template => ActionView::Template::Text.new("Hello nilz!") + render template: ActionView::Template::Text.new("Hello nilz!") end def nilz() end @@ -159,7 +158,7 @@ module AbstractControllerTests layout :objekt def index - render :template => ActionView::Template::Text.new("Hello nilz!") + render template: ActionView::Template::Text.new("Hello nilz!") end def objekt @@ -171,7 +170,7 @@ module AbstractControllerTests layout :no_method def index - render :template => ActionView::Template::Text.new("Hello boom!") + render template: ActionView::Template::Text.new("Hello boom!") end end @@ -179,7 +178,7 @@ module AbstractControllerTests layout "missing" def index - render :template => ActionView::Template::Text.new("Hello missing!") + render template: ActionView::Template::Text.new("Hello missing!") end end @@ -187,7 +186,7 @@ module AbstractControllerTests layout false def index - render :template => ActionView::Template::Text.new("Hello false!") + render template: ActionView::Template::Text.new("Hello false!") end end @@ -195,19 +194,19 @@ module AbstractControllerTests layout nil def index - render :template => ActionView::Template::Text.new("Hello nil!") + render template: ActionView::Template::Text.new("Hello nil!") end end class WithOnlyConditional < WithStringImpliedChild - layout "overwrite", :only => :show + layout "overwrite", only: :show def index - render :template => ActionView::Template::Text.new("Hello index!") + render template: ActionView::Template::Text.new("Hello index!") end def show - render :template => ActionView::Template::Text.new("Hello show!") + render template: ActionView::Template::Text.new("Hello show!") end end @@ -220,14 +219,14 @@ module AbstractControllerTests end class WithExceptConditional < WithStringImpliedChild - layout "overwrite", :except => :show + layout "overwrite", except: :show def index - render :template => ActionView::Template::Text.new("Hello index!") + render template: ActionView::Template::Text.new("Hello index!") end def show - render :template => ActionView::Template::Text.new("Hello show!") + render template: ActionView::Template::Text.new("Hello show!") end end @@ -294,7 +293,7 @@ module AbstractControllerTests 10.times do |x| controller = WithString.new controller.define_singleton_method :index do - render :template => ActionView::Template::Text.new("Hello string!"), :locals => { :"x#{x}" => :omg } + render template: ActionView::Template::Text.new("Hello string!"), locals: { :"x#{x}" => :omg } end controller.process(:index) end @@ -349,7 +348,7 @@ module AbstractControllerTests end test "when layout is specified as a proc, do not leak any methods into controller's action_methods" do - assert_equal Set.new(['index']), WithProc.action_methods + assert_equal Set.new(["index"]), WithProc.action_methods end test "when layout is specified as a proc, call it and use the layout returned" do @@ -422,16 +421,16 @@ module AbstractControllerTests test "when a grandchild has no layout specified, the child has an implied layout, and the " \ "parent has specified a layout, use the child controller layout" do - controller = WithChildOfImplied.new - controller.process(:index) - assert_equal "With Implied Hello string!", controller.response_body + controller = WithChildOfImplied.new + controller.process(:index) + assert_equal "With Implied Hello string!", controller.response_body end test "when a grandchild has nil layout specified, the child has an implied layout, and the " \ "parent has specified a layout, use the grand child controller layout" do - controller = WithGrandChildOfImplied.new - controller.process(:index) - assert_equal "With Grand Child Hello string!", controller.response_body + controller = WithGrandChildOfImplied.new + controller.process(:index) + assert_equal "With Grand Child Hello string!", controller.response_body end test "a child inherits layout from abstract controller" do @@ -543,7 +542,7 @@ module AbstractControllerTests test "layout for anonymous controller" do klass = Class.new(WithString) do def index - render plain: 'index', layout: true + render plain: "index", layout: true end end diff --git a/actionview/test/actionpack/abstract/render_test.rb b/actionview/test/actionpack/abstract/render_test.rb index e185b76adb..8b0c54fb77 100644 --- a/actionview/test/actionpack/abstract/render_test.rb +++ b/actionview/test/actionpack/abstract/render_test.rb @@ -1,8 +1,7 @@ -require 'abstract_unit' +require "abstract_unit" module AbstractController module Testing - class ControllerRenderer < AbstractController::Base include AbstractController::Rendering include ActionView::Rendering @@ -21,15 +20,15 @@ module AbstractController )] def template - render :template => "template" + render template: "template" end def file - render :file => "some/file" + render file: "some/file" end def inline - render :inline => "With <%= :Inline %>" + render inline: "With <%= :Inline %>" end def text @@ -54,7 +53,6 @@ module AbstractController end class TestRenderer < ActiveSupport::TestCase - def setup @controller = ControllerRenderer.new end diff --git a/actionview/test/actionpack/controller/capture_test.rb b/actionview/test/actionpack/controller/capture_test.rb index 933456ce9d..f0ae609845 100644 --- a/actionview/test/actionpack/controller/capture_test.rb +++ b/actionview/test/actionpack/controller/capture_test.rb @@ -1,30 +1,30 @@ -require 'abstract_unit' -require 'active_support/logger' +require "abstract_unit" +require "active_support/logger" class CaptureController < ActionController::Base - self.view_paths = [ File.dirname(__FILE__) + '/../../fixtures/actionpack' ] + self.view_paths = [ File.dirname(__FILE__) + "/../../fixtures/actionpack" ] def self.controller_name; "test"; end def self.controller_path; "test"; end def content_for @title = nil - render :layout => "talk_from_action" + render layout: "talk_from_action" end def content_for_with_parameter @title = nil - render :layout => "talk_from_action" + render layout: "talk_from_action" end def content_for_concatenated @title = nil - render :layout => "talk_from_action" + render layout: "talk_from_action" end def non_erb_block_content_for @title = nil - render :layout => "talk_from_action" + render layout: "talk_from_action" end def proper_block_detection diff --git a/actionview/test/actionpack/controller/layout_test.rb b/actionview/test/actionpack/controller/layout_test.rb index 64bc4c41d6..00147d31f3 100644 --- a/actionview/test/actionpack/controller/layout_test.rb +++ b/actionview/test/actionpack/controller/layout_test.rb @@ -1,15 +1,16 @@ -require 'abstract_unit' -require 'active_support/core_ext/array/extract_options' +require "abstract_unit" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" # The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited # method has access to the view_paths array when looking for a layout to automatically assign. old_load_paths = ActionController::Base.view_paths -ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../../fixtures/actionpack/layout_tests/' ] +ActionController::Base.view_paths = [ File.dirname(__FILE__) + "/../../fixtures/actionpack/layout_tests/" ] class LayoutTest < ActionController::Base - def self.controller_path; 'views' end - def self._implied_layout_name; to_s.underscore.gsub(/_controller$/, '') ; end + def self.controller_path; "views" end + def self._implied_layout_name; to_s.underscore.gsub(/_controller$/, "") ; end self.view_paths = ActionController::Base.view_paths.dup end @@ -54,13 +55,13 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase def test_application_layout_is_default_when_no_controller_match @controller = ProductController.new get :hello - assert_equal 'layout_test.erb hello.erb', @response.body + assert_equal "layout_test.erb hello.erb", @response.body end def test_controller_name_layout_name_match @controller = ItemController.new get :hello - assert_equal 'item.erb hello.erb', @response.body + assert_equal "item.erb hello.erb", @response.body end def test_third_party_template_library_auto_discovers_layout @@ -68,20 +69,20 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase @controller = ThirdPartyTemplateLibraryController.new get :hello assert_response :success - assert_equal 'layouts/third_party_template_library.mab', @response.body + assert_equal "layouts/third_party_template_library.mab", @response.body end end def test_namespaced_controllers_auto_detect_layouts1 @controller = ControllerNameSpace::NestedController.new get :hello - assert_equal 'controller_name_space/nested.erb hello.erb', @response.body + assert_equal "controller_name_space/nested.erb hello.erb", @response.body end def test_namespaced_controllers_auto_detect_layouts2 @controller = MultipleExtensions.new get :hello - assert_equal 'multiple_extensions.html.erb hello.erb', @response.body.strip + assert_equal "multiple_extensions.html.erb hello.erb", @response.body.strip end end @@ -91,16 +92,16 @@ end class StreamingLayoutController < LayoutTest def render(*args) options = args.extract_options! - super(*args, options.merge(:stream => true)) + super(*args, options.merge(stream: true)) end end class AbsolutePathLayoutController < LayoutTest - layout File.expand_path(File.expand_path(__FILE__) + '/../../../fixtures/actionpack/layout_tests/layouts/layout_test') + layout File.expand_path(File.expand_path(__FILE__) + "/../../../fixtures/actionpack/layout_tests/layouts/layout_test") end class HasOwnLayoutController < LayoutTest - layout 'item' + layout "item" end class HasNilLayoutSymbol < LayoutTest @@ -117,28 +118,28 @@ end class PrependsViewPathController < LayoutTest def hello - prepend_view_path File.dirname(__FILE__) + '/../../fixtures/actionpack/layout_tests/alt/' - render :layout => 'alt' + prepend_view_path File.dirname(__FILE__) + "/../../fixtures/actionpack/layout_tests/alt/" + render layout: "alt" end end class OnlyLayoutController < LayoutTest - layout 'item', :only => "hello" + layout "item", only: "hello" end class ExceptLayoutController < LayoutTest - layout 'item', :except => "goodbye" + layout "item", except: "goodbye" end class SetsLayoutInRenderController < LayoutTest def hello - render :layout => 'third_party_template_library' + render layout: "third_party_template_library" end end class RendersNoLayoutController < LayoutTest def hello - render :layout => false + render layout: false end end @@ -149,75 +150,75 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_layout_set_when_using_default_layout @controller = DefaultLayoutController.new get :hello - assert_includes @response.body, 'layout_test.erb' + assert_includes @response.body, "layout_test.erb" end def test_layout_set_when_using_streaming_layout @controller = StreamingLayoutController.new get :hello - assert_includes @response.body, 'layout_test.erb' + assert_includes @response.body, "layout_test.erb" end def test_layout_set_when_set_in_controller @controller = HasOwnLayoutController.new get :hello - assert_includes @response.body, 'item.erb' + assert_includes @response.body, "item.erb" end def test_layout_symbol_set_in_controller_returning_nil_falls_back_to_default @controller = HasNilLayoutSymbol.new get :hello - assert_includes @response.body, 'layout_test.erb' + assert_includes @response.body, "layout_test.erb" end def test_layout_proc_set_in_controller_returning_nil_falls_back_to_default @controller = HasNilLayoutProc.new get :hello - assert_includes @response.body, 'layout_test.erb' + assert_includes @response.body, "layout_test.erb" end def test_layout_only_exception_when_included @controller = OnlyLayoutController.new get :hello - assert_includes @response.body, 'item.erb' + assert_includes @response.body, "item.erb" end def test_layout_only_exception_when_excepted @controller = OnlyLayoutController.new get :goodbye - assert_not_includes @response.body, 'item.erb' + assert_not_includes @response.body, "item.erb" end def test_layout_except_exception_when_included @controller = ExceptLayoutController.new get :hello - assert_includes @response.body, 'item.erb' + assert_includes @response.body, "item.erb" end def test_layout_except_exception_when_excepted @controller = ExceptLayoutController.new get :goodbye - assert_not_includes @response.body, 'item.erb' + assert_not_includes @response.body, "item.erb" end def test_layout_set_when_using_render with_template_handler :mab, lambda { |template| template.source.inspect } do @controller = SetsLayoutInRenderController.new get :hello - assert_includes @response.body, 'layouts/third_party_template_library.mab' + assert_includes @response.body, "layouts/third_party_template_library.mab" end end def test_layout_is_not_set_when_none_rendered @controller = RendersNoLayoutController.new get :hello - assert_equal 'hello.erb', @response.body + assert_equal "hello.erb", @response.body end def test_layout_is_picked_from_the_controller_instances_view_path @controller = PrependsViewPathController.new get :hello - assert_includes @response.body, 'alt.erb' + assert_includes @response.body, "alt.erb" end def test_absolute_pathed_layout @@ -240,7 +241,7 @@ end class LayoutStatusIsRendered < LayoutTest def hello - render :status => 401 + render status: 401 end end @@ -252,7 +253,7 @@ class LayoutStatusIsRenderedTest < ActionController::TestCase end end -unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ +unless /mswin|mingw/.match?(RbConfig::CONFIG["host_os"]) class LayoutSymlinkedTest < LayoutTest layout "symlinked/symlinked_layout" end @@ -262,7 +263,7 @@ unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ @controller = LayoutSymlinkedTest.new get :hello assert_response 200 - assert_includes @response.body, 'This is my layout' + assert_includes @response.body, "This is my layout" end end end diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb index 7b69ffc628..cd89dceb45 100644 --- a/actionview/test/actionpack/controller/render_test.rb +++ b/actionview/test/actionpack/controller/render_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_model' +require "abstract_unit" +require "active_model" class ApplicationController < ActionController::Base self.view_paths = File.join(FIXTURE_LOAD_PATH, "actionpack") @@ -51,7 +51,7 @@ module Quiz # Controller class QuestionsController < ApplicationController def new - render :partial => Quiz::Question.new("Namespaced Partial") + render partial: Quiz::Question.new("Namespaced Partial") end end end @@ -64,7 +64,7 @@ module Fun def hello_world; end def nested_partial_with_form_builder - render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}) + render partial: ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}) end end end @@ -90,7 +90,7 @@ class TestController < ApplicationController end def hello_world_file - render :file => File.expand_path("../../../fixtures/actionpack/hello", __FILE__), :formats => [:html] + render file: File.expand_path("../../../fixtures/actionpack/hello", __FILE__), formats: [:html] end # :ported: @@ -110,12 +110,12 @@ class TestController < ApplicationController # :ported: def render_template_in_top_directory - render :template => 'shared' + render template: "shared" end # :deprecated: def render_template_in_top_directory_with_slash - render '/shared' + render "/shared" end # :ported: @@ -126,11 +126,11 @@ class TestController < ApplicationController # :ported: def render_action_hello_world - render :action => "hello_world" + render action: "hello_world" end def render_action_upcased_hello_world - render :action => "Hello_world" + render action: "Hello_world" end def render_action_hello_world_as_string @@ -138,7 +138,7 @@ class TestController < ApplicationController end def render_action_hello_world_with_symbol - render :action => :hello_world + render action: :hello_world end # :ported: @@ -149,70 +149,70 @@ class TestController < ApplicationController # :ported: def render_text_hello_world_with_layout @variable_for_layout = ", I am here!" - render plain: "hello world", :layout => true + render plain: "hello world", layout: true end def hello_world_with_layout_false - render :layout => false + render layout: false end # :ported: def render_file_with_instance_variables - @secret = 'in the sauce' - path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar') - render :file => path + @secret = "in the sauce" + path = File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_ivar") + render file: path end # :ported: def render_file_not_using_full_path - @secret = 'in the sauce' - render :file => 'test/render_file_with_ivar' + @secret = "in the sauce" + render file: "test/render_file_with_ivar" end def render_file_not_using_full_path_with_dot_in_path - @secret = 'in the sauce' - render :file => 'test/dot.directory/render_file_with_ivar' + @secret = "in the sauce" + render file: "test/dot.directory/render_file_with_ivar" end def render_file_using_pathname - @secret = 'in the sauce' - render :file => Pathname.new(File.dirname(__FILE__)).join('..', '..', 'fixtures', 'test', 'dot.directory', 'render_file_with_ivar') + @secret = "in the sauce" + render file: Pathname.new(File.dirname(__FILE__)).join("..", "..", "fixtures", "test", "dot.directory", "render_file_with_ivar") end def render_file_from_template - @secret = 'in the sauce' - @path = File.expand_path(File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar')) + @secret = "in the sauce" + @path = File.expand_path(File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_ivar")) end def render_file_with_locals - path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals') - render :file => path, :locals => {:secret => 'in the sauce'} + path = File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_locals") + render file: path, locals: { secret: "in the sauce" } end def render_file_as_string_with_locals - path = File.expand_path(File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals')) - render file: path, :locals => {:secret => 'in the sauce'} + path = File.expand_path(File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_locals")) + render file: path, locals: { secret: "in the sauce" } end def accessing_request_in_template - render :inline => "Hello: <%= request.host %>" + render inline: "Hello: <%= request.host %>" end def accessing_logger_in_template - render :inline => "<%= logger.class %>" + render inline: "<%= logger.class %>" end def accessing_action_name_in_template - render :inline => "<%= action_name %>" + render inline: "<%= action_name %>" end def accessing_controller_name_in_template - render :inline => "<%= controller_name %>" + render inline: "<%= controller_name %>" end # :ported: def render_custom_code - render plain: "hello world", :status => 404 + render plain: "hello world", status: 404 end # :ported: @@ -240,7 +240,7 @@ class TestController < ApplicationController # setting content type def render_xml_hello @name = "David" - render :template => "test/hello" + render template: "test/hello" end def render_xml_hello_as_string_template @@ -249,7 +249,7 @@ class TestController < ApplicationController end def render_line_offset - render :inline => '<% raise %>', :locals => {:foo => 'bar'} + render inline: "<% raise %>", locals: { foo: "bar" } end def heading @@ -262,49 +262,49 @@ class TestController < ApplicationController # :ported: def blank_response - render plain: ' ' + render plain: " " end # :ported: def layout_test - render :action => "hello_world" + render action: "hello_world" end # :ported: def builder_layout_test @name = nil - render :action => "hello", :layout => "layouts/builder" + render action: "hello", layout: "layouts/builder" end # :move: test this in Action View def builder_partial_test - render :action => "hello_world_container" + render action: "hello_world_container" end # :ported: def partials_list - @test_unchanged = 'hello' + @test_unchanged = "hello" @customers = [ Customer.new("david"), Customer.new("mary") ] - render :action => "list" + render action: "list" end def partial_only - render :partial => true + render partial: true end def hello_in_a_string @customers = [ Customer.new("david"), Customer.new("mary") ] - render plain: "How's there? " + render_to_string(:template => "test/list") + render plain: "How's there? " + render_to_string(template: "test/list") end def accessing_params_in_template - render :inline => "Hello: <%= params[:name] %>" + render inline: "Hello: <%= params[:name] %>" end def accessing_local_assigns_in_inline_template name = params[:local_name] - render :inline => "<%= 'Goodbye, ' + local_name %>", - :locals => { :local_name => name } + render inline: "<%= 'Goodbye, ' + local_name %>", + locals: { local_name: name } end def render_implicit_html_template_from_xhr_request @@ -320,7 +320,7 @@ class TestController < ApplicationController end def render_to_string_test - @foo = render_to_string :inline => "this is a test" + @foo = render_to_string inline: "this is a test" end def default_render @@ -333,27 +333,27 @@ class TestController < ApplicationController end def render_action_hello_world_as_symbol - render :action => :hello_world + render action: :hello_world end def layout_test_with_different_layout - render :action => "hello_world", :layout => "standard" + render action: "hello_world", layout: "standard" end def layout_test_with_different_layout_and_string_action - render "hello_world", :layout => "standard" + render "hello_world", layout: "standard" end def layout_test_with_different_layout_and_symbol_action - render :hello_world, :layout => "standard" + render :hello_world, layout: "standard" end def rendering_without_layout - render :action => "hello_world", :layout => false + render action: "hello_world", layout: false end def layout_overriding_layout - render :action => "hello_world", :layout => "standard" + render action: "hello_world", layout: "standard" end def rendering_nothing_on_layout @@ -364,38 +364,38 @@ class TestController < ApplicationController @before = "i'm before the render" render_to_string plain: "foo" @after = "i'm after the render" - render :template => "test/hello_world" + render template: "test/hello_world" end def render_to_string_with_exception - render_to_string :file => "exception that will not be caught - this will certainly not work" + render_to_string file: "exception that will not be caught - this will certainly not work" end def render_to_string_with_caught_exception @before = "i'm before the render" begin - render_to_string :file => "exception that will be caught- hope my future instance vars still work!" + render_to_string file: "exception that will be caught- hope my future instance vars still work!" rescue end @after = "i'm after the render" - render :template => "test/hello_world" + render template: "test/hello_world" end def accessing_params_in_template_with_layout - render :layout => true, :inline => "Hello: <%= params[:name] %>" + render layout: true, inline: "Hello: <%= params[:name] %>" end # :ported: def render_with_explicit_template - render :template => "test/hello_world" + render template: "test/hello_world" end def render_with_explicit_unescaped_template - render :template => "test/h*llo_world" + render template: "test/h*llo_world" end def render_with_explicit_escaped_template - render :template => "test/hello,world" + render template: "test/hello,world" end def render_with_explicit_string_template @@ -404,7 +404,7 @@ class TestController < ApplicationController # :ported: def render_with_explicit_template_with_locals - render :template => "test/render_file_with_locals", :locals => { :secret => 'area51' } + render template: "test/render_file_with_locals", locals: { secret: "area51" } end # :ported: @@ -414,13 +414,13 @@ class TestController < ApplicationController end def double_redirect - redirect_to :action => "double_render" - redirect_to :action => "double_render" + redirect_to action: "double_render" + redirect_to action: "double_render" end def render_and_redirect render plain: "hello" - redirect_to :action => "double_render" + redirect_to action: "double_render" end def render_to_string_and_render @@ -429,22 +429,22 @@ class TestController < ApplicationController end def render_to_string_with_inline_and_render - render_to_string :inline => "<%= 'dlrow olleh'.reverse %>" - render :template => "test/hello_world" + render_to_string inline: "<%= 'dlrow olleh'.reverse %>" + render template: "test/hello_world" end def rendering_with_conflicting_local_vars @name = "David" - render :action => "potential_conflicts" + render action: "potential_conflicts" end def hello_world_from_rxml_using_action - render :action => "hello_world_from_rxml", :handlers => [:builder] + render action: "hello_world_from_rxml", handlers: [:builder] end # :deprecated: def hello_world_from_rxml_using_template - render :template => "test/hello_world_from_rxml", :handlers => [:builder] + render template: "test/hello_world_from_rxml", handlers: [:builder] end def action_talk_to_layout @@ -458,11 +458,11 @@ class TestController < ApplicationController end def render_with_assigns_option - render inline: '<%= @hello %>', assigns: { hello: "world" } + render inline: "<%= @hello %>", assigns: { hello: "world" } end def yield_content_for - render :action => "content_for", :layout => "yield" + render action: "content_for", layout: "yield" end def render_content_type_from_body @@ -471,117 +471,117 @@ class TestController < ApplicationController end def render_using_layout_around_block - render :action => "using_layout_around_block" + render action: "using_layout_around_block" end def render_using_layout_around_block_in_main_layout_and_within_content_for_layout - render :action => "using_layout_around_block", :layout => "layouts/block_with_layout" + render action: "using_layout_around_block", layout: "layouts/block_with_layout" end def partial_formats_html - render :partial => 'partial', :formats => [:html] + render partial: "partial", formats: [:html] end def partial - render :partial => 'partial' + render partial: "partial" end def partial_html_erb - render :partial => 'partial_html_erb' + render partial: "partial_html_erb" end def render_to_string_with_partial - @partial_only = render_to_string :partial => "partial_only" - @partial_with_locals = render_to_string :partial => "customer", :locals => { :customer => Customer.new("david") } - render :template => "test/hello_world" + @partial_only = render_to_string partial: "partial_only" + @partial_with_locals = render_to_string partial: "customer", locals: { customer: Customer.new("david") } + render template: "test/hello_world" end def render_to_string_with_template_and_html_partial - @text = render_to_string :template => "test/with_partial", :formats => [:text] - @html = render_to_string :template => "test/with_partial", :formats => [:html] - render :template => "test/with_html_partial" + @text = render_to_string template: "test/with_partial", formats: [:text] + @html = render_to_string template: "test/with_partial", formats: [:html] + render template: "test/with_html_partial" end def render_to_string_and_render_with_different_formats - @html = render_to_string :template => "test/with_partial", :formats => [:html] - render :template => "test/with_partial", :formats => [:text] + @html = render_to_string template: "test/with_partial", formats: [:html] + render template: "test/with_partial", formats: [:text] end def render_template_within_a_template_with_other_format - render :template => "test/with_xml_template", - :formats => [:html], - :layout => "with_html_partial" + render template: "test/with_xml_template", + formats: [:html], + layout: "with_html_partial" end def partial_with_counter - render :partial => "counter", :locals => { :counter_counter => 5 } + render partial: "counter", locals: { counter_counter: 5 } end def partial_with_locals - render :partial => "customer", :locals => { :customer => Customer.new("david") } + render partial: "customer", locals: { customer: Customer.new("david") } end def partial_with_form_builder - render :partial => ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}) + render partial: ActionView::Helpers::FormBuilder.new(:post, nil, view_context, {}) end def partial_with_form_builder_subclass - render :partial => LabellingFormBuilder.new(:post, nil, view_context, {}) + render partial: LabellingFormBuilder.new(:post, nil, view_context, {}) end def partial_collection - render :partial => "customer", :collection => [ Customer.new("david"), Customer.new("mary") ] + render partial: "customer", collection: [ Customer.new("david"), Customer.new("mary") ] end def partial_collection_with_as - render :partial => "customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer + render partial: "customer_with_var", collection: [ Customer.new("david"), Customer.new("mary") ], as: :customer end def partial_collection_with_iteration - render partial: "customer_iteration", collection: [ Customer.new("david"), Customer.new("mary"), Customer.new('christine') ] + render partial: "customer_iteration", collection: [ Customer.new("david"), Customer.new("mary"), Customer.new("christine") ] end def partial_collection_with_as_and_iteration - render partial: "customer_iteration_with_as", collection: [ Customer.new("david"), Customer.new("mary"), Customer.new('christine') ], as: :client + render partial: "customer_iteration_with_as", collection: [ Customer.new("david"), Customer.new("mary"), Customer.new("christine") ], as: :client end def partial_collection_with_counter - render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ] + render partial: "customer_counter", collection: [ Customer.new("david"), Customer.new("mary") ] end def partial_collection_with_as_and_counter - render :partial => "customer_counter_with_as", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :client + render partial: "customer_counter_with_as", collection: [ Customer.new("david"), Customer.new("mary") ], as: :client end def partial_collection_with_locals - render :partial => "customer_greeting", :collection => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } + render partial: "customer_greeting", collection: [ Customer.new("david"), Customer.new("mary") ], locals: { greeting: "Bonjour" } end def partial_collection_with_spacer - render :partial => "customer", :spacer_template => "partial_only", :collection => [ Customer.new("david"), Customer.new("mary") ] + render partial: "customer", spacer_template: "partial_only", collection: [ Customer.new("david"), Customer.new("mary") ] end def partial_collection_with_spacer_which_uses_render - render :partial => "customer", :spacer_template => "partial_with_partial", :collection => [ Customer.new("david"), Customer.new("mary") ] + render partial: "customer", spacer_template: "partial_with_partial", collection: [ Customer.new("david"), Customer.new("mary") ] end def partial_collection_shorthand_with_locals - render :partial => [ Customer.new("david"), Customer.new("mary") ], :locals => { :greeting => "Bonjour" } + render partial: [ Customer.new("david"), Customer.new("mary") ], locals: { greeting: "Bonjour" } end def partial_collection_shorthand_with_different_types_of_records - render :partial => [ + render partial: [ BadCustomer.new("mark"), GoodCustomer.new("craig"), BadCustomer.new("john"), GoodCustomer.new("zach"), GoodCustomer.new("brandon"), BadCustomer.new("dan") ], - :locals => { :greeting => "Bonjour" } + locals: { greeting: "Bonjour" } end def empty_partial_collection - render :partial => "customer", :collection => [] + render partial: "customer", collection: [] end def partial_collection_shorthand_with_different_types_of_records_with_counter @@ -589,15 +589,15 @@ class TestController < ApplicationController end def missing_partial - render :partial => 'thisFileIsntHere' + render partial: "thisFileIsntHere" end def partial_with_hash_object - render :partial => "hash_object", :object => {:first_name => "Sam"} + render partial: "hash_object", object: { first_name: "Sam" } end def partial_with_nested_object - render :partial => "quiz/questions/question", :object => Quiz::Question.new("first") + render partial: "quiz/questions/question", object: Quiz::Question.new("first") end def partial_with_nested_object_shorthand @@ -605,24 +605,24 @@ class TestController < ApplicationController end def partial_hash_collection - render :partial => "hash_object", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ] + render partial: "hash_object", collection: [ { first_name: "Pratik" }, { first_name: "Amy" } ] end def partial_hash_collection_with_locals - render :partial => "hash_greeting", :collection => [ {:first_name => "Pratik"}, {:first_name => "Amy"} ], :locals => { :greeting => "Hola" } + render partial: "hash_greeting", collection: [ { first_name: "Pratik" }, { first_name: "Amy" } ], locals: { greeting: "Hola" } end def partial_with_implicit_local_assignment @customer = Customer.new("Marcel") - render :partial => "customer" + render partial: "customer" end def render_call_to_partial_with_layout - render :action => "calling_partial_with_layout" + render action: "calling_partial_with_layout" end def render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout - render :action => "calling_partial_with_layout", :layout => "layouts/partial_with_layout" + render action: "calling_partial_with_layout", layout: "layouts/partial_with_layout" end before_action only: :render_with_filters do @@ -631,7 +631,7 @@ class TestController < ApplicationController # Ensure that the before filter is executed *before* self.formats is set. def render_with_filters - render :action => :formatted_xml_erb + render action: :formatted_xml_erb end private @@ -642,7 +642,7 @@ class TestController < ApplicationController def determine_layout case action_name - when "hello_world", "layout_test", "rendering_without_layout", + when "hello_world", "layout_test", "rendering_without_layout", "rendering_nothing_on_layout", "render_text_hello_world", "render_text_hello_world_with_layout", "hello_world_with_layout_false", @@ -652,11 +652,11 @@ class TestController < ApplicationController "render_with_explicit_string_template", "update_page", "update_page_with_instance_variables" - "layouts/standard" - when "action_talk_to_layout", "layout_overriding_layout" - "layouts/talk_from_action" - when "render_implicit_html_template_from_xhr_request" - (request.xhr? ? 'layouts/xhr' : 'layouts/standard') + "layouts/standard" + when "action_talk_to_layout", "layout_overriding_layout" + "layouts/talk_from_action" + when "render_implicit_html_template_from_xhr_request" + (request.xhr? ? "layouts/xhr" : "layouts/standard") end end end @@ -771,7 +771,7 @@ class RenderTest < ActionController::TestCase # :ported: def test_do_with_render_action_and_layout_false get :hello_world_with_layout_false - assert_equal 'Hello world!', @response.body + assert_equal "Hello world!", @response.body end # :ported: @@ -826,27 +826,27 @@ class RenderTest < ActionController::TestCase get :render_custom_code assert_response 404 assert_response :missing - assert_equal 'hello world', @response.body + assert_equal "hello world", @response.body end # :ported: def test_render_text_with_nil get :render_text_with_nil assert_response 200 - assert_equal '', @response.body + assert_equal "", @response.body end # :ported: def test_render_text_with_false get :render_text_with_false - assert_equal 'false', @response.body + assert_equal "false", @response.body end # :ported: def test_render_nothing_with_appendix get :render_nothing_with_appendix assert_response 200 - assert_equal 'appended', @response.body + assert_equal "appended", @response.body end def test_render_text_with_resource @@ -941,7 +941,7 @@ class RenderTest < ActionController::TestCase def test_render_to_string_inline get :render_to_string_with_inline_and_render - assert_equal 'Hello world!', @response.body + assert_equal "Hello world!", @response.body end # :ported: @@ -974,24 +974,24 @@ class RenderTest < ActionController::TestCase def test_should_render_formatted_template get :formatted_html_erb - assert_equal 'formatted html erb', @response.body + assert_equal "formatted html erb", @response.body end def test_should_render_formatted_html_erb_template get :formatted_xml_erb - assert_equal '<test>passed formatted html erb</test>', @response.body + assert_equal "<test>passed formatted html erb</test>", @response.body end def test_should_render_formatted_html_erb_template_with_bad_accepts_header @request.env["HTTP_ACCEPT"] = "; a=dsf" get :formatted_xml_erb - assert_equal '<test>passed formatted html erb</test>', @response.body + assert_equal "<test>passed formatted html erb</test>", @response.body end def test_should_render_formatted_html_erb_template_with_faulty_accepts_header @request.accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*" get :formatted_xml_erb - assert_equal '<test>passed formatted html erb</test>', @response.body + assert_equal "<test>passed formatted html erb</test>", @response.body end def test_layout_test_with_different_layout @@ -1021,7 +1021,7 @@ class RenderTest < ActionController::TestCase def test_rendering_nothing_on_layout get :rendering_nothing_on_layout - assert_equal '', @response.body + assert_equal "", @response.body end def test_render_to_string_doesnt_break_assigns @@ -1103,7 +1103,7 @@ class RenderTest < ActionController::TestCase def test_render_text_with_assigns_option get :render_with_assigns_option - assert_equal 'world', response.body + assert_equal "world", response.body end # :ported: diff --git a/actionview/test/actionpack/controller/view_paths_test.rb b/actionview/test/actionpack/controller/view_paths_test.rb index e99659c802..4c58b959a9 100644 --- a/actionview/test/actionpack/controller/view_paths_test.rb +++ b/actionview/test/actionpack/controller/view_paths_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ViewLoadPathsTest < ActionController::TestCase class TestController < ActionController::Base @@ -7,7 +7,7 @@ class ViewLoadPathsTest < ActionController::TestCase before_action :add_view_path, only: :hello_world_at_request_time def hello_world() end - def hello_world_at_request_time() render(:action => 'hello_world') end + def hello_world_at_request_time() render(action: "hello_world") end private def add_view_path @@ -17,15 +17,15 @@ class ViewLoadPathsTest < ActionController::TestCase module Test class SubController < ActionController::Base - layout 'test/sub' - def hello_world; render(:template => 'test/hello_world'); end + layout "test/sub" + def hello_world; render(template: "test/hello_world"); end end end def setup - @request = ActionController::TestRequest.create - @response = ActionDispatch::TestResponse.new @controller = TestController.new + @request = ActionController::TestRequest.create(@controller.class) + @response = ActionDispatch::TestResponse.new @paths = TestController.view_paths end @@ -34,7 +34,7 @@ class ViewLoadPathsTest < ActionController::TestCase end def expand(array) - array.map {|x| File.expand_path(x.to_s)} + array.map { |x| File.expand_path(x.to_s) } end def assert_paths(*paths) @@ -47,7 +47,7 @@ class ViewLoadPathsTest < ActionController::TestCase end def test_controller_appends_view_path_correctly - @controller.append_view_path 'foo' + @controller.append_view_path "foo" assert_paths(FIXTURE_LOAD_PATH, "foo") @controller.append_view_path(%w(bar baz)) @@ -58,7 +58,7 @@ class ViewLoadPathsTest < ActionController::TestCase end def test_controller_prepends_view_path_correctly - @controller.prepend_view_path 'baz' + @controller.prepend_view_path "baz" assert_paths("baz", FIXTURE_LOAD_PATH) @controller.prepend_view_path(%w(foo bar)) @@ -72,7 +72,7 @@ class ViewLoadPathsTest < ActionController::TestCase @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) class_view_paths = TestController.view_paths - @controller.append_view_path 'foo' + @controller.append_view_path "foo" assert_paths FIXTURE_LOAD_PATH, "foo" @controller.append_view_path(%w(bar baz)) @@ -84,7 +84,7 @@ class ViewLoadPathsTest < ActionController::TestCase @controller.instance_variable_set :@template, ActionView::Base.new(TestController.view_paths, {}, @controller) class_view_paths = TestController.view_paths - @controller.prepend_view_path 'baz' + @controller.prepend_view_path "baz" assert_paths "baz", FIXTURE_LOAD_PATH @controller.prepend_view_path(%w(foo bar)) @@ -131,10 +131,8 @@ class ViewLoadPathsTest < ActionController::TestCase "Decorated body", template.identifier, template.handler, - { - :virtual_path => template.virtual_path, - :format => template.formats - } + virtual_path: template.virtual_path, + format: template.formats ) end end @@ -157,14 +155,14 @@ class ViewLoadPathsTest < ActionController::TestCase class C < ActionController::Base; end } - A.view_paths = ['a/path'] + A.view_paths = ["a/path"] assert_paths A, "a/path" assert_paths A, *B.view_paths assert_paths C, *original_load_paths C.view_paths = [] - assert_nothing_raised { C.append_view_path 'c/path' } + assert_nothing_raised { C.append_view_path "c/path" } assert_paths C, "c/path" end diff --git a/actionview/test/active_record_unit.rb b/actionview/test/active_record_unit.rb index f9e94413b5..7f94b7ebb4 100644 --- a/actionview/test/active_record_unit.rb +++ b/actionview/test/active_record_unit.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" # Define the essentials class ActiveRecordTestConnector @@ -16,7 +16,7 @@ unless defined?(ActiveRecord) && defined?(FixtureSet) PATH_TO_AR = "#{File.dirname(__FILE__)}/../../activerecord/lib" raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR) $LOAD_PATH.unshift PATH_TO_AR - require 'active_record' + require "active_record" rescue LoadError => e $stderr.print "Failed to load Active Record. Skipping Active Record assertion tests: #{e}" ActiveRecordTestConnector.able_to_connect = false @@ -24,12 +24,11 @@ unless defined?(ActiveRecord) && defined?(FixtureSet) end $stderr.flush - # Define the rest of the connector class ActiveRecordTestConnector class << self def setup - unless self.connected || !self.able_to_connect + unless connected || !able_to_connect setup_connection load_schema require_fixture_models @@ -44,14 +43,14 @@ class ActiveRecordTestConnector private def setup_connection if Object.const_defined?(:ActiveRecord) - defaults = { :database => ':memory:' } - adapter = defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' - options = defaults.merge :adapter => adapter, :timeout => 500 + defaults = { database: ":memory:" } + adapter = defined?(JRUBY_VERSION) ? "jdbcsqlite3" : "sqlite3" + options = defaults.merge adapter: adapter, timeout: 500 ActiveRecord::Base.establish_connection(options) - ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } + ActiveRecord::Base.configurations = { "sqlite3_ar_integration" => options } ActiveRecord::Base.connection - Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE) + Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name("type")) unless Object.const_defined?(:QUOTED_TYPE) else raise "Can't setup connection since ActiveRecord isn't loaded." end @@ -59,13 +58,13 @@ class ActiveRecordTestConnector # Load actionpack sqlite3 tables def load_schema - File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql| + File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(";").each do |sql| ActiveRecord::Base.connection.execute(sql) unless sql.blank? end end def require_fixture_models - Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f} + Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each { |f| require f } end end end diff --git a/actionview/test/activerecord/controller_runtime_test.rb b/actionview/test/activerecord/controller_runtime_test.rb index af91348d76..590559f592 100644 --- a/actionview/test/activerecord/controller_runtime_test.rb +++ b/actionview/test/activerecord/controller_runtime_test.rb @@ -1,19 +1,19 @@ -require 'active_record_unit' -require 'active_record/railties/controller_runtime' -require 'fixtures/project' -require 'active_support/log_subscriber/test_helper' -require 'action_controller/log_subscriber' +require "active_record_unit" +require "active_record/railties/controller_runtime" +require "fixtures/project" +require "active_support/log_subscriber/test_helper" +require "action_controller/log_subscriber" ActionController::Base.include(ActiveRecord::Railties::ControllerRuntime) class ControllerRuntimeLogSubscriberTest < ActionController::TestCase class LogSubscriberController < ActionController::Base def show - render :inline => "<%= Project.all %>" + render inline: "<%= Project.all %>" end def zero - render :inline => "Zero DB runtime" + render inline: "Zero DB runtime" end def create @@ -24,11 +24,11 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase def redirect Project.all - redirect_to :action => 'show' + redirect_to action: "show" end def db_after_render - render :inline => "Hello world" + render inline: "Hello world" Project.all ActiveRecord::LogSubscriber.runtime += 100 end @@ -38,8 +38,8 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase tests LogSubscriberController def setup - super @old_logger = ActionController::Base.logger + super ActionController::LogSubscriber.attach_to :action_controller end diff --git a/actionview/test/activerecord/debug_helper_test.rb b/actionview/test/activerecord/debug_helper_test.rb index ed1c08e134..06ae555a03 100644 --- a/actionview/test/activerecord/debug_helper_test.rb +++ b/actionview/test/activerecord/debug_helper_test.rb @@ -1,5 +1,5 @@ -require 'active_record_unit' -require 'nokogiri' +require "active_record_unit" +require "nokogiri" class DebugHelperTest < ActionView::TestCase def test_debug @@ -11,7 +11,7 @@ class DebugHelperTest < ActionView::TestCase end def test_debug_with_marshal_error - obj = -> { } + obj = -> {} assert_match obj.inspect, Nokogiri.XML(debug(obj)).content end end diff --git a/actionview/test/activerecord/form_helper_activerecord_test.rb b/actionview/test/activerecord/form_helper_activerecord_test.rb index 2769b97445..6152ec4720 100644 --- a/actionview/test/activerecord/form_helper_activerecord_test.rb +++ b/actionview/test/activerecord/form_helper_activerecord_test.rb @@ -1,6 +1,6 @@ -require 'active_record_unit' -require 'fixtures/project' -require 'fixtures/developer' +require "active_record_unit" +require "fixtures/project" +require "fixtures/developer" class FormHelperActiveRecordTest < ActionView::TestCase tests ActionView::Helpers::FormHelper @@ -39,12 +39,12 @@ class FormHelperActiveRecordTest < ActionView::TestCase def test_nested_fields_for_with_child_index_option_override_on_a_nested_attributes_collection_association form_for(@developer) do |f| - concat f.fields_for(:projects, @developer.projects.first, :child_index => 'abc') { |cf| + concat f.fields_for(:projects, @developer.projects.first, child_index: "abc") { |cf| concat cf.text_field(:name) } end - expected = whole_form('/developers/123', 'edit_developer_123', 'edit_developer', :method => 'patch') do + expected = whole_form("/developers/123", "edit_developer_123", "edit_developer", method: "patch") do '<input id="developer_projects_attributes_abc_name" name="developer[projects_attributes][abc][name]" type="text" value="project #321" />' + '<input id="developer_projects_attributes_abc_id" name="developer[projects_attributes][abc][id]" type="hidden" value="321" />' end @@ -54,35 +54,35 @@ class FormHelperActiveRecordTest < ActionView::TestCase protected - def hidden_fields(method = nil) - txt = %{<input name="utf8" type="hidden" value="✓" />} + def hidden_fields(method = nil) + txt = %{<input name="utf8" type="hidden" value="✓" />} - if method && !%w(get post).include?(method.to_s) - txt << %{<input name="_method" type="hidden" value="#{method}" />} + if method && !%w(get post).include?(method.to_s) + txt << %{<input name="_method" type="hidden" value="#{method}" />} + end + + txt end - txt - end + def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) + txt = %{<form accept-charset="UTF-8" action="#{action}"} + txt << %{ enctype="multipart/form-data"} if multipart + txt << %{ data-remote="true"} if remote + txt << %{ class="#{html_class}"} if html_class + txt << %{ id="#{id}"} if id + method = method.to_s == "get" ? "get" : "post" + txt << %{ method="#{method}">} + end - def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) - txt = %{<form accept-charset="UTF-8" action="#{action}"} - txt << %{ enctype="multipart/form-data"} if multipart - txt << %{ data-remote="true"} if remote - txt << %{ class="#{html_class}"} if html_class - txt << %{ id="#{id}"} if id - method = method.to_s == "get" ? "get" : "post" - txt << %{ method="#{method}">} - end + def whole_form(action = "/", id = nil, html_class = nil, options = nil) + contents = block_given? ? yield : "" - def whole_form(action = "/", id = nil, html_class = nil, options = nil) - contents = block_given? ? yield : "" + if options.is_a?(Hash) + method, remote, multipart = options.values_at(:method, :remote, :multipart) + else + method = options + end - if options.is_a?(Hash) - method, remote, multipart = options.values_at(:method, :remote, :multipart) - else - method = options + form_text(action, id, html_class, remote, multipart, method) + hidden_fields(method) + contents + "</form>" end - - form_text(action, id, html_class, remote, multipart, method) + hidden_fields(method) + contents + "</form>" - end end diff --git a/actionview/test/activerecord/polymorphic_routes_test.rb b/actionview/test/activerecord/polymorphic_routes_test.rb index 34b2698c7f..8495949975 100644 --- a/actionview/test/activerecord/polymorphic_routes_test.rb +++ b/actionview/test/activerecord/polymorphic_routes_test.rb @@ -1,28 +1,28 @@ -require 'active_record_unit' -require 'fixtures/project' +require "active_record_unit" +require "fixtures/project" class Task < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end class Step < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end class Bid < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end class Tax < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end class Fax < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end class Series < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end class ModelDelegator @@ -41,17 +41,17 @@ class ModelDelegate end def to_param - 'overridden' + "overridden" end end module Blog class Post < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end class Blog < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" end def self.use_relative_model_naming? @@ -61,7 +61,7 @@ end class PolymorphicRoutesTest < ActionController::TestCase include SharedTestRoutes.url_helpers - self.default_url_options[:host] = 'example.com' + self.default_url_options[:host] = "example.com" def setup @project = Project.new @@ -79,7 +79,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def assert_url(url, args) host = self.class.default_url_options[:host] - assert_equal url.sub(/http:\/\/#{host}/, ''), polymorphic_path(args) + assert_equal url.sub(/http:\/\/#{host}/, ""), polymorphic_path(args) assert_equal url, polymorphic_url(args) assert_equal url, url_for(args) end @@ -95,7 +95,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_string_with_options with_test_routes do - assert_equal "http://example.com/projects?id=10", polymorphic_url("projects", :id => 10) + assert_equal "http://example.com/projects?id=10", polymorphic_url("projects", id: 10) end end @@ -107,7 +107,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_symbol_with_options with_test_routes do - assert_equal "http://example.com/projects?id=10", polymorphic_url(:projects, :id => 10) + assert_equal "http://example.com/projects?id=10", polymorphic_url(:projects, id: 10) end end @@ -179,7 +179,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_with_nil_id with_test_routes do exception = assert_raise ArgumentError do - polymorphic_url({ :id => nil }) + polymorphic_url(id: nil) end assert_equal "Nil location provided. Can't build URI.", exception.message end @@ -233,8 +233,8 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_class_with_options with_test_routes do - assert_equal "http://example.com/projects?foo=bar", polymorphic_url(@project.class, { :foo => :bar }) - assert_equal "/projects?foo=bar", polymorphic_path(@project.class, { :foo => :bar }) + assert_equal "http://example.com/projects?foo=bar", polymorphic_url(@project.class, foo: :bar) + assert_equal "/projects?foo=bar", polymorphic_path(@project.class, foo: :bar) end end @@ -274,7 +274,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_with_record_and_action with_test_routes do - assert_equal "http://example.com/projects/new", polymorphic_url(@project, :action => 'new') + assert_equal "http://example.com/projects/new", polymorphic_url(@project, action: "new") end end @@ -303,35 +303,35 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_url_helper_prefixed_with_edit_with_url_options with_test_routes do @project.save - assert_equal "http://example.com/projects/#{@project.id}/edit?param1=10", edit_polymorphic_url(@project, :param1 => '10') + assert_equal "http://example.com/projects/#{@project.id}/edit?param1=10", edit_polymorphic_url(@project, param1: "10") end end def test_url_helper_with_url_options with_test_routes do @project.save - assert_equal "http://example.com/projects/#{@project.id}?param1=10", polymorphic_url(@project, :param1 => '10') + assert_equal "http://example.com/projects/#{@project.id}?param1=10", polymorphic_url(@project, param1: "10") end end def test_format_option with_test_routes do @project.save - assert_equal "http://example.com/projects/#{@project.id}.pdf", polymorphic_url(@project, :format => :pdf) + assert_equal "http://example.com/projects/#{@project.id}.pdf", polymorphic_url(@project, format: :pdf) end end def test_format_option_with_url_options with_test_routes do @project.save - assert_equal "http://example.com/projects/#{@project.id}.pdf?param1=10", polymorphic_url(@project, :format => :pdf, :param1 => '10') + assert_equal "http://example.com/projects/#{@project.id}.pdf?param1=10", polymorphic_url(@project, format: :pdf, param1: "10") end end def test_id_and_format_option with_test_routes do @project.save - assert_equal "http://example.com/projects/#{@project.id}.pdf", polymorphic_url(:id => @project, :format => :pdf) + assert_equal "http://example.com/projects/#{@project.id}.pdf", polymorphic_url(id: @project, format: :pdf) end end @@ -373,7 +373,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_new_with_array_and_namespace with_admin_test_routes do - assert_equal "http://example.com/admin/projects/new", polymorphic_url([:admin, @project], :action => 'new') + assert_equal "http://example.com/admin/projects/new", polymorphic_url([:admin, @project], action: "new") end end @@ -426,7 +426,7 @@ class PolymorphicRoutesTest < ActionController::TestCase with_test_routes do @project.save @task.save - assert_equal "http://example.com/projects/#{@project.id}/bid/tasks/#{@task.id}.pdf", polymorphic_url([@project, :bid, @task], :format => :pdf) + assert_equal "http://example.com/projects/#{@project.id}/bid/tasks/#{@task.id}.pdf", polymorphic_url([@project, :bid, @task], format: :pdf) end end @@ -474,13 +474,13 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_with_hash with_test_routes do @project.save - assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url(:id => @project) + assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url(id: @project) end end def test_polymorphic_path_accepts_options with_test_routes do - assert_equal "/projects/new", polymorphic_path(@project, :action => 'new') + assert_equal "/projects/new", polymorphic_path(@project, action: "new") end end @@ -493,7 +493,7 @@ class PolymorphicRoutesTest < ActionController::TestCase object_array = [:admin, @project, @task] original_args = [object_array.dup, options.dup] - assert_no_difference('object_array.size') { polymorphic_path(object_array, options) } + assert_no_difference("object_array.size") { polymorphic_path(object_array, options) } assert_equal original_args, [object_array, options] end end @@ -527,7 +527,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_with_irregular_plural_record_and_action with_test_routes do - assert_equal "http://example.com/taxes/new", polymorphic_url(@tax, :action => 'new') + assert_equal "http://example.com/taxes/new", polymorphic_url(@tax, action: "new") end end @@ -561,7 +561,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def test_new_with_irregular_plural_array_and_namespace with_admin_test_routes do - assert_equal "http://example.com/admin/taxes/new", polymorphic_url([:admin, @tax], :action => 'new') + assert_equal "http://example.com/admin/taxes/new", polymorphic_url([:admin, @tax], action: "new") end end @@ -598,7 +598,7 @@ class PolymorphicRoutesTest < ActionController::TestCase end end - # Tests for uncountable names + # Tests for uncountable names def test_uncountable_resource with_test_routes do @series.save @@ -622,7 +622,7 @@ class PolymorphicRoutesTest < ActionController::TestCase def with_namespaced_routes(name) with_routing do |set| set.draw do - scope(:module => name) do + scope(module: name) do resources :blogs do resources :posts do resources :faxes @@ -728,6 +728,6 @@ class PolymorphicPathRoutesTest < PolymorphicRoutesTest def assert_url(url, args) host = self.class.default_url_options[:host] - assert_equal url.sub(/http:\/\/#{host}/, ''), url_for(args) + assert_equal url.sub(/http:\/\/#{host}/, ""), url_for(args) end end diff --git a/actionview/test/activerecord/relation_cache_test.rb b/actionview/test/activerecord/relation_cache_test.rb index 8e97417b94..880e80a8dc 100644 --- a/actionview/test/activerecord/relation_cache_test.rb +++ b/actionview/test/activerecord/relation_cache_test.rb @@ -1,4 +1,4 @@ -require 'active_record_unit' +require "active_record_unit" class RelationCacheTest < ActionView::TestCase tests ActionView::Helpers::CacheHelper @@ -9,10 +9,9 @@ class RelationCacheTest < ActionView::TestCase end def test_cache_relation_other - cache(Project.all){ concat("Hello World") } + cache(Project.all) { concat("Hello World") } assert_equal "Hello World", controller.cache_store.read("views/projects-#{Project.count}/") end def view_cache_dependencies; end - end diff --git a/actionview/test/activerecord/render_partial_with_record_identification_test.rb b/actionview/test/activerecord/render_partial_with_record_identification_test.rb index 9772ebb39e..55886da30f 100644 --- a/actionview/test/activerecord/render_partial_with_record_identification_test.rb +++ b/actionview/test/activerecord/render_partial_with_record_identification_test.rb @@ -1,48 +1,48 @@ -require 'active_record_unit' +require "active_record_unit" class RenderPartialWithRecordIdentificationController < ActionController::Base def render_with_has_many_and_belongs_to_association @developer = Developer.find(1) - render :partial => @developer.projects + render partial: @developer.projects end def render_with_has_many_association @topic = Topic.find(1) - render :partial => @topic.replies + render partial: @topic.replies end def render_with_scope - render :partial => Reply.base + render partial: Reply.base end def render_with_has_many_through_association @developer = Developer.first - render :partial => @developer.topics + render partial: @developer.topics end def render_with_has_one_association @company = Company.find(1) - render :partial => @company.mascot + render partial: @company.mascot end def render_with_belongs_to_association @reply = Reply.find(1) - render :partial => @reply.topic + render partial: @reply.topic end def render_with_record @developer = Developer.first - render :partial => @developer + render partial: @developer end def render_with_record_collection @developers = Developer.all - render :partial => @developers + render partial: @developers end def render_with_record_collection_and_spacer_template @developer = Developer.find(1) - render :partial => @developer.projects, :spacer_template => 'test/partial_only' + render partial: @developer.projects, spacer_template: "test/partial_only" end end @@ -57,27 +57,27 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase def test_rendering_partial_with_has_many_association get :render_with_has_many_association - assert_equal 'Birdman is better!', @response.body + assert_equal "Birdman is better!", @response.body end def test_rendering_partial_with_scope get :render_with_scope - assert_equal 'Birdman is better!Nuh uh!', @response.body + assert_equal "Birdman is better!Nuh uh!", @response.body end def test_render_with_record get :render_with_record - assert_equal 'David', @response.body + assert_equal "David", @response.body end def test_render_with_record_collection get :render_with_record_collection - assert_equal 'DavidJamisfixture_3fixture_4fixture_5fixture_6fixture_7fixture_8fixture_9fixture_10Jamis', @response.body + assert_equal "DavidJamisfixture_3fixture_4fixture_5fixture_6fixture_7fixture_8fixture_9fixture_10Jamis", @response.body end def test_render_with_record_collection_and_spacer_template get :render_with_record_collection_and_spacer_template - assert_equal Developer.find(1).projects.map(&:name).join('only partial'), @response.body + assert_equal Developer.find(1).projects.map(&:name).join("only partial"), @response.body end def test_rendering_partial_with_has_one_association @@ -98,22 +98,22 @@ end module Fun class NestedController < ActionController::Base def render_with_record_in_nested_controller - render :partial => Game.new("Pong") + render partial: Game.new("Pong") end def render_with_record_collection_in_nested_controller - render :partial => [ Game.new("Pong"), Game.new("Tank") ] + render partial: [ Game.new("Pong"), Game.new("Tank") ] end end module Serious class NestedDeeperController < ActionController::Base def render_with_record_in_deeper_nested_controller - render :partial => Game.new("Chess") + render partial: Game.new("Chess") end def render_with_record_collection_in_deeper_nested_controller - render :partial => [ Game.new("Chess"), Game.new("Sudoku"), Game.new("Solitaire") ] + render partial: [ Game.new("Chess"), Game.new("Sudoku"), Game.new("Solitaire") ] end end end diff --git a/actionview/test/fixtures/company.rb b/actionview/test/fixtures/company.rb index f3ac3642fa..9f527acdd8 100644 --- a/actionview/test/fixtures/company.rb +++ b/actionview/test/fixtures/company.rb @@ -4,6 +4,6 @@ class Company < ActiveRecord::Base validates_presence_of :name def validate - errors.add('rating', 'rating should not be 2') if rating == 2 + errors.add("rating", "rating should not be 2") if rating == 2 end end diff --git a/actionview/test/fixtures/developer.rb b/actionview/test/fixtures/developer.rb index 8b3f0a8039..1a686a33ce 100644 --- a/actionview/test/fixtures/developer.rb +++ b/actionview/test/fixtures/developer.rb @@ -1,6 +1,6 @@ class Developer < ActiveRecord::Base has_and_belongs_to_many :projects has_many :replies - has_many :topics, :through => :replies + has_many :topics, through: :replies accepts_nested_attributes_for :projects end diff --git a/actionview/test/fixtures/helpers_missing/invalid_require_helper.rb b/actionview/test/fixtures/helpers_missing/invalid_require_helper.rb index d8801e54d5..6ac6677daa 100644 --- a/actionview/test/fixtures/helpers_missing/invalid_require_helper.rb +++ b/actionview/test/fixtures/helpers_missing/invalid_require_helper.rb @@ -1,5 +1,4 @@ -require 'very_invalid_file_name' +require "very_invalid_file_name" module InvalidRequireHelper end - diff --git a/actionview/test/fixtures/mascot.rb b/actionview/test/fixtures/mascot.rb index f9f1448b8f..1c0bd7c8fd 100644 --- a/actionview/test/fixtures/mascot.rb +++ b/actionview/test/fixtures/mascot.rb @@ -1,3 +1,3 @@ class Mascot < ActiveRecord::Base belongs_to :company -end
\ No newline at end of file +end diff --git a/actionview/test/fixtures/test/_builder_tag_nested_in_content_tag.erb b/actionview/test/fixtures/test/_builder_tag_nested_in_content_tag.erb new file mode 100644 index 0000000000..ddad7ec3ac --- /dev/null +++ b/actionview/test/fixtures/test/_builder_tag_nested_in_content_tag.erb @@ -0,0 +1,3 @@ +<%= tag.p do %> + <%= tag.b 'Hello' %> +<% end %> diff --git a/actionview/test/fixtures/test/render_file_inspect_local_assigns.erb b/actionview/test/fixtures/test/render_file_inspect_local_assigns.erb new file mode 100644 index 0000000000..aea5c351c5 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_inspect_local_assigns.erb @@ -0,0 +1 @@ +<%= local_assigns.inspect.html_safe %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/render_file_unicode_local.erb b/actionview/test/fixtures/test/render_file_unicode_local.erb new file mode 100644 index 0000000000..cbfd040a76 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_unicode_local.erb @@ -0,0 +1 @@ +<%= 🎃 %>
\ No newline at end of file diff --git a/actionview/test/fixtures/test/render_file_with_ruby_keyword_locals.erb b/actionview/test/fixtures/test/render_file_with_ruby_keyword_locals.erb new file mode 100644 index 0000000000..7e3fe6c6d9 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_with_ruby_keyword_locals.erb @@ -0,0 +1 @@ +The class is <%= local_assigns[:class] %>
\ No newline at end of file diff --git a/actionview/test/fixtures/topic.rb b/actionview/test/fixtures/topic.rb index 9fa9746535..48a3dfba88 100644 --- a/actionview/test/fixtures/topic.rb +++ b/actionview/test/fixtures/topic.rb @@ -1,3 +1,3 @@ class Topic < ActiveRecord::Base - has_many :replies, :dependent => :destroy + has_many :replies, dependent: :destroy end diff --git a/actionview/test/lib/controller/fake_models.rb b/actionview/test/lib/controller/fake_models.rb index 65c68fc34a..cc5f5c1d59 100644 --- a/actionview/test/lib/controller/fake_models.rb +++ b/actionview/test/lib/controller/fake_models.rb @@ -108,7 +108,6 @@ class Tag attr_accessor :relevances def relevances_attributes=(attributes); end - end class CommentRelevance @@ -191,7 +190,7 @@ class Plane attr_reader :to_key def model_name - OpenStruct.new param_key: 'airplane' + OpenStruct.new param_key: "airplane" end def save diff --git a/actionview/test/template/active_model_helper_test.rb b/actionview/test/template/active_model_helper_test.rb index 55d62cf692..8b8f686f96 100644 --- a/actionview/test/template/active_model_helper_test.rb +++ b/actionview/test/template/active_model_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ActiveModelHelperTest < ActionView::TestCase tests ActionView::Helpers::ActiveModelHelper @@ -50,28 +50,28 @@ class ActiveModelHelperTest < ActionView::TestCase def test_select_with_errors_and_blank_option expected_dom = %(<div class="field_with_errors"><select name="post[author_name]" id="post_author_name"><option value="">Choose one...</option>\n<option value="a">a</option>\n<option value="b">b</option></select></div>) - assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], :include_blank => 'Choose one...')) - assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], :prompt => 'Choose one...')) + assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], include_blank: "Choose one...")) + assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], prompt: "Choose one...")) end def test_date_select_with_errors assert_dom_equal( %(<div class="field_with_errors"><select id="post_updated_at_1i" name="post[updated_at(1i)]">\n<option selected="selected" value="2004">2004</option>\n<option value="2005">2005</option>\n</select>\n<input id="post_updated_at_2i" name="post[updated_at(2i)]" type="hidden" value="6" />\n<input id="post_updated_at_3i" name="post[updated_at(3i)]" type="hidden" value="1" />\n</div>), - date_select("post", "updated_at", :discard_month => true, :discard_day => true, :start_year => 2004, :end_year => 2005) + date_select("post", "updated_at", discard_month: true, discard_day: true, start_year: 2004, end_year: 2005) ) end def test_datetime_select_with_errors assert_dom_equal( %(<div class="field_with_errors"><input id="post_updated_at_1i" name="post[updated_at(1i)]" type="hidden" value="2004" />\n<input id="post_updated_at_2i" name="post[updated_at(2i)]" type="hidden" value="6" />\n<input id="post_updated_at_3i" name="post[updated_at(3i)]" type="hidden" value="1" />\n<select id="post_updated_at_4i" name="post[updated_at(4i)]">\n<option selected="selected" value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n</select>\n : <select id="post_updated_at_5i" name="post[updated_at(5i)]">\n<option selected="selected" value="00">00</option>\n</select>\n</div>), - datetime_select("post", "updated_at", :discard_year => true, :discard_month => true, :discard_day => true, :minute_step => 60) + datetime_select("post", "updated_at", discard_year: true, discard_month: true, discard_day: true, minute_step: 60) ) end def test_time_select_with_errors assert_dom_equal( %(<div class="field_with_errors"><input id="post_updated_at_1i" name="post[updated_at(1i)]" type="hidden" value="2004" />\n<input id="post_updated_at_2i" name="post[updated_at(2i)]" type="hidden" value="6" />\n<input id="post_updated_at_3i" name="post[updated_at(3i)]" type="hidden" value="15" />\n<select id="post_updated_at_4i" name="post[updated_at(4i)]">\n<option selected="selected" value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n</select>\n : <select id="post_updated_at_5i" name="post[updated_at(5i)]">\n<option selected="selected" value="00">00</option>\n</select>\n</div>), - time_select("post", "updated_at", :minute_step => 60) + time_select("post", "updated_at", minute_step: 60) ) end @@ -95,5 +95,4 @@ class ActiveModelHelperTest < ActionView::TestCase ensure ActionView::Base.field_error_proc = old_proc if old_proc end - end diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb index 8bfd19eb26..3bdab42f7a 100644 --- a/actionview/test/template/asset_tag_helper_test.rb +++ b/actionview/test/template/asset_tag_helper_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/ordered_options' +require "abstract_unit" +require "active_support/ordered_options" class AssetTagHelperTest < ActionView::TestCase tests ActionView::Helpers::AssetTagHelper @@ -13,10 +13,10 @@ class AssetTagHelperTest < ActionView::TestCase @request = Class.new do attr_accessor :script_name - def protocol() 'http://' end + def protocol() "http://" end def ssl?() false end - def host_with_port() 'localhost' end - def base_url() 'http://www.example.com' end + def host_with_port() "localhost" end + def base_url() "http://www.example.com" end end.new @controller.request = @request @@ -238,7 +238,7 @@ class AssetTagHelperTest < ActionView::TestCase VideoLinkToTag = { %(video_tag("xml.ogg")) => %(<video src="/videos/xml.ogg"></video>), %(video_tag("rss.m4v", :autoplay => true, :controls => true)) => %(<video autoplay="autoplay" controls="controls" src="/videos/rss.m4v"></video>), - %(video_tag("rss.m4v", :autobuffer => true)) => %(<video autobuffer="autobuffer" src="/videos/rss.m4v"></video>), + %(video_tag("rss.m4v", :preload => 'none')) => %(<video preload="none" src="/videos/rss.m4v"></video>), %(video_tag("gold.m4v", :size => "160x120")) => %(<video height="120" src="/videos/gold.m4v" width="160"></video>), %(video_tag("gold.m4v", "size" => "320x240")) => %(<video height="240" src="/videos/gold.m4v" width="320"></video>), %(video_tag("trailer.ogg", :poster => "screenshot.png")) => %(<video poster="/images/screenshot.png" src="/videos/trailer.ogg"></video>), @@ -288,7 +288,7 @@ class AssetTagHelperTest < ActionView::TestCase %(audio_tag("//media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="//media.rubyonrails.org/audio/rails_blog_2.mov"></audio>), %(audio_tag("audio.mp3", "audio.ogg")) => %(<audio><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>), %(audio_tag(["audio.mp3", "audio.ogg"])) => %(<audio><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>), - %(audio_tag(["audio.mp3", "audio.ogg"], :autobuffer => true, :controls => true)) => %(<audio autobuffer="autobuffer" controls="controls"><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>) + %(audio_tag(["audio.mp3", "audio.ogg"], :preload => 'none', :controls => true)) => %(<audio preload="none" controls="controls"><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>) } FontPathToTag = { @@ -306,7 +306,7 @@ class AssetTagHelperTest < ActionView::TestCase end def test_autodiscovery_link_tag_with_unknown_type - result = auto_discovery_link_tag(:xml, '/feed.xml', :type => 'application/xml') + result = auto_discovery_link_tag(:xml, "/feed.xml", type: "application/xml") expected = %(<link href="/feed.xml" rel="alternate" title="XML" type="application/xml" />) assert_dom_equal expected, result end @@ -322,18 +322,18 @@ class AssetTagHelperTest < ActionView::TestCase def test_asset_path_tag_to_not_create_duplicate_slashes @controller.config.asset_host = "host/" - assert_dom_equal('http://host/foo', asset_path("foo")) + assert_dom_equal("http://host/foo", asset_path("foo")) - @controller.config.relative_url_root = '/some/root/' - assert_dom_equal('http://host/some/root/foo', asset_path("foo")) + @controller.config.relative_url_root = "/some/root/" + assert_dom_equal("http://host/some/root/foo", asset_path("foo")) end def test_compute_asset_public_path assert_equal "/robots.txt", compute_asset_path("robots.txt") assert_equal "/robots.txt", compute_asset_path("/robots.txt") - assert_equal "/javascripts/foo.js", compute_asset_path("foo.js", :type => :javascript) - assert_equal "/javascripts/foo.js", compute_asset_path("/foo.js", :type => :javascript) - assert_equal "/stylesheets/foo.css", compute_asset_path("foo.css", :type => :stylesheet) + assert_equal "/javascripts/foo.js", compute_asset_path("foo.js", type: :javascript) + assert_equal "/javascripts/foo.js", compute_asset_path("/foo.js", type: :javascript) + assert_equal "/stylesheets/foo.css", compute_asset_path("foo.css", type: :stylesheet) end def test_auto_discovery_link_tag @@ -362,11 +362,11 @@ class AssetTagHelperTest < ActionView::TestCase def test_javascript_include_tag_with_missing_source assert_nothing_raised { - javascript_include_tag('missing_security_guard') + javascript_include_tag("missing_security_guard") } assert_nothing_raised { - javascript_include_tag('http://example.com/css/missing_security_guard') + javascript_include_tag("http://example.com/css/missing_security_guard") } end @@ -376,13 +376,13 @@ class AssetTagHelperTest < ActionView::TestCase def test_javascript_include_tag_relative_protocol @controller.config.asset_host = "assets.example.com" - assert_dom_equal %(<script src="//assets.example.com/javascripts/prototype.js"></script>), javascript_include_tag('prototype', protocol: :relative) + assert_dom_equal %(<script src="//assets.example.com/javascripts/prototype.js"></script>), javascript_include_tag("prototype", protocol: :relative) end def test_javascript_include_tag_default_protocol @controller.config.asset_host = "assets.example.com" @controller.config.default_asset_host_protocol = :relative - assert_dom_equal %(<script src="//assets.example.com/javascripts/prototype.js"></script>), javascript_include_tag('prototype') + assert_dom_equal %(<script src="//assets.example.com/javascripts/prototype.js"></script>), javascript_include_tag("prototype") end def test_stylesheet_path @@ -407,36 +407,36 @@ class AssetTagHelperTest < ActionView::TestCase def test_stylesheet_link_tag_with_missing_source assert_nothing_raised { - stylesheet_link_tag('missing_security_guard') + stylesheet_link_tag("missing_security_guard") } assert_nothing_raised { - stylesheet_link_tag('http://example.com/css/missing_security_guard') + stylesheet_link_tag("http://example.com/css/missing_security_guard") } end def test_stylesheet_link_tag_is_html_safe - assert stylesheet_link_tag('dir/file').html_safe? - assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe? + assert stylesheet_link_tag("dir/file").html_safe? + assert stylesheet_link_tag("dir/other/file", "dir/file2").html_safe? end def test_stylesheet_link_tag_escapes_options - assert_dom_equal %(<link href="/file.css" media="<script>" rel="stylesheet" />), stylesheet_link_tag('/file', :media => '<script>') + assert_dom_equal %(<link href="/file.css" media="<script>" rel="stylesheet" />), stylesheet_link_tag("/file", media: "<script>") end def test_stylesheet_link_tag_should_not_output_the_same_asset_twice - assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington', 'wellington', 'amsterdam') + assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />), stylesheet_link_tag("wellington", "wellington", "amsterdam") end def test_stylesheet_link_tag_with_relative_protocol @controller.config.asset_host = "assets.example.com" - assert_dom_equal %(<link href="//assets.example.com/stylesheets/wellington.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington', protocol: :relative) + assert_dom_equal %(<link href="//assets.example.com/stylesheets/wellington.css" media="screen" rel="stylesheet" />), stylesheet_link_tag("wellington", protocol: :relative) end def test_stylesheet_link_tag_with_default_protocol @controller.config.asset_host = "assets.example.com" @controller.config.default_asset_host_protocol = :relative - assert_dom_equal %(<link href="//assets.example.com/stylesheets/wellington.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington') + assert_dom_equal %(<link href="//assets.example.com/stylesheets/wellington.css" media="screen" rel="stylesheet" />), stylesheet_link_tag("wellington") end def test_image_path @@ -456,12 +456,12 @@ class AssetTagHelperTest < ActionView::TestCase end def test_image_alt - [nil, '/', '/foo/bar/', 'foo/bar/'].each do |prefix| - assert_equal 'Rails', image_alt("#{prefix}rails.png") - assert_equal 'Rails', image_alt("#{prefix}rails-9c0a079bdd7701d7e729bd956823d153.png") - assert_equal 'Rails', image_alt("#{prefix}rails-f56ef62bc41b040664e801a38f068082a75d506d9048307e8096737463503d0b.png") - assert_equal 'Long file name with hyphens', image_alt("#{prefix}long-file-name-with-hyphens.png") - assert_equal 'Long file name with underscores', image_alt("#{prefix}long_file_name_with_underscores.png") + [nil, "/", "/foo/bar/", "foo/bar/"].each do |prefix| + assert_equal "Rails", image_alt("#{prefix}rails.png") + assert_equal "Rails", image_alt("#{prefix}rails-9c0a079bdd7701d7e729bd956823d153.png") + assert_equal "Rails", image_alt("#{prefix}rails-f56ef62bc41b040664e801a38f068082a75d506d9048307e8096737463503d0b.png") + assert_equal "Long file name with hyphens", image_alt("#{prefix}long-file-name-with-hyphens.png") + assert_equal "Long file name with underscores", image_alt("#{prefix}long_file_name_with_underscores.png") end end @@ -470,14 +470,14 @@ class AssetTagHelperTest < ActionView::TestCase end def test_image_tag_does_not_modify_options - options = {:size => '16x10'} - image_tag('icon', options) - assert_equal({:size => '16x10'}, options) + options = { size: "16x10" } + image_tag("icon", options) + assert_equal({ size: "16x10" }, options) end def test_image_tag_raises_an_error_for_competing_size_arguments exception = assert_raise(ArgumentError) do - image_tag("gold.png", :height => "100", :width => "200", :size => "45x70") + image_tag("gold.png", height: "100", width: "200", size: "45x70") end assert_equal("Cannot pass a :size option with a :height or :width option", exception.message) @@ -532,11 +532,11 @@ class AssetTagHelperTest < ActionView::TestCase end def test_video_audio_tag_does_not_modify_options - options = {:autoplay => true} - video_tag('video', options) - assert_equal({:autoplay => true}, options) - audio_tag('audio', options) - assert_equal({:autoplay => true}, options) + options = { autoplay: true } + video_tag("video", options) + assert_equal({ autoplay: true }, options) + audio_tag("audio", options) + assert_equal({ autoplay: true }, options) end def test_image_tag_interpreting_email_cid_correctly @@ -545,11 +545,11 @@ class AssetTagHelperTest < ActionView::TestCase end def test_image_tag_interpreting_email_adding_optional_alt_tag - assert_equal '<img alt="Image" src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid", :alt => "Image") + assert_equal '<img alt="Image" src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid", alt: "Image") end def test_should_not_modify_source_string - source = '/images/rails.png' + source = "/images/rails.png" copy = source.dup image_tag(source) assert_equal copy, source @@ -557,13 +557,13 @@ class AssetTagHelperTest < ActionView::TestCase class PlaceholderImage def blank?; true; end - def to_s; 'no-image-yet.png'; end + def to_s; "no-image-yet.png"; end end def test_image_tag_with_blank_placeholder assert_equal '<img alt="" src="/images/no-image-yet.png" />', image_tag(PlaceholderImage.new, alt: "") end def test_image_path_with_blank_placeholder - assert_equal '/images/no-image-yet.png', image_path(PlaceholderImage.new) + assert_equal "/images/no-image-yet.png", image_path(PlaceholderImage.new) end def test_image_path_with_asset_host_proc_returning_nil @@ -634,11 +634,11 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase end def test_should_current_request_host_is_always_returned_for_request - assert_equal "gopher://www.example.com", compute_asset_host("foo", :protocol => :request) + assert_equal "gopher://www.example.com", compute_asset_host("foo", protocol: :request) end def test_should_return_custom_host_if_passed_in_options - assert_equal "http://custom.example.com", compute_asset_host("foo", :host => "http://custom.example.com") + assert_equal "http://custom.example.com", compute_asset_host("foo", host: "http://custom.example.com") end def test_should_ignore_relative_root_path_on_complete_url @@ -652,12 +652,12 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase def test_should_return_relative_asset_host @controller.config.asset_host = "assets.example.com" - assert_equal "//assets.example.com", compute_asset_host("foo", :protocol => :relative) + assert_equal "//assets.example.com", compute_asset_host("foo", protocol: :relative) end def test_should_return_custom_protocol_asset_host @controller.config.asset_host = "assets.example.com" - assert_equal "ftp://assets.example.com", compute_asset_host("foo", :protocol => "ftp") + assert_equal "ftp://assets.example.com", compute_asset_host("foo", protocol: "ftp") end def test_should_compute_proper_path_with_asset_host @@ -708,26 +708,26 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase end def test_should_wildcard_asset_host - @controller.config.asset_host = 'http://a%d.example.com' + @controller.config.asset_host = "http://a%d.example.com" assert_match(%r(http://a[0123].example.com), compute_asset_host("foo")) end def test_should_wildcard_asset_host_between_zero_and_four - @controller.config.asset_host = 'http://a%d.example.com' - assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path('xml.png')) - assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_url('xml.png')) + @controller.config.asset_host = "http://a%d.example.com" + assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path("xml.png")) + assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_url("xml.png")) end def test_asset_host_without_protocol_should_be_protocol_relative - @controller.config.asset_host = 'a.example.com' - assert_equal 'gopher://a.example.com/collaboration/hieraki/images/xml.png', image_path('xml.png') - assert_equal 'gopher://a.example.com/collaboration/hieraki/images/xml.png', image_url('xml.png') + @controller.config.asset_host = "a.example.com" + assert_equal "gopher://a.example.com/collaboration/hieraki/images/xml.png", image_path("xml.png") + assert_equal "gopher://a.example.com/collaboration/hieraki/images/xml.png", image_url("xml.png") end def test_asset_host_without_protocol_should_be_protocol_relative_even_if_path_present - @controller.config.asset_host = 'a.example.com/files/go/here' - assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png') - assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_url('xml.png') + @controller.config.asset_host = "a.example.com/files/go/here" + assert_equal "gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png", image_path("xml.png") + assert_equal "gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png", image_url("xml.png") end def test_assert_css_and_js_of_the_same_name_return_correct_extension @@ -747,10 +747,10 @@ class AssetUrlHelperControllerTest < ActionView::TestCase @request = Class.new do attr_accessor :script_name - def protocol() 'http://' end + def protocol() "http://" end def ssl?() false end - def host_with_port() 'www.example.com' end - def base_url() 'http://www.example.com' end + def host_with_port() "www.example.com" end + def base_url() "http://www.example.com" end end.new @controller.request = @request @@ -813,6 +813,6 @@ class AssetUrlHelperEmptyModuleTest < ActionView::TestCase end assert @module.config.asset_host - assert_equal "http://custom.example.com/foo", @module.asset_url("foo", :host => "http://custom.example.com") + assert_equal "http://custom.example.com/foo", @module.asset_url("foo", host: "http://custom.example.com") end end diff --git a/actionview/test/template/atom_feed_helper_test.rb b/actionview/test/template/atom_feed_helper_test.rb index 591cd71404..e9a923dd72 100644 --- a/actionview/test/template/atom_feed_helper_test.rb +++ b/actionview/test/template/atom_feed_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class Scroll < Struct.new(:id, :to_param, :title, :body, :updated_at, :created_at) extend ActiveModel::Naming @@ -28,7 +28,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["entry_options"] = <<-EOT + FEEDS["entry_options"] = <<-EOT atom_feed do |feed| feed.title("My great blog!") feed.updated(@scrolls.first.created_at) @@ -45,7 +45,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["entry_type_options"] = <<-EOT + FEEDS["entry_type_options"] = <<-EOT atom_feed(:schema_date => '2008') do |feed| feed.title("My great blog!") feed.updated(@scrolls.first.created_at) @@ -62,7 +62,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["entry_url_false_option"] = <<-EOT + FEEDS["entry_url_false_option"] = <<-EOT atom_feed do |feed| feed.title("My great blog!") feed.updated(@scrolls.first.created_at) @@ -79,7 +79,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["xml_block"] = <<-EOT + FEEDS["xml_block"] = <<-EOT atom_feed do |feed| feed.title("My great blog!") feed.updated(@scrolls.first.created_at) @@ -96,7 +96,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["feed_with_atomPub_namespace"] = <<-EOT + FEEDS["feed_with_atomPub_namespace"] = <<-EOT atom_feed({'xmlns:app' => 'http://www.w3.org/2007/app', 'xmlns:openSearch' => 'http://a9.com/-/spec/opensearch/1.1/'}) do |feed| feed.title("My great blog!") @@ -115,7 +115,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["feed_with_overridden_ids"] = <<-EOT + FEEDS["feed_with_overridden_ids"] = <<-EOT atom_feed({:id => 'tag:test.rubyonrails.org,2008:test/'}) do |feed| feed.title("My great blog!") feed.updated(@scrolls.first.created_at) @@ -169,7 +169,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["feed_with_xhtml_content"] = <<-'EOT' + FEEDS["feed_with_xhtml_content"] = <<-'EOT' atom_feed do |feed| feed.title("My great blog!") feed.updated(@scrolls.first.created_at) @@ -191,7 +191,7 @@ class ScrollsController < ActionController::Base end end EOT - FEEDS["provide_builder"] = <<-'EOT' + FEEDS["provide_builder"] = <<-'EOT' # we pass in the new_xml to the helper so it doesn't # call anything on the original builder new_xml = Builder::XmlMarkup.new(:target=>'') @@ -217,7 +217,7 @@ class ScrollsController < ActionController::Base Scroll.new(2, "2", "Hello Two", "Something Boring", Time.utc(2007, 12, 12, 15)), ] - render :inline => FEEDS[params[:id]], :type => :builder + render inline: FEEDS[params[:id]], type: :builder end end @@ -278,22 +278,22 @@ class AtomFeedTest < ActionController::TestCase def test_feed_id_should_be_a_valid_tag with_restful_routing(:scrolls) do get :index, params: { id: "defaults" } - assert_select "id", :text => "tag:www.nextangle.com,2008:/scrolls?id=defaults" + assert_select "id", text: "tag:www.nextangle.com,2008:/scrolls?id=defaults" end end def test_entry_id_should_be_a_valid_tag with_restful_routing(:scrolls) do get :index, params: { id: "defaults" } - assert_select "entry id", :text => "tag:www.nextangle.com,2008:Scroll/1" - assert_select "entry id", :text => "tag:www.nextangle.com,2008:Scroll/2" + assert_select "entry id", text: "tag:www.nextangle.com,2008:Scroll/1" + assert_select "entry id", text: "tag:www.nextangle.com,2008:Scroll/2" end end def test_feed_should_allow_nested_xml_blocks with_restful_routing(:scrolls) do get :index, params: { id: "xml_block" } - assert_select "author name", :text => "DHH" + assert_select "author name", text: "DHH" end end @@ -309,15 +309,15 @@ class AtomFeedTest < ActionController::TestCase def test_feed_should_allow_overriding_ids with_restful_routing(:scrolls) do get :index, params: { id: "feed_with_overridden_ids" } - assert_select "id", :text => "tag:test.rubyonrails.org,2008:test/" - assert_select "entry id", :text => "tag:test.rubyonrails.org,2008:1" - assert_select "entry id", :text => "tag:test.rubyonrails.org,2008:2" + assert_select "id", text: "tag:test.rubyonrails.org,2008:test/" + assert_select "entry id", text: "tag:test.rubyonrails.org,2008:1" + assert_select "entry id", text: "tag:test.rubyonrails.org,2008:2" end end def test_feed_xml_processing_instructions with_restful_routing(:scrolls) do - get :index, params: { id: 'feed_with_xml_processing_instructions' } + get :index, params: { id: "feed_with_xml_processing_instructions" } assert_match %r{<\?xml-stylesheet [^\?]*type="text/css"}, @response.body assert_match %r{<\?xml-stylesheet [^\?]*href="t.css"}, @response.body end @@ -325,7 +325,7 @@ class AtomFeedTest < ActionController::TestCase def test_feed_xml_processing_instructions_duplicate_targets with_restful_routing(:scrolls) do - get :index, params: { id: 'feed_with_xml_processing_instructions_duplicate_targets' } + get :index, params: { id: "feed_with_xml_processing_instructions_duplicate_targets" } assert_match %r{<\?target1 (a="1" b="2"|b="2" a="1")\?>}, @response.body assert_match %r{<\?target1 (c="3" d="4"|d="4" c="3")\?>}, @response.body end @@ -335,28 +335,28 @@ class AtomFeedTest < ActionController::TestCase with_restful_routing(:scrolls) do get :index, params: { id: "feed_with_xhtml_content" } assert_match %r{xmlns="http://www.w3.org/1999/xhtml"}, @response.body - assert_select "summary", :text => /Something Boring/ - assert_select "summary", :text => /after 2/ + assert_select "summary", text: /Something Boring/ + assert_select "summary", text: /after 2/ end end def test_feed_entry_type_option_default_to_text_html with_restful_routing(:scrolls) do - get :index, params: { id: 'defaults' } + get :index, params: { id: "defaults" } assert_select "entry link[rel=alternate][type=\"text/html\"]" end end def test_feed_entry_type_option_specified with_restful_routing(:scrolls) do - get :index, params: { id: 'entry_type_options' } + get :index, params: { id: "entry_type_options" } assert_select "entry link[rel=alternate][type=\"text/xml\"]" end end def test_feed_entry_url_false_option_adds_no_link with_restful_routing(:scrolls) do - get :index, params: { id: 'entry_url_false_option' } + get :index, params: { id: "entry_url_false_option" } assert_select "entry link", false end end diff --git a/actionview/test/template/capture_helper_test.rb b/actionview/test/template/capture_helper_test.rb index ffaf773c53..54bf9b4c33 100644 --- a/actionview/test/template/capture_helper_test.rb +++ b/actionview/test/template/capture_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class CaptureHelperTest < ActionView::TestCase def setup @@ -10,18 +10,18 @@ class CaptureHelperTest < ActionView::TestCase def test_capture_captures_the_temporary_output_buffer_in_its_block assert_nil @av.output_buffer string = @av.capture do - @av.output_buffer << 'foo' - @av.output_buffer << 'bar' + @av.output_buffer << "foo" + @av.output_buffer << "bar" end assert_nil @av.output_buffer - assert_equal 'foobar', string + assert_equal "foobar", string end def test_capture_captures_the_value_returned_by_the_block_if_the_temporary_buffer_is_blank - string = @av.capture('foo', 'bar') do |a, b| + string = @av.capture("foo", "bar") do |a, b| a + b end - assert_equal 'foobar', string + assert_equal "foobar", string end def test_capture_returns_nil_if_the_returned_value_is_not_a_string @@ -29,112 +29,112 @@ class CaptureHelperTest < ActionView::TestCase end def test_capture_escapes_html - string = @av.capture { '<em>bar</em>' } - assert_equal '<em>bar</em>', string + string = @av.capture { "<em>bar</em>" } + assert_equal "<em>bar</em>", string end def test_capture_doesnt_escape_twice - string = @av.capture { raw('<em>bar</em>') } - assert_equal '<em>bar</em>', string + string = @av.capture { raw("<em>bar</em>") } + assert_equal "<em>bar</em>", string end def test_capture_used_for_read content_for :foo, "foo" assert_equal "foo", content_for(:foo) - content_for(:bar){ "bar" } + content_for(:bar) { "bar" } assert_equal "bar", content_for(:bar) end def test_content_for_with_multiple_calls assert ! content_for?(:title) - content_for :title, 'foo' - content_for :title, 'bar' - assert_equal 'foobar', content_for(:title) + content_for :title, "foo" + content_for :title, "bar" + assert_equal "foobar", content_for(:title) end def test_content_for_with_multiple_calls_and_flush assert ! content_for?(:title) - content_for :title, 'foo' - content_for :title, 'bar', flush: true - assert_equal 'bar', content_for(:title) + content_for :title, "foo" + content_for :title, "bar", flush: true + assert_equal "bar", content_for(:title) end def test_content_for_with_block assert ! content_for?(:title) content_for :title do - output_buffer << 'foo' - output_buffer << 'bar' + output_buffer << "foo" + output_buffer << "bar" nil end - assert_equal 'foobar', content_for(:title) + assert_equal "foobar", content_for(:title) end def test_content_for_with_block_and_multiple_calls_with_flush assert ! content_for?(:title) content_for :title do - 'foo' + "foo" end content_for :title, flush: true do - 'bar' + "bar" end - assert_equal 'bar', content_for(:title) + assert_equal "bar", content_for(:title) end def test_content_for_with_block_and_multiple_calls_with_flush_nil_content assert ! content_for?(:title) content_for :title do - 'foo' + "foo" end content_for :title, nil, flush: true do - 'bar' + "bar" end - assert_equal 'bar', content_for(:title) + assert_equal "bar", content_for(:title) end def test_content_for_with_block_and_multiple_calls_without_flush assert ! content_for?(:title) content_for :title do - 'foo' + "foo" end content_for :title, flush: false do - 'bar' + "bar" end - assert_equal 'foobar', content_for(:title) + assert_equal "foobar", content_for(:title) end def test_content_for_with_whitespace_block assert ! content_for?(:title) - content_for :title, 'foo' + content_for :title, "foo" content_for :title do output_buffer << " \n " nil end - content_for :title, 'bar' - assert_equal 'foobar', content_for(:title) + content_for :title, "bar" + assert_equal "foobar", content_for(:title) end def test_content_for_with_whitespace_block_and_flush assert ! content_for?(:title) - content_for :title, 'foo' + content_for :title, "foo" content_for :title, flush: true do output_buffer << " \n " nil end - content_for :title, 'bar', flush: true - assert_equal 'bar', content_for(:title) + content_for :title, "bar", flush: true + assert_equal "bar", content_for(:title) end def test_content_for_returns_nil_when_writing assert ! content_for?(:title) - assert_equal nil, content_for(:title, 'foo') - assert_equal nil, content_for(:title) { output_buffer << 'bar'; nil } + assert_equal nil, content_for(:title, "foo") + assert_equal nil, content_for(:title) { output_buffer << "bar"; nil } assert_equal nil, content_for(:title) { output_buffer << " \n "; nil } - assert_equal 'foobar', content_for(:title) - assert_equal nil, content_for(:title, 'foo', flush: true) - assert_equal nil, content_for(:title, flush: true) { output_buffer << 'bar'; nil } + assert_equal "foobar", content_for(:title) + assert_equal nil, content_for(:title, "foo", flush: true) + assert_equal nil, content_for(:title, flush: true) { output_buffer << "bar"; nil } assert_equal nil, content_for(:title, flush: true) { output_buffer << " \n "; nil } - assert_equal 'bar', content_for(:title) + assert_equal "bar", content_for(:title) end def test_content_for_returns_nil_when_content_missing @@ -143,7 +143,7 @@ class CaptureHelperTest < ActionView::TestCase def test_content_for_question_mark assert ! content_for?(:title) - content_for :title, 'title' + content_for :title, "title" assert content_for?(:title) assert ! content_for?(:something_else) end @@ -151,12 +151,12 @@ class CaptureHelperTest < ActionView::TestCase def test_content_for_should_be_html_safe_after_flush_empty assert ! content_for?(:title) content_for :title do - content_tag(:p, 'title') + content_tag(:p, "title") end assert content_for(:title).html_safe? content_for :title, "", flush: true content_for(:title) do - content_tag(:p, 'title') + content_tag(:p, "title") end assert content_for(:title).html_safe? end @@ -178,19 +178,19 @@ class CaptureHelperTest < ActionView::TestCase def test_with_output_buffer_swaps_the_output_buffer_given_no_argument assert_nil @av.output_buffer buffer = @av.with_output_buffer do - @av.output_buffer << '.' + @av.output_buffer << "." end - assert_equal '.', buffer + assert_equal ".", buffer assert_nil @av.output_buffer end def test_with_output_buffer_swaps_the_output_buffer_with_an_argument assert_nil @av.output_buffer - buffer = ActionView::OutputBuffer.new('.') + buffer = ActionView::OutputBuffer.new(".") @av.with_output_buffer(buffer) do - @av.output_buffer << '.' + @av.output_buffer << "." end - assert_equal '..', buffer + assert_equal "..", buffer assert_nil @av.output_buffer end @@ -198,7 +198,7 @@ class CaptureHelperTest < ActionView::TestCase buffer = ActionView::OutputBuffer.new @av.output_buffer = buffer @av.with_output_buffer do - @av.output_buffer << '.' + @av.output_buffer << "." end assert buffer.equal?(@av.output_buffer) end diff --git a/actionview/test/template/compiled_templates_test.rb b/actionview/test/template/compiled_templates_test.rb index f6c1283b92..3ecac46d34 100644 --- a/actionview/test/template/compiled_templates_test.rb +++ b/actionview/test/template/compiled_templates_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class CompiledTemplatesTest < ActiveSupport::TestCase teardown do @@ -6,28 +6,47 @@ class CompiledTemplatesTest < ActiveSupport::TestCase end def test_template_with_nil_erb_return - assert_equal "This is nil: \n", render(:template => "test/nil_return") + assert_equal "This is nil: \n", render(template: "test/nil_return") + end + + def test_template_with_ruby_keyword_locals + assert_equal "The class is foo", + render(file: "test/render_file_with_ruby_keyword_locals", locals: { class: "foo" }) + end + + def test_template_with_invalid_identifier_locals + locals = { + foo: "bar", + Foo: "bar", + "d-a-s-h-e-s": "", + "white space": "", + } + assert_equal locals.inspect, render(file: "test/render_file_inspect_local_assigns", locals: locals) + end + + def test_template_with_unicode_identifier + assert_equal "🎂", render(file: "test/render_file_unicode_local", locals: { 🎃: "🎂" }) end def test_template_gets_recompiled_when_using_different_keys_in_local_assigns - assert_equal "one", render(:file => "test/render_file_with_locals_and_default") - assert_equal "two", render(:file => "test/render_file_with_locals_and_default", :locals => { :secret => "two" }) + assert_equal "one", render(file: "test/render_file_with_locals_and_default") + assert_equal "two", render(file: "test/render_file_with_locals_and_default", locals: { secret: "two" }) end def test_template_changes_are_not_reflected_with_cached_templates - assert_equal "Hello world!", render(:file => "test/hello_world") + assert_equal "Hello world!", render(file: "test/hello_world") modify_template "test/hello_world.erb", "Goodbye world!" do - assert_equal "Hello world!", render(:file => "test/hello_world") + assert_equal "Hello world!", render(file: "test/hello_world") end - assert_equal "Hello world!", render(:file => "test/hello_world") + assert_equal "Hello world!", render(file: "test/hello_world") end def test_template_changes_are_reflected_with_uncached_templates - assert_equal "Hello world!", render_without_cache(:file => "test/hello_world") + assert_equal "Hello world!", render_without_cache(file: "test/hello_world") modify_template "test/hello_world.erb", "Goodbye world!" do - assert_equal "Goodbye world!", render_without_cache(:file => "test/hello_world") + assert_equal "Goodbye world!", render_without_cache(file: "test/hello_world") end - assert_equal "Hello world!", render_without_cache(:file => "test/hello_world") + assert_equal "Hello world!", render_without_cache(file: "test/hello_world") end private diff --git a/actionview/test/template/controller_helper_test.rb b/actionview/test/template/controller_helper_test.rb index b5e94ea4f1..8dd0cedb75 100644 --- a/actionview/test/template/controller_helper_test.rb +++ b/actionview/test/template/controller_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ControllerHelperTest < ActionView::TestCase tests ActionView::Helpers::ControllerHelper @@ -9,13 +9,13 @@ class ControllerHelperTest < ActionView::TestCase @controller = OpenStruct.new(default_form_builder: SpecializedFormBuilder) assign_controller(@controller) - assert_equal SpecializedFormBuilder, self.default_form_builder + assert_equal SpecializedFormBuilder, default_form_builder end def test_assign_controller_skips_default_form_builder @controller = OpenStruct.new assign_controller(@controller) - assert_nil self.default_form_builder + assert_nil default_form_builder end end diff --git a/actionview/test/template/date_helper_i18n_test.rb b/actionview/test/template/date_helper_i18n_test.rb index 52aef56a61..207c8a683e 100644 --- a/actionview/test/template/date_helper_i18n_test.rb +++ b/actionview/test/template/date_helper_i18n_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase include ActionView::Helpers::DateHelper @@ -12,24 +12,24 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase def test_distance_of_time_in_words_calls_i18n { # with include_seconds - [2.seconds, { :include_seconds => true }] => [:'less_than_x_seconds', 5], - [9.seconds, { :include_seconds => true }] => [:'less_than_x_seconds', 10], - [19.seconds, { :include_seconds => true }] => [:'less_than_x_seconds', 20], - [30.seconds, { :include_seconds => true }] => [:'half_a_minute', nil], - [59.seconds, { :include_seconds => true }] => [:'less_than_x_minutes', 1], - [60.seconds, { :include_seconds => true }] => [:'x_minutes', 1], + [2.seconds, { include_seconds: true }] => [:'less_than_x_seconds', 5], + [9.seconds, { include_seconds: true }] => [:'less_than_x_seconds', 10], + [19.seconds, { include_seconds: true }] => [:'less_than_x_seconds', 20], + [30.seconds, { include_seconds: true }] => [:'half_a_minute', nil], + [59.seconds, { include_seconds: true }] => [:'less_than_x_minutes', 1], + [60.seconds, { include_seconds: true }] => [:'x_minutes', 1], # without include_seconds - [29.seconds, { :include_seconds => false }] => [:'less_than_x_minutes', 1], - [60.seconds, { :include_seconds => false }] => [:'x_minutes', 1], - [44.minutes, { :include_seconds => false }] => [:'x_minutes', 44], - [61.minutes, { :include_seconds => false }] => [:'about_x_hours', 1], - [24.hours, { :include_seconds => false }] => [:'x_days', 1], - [30.days, { :include_seconds => false }] => [:'about_x_months', 1], - [60.days, { :include_seconds => false }] => [:'x_months', 2], - [1.year, { :include_seconds => false }] => [:'about_x_years', 1], - [3.years + 6.months, { :include_seconds => false }] => [:'over_x_years', 3], - [3.years + 10.months, { :include_seconds => false }] => [:'almost_x_years', 4] + [29.seconds, { include_seconds: false }] => [:'less_than_x_minutes', 1], + [60.seconds, { include_seconds: false }] => [:'x_minutes', 1], + [44.minutes, { include_seconds: false }] => [:'x_minutes', 44], + [61.minutes, { include_seconds: false }] => [:'about_x_hours', 1], + [24.hours, { include_seconds: false }] => [:'x_days', 1], + [30.days, { include_seconds: false }] => [:'about_x_months', 1], + [60.days, { include_seconds: false }] => [:'x_months', 2], + [1.year, { include_seconds: false }] => [:'about_x_years', 1], + [3.years + 6.months, { include_seconds: false }] => [:'over_x_years', 3], + [3.years + 10.months, { include_seconds: false }] => [:'almost_x_years', 4] }.each do |passed, expected| assert_distance_of_time_in_words_translates_key passed, expected @@ -46,30 +46,30 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase end def test_time_ago_in_words_passes_locale - assert_called_with(I18n, :t, [:less_than_x_minutes, :scope => :'datetime.distance_in_words', :count => 1, :locale => 'ru']) do - time_ago_in_words(15.seconds.ago, :locale => 'ru') + assert_called_with(I18n, :t, [:less_than_x_minutes, scope: :'datetime.distance_in_words', count: 1, locale: "ru"]) do + time_ago_in_words(15.seconds.ago, locale: "ru") end end def test_distance_of_time_pluralizations - { [:'less_than_x_seconds', 1] => 'less than 1 second', - [:'less_than_x_seconds', 2] => 'less than 2 seconds', - [:'less_than_x_minutes', 1] => 'less than a minute', - [:'less_than_x_minutes', 2] => 'less than 2 minutes', - [:'x_minutes', 1] => '1 minute', - [:'x_minutes', 2] => '2 minutes', - [:'about_x_hours', 1] => 'about 1 hour', - [:'about_x_hours', 2] => 'about 2 hours', - [:'x_days', 1] => '1 day', - [:'x_days', 2] => '2 days', - [:'about_x_years', 1] => 'about 1 year', - [:'about_x_years', 2] => 'about 2 years', - [:'over_x_years', 1] => 'over 1 year', - [:'over_x_years', 2] => 'over 2 years' + { [:'less_than_x_seconds', 1] => "less than 1 second", + [:'less_than_x_seconds', 2] => "less than 2 seconds", + [:'less_than_x_minutes', 1] => "less than a minute", + [:'less_than_x_minutes', 2] => "less than 2 minutes", + [:'x_minutes', 1] => "1 minute", + [:'x_minutes', 2] => "2 minutes", + [:'about_x_hours', 1] => "about 1 hour", + [:'about_x_hours', 2] => "about 2 hours", + [:'x_days', 1] => "1 day", + [:'x_days', 2] => "2 days", + [:'about_x_years', 1] => "about 1 year", + [:'about_x_years', 2] => "about 2 years", + [:'over_x_years', 1] => "over 1 year", + [:'over_x_years', 2] => "over 2 years" }.each do |args, expected| key, count = *args - assert_equal expected, I18n.t(key, :count => count, :scope => 'datetime.distance_in_words') + assert_equal expected, I18n.t(key, count: count, scope: "datetime.distance_in_words") end end @@ -78,11 +78,11 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase key, count = *expected to = @from + diff - options = { locale: 'en', scope: :'datetime.distance_in_words' }.merge!(expected_options) + options = { locale: "en", scope: :'datetime.distance_in_words' }.merge!(expected_options) options[:count] = count if count assert_called_with(I18n, :t, [key, options]) do - distance_of_time_in_words(@from, to, passed_options.merge(locale: 'en')) + distance_of_time_in_words(@from, to, passed_options.merge(locale: "en")) end end end @@ -95,28 +95,28 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase def test_select_month_given_use_month_names_option_does_not_translate_monthnames assert_not_called(I18n, :translate) do - select_month(8, :locale => 'en', :use_month_names => Date::MONTHNAMES) + select_month(8, locale: "en", use_month_names: Date::MONTHNAMES) end end def test_select_month_translates_monthnames - assert_called_with(I18n, :translate, [:'date.month_names', :locale => 'en'], returns: Date::MONTHNAMES) do - select_month(8, :locale => 'en') + assert_called_with(I18n, :translate, [:'date.month_names', locale: "en"], returns: Date::MONTHNAMES) do + select_month(8, locale: "en") end end def test_select_month_given_use_short_month_option_translates_abbr_monthnames - assert_called_with(I18n, :translate, [:'date.abbr_month_names', :locale => 'en'], returns: Date::ABBR_MONTHNAMES) do - select_month(8, :locale => 'en', :use_short_month => true) + assert_called_with(I18n, :translate, [:'date.abbr_month_names', locale: "en"], returns: Date::ABBR_MONTHNAMES) do + select_month(8, locale: "en", use_short_month: true) end end def test_date_or_time_select_translates_prompts - prompt_defaults = {:year => 'Year', :month => 'Month', :day => 'Day', :hour => 'Hour', :minute => 'Minute', :second => 'Seconds'} - defaults = {[:'date.order', :locale => 'en', :default => []] => %w(year month day)} + prompt_defaults = { year: "Year", month: "Month", day: "Day", hour: "Hour", minute: "Minute", second: "Seconds" } + defaults = { [:'date.order', locale: "en", default: []] => %w(year month day) } prompt_defaults.each do |key, prompt| - defaults[[('datetime.prompts.' + key.to_s).to_sym, :locale => 'en']] = prompt + defaults[[("datetime.prompts." + key.to_s).to_sym, locale: "en"]] = prompt end prompts_check = -> (prompt, x) do @@ -129,7 +129,7 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase end I18n.stub(:translate, prompts_check) do - datetime_select('post', 'updated_at', :locale => 'en', :include_seconds => true, :prompt => true, :use_month_names => Date::MONTHNAMES) + datetime_select("post", "updated_at", locale: "en", include_seconds: true, prompt: true, use_month_names: Date::MONTHNAMES) end assert_equal defaults.count, @prompt_called end @@ -138,27 +138,27 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase def test_date_or_time_select_given_an_order_options_does_not_translate_order assert_not_called(I18n, :translate) do - datetime_select('post', 'updated_at', :order => [:year, :month, :day], :locale => 'en', :use_month_names => Date::MONTHNAMES) + datetime_select("post", "updated_at", order: [:year, :month, :day], locale: "en", use_month_names: Date::MONTHNAMES) end end def test_date_or_time_select_given_no_order_options_translates_order - assert_called_with(I18n, :translate, [ [:'date.order', :locale => 'en', :default => []], [:"date.month_names", {:locale=>"en"}] ], returns: %w(year month day)) do - datetime_select('post', 'updated_at', :locale => 'en') + assert_called_with(I18n, :translate, [ [:'date.order', locale: "en", default: []], [:"date.month_names", { locale: "en" }] ], returns: %w(year month day)) do + datetime_select("post", "updated_at", locale: "en") end end def test_date_or_time_select_given_invalid_order - assert_called_with(I18n, :translate, [:'date.order', :locale => 'en', :default => []], returns: %w(invalid month day)) do + assert_called_with(I18n, :translate, [:'date.order', locale: "en", default: []], returns: %w(invalid month day)) do assert_raise StandardError do - datetime_select('post', 'updated_at', :locale => 'en') + datetime_select("post", "updated_at", locale: "en") end end end def test_date_or_time_select_given_symbol_keys - assert_called_with(I18n, :translate, [ [:'date.order', :locale => 'en', :default => []], [:"date.month_names", {:locale=>"en"}] ], returns: [:year, :month, :day]) do - datetime_select('post', 'updated_at', :locale => 'en') + assert_called_with(I18n, :translate, [ [:'date.order', locale: "en", default: []], [:"date.month_names", { locale: "en" }] ], returns: [:year, :month, :day]) do + datetime_select("post", "updated_at", locale: "en") end end end diff --git a/actionview/test/template/date_helper_test.rb b/actionview/test/template/date_helper_test.rb index e67d5d0e8c..44e5a8c346 100644 --- a/actionview/test/template/date_helper_test.rb +++ b/actionview/test/template/date_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class DateHelperTest < ActionView::TestCase tests ActionView::Helpers::DateHelper @@ -13,7 +13,7 @@ class DateHelperTest < ActionView::TestCase 123 end def to_param - '123' + "123" end end end @@ -22,32 +22,32 @@ class DateHelperTest < ActionView::TestCase to ||= from # 0..1 minute with :include_seconds => true - assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 0.seconds, :include_seconds => true) - assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 4.seconds, :include_seconds => true) - assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 5.seconds, :include_seconds => true) - assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 9.seconds, :include_seconds => true) - assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 10.seconds, :include_seconds => true) - assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 19.seconds, :include_seconds => true) - assert_equal "half a minute", distance_of_time_in_words(from, to + 20.seconds, :include_seconds => true) - assert_equal "half a minute", distance_of_time_in_words(from, to + 39.seconds, :include_seconds => true) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 40.seconds, :include_seconds => true) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 59.seconds, :include_seconds => true) - assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, :include_seconds => true) - assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, :include_seconds => true) + assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 0.seconds, include_seconds: true) + assert_equal "less than 5 seconds", distance_of_time_in_words(from, to + 4.seconds, include_seconds: true) + assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 5.seconds, include_seconds: true) + assert_equal "less than 10 seconds", distance_of_time_in_words(from, to + 9.seconds, include_seconds: true) + assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 10.seconds, include_seconds: true) + assert_equal "less than 20 seconds", distance_of_time_in_words(from, to + 19.seconds, include_seconds: true) + assert_equal "half a minute", distance_of_time_in_words(from, to + 20.seconds, include_seconds: true) + assert_equal "half a minute", distance_of_time_in_words(from, to + 39.seconds, include_seconds: true) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 40.seconds, include_seconds: true) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 59.seconds, include_seconds: true) + assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, include_seconds: true) + assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, include_seconds: true) # 0..1 minute with :include_seconds => false - assert_equal "less than a minute", distance_of_time_in_words(from, to + 0.seconds, :include_seconds => false) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 4.seconds, :include_seconds => false) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 5.seconds, :include_seconds => false) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 9.seconds, :include_seconds => false) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 10.seconds, :include_seconds => false) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 19.seconds, :include_seconds => false) - assert_equal "less than a minute", distance_of_time_in_words(from, to + 20.seconds, :include_seconds => false) - assert_equal "1 minute", distance_of_time_in_words(from, to + 39.seconds, :include_seconds => false) - assert_equal "1 minute", distance_of_time_in_words(from, to + 40.seconds, :include_seconds => false) - assert_equal "1 minute", distance_of_time_in_words(from, to + 59.seconds, :include_seconds => false) - assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, :include_seconds => false) - assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, :include_seconds => false) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 0.seconds, include_seconds: false) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 4.seconds, include_seconds: false) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 5.seconds, include_seconds: false) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 9.seconds, include_seconds: false) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 10.seconds, include_seconds: false) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 19.seconds, include_seconds: false) + assert_equal "less than a minute", distance_of_time_in_words(from, to + 20.seconds, include_seconds: false) + assert_equal "1 minute", distance_of_time_in_words(from, to + 39.seconds, include_seconds: false) + assert_equal "1 minute", distance_of_time_in_words(from, to + 40.seconds, include_seconds: false) + assert_equal "1 minute", distance_of_time_in_words(from, to + 59.seconds, include_seconds: false) + assert_equal "1 minute", distance_of_time_in_words(from, to + 60.seconds, include_seconds: false) + assert_equal "1 minute", distance_of_time_in_words(from, to + 89.seconds, include_seconds: false) # Note that we are including a 30-second boundary around the interval we # want to test. For instance, "1 minute" is actually 30s to 1m29s. The @@ -119,8 +119,8 @@ class DateHelperTest < ActionView::TestCase # test to < from assert_equal "about 4 hours", distance_of_time_in_words(from + 4.hours, to) - assert_equal "less than 20 seconds", distance_of_time_in_words(from + 19.seconds, to, :include_seconds => true) - assert_equal "less than a minute", distance_of_time_in_words(from + 19.seconds, to, :include_seconds => false) + assert_equal "less than 20 seconds", distance_of_time_in_words(from + 19.seconds, to, include_seconds: true) + assert_equal "less than a minute", distance_of_time_in_words(from + 19.seconds, to, include_seconds: false) end def test_distance_in_words @@ -136,21 +136,21 @@ class DateHelperTest < ActionView::TestCase end def test_time_ago_in_words_passes_include_seconds - assert_equal "less than 20 seconds", time_ago_in_words(15.seconds.ago, :include_seconds => true) - assert_equal "less than a minute", time_ago_in_words(15.seconds.ago, :include_seconds => false) + assert_equal "less than 20 seconds", time_ago_in_words(15.seconds.ago, include_seconds: true) + assert_equal "less than a minute", time_ago_in_words(15.seconds.ago, include_seconds: false) end def test_distance_in_words_with_time_zones from = Time.mktime(2004, 6, 6, 21, 45, 0) - assert_distance_of_time_in_words(from.in_time_zone('Alaska')) - assert_distance_of_time_in_words(from.in_time_zone('Hawaii')) + assert_distance_of_time_in_words(from.in_time_zone("Alaska")) + assert_distance_of_time_in_words(from.in_time_zone("Hawaii")) end def test_distance_in_words_with_different_time_zones from = Time.mktime(2004, 6, 6, 21, 45, 0) assert_distance_of_time_in_words( - from.in_time_zone('Alaska'), - from.in_time_zone('Hawaii') + from.in_time_zone("Alaska"), + from.in_time_zone("Hawaii") ) end @@ -185,10 +185,10 @@ class DateHelperTest < ActionView::TestCase assert_equal "about 1 hour", distance_of_time_in_words(60.minutes) # include seconds - assert_equal "half a minute", distance_of_time_in_words(39.seconds, 0, :include_seconds => true) - assert_equal "less than a minute", distance_of_time_in_words(40.seconds, 0, :include_seconds => true) - assert_equal "less than a minute", distance_of_time_in_words(59.seconds, 0, :include_seconds => true) - assert_equal "1 minute", distance_of_time_in_words(60.seconds, 0, :include_seconds => true) + assert_equal "half a minute", distance_of_time_in_words(39.seconds, 0, include_seconds: true) + assert_equal "less than a minute", distance_of_time_in_words(40.seconds, 0, include_seconds: true) + assert_equal "less than a minute", distance_of_time_in_words(59.seconds, 0, include_seconds: true) + assert_equal "1 minute", distance_of_time_in_words(60.seconds, 0, include_seconds: true) end def test_time_ago_in_words @@ -209,8 +209,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_day(Time.mktime(2003, 8, 16), :include_blank => true) - assert_dom_equal expected, select_day(16, :include_blank => true) + assert_dom_equal expected, select_day(Time.mktime(2003, 8, 16), include_blank: true) + assert_dom_equal expected, select_day(16, include_blank: true) end def test_select_day_nil_with_blank @@ -218,7 +218,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_day(nil, :include_blank => true) + assert_dom_equal expected, select_day(nil, include_blank: true) end def test_select_day_with_two_digit_numbers @@ -226,8 +226,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">01</option>\n<option selected="selected" value="2">02</option>\n<option value="3">03</option>\n<option value="4">04</option>\n<option value="5">05</option>\n<option value="6">06</option>\n<option value="7">07</option>\n<option value="8">08</option>\n<option value="9">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_day(Time.mktime(2011, 8, 2), :use_two_digit_numbers => true) - assert_dom_equal expected, select_day(2, :use_two_digit_numbers => true) + assert_dom_equal expected, select_day(Time.mktime(2011, 8, 2), use_two_digit_numbers: true) + assert_dom_equal expected, select_day(2, use_two_digit_numbers: true) end def test_select_day_with_html_options @@ -235,8 +235,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_day(Time.mktime(2003, 8, 16), {}, :class => 'selector') - assert_dom_equal expected, select_day(16, {}, :class => 'selector') + assert_dom_equal expected, select_day(Time.mktime(2003, 8, 16), {}, class: "selector") + assert_dom_equal expected, select_day(16, {}, class: "selector") end def test_select_day_with_default_prompt @@ -244,7 +244,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Day</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_day(16, :prompt => true) + assert_dom_equal expected, select_day(16, prompt: true) end def test_select_day_with_custom_prompt @@ -252,7 +252,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose day</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_day(16, :prompt => 'Choose day') + assert_dom_equal expected, select_day(16, prompt: "Choose day") end def test_select_day_with_generic_with_css_classes @@ -268,7 +268,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_day(16, with_css_classes: { day: 'my-day' }) + assert_dom_equal expected, select_day(16, with_css_classes: { day: "my-day" }) end def test_select_month @@ -285,8 +285,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">01</option>\n<option value="2">02</option>\n<option value="3">03</option>\n<option value="4">04</option>\n<option value="5">05</option>\n<option value="6">06</option>\n<option value="7">07</option>\n<option value="8" selected="selected">08</option>\n<option value="9">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2011, 8, 16), :use_two_digit_numbers => true) - assert_dom_equal expected, select_month(8, :use_two_digit_numbers => true) + assert_dom_equal expected, select_month(Time.mktime(2011, 8, 16), use_two_digit_numbers: true) + assert_dom_equal expected, select_month(8, use_two_digit_numbers: true) end def test_select_month_with_disabled @@ -294,8 +294,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :disabled => true) - assert_dom_equal expected, select_month(8, :disabled => true) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), disabled: true) + assert_dom_equal expected, select_month(8, disabled: true) end def test_select_month_with_field_name_override @@ -303,8 +303,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :field_name => 'mois') - assert_dom_equal expected, select_month(8, :field_name => 'mois') + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), field_name: "mois") + assert_dom_equal expected, select_month(8, field_name: "mois") end def test_select_month_with_blank @@ -312,8 +312,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :include_blank => true) - assert_dom_equal expected, select_month(8, :include_blank => true) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), include_blank: true) + assert_dom_equal expected, select_month(8, include_blank: true) end def test_select_month_nil_with_blank @@ -321,7 +321,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(nil, :include_blank => true) + assert_dom_equal expected, select_month(nil, include_blank: true) end def test_select_month_with_numbers @@ -329,8 +329,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8" selected="selected">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :use_month_numbers => true) - assert_dom_equal expected, select_month(8, :use_month_numbers => true) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), use_month_numbers: true) + assert_dom_equal expected, select_month(8, use_month_numbers: true) end def test_select_month_with_numbers_and_names @@ -338,8 +338,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1 - January</option>\n<option value="2">2 - February</option>\n<option value="3">3 - March</option>\n<option value="4">4 - April</option>\n<option value="5">5 - May</option>\n<option value="6">6 - June</option>\n<option value="7">7 - July</option>\n<option value="8" selected="selected">8 - August</option>\n<option value="9">9 - September</option>\n<option value="10">10 - October</option>\n<option value="11">11 - November</option>\n<option value="12">12 - December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :add_month_numbers => true) - assert_dom_equal expected, select_month(8, :add_month_numbers => true) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), add_month_numbers: true) + assert_dom_equal expected, select_month(8, add_month_numbers: true) end def test_select_month_with_format_string @@ -347,9 +347,9 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">January (01)</option>\n<option value="2">February (02)</option>\n<option value="3">March (03)</option>\n<option value="4">April (04)</option>\n<option value="5">May (05)</option>\n<option value="6">June (06)</option>\n<option value="7">July (07)</option>\n<option value="8" selected="selected">August (08)</option>\n<option value="9">September (09)</option>\n<option value="10">October (10)</option>\n<option value="11">November (11)</option>\n<option value="12">December (12)</option>\n) expected << "</select>\n" - format_string = '%{name} (%<number>02d)' - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :month_format_string => format_string) - assert_dom_equal expected, select_month(8, :month_format_string => format_string) + format_string = "%{name} (%<number>02d)" + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), month_format_string: format_string) + assert_dom_equal expected, select_month(8, month_format_string: format_string) end def test_select_month_with_numbers_and_names_with_abbv @@ -357,8 +357,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1 - Jan</option>\n<option value="2">2 - Feb</option>\n<option value="3">3 - Mar</option>\n<option value="4">4 - Apr</option>\n<option value="5">5 - May</option>\n<option value="6">6 - Jun</option>\n<option value="7">7 - Jul</option>\n<option value="8" selected="selected">8 - Aug</option>\n<option value="9">9 - Sep</option>\n<option value="10">10 - Oct</option>\n<option value="11">11 - Nov</option>\n<option value="12">12 - Dec</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :add_month_numbers => true, :use_short_month => true) - assert_dom_equal expected, select_month(8, :add_month_numbers => true, :use_short_month => true) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), add_month_numbers: true, use_short_month: true) + assert_dom_equal expected, select_month(8, add_month_numbers: true, use_short_month: true) end def test_select_month_with_abbv @@ -366,8 +366,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">Jan</option>\n<option value="2">Feb</option>\n<option value="3">Mar</option>\n<option value="4">Apr</option>\n<option value="5">May</option>\n<option value="6">Jun</option>\n<option value="7">Jul</option>\n<option value="8" selected="selected">Aug</option>\n<option value="9">Sep</option>\n<option value="10">Oct</option>\n<option value="11">Nov</option>\n<option value="12">Dec</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :use_short_month => true) - assert_dom_equal expected, select_month(8, :use_short_month => true) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), use_short_month: true) + assert_dom_equal expected, select_month(8, use_short_month: true) end def test_select_month_with_custom_names @@ -377,8 +377,8 @@ class DateHelperTest < ActionView::TestCase 1.upto(12) { |month| expected << %(<option value="#{month}"#{' selected="selected"' if month == 8}>#{month_names[month]}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :use_month_names => month_names) - assert_dom_equal expected, select_month(8, :use_month_names => month_names) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), use_month_names: month_names) + assert_dom_equal expected, select_month(8, use_month_names: month_names) end def test_select_month_with_zero_indexed_custom_names @@ -388,16 +388,16 @@ class DateHelperTest < ActionView::TestCase 1.upto(12) { |month| expected << %(<option value="#{month}"#{' selected="selected"' if month == 8}>#{month_names[month-1]}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), :use_month_names => month_names) - assert_dom_equal expected, select_month(8, :use_month_names => month_names) + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), use_month_names: month_names) + assert_dom_equal expected, select_month(8, use_month_names: month_names) end def test_select_month_with_hidden - assert_dom_equal "<input type=\"hidden\" id=\"date_month\" name=\"date[month]\" value=\"8\" />\n", select_month(8, :use_hidden => true) + assert_dom_equal "<input type=\"hidden\" id=\"date_month\" name=\"date[month]\" value=\"8\" />\n", select_month(8, use_hidden: true) end def test_select_month_with_hidden_and_field_name - assert_dom_equal "<input type=\"hidden\" id=\"date_mois\" name=\"date[mois]\" value=\"8\" />\n", select_month(8, :use_hidden => true, :field_name => 'mois') + assert_dom_equal "<input type=\"hidden\" id=\"date_mois\" name=\"date[mois]\" value=\"8\" />\n", select_month(8, use_hidden: true, field_name: "mois") end def test_select_month_with_html_options @@ -405,7 +405,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), {}, :class => 'selector', :accesskey => 'M') + assert_dom_equal expected, select_month(Time.mktime(2003, 8, 16), {}, class: "selector", accesskey: "M") end def test_select_month_with_default_prompt @@ -413,7 +413,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Month</option>\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(8, :prompt => true) + assert_dom_equal expected, select_month(8, prompt: true) end def test_select_month_with_custom_prompt @@ -421,7 +421,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose month</option>\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(8, :prompt => 'Choose month') + assert_dom_equal expected, select_month(8, prompt: "Choose month") end def test_select_month_with_generic_with_css_classes @@ -437,7 +437,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_month(8, with_css_classes: { month: 'my-month' }) + assert_dom_equal expected, select_month(8, with_css_classes: { month: "my-month" }) end def test_select_year @@ -445,8 +445,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005) - assert_dom_equal expected, select_year(2003, :start_year => 2003, :end_year => 2005) + assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005) + assert_dom_equal expected, select_year(2003, start_year: 2003, end_year: 2005) end def test_select_year_with_disabled @@ -454,8 +454,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), :disabled => true, :start_year => 2003, :end_year => 2005) - assert_dom_equal expected, select_year(2003, :disabled => true, :start_year => 2003, :end_year => 2005) + assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), disabled: true, start_year: 2003, end_year: 2005) + assert_dom_equal expected, select_year(2003, disabled: true, start_year: 2003, end_year: 2005) end def test_select_year_with_field_name_override @@ -463,8 +463,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005, :field_name => 'annee') - assert_dom_equal expected, select_year(2003, :start_year => 2003, :end_year => 2005, :field_name => 'annee') + assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, field_name: "annee") + assert_dom_equal expected, select_year(2003, start_year: 2003, end_year: 2005, field_name: "annee") end def test_select_year_with_type_discarding @@ -473,9 +473,9 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" assert_dom_equal expected, select_year( - Time.mktime(2003, 8, 16), :prefix => "date_year", :discard_type => true, :start_year => 2003, :end_year => 2005) + Time.mktime(2003, 8, 16), prefix: "date_year", discard_type: true, start_year: 2003, end_year: 2005) assert_dom_equal expected, select_year( - 2003, :prefix => "date_year", :discard_type => true, :start_year => 2003, :end_year => 2005) + 2003, prefix: "date_year", discard_type: true, start_year: 2003, end_year: 2005) end def test_select_year_descending @@ -483,16 +483,16 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2005" selected="selected">2005</option>\n<option value="2004">2004</option>\n<option value="2003">2003</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(Time.mktime(2005, 8, 16), :start_year => 2005, :end_year => 2003) - assert_dom_equal expected, select_year(2005, :start_year => 2005, :end_year => 2003) + assert_dom_equal expected, select_year(Time.mktime(2005, 8, 16), start_year: 2005, end_year: 2003) + assert_dom_equal expected, select_year(2005, start_year: 2005, end_year: 2003) end def test_select_year_with_hidden - assert_dom_equal "<input type=\"hidden\" id=\"date_year\" name=\"date[year]\" value=\"2007\" />\n", select_year(2007, :use_hidden => true) + assert_dom_equal "<input type=\"hidden\" id=\"date_year\" name=\"date[year]\" value=\"2007\" />\n", select_year(2007, use_hidden: true) end def test_select_year_with_hidden_and_field_name - assert_dom_equal "<input type=\"hidden\" id=\"date_anno\" name=\"date[anno]\" value=\"2007\" />\n", select_year(2007, :use_hidden => true, :field_name => 'anno') + assert_dom_equal "<input type=\"hidden\" id=\"date_anno\" name=\"date[anno]\" value=\"2007\" />\n", select_year(2007, use_hidden: true, field_name: "anno") end def test_select_year_with_html_options @@ -500,7 +500,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), {:start_year => 2003, :end_year => 2005}, :class => 'selector', :accesskey => 'M') + assert_dom_equal expected, select_year(Time.mktime(2003, 8, 16), { start_year: 2003, end_year: 2005 }, class: "selector", accesskey: "M") end def test_select_year_with_default_prompt @@ -508,7 +508,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Year</option>\n<option value="2003">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(nil, :start_year => 2003, :end_year => 2005, :prompt => true) + assert_dom_equal expected, select_year(nil, start_year: 2003, end_year: 2005, prompt: true) end def test_select_year_with_custom_prompt @@ -516,7 +516,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose year</option>\n<option value="2003">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(nil, :start_year => 2003, :end_year => 2005, :prompt => 'Choose year') + assert_dom_equal expected, select_year(nil, start_year: 2003, end_year: 2005, prompt: "Choose year") end def test_select_year_with_generic_with_css_classes @@ -532,7 +532,14 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2003">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_year(nil, start_year: 2003, end_year: 2005, with_css_classes: { year: 'my-year' }) + assert_dom_equal expected, select_year(nil, start_year: 2003, end_year: 2005, with_css_classes: { year: "my-year" }) + end + + def test_select_year_with_position + expected = %(<select id="date_year_1i" name="date[year(1i)]">\n) + expected << %(<option value="2003">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) + expected << "</select>\n" + assert_dom_equal expected, select_year(Date.current, include_position: true, start_year: 2003, end_year: 2005) end def test_select_hour @@ -548,7 +555,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">12 AM</option>\n<option value="01">01 AM</option>\n<option value="02">02 AM</option>\n<option value="03">03 AM</option>\n<option value="04">04 AM</option>\n<option value="05">05 AM</option>\n<option value="06">06 AM</option>\n<option value="07">07 AM</option>\n<option value="08" selected="selected">08 AM</option>\n<option value="09">09 AM</option>\n<option value="10">10 AM</option>\n<option value="11">11 AM</option>\n<option value="12">12 PM</option>\n<option value="13">01 PM</option>\n<option value="14">02 PM</option>\n<option value="15">03 PM</option>\n<option value="16">04 PM</option>\n<option value="17">05 PM</option>\n<option value="18">06 PM</option>\n<option value="19">07 PM</option>\n<option value="20">08 PM</option>\n<option value="21">09 PM</option>\n<option value="22">10 PM</option>\n<option value="23">11 PM</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), :ampm => true) + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), ampm: true) end def test_select_hour_with_disabled @@ -556,7 +563,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), :disabled => true) + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), disabled: true) end def test_select_hour_with_field_name_override @@ -564,7 +571,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), :field_name => 'heure') + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), field_name: "heure") end def test_select_hour_with_blank @@ -572,7 +579,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), :include_blank => true) + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), include_blank: true) end def test_select_hour_nil_with_blank @@ -580,7 +587,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(nil, :include_blank => true) + assert_dom_equal expected, select_hour(nil, include_blank: true) end def test_select_hour_with_html_options @@ -588,7 +595,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), {}, :class => 'selector', :accesskey => 'M') + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), {}, class: "selector", accesskey: "M") end def test_select_hour_with_default_prompt @@ -596,7 +603,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Hour</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), :prompt => true) + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), prompt: true) end def test_select_hour_with_custom_prompt @@ -604,7 +611,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose hour</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), :prompt => 'Choose hour') + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), prompt: "Choose hour") end def test_select_hour_with_generic_with_css_classes @@ -620,7 +627,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), with_css_classes: { hour: 'my-hour' }) + assert_dom_equal expected, select_hour(Time.mktime(2003, 8, 16, 8, 4, 18), with_css_classes: { hour: "my-hour" }) end def test_select_minute @@ -636,7 +643,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), :disabled => true) + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), disabled: true) end def test_select_minute_with_field_name_override @@ -644,7 +651,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), :field_name => 'minuto') + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), field_name: "minuto") end def test_select_minute_with_blank @@ -652,7 +659,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), :include_blank => true) + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), include_blank: true) end def test_select_minute_with_blank_and_step @@ -660,7 +667,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="15">15</option>\n<option value="30">30</option>\n<option value="45">45</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), { :include_blank => true , :minute_step => 15 }) + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), include_blank: true , minute_step: 15) end def test_select_minute_nil_with_blank @@ -668,7 +675,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(nil, :include_blank => true) + assert_dom_equal expected, select_minute(nil, include_blank: true) end def test_select_minute_nil_with_blank_and_step @@ -676,15 +683,15 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="15">15</option>\n<option value="30">30</option>\n<option value="45">45</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(nil, { :include_blank => true , :minute_step => 15 }) + assert_dom_equal expected, select_minute(nil, include_blank: true , minute_step: 15) end def test_select_minute_with_hidden - assert_dom_equal "<input type=\"hidden\" id=\"date_minute\" name=\"date[minute]\" value=\"8\" />\n", select_minute(8, :use_hidden => true) + assert_dom_equal "<input type=\"hidden\" id=\"date_minute\" name=\"date[minute]\" value=\"8\" />\n", select_minute(8, use_hidden: true) end def test_select_minute_with_hidden_and_field_name - assert_dom_equal "<input type=\"hidden\" id=\"date_minuto\" name=\"date[minuto]\" value=\"8\" />\n", select_minute(8, :use_hidden => true, :field_name => 'minuto') + assert_dom_equal "<input type=\"hidden\" id=\"date_minuto\" name=\"date[minuto]\" value=\"8\" />\n", select_minute(8, use_hidden: true, field_name: "minuto") end def test_select_minute_with_html_options @@ -692,7 +699,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), {}, :class => 'selector', :accesskey => 'M') + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), {}, class: "selector", accesskey: "M") end def test_select_minute_with_default_prompt @@ -700,7 +707,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), :prompt => true) + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), prompt: true) end def test_select_minute_with_custom_prompt @@ -708,7 +715,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), :prompt => 'Choose minute') + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), prompt: "Choose minute") end def test_select_minute_with_generic_with_css_classes @@ -724,7 +731,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), with_css_classes: { minute: 'my-minute' }) + assert_dom_equal expected, select_minute(Time.mktime(2003, 8, 16, 8, 4, 18), with_css_classes: { minute: "my-minute" }) end def test_select_second @@ -740,7 +747,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), :disabled => true) + assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), disabled: true) end def test_select_second_with_field_name_override @@ -748,7 +755,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), :field_name => 'segundo') + assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), field_name: "segundo") end def test_select_second_with_blank @@ -756,7 +763,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), :include_blank => true) + assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), include_blank: true) end def test_select_second_nil_with_blank @@ -764,7 +771,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value=""></option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(nil, :include_blank => true) + assert_dom_equal expected, select_second(nil, include_blank: true) end def test_select_second_with_html_options @@ -772,7 +779,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), {}, :class => 'selector', :accesskey => 'M') + assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), {}, class: "selector", accesskey: "M") end def test_select_second_with_default_prompt @@ -780,7 +787,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Seconds</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), :prompt => true) + assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), prompt: true) end def test_select_second_with_custom_prompt @@ -788,7 +795,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose seconds</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), :prompt => 'Choose seconds') + assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), prompt: "Choose seconds") end def test_select_second_with_generic_with_css_classes @@ -804,7 +811,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), with_css_classes: { second: 'my-second' }) + assert_dom_equal expected, select_second(Time.mktime(2003, 8, 16, 8, 4, 18), with_css_classes: { second: "my-second" }) end def test_select_date @@ -820,16 +827,16 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005, :prefix => "date[first]") + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, prefix: "date[first]") end def test_select_date_with_too_big_range_between_start_year_and_end_year - assert_raise(ArgumentError) { select_date(Time.mktime(2003, 8, 16), :start_year => 2000, :end_year => 20000, :prefix => "date[first]", :order => [:month, :day, :year]) } - assert_raise(ArgumentError) { select_date(Time.mktime(2003, 8, 16), :start_year => Date.today.year - 100.years, :end_year => 2000, :prefix => "date[first]", :order => [:month, :day, :year]) } + assert_raise(ArgumentError) { select_date(Time.mktime(2003, 8, 16), start_year: 2000, end_year: 20000, prefix: "date[first]", order: [:month, :day, :year]) } + assert_raise(ArgumentError) { select_date(Time.mktime(2003, 8, 16), start_year: Date.today.year - 100.years, end_year: 2000, prefix: "date[first]", order: [:month, :day, :year]) } end def test_select_date_can_have_more_then_1000_years_interval_if_forced_via_parameter - assert_nothing_raised { select_date(Time.mktime(2003, 8, 16), :start_year => 2000, :end_year => 3100, :max_years_allowed => 2000) } + assert_nothing_raised { select_date(Time.mktime(2003, 8, 16), start_year: 2000, end_year: 3100, max_years_allowed: 2000) } end def test_select_date_with_order @@ -845,7 +852,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", :order => [:month, :day, :year]) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, prefix: "date[first]", order: [:month, :day, :year]) end def test_select_date_with_incomplete_order @@ -854,7 +861,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<input id="date_first_month" name="date[first][month]" type="hidden" value="8" />\n) expected << %(<input id="date_first_day" name="date[first][day]" type="hidden" value="1" />\n) - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", :order => [:day]) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, prefix: "date[first]", order: [:day]) end def test_select_date_with_disabled @@ -870,7 +877,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", :disabled => true) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, prefix: "date[first]", disabled: true) end def test_select_date_with_no_start_year @@ -893,7 +900,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" assert_dom_equal expected, select_date( - Time.mktime(Date.today.year, 8, 16), :end_year => Date.today.year+1, :prefix => "date[first]" + Time.mktime(Date.today.year, 8, 16), end_year: Date.today.year+1, prefix: "date[first]" ) end @@ -917,7 +924,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" assert_dom_equal expected, select_date( - Time.mktime(2003, 8, 16), :start_year => 2003, :prefix => "date[first]" + Time.mktime(2003, 8, 16), start_year: 2003, prefix: "date[first]" ) end @@ -941,7 +948,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" assert_dom_equal expected, select_date( - Time.mktime(Date.today.year, 8, 16), :prefix => "date[first]" + Time.mktime(Date.today.year, 8, 16), prefix: "date[first]" ) end @@ -958,7 +965,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(0, :start_year => 2003, :end_year => 2005, :prefix => "date[first]") + assert_dom_equal expected, select_date(0, start_year: 2003, end_year: 2005, prefix: "date[first]") end def test_select_date_with_zero_value_and_no_start_year @@ -974,7 +981,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(0, :end_year => Date.today.year+1, :prefix => "date[first]") + assert_dom_equal expected, select_date(0, end_year: Date.today.year+1, prefix: "date[first]") end def test_select_date_with_zero_value_and_no_end_year @@ -991,7 +998,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(0, :start_year => 2003, :prefix => "date[first]") + assert_dom_equal expected, select_date(0, start_year: 2003, prefix: "date[first]") end def test_select_date_with_zero_value_and_no_start_and_end_year @@ -1007,7 +1014,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(0, :prefix => "date[first]") + assert_dom_equal expected, select_date(0, prefix: "date[first]") end def test_select_date_with_nil_value_and_no_start_and_end_year @@ -1023,7 +1030,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(nil, :prefix => "date[first]") + assert_dom_equal expected, select_date(nil, prefix: "date[first]") end def test_select_date_with_html_options @@ -1039,7 +1046,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {:start_year => 2003, :end_year => 2005, :prefix => "date[first]"}, :class => "selector") + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { start_year: 2003, end_year: 2005, prefix: "date[first]" }, class: "selector") end def test_select_date_with_separator @@ -1059,7 +1066,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :start_year => 2003, :end_year => 2005, :prefix => "date[first]"}) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), date_separator: " / ", start_year: 2003, end_year: 2005, prefix: "date[first]") end def test_select_date_with_separator_and_discard_day @@ -1075,7 +1082,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<input type="hidden" id="date_first_day" name="date[first][day]" value="1" />\n) - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :discard_day => true, :start_year => 2003, :end_year => 2005, :prefix => "date[first]"}) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), date_separator: " / ", discard_day: true, start_year: 2003, end_year: 2005, prefix: "date[first]") end def test_select_date_with_separator_discard_month_and_day @@ -1086,7 +1093,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<input type="hidden" id="date_first_month" name="date[first][month]" value="8" />\n) expected << %(<input type="hidden" id="date_first_day" name="date[first][day]" value="1" />\n) - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :discard_month => true, :discard_day => true, :start_year => 2003, :end_year => 2005, :prefix => "date[first]"}) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), date_separator: " / ", discard_month: true, discard_day: true, start_year: 2003, end_year: 2005, prefix: "date[first]") end def test_select_date_with_hidden @@ -1094,8 +1101,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<input id="date_first_month" name="date[first][month]" type="hidden" value="8" />\n) expected << %(<input id="date_first_day" name="date[first][day]" type="hidden" value="16" />\n) - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :prefix => "date[first]", :use_hidden => true }) - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :prefix => "date[first]", :use_hidden => true }) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), prefix: "date[first]", use_hidden: true) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), date_separator: " / ", prefix: "date[first]", use_hidden: true) end def test_select_date_with_css_classes_option @@ -1111,7 +1118,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {:start_year => 2003, :end_year => 2005, :prefix => "date[first]", :with_css_classes => true}) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, prefix: "date[first]", with_css_classes: true) end def test_select_date_with_custom_with_css_classes @@ -1127,7 +1134,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, with_css_classes: { year: 'my-year', month: 'my-month', day: 'my-day' }) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), start_year: 2003, end_year: 2005, with_css_classes: { year: "my-year", month: "my-month", day: "my-day" }) end def test_select_date_with_css_classes_option_and_html_class_option @@ -1143,7 +1150,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {:start_year => 2003, :end_year => 2005, :prefix => "date[first]", :with_css_classes => true}, { class: 'datetime optional' }) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { start_year: 2003, end_year: 2005, prefix: "date[first]", with_css_classes: true }, class: "datetime optional") end def test_select_date_with_custom_with_css_classes_and_html_class_option @@ -1159,7 +1166,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {start_year: 2003, end_year: 2005, with_css_classes: { year: 'my-year', month: 'my-month', day: 'my-day' }}, { class: 'date optional' }) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { start_year: 2003, end_year: 2005, with_css_classes: { year: "my-year", month: "my-month", day: "my-day" } }, class: "date optional") end def test_select_date_with_partial_with_css_classes_and_html_class_option @@ -1175,7 +1182,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {start_year: 2003, end_year: 2005, with_css_classes: { month: 'my-month custom-grid' }}, { class: 'date optional' }) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { start_year: 2003, end_year: 2005, with_css_classes: { month: "my-month custom-grid" } }, class: "date optional") end def test_select_date_with_html_class_option @@ -1191,7 +1198,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { start_year: 2003, end_year: 2005 }, { class: 'date optional custom-grid' }) + assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { start_year: 2003, end_year: 2005 }, class: "date optional custom-grid") end def test_select_datetime @@ -1219,7 +1226,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :start_year => 2003, :end_year => 2005, :prefix => "date[first]") + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, prefix: "date[first]") end def test_select_datetime_with_ampm @@ -1247,7 +1254,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", :ampm => true) + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, prefix: "date[first]", ampm: true) end def test_select_datetime_with_separators @@ -1275,7 +1282,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", :datetime_separator => ' — ', :time_separator => ' : ') + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, prefix: "date[first]", datetime_separator: " — ", time_separator: " : ") end def test_select_datetime_with_nil_value_and_no_start_and_end_year @@ -1303,7 +1310,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(nil, :prefix => "date[first]") + assert_dom_equal expected, select_datetime(nil, prefix: "date[first]") end def test_select_datetime_with_html_options @@ -1311,7 +1318,6 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n) expected << "</select>\n" - expected << %(<select id="date_first_month" name="date[first][month]" class="selector">\n) expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n) expected << "</select>\n" @@ -1332,7 +1338,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), {:start_year => 2003, :end_year => 2005, :prefix => "date[first]"}, :class => 'selector') + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), { start_year: 2003, end_year: 2005, prefix: "date[first]" }, class: "selector") end def test_select_datetime_with_all_separators @@ -1364,7 +1370,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), { :datetime_separator => "—", :date_separator => "/", :time_separator => ":", :start_year => 2003, :end_year => 2005, :prefix => "date[first]"}, :class => 'selector') + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), { datetime_separator: "—", date_separator: "/", time_separator: ":", start_year: 2003, end_year: 2005, prefix: "date[first]" }, class: "selector") end def test_select_datetime_should_work_with_date @@ -1396,8 +1402,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :start_year => 2003, :end_year => 2005, - :prefix => "date[first]", :prompt => true) + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, + prefix: "date[first]", prompt: true) end def test_select_datetime_with_custom_prompt @@ -1426,8 +1432,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", - :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year', :hour => 'Choose hour', :minute => 'Choose minute'}) + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, prefix: "date[first]", + prompt: { day: "Choose day", month: "Choose month", year: "Choose year", hour: "Choose hour", minute: "Choose minute" }) end def test_select_datetime_with_generic_with_css_classes @@ -1483,7 +1489,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, with_css_classes: { day: 'my-day', month: 'my-month', year: 'my-year', hour: 'my-hour', minute: 'my-minute' }) + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, with_css_classes: { day: "my-day", month: "my-month", year: "my-year", hour: "my-hour", minute: "my-minute" }) end def test_select_datetime_with_custom_hours @@ -1511,8 +1517,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :start_year => 2003, :end_year => 2005, :start_hour => 1, :end_hour => 9, :prefix => "date[first]", - :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year', :hour => 'Choose hour', :minute => 'Choose minute'}) + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), start_year: 2003, end_year: 2005, start_hour: 1, end_hour: 9, prefix: "date[first]", + prompt: { day: "Choose day", month: "Choose month", year: "Choose year", hour: "Choose hour", minute: "Choose minute" }) end def test_select_datetime_with_hidden @@ -1522,9 +1528,9 @@ class DateHelperTest < ActionView::TestCase expected << %(<input id="date_first_hour" name="date[first][hour]" type="hidden" value="8" />\n) expected << %(<input id="date_first_minute" name="date[first][minute]" type="hidden" value="4" />\n) - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :prefix => "date[first]", :use_hidden => true) - assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), :datetime_separator => "—", :date_separator => "/", - :time_separator => ":", :prefix => "date[first]", :use_hidden => true) + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), prefix: "date[first]", use_hidden: true) + assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), datetime_separator: "—", date_separator: "/", + time_separator: ":", prefix: "date[first]", use_hidden: true) end def test_select_time @@ -1543,7 +1549,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18)) - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :include_seconds => false) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: false) end def test_select_time_with_ampm @@ -1561,7 +1567,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :include_seconds => false, :ampm => true) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: false, ampm: true) end def test_select_time_with_separator @@ -1578,8 +1584,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :time_separator => ' : ') - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :time_separator => ' : ', :include_seconds => false) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), time_separator: " : ") + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), time_separator: " : ", include_seconds: false) end def test_select_time_with_seconds @@ -1591,19 +1597,19 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n) expected << "</select>\n" - expected << ' : ' + expected << " : " expected << %(<select id="date_minute" name="date[minute]">\n) expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - expected << ' : ' + expected << " : " expected << %(<select id="date_second" name="date[second]">\n) expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :include_seconds => true) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: true) end def test_select_time_with_seconds_and_separator @@ -1627,7 +1633,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :include_seconds => true, :time_separator => ' : ') + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: true, time_separator: " : ") end def test_select_time_with_html_options @@ -1645,8 +1651,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {}, :class => 'selector') - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {:include_seconds => false}, :class => 'selector') + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {}, class: "selector") + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), { include_seconds: false }, class: "selector") end def test_select_time_should_work_with_date @@ -1674,7 +1680,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Seconds</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :include_seconds => true, :prompt => true) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: true, prompt: true) end def test_select_time_with_custom_prompt @@ -1698,8 +1704,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose seconds</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :include_seconds => true, - :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'}) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: true, + prompt: { hour: "Choose hour", minute: "Choose minute", second: "Choose seconds" }) end def test_select_time_with_generic_with_css_classes @@ -1747,7 +1753,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: true, with_css_classes: { hour: 'my-hour', minute: 'my-minute', second: 'my-second' }) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), include_seconds: true, with_css_classes: { hour: "my-hour", minute: "my-minute", second: "my-second" }) end def test_select_time_with_hidden @@ -1757,8 +1763,8 @@ class DateHelperTest < ActionView::TestCase expected << %(<input id="date_first_hour" name="date[first][hour]" type="hidden" value="8" />\n) expected << %(<input id="date_first_minute" name="date[first][minute]" type="hidden" value="4" />\n) - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :prefix => "date[first]", :use_hidden => true) - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :time_separator => ":", :prefix => "date[first]", :use_hidden => true) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), prefix: "date[first]", use_hidden: true) + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), time_separator: ":", prefix: "date[first]", use_hidden: true) end def test_date_select @@ -1798,7 +1804,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :selected => Date.new(2004, 07, 10)) + assert_dom_equal expected, date_select("post", "written_on", selected: Date.new(2004, 07, 10)) end def test_date_select_with_selected_in_hash @@ -1818,7 +1824,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :selected => {day: 10, month: 07, year: 2004}) + assert_dom_equal expected, date_select("post", "written_on", selected: { day: 10, month: 07, year: 2004 }) end def test_date_select_with_selected_nil @@ -1853,7 +1859,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n} expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :order => [ :month, :year ]) + assert_dom_equal expected, date_select("post", "written_on", order: [ :month, :year ]) end def test_date_select_without_day_and_month @@ -1867,7 +1873,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n} expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :order => [ :year ]) + assert_dom_equal expected, date_select("post", "written_on", order: [ :year ]) end def test_date_select_without_day_with_separator @@ -1886,7 +1892,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n} expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :date_separator => '/', :order => [ :month, :year ]) + assert_dom_equal expected, date_select("post", "written_on", date_separator: "/", order: [ :month, :year ]) end def test_date_select_without_day_and_with_disabled_html_option @@ -1903,7 +1909,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n} expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", { :order => [ :month, :year ] }, :disabled => true) + assert_dom_equal expected, date_select("post", "written_on", { order: [ :month, :year ] }, disabled: true) end def test_date_select_within_fields_for @@ -1926,7 +1932,7 @@ class DateHelperTest < ActionView::TestCase @post.written_on = Date.new(2004, 6, 15) id = 27 - output_buffer = fields_for :post, @post, :index => id do |f| + output_buffer = fields_for :post, @post, index: id do |f| concat f.date_select(:written_on) end @@ -1942,11 +1948,10 @@ class DateHelperTest < ActionView::TestCase @post.written_on = Date.new(2004, 6, 15) id = nil - output_buffer = fields_for :post, @post, :index => id do |f| + output_buffer = fields_for :post, @post, index: id do |f| concat f.date_select(:written_on) end - expected = %{<select id="post_#{id}_written_on_1i" name="post[#{id}][written_on(1i)]">\n<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option selected="selected" value="2004">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n</select>\n} expected << %{<select id="post_#{id}_written_on_2i" name="post[#{id}][written_on(2i)]">\n<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option selected="selected" value="6">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n</select>\n} expected << %{<select id="post_#{id}_written_on_3i" name="post[#{id}][written_on(3i)]">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option selected="selected" value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n</select>\n} @@ -1971,7 +1976,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n} expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :index => id) + assert_dom_equal expected, date_select("post", "written_on", index: id) end def test_date_select_with_auto_index @@ -2010,7 +2015,7 @@ class DateHelperTest < ActionView::TestCase 1999.upto(2009) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 2004}>#{i}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :order => [:day, :month, :year]) + assert_dom_equal expected, date_select("post", "written_on", order: [:day, :month, :year]) end def test_date_select_with_nil @@ -2053,7 +2058,7 @@ class DateHelperTest < ActionView::TestCase 1.upto(31) { |i| expected << %(<option value="#{i}">#{i}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :include_blank => true) + assert_dom_equal expected, date_select("post", "written_on", include_blank: true) end def test_date_select_with_nil_and_blank_and_order @@ -2073,7 +2078,7 @@ class DateHelperTest < ActionView::TestCase 1.upto(12) { |i| expected << %(<option value="#{i}">#{Date::MONTHNAMES[i]}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :order=>[:year, :month], :include_blank=>true) + assert_dom_equal expected, date_select("post", "written_on", order: [:year, :month], include_blank: true) end def test_date_select_with_nil_and_blank_and_discard_month @@ -2089,7 +2094,7 @@ class DateHelperTest < ActionView::TestCase expected << '<input name="post[written_on(2i)]" type="hidden" id="post_written_on_2i" value="1"/>' + "\n" expected << '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i" value="1"/>' + "\n" - assert_dom_equal expected, date_select("post", "written_on", :discard_month => true, :include_blank=>true) + assert_dom_equal expected, date_select("post", "written_on", discard_month: true, include_blank: true) end def test_date_select_with_nil_and_blank_and_discard_year @@ -2107,7 +2112,7 @@ class DateHelperTest < ActionView::TestCase 1.upto(31) { |i| expected << %(<option value="#{i}">#{i}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :discard_year => true, :include_blank=>true) + assert_dom_equal expected, date_select("post", "written_on", discard_year: true, include_blank: true) end def test_date_select_cant_override_discard_hour @@ -2126,7 +2131,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n} expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :discard_hour => false) + assert_dom_equal expected, date_select("post", "written_on", discard_hour: false) end def test_date_select_with_html_options @@ -2146,7 +2151,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", {}, :class => 'selector') + assert_dom_equal expected, date_select("post", "written_on", {}, class: "selector") end def test_date_select_with_html_options_within_fields_for @@ -2154,7 +2159,7 @@ class DateHelperTest < ActionView::TestCase @post.written_on = Date.new(2004, 6, 15) output_buffer = fields_for :post, @post do |f| - concat f.date_select(:written_on, {}, :class => 'selector') + concat f.date_select(:written_on, {}, class: "selector") end expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]" class="selector">\n} @@ -2194,7 +2199,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", { :date_separator => " / " }) + assert_dom_equal expected, date_select("post", "written_on", date_separator: " / ") end def test_date_select_with_separator_and_order @@ -2217,7 +2222,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n} expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", { :order => [:day, :month, :year], :date_separator => " / " }) + assert_dom_equal expected, date_select("post", "written_on", order: [:day, :month, :year], date_separator: " / ") end def test_date_select_with_separator_and_order_and_year_discarded @@ -2235,7 +2240,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" expected << %{<input type="hidden" id="post_written_on_1i" name="post[written_on(1i)]" value="2004" />\n} - assert_dom_equal expected, date_select("post", "written_on", { :order => [:day, :month, :year], :discard_year => true, :date_separator => " / " }) + assert_dom_equal expected, date_select("post", "written_on", order: [:day, :month, :year], discard_year: true, date_separator: " / ") end def test_date_select_with_default_prompt @@ -2255,7 +2260,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :prompt => true) + assert_dom_equal expected, date_select("post", "written_on", prompt: true) end def test_date_select_with_custom_prompt @@ -2275,7 +2280,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", :prompt => {:year => 'Choose year', :month => 'Choose month', :day => 'Choose day'}) + assert_dom_equal expected, date_select("post", "written_on", prompt: { year: "Choose year", month: "Choose month", day: "Choose day" }) end def test_date_select_with_generic_with_css_classes @@ -2315,7 +2320,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" - assert_dom_equal expected, date_select("post", "written_on", with_css_classes: { year: 'my-year', month: 'my-month', day: 'my-day' }) + assert_dom_equal expected, date_select("post", "written_on", with_css_classes: { year: "my-year", month: "my-month", day: "my-day" }) end def test_time_select @@ -2387,7 +2392,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", :ignore_date => true) + assert_dom_equal expected, time_select("post", "written_on", ignore_date: true) end def test_time_select_with_seconds @@ -2410,7 +2415,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 35}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", :include_seconds => true) + assert_dom_equal expected, time_select("post", "written_on", include_seconds: true) end def test_time_select_with_html_options @@ -2429,7 +2434,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", {}, :class => 'selector') + assert_dom_equal expected, time_select("post", "written_on", {}, class: "selector") end def test_time_select_with_html_options_within_fields_for @@ -2437,7 +2442,7 @@ class DateHelperTest < ActionView::TestCase @post.written_on = Time.local(2004, 6, 15, 15, 16, 35) output_buffer = fields_for :post, @post do |f| - concat f.time_select(:written_on, {}, :class => 'selector') + concat f.time_select(:written_on, {}, class: "selector") end expected = %{<input type="hidden" id="post_written_on_1i" name="post[written_on(1i)]" value="2004" />\n} @@ -2479,7 +2484,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 35}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", { :time_separator => " - ", :include_seconds => true }) + assert_dom_equal expected, time_select("post", "written_on", time_separator: " - ", include_seconds: true) end def test_time_select_with_default_prompt @@ -2496,11 +2501,11 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" expected << " : " expected << %(<select id="post_written_on_5i" name="post[written_on(5i)]">\n) - expected << %(<option value="">Minute</option>\n) + expected << %(<option value="">Minute</option>\n) 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", :prompt => true) + assert_dom_equal expected, time_select("post", "written_on", prompt: true) end def test_time_select_with_custom_prompt @@ -2517,11 +2522,11 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" expected << " : " expected << %(<select id="post_written_on_5i" name="post[written_on(5i)]">\n) - expected << %(<option value="">Choose minute</option>\n) + expected << %(<option value="">Choose minute</option>\n) 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute'}) + assert_dom_equal expected, time_select("post", "written_on", prompt: { hour: "Choose hour", minute: "Choose minute" }) end def test_time_select_with_generic_with_css_classes @@ -2563,7 +2568,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", with_css_classes: { hour: 'my-hour', minute: 'my-minute' }) + assert_dom_equal expected, time_select("post", "written_on", with_css_classes: { hour: "my-hour", minute: "my-minute" }) end def test_time_select_with_disabled_html_option @@ -2582,7 +2587,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, time_select("post", "written_on", {}, :disabled => true) + assert_dom_equal expected, time_select("post", "written_on", {}, disabled: true) end def test_datetime_select @@ -2640,7 +2645,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30" selected="selected">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n} expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :selected => Time.local(2004, 3, 10, 12, 30)) + assert_dom_equal expected, datetime_select("post", "updated_at", selected: Time.local(2004, 3, 10, 12, 30)) end def test_datetime_select_with_selected_nil @@ -2674,7 +2679,7 @@ class DateHelperTest < ActionView::TestCase # The love zone is UTC+0 mytz = Class.new(ActiveSupport::TimeZone) { attr_accessor :now - }.create('tenderlove', 0, ActiveSupport::TimeZone.find_tzinfo('UTC')) + }.create("tenderlove", 0, ActiveSupport::TimeZone.find_tzinfo("UTC")) now = Time.mktime(2004, 6, 15, 16, 35, 0) mytz.now = now @@ -2716,7 +2721,7 @@ class DateHelperTest < ActionView::TestCase @post.updated_at = Time.local(2004, 6, 15, 16, 35) output_buffer = fields_for :post, @post do |f| - concat f.datetime_select(:updated_at, {}, :class => 'selector') + concat f.datetime_select(:updated_at, {}, class: "selector") end expected = %{<select id="post_updated_at_1i" name="post[updated_at(1i)]" class="selector">\n<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option selected="selected" value="2004">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n</select>\n} @@ -2766,7 +2771,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 35}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", { :date_separator => " / ", :datetime_separator => " , ", :time_separator => " - ", :include_seconds => true }) + assert_dom_equal expected, datetime_select("post", "updated_at", date_separator: " / ", datetime_separator: " , ", time_separator: " - ", include_seconds: true) end def test_datetime_select_with_integer @@ -2807,7 +2812,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="">Minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n} expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :start_year=>1999, :end_year=>2009, :prompt => true) + assert_dom_equal expected, datetime_select("post", "updated_at", start_year: 1999, end_year: 2009, prompt: true) end def test_datetime_select_with_custom_prompt @@ -2836,7 +2841,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="">Choose minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n} expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :start_year=>1999, :end_year=>2009, :prompt => {:year => 'Choose year', :month => 'Choose month', :day => 'Choose day', :hour => 'Choose hour', :minute => 'Choose minute'}) + assert_dom_equal expected, datetime_select("post", "updated_at", start_year: 1999, end_year: 2009, prompt: { year: "Choose year", month: "Choose month", day: "Choose day", hour: "Choose hour", minute: "Choose minute" }) end def test_datetime_select_with_generic_with_css_classes @@ -2894,7 +2899,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n} expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "written_on", start_year: 1999, end_year: 2009, with_css_classes: { year: 'my-year', month: 'my-month', day: 'my-day', hour: 'my-hour', minute: 'my-minute' }) + assert_dom_equal expected, datetime_select("post", "written_on", start_year: 1999, end_year: 2009, with_css_classes: { year: "my-year", month: "my-month", day: "my-day", hour: "my-hour", minute: "my-minute" }) end def test_date_select_with_zero_value_and_no_start_year @@ -2910,7 +2915,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(0, :end_year => Date.today.year+1, :prefix => "date[first]") + assert_dom_equal expected, select_date(0, end_year: Date.today.year+1, prefix: "date[first]") end def test_date_select_with_zero_value_and_no_end_year @@ -2927,7 +2932,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(0, :start_year => 2003, :prefix => "date[first]") + assert_dom_equal expected, select_date(0, start_year: 2003, prefix: "date[first]") end def test_date_select_with_zero_value_and_no_start_and_end_year @@ -2943,7 +2948,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(0, :prefix => "date[first]") + assert_dom_equal expected, select_date(0, prefix: "date[first]") end def test_date_select_with_nil_value_and_no_start_and_end_year @@ -2959,7 +2964,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_date(nil, :prefix => "date[first]") + assert_dom_equal expected, select_date(nil, prefix: "date[first]") end def test_datetime_select_with_nil_value_and_no_start_and_end_year @@ -2987,7 +2992,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_datetime(nil, :prefix => "date[first]") + assert_dom_equal expected, select_datetime(nil, prefix: "date[first]") end def test_datetime_select_with_options_index @@ -3017,7 +3022,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35" selected="selected">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n} expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :index => id) + assert_dom_equal expected, datetime_select("post", "updated_at", index: id) end def test_datetime_select_within_fields_for_with_options_index @@ -3025,7 +3030,7 @@ class DateHelperTest < ActionView::TestCase @post.updated_at = Time.local(2004, 6, 15, 16, 35) id = 456 - output_buffer = fields_for :post, @post, :index => id do |f| + output_buffer = fields_for :post, @post, index: id do |f| concat f.datetime_select(:updated_at) end @@ -3112,7 +3117,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 35}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :include_seconds => true) + assert_dom_equal expected, datetime_select("post", "updated_at", include_seconds: true) end def test_datetime_select_discard_year @@ -3137,7 +3142,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :discard_year => true) + assert_dom_equal expected, datetime_select("post", "updated_at", discard_year: true) end def test_datetime_select_discard_month @@ -3160,7 +3165,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :discard_month => true) + assert_dom_equal expected, datetime_select("post", "updated_at", discard_month: true) end def test_datetime_select_discard_year_and_month @@ -3179,7 +3184,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :discard_year => true, :discard_month => true) + assert_dom_equal expected, datetime_select("post", "updated_at", discard_year: true, discard_month: true) end def test_datetime_select_discard_year_and_month_with_disabled_html_option @@ -3198,7 +3203,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", { :discard_year => true, :discard_month => true }, :disabled => true) + assert_dom_equal expected, datetime_select("post", "updated_at", { discard_year: true, discard_month: true }, disabled: true) end def test_datetime_select_discard_hour @@ -3215,7 +3220,7 @@ class DateHelperTest < ActionView::TestCase 1.upto(31) { |i| expected << %(<option value="#{i}"#{' selected="selected"' if i == 15}>#{i}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :discard_hour => true) + assert_dom_equal expected, datetime_select("post", "updated_at", discard_hour: true) end def test_datetime_select_discard_minute @@ -3239,7 +3244,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" expected << %{<input type="hidden" id="post_updated_at_5i" name="post[updated_at(5i)]" value="16" />\n} - assert_dom_equal expected, datetime_select("post", "updated_at", :discard_minute => true) + assert_dom_equal expected, datetime_select("post", "updated_at", discard_minute: true) end def test_datetime_select_disabled_and_discard_minute @@ -3263,7 +3268,7 @@ class DateHelperTest < ActionView::TestCase expected << "</select>\n" expected << %{<input type="hidden" id="post_updated_at_5i" disabled="disabled" name="post[updated_at(5i)]" value="16" />\n} - assert_dom_equal expected, datetime_select("post", "updated_at", :discard_minute => true, :disabled => true) + assert_dom_equal expected, datetime_select("post", "updated_at", discard_minute: true, disabled: true) end def test_datetime_select_invalid_order @@ -3290,7 +3295,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :order => [:minute, :day, :hour, :month, :year, :second]) + assert_dom_equal expected, datetime_select("post", "updated_at", order: [:minute, :day, :hour, :month, :year, :second]) end def test_datetime_select_discard_with_order @@ -3315,7 +3320,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :order => [:day, :month]) + assert_dom_equal expected, datetime_select("post", "updated_at", order: [:day, :month]) end def test_datetime_select_with_default_value_as_time @@ -3342,7 +3347,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 16}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :default => Time.local(2006, 9, 19, 15, 16, 35)) + assert_dom_equal expected, datetime_select("post", "updated_at", default: Time.local(2006, 9, 19, 15, 16, 35)) end def test_include_blank_overrides_default_option @@ -3362,7 +3367,7 @@ class DateHelperTest < ActionView::TestCase 1.upto(31) { |i| expected << %(<option value="#{i}">#{i}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, date_select("post", "updated_at", :default => Time.local(2006, 9, 19, 15, 16, 35), :include_blank => true) + assert_dom_equal expected, date_select("post", "updated_at", default: Time.local(2006, 9, 19, 15, 16, 35), include_blank: true) end def test_datetime_select_with_default_value_as_hash @@ -3389,7 +3394,7 @@ class DateHelperTest < ActionView::TestCase 0.upto(59) { |i| expected << %(<option value="#{sprintf("%02d", i)}"#{' selected="selected"' if i == 42}>#{sprintf("%02d", i)}</option>\n) } expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", :default => { :month => 10, :minute => 42, :hour => 9 }) + assert_dom_equal expected, datetime_select("post", "updated_at", default: { month: 10, minute: 42, hour: 9 }) end def test_datetime_select_with_html_options @@ -3418,7 +3423,7 @@ class DateHelperTest < ActionView::TestCase expected << %{<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35" selected="selected">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n} expected << "</select>\n" - assert_dom_equal expected, datetime_select("post", "updated_at", {}, :class => 'selector') + assert_dom_equal expected, datetime_select("post", "updated_at", {}, class: "selector") end def test_date_select_should_not_change_passed_options_hash @@ -3426,24 +3431,24 @@ class DateHelperTest < ActionView::TestCase @post.updated_at = Time.local(2008, 7, 16, 23, 30) options = { - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true } date_select(@post, :updated_at, options) # note: the literal hash is intentional to show that the actual options hash isn't modified # don't change this! assert_equal({ - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true }, options) end @@ -3452,24 +3457,24 @@ class DateHelperTest < ActionView::TestCase @post.updated_at = Time.local(2008, 7, 16, 23, 30) options = { - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true } datetime_select(@post, :updated_at, options) # note: the literal hash is intentional to show that the actual options hash isn't modified # don't change this! assert_equal({ - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true }, options) end @@ -3478,93 +3483,93 @@ class DateHelperTest < ActionView::TestCase @post.updated_at = Time.local(2008, 7, 16, 23, 30) options = { - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true } time_select(@post, :updated_at, options) # note: the literal hash is intentional to show that the actual options hash isn't modified # don't change this! assert_equal({ - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true }, options) end def test_select_date_should_not_change_passed_options_hash options = { - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true } select_date(Date.today, options) # note: the literal hash is intentional to show that the actual options hash isn't modified # don't change this! assert_equal({ - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true }, options) end def test_select_datetime_should_not_change_passed_options_hash options = { - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true } select_datetime(Time.now, options) # note: the literal hash is intentional to show that the actual options hash isn't modified # don't change this! assert_equal({ - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true }, options) end def test_select_time_should_not_change_passed_options_hash options = { - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true } select_time(Time.now, options) # note: the literal hash is intentional to show that the actual options hash isn't modified # don't change this! assert_equal({ - :order => [ :year, :month, :day ], - :default => { :year => 2008, :month => 7, :day => 16, :hour => 23, :minute => 30, :second => 1 }, - :discard_type => false, - :include_blank => false, - :ignore_date => false, - :include_seconds => true + order: [ :year, :month, :day ], + default: { year: 2008, month: 7, day: 16, hour: 23, minute: 30, second: 1 }, + discard_type: false, + include_blank: false, + ignore_date: false, + include_seconds: true }, options) end @@ -3575,19 +3580,19 @@ class DateHelperTest < ActionView::TestCase assert select_minute(Time.mktime(2003, 8, 16, 8, 4, 18)).html_safe? assert select_second(Time.mktime(2003, 8, 16, 8, 4, 18)).html_safe? - assert select_minute(8, :use_hidden => true).html_safe? - assert select_month(8, :prompt => 'Choose month').html_safe? + assert select_minute(8, use_hidden: true).html_safe? + assert select_month(8, prompt: "Choose month").html_safe? - assert select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {}, :class => 'selector').html_safe? - assert select_date(Time.mktime(2003, 8, 16), :date_separator => " / ", :start_year => 2003, :end_year => 2005, :prefix => "date[first]").html_safe? + assert select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {}, class: "selector").html_safe? + assert select_date(Time.mktime(2003, 8, 16), date_separator: " / ", start_year: 2003, end_year: 2005, prefix: "date[first]").html_safe? end def test_object_select_html_safety @post = Post.new @post.written_on = Date.new(2004, 6, 15) - assert date_select("post", "written_on", :default => Time.local(2006, 9, 19, 15, 16, 35), :include_blank => true).html_safe? - assert time_select("post", "written_on", :ignore_date => true).html_safe? + assert date_select("post", "written_on", default: Time.local(2006, 9, 19, 15, 16, 35), include_blank: true).html_safe? + assert time_select("post", "written_on", ignore_date: true).html_safe? end def test_time_tag_with_date @@ -3597,26 +3602,22 @@ class DateHelperTest < ActionView::TestCase end def test_time_tag_with_time - time = Time.new(2013, 2, 20, 0, 0, 0, '+00:00') + time = Time.new(2013, 2, 20, 0, 0, 0, "+00:00") expected = '<time datetime="2013-02-20T00:00:00+00:00">February 20, 2013 00:00</time>' assert_equal expected, time_tag(time) end - def test_time_tag_pubdate_option - assert_match(/<time.*pubdate="pubdate">.*<\/time>/, time_tag(Time.now, :pubdate => true)) - end - def test_time_tag_with_given_text - assert_match(/<time.*>Right now<\/time>/, time_tag(Time.now, 'Right now')) + assert_match(/<time.*>Right now<\/time>/, time_tag(Time.now, "Right now")) end def test_time_tag_with_given_block - assert_match(/<time.*><span>Right now<\/span><\/time>/, time_tag(Time.now){ raw('<span>Right now</span>') }) + assert_match(/<time.*><span>Right now<\/span><\/time>/, time_tag(Time.now) { raw("<span>Right now</span>") }) end def test_time_tag_with_different_format - time = Time.new(2013, 2, 20, 0, 0, 0, '+00:00') + time = Time.new(2013, 2, 20, 0, 0, 0, "+00:00") expected = '<time datetime="2013-02-20T00:00:00+00:00">20 Feb 00:00</time>' - assert_equal expected, time_tag(time, :format => :short) + assert_equal expected, time_tag(time, format: :short) end end diff --git a/actionview/test/template/dependency_tracker_test.rb b/actionview/test/template/dependency_tracker_test.rb index 3ece9e50cd..89917035ff 100644 --- a/actionview/test/template/dependency_tracker_test.rb +++ b/actionview/test/template/dependency_tracker_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_view/dependency_tracker' +require "abstract_unit" +require "action_view/dependency_tracker" class NeckbeardTracker def self.call(name, template) @@ -15,8 +15,8 @@ class FakeTemplate end end -Neckbeard = lambda {|template| template.source } -Bowtie = lambda {|template| template.source } +Neckbeard = lambda { |template| template.source } +Bowtie = lambda { |template| template.source } class DependencyTrackerTest < ActionView::TestCase def tracker diff --git a/actionview/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb index 410f562f07..093ff28c14 100644 --- a/actionview/test/template/digestor_test.rb +++ b/actionview/test/template/digestor_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'fileutils' -require 'action_view/dependency_tracker' +require "abstract_unit" +require "fileutils" +require "action_view/dependency_tracker" class FixtureTemplate attr_reader :source, :handler @@ -17,7 +17,7 @@ class FixtureFinder < ActionView::LookupContext FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor" def initialize(details = {}) - super(ActionView::PathSet.new(['digestor', 'digestor/api']), details, []) + super(ActionView::PathSet.new(["digestor", "digestor/api"]), details, []) @rendered_format = :html end end @@ -135,12 +135,12 @@ class TemplateDigestorTest < ActionView::TestCase def test_getting_of_singly_nested_dependencies singly_nested_dependencies = ["messages/header", "messages/form", "messages/message", "events/event", "comments/comment"] - assert_equal singly_nested_dependencies, nested_dependencies('messages/edit') + assert_equal singly_nested_dependencies, nested_dependencies("messages/edit") end def test_getting_of_doubly_nested_dependencies - doubly_nested = [{"comments/comments"=>["comments/comment"]}, "messages/message"] - assert_equal doubly_nested, nested_dependencies('messages/peek') + doubly_nested = [{ "comments/comments"=>["comments/comment"] }, "messages/message"] + assert_equal doubly_nested, nested_dependencies("messages/peek") end def test_nested_template_directory @@ -150,13 +150,13 @@ class TemplateDigestorTest < ActionView::TestCase end def test_nested_template_deps - nested_deps = ["messages/header", {"comments/comments"=>["comments/comment"]}, "messages/actions/move", "events/event", "messages/something_missing", "messages/something_missing_1", "messages/message", "messages/form"] + nested_deps = ["messages/header", { "comments/comments"=>["comments/comment"] }, "messages/actions/move", "events/event", "messages/something_missing", "messages/something_missing_1", "messages/message", "messages/form"] assert_equal nested_deps, nested_dependencies("messages/show") end def test_nested_template_deps_with_non_default_rendered_format finder.rendered_format = nil - nested_deps = [{"comments/comments"=>["comments/comment"]}] + nested_deps = [{ "comments/comments"=>["comments/comment"] }] assert_equal nested_deps, nested_dependencies("messages/thread") end @@ -195,7 +195,7 @@ class TemplateDigestorTest < ActionView::TestCase end def test_dont_generate_a_digest_for_missing_templates - assert_equal '', digest("nothing/there") + assert_equal "", digest("nothing/there") end def test_collection_dependency @@ -216,7 +216,7 @@ class TemplateDigestorTest < ActionView::TestCase def test_details_are_included_in_cache_key # Cache the template digest. - @finder = FixtureFinder.new({:formats => [:html]}) + @finder = FixtureFinder.new(formats: [:html]) old_digest = digest("events/_event") # Change the template; the cached digest remains unchanged. diff --git a/actionview/test/template/erb_util_test.rb b/actionview/test/template/erb_util_test.rb index 3e72be31de..0a16364ed3 100644 --- a/actionview/test/template/erb_util_test.rb +++ b/actionview/test/template/erb_util_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/json' +require "abstract_unit" +require "active_support/json" class ErbUtilTest < ActiveSupport::TestCase include ERB::Util @@ -17,19 +17,19 @@ class ErbUtilTest < ActiveSupport::TestCase end HTML_ESCAPE_TEST_CASES = [ - ['<br>', '<br>'], - ['a & b', 'a & b'], - ['"quoted" string', '"quoted" string'], - ["'quoted' string", ''quoted' string'], + ["<br>", "<br>"], + ["a & b", "a & b"], + ['"quoted" string', ""quoted" string"], + ["'quoted' string", "'quoted' string"], [ '<script type="application/javascript">alert("You are \'pwned\'!")</script>', - '<script type="application/javascript">alert("You are 'pwned'!")</script>' + "<script type="application/javascript">alert("You are 'pwned'!")</script>" ] ] JSON_ESCAPE_TEST_CASES = [ - ['1', '1'], - ['null', 'null'], + ["1", "1"], + ["null", "null"], ['"&"', '"\u0026"'], ['"</script>"', '"\u003c/script\u003e"'], ['["</script>"]', '["\u003c/script\u003e"]'], @@ -91,17 +91,17 @@ class ErbUtilTest < ActiveSupport::TestCase end def test_html_escape_once - assert_equal '1 <>&"' 2 & 3', html_escape_once('1 <>&"\' 2 & 3') + assert_equal "1 <>&"' 2 & 3", html_escape_once('1 <>&"\' 2 & 3') assert_equal " ' ' λ λ " ' < > ", html_escape_once(" ' ' λ λ \" ' < > ") end def test_html_escape_once_returns_unsafe_strings_when_passed_unsafe_strings - value = html_escape_once('1 < 2 & 3') + value = html_escape_once("1 < 2 & 3") assert !value.html_safe? end def test_html_escape_once_returns_safe_strings_when_passed_safe_strings - value = html_escape_once('1 < 2 & 3'.html_safe) + value = html_escape_once("1 < 2 & 3".html_safe) assert value.html_safe? end end diff --git a/actionview/test/template/form_collections_helper_test.rb b/actionview/test/template/form_collections_helper_test.rb index 4f7ea88169..3774dcf872 100644 --- a/actionview/test/template/form_collections_helper_test.rb +++ b/actionview/test/template/form_collections_helper_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' +require "abstract_unit" class Category < Struct.new(:id, :name) end class FormCollectionsHelperTest < ActionView::TestCase def assert_no_select(selector, value = nil) - assert_select(selector, :text => value, :count => 0) + assert_select(selector, text: value, count: 0) end def with_collection_radio_buttons(*args, &block) @@ -17,170 +17,170 @@ class FormCollectionsHelperTest < ActionView::TestCase end # COLLECTION RADIO BUTTONS - test 'collection radio accepts a collection and generates inputs from value method' do + test "collection radio accepts a collection and generates inputs from value method" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s - assert_select 'input[type=radio][value=true]#user_active_true' - assert_select 'input[type=radio][value=false]#user_active_false' + assert_select "input[type=radio][value=true]#user_active_true" + assert_select "input[type=radio][value=false]#user_active_false" end - test 'collection radio accepts a collection and generates inputs from label method' do + test "collection radio accepts a collection and generates inputs from label method" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s - assert_select 'label[for=user_active_true]', 'true' - assert_select 'label[for=user_active_false]', 'false' + assert_select "label[for=user_active_true]", "true" + assert_select "label[for=user_active_false]", "false" end - test 'collection radio handles camelized collection values for labels correctly' do - with_collection_radio_buttons :user, :active, ['Yes', 'No'], :to_s, :to_s + test "collection radio handles camelized collection values for labels correctly" do + with_collection_radio_buttons :user, :active, ["Yes", "No"], :to_s, :to_s - assert_select 'label[for=user_active_yes]', 'Yes' - assert_select 'label[for=user_active_no]', 'No' + assert_select "label[for=user_active_yes]", "Yes" + assert_select "label[for=user_active_no]", "No" end - test 'collection radio should sanitize collection values for labels correctly' do - with_collection_radio_buttons :user, :name, ['$0.99', '$1.99'], :to_s, :to_s - assert_select 'label[for=user_name_099]', '$0.99' - assert_select 'label[for=user_name_199]', '$1.99' + test "collection radio should sanitize collection values for labels correctly" do + with_collection_radio_buttons :user, :name, ["$0.99", "$1.99"], :to_s, :to_s + assert_select "label[for=user_name_099]", "$0.99" + assert_select "label[for=user_name_199]", "$1.99" end - test 'collection radio accepts checked item' do - with_collection_radio_buttons :user, :active, [[1, true], [0, false]], :last, :first, :checked => true + test "collection radio accepts checked item" do + with_collection_radio_buttons :user, :active, [[1, true], [0, false]], :last, :first, checked: true - assert_select 'input[type=radio][value=true][checked=checked]' - assert_no_select 'input[type=radio][value=false][checked=checked]' + assert_select "input[type=radio][value=true][checked=checked]" + assert_no_select "input[type=radio][value=false][checked=checked]" end - test 'collection radio accepts multiple disabled items' do - collection = [[1, true], [0, false], [2, 'other']] - with_collection_radio_buttons :user, :active, collection, :last, :first, :disabled => [true, false] + test "collection radio accepts multiple disabled items" do + collection = [[1, true], [0, false], [2, "other"]] + with_collection_radio_buttons :user, :active, collection, :last, :first, disabled: [true, false] - assert_select 'input[type=radio][value=true][disabled=disabled]' - assert_select 'input[type=radio][value=false][disabled=disabled]' - assert_no_select 'input[type=radio][value=other][disabled=disabled]' + assert_select "input[type=radio][value=true][disabled=disabled]" + assert_select "input[type=radio][value=false][disabled=disabled]" + assert_no_select "input[type=radio][value=other][disabled=disabled]" end - test 'collection radio accepts single disabled item' do + test "collection radio accepts single disabled item" do collection = [[1, true], [0, false]] - with_collection_radio_buttons :user, :active, collection, :last, :first, :disabled => true + with_collection_radio_buttons :user, :active, collection, :last, :first, disabled: true - assert_select 'input[type=radio][value=true][disabled=disabled]' - assert_no_select 'input[type=radio][value=false][disabled=disabled]' + assert_select "input[type=radio][value=true][disabled=disabled]" + assert_no_select "input[type=radio][value=false][disabled=disabled]" end - test 'collection radio accepts multiple readonly items' do - collection = [[1, true], [0, false], [2, 'other']] - with_collection_radio_buttons :user, :active, collection, :last, :first, :readonly => [true, false] + test "collection radio accepts multiple readonly items" do + collection = [[1, true], [0, false], [2, "other"]] + with_collection_radio_buttons :user, :active, collection, :last, :first, readonly: [true, false] - assert_select 'input[type=radio][value=true][readonly=readonly]' - assert_select 'input[type=radio][value=false][readonly=readonly]' - assert_no_select 'input[type=radio][value=other][readonly=readonly]' + assert_select "input[type=radio][value=true][readonly=readonly]" + assert_select "input[type=radio][value=false][readonly=readonly]" + assert_no_select "input[type=radio][value=other][readonly=readonly]" end - test 'collection radio accepts single readonly item' do + test "collection radio accepts single readonly item" do collection = [[1, true], [0, false]] - with_collection_radio_buttons :user, :active, collection, :last, :first, :readonly => true + with_collection_radio_buttons :user, :active, collection, :last, :first, readonly: true - assert_select 'input[type=radio][value=true][readonly=readonly]' - assert_no_select 'input[type=radio][value=false][readonly=readonly]' + assert_select "input[type=radio][value=true][readonly=readonly]" + assert_no_select "input[type=radio][value=false][readonly=readonly]" end - test 'collection radio accepts html options as input' do + test "collection radio accepts html options as input" do collection = [[1, true], [0, false]] - with_collection_radio_buttons :user, :active, collection, :last, :first, {}, :class => 'special-radio' + with_collection_radio_buttons :user, :active, collection, :last, :first, {}, class: "special-radio" - assert_select 'input[type=radio][value=true].special-radio#user_active_true' - assert_select 'input[type=radio][value=false].special-radio#user_active_false' + assert_select "input[type=radio][value=true].special-radio#user_active_true" + assert_select "input[type=radio][value=false].special-radio#user_active_false" end - test 'collection radio accepts html options as the last element of array' do - collection = [[1, true, {class: 'foo'}], [0, false, {class: 'bar'}]] + test "collection radio accepts html options as the last element of array" do + collection = [[1, true, { class: "foo" }], [0, false, { class: "bar" }]] with_collection_radio_buttons :user, :active, collection, :second, :first - assert_select 'input[type=radio][value=true].foo#user_active_true' - assert_select 'input[type=radio][value=false].bar#user_active_false' + assert_select "input[type=radio][value=true].foo#user_active_true" + assert_select "input[type=radio][value=false].bar#user_active_false" end - test 'collection radio sets the label class defined inside the block' do - collection = [[1, true, {class: 'foo'}], [0, false, {class: 'bar'}]] + test "collection radio sets the label class defined inside the block" do + collection = [[1, true, { class: "foo" }], [0, false, { class: "bar" }]] with_collection_radio_buttons :user, :active, collection, :second, :first do |b| b.label(class: "collection_radio_buttons") end - assert_select 'label.collection_radio_buttons[for=user_active_true]' - assert_select 'label.collection_radio_buttons[for=user_active_false]' + assert_select "label.collection_radio_buttons[for=user_active_true]" + assert_select "label.collection_radio_buttons[for=user_active_false]" end - test 'collection radio does not include the input class in the respective label' do - collection = [[1, true, {class: 'foo'}], [0, false, {class: 'bar'}]] + test "collection radio does not include the input class in the respective label" do + collection = [[1, true, { class: "foo" }], [0, false, { class: "bar" }]] with_collection_radio_buttons :user, :active, collection, :second, :first - assert_no_select 'label.foo[for=user_active_true]' - assert_no_select 'label.bar[for=user_active_false]' + assert_no_select "label.foo[for=user_active_true]" + assert_no_select "label.bar[for=user_active_false]" end - test 'collection radio does not wrap input inside the label' do + test "collection radio does not wrap input inside the label" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s - assert_select 'input[type=radio] + label' - assert_no_select 'label input' + assert_select "input[type=radio] + label" + assert_no_select "label input" end - test 'collection radio accepts a block to render the label as radio button wrapper' do + test "collection radio accepts a block to render the label as radio button wrapper" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| b.label { b.radio_button } end - assert_select 'label[for=user_active_true] > input#user_active_true[type=radio]' - assert_select 'label[for=user_active_false] > input#user_active_false[type=radio]' + assert_select "label[for=user_active_true] > input#user_active_true[type=radio]" + assert_select "label[for=user_active_false] > input#user_active_false[type=radio]" end - test 'collection radio accepts a block to change the order of label and radio button' do + test "collection radio accepts a block to change the order of label and radio button" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| b.label + b.radio_button end - assert_select 'label[for=user_active_true] + input#user_active_true[type=radio]' - assert_select 'label[for=user_active_false] + input#user_active_false[type=radio]' + assert_select "label[for=user_active_true] + input#user_active_true[type=radio]" + assert_select "label[for=user_active_false] + input#user_active_false[type=radio]" end - test 'collection radio with block helpers accept extra html options' do + test "collection radio with block helpers accept extra html options" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| - b.label(:class => "radio_button") + b.radio_button(:class => "radio_button") + b.label(class: "radio_button") + b.radio_button(class: "radio_button") end - assert_select 'label.radio_button[for=user_active_true] + input#user_active_true.radio_button[type=radio]' - assert_select 'label.radio_button[for=user_active_false] + input#user_active_false.radio_button[type=radio]' + assert_select "label.radio_button[for=user_active_true] + input#user_active_true.radio_button[type=radio]" + assert_select "label.radio_button[for=user_active_false] + input#user_active_false.radio_button[type=radio]" end - test 'collection radio with block helpers allows access to current text and value' do + test "collection radio with block helpers allows access to current text and value" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| - b.label(:"data-value" => b.value) { b.radio_button + b.text } + b.label("data-value": b.value) { b.radio_button + b.text } end - assert_select 'label[for=user_active_true][data-value=true]', 'true' do - assert_select 'input#user_active_true[type=radio]' + assert_select "label[for=user_active_true][data-value=true]", "true" do + assert_select "input#user_active_true[type=radio]" end - assert_select 'label[for=user_active_false][data-value=false]', 'false' do - assert_select 'input#user_active_false[type=radio]' + assert_select "label[for=user_active_false][data-value=false]", "false" do + assert_select "input#user_active_false[type=radio]" end end - test 'collection radio with block helpers allows access to the current object item in the collection to access extra properties' do + test "collection radio with block helpers allows access to the current object item in the collection to access extra properties" do with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| - b.label(:class => b.object) { b.radio_button + b.text } + b.label(class: b.object) { b.radio_button + b.text } end - assert_select 'label.true[for=user_active_true]', 'true' do - assert_select 'input#user_active_true[type=radio]' + assert_select "label.true[for=user_active_true]", "true" do + assert_select "input#user_active_true[type=radio]" end - assert_select 'label.false[for=user_active_false]', 'false' do - assert_select 'input#user_active_false[type=radio]' + assert_select "label.false[for=user_active_false]", "false" do + assert_select "input#user_active_false[type=radio]" end end - test 'collection radio buttons with fields for' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection radio buttons with fields for" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] @output_buffer = fields_for(:post) do |p| p.collection_radio_buttons :category_id, collection, :id, :name end @@ -188,186 +188,186 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_select 'input#post_category_id_1[type=radio][value="1"]' assert_select 'input#post_category_id_2[type=radio][value="2"]' - assert_select 'label[for=post_category_id_1]', 'Category 1' - assert_select 'label[for=post_category_id_2]', 'Category 2' + assert_select "label[for=post_category_id_1]", "Category 1" + assert_select "label[for=post_category_id_2]", "Category 2" end - test 'collection radio accepts checked item which has a value of false' do - with_collection_radio_buttons :user, :active, [[1, true], [0, false]], :last, :first, :checked => false - assert_no_select 'input[type=radio][value=true][checked=checked]' - assert_select 'input[type=radio][value=false][checked=checked]' + test "collection radio accepts checked item which has a value of false" do + with_collection_radio_buttons :user, :active, [[1, true], [0, false]], :last, :first, checked: false + assert_no_select "input[type=radio][value=true][checked=checked]" + assert_select "input[type=radio][value=false][checked=checked]" end - test 'collection radio buttons generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection radio buttons generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] with_collection_radio_buttons :user, :category_ids, collection, :id, :name assert_select "input[type=hidden][name='user[category_ids]'][value='']", count: 1 end - test 'collection radio buttons generates a hidden field using the given :name in :html_options' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] - with_collection_radio_buttons :user, :category_ids, collection, :id, :name, {}, { name: "user[other_category_ids]" } + test "collection radio buttons generates a hidden field using the given :name in :html_options" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name, {}, name: "user[other_category_ids]" assert_select "input[type=hidden][name='user[other_category_ids]'][value='']", count: 1 end - test 'collection radio buttons generates a hidden field with index if it was provided' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] - with_collection_radio_buttons :user, :category_ids, collection, :id, :name, { index: 322 } + test "collection radio buttons generates a hidden field with index if it was provided" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name, index: 322 assert_select "input[type=hidden][name='user[322][category_ids]'][value='']", count: 1 end - test 'collection radio buttons does not generate a hidden field if include_hidden option is false' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection radio buttons does not generate a hidden field if include_hidden option is false" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] with_collection_radio_buttons :user, :category_ids, collection, :id, :name, include_hidden: false assert_select "input[type=hidden][name='user[category_ids]'][value='']", count: 0 end - test 'collection radio buttons does not generate a hidden field if include_hidden option is false with key as string' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] - with_collection_radio_buttons :user, :category_ids, collection, :id, :name, 'include_hidden' => false + test "collection radio buttons does not generate a hidden field if include_hidden option is false with key as string" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name, "include_hidden" => false assert_select "input[type=hidden][name='user[category_ids]'][value='']", count: 0 end # COLLECTION CHECK BOXES - test 'collection check boxes accepts a collection and generate a series of checkboxes for value method' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection check boxes accepts a collection and generate a series of checkboxes for value method" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] with_collection_check_boxes :user, :category_ids, collection, :id, :name assert_select 'input#user_category_ids_1[type=checkbox][value="1"]' assert_select 'input#user_category_ids_2[type=checkbox][value="2"]' end - test 'collection check boxes generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection check boxes generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] with_collection_check_boxes :user, :category_ids, collection, :id, :name - assert_select "input[type=hidden][name='user[category_ids][]'][value='']", :count => 1 + assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 1 end - test 'collection check boxes generates a hidden field using the given :name in :html_options' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] - with_collection_check_boxes :user, :category_ids, collection, :id, :name, {}, {name: "user[other_category_ids][]"} + test "collection check boxes generates a hidden field using the given :name in :html_options" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] + with_collection_check_boxes :user, :category_ids, collection, :id, :name, {}, name: "user[other_category_ids][]" - assert_select "input[type=hidden][name='user[other_category_ids][]'][value='']", :count => 1 + assert_select "input[type=hidden][name='user[other_category_ids][]'][value='']", count: 1 end - test 'collection check boxes generates a hidden field with index if it was provided' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] - with_collection_check_boxes :user, :category_ids, collection, :id, :name, { index: 322 } + test "collection check boxes generates a hidden field with index if it was provided" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] + with_collection_check_boxes :user, :category_ids, collection, :id, :name, index: 322 assert_select "input[type=hidden][name='user[322][category_ids][]'][value='']", count: 1 end - test 'collection check boxes does not generate a hidden field if include_hidden option is false' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection check boxes does not generate a hidden field if include_hidden option is false" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] with_collection_check_boxes :user, :category_ids, collection, :id, :name, include_hidden: false - assert_select "input[type=hidden][name='user[category_ids][]'][value='']", :count => 0 + assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0 end - test 'collection check boxes does not generate a hidden field if include_hidden option is false with key as string' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] - with_collection_check_boxes :user, :category_ids, collection, :id, :name, 'include_hidden' => false + test "collection check boxes does not generate a hidden field if include_hidden option is false with key as string" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] + with_collection_check_boxes :user, :category_ids, collection, :id, :name, "include_hidden" => false assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0 end - test 'collection check boxes accepts a collection and generate a series of checkboxes with labels for label method' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection check boxes accepts a collection and generate a series of checkboxes with labels for label method" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] with_collection_check_boxes :user, :category_ids, collection, :id, :name - assert_select 'label[for=user_category_ids_1]', 'Category 1' - assert_select 'label[for=user_category_ids_2]', 'Category 2' + assert_select "label[for=user_category_ids_1]", "Category 1" + assert_select "label[for=user_category_ids_2]", "Category 2" end - test 'collection check boxes handles camelized collection values for labels correctly' do - with_collection_check_boxes :user, :active, ['Yes', 'No'], :to_s, :to_s + test "collection check boxes handles camelized collection values for labels correctly" do + with_collection_check_boxes :user, :active, ["Yes", "No"], :to_s, :to_s - assert_select 'label[for=user_active_yes]', 'Yes' - assert_select 'label[for=user_active_no]', 'No' + assert_select "label[for=user_active_yes]", "Yes" + assert_select "label[for=user_active_no]", "No" end - test 'collection check box should sanitize collection values for labels correctly' do - with_collection_check_boxes :user, :name, ['$0.99', '$1.99'], :to_s, :to_s - assert_select 'label[for=user_name_099]', '$0.99' - assert_select 'label[for=user_name_199]', '$1.99' + test "collection check box should sanitize collection values for labels correctly" do + with_collection_check_boxes :user, :name, ["$0.99", "$1.99"], :to_s, :to_s + assert_select "label[for=user_name_099]", "$0.99" + assert_select "label[for=user_name_199]", "$1.99" end - test 'collection check boxes accepts html options as the last element of array' do - collection = [[1, 'Category 1', {class: 'foo'}], [2, 'Category 2', {class: 'bar'}]] + test "collection check boxes accepts html options as the last element of array" do + collection = [[1, "Category 1", { class: "foo" }], [2, "Category 2", { class: "bar" }]] with_collection_check_boxes :user, :active, collection, :first, :second assert_select 'input[type=checkbox][value="1"].foo' assert_select 'input[type=checkbox][value="2"].bar' end - test 'collection check boxes propagates input id to the label for attribute' do - collection = [[1, 'Category 1', {id: 'foo'}], [2, 'Category 2', {id: 'bar'}]] + test "collection check boxes propagates input id to the label for attribute" do + collection = [[1, "Category 1", { id: "foo" }], [2, "Category 2", { id: "bar" }]] with_collection_check_boxes :user, :active, collection, :first, :second assert_select 'input[type=checkbox][value="1"]#foo' assert_select 'input[type=checkbox][value="2"]#bar' - assert_select 'label[for=foo]' - assert_select 'label[for=bar]' + assert_select "label[for=foo]" + assert_select "label[for=bar]" end - test 'collection check boxes sets the label class defined inside the block' do - collection = [[1, 'Category 1', {class: 'foo'}], [2, 'Category 2', {class: 'bar'}]] + test "collection check boxes sets the label class defined inside the block" do + collection = [[1, "Category 1", { class: "foo" }], [2, "Category 2", { class: "bar" }]] with_collection_check_boxes :user, :active, collection, :second, :first do |b| - b.label(class: 'collection_check_boxes') + b.label(class: "collection_check_boxes") end - assert_select 'label.collection_check_boxes[for=user_active_category_1]' - assert_select 'label.collection_check_boxes[for=user_active_category_2]' + assert_select "label.collection_check_boxes[for=user_active_category_1]" + assert_select "label.collection_check_boxes[for=user_active_category_2]" end - test 'collection check boxes does not include the input class in the respective label' do - collection = [[1, 'Category 1', {class: 'foo'}], [2, 'Category 2', {class: 'bar'}]] + test "collection check boxes does not include the input class in the respective label" do + collection = [[1, "Category 1", { class: "foo" }], [2, "Category 2", { class: "bar" }]] with_collection_check_boxes :user, :active, collection, :second, :first - assert_no_select 'label.foo[for=user_active_category_1]' - assert_no_select 'label.bar[for=user_active_category_2]' + assert_no_select "label.foo[for=user_active_category_1]" + assert_no_select "label.bar[for=user_active_category_2]" end - test 'collection check boxes accepts selected values as :checked option' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => [1, 3] + test "collection check boxes accepts selected values as :checked option" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, checked: [1, 3] assert_select 'input[type=checkbox][value="1"][checked=checked]' assert_select 'input[type=checkbox][value="3"][checked=checked]' assert_no_select 'input[type=checkbox][value="2"][checked=checked]' end - test 'collection check boxes accepts selected string values as :checked option' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => ['1', '3'] + test "collection check boxes accepts selected string values as :checked option" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, checked: ["1", "3"] assert_select 'input[type=checkbox][value="1"][checked=checked]' assert_select 'input[type=checkbox][value="3"][checked=checked]' assert_no_select 'input[type=checkbox][value="2"][checked=checked]' end - test 'collection check boxes accepts a single checked value' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => 3 + test "collection check boxes accepts a single checked value" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, checked: 3 assert_select 'input[type=checkbox][value="3"][checked=checked]' assert_no_select 'input[type=checkbox][value="1"][checked=checked]' assert_no_select 'input[type=checkbox][value="2"][checked=checked]' end - test 'collection check boxes accepts selected values as :checked option and override the model values' do + test "collection check boxes accepts selected values as :checked option and override the model values" do user = Struct.new(:category_ids).new(2) - collection = (1..3).map{|i| [i, "Category #{i}"] } + collection = (1..3).map { |i| [i, "Category #{i}"] } @output_buffer = fields_for(:user, user) do |p| - p.collection_check_boxes :category_ids, collection, :first, :last, :checked => [1, 3] + p.collection_check_boxes :category_ids, collection, :first, :last, checked: [1, 3] end assert_select 'input[type=checkbox][value="1"][checked=checked]' @@ -375,70 +375,70 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_no_select 'input[type=checkbox][value="2"][checked=checked]' end - test 'collection check boxes accepts multiple disabled items' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => [1, 3] + test "collection check boxes accepts multiple disabled items" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, disabled: [1, 3] assert_select 'input[type=checkbox][value="1"][disabled=disabled]' assert_select 'input[type=checkbox][value="3"][disabled=disabled]' assert_no_select 'input[type=checkbox][value="2"][disabled=disabled]' end - test 'collection check boxes accepts single disabled item' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => 1 + test "collection check boxes accepts single disabled item" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, disabled: 1 assert_select 'input[type=checkbox][value="1"][disabled=disabled]' assert_no_select 'input[type=checkbox][value="3"][disabled=disabled]' assert_no_select 'input[type=checkbox][value="2"][disabled=disabled]' end - test 'collection check boxes accepts a proc to disabled items' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => proc { |i| i.first == 1 } + test "collection check boxes accepts a proc to disabled items" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, disabled: proc { |i| i.first == 1 } assert_select 'input[type=checkbox][value="1"][disabled=disabled]' assert_no_select 'input[type=checkbox][value="3"][disabled=disabled]' assert_no_select 'input[type=checkbox][value="2"][disabled=disabled]' end - test 'collection check boxes accepts multiple readonly items' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :readonly => [1, 3] + test "collection check boxes accepts multiple readonly items" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, readonly: [1, 3] assert_select 'input[type=checkbox][value="1"][readonly=readonly]' assert_select 'input[type=checkbox][value="3"][readonly=readonly]' assert_no_select 'input[type=checkbox][value="2"][readonly=readonly]' end - test 'collection check boxes accepts single readonly item' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :readonly => 1 + test "collection check boxes accepts single readonly item" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, readonly: 1 assert_select 'input[type=checkbox][value="1"][readonly=readonly]' assert_no_select 'input[type=checkbox][value="3"][readonly=readonly]' assert_no_select 'input[type=checkbox][value="2"][readonly=readonly]' end - test 'collection check boxes accepts a proc to readonly items' do - collection = (1..3).map{|i| [i, "Category #{i}"] } - with_collection_check_boxes :user, :category_ids, collection, :first, :last, :readonly => proc { |i| i.first == 1 } + test "collection check boxes accepts a proc to readonly items" do + collection = (1..3).map { |i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, readonly: proc { |i| i.first == 1 } assert_select 'input[type=checkbox][value="1"][readonly=readonly]' assert_no_select 'input[type=checkbox][value="3"][readonly=readonly]' assert_no_select 'input[type=checkbox][value="2"][readonly=readonly]' end - test 'collection check boxes accepts html options' do - collection = [[1, 'Category 1'], [2, 'Category 2']] - with_collection_check_boxes :user, :category_ids, collection, :first, :last, {}, :class => 'check' + test "collection check boxes accepts html options" do + collection = [[1, "Category 1"], [2, "Category 2"]] + with_collection_check_boxes :user, :category_ids, collection, :first, :last, {}, class: "check" assert_select 'input.check[type=checkbox][value="1"]' assert_select 'input.check[type=checkbox][value="2"]' end - test 'collection check boxes with fields for' do - collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + test "collection check boxes with fields for" do + collection = [Category.new(1, "Category 1"), Category.new(2, "Category 2")] @output_buffer = fields_for(:post) do |p| p.collection_check_boxes :category_ids, collection, :id, :name end @@ -446,67 +446,67 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_select 'input#post_category_ids_1[type=checkbox][value="1"]' assert_select 'input#post_category_ids_2[type=checkbox][value="2"]' - assert_select 'label[for=post_category_ids_1]', 'Category 1' - assert_select 'label[for=post_category_ids_2]', 'Category 2' + assert_select "label[for=post_category_ids_1]", "Category 1" + assert_select "label[for=post_category_ids_2]", "Category 2" end - test 'collection check boxes does not wrap input inside the label' do + test "collection check boxes does not wrap input inside the label" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s - assert_select 'input[type=checkbox] + label' - assert_no_select 'label input' + assert_select "input[type=checkbox] + label" + assert_no_select "label input" end - test 'collection check boxes accepts a block to render the label as check box wrapper' do + test "collection check boxes accepts a block to render the label as check box wrapper" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| b.label { b.check_box } end - assert_select 'label[for=user_active_true] > input#user_active_true[type=checkbox]' - assert_select 'label[for=user_active_false] > input#user_active_false[type=checkbox]' + assert_select "label[for=user_active_true] > input#user_active_true[type=checkbox]" + assert_select "label[for=user_active_false] > input#user_active_false[type=checkbox]" end - test 'collection check boxes accepts a block to change the order of label and check box' do + test "collection check boxes accepts a block to change the order of label and check box" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| b.label + b.check_box end - assert_select 'label[for=user_active_true] + input#user_active_true[type=checkbox]' - assert_select 'label[for=user_active_false] + input#user_active_false[type=checkbox]' + assert_select "label[for=user_active_true] + input#user_active_true[type=checkbox]" + assert_select "label[for=user_active_false] + input#user_active_false[type=checkbox]" end - test 'collection check boxes with block helpers accept extra html options' do + test "collection check boxes with block helpers accept extra html options" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| - b.label(:class => "check_box") + b.check_box(:class => "check_box") + b.label(class: "check_box") + b.check_box(class: "check_box") end - assert_select 'label.check_box[for=user_active_true] + input#user_active_true.check_box[type=checkbox]' - assert_select 'label.check_box[for=user_active_false] + input#user_active_false.check_box[type=checkbox]' + assert_select "label.check_box[for=user_active_true] + input#user_active_true.check_box[type=checkbox]" + assert_select "label.check_box[for=user_active_false] + input#user_active_false.check_box[type=checkbox]" end - test 'collection check boxes with block helpers allows access to current text and value' do + test "collection check boxes with block helpers allows access to current text and value" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| - b.label(:"data-value" => b.value) { b.check_box + b.text } + b.label("data-value": b.value) { b.check_box + b.text } end - assert_select 'label[for=user_active_true][data-value=true]', 'true' do - assert_select 'input#user_active_true[type=checkbox]' + assert_select "label[for=user_active_true][data-value=true]", "true" do + assert_select "input#user_active_true[type=checkbox]" end - assert_select 'label[for=user_active_false][data-value=false]', 'false' do - assert_select 'input#user_active_false[type=checkbox]' + assert_select "label[for=user_active_false][data-value=false]", "false" do + assert_select "input#user_active_false[type=checkbox]" end end - test 'collection check boxes with block helpers allows access to the current object item in the collection to access extra properties' do + test "collection check boxes with block helpers allows access to the current object item in the collection to access extra properties" do with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| - b.label(:class => b.object) { b.check_box + b.text } + b.label(class: b.object) { b.check_box + b.text } end - assert_select 'label.true[for=user_active_true]', 'true' do - assert_select 'input#user_active_true[type=checkbox]' + assert_select "label.true[for=user_active_true]", "true" do + assert_select "input#user_active_true[type=checkbox]" end - assert_select 'label.false[for=user_active_false]', 'false' do - assert_select 'input#user_active_false[type=checkbox]' + assert_select "label.false[for=user_active_false]", "false" do + assert_select "input#user_active_false[type=checkbox]" end end end diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb index 310d0ce514..395c4e4f41 100644 --- a/actionview/test/template/form_helper_test.rb +++ b/actionview/test/template/form_helper_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'controller/fake_models' +require "abstract_unit" +require "controller/fake_models" class FormHelperTest < ActionView::TestCase include RenderERBUtils @@ -16,13 +16,13 @@ class FormHelperTest < ActionView::TestCase setup do # Create "label" locale for testing I18n label helpers - I18n.backend.store_translations 'label', { + I18n.backend.store_translations "label", activemodel: { attributes: { post: { cost: "Total cost" }, - :"post/language" => { + "post/language": { spanish: "Espanol" } } @@ -42,33 +42,31 @@ class FormHelperTest < ActionView::TestCase value: "Tag" }, post_delegate: { - title: 'Delegate model_name title' + title: "Delegate model_name title" } } } - } # Create "submit" locale for testing I18n submit helpers - I18n.backend.store_translations 'submit', { + I18n.backend.store_translations "submit", helpers: { submit: { - create: 'Create %{model}', - update: 'Confirm %{model} changes', - submit: 'Save changes', + create: "Create %{model}", + update: "Confirm %{model} changes", + submit: "Save changes", another_post: { - update: 'Update your %{model}' + update: "Update your %{model}" } } } - } - I18n.backend.store_translations 'placeholder', { + I18n.backend.store_translations "placeholder", activemodel: { attributes: { post: { cost: "Total cost" }, - :"post/cost" => { + "post/cost": { uk: "Pounds" } } @@ -85,14 +83,13 @@ class FormHelperTest < ActionView::TestCase } }, post_delegate: { - title: 'Delegate model_name title' + title: "Delegate model_name title" }, tag: { value: "Tag" } } } - } @post = Post.new @comment = Comment.new @@ -108,7 +105,7 @@ class FormHelperTest < ActionView::TestCase def @post.id; 0; end def @post.id_before_type_cast; "omg"; end def @post.id_came_from_user?; true; end - def @post.to_param; '123'; end + def @post.to_param; "123"; end @post.persisted = true @post.title = "Hello World" @@ -125,7 +122,7 @@ class FormHelperTest < ActionView::TestCase @post_delegator = PostDelegator.new - @post_delegator.title = 'Hello World' + @post_delegator.title = "Hello World" @car = Car.new("#000FFF") end @@ -178,7 +175,7 @@ class FormHelperTest < ActionView::TestCase ) assert_dom_equal( '<label class="title_label" for="post_title">Title</label>', - label("post", "title", nil, class: 'title_label') + label("post", "title", nil, class: "title_label") ) assert_dom_equal('<label for="post_secret">Secret?</label>', label("post", "secret?")) end @@ -229,7 +226,7 @@ class FormHelperTest < ActionView::TestCase def test_label_with_locales_and_nested_attributes with_locale :label do - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| f.fields_for(:comments) do |cf| concat cf.label(:body) end @@ -245,7 +242,7 @@ class FormHelperTest < ActionView::TestCase def test_label_with_locales_fallback_and_nested_attributes with_locale :label do - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| f.fields_for(:tags) do |cf| concat cf.label(:value) end @@ -260,7 +257,7 @@ class FormHelperTest < ActionView::TestCase end def test_label_with_non_active_record_object - form_for(OpenStruct.new(name:'ok'), as: 'person', url: 'an_url', html: { id: 'create-person' }) do |f| + form_for(OpenStruct.new(name:"ok"), as: "person", url: "an_url", html: { id: "create-person" }) do |f| f.label(:name) end @@ -280,7 +277,7 @@ class FormHelperTest < ActionView::TestCase end def test_label_does_not_generate_for_attribute_when_given_nil - assert_dom_equal('<label>Title</label>', label(:post, :title, for: nil)) + assert_dom_equal("<label>Title</label>", label(:post, :title, for: nil)) end def test_label_with_id_attribute_as_symbol @@ -429,7 +426,7 @@ class FormHelperTest < ActionView::TestCase def test_text_field_placeholder_with_locales_and_nested_attributes with_locale :placeholder do - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| f.fields_for(:comments) do |cf| concat cf.text_field(:body, placeholder: true) end @@ -445,7 +442,7 @@ class FormHelperTest < ActionView::TestCase def test_text_field_placeholder_with_locales_fallback_and_nested_attributes with_locale :placeholder do - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| f.fields_for(:tags) do |cf| concat cf.text_field(:value, placeholder: true) end @@ -523,39 +520,24 @@ class FormHelperTest < ActionView::TestCase end def test_text_field_doesnt_change_param_values - object_name = 'post[]' + object_name = "post[]" expected = '<input id="post_123_title" name="post[123][title]" type="text" value="Hello World" />' assert_dom_equal expected, text_field(object_name, "title") end - def test_file_field_does_generate_a_hidden_field - expected = '<input name="user[avatar]" type="hidden" value="" /><input id="user_avatar" name="user[avatar]" type="file" />' - assert_dom_equal expected, file_field("user", "avatar") - end - - def test_file_field_does_not_generate_a_hidden_field_if_included_hidden_option_is_false - expected = '<input id="user_avatar" name="user[avatar]" type="file" />' - assert_dom_equal expected, file_field("user", "avatar", include_hidden: false) - end - - def test_file_field_does_not_generate_a_hidden_field_if_included_hidden_option_is_false_with_key_as_string - expected = '<input id="user_avatar" name="user[avatar]" type="file" />' - assert_dom_equal expected, file_field("user", "avatar", "include_hidden" => false) - end - def test_file_field_has_no_size - expected = '<input name="user[avatar]" type="hidden" value="" /><input id="user_avatar" name="user[avatar]" type="file" />' + expected = '<input id="user_avatar" name="user[avatar]" type="file" />' assert_dom_equal expected, file_field("user", "avatar") end def test_file_field_with_multiple_behavior - expected = '<input name="import[file][]" type="hidden" value="" /><input id="import_file" multiple="multiple" name="import[file][]" type="file" />' - assert_dom_equal expected, file_field("import", "file", :multiple => true) + expected = '<input id="import_file" multiple="multiple" name="import[file][]" type="file" />' + assert_dom_equal expected, file_field("import", "file", multiple: true) end def test_file_field_with_multiple_behavior_and_explicit_name - expected = '<input name="custom" type="hidden" value="" /><input id="import_file" multiple="multiple" name="custom" type="file" />' - assert_dom_equal expected, file_field("import", "file", :multiple => true, :name => "custom") + expected = '<input id="import_file" multiple="multiple" name="custom" type="file" />' + assert_dom_equal expected, file_field("import", "file", multiple: true, name: "custom") end def test_hidden_field @@ -636,19 +618,19 @@ class FormHelperTest < ActionView::TestCase end def test_check_box_checked_if_object_value_includes_checked_value - @post.secret = ['0'] + @post.secret = ["0"] assert_dom_equal( '<input name="post[secret]" type="hidden" value="0" /><input id="post_secret" name="post[secret]" type="checkbox" value="1" />', check_box("post", "secret") ) - @post.secret = ['1'] + @post.secret = ["1"] assert_dom_equal( '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />', check_box("post", "secret") ) - @post.secret = Set.new(['1']) + @post.secret = Set.new(["1"]) assert_dom_equal( '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />', check_box("post", "secret") @@ -791,7 +773,7 @@ class FormHelperTest < ActionView::TestCase def test_checkbox_disabled_disables_hidden_field assert_dom_equal( '<input name="post[secret]" type="hidden" value="0" disabled="disabled"/><input checked="checked" disabled="disabled" id="post_secret" name="post[secret]" type="checkbox" value="1" />', - check_box("post", "secret", { disabled: true }) + check_box("post", "secret", disabled: true) ) end @@ -826,9 +808,9 @@ class FormHelperTest < ActionView::TestCase end def test_radio_button_respects_passed_in_id - assert_dom_equal('<input checked="checked" id="foo" name="post[secret]" type="radio" value="1" />', - radio_button("post", "secret", "1", id: "foo") - ) + assert_dom_equal('<input checked="checked" id="foo" name="post[secret]" type="radio" value="1" />', + radio_button("post", "secret", "1", id: "foo") + ) end def test_radio_button_with_booleans @@ -897,7 +879,7 @@ class FormHelperTest < ActionView::TestCase def test_text_area_placeholder_with_locales_and_nested_attributes with_locale :placeholder do - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| f.fields_for(:comments) do |cf| concat cf.text_area(:body, placeholder: true) end @@ -913,7 +895,7 @@ class FormHelperTest < ActionView::TestCase def test_text_area_placeholder_with_locales_fallback_and_nested_attributes with_locale :placeholder do - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| f.fields_for(:tags) do |cf| concat cf.text_area(:value, placeholder: true) end @@ -1056,9 +1038,9 @@ class FormHelperTest < ActionView::TestCase end def test_date_field_with_timewithzone_value - previous_time_zone, Time.zone = Time.zone, 'UTC' + previous_time_zone, Time.zone = Time.zone, "UTC" expected = %{<input id="post_written_on" name="post[written_on]" type="date" value="2004-06-15" />} - @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + @post.written_on = Time.zone.parse("2004-06-15 15:30:45") assert_dom_equal(expected, date_field("post", "written_on")) ensure Time.zone = previous_time_zone @@ -1107,9 +1089,9 @@ class FormHelperTest < ActionView::TestCase end def test_time_field_with_timewithzone_value - previous_time_zone, Time.zone = Time.zone, 'UTC' + previous_time_zone, Time.zone = Time.zone, "UTC" expected = %{<input id="post_written_on" name="post[written_on]" type="time" value="01:02:03.000" />} - @post.written_on = Time.zone.parse('2004-06-15 01:02:03') + @post.written_on = Time.zone.parse("2004-06-15 01:02:03") assert_dom_equal(expected, time_field("post", "written_on")) ensure Time.zone = previous_time_zone @@ -1138,76 +1120,60 @@ class FormHelperTest < ActionView::TestCase end def test_datetime_field - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2004-06-15T00:00:00.000+0000" />} - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on")) - end + expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T00:00:00" />} + assert_dom_equal(expected, datetime_field("post", "written_on")) end def test_datetime_field_with_datetime_value - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2004-06-15T01:02:03.000+0000" />} + expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on")) - end + assert_dom_equal(expected, datetime_field("post", "written_on")) end def test_datetime_field_with_extra_attrs - expected = %{<input id="post_written_on" step="60" max="2010-08-15T10:25:00.000+0000" min="2000-06-15T20:45:30.000+0000" name="post[written_on]" type="datetime" value="2004-06-15T01:02:03.000+0000" />} + expected = %{<input id="post_written_on" step="60" max="2010-08-15T10:25:00" min="2000-06-15T20:45:30" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) min_value = DateTime.new(2000, 6, 15, 20, 45, 30) max_value = DateTime.new(2010, 8, 15, 10, 25, 00) step = 60 - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on", min: min_value, max: max_value, step: step)) - end + assert_dom_equal(expected, datetime_field("post", "written_on", min: min_value, max: max_value, step: step)) end def test_datetime_field_with_value_attr - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2013-06-29T13:37:00+00:00" />} + expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2013-06-29T13:37:00+00:00" />} value = DateTime.new(2013,6,29,13,37) - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on", value: value)) - end + assert_dom_equal(expected, datetime_field("post", "written_on", value: value)) end def test_datetime_field_with_timewithzone_value - previous_time_zone, Time.zone = Time.zone, 'UTC' - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2004-06-15T15:30:45.000+0000" />} - @post.written_on = Time.zone.parse('2004-06-15 15:30:45') - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on")) - end + previous_time_zone, Time.zone = Time.zone, "UTC" + expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T15:30:45" />} + @post.written_on = Time.zone.parse("2004-06-15 15:30:45") + assert_dom_equal(expected, datetime_field("post", "written_on")) ensure Time.zone = previous_time_zone end def test_datetime_field_with_nil_value - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" />} + expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" />} @post.written_on = nil - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on")) - end + assert_dom_equal(expected, datetime_field("post", "written_on")) end def test_datetime_field_with_string_values_for_min_and_max - expected = %{<input id="post_written_on" max="2010-08-15T10:25:00.000+0000" min="2000-06-15T20:45:30.000+0000" name="post[written_on]" type="datetime" value="2004-06-15T01:02:03.000+0000" />} + expected = %{<input id="post_written_on" max="2010-08-15T10:25:00" min="2000-06-15T20:45:30" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) - min_value = "2000-06-15T20:45:30.000+0000" - max_value = "2010-08-15T10:25:00.000+0000" - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on", min: min_value, max: max_value)) - end + min_value = "2000-06-15T20:45:30" + max_value = "2010-08-15T10:25:00" + assert_dom_equal(expected, datetime_field("post", "written_on", min: min_value, max: max_value)) end def test_datetime_field_with_invalid_string_values_for_min_and_max - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2004-06-15T01:02:03.000+0000" />} + expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) min_value = "foo" max_value = "bar" - assert_deprecated do - assert_dom_equal(expected, datetime_field("post", "written_on", min: min_value, max: max_value)) - end + assert_dom_equal(expected, datetime_field("post", "written_on", min: min_value, max: max_value)) end def test_datetime_local_field @@ -1215,52 +1181,6 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal(expected, datetime_local_field("post", "written_on")) end - def test_datetime_local_field_with_datetime_value - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} - @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) - assert_dom_equal(expected, datetime_local_field("post", "written_on")) - end - - def test_datetime_local_field_with_extra_attrs - expected = %{<input id="post_written_on" step="60" max="2010-08-15T10:25:00" min="2000-06-15T20:45:30" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} - @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) - min_value = DateTime.new(2000, 6, 15, 20, 45, 30) - max_value = DateTime.new(2010, 8, 15, 10, 25, 00) - step = 60 - assert_dom_equal(expected, datetime_local_field("post", "written_on", min: min_value, max: max_value, step: step)) - end - - def test_datetime_local_field_with_timewithzone_value - previous_time_zone, Time.zone = Time.zone, 'UTC' - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T15:30:45" />} - @post.written_on = Time.zone.parse('2004-06-15 15:30:45') - assert_dom_equal(expected, datetime_local_field("post", "written_on")) - ensure - Time.zone = previous_time_zone - end - - def test_datetime_local_field_with_nil_value - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" />} - @post.written_on = nil - assert_dom_equal(expected, datetime_local_field("post", "written_on")) - end - - def test_datetime_local_field_with_string_values_for_min_and_max - expected = %{<input id="post_written_on" max="2010-08-15T10:25:00" min="2000-06-15T20:45:30" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} - @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) - min_value = "2000-06-15T20:45:30" - max_value = "2010-08-15T10:25:00" - assert_dom_equal(expected, datetime_local_field("post", "written_on", min: min_value, max: max_value)) - end - - def test_datetime_local_field_with_invalid_string_values_for_min_and_max - expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />} - @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) - min_value = "foo" - max_value = "bar" - assert_dom_equal(expected, datetime_local_field("post", "written_on", min: min_value, max: max_value)) - end - def test_month_field expected = %{<input id="post_written_on" name="post[written_on]" type="month" value="2004-06" />} assert_dom_equal(expected, month_field("post", "written_on")) @@ -1288,9 +1208,9 @@ class FormHelperTest < ActionView::TestCase end def test_month_field_with_timewithzone_value - previous_time_zone, Time.zone = Time.zone, 'UTC' + previous_time_zone, Time.zone = Time.zone, "UTC" expected = %{<input id="post_written_on" name="post[written_on]" type="month" value="2004-06" />} - @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + @post.written_on = Time.zone.parse("2004-06-15 15:30:45") assert_dom_equal(expected, month_field("post", "written_on")) ensure Time.zone = previous_time_zone @@ -1323,9 +1243,9 @@ class FormHelperTest < ActionView::TestCase end def test_week_field_with_timewithzone_value - previous_time_zone, Time.zone = Time.zone, 'UTC' + previous_time_zone, Time.zone = Time.zone, "UTC" expected = %{<input id="post_written_on" name="post[written_on]" type="week" value="2004-W25" />} - @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + @post.written_on = Time.zone.parse("2004-06-15 15:30:45") assert_dom_equal(expected, week_field("post", "written_on")) ensure Time.zone = previous_time_zone @@ -1484,26 +1404,26 @@ class FormHelperTest < ActionView::TestCase def test_index_with_nil_id assert_dom_equal( '<input name="post[5][title]" type="text" value="Hello World" />', - text_field("post", "title", "index" => 5, 'id' => nil) + text_field("post", "title", "index" => 5, "id" => nil) ) assert_dom_equal( %{<textarea name="post[5][body]">\nBack to the hill and over it again!</textarea>}, - text_area("post", "body", "index" => 5, 'id' => nil) + text_area("post", "body", "index" => 5, "id" => nil) ) assert_dom_equal( '<input name="post[5][secret]" type="hidden" value="0" /><input checked="checked" name="post[5][secret]" type="checkbox" value="1" />', - check_box("post", "secret", "index" => 5, 'id' => nil) + check_box("post", "secret", "index" => 5, "id" => nil) ) assert_dom_equal( - text_field("post", "title", "index" => 5, 'id' => nil), + text_field("post", "title", "index" => 5, "id" => nil), text_field("post", "title", index: 5, id: nil) ) assert_dom_equal( - text_area("post", "body", "index" => 5, 'id' => nil), + text_area("post", "body", "index" => 5, "id" => nil), text_area("post", "body", index: 5, id: nil) ) assert_dom_equal( - check_box("post", "secret", "index" => 5, 'id' => nil), + check_box("post", "secret", "index" => 5, "id" => nil), check_box("post", "secret", index: 5, id: nil) ) end @@ -1526,10 +1446,10 @@ class FormHelperTest < ActionView::TestCase %{<input name="post[#{pid}][secret]" type="hidden" value="0" /><input checked="checked" id="post_#{pid}_secret" name="post[#{pid}][secret]" type="checkbox" value="1" />}, check_box("post[]", "secret") ) - assert_dom_equal( - %{<input checked="checked" id="post_#{pid}_title_hello_world" name="post[#{pid}][title]" type="radio" value="Hello World" />}, - radio_button("post[]", "title", "Hello World") - ) + assert_dom_equal( + %{<input checked="checked" id="post_#{pid}_title_hello_world" name="post[#{pid}][title]" type="radio" value="Hello World" />}, + radio_button("post[]", "title", "Hello World") + ) assert_dom_equal( %{<input id="post_#{pid}_title_goodbye_world" name="post[#{pid}][title]" type="radio" value="Goodbye World" />}, radio_button("post[]", "title", "Goodbye World") @@ -1550,10 +1470,10 @@ class FormHelperTest < ActionView::TestCase %{<input name="post[#{pid}][secret]" type="hidden" value="0" /><input checked="checked" name="post[#{pid}][secret]" type="checkbox" value="1" />}, check_box("post[]", "secret", id: nil) ) - assert_dom_equal( - %{<input checked="checked" name="post[#{pid}][title]" type="radio" value="Hello World" />}, - radio_button("post[]", "title", "Hello World", id: nil) - ) + assert_dom_equal( + %{<input checked="checked" name="post[#{pid}][title]" type="radio" value="Hello World" />}, + radio_button("post[]", "title", "Hello World", id: nil) + ) assert_dom_equal( %{<input name="post[#{pid}][title]" type="radio" value="Goodbye World" />}, radio_button("post[]", "title", "Goodbye World", id: nil) @@ -1562,35 +1482,35 @@ class FormHelperTest < ActionView::TestCase def test_form_for_requires_block error = assert_raises(ArgumentError) do - form_for(@post, html: { id: 'create-post' }) + form_for(@post, html: { id: "create-post" }) end assert_equal "Missing block", error.message end def test_form_for_requires_arguments error = assert_raises(ArgumentError) do - form_for(nil, html: { id: 'create-post' }) do + form_for(nil, html: { id: "create-post" }) do end end assert_equal "First argument in form cannot contain nil or be empty", error.message error = assert_raises(ArgumentError) do - form_for([nil, nil], html: { id: 'create-post' }) do + form_for([nil, nil], html: { id: "create-post" }) do end end assert_equal "First argument in form cannot contain nil or be empty", error.message end def test_form_for - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| concat f.label(:title) { "The Title" } concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) - concat f.submit('Create post') - concat f.button('Create post') + concat f.submit("Create post") + concat f.button("Create post") concat f.button { - concat content_tag(:span, 'Create post') + concat content_tag(:span, "Create post") } end @@ -1681,7 +1601,7 @@ class FormHelperTest < ActionView::TestCase post = Post.new def post.active; false; end - form_for(post, namespace: 'foo') do |f| + form_for(post, namespace: "foo") do |f| concat f.collection_radio_buttons(:active, [true, false], :to_s, :to_s) end @@ -1700,7 +1620,7 @@ class FormHelperTest < ActionView::TestCase post = Post.new def post.active; false; end - form_for(post, index: '1') do |f| + form_for(post, index: "1") do |f| concat f.collection_radio_buttons(:active, [true, false], :to_s, :to_s) end @@ -1799,7 +1719,7 @@ class FormHelperTest < ActionView::TestCase def post.tag_ids; [1]; end collection = [[1, "Tag 1"]] - form_for(post, namespace: 'foo') do |f| + form_for(post, namespace: "foo") do |f| concat f.collection_check_boxes(:tag_ids, collection, :first, :last) end @@ -1817,7 +1737,7 @@ class FormHelperTest < ActionView::TestCase def post.tag_ids; [1]; end collection = [[1, "Tag 1"]] - form_for(post, index: '1') do |f| + form_for(post, index: "1") do |f| concat f.collection_check_boxes(:tag_ids, collection, :first, :last) end @@ -1833,12 +1753,12 @@ class FormHelperTest < ActionView::TestCase def test_form_for_with_file_field_generate_multipart Post.send :attr_accessor, :file - form_for(@post, html: { id: 'create-post' }) do |f| + form_for(@post, html: { id: "create-post" }) do |f| concat f.file_field(:file) end expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch", multipart: true) do - "<input name='post[file]' type='hidden' value='' /><input name='post[file]' type='file' id='post_file' />" + "<input name='post[file]' type='file' id='post_file' />" end assert_dom_equal expected, output_buffer @@ -1854,7 +1774,7 @@ class FormHelperTest < ActionView::TestCase end expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch", multipart: true) do - "<input name='post[comment][file]' type='hidden' value='' /><input name='post[comment][file]' type='file' id='post_comment_file' />" + "<input name='post[comment][file]' type='file' id='post_comment_file' />" end assert_dom_equal expected, output_buffer @@ -1865,7 +1785,7 @@ class FormHelperTest < ActionView::TestCase concat f.label(:title) end - expected = whole_form("/posts/123.json", "edit_post_123", "edit_post", method: 'patch') do + expected = whole_form("/posts/123.json", "edit_post_123", "edit_post", method: "patch") do "<label for='post_title'>Title</label>" end @@ -1877,7 +1797,7 @@ class FormHelperTest < ActionView::TestCase form_for(blog_post) do |f| concat f.text_field :title - concat f.submit('Edit post') + concat f.submit("Edit post") end expected = whole_form("/posts/44", "edit_post_44", "edit_post", method: "patch") do @@ -1888,13 +1808,13 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end - def test_form_for_with_symbol_object_name + def test_form_for_with_symbol_as form_for(@post, as: "other_name", html: { id: "create-post" }) do |f| - concat f.label(:title, class: 'post_title') + concat f.label(:title, class: "post_title") concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) - concat f.submit('Create post') + concat f.submit("Create post") end expected = whole_form("/posts/123", "create-post", "edit_other_name", method: "patch") do @@ -1918,13 +1838,13 @@ class FormHelperTest < ActionView::TestCase end end.new - form_for(obj, as: "other_name", url: '/', html: { id: "edit-other-name" }) do |f| + form_for(obj, as: "other_name", url: "/", html: { id: "edit-other-name" }) do |f| assert_raise(NoMethodError) { f.hidden_field(:private_property) } end end def test_form_for_with_method_as_part_of_html_options - form_for(@post, url: '/', html: { id: 'create-post', method: :delete }) do |f| + form_for(@post, url: "/", html: { id: "create-post", method: :delete }) do |f| concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) @@ -1941,7 +1861,7 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_method - form_for(@post, url: '/', method: :delete, html: { id: 'create-post' }) do |f| + form_for(@post, url: "/", method: :delete, html: { id: "create-post" }) do |f| concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) @@ -1972,7 +1892,7 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_remote - form_for(@post, url: '/', remote: true, html: { id: 'create-post', method: :patch }) do |f| + form_for(@post, url: "/", remote: true, html: { id: "create-post", method: :patch }) do |f| concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) @@ -2013,7 +1933,7 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_remote_in_html - form_for(@post, url: '/', html: { remote: true, id: 'create-post', method: :patch }) do |f| + form_for(@post, url: "/", html: { remote: true, id: "create-post", method: :patch }) do |f| concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) @@ -2050,7 +1970,7 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_without_object - form_for(:post, html: { id: 'create-post' }) do |f| + form_for(:post, html: { id: "create-post" }) do |f| concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) @@ -2074,7 +1994,7 @@ class FormHelperTest < ActionView::TestCase concat f.check_box(:secret) end - expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do "<label for='post_123_title'>Title</label>" + "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" + "<textarea name='post[123][body]' id='post_123_body'>\nBack to the hill and over it again!</textarea>" + @@ -2092,7 +2012,7 @@ class FormHelperTest < ActionView::TestCase concat f.check_box(:secret) end - expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do "<input name='post[][title]' type='text' id='post__title' value='Hello World' />" + "<textarea name='post[][body]' id='post__body'>\nBack to the hill and over it again!</textarea>" + "<input name='post[][secret]' type='hidden' value='0' />" + @@ -2104,12 +2024,12 @@ class FormHelperTest < ActionView::TestCase def test_form_for_label_error_wrapping form_for(@post) do |f| - concat f.label(:author_name, class: 'label') + concat f.label(:author_name, class: "label") concat f.text_field(:author_name) - concat f.submit('Create post') + concat f.submit("Create post") end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" + "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" + "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" @@ -2122,12 +2042,12 @@ class FormHelperTest < ActionView::TestCase post = remove_instance_variable :@post form_for(post) do |f| - concat f.label(:author_name, class: 'label') + concat f.label(:author_name, class: "label") concat f.text_field(:author_name) - concat f.submit('Create post') + concat f.submit("Create post") end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" + "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" + "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" @@ -2138,11 +2058,11 @@ class FormHelperTest < ActionView::TestCase def test_form_for_label_error_wrapping_block_and_non_block_versions form_for(@post) do |f| - concat f.label(:author_name, 'Name', class: 'label') - concat f.label(:author_name, class: 'label') { 'Name' } + concat f.label(:author_name, "Name", class: "label") + concat f.label(:author_name, class: "label") { "Name" } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>" + "<div class='field_with_errors'><label for='post_author_name' class='label'>Name</label></div>" end @@ -2151,13 +2071,13 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_namespace - form_for(@post, namespace: 'namespace') do |f| + form_for(@post, namespace: "namespace") do |f| concat f.text_field(:title) concat f.text_area(:body) concat f.check_box(:secret) end - expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" + "<textarea name='post[body]' id='namespace_post_body'>\nBack to the hill and over it again!</textarea>" + "<input name='post[secret]' type='hidden' value='0' />" + @@ -2168,20 +2088,20 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_namespace_with_date_select - form_for(@post, namespace: 'namespace') do |f| + form_for(@post, namespace: "namespace") do |f| concat f.date_select(:written_on) end - assert_select 'select#namespace_post_written_on_1i' + assert_select "select#namespace_post_written_on_1i" end def test_form_for_with_namespace_with_label - form_for(@post, namespace: 'namespace') do |f| + form_for(@post, namespace: "namespace") do |f| concat f.label(:title) concat f.text_field(:title) end - expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do "<label for='namespace_post_title'>Title</label>" + "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" end @@ -2190,11 +2110,11 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_namespace_and_as_option - form_for(@post, namespace: 'namespace', as: 'custom_name') do |f| + form_for(@post, namespace: "namespace", as: "custom_name") do |f| concat f.text_field(:title) end - expected = whole_form('/posts/123', 'namespace_edit_custom_name', 'edit_custom_name', method: 'patch') do + expected = whole_form("/posts/123", "namespace_edit_custom_name", "edit_custom_name", method: "patch") do "<input id='namespace_custom_name_title' name='custom_name[title]' type='text' value='Hello World' />" end @@ -2202,24 +2122,24 @@ class FormHelperTest < ActionView::TestCase end def test_two_form_for_with_namespace - form_for(@post, namespace: 'namespace_1') do |f| + form_for(@post, namespace: "namespace_1") do |f| concat f.label(:title) concat f.text_field(:title) end - expected_1 = whole_form('/posts/123', 'namespace_1_edit_post_123', 'edit_post', method: 'patch') do + expected_1 = whole_form("/posts/123", "namespace_1_edit_post_123", "edit_post", method: "patch") do "<label for='namespace_1_post_title'>Title</label>" + "<input name='post[title]' type='text' id='namespace_1_post_title' value='Hello World' />" end assert_dom_equal expected_1, output_buffer - form_for(@post, namespace: 'namespace_2') do |f| + form_for(@post, namespace: "namespace_2") do |f| concat f.label(:title) concat f.text_field(:title) end - expected_2 = whole_form('/posts/123', 'namespace_2_edit_post_123', 'edit_post', method: 'patch') do + expected_2 = whole_form("/posts/123", "namespace_2_edit_post_123", "edit_post", method: "patch") do "<label for='namespace_2_post_title'>Title</label>" + "<input name='post[title]' type='text' id='namespace_2_post_title' value='Hello World' />" end @@ -2228,8 +2148,8 @@ class FormHelperTest < ActionView::TestCase end def test_fields_for_with_namespace - @comment.body = 'Hello World' - form_for(@post, namespace: 'namespace') do |f| + @comment.body = "Hello World" + form_for(@post, namespace: "namespace") do |f| concat f.text_field(:title) concat f.text_area(:body) concat f.fields_for(@comment) { |c| @@ -2237,7 +2157,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" + "<textarea name='post[body]' id='namespace_post_body'>\nBack to the hill and over it again!</textarea>" + "<input name='post[comment][body]' type='text' id='namespace_post_comment_body' value='Hello World' />" @@ -2254,7 +2174,7 @@ class FormHelperTest < ActionView::TestCase concat f.submit end - expected = whole_form('/posts', 'new_post', 'new_post') do + expected = whole_form("/posts", "new_post", "new_post") do "<input name='commit' data-disable-with='Create Post' type='submit' value='Create Post' />" end @@ -2269,8 +2189,8 @@ class FormHelperTest < ActionView::TestCase concat f.submit end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do - "<input name='commit' data-disable-with='Confirm Post changes' type='submit' value='Confirm Post changes' />" + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do + "<input name='commit' data-disable-with='Confirm Post changes' type='submit' value='Confirm Post changes' />" end assert_dom_equal expected, output_buffer @@ -2284,7 +2204,7 @@ class FormHelperTest < ActionView::TestCase end expected = whole_form do - "<input name='commit' class='extra' data-disable-with='Save changes' type='submit' value='Save changes' />" + "<input name='commit' class='extra' data-disable-with='Save changes' type='submit' value='Save changes' />" end assert_dom_equal expected, output_buffer @@ -2297,8 +2217,8 @@ class FormHelperTest < ActionView::TestCase concat f.submit end - expected = whole_form('/posts/123', 'edit_another_post', 'edit_another_post', method: 'patch') do - "<input name='commit' data-disable-with='Update your Post' type='submit' value='Update your Post' />" + expected = whole_form("/posts/123", "edit_another_post", "edit_another_post", method: "patch") do + "<input name='commit' data-disable-with='Update your Post' type='submit' value='Update your Post' />" end assert_dom_equal expected, output_buffer @@ -2306,14 +2226,14 @@ class FormHelperTest < ActionView::TestCase end def test_nested_fields_for - @comment.body = 'Hello World' + @comment.body = "Hello World" form_for(@post) do |f| concat f.fields_for(@comment) { |c| concat c.text_field(:body) } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<input name='post[comment][body]' type='text' id='post_comment_body' value='Hello World' />" end @@ -2323,10 +2243,10 @@ class FormHelperTest < ActionView::TestCase def test_deep_nested_fields_for @comment.save form_for(:posts) do |f| - f.fields_for('post[]', @post) do |f2| + f.fields_for("post[]", @post) do |f2| f2.text_field(:id) @post.comments.each do |comment| - concat f2.fields_for('comment[]', comment) { |c| + concat f2.fields_for("comment[]", comment) { |c| concat c.text_field(:name) } end @@ -2340,16 +2260,15 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end - def test_nested_fields_for_with_nested_collections - form_for(@post, as: 'post[]') do |f| + form_for(@post, as: "post[]") do |f| concat f.text_field(:title) - concat f.fields_for('comment[]', @comment) { |c| + concat f.fields_for("comment[]", @comment) { |c| concat c.text_field(:name) } end - expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" + "<input name='post[123][comment][][name]' type='text' id='post_123_comment__name' value='new comment' />" end @@ -2360,12 +2279,12 @@ class FormHelperTest < ActionView::TestCase def test_nested_fields_for_with_index_and_parent_fields form_for(@post, index: 1) do |c| concat c.text_field(:title) - concat c.fields_for('comment', @comment, index: 1) { |r| + concat c.fields_for("comment", @comment, index: 1) { |r| concat r.text_field(:name) } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<input name='post[1][title]' type='text' id='post_1_title' value='Hello World' />" + "<input name='post[1][comment][1][name]' type='text' id='post_1_comment_1_name' value='new comment' />" end @@ -2380,7 +2299,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<input name='post[1][comment][title]' type='text' id='post_1_comment_title' value='Hello World' />" end @@ -2394,7 +2313,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<input name='post[1][comment][5][title]' type='text' id='post_1_comment_5_title' value='Hello World' />" end @@ -2408,7 +2327,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do "<input name='post[123][comment][title]' type='text' id='post_123_comment_title' value='Hello World' />" end @@ -2422,7 +2341,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<input name='post[comment][5][title]' type='radio' id='post_comment_5_title_hello' value='hello' />" end @@ -2436,7 +2355,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do "<input name='post[123][comment][123][title]' type='text' id='post_123_comment_123_title' value='Hello World' />" end @@ -2456,9 +2375,9 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + expected = whole_form("/posts/123", "edit_post[]", "edit_post[]", method: "patch") do "<input name='post[123][comment][5][title]' type='text' id='post_123_comment_5_title' value='Hello World' />" - end + whole_form('/posts/123', 'edit_post', 'edit_post', method: 'patch') do + end + whole_form("/posts/123", "edit_post", "edit_post", method: "patch") do "<input name='post[1][comment][123][title]' type='text' id='post_1_comment_123_title' value='Hello World' />" end @@ -2475,7 +2394,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="new author" />' end @@ -2502,11 +2421,11 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do - '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + - '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' + - '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' - end + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do + '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' + + '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' + end assert_dom_equal expected, output_buffer end @@ -2521,7 +2440,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' + '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' @@ -2540,7 +2459,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' end @@ -2558,7 +2477,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' end @@ -2576,7 +2495,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' + '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' @@ -2596,7 +2515,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' @@ -2617,7 +2536,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + @@ -2644,7 +2563,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' + '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' + @@ -2671,7 +2590,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' + @@ -2697,7 +2616,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' + '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' + @@ -2720,7 +2639,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + @@ -2744,7 +2663,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' + @@ -2767,7 +2686,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="new comment" />' + '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="new comment" />' @@ -2788,7 +2707,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' + @@ -2806,7 +2725,7 @@ class FormHelperTest < ActionView::TestCase end end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' end @@ -2823,7 +2742,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + @@ -2844,7 +2763,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + @@ -2858,7 +2777,7 @@ class FormHelperTest < ActionView::TestCase def test_nested_fields_label_translation_with_more_than_10_records @post.comments = Array.new(11) { |id| Comment.new(id + 1) } - params = 11.times.map { ['post.comments.body', default: [:"comment.body", ''], scope: "helpers.label"] } + params = 11.times.map { ["post.comments.body", default: [:"comment.body", ""], scope: "helpers.label"] } assert_called_with(I18n, :t, params, returns: "Write body here") do form_for(@post) do |f| f.fields_for(:comments) do |cf| @@ -2879,7 +2798,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + @@ -2902,7 +2821,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input name="post[title]" type="text" id="post_title" value="Hello World" />' + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' + @@ -2917,12 +2836,12 @@ class FormHelperTest < ActionView::TestCase @post.comments = [] form_for(@post) do |f| - concat f.fields_for(:comments, Comment.new(321), child_index: 'abc') { |cf| + concat f.fields_for(:comments, Comment.new(321), child_index: "abc") { |cf| concat cf.text_field(:name) } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' + '<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />' end @@ -2934,12 +2853,12 @@ class FormHelperTest < ActionView::TestCase @post.comments = [] form_for(@post) do |f| - concat f.fields_for(:comments, Comment.new(321), child_index: -> { 'abc' } ) { |cf| + concat f.fields_for(:comments, Comment.new(321), child_index: -> { "abc" } ) { |cf| concat cf.text_field(:name) } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' + '<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />' end @@ -2957,12 +2876,12 @@ class FormHelperTest < ActionView::TestCase @post.comments = FakeAssociationProxy.new form_for(@post) do |f| - concat f.fields_for(:comments, Comment.new(321), child_index: 'abc') { |cf| + concat f.fields_for(:comments, Comment.new(321), child_index: "abc") { |cf| concat cf.text_field(:name) } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' + '<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />' end @@ -3014,8 +2933,8 @@ class FormHelperTest < ActionView::TestCase @post.comments = [] form_for(@post) do |f| - f.fields_for(:comments, Comment.new(321), child_index: 'abc') { |cf| - assert_equal cf.index, 'abc' + f.fields_for(:comments, Comment.new(321), child_index: "abc") { |cf| + assert_equal cf.index, "abc" } end end @@ -3040,7 +2959,7 @@ class FormHelperTest < ActionView::TestCase concat trf.text_field(:value) } } - concat f.fields_for('tags', @post.tags[1]) { |tf| + concat f.fields_for("tags", @post.tags[1]) { |tf| concat tf.text_field(:value) concat tf.fields_for(:relevances, TagRelevance.new(31415)) { |trf| concat trf.text_field(:value) @@ -3048,7 +2967,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' + '<input id="post_comments_attributes_0_relevances_attributes_0_value" name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" />' + '<input id="post_comments_attributes_0_relevances_attributes_0_id" name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' + @@ -3075,7 +2994,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="hash backed author" />' end @@ -3201,11 +3120,11 @@ class FormHelperTest < ActionView::TestCase end def test_form_builder_does_not_have_form_for_method - assert !ActionView::Helpers::FormBuilder.instance_methods.include?(:form_for) + assert_not_includes ActionView::Helpers::FormBuilder.instance_methods, :form_for end def test_form_for_and_fields_for - form_for(@post, as: :post, html: { id: 'create-post' }) do |post_form| + form_for(@post, as: :post, html: { id: "create-post" }) do |post_form| concat post_form.text_field(:title) concat post_form.text_area(:body) @@ -3214,7 +3133,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'create-post', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do "<input name='post[title]' type='text' id='post_title' value='Hello World' />" + "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" + "<input name='parent_post[secret]' type='hidden' value='0' />" + @@ -3225,7 +3144,7 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_and_fields_for_with_object - form_for(@post, as: :post, html: { id: 'create-post' }) do |post_form| + form_for(@post, as: :post, html: { id: "create-post" }) do |post_form| concat post_form.text_field(:title) concat post_form.text_area(:body) @@ -3234,7 +3153,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'create-post', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do "<input name='post[title]' type='text' id='post_title' value='Hello World' />" + "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" + "<input name='post[comment][name]' type='text' id='post_comment_name' value='new comment' />" @@ -3250,7 +3169,7 @@ class FormHelperTest < ActionView::TestCase } end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<input name='post[category][name]' type='text' id='post_category_name' />" end @@ -3274,7 +3193,7 @@ class FormHelperTest < ActionView::TestCase concat f.check_box(:secret) end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" + "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" + "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>" @@ -3293,7 +3212,7 @@ class FormHelperTest < ActionView::TestCase concat f.check_box(:secret) end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" + "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" + "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>" @@ -3312,7 +3231,7 @@ class FormHelperTest < ActionView::TestCase concat f.text_field(:title) end - expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") do "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" end @@ -3366,7 +3285,7 @@ class FormHelperTest < ActionView::TestCase form_for(@post, builder: LabelledFormBuilder) do |f| f.fields_for(:comments, Comment.new) do |nested_fields| klass = nested_fields.class - '' + "" end end @@ -3377,9 +3296,9 @@ class FormHelperTest < ActionView::TestCase klass = nil form_for(@post, builder: LabelledFormBuilder) do |f| - f.fields_for(:comments, Comment.new, index: 'foo') do |nested_fields| + f.fields_for(:comments, Comment.new, index: "foo") do |nested_fields| klass = nested_fields.class - '' + "" end end @@ -3391,10 +3310,10 @@ class FormHelperTest < ActionView::TestCase form_for(@post, builder: LabelledFormBuilder) do |f| path = f.to_partial_path - '' + "" end - assert_equal 'labelled_form', path + assert_equal "labelled_form", path end class LabelledFormBuilderSubclass < LabelledFormBuilder; end @@ -3405,7 +3324,7 @@ class FormHelperTest < ActionView::TestCase form_for(@post, builder: LabelledFormBuilder) do |f| f.fields_for(:comments, Comment.new, builder: LabelledFormBuilderSubclass) do |nested_fields| klass = nested_fields.class - '' + "" end end @@ -3413,23 +3332,23 @@ class FormHelperTest < ActionView::TestCase end def test_form_for_with_html_options_adds_options_to_form_tag - form_for(@post, html: { id: 'some_form', class: 'some_class', multipart: true }) do |f| end + form_for(@post, html: { id: "some_form", class: "some_class", multipart: true }) do |f| end expected = whole_form("/posts/123", "some_form", "some_class", method: "patch", multipart: "multipart/form-data") assert_dom_equal expected, output_buffer end def test_form_for_with_string_url_option - form_for(@post, url: 'http://www.otherdomain.com') do |f| end + form_for(@post, url: "http://www.otherdomain.com") do |f| end assert_dom_equal whole_form("http://www.otherdomain.com", "edit_post_123", "edit_post", method: "patch"), output_buffer end def test_form_for_with_hash_url_option - form_for(@post, url: { controller: 'controller', action: 'action' }) do |f| end + form_for(@post, url: { controller: "controller", action: "action" }) do |f| end - assert_equal 'controller', @url_for_options[:controller] - assert_equal 'action', @url_for_options[:action] + assert_equal "controller", @url_for_options[:controller] + assert_equal "action", @url_for_options[:action] end def test_form_for_with_record_url_option @@ -3520,54 +3439,54 @@ class FormHelperTest < ActionView::TestCase end end - form_for(@post, builder: builder_class) { } - assert_equal 1, initialization_count, 'form builder instantiated more than once' + form_for(@post, builder: builder_class) {} + assert_equal 1, initialization_count, "form builder instantiated more than once" end protected - def hidden_fields(options = {}) - method = options[:method] + def hidden_fields(options = {}) + method = options[:method] - if options.fetch(:enforce_utf8, true) - txt = %{<input name="utf8" type="hidden" value="✓" />} - else - txt = '' - end + if options.fetch(:enforce_utf8, true) + txt = %{<input name="utf8" type="hidden" value="✓" />} + else + txt = "" + end - if method && !%w(get post).include?(method.to_s) - txt << %{<input name="_method" type="hidden" value="#{method}" />} - end + if method && !%w(get post).include?(method.to_s) + txt << %{<input name="_method" type="hidden" value="#{method}" />} + end - txt - end + txt + end - def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) - txt = %{<form accept-charset="UTF-8" action="#{action}"} - txt << %{ enctype="multipart/form-data"} if multipart - txt << %{ data-remote="true"} if remote - txt << %{ class="#{html_class}"} if html_class - txt << %{ id="#{id}"} if id - method = method.to_s == "get" ? "get" : "post" - txt << %{ method="#{method}">} - end + def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) + txt = %{<form accept-charset="UTF-8" action="#{action}"} + txt << %{ enctype="multipart/form-data"} if multipart + txt << %{ data-remote="true"} if remote + txt << %{ class="#{html_class}"} if html_class + txt << %{ id="#{id}"} if id + method = method.to_s == "get" ? "get" : "post" + txt << %{ method="#{method}">} + end - def whole_form(action = "/", id = nil, html_class = nil, options = {}) - contents = block_given? ? yield : "" + def whole_form(action = "/", id = nil, html_class = nil, options = {}) + contents = block_given? ? yield : "" - method, remote, multipart = options.values_at(:method, :remote, :multipart) + method, remote, multipart = options.values_at(:method, :remote, :multipart) - form_text(action, id, html_class, remote, multipart, method) + hidden_fields(options.slice :method, :enforce_utf8) + contents + "</form>" - end + form_text(action, id, html_class, remote, multipart, method) + hidden_fields(options.slice :method, :enforce_utf8) + contents + "</form>" + end - def protect_against_forgery? - false - end + def protect_against_forgery? + false + end - def with_locale(testing_locale = :label) - old_locale, I18n.locale = I18n.locale, testing_locale - yield - ensure - I18n.locale = old_locale - end + def with_locale(testing_locale = :label) + old_locale, I18n.locale = I18n.locale, testing_locale + yield + ensure + I18n.locale = old_locale + end end diff --git a/actionview/test/template/form_options_helper_i18n_test.rb b/actionview/test/template/form_options_helper_i18n_test.rb index 26ede09a5f..a1048fbb89 100644 --- a/actionview/test/template/form_options_helper_i18n_test.rb +++ b/actionview/test/template/form_options_helper_i18n_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' +require "abstract_unit" class FormOptionsHelperI18nTests < ActionView::TestCase tests ActionView::Helpers::FormOptionsHelper def setup - @prompt_message = 'Select!' + @prompt_message = "Select!" I18n.backend.send(:init_translations) - I18n.backend.store_translations :en, :helpers => { :select => { :prompt => @prompt_message } } + I18n.backend.store_translations :en, helpers: { select: { prompt: @prompt_message } } end def teardown @@ -14,15 +14,15 @@ class FormOptionsHelperI18nTests < ActionView::TestCase end def test_select_with_prompt_true_translates_prompt_message - assert_called_with(I18n, :translate, ['helpers.select.prompt', { :default => 'Please select' }]) do - select('post', 'category', [], :prompt => true) + assert_called_with(I18n, :translate, ["helpers.select.prompt", { default: "Please select" }]) do + select("post", "category", [], prompt: true) end end def test_select_with_translated_prompt assert_dom_equal( %Q(<select id="post_category" name="post[category]"><option value="">#{@prompt_message}</option>\n</select>), - select('post', 'category', [], :prompt => true) + select("post", "category", [], prompt: true) ) end end diff --git a/actionview/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb index 7a5904f151..477d4f9eca 100644 --- a/actionview/test/template/form_options_helper_test.rb +++ b/actionview/test/template/form_options_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class Map < Hash def category @@ -10,11 +10,11 @@ class FormOptionsHelperTest < ActionView::TestCase tests ActionView::Helpers::FormOptionsHelper silence_warnings do - Post = Struct.new('Post', :title, :author_name, :body, :secret, :written_on, :category, :origin, :allow_comments) - Continent = Struct.new('Continent', :continent_name, :countries) - Country = Struct.new('Country', :country_id, :country_name) - Firm = Struct.new('Firm', :time_zone) - Album = Struct.new('Album', :id, :title, :genre) + Post = Struct.new("Post", :title, :author_name, :body, :secret, :written_on, :category, :origin, :allow_comments) + Continent = Struct.new("Continent", :continent_name, :countries) + Country = Struct.new("Country", :country_id, :country_name) + Firm = Struct.new("Firm", :time_zone) + Album = Struct.new("Album", :id, :title, :genre) end module FakeZones @@ -57,7 +57,6 @@ class FormOptionsHelperTest < ActionView::TestCase ) end - def test_collection_options_with_preselected_value assert_dom_equal( "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" selected=\"selected\">Babe went home</option>\n<option value=\"Cabe\">Cabe went home</option>", @@ -66,44 +65,44 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_collection_options_with_preselected_value_array - assert_dom_equal( - "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" selected=\"selected\">Babe went home</option>\n<option value=\"Cabe\" selected=\"selected\">Cabe went home</option>", - options_from_collection_for_select(dummy_posts, "author_name", "title", [ "Babe", "Cabe" ]) - ) + assert_dom_equal( + "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" selected=\"selected\">Babe went home</option>\n<option value=\"Cabe\" selected=\"selected\">Cabe went home</option>", + options_from_collection_for_select(dummy_posts, "author_name", "title", [ "Babe", "Cabe" ]) + ) end def test_collection_options_with_proc_for_selected assert_dom_equal( "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" selected=\"selected\">Babe went home</option>\n<option value=\"Cabe\">Cabe went home</option>", - options_from_collection_for_select(dummy_posts, "author_name", "title", lambda{|p| p.author_name == 'Babe' }) + options_from_collection_for_select(dummy_posts, "author_name", "title", lambda { |p| p.author_name == "Babe" }) ) end def test_collection_options_with_disabled_value assert_dom_equal( "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" disabled=\"disabled\">Babe went home</option>\n<option value=\"Cabe\">Cabe went home</option>", - options_from_collection_for_select(dummy_posts, "author_name", "title", :disabled => "Babe") + options_from_collection_for_select(dummy_posts, "author_name", "title", disabled: "Babe") ) end def test_collection_options_with_disabled_array assert_dom_equal( "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" disabled=\"disabled\">Babe went home</option>\n<option value=\"Cabe\" disabled=\"disabled\">Cabe went home</option>", - options_from_collection_for_select(dummy_posts, "author_name", "title", :disabled => [ "Babe", "Cabe" ]) + options_from_collection_for_select(dummy_posts, "author_name", "title", disabled: [ "Babe", "Cabe" ]) ) end def test_collection_options_with_preselected_and_disabled_value assert_dom_equal( "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" disabled=\"disabled\">Babe went home</option>\n<option value=\"Cabe\" selected=\"selected\">Cabe went home</option>", - options_from_collection_for_select(dummy_posts, "author_name", "title", :selected => "Cabe", :disabled => "Babe") + options_from_collection_for_select(dummy_posts, "author_name", "title", selected: "Cabe", disabled: "Babe") ) end def test_collection_options_with_proc_for_disabled assert_dom_equal( "<option value=\"<Abe>\"><Abe> went home</option>\n<option value=\"Babe\" disabled=\"disabled\">Babe went home</option>\n<option value=\"Cabe\" disabled=\"disabled\">Cabe went home</option>", - options_from_collection_for_select(dummy_posts, "author_name", "title", :disabled => lambda {|p| %w(Babe Cabe).include?(p.author_name)}) + options_from_collection_for_select(dummy_posts, "author_name", "title", disabled: lambda { |p| %w(Babe Cabe).include?(p.author_name) }) ) end @@ -124,7 +123,7 @@ class FormOptionsHelperTest < ActionView::TestCase def test_collection_options_with_element_attributes assert_dom_equal( "<option value=\"USA\" class=\"bold\">USA</option>", - options_from_collection_for_select([[ "USA", "USA", { :class => 'bold' } ]], :first, :second) + options_from_collection_for_select([[ "USA", "USA", { class: "bold" } ]], :first, :second) ) end @@ -147,8 +146,8 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<option selected=\"selected\" type=\"Coach\" value=\"1\">Richard Bandler</option>\n<option type=\"Coachee\" value=\"1\">Richard Bandler</option>", options_for_select([ - ['Richard Bandler', 1, { type: 'Coach', selected: 'selected' }], - ['Richard Bandler', 1, { type: 'Coachee' }] + ["Richard Bandler", 1, { type: "Coach", selected: "selected" }], + ["Richard Bandler", 1, { type: "Coachee" }] ]) ) end @@ -157,8 +156,8 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<option disabled=\"disabled\" type=\"Coach\" value=\"1\">Richard Bandler</option>\n<option type=\"Coachee\" value=\"1\">Richard Bandler</option>", options_for_select([ - ['Richard Bandler', 1, { type: 'Coach', disabled: 'disabled' }], - ['Richard Bandler', 1, { type: 'Coachee' }] + ["Richard Bandler", 1, { type: "Coach", disabled: "disabled" }], + ["Richard Bandler", 1, { type: "Coachee" }] ]) ) end @@ -171,37 +170,37 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_array_options_for_select_with_selection_array - assert_dom_equal( - "<option value=\"Denmark\">Denmark</option>\n<option value=\"<USA>\" selected=\"selected\"><USA></option>\n<option value=\"Sweden\" selected=\"selected\">Sweden</option>", - options_for_select([ "Denmark", "<USA>", "Sweden" ], [ "<USA>", "Sweden" ]) - ) + assert_dom_equal( + "<option value=\"Denmark\">Denmark</option>\n<option value=\"<USA>\" selected=\"selected\"><USA></option>\n<option value=\"Sweden\" selected=\"selected\">Sweden</option>", + options_for_select([ "Denmark", "<USA>", "Sweden" ], [ "<USA>", "Sweden" ]) + ) end def test_array_options_for_select_with_disabled_value assert_dom_equal( "<option value=\"Denmark\">Denmark</option>\n<option value=\"<USA>\" disabled=\"disabled\"><USA></option>\n<option value=\"Sweden\">Sweden</option>", - options_for_select([ "Denmark", "<USA>", "Sweden" ], :disabled => "<USA>") + options_for_select([ "Denmark", "<USA>", "Sweden" ], disabled: "<USA>") ) end def test_array_options_for_select_with_disabled_array assert_dom_equal( "<option value=\"Denmark\">Denmark</option>\n<option value=\"<USA>\" disabled=\"disabled\"><USA></option>\n<option value=\"Sweden\" disabled=\"disabled\">Sweden</option>", - options_for_select([ "Denmark", "<USA>", "Sweden" ], :disabled => ["<USA>", "Sweden"]) + options_for_select([ "Denmark", "<USA>", "Sweden" ], disabled: ["<USA>", "Sweden"]) ) end def test_array_options_for_select_with_selection_and_disabled_value assert_dom_equal( "<option value=\"Denmark\" selected=\"selected\">Denmark</option>\n<option value=\"<USA>\" disabled=\"disabled\"><USA></option>\n<option value=\"Sweden\">Sweden</option>", - options_for_select([ "Denmark", "<USA>", "Sweden" ], :selected => "Denmark", :disabled => "<USA>") + options_for_select([ "Denmark", "<USA>", "Sweden" ], selected: "Denmark", disabled: "<USA>") ) end def test_boolean_array_options_for_select_with_selection_and_disabled_value assert_dom_equal( "<option value=\"true\">true</option>\n<option value=\"false\" selected=\"selected\">false</option>", - options_for_select([ true, false ], :selected => false, :disabled => nil) + options_for_select([ true, false ], selected: false, disabled: nil) ) end @@ -213,18 +212,18 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_array_options_for_string_include_in_other_string_bug_fix - assert_dom_equal( - "<option value=\"ruby\">ruby</option>\n<option value=\"rubyonrails\" selected=\"selected\">rubyonrails</option>", - options_for_select([ "ruby", "rubyonrails" ], "rubyonrails") - ) - assert_dom_equal( - "<option value=\"ruby\" selected=\"selected\">ruby</option>\n<option value=\"rubyonrails\">rubyonrails</option>", - options_for_select([ "ruby", "rubyonrails" ], "ruby") - ) - assert_dom_equal( - %(<option value="ruby" selected="selected">ruby</option>\n<option value="rubyonrails">rubyonrails</option>\n<option value=""></option>), - options_for_select([ "ruby", "rubyonrails", nil ], "ruby") - ) + assert_dom_equal( + "<option value=\"ruby\">ruby</option>\n<option value=\"rubyonrails\" selected=\"selected\">rubyonrails</option>", + options_for_select([ "ruby", "rubyonrails" ], "rubyonrails") + ) + assert_dom_equal( + "<option value=\"ruby\" selected=\"selected\">ruby</option>\n<option value=\"rubyonrails\">rubyonrails</option>", + options_for_select([ "ruby", "rubyonrails" ], "ruby") + ) + assert_dom_equal( + %(<option value="ruby" selected="selected">ruby</option>\n<option value="rubyonrails">rubyonrails</option>\n<option value=""></option>), + options_for_select([ "ruby", "rubyonrails", nil ], "ruby") + ) end def test_hash_options_for_select @@ -262,7 +261,7 @@ class FormOptionsHelperTest < ActionView::TestCase albums = [ Album.new(1, "first","rap"), Album.new(2, "second","pop")] assert_dom_equal( %(<option selected="selected" value="1">rap</option>\n<option value="2">pop</option>), - options_from_collection_for_select(albums, "id", "genre", :selected => "1") + options_from_collection_for_select(albums, "id", "genre", selected: "1") ) end @@ -271,7 +270,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %(<option selected="selected" value="1">rap</option>\n<option value="2">pop</option>), - options_from_collection_for_select(albums, "id", "genre", :selected => 1) + options_from_collection_for_select(albums, "id", "genre", selected: 1) ) end @@ -280,7 +279,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %(<option value="1.0">rap</option>\n<option value="2.0" selected="selected">pop</option>), - options_from_collection_for_select(albums, "id", "genre", :selected => "2.0") + options_from_collection_for_select(albums, "id", "genre", selected: "2.0") ) end @@ -289,7 +288,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %(<option value="1.0">rap</option>\n<option value="2.0">pop</option>), - options_from_collection_for_select(albums, "id", "genre", :selected => nil) + options_from_collection_for_select(albums, "id", "genre", selected: nil) ) end @@ -298,7 +297,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %(<option value="1.0">rap</option>\n<option value="2.0">pop</option>), - options_from_collection_for_select(albums, "id", "genre", :disabled => nil) + options_from_collection_for_select(albums, "id", "genre", disabled: nil) ) end @@ -307,7 +306,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %(<option disabled="disabled" value="1.0">rap</option>\n<option disabled="disabled" value="2.0">pop</option>), - options_from_collection_for_select(albums, "id", "genre", :disabled => ["1.0", 2.0]) + options_from_collection_for_select(albums, "id", "genre", disabled: ["1.0", 2.0]) ) end @@ -336,7 +335,7 @@ class FormOptionsHelperTest < ActionView::TestCase "<optgroup label=\"North America\"><option value=\"US\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"Europe\"><option value=\"GB\">Great Britain</option>\n<option value=\"Germany\">Germany</option></optgroup>", grouped_options_for_select([ ["North America", - [['United States','US'],"Canada"]], + [["United States","US"],"Canada"]], ["Europe", [["Great Britain","GB"], "Germany"]] ]) @@ -347,8 +346,8 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<optgroup label=\"North America\" data-foo=\"bar\"><option value=\"US\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"Europe\" disabled=\"disabled\"><option value=\"GB\">Great Britain</option>\n<option value=\"Germany\">Germany</option></optgroup>", grouped_options_for_select([ - ["North America", [['United States','US'],"Canada"], :data => { :foo => 'bar' }], - ["Europe", [["Great Britain","GB"], "Germany"], :disabled => 'disabled'] + ["North America", [["United States","US"],"Canada"], data: { foo: "bar" }], + ["Europe", [["Great Britain","GB"], "Germany"], disabled: "disabled"] ]) ) end @@ -357,7 +356,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<optgroup label=\"----------\"><option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"----------\"><option value=\"GB\">GB</option>\n<option value=\"Germany\">Germany</option></optgroup>", - grouped_options_for_select([['US',"Canada"] , ["GB", "Germany"]], nil, divider: "----------") + grouped_options_for_select([["US","Canada"] , ["GB", "Germany"]], nil, divider: "----------") ) end @@ -382,13 +381,13 @@ class FormOptionsHelperTest < ActionView::TestCase def test_grouped_options_for_select_with_prompt_returns_html_escaped_string assert_dom_equal( "<option value=\"\"><Choose One></option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>", - grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, prompt: '<Choose One>')) + grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, prompt: "<Choose One>")) end def test_optgroups_with_with_options_with_hash assert_dom_equal( "<optgroup label=\"North America\"><option value=\"United States\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"Europe\"><option value=\"Denmark\">Denmark</option>\n<option value=\"Germany\">Germany</option></optgroup>", - grouped_options_for_select({'North America' => ['United States','Canada'], 'Europe' => ['Denmark','Germany']}) + grouped_options_for_select("North America" => ["United States","Canada"], "Europe" => ["Denmark","Germany"]) ) end @@ -481,7 +480,7 @@ class FormOptionsHelperTest < ActionView::TestCase def test_select_without_multiple assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"></select>", - select(:post, :category, "", {}, :multiple => false) + select(:post, :category, "", {}, multiple: false) ) end @@ -495,9 +494,9 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( [ - %Q{<select id="post_origin" name="post[origin]"><optgroup label="<Africa>"><option value="<sa>"><South Africa></option>}, - %Q{<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk">Denmark</option>}, - %Q{<option value="ie">Ireland</option></optgroup></select>}, + '<select id="post_origin" name="post[origin]"><optgroup label="<Africa>"><option value="<sa>"><South Africa></option>', + '<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk">Denmark</option>', + '<option value="ie">Ireland</option></optgroup></select>', ].join("\n"), select("post", "origin", countries_by_continent) ) @@ -513,9 +512,9 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( [ - %Q{<select id="post_origin" name="post[origin]"><optgroup label="<Africa>"><option value="<sa>"><South Africa></option>}, - %Q{<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk">Denmark</option>}, - %Q{<option value="ie">Ireland</option></optgroup></select>}, + '<select id="post_origin" name="post[origin]"><optgroup label="<Africa>"><option value="<sa>"><South Africa></option>', + '<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk">Denmark</option>', + '<option value="ie">Ireland</option></optgroup></select>', ].join("\n"), select("post", "origin", countries_by_continent) ) @@ -561,7 +560,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new @post.category = "<mus>" - output_buffer = fields_for :post, @post, :index => 108 do |f| + output_buffer = fields_for :post, @post, index: 108 do |f| concat f.select(:category, %w( abe <mus> hest)) end @@ -591,7 +590,7 @@ class FormOptionsHelperTest < ActionView::TestCase options = raw("<option value=\"abe\">abe</option><option value=\"mus\">mus</option><option value=\"hest\">hest</option>") output_buffer = fields_for :post, @post do |f| - concat f.select(:category, options, :prompt => 'The prompt') + concat f.select(:category, options, prompt: "The prompt") end assert_dom_equal( @@ -629,7 +628,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_select_with_multiple_to_add_hidden_input - output_buffer = select(:post, :category, "", {}, :multiple => true) + output_buffer = select(:post, :category, "", {}, multiple: true) assert_dom_equal( "<input type=\"hidden\" name=\"post[category][]\" value=\"\"/><select multiple=\"multiple\" id=\"post_category\" name=\"post[category][]\"></select>", output_buffer @@ -637,7 +636,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_select_with_multiple_and_without_hidden_input - output_buffer = select(:post, :category, "", {:include_hidden => false}, :multiple => true) + output_buffer = select(:post, :category, "", { include_hidden: false }, multiple: true) assert_dom_equal( "<select multiple=\"multiple\" id=\"post_category\" name=\"post[category][]\"></select>", output_buffer @@ -645,7 +644,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_select_with_multiple_and_with_explicit_name_ending_with_brackets - output_buffer = select(:post, :category, [], {include_hidden: false}, multiple: true, name: 'post[category][]') + output_buffer = select(:post, :category, [], { include_hidden: false }, multiple: true, name: "post[category][]") assert_dom_equal( "<select multiple=\"multiple\" id=\"post_category\" name=\"post[category][]\"></select>", output_buffer @@ -653,7 +652,7 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_select_with_multiple_and_disabled_to_add_disabled_hidden_input - output_buffer = select(:post, :category, "", {}, :multiple => true, :disabled => true) + output_buffer = select(:post, :category, "", {}, multiple: true, disabled: true) assert_dom_equal( "<input disabled=\"disabled\"type=\"hidden\" name=\"post[category][]\" value=\"\"/><select multiple=\"multiple\" disabled=\"disabled\" id=\"post_category\" name=\"post[category][]\"></select>", output_buffer @@ -665,14 +664,14 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\"></option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :include_blank => true) + select("post", "category", %w( abe <mus> hest), include_blank: true) ) end def test_select_with_include_blank_false_and_required @post = Post.new @post.category = "<mus>" - e = assert_raises(ArgumentError) { select("post", "category", %w( abe <mus> hest), { include_blank: false }, required: 'required') } + e = assert_raises(ArgumentError) { select("post", "category", %w( abe <mus> hest), { include_blank: false }, required: "required") } assert_match(/include_blank cannot be false for a required field./, e.message) end @@ -681,7 +680,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">None</option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :include_blank => 'None') + select("post", "category", %w( abe <mus> hest), include_blank: "None") ) end @@ -690,7 +689,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\"><None></option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :include_blank => '<None>') + select("post", "category", %w( abe <mus> hest), include_blank: "<None>") ) end @@ -699,7 +698,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">Please select</option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :prompt => true) + select("post", "category", %w( abe <mus> hest), prompt: true) ) end @@ -708,7 +707,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :prompt => true) + select("post", "category", %w( abe <mus> hest), prompt: true) ) end @@ -717,7 +716,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">The prompt</option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :prompt => 'The prompt') + select("post", "category", %w( abe <mus> hest), prompt: "The prompt") ) end @@ -725,7 +724,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\"><The prompt></option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :prompt => '<The prompt>') + select("post", "category", %w( abe <mus> hest), prompt: "<The prompt>") ) end @@ -734,16 +733,25 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">Please select</option>\n<option value=\"\"></option>\n<option value=\"abe\">abe</option>\n<option value=\"<mus>\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest), :prompt => true, :include_blank => true) + select("post", "category", %w( abe <mus> hest), prompt: true, include_blank: true) ) end - def test_empty + def test_select_with_empty @post = Post.new @post.category = "" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">Please select</option>\n<option value=\"\"></option>\n</select>", - select("post", "category", [], :prompt => true, :include_blank => true) + select("post", "category", [], prompt: true, include_blank: true) + ) + end + + def test_select_with_html_options + @post = Post.new + @post.category = "" + assert_dom_equal( + "<select class=\"disabled\" disabled=\"disabled\" name=\"post[category]\" id=\"post_category\"><option value=\"\">Please select</option>\n<option value=\"\"></option>\n</select>", + select("post", "category", [], { prompt: true, include_blank: true }, class: "disabled", disabled: true) ) end @@ -803,7 +811,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">Please select</option>\n<option value=\"\"></option>\n<option value=\"1\">1</option></select>", - select("post", "category", [1], :prompt => true, :include_blank => true) + select("post", "category", [1], prompt: true, include_blank: true) ) end @@ -812,7 +820,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">Please select</option>\n<option value=\"\"></option>\n<option value=\"number\">Number</option>\n<option value=\"text\">Text</option>\n<option value=\"boolean\">Yes/No</option></select>", - select("post", "category", [["Number", "number"], ["Text", "text"], ["Yes/No", "boolean"]], :prompt => true, :include_blank => true) + select("post", "category", [["Number", "number"], ["Text", "text"], ["Yes/No", "boolean"]], prompt: true, include_blank: true) ) end @@ -821,7 +829,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\" selected=\"selected\">abe</option>\n<option value=\"<mus>\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest ), :selected => 'abe') + select("post", "category", %w( abe <mus> hest ), selected: "abe") ) end @@ -833,14 +841,14 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( expected, - select("album[]", "genre", %w[rap rock country], {}, { :index => nil }) + select("album[]", "genre", %w[rap rock country], {}, index: nil) ) end def test_select_escapes_options assert_dom_equal( '<select id="post_title" name="post[title]"><script>alert(1)</script></select>', - select('post', 'title', '<script>alert(1)</script>') + select("post", "title", "<script>alert(1)</script>") ) end @@ -849,7 +857,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\">abe</option>\n<option value=\"<mus>\"><mus></option>\n<option value=\"hest\">hest</option></select>", - select("post", "category", %w( abe <mus> hest ), :selected => nil) + select("post", "category", %w( abe <mus> hest ), selected: nil) ) end @@ -858,7 +866,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\" disabled=\"disabled\">hest</option></select>", - select("post", "category", %w( abe <mus> hest ), :disabled => 'hest') + select("post", "category", %w( abe <mus> hest ), disabled: "hest") ) end @@ -866,7 +874,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new assert_dom_equal( "<select id=\"post_locale\" name=\"post[locale]\"><option value=\"en\">en</option>\n<option value=\"ru\" selected=\"selected\">ru</option></select>", - select("post", "locale", %w( en ru ), :selected => 'ru') + select("post", "locale", %w( en ru ), selected: "ru") ) end @@ -874,7 +882,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"one\">one</option>\n<option selected=\"selected\" value=\"two\">two</option></select>", - select("post", "category", %w( one two ), :selected => 'two', :prompt => true) + select("post", "category", %w( one two ), selected: "two", prompt: true) ) end @@ -883,7 +891,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post.category = "<mus>" assert_dom_equal( "<select id=\"post_category\" name=\"post[category]\"><option value=\"abe\" disabled=\"disabled\">abe</option>\n<option value=\"<mus>\" selected=\"selected\"><mus></option>\n<option value=\"hest\" disabled=\"disabled\">hest</option></select>", - select("post", "category", %w( abe <mus> hest ), :disabled => ['hest', 'abe']) + select("post", "category", %w( abe <mus> hest ), disabled: ["hest", "abe"]) ) end @@ -924,7 +932,7 @@ class FormOptionsHelperTest < ActionView::TestCase @post = Post.new @post.author_name = "Babe" - output_buffer = fields_for :post, @post, :index => 815 do |f| + output_buffer = fields_for :post, @post, index: 815 do |f| concat f.collection_select(:author_name, dummy_posts, :author_name, :author_name) end @@ -955,7 +963,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<select id=\"post_author_name\" name=\"post[author_name]\" style=\"width: 200px\"><option value=\"\"></option>\n<option value=\"<Abe>\"><Abe></option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\">Cabe</option></select>", - collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => true }, "style" => "width: 200px") + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { include_blank: true }, "style" => "width: 200px") ) end @@ -965,7 +973,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<select id=\"post_author_name\" name=\"post[author_name]\" style=\"width: 200px\"><option value=\"\">No Selection</option>\n<option value=\"<Abe>\"><Abe></option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\">Cabe</option></select>", - collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => 'No Selection' }, "style" => "width: 200px") + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { include_blank: "No Selection" }, "style" => "width: 200px") ) end @@ -976,10 +984,10 @@ class FormOptionsHelperTest < ActionView::TestCase expected = "<input type=\"hidden\" name=\"post[author_name][]\" value=\"\"/><select id=\"post_author_name\" name=\"post[author_name][]\" multiple=\"multiple\"><option value=\"\"></option>\n<option value=\"<Abe>\"><Abe></option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\">Cabe</option></select>" # Should suffix default name with []. - assert_dom_equal expected, collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => true }, :multiple => true) + assert_dom_equal expected, collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { include_blank: true }, multiple: true) # Shouldn't suffix custom name with []. - assert_dom_equal expected, collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => true, :name => 'post[author_name][]' }, :multiple => true) + assert_dom_equal expected, collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { include_blank: true, name: "post[author_name][]" }, multiple: true) end def test_collection_select_with_blank_and_selected @@ -988,7 +996,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %{<select id="post_author_name" name="post[author_name]"><option value=""></option>\n<option value="<Abe>" selected="selected"><Abe></option>\n<option value="Babe">Babe</option>\n<option value="Cabe">Cabe</option></select>}, - collection_select("post", "author_name", dummy_posts, "author_name", "author_name", {:include_blank => true, :selected => "<Abe>"}) + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", include_blank: true, selected: "<Abe>") ) end @@ -998,7 +1006,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( "<select id=\"post_author_name\" name=\"post[author_name]\"><option value=\"<Abe>\"><Abe></option>\n<option value=\"Babe\" selected=\"selected\">Babe</option>\n<option value=\"Cabe\" disabled=\"disabled\">Cabe</option></select>", - collection_select("post", "author_name", dummy_posts, "author_name", "author_name", :disabled => 'Cabe') + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", disabled: "Cabe") ) end @@ -1055,7 +1063,7 @@ class FormOptionsHelperTest < ActionView::TestCase def test_time_zone_select_under_fields_for_with_index @firm = Firm.new("D") - output_buffer = fields_for :firm, @firm, :index => 305 do |f| + output_buffer = fields_for :firm, @firm, index: 305 do |f| concat f.time_zone_select(:time_zone) end @@ -1093,7 +1101,7 @@ class FormOptionsHelperTest < ActionView::TestCase def test_time_zone_select_with_blank @firm = Firm.new("D") - html = time_zone_select("firm", "time_zone", nil, :include_blank => true) + html = time_zone_select("firm", "time_zone", nil, include_blank: true) assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" + "<option value=\"\"></option>\n" + "<option value=\"A\">A</option>\n" + @@ -1107,7 +1115,7 @@ class FormOptionsHelperTest < ActionView::TestCase def test_time_zone_select_with_blank_as_string @firm = Firm.new("D") - html = time_zone_select("firm", "time_zone", nil, :include_blank => 'No Zone') + html = time_zone_select("firm", "time_zone", nil, include_blank: "No Zone") assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" + "<option value=\"\">No Zone</option>\n" + "<option value=\"A\">A</option>\n" + @@ -1132,13 +1140,13 @@ class FormOptionsHelperTest < ActionView::TestCase "</select>", html assert_dom_equal html, time_zone_select("firm", "time_zone", nil, {}, - :style => "color: red") + style: "color: red") end def test_time_zone_select_with_blank_and_style @firm = Firm.new("D") html = time_zone_select("firm", "time_zone", nil, - { :include_blank => true }, "style" => "color: red") + { include_blank: true }, "style" => "color: red") assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" + "<option value=\"\"></option>\n" + "<option value=\"A\">A</option>\n" + @@ -1149,13 +1157,13 @@ class FormOptionsHelperTest < ActionView::TestCase "</select>", html assert_dom_equal html, time_zone_select("firm", "time_zone", nil, - { :include_blank => true }, :style => "color: red") + { include_blank: true }, style: "color: red") end def test_time_zone_select_with_blank_as_string_and_style @firm = Firm.new("D") html = time_zone_select("firm", "time_zone", nil, - { :include_blank => 'No Zone' }, "style" => "color: red") + { include_blank: "No Zone" }, "style" => "color: red") assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\" style=\"color: red\">" + "<option value=\"\">No Zone</option>\n" + "<option value=\"A\">A</option>\n" + @@ -1166,7 +1174,7 @@ class FormOptionsHelperTest < ActionView::TestCase "</select>", html assert_dom_equal html, time_zone_select("firm", "time_zone", nil, - { :include_blank => 'No Zone' }, :style => "color: red") + { include_blank: "No Zone" }, style: "color: red") end def test_time_zone_select_with_priority_zones @@ -1225,24 +1233,24 @@ class FormOptionsHelperTest < ActionView::TestCase end def test_time_zone_select_with_default_time_zone_and_nil_value - @firm = Firm.new() - @firm.time_zone = nil + @firm = Firm.new() + @firm.time_zone = nil - html = time_zone_select( "firm", "time_zone", nil, :default => 'B' ) - assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" + - "<option value=\"A\">A</option>\n" + - "<option value=\"B\" selected=\"selected\">B</option>\n" + - "<option value=\"C\">C</option>\n" + - "<option value=\"D\">D</option>\n" + - "<option value=\"E\">E</option>" + - "</select>", - html + html = time_zone_select( "firm", "time_zone", nil, default: "B" ) + assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" + + "<option value=\"A\">A</option>\n" + + "<option value=\"B\" selected=\"selected\">B</option>\n" + + "<option value=\"C\">C</option>\n" + + "<option value=\"D\">D</option>\n" + + "<option value=\"E\">E</option>" + + "</select>", + html end def test_time_zone_select_with_default_time_zone_and_value - @firm = Firm.new('D') + @firm = Firm.new("D") - html = time_zone_select( "firm", "time_zone", nil, :default => 'B' ) + html = time_zone_select( "firm", "time_zone", nil, default: "B" ) assert_dom_equal "<select id=\"firm_time_zone\" name=\"firm[time_zone]\">" + "<option value=\"A\">A</option>\n" + "<option value=\"B\">B</option>\n" + @@ -1256,86 +1264,86 @@ class FormOptionsHelperTest < ActionView::TestCase def test_options_for_select_with_element_attributes assert_dom_equal( "<option value=\"<Denmark>\" class=\"bold\"><Denmark></option>\n<option value=\"USA\" onclick=\"alert('Hello World');\">USA</option>\n<option value=\"Sweden\">Sweden</option>\n<option value=\"Germany\">Germany</option>", - options_for_select([ [ "<Denmark>", { :class => 'bold' } ], [ "USA", { :onclick => "alert('Hello World');" } ], [ "Sweden" ], "Germany" ]) + options_for_select([ [ "<Denmark>", { class: "bold" } ], [ "USA", { onclick: "alert('Hello World');" } ], [ "Sweden" ], "Germany" ]) ) end def test_options_for_select_with_data_element assert_dom_equal( "<option value=\"<Denmark>\" data-test=\"bold\"><Denmark></option>", - options_for_select([ [ "<Denmark>", { :data => { :test => 'bold' } } ] ]) + options_for_select([ [ "<Denmark>", { data: { test: "bold" } } ] ]) ) end def test_options_for_select_with_data_element_with_special_characters assert_dom_equal( "<option value=\"<Denmark>\" data-test=\"<bold>\"><Denmark></option>", - options_for_select([ [ "<Denmark>", { :data => { :test => '<bold>' } } ] ]) + options_for_select([ [ "<Denmark>", { data: { test: "<bold>" } } ] ]) ) end def test_options_for_select_with_element_attributes_and_selection assert_dom_equal( "<option value=\"<Denmark>\"><Denmark></option>\n<option value=\"USA\" class=\"bold\" selected=\"selected\">USA</option>\n<option value=\"Sweden\">Sweden</option>", - options_for_select([ "<Denmark>", [ "USA", { :class => 'bold' } ], "Sweden" ], "USA") + options_for_select([ "<Denmark>", [ "USA", { class: "bold" } ], "Sweden" ], "USA") ) end def test_options_for_select_with_element_attributes_and_selection_array assert_dom_equal( "<option value=\"<Denmark>\"><Denmark></option>\n<option value=\"USA\" class=\"bold\" selected=\"selected\">USA</option>\n<option value=\"Sweden\" selected=\"selected\">Sweden</option>", - options_for_select([ "<Denmark>", [ "USA", { :class => 'bold' } ], "Sweden" ], [ "USA", "Sweden" ]) + options_for_select([ "<Denmark>", [ "USA", { class: "bold" } ], "Sweden" ], [ "USA", "Sweden" ]) ) end def test_options_for_select_with_special_characters assert_dom_equal( "<option value=\"<Denmark>\" onclick=\"alert("<code>")\"><Denmark></option>", - options_for_select([ [ "<Denmark>", { :onclick => %(alert("<code>")) } ] ]) + options_for_select([ [ "<Denmark>", { onclick: %(alert("<code>")) } ] ]) ) end def test_option_html_attributes_with_no_array_element - assert_equal({}, option_html_attributes('foo')) + assert_equal({}, option_html_attributes("foo")) end def test_option_html_attributes_without_hash - assert_equal({}, option_html_attributes([ 'foo', 'bar' ])) + assert_equal({}, option_html_attributes([ "foo", "bar" ])) end def test_option_html_attributes_with_single_element_hash assert_equal( - {:class => 'fancy'}, - option_html_attributes([ 'foo', 'bar', { :class => 'fancy' } ]) + { class: "fancy" }, + option_html_attributes([ "foo", "bar", { class: "fancy" } ]) ) end def test_option_html_attributes_with_multiple_element_hash assert_equal( - {:class => 'fancy', 'onclick' => "alert('Hello World');"}, - option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ]) + { :class => "fancy", "onclick" => "alert('Hello World');" }, + option_html_attributes([ "foo", "bar", { :class => "fancy", "onclick" => "alert('Hello World');" } ]) ) end def test_option_html_attributes_with_multiple_hashes assert_equal( - {:class => 'fancy', 'onclick' => "alert('Hello World');"}, - option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ]) + { :class => "fancy", "onclick" => "alert('Hello World');" }, + option_html_attributes([ "foo", "bar", { class: "fancy" }, { "onclick" => "alert('Hello World');" } ]) ) end def test_option_html_attributes_with_multiple_hashes_does_not_modify_them - options1 = { class: 'fancy' } + options1 = { class: "fancy" } options2 = { onclick: "alert('Hello World');" } - option_html_attributes([ 'foo', 'bar', options1, options2 ]) + option_html_attributes([ "foo", "bar", options1, options2 ]) - assert_equal({ class: 'fancy' }, options1) + assert_equal({ class: "fancy" }, options1) assert_equal({ onclick: "alert('Hello World');" }, options2) end def test_grouped_collection_select @post = Post.new - @post.origin = 'dk' + @post.origin = "dk" assert_dom_equal( %Q{<select id="post_origin" name="post[origin]"><optgroup label="<Africa>"><option value="<sa>"><South Africa></option>\n<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk" selected="selected">Denmark</option>\n<option value="ie">Ireland</option></optgroup></select>}, @@ -1348,7 +1356,7 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %Q{<select id="post_origin" name="post[origin]"><optgroup label="<Africa>"><option value="<sa>"><South Africa></option>\n<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk" selected="selected">Denmark</option>\n<option value="ie">Ireland</option></optgroup></select>}, - grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, :selected => 'dk') + grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, selected: "dk") ) end @@ -1357,13 +1365,13 @@ class FormOptionsHelperTest < ActionView::TestCase assert_dom_equal( %Q{<select id="post_origin" name="post[origin]"><optgroup label="<Africa>"><option value="<sa>"><South Africa></option>\n<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option disabled="disabled" value="dk">Denmark</option>\n<option value="ie">Ireland</option></optgroup></select>}, - grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, :disabled => 'dk') + grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, disabled: "dk") ) end def test_grouped_collection_select_under_fields_for @post = Post.new - @post.origin = 'dk' + @post.origin = "dk" output_buffer = fields_for :post, @post do |f| concat f.grouped_collection_select("origin", dummy_continents, :countries, :continent_name, :country_id, :country_name) @@ -1377,14 +1385,14 @@ class FormOptionsHelperTest < ActionView::TestCase private - def dummy_posts - [ Post.new("<Abe> went home", "<Abe>", "To a little house", "shh!"), - Post.new("Babe went home", "Babe", "To a little house", "shh!"), - Post.new("Cabe went home", "Cabe", "To a little house", "shh!") ] - end + def dummy_posts + [ Post.new("<Abe> went home", "<Abe>", "To a little house", "shh!"), + Post.new("Babe went home", "Babe", "To a little house", "shh!"), + Post.new("Cabe went home", "Cabe", "To a little house", "shh!") ] + end - def dummy_continents - [ Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")]), - Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")]) ] - end + def dummy_continents + [ Continent.new("<Africa>", [Country.new("<sa>", "<South Africa>"), Country.new("so", "Somalia")]), + Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")]) ] + end end diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb index 5b0b708618..da929cac8f 100644 --- a/actionview/test/template/form_tag_helper_test.rb +++ b/actionview/test/template/form_tag_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class FormTagHelperTest < ActionView::TestCase include RenderERBUtils @@ -14,7 +14,7 @@ class FormTagHelperTest < ActionView::TestCase method = options[:method] enforce_utf8 = options.fetch(:enforce_utf8, true) - ''.tap do |txt| + "".tap do |txt| if enforce_utf8 txt << %{<input name="utf8" type="hidden" value="✓" />} end @@ -78,7 +78,7 @@ class FormTagHelperTest < ActionView::TestCase def test_check_box_tag_id_sanitized label_elem = root_elem(check_box_tag("project[2][admin]")) - assert_match VALID_HTML_ID, label_elem['id'] + assert_match VALID_HTML_ID, label_elem["id"] end def test_form_tag @@ -88,54 +88,54 @@ class FormTagHelperTest < ActionView::TestCase end def test_form_tag_multipart - actual = form_tag({}, { 'multipart' => true }) - expected = whole_form("http://www.example.com", :enctype => true) + actual = form_tag({}, "multipart" => true) + expected = whole_form("http://www.example.com", enctype: true) assert_dom_equal expected, actual end def test_form_tag_with_method_patch - actual = form_tag({}, { :method => :patch }) - expected = whole_form("http://www.example.com", :method => :patch) + actual = form_tag({}, method: :patch) + expected = whole_form("http://www.example.com", method: :patch) assert_dom_equal expected, actual end def test_form_tag_with_method_put - actual = form_tag({}, { :method => :put }) - expected = whole_form("http://www.example.com", :method => :put) + actual = form_tag({}, method: :put) + expected = whole_form("http://www.example.com", method: :put) assert_dom_equal expected, actual end def test_form_tag_with_method_delete - actual = form_tag({}, { :method => :delete }) + actual = form_tag({}, method: :delete) - expected = whole_form("http://www.example.com", :method => :delete) + expected = whole_form("http://www.example.com", method: :delete) assert_dom_equal expected, actual end def test_form_tag_with_remote - actual = form_tag({}, :remote => true) + actual = form_tag({}, remote: true) - expected = whole_form("http://www.example.com", :remote => true) + expected = whole_form("http://www.example.com", remote: true) assert_dom_equal expected, actual end def test_form_tag_with_remote_false - actual = form_tag({}, :remote => false) + actual = form_tag({}, remote: false) expected = whole_form assert_dom_equal expected, actual end def test_form_tag_enforce_utf8_true - actual = form_tag({}, { :enforce_utf8 => true }) - expected = whole_form("http://www.example.com", :enforce_utf8 => true) + actual = form_tag({}, enforce_utf8: true) + expected = whole_form("http://www.example.com", enforce_utf8: true) assert_dom_equal expected, actual assert actual.html_safe? end def test_form_tag_enforce_utf8_false - actual = form_tag({}, { :enforce_utf8 => false }) - expected = whole_form("http://www.example.com", :enforce_utf8 => false) + actual = form_tag({}, enforce_utf8: false) + expected = whole_form("http://www.example.com", enforce_utf8: false) assert_dom_equal expected, actual assert actual.html_safe? end @@ -150,7 +150,7 @@ class FormTagHelperTest < ActionView::TestCase def test_form_tag_with_block_and_method_in_erb output_buffer = render_erb("<%= form_tag('http://www.example.com', :method => :put) do %>Hello world!<% end %>") - expected = whole_form("http://www.example.com", :method => "put") do + expected = whole_form("http://www.example.com", method: "put") do "Hello world!" end @@ -165,7 +165,7 @@ class FormTagHelperTest < ActionView::TestCase def test_hidden_field_tag_id_sanitized input_elem = root_elem(hidden_field_tag("item[][title]")) - assert_match VALID_HTML_ID, input_elem['id'] + assert_match VALID_HTML_ID, input_elem["id"] end def test_file_field_tag @@ -173,7 +173,7 @@ class FormTagHelperTest < ActionView::TestCase end def test_file_field_tag_with_options - assert_dom_equal "<input name=\"picsplz\" type=\"file\" id=\"picsplz\" class=\"pix\"/>", file_field_tag("picsplz", :class => "pix") + assert_dom_equal "<input name=\"picsplz\" type=\"file\" id=\"picsplz\" class=\"pix\"/>", file_field_tag("picsplz", class: "pix") end def test_password_field_tag @@ -183,7 +183,7 @@ class FormTagHelperTest < ActionView::TestCase end def test_multiple_field_tags_with_same_options - options = {class: 'important'} + options = { class: "important" } assert_dom_equal %(<input name="title" type="file" id="title" class="important"/>), file_field_tag("title", options) assert_dom_equal %(<input type="password" name="title" id="title" value="Hello!" class="important" />), password_field_tag("title", "Hello!", options) assert_dom_equal %(<input type="text" name="title" id="title" value="Hello!" class="important" />), text_field_tag("title", "Hello!", options) @@ -210,7 +210,7 @@ class FormTagHelperTest < ActionView::TestCase expected = %(<input id="person_gender_m" name="person[gender]" type="radio" value="m" />) assert_dom_equal expected, actual - actual = radio_button_tag('ctrlname', 'apache2.2') + actual = radio_button_tag("ctrlname", "apache2.2") expected = %(<input id="ctrlname_apache2.2" name="ctrlname" type="radio" value="apache2.2" />) assert_dom_equal expected, actual end @@ -235,7 +235,7 @@ class FormTagHelperTest < ActionView::TestCase def test_select_tag_id_sanitized input_elem = root_elem(select_tag("project[1]people", "<option>david</option>")) - assert_match VALID_HTML_ID, input_elem['id'] + assert_match VALID_HTML_ID, input_elem["id"] end def test_select_tag_with_include_blank @@ -251,19 +251,19 @@ class FormTagHelperTest < ActionView::TestCase end def test_select_tag_with_include_blank_string - actual = select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), include_blank: 'Choose' + actual = select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), include_blank: "Choose" expected = %(<select id="places" name="places"><option value="">Choose</option><option>Home</option><option>Work</option><option>Pub</option></select>) assert_dom_equal expected, actual end def test_select_tag_with_prompt - actual = select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), :prompt => "string" + actual = select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), prompt: "string" expected = %(<select id="places" name="places"><option value="">string</option><option>Home</option><option>Work</option><option>Pub</option></select>) assert_dom_equal expected, actual end def test_select_tag_escapes_prompt - actual = select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), :prompt => "<script>alert(1337)</script>" + actual = select_tag "places", raw("<option>Home</option><option>Work</option><option>Pub</option>"), prompt: "<script>alert(1337)</script>" expected = %(<select id="places" name="places"><option value=""><script>alert(1337)</script></option><option>Home</option><option>Work</option><option>Pub</option></select>) assert_dom_equal expected, actual end @@ -275,13 +275,13 @@ class FormTagHelperTest < ActionView::TestCase end def test_select_tag_with_nil_option_tags_and_include_blank - actual = select_tag "places", nil, :include_blank => true + actual = select_tag "places", nil, include_blank: true expected = %(<select id="places" name="places"><option value="" label=" "></option></select>) assert_dom_equal expected, actual end def test_select_tag_with_nil_option_tags_and_prompt - actual = select_tag "places", nil, :prompt => "string" + actual = select_tag "places", nil, prompt: "string" expected = %(<select id="places" name="places"><option value="">string</option></select>) assert_dom_equal expected, actual end @@ -293,36 +293,36 @@ class FormTagHelperTest < ActionView::TestCase end def test_text_area_tag_size_symbol - actual = text_area_tag "body", "hello world", :size => "20x40" + actual = text_area_tag "body", "hello world", size: "20x40" expected = %(<textarea cols="20" id="body" name="body" rows="40">\nhello world</textarea>) assert_dom_equal expected, actual end def test_text_area_tag_should_disregard_size_if_its_given_as_an_integer - actual = text_area_tag "body", "hello world", :size => 20 + actual = text_area_tag "body", "hello world", size: 20 expected = %(<textarea id="body" name="body">\nhello world</textarea>) assert_dom_equal expected, actual end def test_text_area_tag_id_sanitized input_elem = root_elem(text_area_tag("item[][description]")) - assert_match VALID_HTML_ID, input_elem['id'] + assert_match VALID_HTML_ID, input_elem["id"] end def test_text_area_tag_escape_content - actual = text_area_tag "body", "<b>hello world</b>", :size => "20x40" + actual = text_area_tag "body", "<b>hello world</b>", size: "20x40" expected = %(<textarea cols="20" id="body" name="body" rows="40">\n<b>hello world</b></textarea>) assert_dom_equal expected, actual end def test_text_area_tag_unescaped_content - actual = text_area_tag "body", "<b>hello world</b>", :size => "20x40", :escape => false + actual = text_area_tag "body", "<b>hello world</b>", size: "20x40", escape: false expected = %(<textarea cols="20" id="body" name="body" rows="40">\n<b>hello world</b></textarea>) assert_dom_equal expected, actual end def test_text_area_tag_unescaped_nil_content - actual = text_area_tag "body", nil, :escape => false + actual = text_area_tag "body", nil, escape: false expected = %(<textarea id="body" name="body">\n</textarea>) assert_dom_equal expected, actual end @@ -340,7 +340,7 @@ class FormTagHelperTest < ActionView::TestCase end def test_text_field_tag_size_symbol - actual = text_field_tag "title", "Hello!", :size => 75 + actual = text_field_tag "title", "Hello!", size: 75 expected = %(<input id="title" name="title" size="75" type="text" value="Hello!" />) assert_dom_equal expected, actual end @@ -352,7 +352,7 @@ class FormTagHelperTest < ActionView::TestCase end def test_text_field_tag_maxlength_symbol - actual = text_field_tag "title", "Hello!", :maxlength => 75 + actual = text_field_tag "title", "Hello!", maxlength: 75 expected = %(<input id="title" name="title" maxlength="75" type="text" value="Hello!" />) assert_dom_equal expected, actual end @@ -370,20 +370,20 @@ class FormTagHelperTest < ActionView::TestCase end def test_text_field_tag_with_placeholder_option - actual = text_field_tag "title", "Hello!", placeholder: 'Enter search term...' + actual = text_field_tag "title", "Hello!", placeholder: "Enter search term..." expected = %(<input id="title" name="title" placeholder="Enter search term..." type="text" value="Hello!" />) assert_dom_equal expected, actual end def test_text_field_tag_with_multiple_options - actual = text_field_tag "title", "Hello!", :size => 70, :maxlength => 80 + actual = text_field_tag "title", "Hello!", size: 70, maxlength: 80 expected = %(<input id="title" name="title" size="70" maxlength="80" type="text" value="Hello!" />) assert_dom_equal expected, actual end def test_text_field_tag_id_sanitized input_elem = root_elem(text_field_tag("item[][title]")) - assert_match VALID_HTML_ID, input_elem['id'] + assert_match VALID_HTML_ID, input_elem["id"] end def test_label_tag_without_text @@ -412,11 +412,11 @@ class FormTagHelperTest < ActionView::TestCase def test_label_tag_id_sanitized label_elem = root_elem(label_tag("item[title]")) - assert_match VALID_HTML_ID, label_elem['for'] + assert_match VALID_HTML_ID, label_elem["for"] end def test_label_tag_with_block - assert_dom_equal('<label>Blocked</label>', label_tag { "Blocked" }) + assert_dom_equal("<label>Blocked</label>", label_tag { "Blocked" }) end def test_label_tag_with_block_and_argument @@ -425,21 +425,21 @@ class FormTagHelperTest < ActionView::TestCase end def test_label_tag_with_block_and_argument_and_options - output = label_tag("clock", :id => "label_clock") { "Grandfather" } + output = label_tag("clock", id: "label_clock") { "Grandfather" } assert_dom_equal('<label for="clock" id="label_clock">Grandfather</label>', output) end def test_boolean_options - assert_dom_equal %(<input checked="checked" disabled="disabled" id="admin" name="admin" readonly="readonly" type="checkbox" value="1" />), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes") - assert_dom_equal %(<input checked="checked" id="admin" name="admin" type="checkbox" value="1" />), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil) - assert_dom_equal %(<input type="checkbox" />), tag(:input, :type => "checkbox", :checked => false) - assert_dom_equal %(<select id="people" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people", raw("<option>david</option>"), :multiple => true) - assert_dom_equal %(<select id="people_" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people[]", raw("<option>david</option>"), :multiple => true) - assert_dom_equal %(<select id="people" name="people"><option>david</option></select>), select_tag("people", raw("<option>david</option>"), :multiple => nil) + assert_dom_equal %(<input checked="checked" disabled="disabled" id="admin" name="admin" readonly="readonly" type="checkbox" value="1" />), check_box_tag("admin", 1, true, "disabled" => true, :readonly => "yes") + assert_dom_equal %(<input checked="checked" id="admin" name="admin" type="checkbox" value="1" />), check_box_tag("admin", 1, true, disabled: false, readonly: nil) + assert_dom_equal %(<input type="checkbox" />), tag(:input, type: "checkbox", checked: false) + assert_dom_equal %(<select id="people" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people", raw("<option>david</option>"), multiple: true) + assert_dom_equal %(<select id="people_" multiple="multiple" name="people[]"><option>david</option></select>), select_tag("people[]", raw("<option>david</option>"), multiple: true) + assert_dom_equal %(<select id="people" name="people"><option>david</option></select>), select_tag("people", raw("<option>david</option>"), multiple: nil) end def test_stringify_symbol_keys - actual = text_field_tag "title", "Hello!", :id => "admin" + actual = text_field_tag "title", "Hello!", id: "admin" expected = %(<input id="admin" name="title" type="text" value="Hello!" />) assert_dom_equal expected, actual end @@ -447,7 +447,7 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag assert_dom_equal( %(<input name='commit' data-disable-with="Saving..." onclick="alert('hello!')" type="submit" value="Save" />), - submit_tag("Save", :onclick => "alert('hello!')", :data => { :disable_with => "Saving..." }) + submit_tag("Save", onclick: "alert('hello!')", data: { disable_with: "Saving..." }) ) end @@ -471,42 +471,42 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag_having_data_disable_with_string assert_dom_equal( %(<input data-disable-with="Processing..." data-confirm="Are you sure?" name='commit' type="submit" value="Save" />), - submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" }) + submit_tag("Save", "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?") ) end def test_submit_tag_having_data_disable_with_boolean assert_dom_equal( %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />), - submit_tag("Save", { "data-disable-with" => false, "data-confirm" => "Are you sure?" }) + submit_tag("Save", "data-disable-with" => false, "data-confirm" => "Are you sure?") ) end def test_submit_tag_having_data_hash_disable_with_boolean assert_dom_equal( %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />), - submit_tag("Save", { :data => { :confirm => "Are you sure?", :disable_with => false } }) + submit_tag("Save", data: { confirm: "Are you sure?", disable_with: false }) ) end def test_submit_tag_with_no_onclick_options assert_dom_equal( %(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />), - submit_tag("Save", :data => { :disable_with => "Saving..." }) + submit_tag("Save", data: { disable_with: "Saving..." }) ) end def test_submit_tag_with_confirmation assert_dom_equal( %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" data-disable-with="Save" />), - submit_tag("Save", :data => { :confirm => "Are you sure?" }) + submit_tag("Save", data: { confirm: "Are you sure?" }) ) end def test_submit_tag_doesnt_have_data_disable_with_twice assert_equal( %(<input type="submit" name="commit" value="Save" data-confirm="Are you sure?" data-disable-with="Processing..." />), - submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" }) + submit_tag("Save", "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?") ) end @@ -517,7 +517,6 @@ class FormTagHelperTest < ActionView::TestCase ) end - def test_button_tag assert_dom_equal( %(<button name="button" type="submit">Button</button>), @@ -528,56 +527,56 @@ class FormTagHelperTest < ActionView::TestCase def test_button_tag_with_submit_type assert_dom_equal( %(<button name="button" type="submit">Save</button>), - button_tag("Save", :type => "submit") + button_tag("Save", type: "submit") ) end def test_button_tag_with_button_type assert_dom_equal( %(<button name="button" type="button">Button</button>), - button_tag("Button", :type => "button") + button_tag("Button", type: "button") ) end def test_button_tag_with_reset_type assert_dom_equal( %(<button name="button" type="reset">Reset</button>), - button_tag("Reset", :type => "reset") + button_tag("Reset", type: "reset") ) end def test_button_tag_with_disabled_option assert_dom_equal( %(<button name="button" type="reset" disabled="disabled">Reset</button>), - button_tag("Reset", :type => "reset", :disabled => true) + button_tag("Reset", type: "reset", disabled: true) ) end def test_button_tag_escape_content assert_dom_equal( %(<button name="button" type="reset" disabled="disabled"><b>Reset</b></button>), - button_tag("<b>Reset</b>", :type => "reset", :disabled => true) + button_tag("<b>Reset</b>", type: "reset", disabled: true) ) end def test_button_tag_with_block - assert_dom_equal('<button name="button" type="submit">Content</button>', button_tag { 'Content' }) + assert_dom_equal('<button name="button" type="submit">Content</button>', button_tag { "Content" }) end def test_button_tag_with_block_and_options - output = button_tag(:name => 'temptation', :type => 'button') { content_tag(:strong, 'Do not press me') } + output = button_tag(name: "temptation", type: "button") { content_tag(:strong, "Do not press me") } assert_dom_equal('<button name="temptation" type="button"><strong>Do not press me</strong></button>', output) end def test_button_tag_defaults_with_block_and_options - output = button_tag(:name => 'temptation', :value => 'within') { content_tag(:strong, 'Do not press me') } + output = button_tag(name: "temptation", value: "within") { content_tag(:strong, "Do not press me") } assert_dom_equal('<button name="temptation" value="within" type="submit" ><strong>Do not press me</strong></button>', output) end def test_button_tag_with_confirmation assert_dom_equal( %(<button name="button" type="submit" data-confirm="Are you sure?">Save</button>), - button_tag("Save", :type => "submit", :data => { :confirm => "Are you sure?" }) + button_tag("Save", type: "submit", data: { confirm: "Are you sure?" }) ) end @@ -591,7 +590,7 @@ class FormTagHelperTest < ActionView::TestCase def test_image_submit_tag_with_confirmation assert_dom_equal( %(<input alt="Save" type="image" src="/images/save.gif" data-confirm="Are you sure?" />), - image_submit_tag("save.gif", :data => { :confirm => "Are you sure?" }) + image_submit_tag("save.gif", data: { confirm: "Are you sure?" }) ) end @@ -621,10 +620,8 @@ class FormTagHelperTest < ActionView::TestCase end def test_datetime_field_tag - expected = %{<input id="appointment" name="appointment" type="datetime" />} - assert_deprecated do - assert_dom_equal(expected, datetime_field_tag("appointment")) - end + expected = %{<input id="appointment" name="appointment" type="datetime-local" />} + assert_dom_equal(expected, datetime_field_tag("appointment")) end def test_datetime_local_field_tag @@ -654,12 +651,12 @@ class FormTagHelperTest < ActionView::TestCase def test_number_field_tag expected = %{<input name="quantity" max="9" id="quantity" type="number" min="1" />} - assert_dom_equal(expected, number_field_tag("quantity", nil, :in => 1...10)) + assert_dom_equal(expected, number_field_tag("quantity", nil, in: 1...10)) end def test_range_input_tag expected = %{<input name="volume" step="0.1" max="11" id="volume" type="range" min="0" />} - assert_dom_equal(expected, range_field_tag("volume", nil, :in => 0..11, :step => 0.1)) + assert_dom_equal(expected, range_field_tag("volume", nil, in: 0..11, step: 0.1)) end def test_field_set_tag_in_erb @@ -695,33 +692,33 @@ class FormTagHelperTest < ActionView::TestCase end def test_text_area_tag_options_symbolize_keys_side_effects - options = { :option => "random_option" } + options = { option: "random_option" } text_area_tag "body", "hello world", options - assert_equal options, { :option => "random_option" } + assert_equal options, option: "random_option" end def test_submit_tag_options_symbolize_keys_side_effects - options = { :option => "random_option" } + options = { option: "random_option" } submit_tag "submit value", options - assert_equal options, { :option => "random_option" } + assert_equal options, option: "random_option" end def test_button_tag_options_symbolize_keys_side_effects - options = { :option => "random_option" } + options = { option: "random_option" } button_tag "button value", options - assert_equal options, { :option => "random_option" } + assert_equal options, option: "random_option" end def test_image_submit_tag_options_symbolize_keys_side_effects - options = { :option => "random_option" } + options = { option: "random_option" } image_submit_tag "submit source", options - assert_equal options, { :option => "random_option" } + assert_equal options, option: "random_option" end def test_image_label_tag_options_symbolize_keys_side_effects - options = { :option => "random_option" } + options = { option: "random_option" } label_tag "submit source", "title", options - assert_equal options, { :option => "random_option" } + assert_equal options, option: "random_option" end def protect_against_forgery? @@ -730,7 +727,7 @@ class FormTagHelperTest < ActionView::TestCase private - def root_elem(rendered_content) - Nokogiri::HTML::DocumentFragment.parse(rendered_content).children.first # extract from nodeset - end + def root_elem(rendered_content) + Nokogiri::HTML::DocumentFragment.parse(rendered_content).children.first # extract from nodeset + end end diff --git a/actionview/test/template/html_test.rb b/actionview/test/template/html_test.rb index 549c12c88c..60f4b0aee6 100644 --- a/actionview/test/template/html_test.rb +++ b/actionview/test/template/html_test.rb @@ -1,17 +1,17 @@ -require 'abstract_unit' +require "abstract_unit" class HTMLTest < ActiveSupport::TestCase - test 'formats returns symbol for recognized MIME type' do - assert_equal [:html], ActionView::Template::HTML.new('', :html).formats + test "formats returns symbol for recognized MIME type" do + assert_equal [:html], ActionView::Template::HTML.new("", :html).formats end - test 'formats returns string for recognized MIME type when MIME does not have symbol' do + test "formats returns string for recognized MIME type when MIME does not have symbol" do foo = Mime::Type.lookup("foo") assert_nil foo.to_sym - assert_equal ['foo'], ActionView::Template::HTML.new('', foo).formats + assert_equal ["foo"], ActionView::Template::HTML.new("", foo).formats end - test 'formats returns string for unknown MIME type' do - assert_equal ['foo'], ActionView::Template::HTML.new('', 'foo').formats + test "formats returns string for unknown MIME type" do + assert_equal ["foo"], ActionView::Template::HTML.new("", "foo").formats end end diff --git a/actionview/test/template/javascript_helper_test.rb b/actionview/test/template/javascript_helper_test.rb index 9f1535ef53..0468c845d2 100644 --- a/actionview/test/template/javascript_helper_test.rb +++ b/actionview/test/template/javascript_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class JavaScriptHelperTest < ActionView::TestCase tests ActionView::Helpers::JavaScriptHelper @@ -16,7 +16,7 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_escape_javascript - assert_equal '', escape_javascript(nil) + assert_equal "", escape_javascript(nil) assert_equal %(This \\"thing\\" is really\\n netos\\'), escape_javascript(%(This "thing" is really\n netos')) assert_equal %(backslash\\\\test), escape_javascript( %(backslash\\test) ) assert_equal %(dont <\\/close> tags), escape_javascript(%(dont </close> tags)) @@ -36,24 +36,24 @@ class JavaScriptHelperTest < ActionView::TestCase end def test_javascript_tag - self.output_buffer = 'foo' + self.output_buffer = "foo" assert_dom_equal "<script>\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", javascript_tag("alert('hello')") - assert_equal 'foo', output_buffer, 'javascript_tag without a block should not concat to output_buffer' + assert_equal "foo", output_buffer, "javascript_tag without a block should not concat to output_buffer" end # Setting the :extname option will control what extension (if any) is appended to the url for assets def test_javascript_include_tag - assert_dom_equal "<script src='/foo.js'></script>", javascript_include_tag('/foo') - assert_dom_equal "<script src='/foo'></script>", javascript_include_tag('/foo', extname: false ) - assert_dom_equal "<script src='/foo.bar'></script>", javascript_include_tag('/foo', extname: '.bar' ) + assert_dom_equal "<script src='/foo.js'></script>", javascript_include_tag("/foo") + assert_dom_equal "<script src='/foo'></script>", javascript_include_tag("/foo", extname: false ) + assert_dom_equal "<script src='/foo.bar'></script>", javascript_include_tag("/foo", extname: ".bar" ) end def test_javascript_tag_with_options assert_dom_equal "<script id=\"the_js_tag\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", - javascript_tag("alert('hello')", :id => "the_js_tag") + javascript_tag("alert('hello')", id: "the_js_tag") end def test_javascript_cdata_section diff --git a/actionview/test/template/log_subscriber_test.rb b/actionview/test/template/log_subscriber_test.rb index 7683444bf0..7f358add7e 100644 --- a/actionview/test/template/log_subscriber_test.rb +++ b/actionview/test/template/log_subscriber_test.rb @@ -30,9 +30,21 @@ class AVLogSubscriberTest < ActiveSupport::TestCase ActionView::Base.logger = logger end + def set_cache_controller + controller = ActionController::Base.new + controller.perform_caching = true + controller.cache_store = ActiveSupport::Cache::MemoryStore.new + @view.controller = controller + end + + def set_view_cache_dependencies + def @view.view_cache_dependencies; []; end + def @view.fragment_cache_key(*); "ahoy `controller` dependency"; end + end + def test_render_file_template Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render(:file => "test/hello_world") + @view.render(file: "test/hello_world") wait assert_equal 2, @logger.logged(:info).size @@ -43,7 +55,7 @@ class AVLogSubscriberTest < ActiveSupport::TestCase def test_render_text_template Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render(:text => "TEXT") + @view.render(plain: "TEXT") wait assert_equal 2, @logger.logged(:info).size @@ -54,7 +66,7 @@ class AVLogSubscriberTest < ActiveSupport::TestCase def test_render_inline_template Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render(:inline => "<%= 'TEXT' %>") + @view.render(inline: "<%= 'TEXT' %>") wait assert_equal 2, @logger.logged(:info).size @@ -63,29 +75,66 @@ class AVLogSubscriberTest < ActiveSupport::TestCase end end - def test_render_partial_template + def test_render_partial_with_implicit_path Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render(:partial => "test/customer") + @view.render(Customer.new("david"), greeting: "hi") wait assert_equal 1, @logger.logged(:info).size - assert_match(/Rendered test\/_customer.erb/, @logger.logged(:info).last) + assert_match(/Rendered customers\/_customer\.html\.erb/, @logger.logged(:info).last) end end - def test_render_partial_with_implicit_path + def test_render_partial_with_cache_missed Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render(Customer.new("david"), :greeting => "hi") + set_view_cache_dependencies + set_cache_controller + + @view.render(partial: "test/cached_customer", locals: { cached_customer: Customer.new("david") }) wait assert_equal 1, @logger.logged(:info).size - assert_match(/Rendered customers\/_customer\.html\.erb/, @logger.logged(:info).last) + assert_match(/Rendered test\/_cached_customer\.erb (.*) \[cache miss\]/, @logger.logged(:info).last) + end + end + + def test_render_partial_with_cache_hitted + Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do + set_view_cache_dependencies + set_cache_controller + + @view.render(partial: "test/cached_customer", locals: { cached_customer: Customer.new("david") }) + # Second render should hit cache. + @view.render(partial: "test/cached_customer", locals: { cached_customer: Customer.new("david") }) + wait + + assert_equal 2, @logger.logged(:info).size + assert_match(/Rendered test\/_cached_customer\.erb (.*) \[cache hit\]/, @logger.logged(:info).last) + end + end + + def test_render_partial_with_cache_hitted_and_missed + Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do + set_view_cache_dependencies + set_cache_controller + + @view.render(partial: "test/cached_customer", locals: { cached_customer: Customer.new("david") }) + wait + assert_match(/Rendered test\/_cached_customer\.erb (.*) \[cache miss\]/, @logger.logged(:info).last) + + @view.render(partial: "test/cached_customer", locals: { cached_customer: Customer.new("david") }) + wait + assert_match(/Rendered test\/_cached_customer\.erb (.*) \[cache hit\]/, @logger.logged(:info).last) + + @view.render(partial: "test/cached_customer", locals: { cached_customer: Customer.new("Stan") }) + wait + assert_match(/Rendered test\/_cached_customer\.erb (.*) \[cache miss\]/, @logger.logged(:info).last) end end def test_render_collection_template Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ]) + @view.render(partial: "test/customer", collection: [ Customer.new("david"), Customer.new("mary") ]) wait assert_equal 1, @logger.logged(:info).size @@ -95,7 +144,7 @@ class AVLogSubscriberTest < ActiveSupport::TestCase def test_render_collection_with_implicit_path Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render([ Customer.new("david"), Customer.new("mary") ], :greeting => "hi") + @view.render([ Customer.new("david"), Customer.new("mary") ], greeting: "hi") wait assert_equal 1, @logger.logged(:info).size @@ -105,7 +154,7 @@ class AVLogSubscriberTest < ActiveSupport::TestCase def test_render_collection_template_without_path Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render([ GoodCustomer.new("david"), Customer.new("mary") ], :greeting => "hi") + @view.render([ GoodCustomer.new("david"), Customer.new("mary") ], greeting: "hi") wait assert_equal 1, @logger.logged(:info).size @@ -115,11 +164,10 @@ class AVLogSubscriberTest < ActiveSupport::TestCase def test_render_collection_with_cached_set Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - def @view.view_cache_dependencies; []; end - def @view.fragment_cache_key(*); 'ahoy `controller` dependency'; end + set_view_cache_dependencies - @view.render(partial: 'customers/customer', collection: [ Customer.new('david'), Customer.new('mary') ], cached: true, - locals: { greeting: 'hi' }) + @view.render(partial: "customers/customer", collection: [ Customer.new("david"), Customer.new("mary") ], cached: true, + locals: { greeting: "hi" }) wait assert_equal 1, @logger.logged(:info).size diff --git a/actionview/test/template/lookup_context_test.rb b/actionview/test/template/lookup_context_test.rb index 2e3a3f9bae..b47d92df34 100644 --- a/actionview/test/template/lookup_context_test.rb +++ b/actionview/test/template/lookup_context_test.rb @@ -120,8 +120,8 @@ class LookupContextTest < ActiveSupport::TestCase @lookup_context.with_fallbacks do assert_equal 3, @lookup_context.view_paths.size - assert @lookup_context.view_paths.include?(ActionView::FallbackFileSystemResolver.new("")) - assert @lookup_context.view_paths.include?(ActionView::FallbackFileSystemResolver.new("/")) + assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.new("") + assert_includes @lookup_context.view_paths, ActionView::FallbackFileSystemResolver.new("/") end end @@ -279,10 +279,9 @@ class TestMissingTemplate < ActiveSupport::TestCase test "if a single prefix is passed as a string and the lookup fails, MissingTemplate accepts it" do e = assert_raise ActionView::MissingTemplate do - details = {:handlers=>[], :formats=>[], :variants=>[], :locale=>[]} + details = { handlers: [], formats: [], variants: [], locale: [] } @lookup_context.view_paths.find("foo", "parent", true, details) end assert_match %r{Missing partial parent/_foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message end - end diff --git a/actionview/test/template/number_helper_test.rb b/actionview/test/template/number_helper_test.rb index ace3e950b8..2a2ada2b36 100644 --- a/actionview/test/template/number_helper_test.rb +++ b/actionview/test/template/number_helper_test.rb @@ -20,16 +20,16 @@ class NumberHelperTest < ActionView::TestCase assert_equal "&pound;1,234,567,890.50", number_to_currency("1234567890.50", unit: "£") assert_equal "<b>1,234,567,890.50</b> $", number_to_currency("1234567890.50", format: "<b>%n</b> %u") assert_equal "<b>1,234,567,890.50</b> $", number_to_currency("-1234567890.50", negative_format: "<b>%n</b> %u") - assert_equal "<b>1,234,567,890.50</b> $", number_to_currency("-1234567890.50", 'negative_format' => "<b>%n</b> %u") - assert_equal '₹ 12,30,000.00', number_to_currency(1230000, delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/, unit: '₹', format: "%u %n") + assert_equal "<b>1,234,567,890.50</b> $", number_to_currency("-1234567890.50", "negative_format" => "<b>%n</b> %u") + assert_equal "₹ 12,30,000.00", number_to_currency(1230000, delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/, unit: "₹", format: "%u %n") end def test_number_to_percentage assert_equal nil, number_to_percentage(nil) assert_equal "100.000%", number_to_percentage(100) - assert_equal "100.000 %", number_to_percentage(100, format: '%n %') - assert_equal "<b>100.000</b> %", number_to_percentage(100, format: '<b>%n</b> %') - assert_equal "<b>100.000</b> %", number_to_percentage(100, format: raw('<b>%n</b> %')) + assert_equal "100.000 %", number_to_percentage(100, format: "%n %") + assert_equal "<b>100.000</b> %", number_to_percentage(100, format: "<b>%n</b> %") + assert_equal "<b>100.000</b> %", number_to_percentage(100, format: raw("<b>%n</b> %")) assert_equal "100%", number_to_percentage(100, precision: 0) assert_equal "123.4%", number_to_percentage(123.400, precision: 3, strip_insignificant_zeros: true) assert_equal "1.000,000%", number_to_percentage(1000, delimiter: ".", separator: ",") @@ -71,27 +71,27 @@ class NumberHelperTest < ActionView::TestCase def test_number_to_human_escape_units volume = { unit: "<b>ml</b>", thousand: "<b>lt</b>", million: "<b>m3</b>", trillion: "<b>km3</b>", quadrillion: "<b>Pl</b>" } - assert_equal '123 <b>lt</b>', number_to_human(123456, :units => volume) - assert_equal '12 <b>ml</b>', number_to_human(12, :units => volume) - assert_equal '1.23 <b>m3</b>', number_to_human(1234567, :units => volume) - assert_equal '1.23 <b>km3</b>', number_to_human(1_234_567_000_000, :units => volume) - assert_equal '1.23 <b>Pl</b>', number_to_human(1_234_567_000_000_000, :units => volume) + assert_equal "123 <b>lt</b>", number_to_human(123456, units: volume) + assert_equal "12 <b>ml</b>", number_to_human(12, units: volume) + assert_equal "1.23 <b>m3</b>", number_to_human(1234567, units: volume) + assert_equal "1.23 <b>km3</b>", number_to_human(1_234_567_000_000, units: volume) + assert_equal "1.23 <b>Pl</b>", number_to_human(1_234_567_000_000_000, units: volume) #Including fractionals distance = { mili: "<b>mm</b>", centi: "<b>cm</b>", deci: "<b>dm</b>", unit: "<b>m</b>", ten: "<b>dam</b>", hundred: "<b>hm</b>", thousand: "<b>km</b>", - micro: "<b>um</b>", nano: "<b>nm</b>", pico: "<b>pm</b>", femto: "<b>fm</b>"} - assert_equal '1.23 <b>mm</b>', number_to_human(0.00123, :units => distance) - assert_equal '1.23 <b>cm</b>', number_to_human(0.0123, :units => distance) - assert_equal '1.23 <b>dm</b>', number_to_human(0.123, :units => distance) - assert_equal '1.23 <b>m</b>', number_to_human(1.23, :units => distance) - assert_equal '1.23 <b>dam</b>', number_to_human(12.3, :units => distance) - assert_equal '1.23 <b>hm</b>', number_to_human(123, :units => distance) - assert_equal '1.23 <b>km</b>', number_to_human(1230, :units => distance) - assert_equal '1.23 <b>um</b>', number_to_human(0.00000123, :units => distance) - assert_equal '1.23 <b>nm</b>', number_to_human(0.00000000123, :units => distance) - assert_equal '1.23 <b>pm</b>', number_to_human(0.00000000000123, :units => distance) - assert_equal '1.23 <b>fm</b>', number_to_human(0.00000000000000123, :units => distance) + micro: "<b>um</b>", nano: "<b>nm</b>", pico: "<b>pm</b>", femto: "<b>fm</b>" } + assert_equal "1.23 <b>mm</b>", number_to_human(0.00123, units: distance) + assert_equal "1.23 <b>cm</b>", number_to_human(0.0123, units: distance) + assert_equal "1.23 <b>dm</b>", number_to_human(0.123, units: distance) + assert_equal "1.23 <b>m</b>", number_to_human(1.23, units: distance) + assert_equal "1.23 <b>dam</b>", number_to_human(12.3, units: distance) + assert_equal "1.23 <b>hm</b>", number_to_human(123, units: distance) + assert_equal "1.23 <b>km</b>", number_to_human(1230, units: distance) + assert_equal "1.23 <b>um</b>", number_to_human(0.00000123, units: distance) + assert_equal "1.23 <b>nm</b>", number_to_human(0.00000000123, units: distance) + assert_equal "1.23 <b>pm</b>", number_to_human(0.00000000000123, units: distance) + assert_equal "1.23 <b>fm</b>", number_to_human(0.00000000000000123, units: distance) end def test_number_helpers_escape_delimiter_and_separator @@ -116,9 +116,9 @@ class NumberHelperTest < ActionView::TestCase end def test_number_to_human_with_custom_translation_scope - I18n.backend.store_translations 'ts', - :custom_units_for_number_to_human => {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} - assert_equal "1.01 cm", number_to_human(0.0101, :locale => 'ts', :units => :custom_units_for_number_to_human) + I18n.backend.store_translations "ts", + custom_units_for_number_to_human: { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } + assert_equal "1.01 cm", number_to_human(0.0101, locale: "ts", units: :custom_units_for_number_to_human) ensure I18n.reload! end diff --git a/actionview/test/template/output_safety_helper_test.rb b/actionview/test/template/output_safety_helper_test.rb index b940c9dd36..98b1938276 100644 --- a/actionview/test/template/output_safety_helper_test.rb +++ b/actionview/test/template/output_safety_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class OutputSafetyHelperTest < ActionView::TestCase tests ActionView::Helpers::OutputSafetyHelper @@ -26,11 +26,11 @@ class OutputSafetyHelperTest < ActionView::TestCase end test "safe_join should work recursively similarly to Array.join" do - joined = safe_join(['a',['b','c']], ':') - assert_equal 'a:b:c', joined + joined = safe_join(["a",["b","c"]], ":") + assert_equal "a:b:c", joined - joined = safe_join(['"a"',['<b>','<c>']], ' <br/> ') - assert_equal '"a" <br/> <b> <br/> <c>', joined + joined = safe_join(['"a"',["<b>","<c>"]], " <br/> ") + assert_equal ""a" <br/> <b> <br/> <c>", joined end test "to_sentence should escape non-html_safe values" do @@ -50,9 +50,9 @@ class OutputSafetyHelperTest < ActionView::TestCase end test "to_sentence connector words are checked for html safety" do - assert_equal "one & two, and three", to_sentence(['one', 'two', 'three'], words_connector: ' & '.html_safe) - assert_equal "one & two", to_sentence(['one', 'two'], two_words_connector: ' & '.html_safe) - assert_equal "one, two <script>alert(1)</script> three", to_sentence(['one', 'two', 'three'], last_word_connector: ' <script>alert(1)</script> ') + assert_equal "one & two, and three", to_sentence(["one", "two", "three"], words_connector: " & ".html_safe) + assert_equal "one & two", to_sentence(["one", "two"], two_words_connector: " & ".html_safe) + assert_equal "one, two <script>alert(1)</script> three", to_sentence(["one", "two", "three"], last_word_connector: " <script>alert(1)</script> ") end test "to_sentence should not escape html_safe values" do @@ -67,24 +67,24 @@ class OutputSafetyHelperTest < ActionView::TestCase end test "to_sentence handles blank strings" do - actual = to_sentence(['', 'two', 'three']) + actual = to_sentence(["", "two", "three"]) assert actual.html_safe? assert_equal ", two, and three", actual end test "to_sentence handles nil values" do - actual = to_sentence([nil, 'two', 'three']) + actual = to_sentence([nil, "two", "three"]) assert actual.html_safe? assert_equal ", two, and three", actual end test "to_sentence still supports ActiveSupports Array#to_sentence arguments" do - assert_equal "one two, and three", to_sentence(['one', 'two', 'three'], words_connector: ' ') - assert_equal "one & two, and three", to_sentence(['one', 'two', 'three'], words_connector: ' & '.html_safe) - assert_equal "onetwo, and three", to_sentence(['one', 'two', 'three'], words_connector: nil) - assert_equal "one, two, and also three", to_sentence(['one', 'two', 'three'], last_word_connector: ', and also ') - assert_equal "one, twothree", to_sentence(['one', 'two', 'three'], last_word_connector: nil) - assert_equal "one, two three", to_sentence(['one', 'two', 'three'], last_word_connector: ' ') - assert_equal "one, two and three", to_sentence(['one', 'two', 'three'], last_word_connector: ' and ') + assert_equal "one two, and three", to_sentence(["one", "two", "three"], words_connector: " ") + assert_equal "one & two, and three", to_sentence(["one", "two", "three"], words_connector: " & ".html_safe) + assert_equal "onetwo, and three", to_sentence(["one", "two", "three"], words_connector: nil) + assert_equal "one, two, and also three", to_sentence(["one", "two", "three"], last_word_connector: ", and also ") + assert_equal "one, twothree", to_sentence(["one", "two", "three"], last_word_connector: nil) + assert_equal "one, two three", to_sentence(["one", "two", "three"], last_word_connector: " ") + assert_equal "one, two and three", to_sentence(["one", "two", "three"], last_word_connector: " and ") end end diff --git a/actionview/test/template/partial_iteration_test.rb b/actionview/test/template/partial_iteration_test.rb index 695f9f1bef..3ebf3b550a 100644 --- a/actionview/test/template/partial_iteration_test.rb +++ b/actionview/test/template/partial_iteration_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'action_view/renderer/partial_renderer' +require "abstract_unit" +require "action_view/renderer/partial_renderer" class PartialIterationTest < ActiveSupport::TestCase def test_has_size_and_index diff --git a/actionview/test/template/record_identifier_test.rb b/actionview/test/template/record_identifier_test.rb index 04898c0b0e..ce446715fd 100644 --- a/actionview/test/template/record_identifier_test.rb +++ b/actionview/test/template/record_identifier_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'controller/fake_models' +require "abstract_unit" +require "controller/fake_models" class RecordIdentifierTest < ActiveSupport::TestCase include ActionView::RecordIdentifier @@ -7,8 +7,8 @@ class RecordIdentifierTest < ActiveSupport::TestCase def setup @klass = Comment @record = @klass.new - @singular = 'comment' - @plural = 'comments' + @singular = "comment" + @plural = "comments" end def test_dom_id_with_new_record @@ -73,7 +73,7 @@ class RecordIdentifierWithoutActiveModelTest < ActiveSupport::TestCase end def test_dom_class - assert_equal 'airplane', dom_class(@record) + assert_equal "airplane", dom_class(@record) end def test_dom_class_with_prefix @@ -86,6 +86,6 @@ class RecordIdentifierWithoutActiveModelTest < ActiveSupport::TestCase end def test_dom_class_as_singleton_method - assert_equal 'airplane', ActionView::RecordIdentifier.dom_class(@record) + assert_equal "airplane", ActionView::RecordIdentifier.dom_class(@record) end end diff --git a/actionview/test/template/record_tag_helper_test.rb b/actionview/test/template/record_tag_helper_test.rb index bfc5d04bed..3685230558 100644 --- a/actionview/test/template/record_tag_helper_test.rb +++ b/actionview/test/template/record_tag_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class RecordTagPost extend ActiveModel::Naming @@ -14,7 +14,6 @@ class RecordTagPost end class RecordTagHelperTest < ActionView::TestCase - tests ActionView::Helpers::RecordTagHelper def setup diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb index ad93236d32..e7e0b147c7 100644 --- a/actionview/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' -require 'controller/fake_models' +require "abstract_unit" +require "controller/fake_models" class TestController < ActionController::Base end module RenderTestCases def setup_view(paths) - @assigns = { :secret => 'in the sauce' } + @assigns = { secret: "in the sauce" } @view = Class.new(ActionView::Base) do def view_cache_dependencies; end @@ -18,8 +18,8 @@ module RenderTestCases @controller_view = TestController.new.view_context # Reload and register danish language for testing - I18n.backend.store_translations 'da', {} - I18n.backend.store_translations 'pt-BR', {} + I18n.backend.store_translations "da", {} + I18n.backend.store_translations "pt-BR", {} # Ensure original are still the same since we are reindexing view paths assert_equal ORIGINAL_LOCALES, I18n.available_locales.map(&:to_s).sort @@ -31,117 +31,124 @@ module RenderTestCases end def test_render_file - assert_equal "Hello world!", @view.render(:file => "test/hello_world") + assert_equal "Hello world!", @view.render(file: "test/hello_world") end # Test if :formats, :locale etc. options are passed correctly to the resolvers. def test_render_file_with_format - assert_match "<h1>No Comment</h1>", @view.render(:file => "comments/empty", :formats => [:html]) - assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => [:xml]) - assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => :xml) + assert_match "<h1>No Comment</h1>", @view.render(file: "comments/empty", formats: [:html]) + assert_match "<error>No Comment</error>", @view.render(file: "comments/empty", formats: [:xml]) + assert_match "<error>No Comment</error>", @view.render(file: "comments/empty", formats: :xml) end def test_render_template_with_format - assert_match "<h1>No Comment</h1>", @view.render(:template => "comments/empty", :formats => [:html]) - assert_match "<error>No Comment</error>", @view.render(:template => "comments/empty", :formats => [:xml]) + assert_match "<h1>No Comment</h1>", @view.render(template: "comments/empty", formats: [:html]) + assert_match "<error>No Comment</error>", @view.render(template: "comments/empty", formats: [:xml]) end def test_rendered_format_without_format - @view.render(:inline => "test") + @view.render(inline: "test") assert_equal :html, @view.lookup_context.rendered_format end def test_render_partial_implicitly_use_format_of_the_rendered_template @view.lookup_context.formats = [:json] - assert_equal "Hello world", @view.render(:template => "test/one", :formats => [:html]) + assert_equal "Hello world", @view.render(template: "test/one", formats: [:html]) end def test_render_partial_implicitly_use_format_of_the_rendered_partial @view.lookup_context.formats = [:html] - assert_equal "Third level", @view.render(:template => "test/html_template") + assert_equal "Third level", @view.render(template: "test/html_template") end def test_render_partial_use_last_prepended_format_for_partials_with_the_same_names @view.lookup_context.formats = [:html] - assert_equal "\nHTML Template, but JSON partial", @view.render(:template => "test/change_priority") + assert_equal "\nHTML Template, but JSON partial", @view.render(template: "test/change_priority") end def test_render_template_with_a_missing_partial_of_another_format @view.lookup_context.formats = [:html] e = assert_raise ActionView::Template::Error do - @view.render(:template => "with_format", :formats => [:json]) + @view.render(template: "with_format", formats: [:json]) end assert_includes(e.message, "Missing partial /_missing with {:locale=>[:en], :formats=>[:json], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby]}.") end def test_render_file_with_locale - assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => [:de]) - assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => :de) + assert_equal "<h1>Kein Kommentar</h1>", @view.render(file: "comments/empty", locale: [:de]) + assert_equal "<h1>Kein Kommentar</h1>", @view.render(file: "comments/empty", locale: :de) end def test_render_template_with_locale - assert_equal "<h1>Kein Kommentar</h1>", @view.render(:template => "comments/empty", :locale => [:de]) + assert_equal "<h1>Kein Kommentar</h1>", @view.render(template: "comments/empty", locale: [:de]) end def test_render_file_with_handlers - assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => [:builder]) - assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => :builder) + assert_equal "<h1>No Comment</h1>\n", @view.render(file: "comments/empty", handlers: [:builder]) + assert_equal "<h1>No Comment</h1>\n", @view.render(file: "comments/empty", handlers: :builder) end def test_render_template_with_handlers - assert_equal "<h1>No Comment</h1>\n", @view.render(:template => "comments/empty", :handlers => [:builder]) + assert_equal "<h1>No Comment</h1>\n", @view.render(template: "comments/empty", handlers: [:builder]) end def test_render_raw_template_with_handlers - assert_equal "<%= hello_world %>\n", @view.render(:template => "plain_text") + assert_equal "<%= hello_world %>\n", @view.render(template: "plain_text") end def test_render_raw_template_with_quotes - assert_equal %q;Here are some characters: !@#$%^&*()-="'}{`; + "\n", @view.render(:template => "plain_text_with_characters") + assert_equal %q;Here are some characters: !@#$%^&*()-="'}{`; + "\n", @view.render(template: "plain_text_with_characters") + end + + def test_render_raw_is_html_safe_and_does_not_escape_output + buffer = ActiveSupport::SafeBuffer.new + buffer << @view.render(file: "plain_text") + assert_equal true, buffer.html_safe? + assert_equal buffer, "<%= hello_world %>\n" end def test_render_ruby_template_with_handlers - assert_equal "Hello from Ruby code", @view.render(:template => "ruby_template") + assert_equal "Hello from Ruby code", @view.render(template: "ruby_template") end def test_render_ruby_template_inline - assert_equal '4', @view.render(:inline => "(2**2).to_s", :type => :ruby) + assert_equal "4", @view.render(inline: "(2**2).to_s", type: :ruby) end def test_render_file_with_localization_on_context_level old_locale, @view.locale = @view.locale, :da - assert_equal "Hey verden", @view.render(:file => "test/hello_world") + assert_equal "Hey verden", @view.render(file: "test/hello_world") ensure @view.locale = old_locale end def test_render_file_with_dashed_locale old_locale, @view.locale = @view.locale, :"pt-BR" - assert_equal "Ola mundo", @view.render(:file => "test/hello_world") + assert_equal "Ola mundo", @view.render(file: "test/hello_world") ensure @view.locale = old_locale end def test_render_file_at_top_level - assert_equal 'Elastica', @view.render(:file => '/shared') + assert_equal "Elastica", @view.render(file: "/shared") end def test_render_file_with_full_path - template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world') - assert_equal "Hello world!", @view.render(:file => template_path) + template_path = File.join(File.dirname(__FILE__), "../fixtures/test/hello_world") + assert_equal "Hello world!", @view.render(file: template_path) end def test_render_file_with_instance_variables - assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_ivar") + assert_equal "The secret is in the sauce\n", @view.render(file: "test/render_file_with_ivar") end def test_render_file_with_locals - locals = { :secret => 'in the sauce' } - assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_locals", :locals => locals) + locals = { secret: "in the sauce" } + assert_equal "The secret is in the sauce\n", @view.render(file: "test/render_file_with_locals", locals: locals) end def test_render_file_not_using_full_path_with_dot_in_path - assert_equal "The secret is in the sauce\n", @view.render(:file => "test/dot.directory/render_file_with_ivar") + assert_equal "The secret is in the sauce\n", @view.render(file: "test/dot.directory/render_file_with_ivar") end def test_render_partial_from_default @@ -149,84 +156,84 @@ module RenderTestCases end def test_render_outside_path - assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')) + assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")) assert_raises ActionView::MissingTemplate do - @view.render(:template => "../\\../test/abstract_unit.rb") + @view.render(template: "../\\../test/abstract_unit.rb") end end def test_render_partial - assert_equal "only partial", @view.render(:partial => "test/partial_only") + assert_equal "only partial", @view.render(partial: "test/partial_only") end def test_render_partial_with_format - assert_equal 'partial html', @view.render(:partial => 'test/partial') + assert_equal "partial html", @view.render(partial: "test/partial") end def test_render_partial_with_selected_format - assert_equal 'partial html', @view.render(:partial => 'test/partial', :formats => :html) - assert_equal 'partial js', @view.render(:partial => 'test/partial', :formats => [:js]) + assert_equal "partial html", @view.render(partial: "test/partial", formats: :html) + assert_equal "partial js", @view.render(partial: "test/partial", formats: [:js]) end def test_render_partial_at_top_level # file fixtures/_top_level_partial_only (not fixtures/test) - assert_equal 'top level partial', @view.render(:partial => '/top_level_partial_only') + assert_equal "top level partial", @view.render(partial: "/top_level_partial_only") end def test_render_partial_with_format_at_top_level # file fixtures/_top_level_partial.html (not fixtures/test, with format extension) - assert_equal 'top level partial html', @view.render(:partial => '/top_level_partial') + assert_equal "top level partial html", @view.render(partial: "/top_level_partial") end def test_render_partial_with_locals - assert_equal "5", @view.render(:partial => "test/counter", :locals => { :counter_counter => 5 }) + assert_equal "5", @view.render(partial: "test/counter", locals: { counter_counter: 5 }) end def test_render_partial_with_locals_from_default - assert_equal "only partial", @view.render("test/partial_only", :counter_counter => 5) + assert_equal "only partial", @view.render("test/partial_only", counter_counter: 5) end def test_render_partial_with_number - assert_nothing_raised { @view.render(:partial => "test/200") } + assert_nothing_raised { @view.render(partial: "test/200") } end def test_render_partial_with_missing_filename - assert_raises(ActionView::MissingTemplate) { @view.render(:partial => "test/") } + assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/") } end def test_render_partial_with_incompatible_object - e = assert_raises(ArgumentError) { @view.render(:partial => nil) } + e = assert_raises(ArgumentError) { @view.render(partial: nil) } assert_equal "'#{nil.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.", e.message end def test_render_partial_starting_with_a_capital - assert_nothing_raised { @view.render(:partial => 'test/FooBar') } + assert_nothing_raised { @view.render(partial: "test/FooBar") } end def test_render_partial_with_hyphen - assert_nothing_raised { @view.render(:partial => "test/a-in") } + assert_nothing_raised { @view.render(partial: "test/a-in") } end def test_render_partial_with_unicode_text - assert_nothing_raised { @view.render(:partial => "test/ðŸ£") } + assert_nothing_raised { @view.render(partial: "test/ðŸ£") } end def test_render_partial_with_invalid_option_as - e = assert_raises(ArgumentError) { @view.render(:partial => "test/partial_only", :as => 'a-in') } + e = assert_raises(ArgumentError) { @view.render(partial: "test/partial_only", as: "a-in") } assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " + "make sure it starts with lowercase letter, " + "and is followed by any combination of letters, numbers and underscores.", e.message end def test_render_partial_with_hyphen_and_invalid_option_as - e = assert_raises(ArgumentError) { @view.render(:partial => "test/a-in", :as => 'a-in') } + e = assert_raises(ArgumentError) { @view.render(partial: "test/a-in", as: "a-in") } assert_equal "The value (a-in) of the option `as` is not a valid Ruby identifier; " + "make sure it starts with lowercase letter, " + "and is followed by any combination of letters, numbers and underscores.", e.message end def test_render_partial_with_errors - e = assert_raises(ActionView::Template::Error) { @view.render(:partial => "test/raise") } + e = assert_raises(ActionView::Template::Error) { @view.render(partial: "test/raise") } assert_match %r!method.*doesnt_exist!, e.message assert_equal "", e.sub_template_message assert_equal "1", e.line_number @@ -235,7 +242,7 @@ module RenderTestCases end def test_render_error_indentation - e = assert_raises(ActionView::Template::Error) { @view.render(:partial => "test/raise_indentation") } + e = assert_raises(ActionView::Template::Error) { @view.render(partial: "test/raise_indentation") } error_lines = e.annoted_source_code assert_match %r!error\shere!, e.message assert_equal "11", e.line_number @@ -244,7 +251,7 @@ module RenderTestCases end def test_render_sub_template_with_errors - e = assert_raises(ActionView::Template::Error) { @view.render(:template => "test/sub_template_raise") } + e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/sub_template_raise") } assert_match %r!method.*doesnt_exist!, e.message assert_equal "Trace of template inclusion: #{File.expand_path("#{FIXTURE_LOAD_PATH}/test/sub_template_raise.html.erb")}", e.sub_template_message assert_equal "1", e.line_number @@ -252,7 +259,7 @@ module RenderTestCases end def test_render_file_with_errors - e = assert_raises(ActionView::Template::Error) { @view.render(:file => File.expand_path("test/_raise", FIXTURE_LOAD_PATH)) } + e = assert_raises(ActionView::Template::Error) { @view.render(file: File.expand_path("test/_raise", FIXTURE_LOAD_PATH)) } assert_match %r!method.*doesnt_exist!, e.message assert_equal "", e.sub_template_message assert_equal "1", e.line_number @@ -261,109 +268,117 @@ module RenderTestCases end def test_render_object - assert_equal "Hello: david", @view.render(:partial => "test/customer", :object => Customer.new("david")) - assert_equal "FalseClass", @view.render(:partial => "test/klass", :object => false) - assert_equal "NilClass", @view.render(:partial => "test/klass", :object => nil) + assert_equal "Hello: david", @view.render(partial: "test/customer", object: Customer.new("david")) + assert_equal "FalseClass", @view.render(partial: "test/klass", object: false) + assert_equal "NilClass", @view.render(partial: "test/klass", object: nil) end def test_render_object_with_array - assert_equal "[1, 2, 3]", @view.render(:partial => "test/object_inspector", :object => [1, 2, 3]) + assert_equal "[1, 2, 3]", @view.render(partial: "test/object_inspector", object: [1, 2, 3]) end def test_render_partial_collection - assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ]) + assert_equal "Hello: davidHello: mary", @view.render(partial: "test/customer", collection: [ Customer.new("david"), Customer.new("mary") ]) end def test_render_partial_collection_with_partial_name_containing_dot assert_equal "Hello: davidHello: mary", - @view.render(:partial => "test/customer.mobile", :collection => [ Customer.new("david"), Customer.new("mary") ]) + @view.render(partial: "test/customer.mobile", collection: [ Customer.new("david"), Customer.new("mary") ]) end def test_render_partial_collection_as_by_string assert_equal "david david davidmary mary mary", - @view.render(:partial => "test/customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => 'customer') + @view.render(partial: "test/customer_with_var", collection: [ Customer.new("david"), Customer.new("mary") ], as: "customer") end def test_render_partial_collection_as_by_symbol assert_equal "david david davidmary mary mary", - @view.render(:partial => "test/customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer) + @view.render(partial: "test/customer_with_var", collection: [ Customer.new("david"), Customer.new("mary") ], as: :customer) end def test_render_partial_collection_without_as assert_equal "local_inspector,local_inspector_counter,local_inspector_iteration", - @view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ]) + @view.render(partial: "test/local_inspector", collection: [ Customer.new("mary") ]) end def test_render_partial_with_empty_collection_should_return_nil - assert_nil @view.render(:partial => "test/customer", :collection => []) + assert_nil @view.render(partial: "test/customer", collection: []) end def test_render_partial_with_nil_collection_should_return_nil - assert_nil @view.render(:partial => "test/customer", :collection => nil) + assert_nil @view.render(partial: "test/customer", collection: nil) + end + + def test_render_partial_collection_for_non_array + customers = Enumerator.new do |y| + y.yield(Customer.new("david")) + y.yield(Customer.new("mary")) + end + assert_equal "Hello: davidHello: mary", @view.render(partial: "test/customer", collection: customers) end def test_render_partial_without_object_does_not_put_partial_name_to_local_assigns - assert_equal 'false', @view.render(partial: 'test/partial_name_in_local_assigns') + assert_equal "false", @view.render(partial: "test/partial_name_in_local_assigns") end def test_render_partial_with_nil_object_puts_partial_name_to_local_assigns - assert_equal 'true', @view.render(partial: 'test/partial_name_in_local_assigns', object: nil) + assert_equal "true", @view.render(partial: "test/partial_name_in_local_assigns", object: nil) end def test_render_partial_with_nil_values_in_collection - assert_equal "Hello: davidHello: Anonymous", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), nil ]) + assert_equal "Hello: davidHello: Anonymous", @view.render(partial: "test/customer", collection: [ Customer.new("david"), nil ]) end def test_render_partial_with_layout_using_collection_and_template - assert_equal "<b>Hello: Amazon</b><b>Hello: Yahoo</b>", @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + assert_equal "<b>Hello: Amazon</b><b>Hello: Yahoo</b>", @view.render(partial: "test/customer", layout: "test/b_layout_for_partial", collection: [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end def test_render_partial_with_layout_using_collection_and_template_makes_current_item_available_in_layout assert_equal '<b class="amazon">Hello: Amazon</b><b class="yahoo">Hello: Yahoo</b>', - @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + @view.render(partial: "test/customer", layout: "test/b_layout_for_partial_with_object", collection: [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end def test_render_partial_with_layout_using_collection_and_template_makes_current_item_counter_available_in_layout assert_equal '<b data-counter="0">Hello: Amazon</b><b data-counter="1">Hello: Yahoo</b>', - @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object_counter', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + @view.render(partial: "test/customer", layout: "test/b_layout_for_partial_with_object_counter", collection: [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end def test_render_partial_with_layout_using_object_and_template_makes_object_available_in_layout assert_equal '<b class="amazon">Hello: Amazon</b>', - @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :object => Customer.new("Amazon")) + @view.render(partial: "test/customer", layout: "test/b_layout_for_partial_with_object", object: Customer.new("Amazon")) end def test_render_partial_with_empty_array_should_return_nil - assert_nil @view.render(:partial => []) + assert_nil @view.render(partial: []) end def test_render_partial_using_string - assert_equal "Hello: Anonymous", @controller_view.render('customer') + assert_equal "Hello: Anonymous", @controller_view.render("customer") end def test_render_partial_with_locals_using_string - assert_equal "Hola: david", @controller_view.render('customer_greeting', :greeting => 'Hola', :customer_greeting => Customer.new("david")) + assert_equal "Hola: david", @controller_view.render("customer_greeting", greeting: "Hola", customer_greeting: Customer.new("david")) end def test_render_partial_with_object_uses_render_partial_path assert_equal "Hello: lifo", - @controller_view.render(:partial => Customer.new("lifo"), :locals => {:greeting => "Hello"}) + @controller_view.render(partial: Customer.new("lifo"), locals: { greeting: "Hello" }) end def test_render_partial_with_object_and_format_uses_render_partial_path assert_equal "<greeting>Hello</greeting><name>lifo</name>", - @controller_view.render(:partial => Customer.new("lifo"), :formats => :xml, :locals => {:greeting => "Hello"}) + @controller_view.render(partial: Customer.new("lifo"), formats: :xml, locals: { greeting: "Hello" }) end def test_render_partial_using_object assert_equal "Hello: lifo", - @controller_view.render(Customer.new("lifo"), :greeting => "Hello") + @controller_view.render(Customer.new("lifo"), greeting: "Hello") end def test_render_partial_using_collection customers = [ Customer.new("Amazon"), Customer.new("Yahoo") ] assert_equal "Hello: AmazonHello: Yahoo", - @controller_view.render(customers, :greeting => "Hello") + @controller_view.render(customers, greeting: "Hello") end def test_render_partial_using_collection_without_path @@ -380,32 +395,32 @@ module RenderTestCases # TODO: The reason for this test is unclear, improve documentation def test_render_partial_and_fallback_to_layout - assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" }) + assert_equal "Before (Josh)\n\nAfter", @view.render(partial: "test/layout_for_partial", locals: { name: "Josh" }) end # TODO: The reason for this test is unclear, improve documentation def test_render_missing_xml_partial_and_raise_missing_template @view.formats = [:xml] - assert_raises(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") } + assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/layout_for_partial") } ensure @view.formats = nil end def test_render_layout_with_block_and_other_partial_inside - render = @view.render(:layout => "test/layout_with_partial_and_yield") { "Yield!" } + render = @view.render(layout: "test/layout_with_partial_and_yield") { "Yield!" } assert_equal "Before\npartial html\nYield!\nAfter\n", render end def test_render_inline - assert_equal "Hello, World!", @view.render(:inline => "Hello, World!") + assert_equal "Hello, World!", @view.render(inline: "Hello, World!") end def test_render_inline_with_locals - assert_equal "Hello, Josh!", @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }) + assert_equal "Hello, Josh!", @view.render(inline: "Hello, <%= name %>!", locals: { name: "Josh" }) end def test_render_fallbacks_to_erb_for_unknown_types - assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :bar) + assert_equal "Hello, World!", @view.render(inline: "Hello, World!", type: :bar) end CustomHandler = lambda do |template| @@ -415,7 +430,7 @@ module RenderTestCases def test_render_inline_with_render_from_to_proc ActionView::Template.register_template_handler :ruby_handler, :source.to_proc - assert_equal '3', @view.render(inline: "(1 + 2).to_s", type: :ruby_handler) + assert_equal "3", @view.render(inline: "(1 + 2).to_s", type: :ruby_handler) ensure ActionView::Template.unregister_template_handler :ruby_handler end @@ -435,17 +450,17 @@ module RenderTestCases end def test_render_body - assert_equal 'some body', @view.render(body: 'some body') + assert_equal "some body", @view.render(body: "some body") end def test_render_plain - assert_equal 'some plaintext', @view.render(plain: 'some plaintext') + assert_equal "some plaintext", @view.render(plain: "some plaintext") end def test_render_knows_about_types_registered_when_extensions_are_checked_earlier_in_initialization ActionView::Template::Handlers.extensions ActionView::Template.register_template_handler :foo, CustomHandler - assert ActionView::Template::Handlers.extensions.include?(:foo) + assert_includes ActionView::Template::Handlers.extensions, :foo ensure ActionView::Template.unregister_template_handler :foo end @@ -463,54 +478,54 @@ module RenderTestCases ActiveSupport::Deprecation.silence do %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| assert File.exist?(File.expand_path("#{FIXTURE_LOAD_PATH}/test/malformed/#{name}~")), "Malformed file (#{name}~) which should be ignored does not exists" - assert_raises(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") } + assert_raises(ActionView::MissingTemplate) { @view.render(file: "test/malformed/#{name}") } end end end def test_render_with_layout assert_equal %(<title></title>\nHello world!\n), - @view.render(:file => "test/hello_world", :layout => "layouts/yield") + @view.render(file: "test/hello_world", layout: "layouts/yield") end def test_render_with_layout_which_has_render_inline assert_equal %(welcome\nHello world!\n), - @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside") + @view.render(file: "test/hello_world", layout: "layouts/yield_with_render_inline_inside") end def test_render_with_layout_which_renders_another_partial assert_equal %(partial html\nHello world!\n), - @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside") + @view.render(file: "test/hello_world", layout: "layouts/yield_with_render_partial_inside") end def test_render_partial_with_html_only_extension assert_equal %(<h1>partial html</h1>\nHello world!\n), - @view.render(:file => "test/hello_world", :layout => "layouts/render_partial_html") + @view.render(file: "test/hello_world", layout: "layouts/render_partial_html") end def test_render_layout_with_block_and_yield assert_equal %(Content from block!\n), - @view.render(:layout => "layouts/yield_only") { "Content from block!" } + @view.render(layout: "layouts/yield_only") { "Content from block!" } end def test_render_layout_with_block_and_yield_with_params assert_equal %(Yield! Content from block!\n), - @view.render(:layout => "layouts/yield_with_params") { |param| "#{param} Content from block!" } + @view.render(layout: "layouts/yield_with_params") { |param| "#{param} Content from block!" } end def test_render_layout_with_block_which_renders_another_partial_and_yields assert_equal %(partial html\nContent from block!\n), - @view.render(:layout => "layouts/partial_and_yield") { "Content from block!" } + @view.render(layout: "layouts/partial_and_yield") { "Content from block!" } end def test_render_partial_and_layout_without_block_with_locals assert_equal %(Before (Foo!)\npartial html\nAfter), - @view.render(:partial => 'test/partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + @view.render(partial: "test/partial", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_partial_and_layout_without_block_with_locals_and_rendering_another_partial assert_equal %(Before (Foo!)\npartial html\npartial with partial\n\nAfter), - @view.render(:partial => 'test/partial_with_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + @view.render(partial: "test/partial_with_partial", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_partial_shortcut_with_block_content @@ -520,37 +535,37 @@ module RenderTestCases def test_render_layout_with_a_nested_render_layout_call assert_equal %(Before (Foo!)\nBefore (Bar!)\npartial html\nAfter\npartial with layout\n\nAfter), - @view.render(:partial => 'test/partial_with_layout', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + @view.render(partial: "test/partial_with_layout", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_partial assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n partial html\n\nAfterpartial with layout\n\nAfter), - @view.render(:partial => 'test/partial_with_layout_block_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + @view.render(partial: "test/partial_with_layout_block_partial", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_content assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n Content from inside layout!\n\nAfterpartial with layout\n\nAfter), - @view.render(:partial => 'test/partial_with_layout_block_content', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + @view.render(partial: "test/partial_with_layout_block_content", layout: "test/layout_for_partial", locals: { name: "Foo!" }) end def test_render_partial_with_layout_raises_descriptive_error - e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: 'test/partial', layout: true) } + e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/partial", layout: true) } assert_match "Missing partial /_true with", e.message end def test_render_with_nested_layout assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), - @view.render(:file => "test/nested_layout", :layout => "layouts/yield") + @view.render(file: "test/nested_layout", layout: "layouts/yield") end def test_render_with_file_in_layout assert_equal %(\n<title>title</title>\n\n), - @view.render(:file => "test/layout_render_file") + @view.render(file: "test/layout_render_file") end def test_render_layout_with_object assert_equal %(<title>David</title>), - @view.render(:file => "test/layout_render_object") + @view.render(file: "test/layout_render_object") end def test_render_with_passing_couple_extensions_to_one_register_template_handler_function_call @@ -600,7 +615,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_magic_comment with_external_encoding Encoding::ASCII_8BIT do - result = @view.render(:file => "test/utf8_magic", :formats => [:html], :layouts => "layouts/yield") + result = @view.render(file: "test/utf8_magic", formats: [:html], layouts: "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "\nРуÑÑкий \nтекÑÑ‚\n\nUTF-8\nUTF-8\nUTF-8\n", result end @@ -608,7 +623,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_default_external_encoding with_external_encoding Encoding::UTF_8 do - result = @view.render(:file => "test/utf8", :formats => [:html], :layouts => "layouts/yield") + result = @view.render(file: "test/utf8", formats: [:html], layouts: "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "РуÑÑкий текÑÑ‚\n\nUTF-8\nUTF-8\nUTF-8\n", result end @@ -616,15 +631,15 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_incompatible_external_encoding with_external_encoding Encoding::SHIFT_JIS do - e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8", :formats => [:html], :layouts => "layouts/yield") } - assert_match 'Your template was not saved as valid Shift_JIS', e.cause.message + e = assert_raises(ActionView::Template::Error) { @view.render(file: "test/utf8", formats: [:html], layouts: "layouts/yield") } + assert_match "Your template was not saved as valid Shift_JIS", e.cause.message end end def test_render_utf8_template_with_partial_with_incompatible_encoding with_external_encoding Encoding::SHIFT_JIS do - e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8_magic_with_bare_partial", :formats => [:html], :layouts => "layouts/yield") } - assert_match 'Your template was not saved as valid Shift_JIS', e.cause.message + e = assert_raises(ActionView::Template::Error) { @view.render(file: "test/utf8_magic_with_bare_partial", formats: [:html], layouts: "layouts/yield") } + assert_match "Your template was not saved as valid Shift_JIS", e.cause.message end end @@ -661,7 +676,7 @@ class CachedCollectionViewRenderTest < ActiveSupport::TestCase customer = Customer.new("david", 1) key = cache_key(customer, "test/_customer") - ActionView::PartialRenderer.collection_cache.write(key, 'Cached') + ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_not_equal "Cached", @view.render(partial: "test/customer", collection: [customer]) @@ -671,7 +686,7 @@ class CachedCollectionViewRenderTest < ActiveSupport::TestCase customer = Customer.new("david", 1) key = cache_key(customer, "test/_customer") - ActionView::PartialRenderer.collection_cache.write(key, 'Cached') + ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_equal "Cached", @view.render(partial: "test/customer", collection: [customer], cached: true) @@ -681,7 +696,7 @@ class CachedCollectionViewRenderTest < ActiveSupport::TestCase customer = CachedCustomer.new("david", 1) key = cache_key(customer, "test/_cached_customer") - ActionView::PartialRenderer.collection_cache.write(key, 'Cached') + ActionView::PartialRenderer.collection_cache.write(key, "Cached") assert_equal "Cached", @view.render(partial: "test/cached_customer", collection: [customer], cached: true) diff --git a/actionview/test/template/resolver_cache_test.rb b/actionview/test/template/resolver_cache_test.rb index 1081c13db0..0ecfccd375 100644 --- a/actionview/test/template/resolver_cache_test.rb +++ b/actionview/test/template/resolver_cache_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ResolverCacheTest < ActiveSupport::TestCase def test_inspect_shields_cache_internals diff --git a/actionview/test/template/resolver_patterns_test.rb b/actionview/test/template/resolver_patterns_test.rb index 1a091bd692..43e3f21076 100644 --- a/actionview/test/template/resolver_patterns_test.rb +++ b/actionview/test/template/resolver_patterns_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ResolverPatternsTest < ActiveSupport::TestCase def setup @@ -8,12 +8,12 @@ class ResolverPatternsTest < ActiveSupport::TestCase end def test_should_return_empty_list_for_unknown_path - templates = @resolver.find_all("unknown", "custom_pattern", false, {locale: [], formats: [:html], variants: [], handlers: [:erb]}) + templates = @resolver.find_all("unknown", "custom_pattern", false, locale: [], formats: [:html], variants: [], handlers: [:erb]) assert_equal [], templates, "expected an empty list of templates" end def test_should_return_template_for_declared_path - templates = @resolver.find_all("path", "custom_pattern", false, {locale: [], formats: [:html], variants: [], handlers: [:erb]}) + templates = @resolver.find_all("path", "custom_pattern", false, locale: [], formats: [:html], variants: [], handlers: [:erb]) assert_equal 1, templates.size, "expected one template" assert_equal "Hello custom patterns!", templates.first.source assert_equal "custom_pattern/path", templates.first.virtual_path @@ -21,7 +21,7 @@ class ResolverPatternsTest < ActiveSupport::TestCase end def test_should_return_all_templates_when_ambiguous_pattern - templates = @resolver.find_all("another", "custom_pattern", false, {locale: [], formats: [:html], variants: [], handlers: [:erb]}) + templates = @resolver.find_all("another", "custom_pattern", false, locale: [], formats: [:html], variants: [], handlers: [:erb]) assert_equal 2, templates.size, "expected two templates" assert_equal "Another template!", templates[0].source assert_equal "custom_pattern/another", templates[0].virtual_path @@ -30,7 +30,7 @@ class ResolverPatternsTest < ActiveSupport::TestCase end def test_should_return_all_variants_for_any - templates = @resolver.find_all("hello_world", "test", false, {locale: [], formats: [:html, :text], variants: :any, handlers: [:erb]}) + templates = @resolver.find_all("hello_world", "test", false, locale: [], formats: [:html, :text], variants: :any, handlers: [:erb]) assert_equal 3, templates.size, "expected three templates" assert_equal "Hello phone!", templates[0].source assert_equal "test/hello_world", templates[0].virtual_path diff --git a/actionview/test/template/sanitize_helper_test.rb b/actionview/test/template/sanitize_helper_test.rb index efe846a7eb..c8963fee9c 100644 --- a/actionview/test/template/sanitize_helper_test.rb +++ b/actionview/test/template/sanitize_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" # The exhaustive tests are in test/controller/html/sanitizer_test.rb. # This tests that the helpers hook up correctly to the sanitizer classes. @@ -13,7 +13,7 @@ class SanitizeHelperTest < ActionView::TestCase end def test_sanitize_form - assert_equal '', sanitize("<form action=\"/foo/bar\" method=\"post\"><input></form>") + assert_equal "", sanitize("<form action=\"/foo/bar\" method=\"post\"><input></form>") end def test_should_sanitize_illegal_style_properties diff --git a/actionview/test/template/streaming_render_test.rb b/actionview/test/template/streaming_render_test.rb index d06ba4ceb0..6ce66a1275 100644 --- a/actionview/test/template/streaming_render_test.rb +++ b/actionview/test/template/streaming_render_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TestController < ActionController::Base end @@ -6,7 +6,7 @@ end class FiberedTest < ActiveSupport::TestCase def setup view_paths = ActionController::Base.view_paths - @assigns = { :secret => 'in the sauce', :name => nil } + @assigns = { secret: "in the sauce", name: nil } @view = ActionView::Base.new(view_paths, @assigns) @controller_view = TestController.new.view_context end @@ -26,7 +26,7 @@ class FiberedTest < ActiveSupport::TestCase def test_streaming_works content = [] - body = render_body(:template => "test/hello_world", :layout => "layouts/yield") + body = render_body(template: "test/hello_world", layout: "layouts/yield") body.each do |piece| content << piece @@ -40,68 +40,68 @@ class FiberedTest < ActiveSupport::TestCase end def test_render_file - assert_equal "Hello world!", buffered_render(:file => "test/hello_world") + assert_equal "Hello world!", buffered_render(file: "test/hello_world") end def test_render_file_with_locals - locals = { :secret => 'in the sauce' } - assert_equal "The secret is in the sauce\n", buffered_render(:file => "test/render_file_with_locals", :locals => locals) + locals = { secret: "in the sauce" } + assert_equal "The secret is in the sauce\n", buffered_render(file: "test/render_file_with_locals", locals: locals) end def test_render_partial - assert_equal "only partial", buffered_render(:partial => "test/partial_only") + assert_equal "only partial", buffered_render(partial: "test/partial_only") end def test_render_inline - assert_equal "Hello, World!", buffered_render(:inline => "Hello, World!") + assert_equal "Hello, World!", buffered_render(inline: "Hello, World!") end def test_render_without_layout - assert_equal "Hello world!", buffered_render(:template => "test/hello_world") + assert_equal "Hello world!", buffered_render(template: "test/hello_world") end def test_render_with_layout assert_equal %(<title></title>\nHello world!\n), - buffered_render(:template => "test/hello_world", :layout => "layouts/yield") + buffered_render(template: "test/hello_world", layout: "layouts/yield") end def test_render_with_layout_which_has_render_inline assert_equal %(welcome\nHello world!\n), - buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside") + buffered_render(template: "test/hello_world", layout: "layouts/yield_with_render_inline_inside") end def test_render_with_layout_which_renders_another_partial assert_equal %(partial html\nHello world!\n), - buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside") + buffered_render(template: "test/hello_world", layout: "layouts/yield_with_render_partial_inside") end def test_render_with_nested_layout assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), - buffered_render(:template => "test/nested_layout", :layout => "layouts/yield") + buffered_render(template: "test/nested_layout", layout: "layouts/yield") end def test_render_with_file_in_layout assert_equal %(\n<title>title</title>\n\n), - buffered_render(:template => "test/layout_render_file") + buffered_render(template: "test/layout_render_file") end def test_render_with_handler_without_streaming_support - assert_match "<p>This is grand!</p>", buffered_render(:template => "test/hello") + assert_match "<p>This is grand!</p>", buffered_render(template: "test/hello") end def test_render_with_streaming_multiple_yields_provide_and_content_for assert_equal "Yes, \nthis works\n like a charm.", - buffered_render(:template => "test/streaming", :layout => "layouts/streaming") + buffered_render(template: "test/streaming", layout: "layouts/streaming") end def test_render_with_streaming_with_fake_yields_and_streaming_buster assert_equal "This won't look\n good.", - buffered_render(:template => "test/streaming_buster", :layout => "layouts/streaming") + buffered_render(template: "test/streaming_buster", layout: "layouts/streaming") end def test_render_with_nested_streaming_multiple_yields_provide_and_content_for assert_equal "?Yes, \n\nthis works\n\n? like a charm.", - buffered_render(:template => "test/nested_streaming", :layout => "layouts/streaming") + buffered_render(template: "test/nested_streaming", layout: "layouts/streaming") end def test_render_with_streaming_and_capture diff --git a/actionview/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb index f3956a31f6..f1e5946e14 100644 --- a/actionview/test/template/tag_helper_test.rb +++ b/actionview/test/template/tag_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TagHelperTest < ActionView::TestCase include RenderERBUtils @@ -7,10 +7,28 @@ class TagHelperTest < ActionView::TestCase def test_tag assert_equal "<br />", tag("br") - assert_equal "<br clear=\"left\" />", tag(:br, :clear => "left") + assert_equal "<br clear=\"left\" />", tag(:br, clear: "left") assert_equal "<br>", tag("br", nil, true) end + def test_tag_builder + assert_equal "<span></span>", tag.span + assert_equal "<span class=\"bookmark\"></span>", tag.span(class: "bookmark") + end + + def test_tag_builder_void_tag + assert_equal "<br>", tag.br + assert_equal "<br class=\"some_class\">", tag.br(class: "some_class") + end + + def test_tag_builder_void_tag_with_forced_content + assert_equal "<br>some content</br>", tag.br("some content") + end + + def test_tag_builder_is_singleton + assert_equal tag, tag + end + def test_tag_options str = tag("p", "class" => "show", :class => "elsewhere") assert_match(/class="show"/, str) @@ -18,31 +36,76 @@ class TagHelperTest < ActionView::TestCase end def test_tag_options_rejects_nil_option - assert_equal "<p />", tag("p", :ignored => nil) + assert_equal "<p />", tag("p", ignored: nil) + end + + def test_tag_builder_options_rejects_nil_option + assert_equal "<p></p>", tag.p(ignored: nil) end def test_tag_options_accepts_false_option - assert_equal "<p value=\"false\" />", tag("p", :value => false) + assert_equal "<p value=\"false\" />", tag("p", value: false) + end + + def test_tag_builder_options_accepts_false_option + assert_equal "<p value=\"false\"></p>", tag.p(value: false) end def test_tag_options_accepts_blank_option - assert_equal "<p included=\"\" />", tag("p", :included => '') + assert_equal "<p included=\"\" />", tag("p", included: "") + end + + def test_tag_builder_options_accepts_blank_option + assert_equal "<p included=\"\"></p>", tag.p(included: "") + end + + def test_tag_options_accepts_symbol_option_when_not_escaping + assert_equal "<p value=\"symbol\" />", tag("p", { value: :symbol }, false, false) + end + + def test_tag_options_accepts_integer_option_when_not_escaping + assert_equal "<p value=\"42\" />", tag("p", { value: 42 }, false, false) end def test_tag_options_converts_boolean_option assert_dom_equal '<p disabled="disabled" itemscope="itemscope" multiple="multiple" readonly="readonly" allowfullscreen="allowfullscreen" seamless="seamless" typemustmatch="typemustmatch" sortable="sortable" default="default" inert="inert" truespeed="truespeed" />', - tag("p", :disabled => true, :itemscope => true, :multiple => true, :readonly => true, :allowfullscreen => true, :seamless => true, :typemustmatch => true, :sortable => true, :default => true, :inert => true, :truespeed => true) + tag("p", disabled: true, itemscope: true, multiple: true, readonly: true, allowfullscreen: true, seamless: true, typemustmatch: true, sortable: true, default: true, inert: true, truespeed: true) + end + + def test_tag_builder_options_converts_boolean_option + assert_dom_equal '<p disabled="disabled" itemscope="itemscope" multiple="multiple" readonly="readonly" allowfullscreen="allowfullscreen" seamless="seamless" typemustmatch="typemustmatch" sortable="sortable" default="default" inert="inert" truespeed="truespeed" />', + tag.p(disabled: true, itemscope: true, multiple: true, readonly: true, allowfullscreen: true, seamless: true, typemustmatch: true, sortable: true, default: true, inert: true, truespeed: true) end def test_content_tag assert_equal "<a href=\"create\">Create</a>", content_tag("a", "Create", "href" => "create") assert content_tag("a", "Create", "href" => "create").html_safe? assert_equal content_tag("a", "Create", "href" => "create"), - content_tag("a", "Create", :href => "create") + content_tag("a", "Create", href: "create") + assert_equal "<p><script>evil_js</script></p>", + content_tag(:p, "<script>evil_js</script>") + assert_equal "<p><script>evil_js</script></p>", + content_tag(:p, "<script>evil_js</script>", nil, false) + end + + def test_tag_builder_with_content + assert_equal "<div id=\"post_1\">Content</div>", tag.div("Content", id: "post_1") + assert tag.div("Content", id: "post_1").html_safe? + assert_equal tag.div("Content", id: "post_1"), + tag.div("Content", "id": "post_1") assert_equal "<p><script>evil_js</script></p>", - content_tag(:p, '<script>evil_js</script>') + tag.p("<script>evil_js</script>") assert_equal "<p><script>evil_js</script></p>", - content_tag(:p, '<script>evil_js</script>', nil, false) + tag.p("<script>evil_js</script>", escape_attributes: false) + end + + def test_tag_builder_nested + assert_equal "<div>content</div>", + tag.div { "content" } + assert_equal "<div id=\"header\"><span>hello</span></div>", + tag.div(id: "header") { |tag| tag.span "hello" } + assert_equal "<div id=\"header\"><div class=\"world\"><span>hello</span></div></div>", + tag.div(id: "header") { |tag| tag.div(class: "world") { tag.span "hello" } } end def test_content_tag_with_block_in_erb @@ -50,72 +113,138 @@ class TagHelperTest < ActionView::TestCase assert_dom_equal "<div>Hello world!</div>", buffer end + def test_tag_builder_with_block_in_erb + buffer = render_erb("<%= tag.div do %>Hello world!<% end %>") + assert_dom_equal "<div>Hello world!</div>", buffer + end + def test_content_tag_with_block_in_erb_containing_non_displayed_erb buffer = render_erb("<%= content_tag(:p) do %><% 1 %><% end %>") assert_dom_equal "<p></p>", buffer end + def test_tag_builder_with_block_in_erb_containing_non_displayed_erb + buffer = render_erb("<%= tag.p do %><% 1 %><% end %>") + assert_dom_equal "<p></p>", buffer + end + def test_content_tag_with_block_and_options_in_erb buffer = render_erb("<%= content_tag(:div, :class => 'green') do %>Hello world!<% end %>") assert_dom_equal %(<div class="green">Hello world!</div>), buffer end + def test_tag_builder_with_block_and_options_in_erb + buffer = render_erb("<%= tag.div(class: 'green') do %>Hello world!<% end %>") + assert_dom_equal %(<div class="green">Hello world!</div>), buffer + end + def test_content_tag_with_block_and_options_out_of_erb - assert_dom_equal %(<div class="green">Hello world!</div>), content_tag(:div, :class => "green") { "Hello world!" } + assert_dom_equal %(<div class="green">Hello world!</div>), content_tag(:div, class: "green") { "Hello world!" } + end + + def test_tag_builder_with_block_and_options_out_of_erb + assert_dom_equal %(<div class="green">Hello world!</div>), tag.div(class: "green") { "Hello world!" } end def test_content_tag_with_block_and_options_outside_out_of_erb - assert_equal content_tag("a", "Create", :href => "create"), + assert_equal content_tag("a", "Create", href: "create"), content_tag("a", "href" => "create") { "Create" } end + def test_tag_builder_with_block_and_options_outside_out_of_erb + assert_equal tag.a("Create", href: "create"), + tag.a("href": "create") { "Create" } + end + def test_content_tag_with_block_and_non_string_outside_out_of_erb assert_equal content_tag("p"), content_tag("p") { 3.times { "do_something" } } end + def test_tag_builder_with_block_and_non_string_outside_out_of_erb + assert_equal tag.p, + tag.p { 3.times { "do_something" } } + end + def test_content_tag_nested_in_content_tag_out_of_erb assert_equal content_tag("p", content_tag("b", "Hello")), content_tag("p") { content_tag("b", "Hello") }, output_buffer + assert_equal tag.p(tag.b("Hello")), + tag.p { tag.b("Hello") }, + output_buffer end def test_content_tag_nested_in_content_tag_in_erb assert_equal "<p>\n <b>Hello</b>\n</p>", view.render("test/content_tag_nested_in_content_tag") + assert_equal "<p>\n <b>Hello</b>\n</p>", view.render("test/builder_tag_nested_in_content_tag") end def test_content_tag_with_escaped_array_class - str = content_tag('p', "limelight", :class => ["song", "play>"]) + str = content_tag("p", "limelight", class: ["song", "play>"]) + assert_equal "<p class=\"song play>\">limelight</p>", str + + str = content_tag("p", "limelight", class: ["song", "play"]) + assert_equal "<p class=\"song play\">limelight</p>", str + + str = content_tag("p", "limelight", class: ["song", ["play"]]) + assert_equal "<p class=\"song play\">limelight</p>", str + end + + def test_tag_builder_with_escaped_array_class + str = tag.p "limelight", class: ["song", "play>"] assert_equal "<p class=\"song play>\">limelight</p>", str - str = content_tag('p', "limelight", :class => ["song", "play"]) + str = tag.p "limelight", class: ["song", "play"] assert_equal "<p class=\"song play\">limelight</p>", str - str = content_tag('p', "limelight", :class => ["song", ["play"]]) + str = tag.p "limelight", class: ["song", ["play"]] assert_equal "<p class=\"song play\">limelight</p>", str end def test_content_tag_with_unescaped_array_class - str = content_tag('p', "limelight", {:class => ["song", "play>"]}, false) + str = content_tag("p", "limelight", { class: ["song", "play>"] }, false) assert_equal "<p class=\"song play>\">limelight</p>", str - str = content_tag('p', "limelight", {:class => ["song", ["play>"]]}, false) + str = content_tag("p", "limelight", { class: ["song", ["play>"]] }, false) + assert_equal "<p class=\"song play>\">limelight</p>", str + end + + def test_tag_builder_with_unescaped_array_class + str = tag.p "limelight", class: ["song", "play>"], escape_attributes: false + assert_equal "<p class=\"song play>\">limelight</p>", str + + str = tag.p "limelight", class: ["song", ["play>"]], escape_attributes: false assert_equal "<p class=\"song play>\">limelight</p>", str end def test_content_tag_with_empty_array_class - str = content_tag('p', 'limelight', {:class => []}) + str = content_tag("p", "limelight", class: []) assert_equal '<p class="">limelight</p>', str end + def test_tag_builder_with_empty_array_class + assert_equal '<p class="">limelight</p>', tag.p("limelight", class: []) + end + def test_content_tag_with_unescaped_empty_array_class - str = content_tag('p', 'limelight', {:class => []}, false) + str = content_tag("p", "limelight", { class: [] }, false) + assert_equal '<p class="">limelight</p>', str + end + + def test_tag_builder_with_unescaped_empty_array_class + str = tag.p "limelight", class: [], escape_attributes: false assert_equal '<p class="">limelight</p>', str end def test_content_tag_with_data_attributes assert_dom_equal '<p data-number="1" data-string="hello" data-string-with-quotes="double"quote"party"">limelight</p>', - content_tag('p', "limelight", data: { number: 1, string: 'hello', string_with_quotes: 'double"quote"party"' }) + content_tag("p", "limelight", data: { number: 1, string: "hello", string_with_quotes: 'double"quote"party"' }) + end + + def test_tag_builder_with_data_attributes + assert_dom_equal '<p data-number="1" data-string="hello" data-string-with-quotes="double"quote"party"">limelight</p>', + tag.p("limelight", data: { number: 1, string: "hello", string_with_quotes: 'double"quote"party"' }) end def test_cdata_section @@ -132,51 +261,95 @@ class TagHelperTest < ActionView::TestCase end def test_escape_once - assert_equal '1 < 2 & 3', escape_once('1 < 2 & 3') + assert_equal "1 < 2 & 3", escape_once("1 < 2 & 3") assert_equal " ' ' λ λ " ' < > ", escape_once(" ' ' λ λ \" ' < > ") end def test_tag_honors_html_safe_for_param_values - ['1&2', '1 < 2', '“test“'].each do |escaped| - assert_equal %(<a href="#{escaped}" />), tag('a', :href => escaped.html_safe) + ["1&2", "1 < 2", "“test“"].each do |escaped| + assert_equal %(<a href="#{escaped}" />), tag("a", href: escaped.html_safe) + assert_equal %(<a href="#{escaped}"></a>), tag.a(href: escaped.html_safe) end end def test_tag_honors_html_safe_with_escaped_array_class - str = tag('p', :class => ['song>', raw('play>')]) - assert_equal '<p class="song> play>" />', str + assert_equal '<p class="song> play>" />', tag("p", class: ["song>", raw("play>")]) + assert_equal '<p class="song> play>" />', tag("p", class: [raw("song>"), "play>"]) + end + + def test_tag_builder_honors_html_safe_with_escaped_array_class + assert_equal '<p class="song> play>"></p>', tag.p(class: ["song>", raw("play>")]) + assert_equal '<p class="song> play>"></p>', tag.p(class: [raw("song>"), "play>"]) + end + + def test_tag_does_not_honor_html_safe_double_quotes_as_attributes + assert_dom_equal '<p title=""">content</p>', + content_tag("p", "content", title: '"'.html_safe) + end - str = tag('p', :class => [raw('song>'), 'play>']) - assert_equal '<p class="song> play>" />', str + def test_data_tag_does_not_honor_html_safe_double_quotes_as_attributes + assert_dom_equal '<p data-title=""">content</p>', + content_tag("p", "content", data: { title: '"'.html_safe }) end def test_skip_invalid_escaped_attributes - ['&1;', 'dfa3;', '& #123;'].each do |escaped| - assert_equal %(<a href="#{escaped.gsub(/&/, '&')}" />), tag('a', :href => escaped) + ["&1;", "dfa3;", "& #123;"].each do |escaped| + assert_equal %(<a href="#{escaped.gsub(/&/, '&')}" />), tag("a", href: escaped) + assert_equal %(<a href="#{escaped.gsub(/&/, '&')}"></a>), tag.a(href: escaped) end end def test_disable_escaping - assert_equal '<a href="&" />', tag('a', { :href => '&' }, false, false) + assert_equal '<a href="&" />', tag("a", { href: "&" }, false, false) + end + + def test_tag_builder_disable_escaping + assert_equal '<a href="&"></a>', tag.a(href: "&", escape_attributes: false) + assert_equal '<a href="&">cnt</a>', tag.a(href: "&" , escape_attributes: false) { "cnt" } + assert_equal '<br data-hidden="&">', tag.br("data-hidden": "&" , escape_attributes: false) + assert_equal '<a href="&">content</a>', tag.a("content", href: "&", escape_attributes: false) + assert_equal '<a href="&">content</a>', tag.a(href: "&", escape_attributes: false) { "content" } end def test_data_attributes - ['data', :data].each { |data| + ["data", :data].each { |data| assert_dom_equal '<a data-a-float="3.14" data-a-big-decimal="-123.456" data-a-number="1" data-array="[1,2,3]" data-hash="{"key":"value"}" data-string-with-quotes="double"quote"party"" data-string="hello" data-symbol="foo" />', - tag('a', { data => { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: 'hello', symbol: :foo, array: [1, 2, 3], hash: { key: 'value'}, string_with_quotes: 'double"quote"party"' } }) + tag("a", data => { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { key: "value" }, string_with_quotes: 'double"quote"party"' }) + assert_dom_equal '<a data-a-float="3.14" data-a-big-decimal="-123.456" data-a-number="1" data-array="[1,2,3]" data-hash="{"key":"value"}" data-string-with-quotes="double"quote"party"" data-string="hello" data-symbol="foo" />', + tag.a(data: { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { key: "value" }, string_with_quotes: 'double"quote"party"' }) } end def test_aria_attributes - ['aria', :aria].each { |aria| + ["aria", :aria].each { |aria| + assert_dom_equal '<a aria-a-float="3.14" aria-a-big-decimal="-123.456" aria-a-number="1" aria-array="[1,2,3]" aria-hash="{"key":"value"}" aria-string-with-quotes="double"quote"party"" aria-string="hello" aria-symbol="foo" />', + tag("a", aria => { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { key: "value" }, string_with_quotes: 'double"quote"party"' }) assert_dom_equal '<a aria-a-float="3.14" aria-a-big-decimal="-123.456" aria-a-number="1" aria-array="[1,2,3]" aria-hash="{"key":"value"}" aria-string-with-quotes="double"quote"party"" aria-string="hello" aria-symbol="foo" />', - tag('a', { aria => { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: 'hello', symbol: :foo, array: [1, 2, 3], hash: { key: 'value'}, string_with_quotes: 'double"quote"party"' } }) + tag.a(aria: { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: "hello", symbol: :foo, array: [1, 2, 3], hash: { key: "value" }, string_with_quotes: 'double"quote"party"' }) } end def test_link_to_data_nil_equal - div_type1 = content_tag(:div, 'test', { 'data-tooltip' => nil }) - div_type2 = content_tag(:div, 'test', { data: {tooltip: nil} }) - assert_dom_equal div_type1, div_type2 + div_type1 = content_tag(:div, "test", "data-tooltip" => nil) + div_type2 = content_tag(:div, "test", data: { tooltip: nil }) + assert_dom_equal div_type1, div_type2 + end + + def test_tag_builder_link_to_data_nil_equal + div_type1 = tag.div "test", 'data-tooltip': nil + div_type2 = tag.div "test", data: { tooltip: nil } + assert_dom_equal div_type1, div_type2 + end + + def test_tag_builder_allow_call_via_method_object + assert_equal "<foo></foo>", tag.method(:foo).call + end + + def test_tag_builder_dasherize_names + assert_equal "<img-slider></img-slider>", tag.img_slider + end + + def test_respond_to + assert_respond_to tag, :any_tag end end diff --git a/actionview/test/template/template_test.rb b/actionview/test/template/template_test.rb index 533c1c3219..9d31a98703 100644 --- a/actionview/test/template/template_test.rb +++ b/actionview/test/template/template_test.rb @@ -35,7 +35,7 @@ class TestERBTemplate < ActiveSupport::TestCase "<%= @virtual_path %>", "partial", ERBHandler, - :virtual_path => "partial" + virtual_path: "partial" ) end @@ -53,7 +53,7 @@ class TestERBTemplate < ActiveSupport::TestCase end def new_template(body = "<%= hello %>", details = { format: :html }) - ActionView::Template.new(body, "hello template", details.fetch(:handler) { ERBHandler }, {:virtual_path => "hello"}.merge!(details)) + ActionView::Template.new(body, "hello template", details.fetch(:handler) { ERBHandler }, { virtual_path: "hello" }.merge!(details)) end def render(locals = {}) @@ -80,7 +80,7 @@ class TestERBTemplate < ActiveSupport::TestCase end def test_raw_template - @template = new_template("<%= hello %>", :handler => ActionView::Template::Handlers::Raw.new) + @template = new_template("<%= hello %>", handler: ActionView::Template::Handlers::Raw.new) assert_equal "<%= hello %>", render end @@ -91,7 +91,7 @@ class TestERBTemplate < ActiveSupport::TestCase end def test_template_does_not_lose_its_source_after_rendering_if_it_does_not_have_a_virtual_path - @template = new_template("Hello", :virtual_path => nil) + @template = new_template("Hello", virtual_path: nil) render assert_equal "Hello", @template.source end @@ -99,7 +99,7 @@ class TestERBTemplate < ActiveSupport::TestCase def test_locals @template = new_template("<%= my_local %>") @template.locals = [:my_local] - assert_equal "I am a local", render(:my_local => "I am a local") + assert_equal "I am a local", render(my_local: "I am a local") end def test_restores_buffer @@ -116,23 +116,23 @@ class TestERBTemplate < ActiveSupport::TestCase end def test_refresh_with_templates - @template = new_template("Hello", :virtual_path => "test/foo/bar") + @template = new_template("Hello", virtual_path: "test/foo/bar") @template.locals = [:key] - assert_called_with(@context.lookup_context, :find_template,["bar", %w(test/foo), false, [:key]], returns: "template") do + assert_called_with(@context.lookup_context, :find_template, ["bar", %w(test/foo), false, [:key]], returns: "template") do assert_equal "template", @template.refresh(@context) end end def test_refresh_with_partials - @template = new_template("Hello", :virtual_path => "test/_foo") + @template = new_template("Hello", virtual_path: "test/_foo") @template.locals = [:key] - assert_called_with(@context.lookup_context, :find_template,[ "foo", %w(test), true, [:key]], returns: "partial") do + assert_called_with(@context.lookup_context, :find_template, ["foo", %w(test), true, [:key]], returns: "partial") do assert_equal "partial", @template.refresh(@context) end end def test_refresh_raises_an_error_without_virtual_path - @template = new_template("Hello", :virtual_path => nil) + @template = new_template("Hello", virtual_path: nil) assert_raise RuntimeError do @template.refresh(@context) end @@ -171,14 +171,14 @@ class TestERBTemplate < ActiveSupport::TestCase # inside Rails. def test_lying_with_magic_comment assert_raises(ActionView::Template::Error) do - @template = new_template("# encoding: UTF-8\nhello \xFCmlat", :virtual_path => nil) + @template = new_template("# encoding: UTF-8\nhello \xFCmlat", virtual_path: nil) render end end def test_encoding_can_be_specified_with_magic_comment_in_erb with_external_encoding Encoding::UTF_8 do - @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat", :virtual_path => nil) + @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat", virtual_path: nil) assert_equal Encoding::UTF_8, render.encoding assert_equal "hello \u{fc}mlat", render end @@ -186,10 +186,12 @@ class TestERBTemplate < ActiveSupport::TestCase def test_error_when_template_isnt_valid_utf8 e = assert_raises ActionView::Template::Error do - @template = new_template("hello \xFCmlat", :virtual_path => nil) + @template = new_template("hello \xFCmlat", virtual_path: nil) render end - assert_match(/\xFC/, e.message) + # Hack: We write the regexp this way because the parser of RuboCop + # errs with /\xFC/. + assert_match(Regexp.new("\xFC"), e.message) end def with_external_encoding(encoding) diff --git a/actionview/test/template/test_case_test.rb b/actionview/test/template/test_case_test.rb index d69d5819b6..41225000f0 100644 --- a/actionview/test/template/test_case_test.rb +++ b/actionview/test/template/test_case_test.rb @@ -1,20 +1,19 @@ -require 'abstract_unit' -require 'rails/engine' +require "abstract_unit" +require "rails/engine" module ActionView - module ATestHelper end module AnotherTestHelper def from_another_helper - 'Howdy!' + "Howdy!" end end module ASharedTestHelper def from_shared_helper - 'Holla!' + "Holla!" end end @@ -26,8 +25,8 @@ module ActionView def self.included(test_case) test_case.class_eval do test "helpers defined on ActionView::TestCase are available" do - assert test_case.ancestors.include?(ASharedTestHelper) - assert_equal 'Holla!', from_shared_helper + assert_includes test_case.ancestors, ASharedTestHelper + assert_equal "Holla!", from_shared_helper end end end @@ -55,18 +54,18 @@ module ActionView end test "works without testing a helper module" do - assert_equal 'Eloy', render('developers/developer', :developer => DeveloperStruct.new('Eloy')) + assert_equal "Eloy", render("developers/developer", developer: DeveloperStruct.new("Eloy")) end test "can render a layout with block" do assert_equal "Before (ChrisCruft)\n!\nAfter", - render(:layout => "test/layout_for_partial", :locals => {:name => "ChrisCruft"}) {"!"} + render(layout: "test/layout_for_partial", locals: { name: "ChrisCruft" }) { "!" } end helper AnotherTestHelper test "additional helper classes can be specified as in a controller" do - assert test_case.ancestors.include?(AnotherTestHelper) - assert_equal 'Howdy!', from_another_helper + assert_includes test_case.ancestors, AnotherTestHelper + assert_equal "Howdy!", from_another_helper end test "determine_default_helper_class returns nil if the test name constant resolves to a class" do @@ -86,7 +85,7 @@ module ActionView end test "uses controller lookup context" do - assert_equal self.lookup_context, @controller.lookup_context + assert_equal lookup_context, @controller.lookup_context end end @@ -97,44 +96,44 @@ module ActionView tests ATestHelper test "tests the specified helper module" do assert_equal ATestHelper, test_case.helper_class - assert test_case.ancestors.include?(ATestHelper) + assert_includes test_case.ancestors, ATestHelper end helper AnotherTestHelper test "additional helper classes can be specified as in a controller" do - assert test_case.ancestors.include?(AnotherTestHelper) - assert_equal 'Howdy!', from_another_helper + assert_includes test_case.ancestors, AnotherTestHelper + assert_equal "Howdy!", from_another_helper test_case.helper_class.module_eval do def render_from_helper from_another_helper end end - assert_equal 'Howdy!', render(:partial => 'test/from_helper') + assert_equal "Howdy!", render(partial: "test/from_helper") end end class HelperInclusionTest < ActionView::TestCase module RenderHelper def render_from_helper - render :partial => 'customer', :collection => @customers + render partial: "customer", collection: @customers end end helper RenderHelper test "helper class that is being tested is always included in view instance" do - @controller.controller_path = 'test' + @controller.controller_path = "test" - @customers = [DeveloperStruct.new('Eloy'), DeveloperStruct.new('Manfred')] - assert_match(/Hello: EloyHello: Manfred/, render(:partial => 'test/from_helper')) + @customers = [DeveloperStruct.new("Eloy"), DeveloperStruct.new("Manfred")] + assert_match(/Hello: EloyHello: Manfred/, render(partial: "test/from_helper")) end end class ControllerHelperMethod < ActionView::TestCase module SomeHelper def some_method - render :partial => 'test/from_helper' + render partial: "test/from_helper" end end @@ -148,21 +147,21 @@ module ActionView EOF @controller.class.helper_method :render_from_helper - assert_equal 'controller_helper_method', some_method + assert_equal "controller_helper_method", some_method end end class ViewAssignsTest < ActionView::TestCase test "view_assigns returns a Hash of user defined ivars" do - @a = 'b' - @c = 'd' - assert_equal({:a => 'b', :c => 'd'}, view_assigns) + @a = "b" + @c = "d" + assert_equal({ a: "b", c: "d" }, view_assigns) end test "view_assigns excludes internal ivars" do INTERNAL_IVARS.each do |ivar| assert defined?(ivar), "expected #{ivar} to be defined" - assert !view_assigns.keys.include?(ivar.to_s.tr('@', '').to_sym), "expected #{ivar} to be excluded from view_assigns" + assert_not_includes view_assigns.keys, ivar.to_s.tr("@", "").to_sym, "expected #{ivar} to be excluded from view_assigns" end end end @@ -174,10 +173,10 @@ module ActionView end end) test "is able to make methods available to the view" do - assert_equal 'Word!', render(:partial => 'test/from_helper') + assert_equal "Word!", render(partial: "test/from_helper") end - def from_test_case; 'Word!'; end + def from_test_case; "Word!"; end helper_method :from_test_case end @@ -193,7 +192,6 @@ module ActionView test "protect_from_forgery? in any helpers returns false" do assert !view.help_me end - end class ATestHelperTest < ActionView::TestCase @@ -202,30 +200,30 @@ module ActionView test "inflects the name of the helper module to test from the test case class" do assert_equal ATestHelper, test_case.helper_class - assert test_case.ancestors.include?(ATestHelper) + assert_includes test_case.ancestors, ATestHelper end test "a configured test controller is available" do assert_kind_of ActionController::Base, controller - assert_equal '', controller.controller_path + assert_equal "", controller.controller_path end test "no additional helpers should shared across test cases" do - assert !test_case.ancestors.include?(AnotherTestHelper) + assert_not_includes test_case.ancestors, AnotherTestHelper assert_raise(NoMethodError) { send :from_another_helper } end test "is able to use routes" do - controller.request.assign_parameters(@routes, 'foo', 'index', {}, '/foo', []) - assert_equal '/foo', url_for - assert_equal '/bar', url_for(:controller => 'bar') + controller.request.assign_parameters(@routes, "foo", "index", {}, "/foo", []) + assert_equal "/foo", url_for + assert_equal "/bar", url_for(controller: "bar") end test "is able to use named routes" do with_routing do |set| set.draw { resources :contents } - assert_equal 'http://test.host/contents/new', new_content_url - assert_equal 'http://test.host/contents/1', content_url(:id => 1) + assert_equal "http://test.host/contents/new", new_content_url + assert_equal "http://test.host/contents/1", content_url(id: 1) end end @@ -236,7 +234,7 @@ module ActionView @routes ||= ActionDispatch::Routing::RouteSet.new end - routes.draw { get "bar", :to => lambda {} } + routes.draw { get "bar", to: lambda {} } def self.call(*) end @@ -244,7 +242,7 @@ module ActionView set.draw { mount app => "/foo", :as => "foo_app" } - assert_equal '/foo/bar', foo_app.bar_path + assert_equal "/foo/bar", foo_app.bar_path end end @@ -257,21 +255,21 @@ module ActionView end end - assert_equal 'http://test.host/contents/new', render(:partial => 'test/from_helper') + assert_equal "http://test.host/contents/new", render(partial: "test/from_helper") end end test "is able to render partials with local variables" do - assert_equal 'Eloy', render('developers/developer', :developer => DeveloperStruct.new('Eloy')) - assert_equal 'Eloy', render(:partial => 'developers/developer', - :locals => { :developer => DeveloperStruct.new('Eloy') }) + assert_equal "Eloy", render("developers/developer", developer: DeveloperStruct.new("Eloy")) + assert_equal "Eloy", render(partial: "developers/developer", + locals: { developer: DeveloperStruct.new("Eloy") }) end test "is able to render partials from templates and also use instance variables" do @controller.controller_path = "test" - @customers = [DeveloperStruct.new('Eloy'), DeveloperStruct.new('Manfred')] - assert_match(/Hello: EloyHello: Manfred/, render(:file => 'test/list')) + @customers = [DeveloperStruct.new("Eloy"), DeveloperStruct.new("Manfred")] + assert_match(/Hello: EloyHello: Manfred/, render(file: "test/list")) end test "is able to render partials from templates and also use instance variables after view has been referenced" do @@ -279,37 +277,36 @@ module ActionView view - @customers = [DeveloperStruct.new('Eloy'), DeveloperStruct.new('Manfred')] - assert_match(/Hello: EloyHello: Manfred/, render(:file => 'test/list')) + @customers = [DeveloperStruct.new("Eloy"), DeveloperStruct.new("Manfred")] + assert_match(/Hello: EloyHello: Manfred/, render(file: "test/list")) end - end class AssertionsTest < ActionView::TestCase def render_from_helper - form_tag('/foo') do - safe_concat render(:text => '<ul><li>foo</li></ul>') + form_tag("/foo") do + safe_concat render(plain: "<ul><li>foo</li></ul>") end end helper_method :render_from_helper test "uses the output_buffer for assert_select" do - render(:partial => 'test/from_helper') + render(partial: "test/from_helper") - assert_select 'form' do - assert_select 'li', :text => 'foo' + assert_select "form" do + assert_select "li", text: "foo" end end test "do not memoize the document_root_element in view tests" do - concat form_tag('/foo') + concat form_tag("/foo") - assert_select 'form' + assert_select "form" - concat content_tag(:b, 'Strong', class: 'foo') + concat content_tag(:b, "Strong", class: "foo") - assert_select 'form' - assert_select 'b.foo' + assert_select "form" + assert_select "b.foo" end end diff --git a/actionview/test/template/test_test.rb b/actionview/test/template/test_test.rb index e1ff639979..52cac77bc5 100644 --- a/actionview/test/template/test_test.rb +++ b/actionview/test/template/test_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module PeopleHelper def title(text) @@ -41,7 +41,7 @@ class PeopleHelperTest < ActionView::TestCase extend ActiveModel::Naming def to_model; self; end def persisted?; true; end - def self.name; 'Minitest::Mock'; end + def self.name; "Minitest::Mock"; end }.new "David" the_model = nil @@ -60,7 +60,7 @@ class PeopleHelperTest < ActionView::TestCase def with_test_route_set with_routing do |set| set.draw do - get 'people', :to => 'people#index', :as => :people + get "people", to: "people#index", as: :people end yield end @@ -84,7 +84,7 @@ class CrazySymbolHelperTest < ActionView::TestCase end class CrazyStringHelperTest < ActionView::TestCase - tests 'people' + tests "people" def test_set_helper_class_using_string assert_equal PeopleHelper, self.class.helper_class diff --git a/actionview/test/template/testing/fixture_resolver_test.rb b/actionview/test/template/testing/fixture_resolver_test.rb index d6cfa997cd..effe453fc0 100644 --- a/actionview/test/template/testing/fixture_resolver_test.rb +++ b/actionview/test/template/testing/fixture_resolver_test.rb @@ -1,15 +1,15 @@ -require 'abstract_unit' +require "abstract_unit" class FixtureResolverTest < ActiveSupport::TestCase def test_should_return_empty_list_for_unknown_path resolver = ActionView::FixtureResolver.new() - templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :variants => [], :handlers => []}) + templates = resolver.find_all("path", "arbitrary", false, locale: [], formats: [:html], variants: [], handlers: []) assert_equal [], templates, "expected an empty list of templates" end def test_should_return_template_for_declared_path resolver = ActionView::FixtureResolver.new("arbitrary/path.erb" => "this text") - templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :variants => [], :handlers => [:erb]}) + templates = resolver.find_all("path", "arbitrary", false, locale: [], formats: [:html], variants: [], handlers: [:erb]) assert_equal 1, templates.size, "expected one template" assert_equal "this text", templates.first.source assert_equal "arbitrary/path", templates.first.virtual_path diff --git a/actionview/test/template/testing/null_resolver_test.rb b/actionview/test/template/testing/null_resolver_test.rb index 55ec36e753..5346fd3368 100644 --- a/actionview/test/template/testing/null_resolver_test.rb +++ b/actionview/test/template/testing/null_resolver_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' +require "abstract_unit" class NullResolverTest < ActiveSupport::TestCase def test_should_return_template_for_any_path resolver = ActionView::NullResolver.new() - templates = resolver.find_all("path.erb", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []}) + templates = resolver.find_all("path.erb", "arbitrary", false, locale: [], formats: [:html], handlers: []) assert_equal 1, templates.size, "expected one template" assert_equal "Template generated by Null Resolver", templates.first.source assert_equal "arbitrary/path.erb", templates.first.virtual_path.to_s diff --git a/actionview/test/template/text_helper_test.rb b/actionview/test/template/text_helper_test.rb index 03c7597505..fb557c24ac 100644 --- a/actionview/test/template/text_helper_test.rb +++ b/actionview/test/template/text_helper_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TextHelperTest < ActionView::TestCase tests ActionView::Helpers::TextHelper @@ -11,9 +11,9 @@ class TextHelperTest < ActionView::TestCase end def test_concat - self.output_buffer = 'foo' - assert_equal 'foobar', concat('bar') - assert_equal 'foobar', output_buffer + self.output_buffer = "foo" + assert_equal "foobar", concat("bar") + assert_equal "foobar", output_buffer end def test_simple_format_should_be_html_safe @@ -38,8 +38,8 @@ class TextHelperTest < ActionView::TestCase text = "A\r\n \nB\n\n\r\n\t\nC\nD".freeze assert_equal "<p>A\n<br /> \n<br />B</p>\n\n<p>\t\n<br />C\n<br />D</p>", simple_format(text) - assert_equal %q(<p class="test">This is a classy test</p>), simple_format("This is a classy test", :class => 'test') - assert_equal %Q(<p class="test">para 1</p>\n\n<p class="test">para 2</p>), simple_format("para 1\n\npara 2", :class => 'test') + assert_equal '<p class="test">This is a classy test</p>', simple_format("This is a classy test", class: "test") + assert_equal %Q(<p class="test">para 1</p>\n\n<p class="test">para 2</p>), simple_format("para 1\n\npara 2", class: "test") end def test_simple_format_should_sanitize_input_when_sanitize_option_is_not_false @@ -47,20 +47,20 @@ class TextHelperTest < ActionView::TestCase end def test_simple_format_should_sanitize_input_when_sanitize_option_is_true - assert_equal '<p><b> test with unsafe string </b>code!</p>', - simple_format('<b> test with unsafe string </b><script>code!</script>', {}, sanitize: true) + assert_equal "<p><b> test with unsafe string </b>code!</p>", + simple_format("<b> test with unsafe string </b><script>code!</script>", {}, sanitize: true) end def test_simple_format_should_not_sanitize_input_when_sanitize_option_is_false - assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, :sanitize => false) + assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, sanitize: false) end def test_simple_format_with_custom_wrapper - assert_equal "<div></div>", simple_format(nil, {}, :wrapper_tag => "div") + assert_equal "<div></div>", simple_format(nil, {}, wrapper_tag: "div") end def test_simple_format_with_custom_wrapper_and_multi_line_breaks - assert_equal "<div>We want to put a wrapper...</div>\n\n<div>...right there.</div>", simple_format("We want to put a wrapper...\n\n...right there.", {}, :wrapper_tag => "div") + assert_equal "<div>We want to put a wrapper...</div>\n\n<div>...right there.</div>", simple_format("We want to put a wrapper...\n\n...right there.", {}, wrapper_tag: "div") end def test_simple_format_should_not_change_the_text_passed @@ -71,22 +71,22 @@ class TextHelperTest < ActionView::TestCase end def test_simple_format_does_not_modify_the_html_options_hash - options = { :class => "foobar"} + options = { class: "foobar" } passed_options = options.dup simple_format("some text", passed_options) assert_equal options, passed_options end def test_simple_format_does_not_modify_the_options_hash - options = { :wrapper_tag => :div, :sanitize => false } + options = { wrapper_tag: :div, sanitize: false } passed_options = options.dup simple_format("some text", {}, passed_options) assert_equal options, passed_options end def test_truncate - assert_equal "Hello World!", truncate("Hello World!", :length => 12) - assert_equal "Hello Wor...", truncate("Hello World!!", :length => 12) + assert_equal "Hello World!", truncate("Hello World!", length: 12) + assert_equal "Hello Wor...", truncate("Hello World!!", length: 12) end def test_truncate_should_use_default_length_of_30 @@ -95,21 +95,21 @@ class TextHelperTest < ActionView::TestCase end def test_truncate_with_options_hash - assert_equal "This is a string that wil[...]", truncate("This is a string that will go longer then the default truncate length of 30", :omission => "[...]") - assert_equal "Hello W...", truncate("Hello World!", :length => 10) - assert_equal "Hello[...]", truncate("Hello World!", :omission => "[...]", :length => 10) - assert_equal "Hello[...]", truncate("Hello Big World!", :omission => "[...]", :length => 13, :separator => ' ') - assert_equal "Hello Big[...]", truncate("Hello Big World!", :omission => "[...]", :length => 14, :separator => ' ') - assert_equal "Hello Big[...]", truncate("Hello Big World!", :omission => "[...]", :length => 15, :separator => ' ') + assert_equal "This is a string that wil[...]", truncate("This is a string that will go longer then the default truncate length of 30", omission: "[...]") + assert_equal "Hello W...", truncate("Hello World!", length: 10) + assert_equal "Hello[...]", truncate("Hello World!", omission: "[...]", length: 10) + assert_equal "Hello[...]", truncate("Hello Big World!", omission: "[...]", length: 13, separator: " ") + assert_equal "Hello Big[...]", truncate("Hello Big World!", omission: "[...]", length: 14, separator: " ") + assert_equal "Hello Big[...]", truncate("Hello Big World!", omission: "[...]", length: 15, separator: " ") end def test_truncate_multibyte assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...".force_encoding(Encoding::UTF_8), - truncate("\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding(Encoding::UTF_8), :length => 10) + truncate("\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding(Encoding::UTF_8), length: 10) end def test_truncate_does_not_modify_the_options_hash - options = { :length => 10 } + options = { length: 10 } passed_options = options.dup truncate("some text", passed_options) assert_equal options, passed_options @@ -117,49 +117,49 @@ class TextHelperTest < ActionView::TestCase def test_truncate_with_link_options assert_equal "Here is a long test and ...<a href=\"#\">Continue</a>", - truncate("Here is a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + truncate("Here is a long test and I need a continue to read link", length: 27) { link_to "Continue", "#" } end def test_truncate_should_be_html_safe - assert truncate("Hello World!", :length => 12).html_safe? + assert truncate("Hello World!", length: 12).html_safe? end def test_truncate_should_escape_the_input - assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", :length => 12) + assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", length: 12) end def test_truncate_should_not_escape_the_input_with_escape_false - assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", :length => 12, :escape => false) + assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", length: 12, escape: false) end def test_truncate_with_escape_false_should_be_html_safe - truncated = truncate("Hello <script>code!</script>World!!", :length => 12, :escape => false) + truncated = truncate("Hello <script>code!</script>World!!", length: 12, escape: false) assert truncated.html_safe? end def test_truncate_with_block_should_be_html_safe - truncated = truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + truncated = truncate("Here's a long test and I need a continue to read link", length: 27) { link_to "Continue", "#" } assert truncated.html_safe? end def test_truncate_with_block_should_escape_the_input assert_equal "<script>code!</script>He...<a href=\"#\">Continue</a>", - truncate("<script>code!</script>Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + truncate("<script>code!</script>Here's a long test and I need a continue to read link", length: 27) { link_to "Continue", "#" } end def test_truncate_with_block_should_not_escape_the_input_with_escape_false assert_equal "<script>code!</script>He...<a href=\"#\">Continue</a>", - truncate("<script>code!</script>Here's a long test and I need a continue to read link", :length => 27, :escape => false) { link_to 'Continue', '#' } + truncate("<script>code!</script>Here's a long test and I need a continue to read link", length: 27, escape: false) { link_to "Continue", "#" } end def test_truncate_with_block_with_escape_false_should_be_html_safe - truncated = truncate("<script>code!</script>Here's a long test and I need a continue to read link", :length => 27, :escape => false) { link_to 'Continue', '#' } + truncated = truncate("<script>code!</script>Here's a long test and I need a continue to read link", length: 27, escape: false) { link_to "Continue", "#" } assert truncated.html_safe? end def test_truncate_with_block_should_escape_the_block assert_equal "Here is a long test and ...<script>alert('foo');</script>", - truncate("Here is a long test and I need a continue to read link", :length => 27) { "<script>alert('foo');</script>" } + truncate("Here is a long test and I need a continue to read link", length: 27) { "<script>alert('foo');</script>" } end def test_highlight_should_be_html_safe @@ -179,7 +179,7 @@ class TextHelperTest < ActionView::TestCase assert_equal( "This is a <b>beautiful</b> morning, but also a <b>beautiful</b> day", - highlight("This is a beautiful morning, but also a beautiful day", "beautiful", :highlighter => '<b>\1</b>') + highlight("This is a beautiful morning, but also a beautiful day", "beautiful", highlighter: '<b>\1</b>') ) assert_equal( @@ -189,11 +189,11 @@ class TextHelperTest < ActionView::TestCase end def test_highlight_pending - assert_equal ' ', highlight(' ', 'blank text is returned verbatim') + assert_equal " ", highlight(" ", "blank text is returned verbatim") end def test_highlight_should_return_blank_string_for_nil - assert_equal '', highlight(nil, 'blank string is returned for nil') + assert_equal "", highlight(nil, "blank string is returned for nil") end def test_highlight_should_sanitize_input @@ -206,7 +206,7 @@ class TextHelperTest < ActionView::TestCase def test_highlight_should_not_sanitize_if_sanitize_option_if_false assert_equal( "This is a <mark>beautiful</mark> morning<script>code!</script>", - highlight("This is a beautiful morning<script>code!</script>", "beautiful", :sanitize => false) + highlight("This is a beautiful morning<script>code!</script>", "beautiful", sanitize: false) ) end @@ -233,7 +233,7 @@ class TextHelperTest < ActionView::TestCase end def test_highlight_with_multiple_phrases_in_one_pass - assert_equal %(<em>wow</em> <em>em</em>), highlight('wow em', %w(wow em), :highlighter => '<em>\1</em>') + assert_equal %(<em>wow</em> <em>em</em>), highlight("wow em", %w(wow em), highlighter: '<em>\1</em>') end def test_highlight_with_html @@ -259,12 +259,12 @@ class TextHelperTest < ActionView::TestCase ) assert_equal( "<div>abc <b>div</b></div>", - highlight("<div>abc div</div>", "div", :highlighter => '<b>\1</b>') + highlight("<div>abc div</div>", "div", highlighter: '<b>\1</b>') ) end def test_highlight_does_not_modify_the_options_hash - options = { :highlighter => '<b>\1</b>', :sanitize => false } + options = { highlighter: '<b>\1</b>', sanitize: false } passed_options = options.dup highlight("<div>abc div</div>", "div", passed_options) assert_equal options, passed_options @@ -278,89 +278,89 @@ class TextHelperTest < ActionView::TestCase end def test_excerpt - assert_equal("...is a beautiful morn...", excerpt("This is a beautiful morning", "beautiful", :radius => 5)) - assert_equal("This is a...", excerpt("This is a beautiful morning", "this", :radius => 5)) - assert_equal("...iful morning", excerpt("This is a beautiful morning", "morning", :radius => 5)) + assert_equal("...is a beautiful morn...", excerpt("This is a beautiful morning", "beautiful", radius: 5)) + assert_equal("This is a...", excerpt("This is a beautiful morning", "this", radius: 5)) + assert_equal("...iful morning", excerpt("This is a beautiful morning", "morning", radius: 5)) assert_nil excerpt("This is a beautiful morning", "day") end def test_excerpt_with_regex - assert_equal('...is a beautiful! mor...', excerpt('This is a beautiful! morning', 'beautiful', :radius => 5)) - assert_equal('...is a beautiful? mor...', excerpt('This is a beautiful? morning', 'beautiful', :radius => 5)) - assert_equal('...is a beautiful? mor...', excerpt('This is a beautiful? morning', /\bbeau\w*\b/i, :radius => 5)) - assert_equal('...is a beautiful? mor...', excerpt('This is a beautiful? morning', /\b(beau\w*)\b/i, :radius => 5)) - assert_equal("...udge Allen and...", excerpt("This day was challenging for judge Allen and his colleagues.", /\ballen\b/i, :radius => 5)) - assert_equal("...judge Allen and...", excerpt("This day was challenging for judge Allen and his colleagues.", /\ballen\b/i, :radius => 1, :separator => ' ')) - assert_equal("...was challenging for...", excerpt("This day was challenging for judge Allen and his colleagues.", /\b(\w*allen\w*)\b/i, :radius => 5)) + assert_equal("...is a beautiful! mor...", excerpt("This is a beautiful! morning", "beautiful", radius: 5)) + assert_equal("...is a beautiful? mor...", excerpt("This is a beautiful? morning", "beautiful", radius: 5)) + assert_equal("...is a beautiful? mor...", excerpt("This is a beautiful? morning", /\bbeau\w*\b/i, radius: 5)) + assert_equal("...is a beautiful? mor...", excerpt("This is a beautiful? morning", /\b(beau\w*)\b/i, radius: 5)) + assert_equal("...udge Allen and...", excerpt("This day was challenging for judge Allen and his colleagues.", /\ballen\b/i, radius: 5)) + assert_equal("...judge Allen and...", excerpt("This day was challenging for judge Allen and his colleagues.", /\ballen\b/i, radius: 1, separator: " ")) + assert_equal("...was challenging for...", excerpt("This day was challenging for judge Allen and his colleagues.", /\b(\w*allen\w*)\b/i, radius: 5)) end def test_excerpt_should_not_be_html_safe - assert !excerpt('This is a beautiful! morning', 'beautiful', :radius => 5).html_safe? + assert !excerpt("This is a beautiful! morning", "beautiful", radius: 5).html_safe? end def test_excerpt_in_borderline_cases - assert_equal("", excerpt("", "", :radius => 0)) - assert_equal("a", excerpt("a", "a", :radius => 0)) - assert_equal("...b...", excerpt("abc", "b", :radius => 0)) - assert_equal("abc", excerpt("abc", "b", :radius => 1)) - assert_equal("abc...", excerpt("abcd", "b", :radius => 1)) - assert_equal("...abc", excerpt("zabc", "b", :radius => 1)) - assert_equal("...abc...", excerpt("zabcd", "b", :radius => 1)) - assert_equal("zabcd", excerpt("zabcd", "b", :radius => 2)) + assert_equal("", excerpt("", "", radius: 0)) + assert_equal("a", excerpt("a", "a", radius: 0)) + assert_equal("...b...", excerpt("abc", "b", radius: 0)) + assert_equal("abc", excerpt("abc", "b", radius: 1)) + assert_equal("abc...", excerpt("abcd", "b", radius: 1)) + assert_equal("...abc", excerpt("zabc", "b", radius: 1)) + assert_equal("...abc...", excerpt("zabcd", "b", radius: 1)) + assert_equal("zabcd", excerpt("zabcd", "b", radius: 2)) # excerpt strips the resulting string before ap-/prepending excerpt_string. # whether this behavior is meaningful when excerpt_string is not to be # appended is questionable. - assert_equal("zabcd", excerpt(" zabcd ", "b", :radius => 4)) - assert_equal("...abc...", excerpt("z abc d", "b", :radius => 1)) + assert_equal("zabcd", excerpt(" zabcd ", "b", radius: 4)) + assert_equal("...abc...", excerpt("z abc d", "b", radius: 1)) end def test_excerpt_with_omission - assert_equal("[...]is a beautiful morn[...]", excerpt("This is a beautiful morning", "beautiful", :omission => "[...]",:radius => 5)) + assert_equal("[...]is a beautiful morn[...]", excerpt("This is a beautiful morning", "beautiful", omission: "[...]",radius: 5)) assert_equal( "This is the ultimate supercalifragilisticexpialidoceous very looooooooooooooooooong looooooooooooong beautiful morning with amazing sunshine and awesome tempera[...]", excerpt("This is the ultimate supercalifragilisticexpialidoceous very looooooooooooooooooong looooooooooooong beautiful morning with amazing sunshine and awesome temperatures. So what are you gonna do about it?", "very", - :omission => "[...]") + omission: "[...]") ) end def test_excerpt_with_utf8 - assert_equal("...\357\254\203ciency could not be...".force_encoding(Encoding::UTF_8), excerpt("That's why e\357\254\203ciency could not be helped".force_encoding(Encoding::UTF_8), 'could', :radius => 8)) + assert_equal("...\357\254\203ciency could not be...".force_encoding(Encoding::UTF_8), excerpt("That's why e\357\254\203ciency could not be helped".force_encoding(Encoding::UTF_8), "could", radius: 8)) end def test_excerpt_does_not_modify_the_options_hash - options = { :omission => "[...]",:radius => 5 } + options = { omission: "[...]",radius: 5 } passed_options = options.dup excerpt("This is a beautiful morning", "beautiful", passed_options) assert_equal options, passed_options end def test_excerpt_with_separator - options = { :separator => ' ', :radius => 1 } - assert_equal('...a very beautiful...', excerpt('This is a very beautiful morning', 'very', options)) - assert_equal('This is...', excerpt('This is a very beautiful morning', 'this', options)) - assert_equal('...beautiful morning', excerpt('This is a very beautiful morning', 'morning', options)) + options = { separator: " ", radius: 1 } + assert_equal("...a very beautiful...", excerpt("This is a very beautiful morning", "very", options)) + assert_equal("This is...", excerpt("This is a very beautiful morning", "this", options)) + assert_equal("...beautiful morning", excerpt("This is a very beautiful morning", "morning", options)) - options = { :separator => "\n", :radius => 0 } - assert_equal("...very long...", excerpt("my very\nvery\nvery long\nstring", 'long', options)) + options = { separator: "\n", radius: 0 } + assert_equal("...very long...", excerpt("my very\nvery\nvery long\nstring", "long", options)) - options = { :separator => "\n", :radius => 1 } - assert_equal("...very\nvery long\nstring", excerpt("my very\nvery\nvery long\nstring", 'long', options)) + options = { separator: "\n", radius: 1 } + assert_equal("...very\nvery long\nstring", excerpt("my very\nvery\nvery long\nstring", "long", options)) - assert_equal excerpt('This is a beautiful morning', 'a'), - excerpt('This is a beautiful morning', 'a', separator: nil) + assert_equal excerpt("This is a beautiful morning", "a"), + excerpt("This is a beautiful morning", "a", separator: nil) end def test_word_wrap - assert_equal("my very very\nvery long\nstring", word_wrap("my very very very long string", :line_width => 15)) + assert_equal("my very very\nvery long\nstring", word_wrap("my very very very long string", line_width: 15)) end def test_word_wrap_with_extra_newlines - assert_equal("my very very\nvery long\nstring\n\nwith another\nline", word_wrap("my very very very long string\n\nwith another line", :line_width => 15)) + assert_equal("my very very\nvery long\nstring\n\nwith another\nline", word_wrap("my very very very long string\n\nwith another line", line_width: 15)) end def test_word_wrap_does_not_modify_the_options_hash - options = { :line_width => 15 } + options = { line_width: 15 } passed_options = options.dup word_wrap("some text", passed_options) assert_equal options, passed_options @@ -373,12 +373,14 @@ class TextHelperTest < ActionView::TestCase def test_pluralization assert_equal("1 count", pluralize(1, "count")) assert_equal("2 counts", pluralize(2, "count")) - assert_equal("1 count", pluralize('1', "count")) - assert_equal("2 counts", pluralize('2', "count")) - assert_equal("1,066 counts", pluralize('1,066', "count")) - assert_equal("1.25 counts", pluralize('1.25', "count")) - assert_equal("1.0 count", pluralize('1.0', "count")) - assert_equal("1.00 count", pluralize('1.00', "count")) + assert_equal("1 count", pluralize("1", "count")) + assert_equal("2 counts", pluralize("2", "count")) + assert_equal("1,066 counts", pluralize("1,066", "count")) + assert_equal("1.25 counts", pluralize("1.25", "count")) + assert_equal("1.0 count", pluralize("1.0", "count")) + assert_equal("1.00 count", pluralize("1.00", "count")) + assert_equal("2 counters", pluralize(2, "count", "counters")) + assert_equal("0 counters", pluralize(nil, "count", "counters")) assert_equal("2 counters", pluralize(2, "count", plural: "counters")) assert_equal("0 counters", pluralize(nil, "count", plural: "counters")) assert_equal("2 people", pluralize(2, "person")) @@ -394,7 +396,7 @@ class TextHelperTest < ActionView::TestCase I18n.locale = :de ActiveSupport::Inflector.inflections(:de) do |inflect| - inflect.irregular 'region', 'regionen' + inflect.irregular "region", "regionen" end assert_equal("1 region", pluralize(1, "region")) @@ -405,12 +407,6 @@ class TextHelperTest < ActionView::TestCase end end - def test_deprecated_plural_as_positional_argument - assert_deprecated do - pluralize(2, 'count', 'counters') - end - end - def test_cycle_class value = Cycle.new("one", 2, "3") assert_equal("one", value.to_s) @@ -458,12 +454,12 @@ class TextHelperTest < ActionView::TestCase end def test_named_cycles - assert_equal("1", cycle(1, 2, 3, :name => "numbers")) - assert_equal("red", cycle("red", "blue", :name => "colors")) - assert_equal("2", cycle(1, 2, 3, :name => "numbers")) - assert_equal("blue", cycle("red", "blue", :name => "colors")) - assert_equal("3", cycle(1, 2, 3, :name => "numbers")) - assert_equal("red", cycle("red", "blue", :name => "colors")) + assert_equal("1", cycle(1, 2, 3, name: "numbers")) + assert_equal("red", cycle("red", "blue", name: "colors")) + assert_equal("2", cycle(1, 2, 3, name: "numbers")) + assert_equal("blue", cycle("red", "blue", name: "colors")) + assert_equal("3", cycle(1, 2, 3, name: "numbers")) + assert_equal("red", cycle("red", "blue", name: "colors")) end def test_current_cycle_with_default_name @@ -476,11 +472,11 @@ class TextHelperTest < ActionView::TestCase end def test_current_cycle_with_named_cycles - cycle("red", "blue", :name => "colors") + cycle("red", "blue", name: "colors") assert_equal "red", current_cycle("colors") - cycle("red", "blue", :name => "colors") + cycle("red", "blue", name: "colors") assert_equal "blue", current_cycle("colors") - cycle("red", "blue", :name => "colors") + cycle("red", "blue", name: "colors") assert_equal "red", current_cycle("colors") end @@ -502,7 +498,7 @@ class TextHelperTest < ActionView::TestCase def test_default_named_cycle assert_equal("1", cycle(1, 2, 3)) - assert_equal("2", cycle(1, 2, 3, :name => "default")) + assert_equal("2", cycle(1, 2, 3, name: "default")) assert_equal("3", cycle(1, 2, 3)) end @@ -518,13 +514,13 @@ class TextHelperTest < ActionView::TestCase end def test_reset_named_cycle - assert_equal("1", cycle(1, 2, 3, :name => "numbers")) - assert_equal("red", cycle("red", "blue", :name => "colors")) + assert_equal("1", cycle(1, 2, 3, name: "numbers")) + assert_equal("red", cycle("red", "blue", name: "colors")) reset_cycle("numbers") - assert_equal("1", cycle(1, 2, 3, :name => "numbers")) - assert_equal("blue", cycle("red", "blue", :name => "colors")) - assert_equal("2", cycle(1, 2, 3, :name => "numbers")) - assert_equal("red", cycle("red", "blue", :name => "colors")) + assert_equal("1", cycle(1, 2, 3, name: "numbers")) + assert_equal("blue", cycle("red", "blue", name: "colors")) + assert_equal("2", cycle(1, 2, 3, name: "numbers")) + assert_equal("red", cycle("red", "blue", name: "colors")) end def test_cycle_no_instance_variable_clashes diff --git a/actionview/test/template/text_test.rb b/actionview/test/template/text_test.rb index d899d54589..6510688f97 100644 --- a/actionview/test/template/text_test.rb +++ b/actionview/test/template/text_test.rb @@ -1,17 +1,17 @@ -require 'abstract_unit' +require "abstract_unit" class TextTest < ActiveSupport::TestCase - test 'formats returns symbol for recognized MIME type' do - assert_equal [:text], ActionView::Template::Text.new('', :text).formats + test "formats returns symbol for recognized MIME type" do + assert_equal [:text], ActionView::Template::Text.new("", :text).formats end - test 'formats returns string for recognized MIME type when MIME does not have symbol' do + test "formats returns string for recognized MIME type when MIME does not have symbol" do foo = Mime::Type.lookup("foo") assert_nil foo.to_sym - assert_equal ['foo'], ActionView::Template::Text.new('', foo).formats + assert_equal ["foo"], ActionView::Template::Text.new("", foo).formats end - test 'formats returns string for unknown MIME type' do - assert_equal ['foo'], ActionView::Template::Text.new('', 'foo').formats + test "formats returns string for unknown MIME type" do + assert_equal ["foo"], ActionView::Template::Text.new("", "foo").formats end end diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb index 38b9284767..1cfc13f337 100644 --- a/actionview/test/template/translation_helper_test.rb +++ b/actionview/test/template/translation_helper_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' +require "abstract_unit" module I18n class CustomExceptionHandler def self.call(exception, locale, key, options) - 'from CustomExceptionHandler' + "from CustomExceptionHandler" end end end @@ -15,22 +15,22 @@ class TranslationHelperTest < ActiveSupport::TestCase setup do I18n.backend.store_translations(:en, - :translations => { - :templates => { - :found => { :foo => 'Foo' }, - :array => { :foo => { :bar => 'Foo Bar' } }, - :default => { :foo => 'Foo' } + translations: { + templates: { + found: { foo: "Foo" }, + array: { foo: { bar: "Foo Bar" } }, + default: { foo: "Foo" } }, - :foo => 'Foo', - :hello => '<a>Hello World</a>', - :html => '<a>Hello World</a>', - :hello_html => '<a>Hello World</a>', - :interpolated_html => '<a>Hello %{word}</a>', - :array_html => %w(foo bar), - :array => %w(foo bar), - :count_html => { - :one => '<a>One %{count}</a>', - :other => '<a>Other %{count}</a>' + foo: "Foo", + hello: "<a>Hello World</a>", + html: "<a>Hello World</a>", + hello_html: "<a>Hello World</a>", + interpolated_html: "<a>Hello %{word}</a>", + array_html: %w(foo bar), + array: %w(foo bar), + count_html: { + one: "<a>One %{count}</a>", + other: "<a>Other %{count}</a>" } } ) @@ -42,8 +42,8 @@ class TranslationHelperTest < ActiveSupport::TestCase end def test_delegates_setting_to_i18n - assert_called_with(I18n, :translate, [:foo, :locale => 'en', :raise => true], returns: "") do - translate :foo, :locale => 'en' + assert_called_with(I18n, :translate, [:foo, locale: "en", raise: true], returns: "") do + translate :foo, locale: "en" end end @@ -58,7 +58,7 @@ class TranslationHelperTest < ActiveSupport::TestCase old_value = ActionView::Base.debug_missing_translation ActionView::Base.debug_missing_translation = false - expected = 'translation missing: en.translations.missing' + expected = "translation missing: en.translations.missing" assert_equal expected, translate(:"translations.missing") ensure ActionView::Base.debug_missing_translation = old_value @@ -78,10 +78,10 @@ class TranslationHelperTest < ActiveSupport::TestCase def test_returns_missing_translation_message_does_filters_out_i18n_options expected = '<span class="translation_missing" title="translation missing: en.translations.missing, year: 2015">Missing</span>' - assert_equal expected, translate(:"translations.missing", year: '2015', default: []) + assert_equal expected, translate(:"translations.missing", year: "2015", default: []) expected = '<span class="translation_missing" title="translation missing: en.scoped.translations.missing, year: 2015">Missing</span>' - assert_equal expected, translate(:"translations.missing", year: '2015', scope: %i(scoped)) + assert_equal expected, translate(:"translations.missing", year: "2015", scope: %i(scoped)) end def test_raises_missing_translation_message_with_raise_config_option @@ -96,14 +96,14 @@ class TranslationHelperTest < ActiveSupport::TestCase def test_raises_missing_translation_message_with_raise_option assert_raise(I18n::MissingTranslationData) do - translate(:"translations.missing", :raise => true) + translate(:"translations.missing", raise: true) end end def test_uses_custom_exception_handler_when_specified old_exception_handler = I18n.exception_handler I18n.exception_handler = I18n::CustomExceptionHandler - assert_equal 'from CustomExceptionHandler', translate(:"translations.missing", raise: false) + assert_equal "from CustomExceptionHandler", translate(:"translations.missing", raise: false) ensure I18n.exception_handler = old_exception_handler end @@ -111,7 +111,7 @@ class TranslationHelperTest < ActiveSupport::TestCase def test_uses_custom_exception_handler_when_specified_for_html old_exception_handler = I18n.exception_handler I18n.exception_handler = I18n::CustomExceptionHandler - assert_equal 'from CustomExceptionHandler', translate(:"translations.missing_html", raise: false) + assert_equal "from CustomExceptionHandler", translate(:"translations.missing_html", raise: false) ensure I18n.exception_handler = old_exception_handler end @@ -122,20 +122,20 @@ class TranslationHelperTest < ActiveSupport::TestCase end def test_finds_translation_scoped_by_partial - assert_equal 'Foo', view.render(:file => 'translations/templates/found').strip + assert_equal "Foo", view.render(file: "translations/templates/found").strip end def test_finds_array_of_translations_scoped_by_partial - assert_equal 'Foo Bar', @view.render(:file => 'translations/templates/array').strip + assert_equal "Foo Bar", @view.render(file: "translations/templates/array").strip end def test_default_lookup_scoped_by_partial - assert_equal 'Foo', view.render(:file => 'translations/templates/default').strip + assert_equal "Foo", view.render(file: "translations/templates/default").strip end def test_missing_translation_scoped_by_partial expected = '<span class="translation_missing" title="translation missing: en.translations.templates.missing.missing">Missing</span>' - assert_equal expected, view.render(:file => 'translations/templates/missing').strip + assert_equal expected, view.render(file: "translations/templates/missing").strip end def test_translate_does_not_mark_plain_text_as_safe_html @@ -152,14 +152,14 @@ class TranslationHelperTest < ActiveSupport::TestCase def test_translate_escapes_interpolations_in_translations_with_a_html_suffix word_struct = Struct.new(:to_s) - assert_equal '<a>Hello <World></a>', translate(:'translations.interpolated_html', :word => '<World>') - assert_equal '<a>Hello <World></a>', translate(:'translations.interpolated_html', :word => word_struct.new("<World>")) + assert_equal "<a>Hello <World></a>", translate(:'translations.interpolated_html', word: "<World>") + assert_equal "<a>Hello <World></a>", translate(:'translations.interpolated_html', word: word_struct.new("<World>")) end def test_translate_with_html_count - assert_equal '<a>One 1</a>', translate(:'translations.count_html', :count => 1) - assert_equal '<a>Other 2</a>', translate(:'translations.count_html', :count => 2) - assert_equal '<a>Other <One></a>', translate(:'translations.count_html', :count => '<One>') + assert_equal "<a>One 1</a>", translate(:'translations.count_html', count: 1) + assert_equal "<a>Other 2</a>", translate(:'translations.count_html', count: 2) + assert_equal "<a>Other <One></a>", translate(:'translations.count_html', count: "<One>") end def test_translation_returning_an_array_ignores_html_suffix @@ -167,13 +167,13 @@ class TranslationHelperTest < ActiveSupport::TestCase end def test_translate_with_default_named_html - translation = translate(:'translations.missing', :default => :'translations.hello_html') - assert_equal '<a>Hello World</a>', translation + translation = translate(:'translations.missing', default: :'translations.hello_html') + assert_equal "<a>Hello World</a>", translation assert_equal true, translation.html_safe? end def test_translate_with_missing_default - translation = translate(:'translations.missing', :default => :'translations.missing_html') + translation = translate(:'translations.missing', default: :'translations.missing_html') expected = '<span class="translation_missing" title="translation missing: en.translations.missing_html">Missing Html</span>' assert_equal expected, translation assert_equal true, translation.html_safe? @@ -181,31 +181,31 @@ class TranslationHelperTest < ActiveSupport::TestCase def test_translate_with_missing_default_and_raise_option assert_raise(I18n::MissingTranslationData) do - translate(:'translations.missing', :default => :'translations.missing_html', :raise => true) + translate(:'translations.missing', default: :'translations.missing_html', raise: true) end end def test_translate_with_two_defaults_named_html - translation = translate(:'translations.missing', :default => [:'translations.missing_html', :'translations.hello_html']) - assert_equal '<a>Hello World</a>', translation + translation = translate(:'translations.missing', default: [:'translations.missing_html', :'translations.hello_html']) + assert_equal "<a>Hello World</a>", translation assert_equal true, translation.html_safe? end def test_translate_with_last_default_named_html - translation = translate(:'translations.missing', :default => [:'translations.missing', :'translations.hello_html']) - assert_equal '<a>Hello World</a>', translation + translation = translate(:'translations.missing', default: [:'translations.missing', :'translations.hello_html']) + assert_equal "<a>Hello World</a>", translation assert_equal true, translation.html_safe? end def test_translate_with_last_default_not_named_html - translation = translate(:'translations.missing', :default => [:'translations.missing_html', :'translations.foo']) - assert_equal 'Foo', translation + translation = translate(:'translations.missing', default: [:'translations.missing_html', :'translations.foo']) + assert_equal "Foo", translation assert_equal false, translation.html_safe? end def test_translate_with_string_default - translation = translate(:'translations.missing', default: 'A Generic String') - assert_equal 'A Generic String', translation + translation = translate(:'translations.missing', default: "A Generic String") + assert_equal "A Generic String", translation end def test_translate_with_object_default @@ -214,13 +214,13 @@ class TranslationHelperTest < ActiveSupport::TestCase end def test_translate_with_array_of_string_defaults - translation = translate(:'translations.missing', default: ['A Generic String', 'Second generic string']) - assert_equal 'A Generic String', translation + translation = translate(:'translations.missing', default: ["A Generic String", "Second generic string"]) + assert_equal "A Generic String", translation end def test_translate_with_array_of_defaults_with_nil - translation = translate(:'translations.missing', default: [:'also_missing', nil, 'A Generic String']) - assert_equal 'A Generic String', translation + translation = translate(:'translations.missing', default: [:'also_missing', nil, "A Generic String"]) + assert_equal "A Generic String", translation end def test_translate_with_array_of_array_default diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb index ab56d80de3..5a2319fe96 100644 --- a/actionview/test/template/url_helper_test.rb +++ b/actionview/test/template/url_helper_test.rb @@ -1,7 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" class UrlHelperTest < ActiveSupport::TestCase - # In a few cases, the helper proxies to 'controller' # or request. # @@ -43,59 +42,59 @@ class UrlHelperTest < ActiveSupport::TestCase end def test_url_for_with_back - referer = 'http://www.example.com/referer' + referer = "http://www.example.com/referer" @controller = Struct.new(:request).new(Struct.new(:env).new("HTTP_REFERER" => referer)) - assert_equal 'http://www.example.com/referer', url_for(:back) + assert_equal "http://www.example.com/referer", url_for(:back) end def test_url_for_with_back_and_no_referer @controller = Struct.new(:request).new(Struct.new(:env).new({})) - assert_equal 'javascript:history.back()', url_for(:back) + assert_equal "javascript:history.back()", url_for(:back) end def test_url_for_with_back_and_no_controller @controller = nil - assert_equal 'javascript:history.back()', url_for(:back) + assert_equal "javascript:history.back()", url_for(:back) end def test_url_for_with_back_and_javascript_referer - referer = 'javascript:alert(document.cookie)' + referer = "javascript:alert(document.cookie)" @controller = Struct.new(:request).new(Struct.new(:env).new("HTTP_REFERER" => referer)) - assert_equal 'javascript:history.back()', url_for(:back) + assert_equal "javascript:history.back()", url_for(:back) end def test_url_for_with_invalid_referer - referer = 'THIS IS NOT A URL' + referer = "THIS IS NOT A URL" @controller = Struct.new(:request).new(Struct.new(:env).new("HTTP_REFERER" => referer)) - assert_equal 'javascript:history.back()', url_for(:back) + assert_equal "javascript:history.back()", url_for(:back) end def test_to_form_params_with_hash assert_equal( - [{ name: :name, value: 'David' }, { name: :nationality, value: 'Danish' }], - to_form_params(name: 'David', nationality: 'Danish') + [{ name: :name, value: "David" }, { name: :nationality, value: "Danish" }], + to_form_params(name: "David", nationality: "Danish") ) end def test_to_form_params_with_nested_hash assert_equal( - [{ name: 'country[name]', value: 'Denmark' }], - to_form_params(country: { name: 'Denmark' }) + [{ name: "country[name]", value: "Denmark" }], + to_form_params(country: { name: "Denmark" }) ) end def test_to_form_params_with_array_nested_in_hash assert_equal( - [{ name: 'countries[]', value: 'Denmark' }, { name: 'countries[]', value: 'Sweden' }], - to_form_params(countries: ['Denmark', 'Sweden']) + [{ name: "countries[]", value: "Denmark" }, { name: "countries[]", value: "Sweden" }], + to_form_params(countries: ["Denmark", "Sweden"]) ) end def test_to_form_params_with_namespace assert_equal( - [{ name: 'country[name]', value: 'Denmark' }], - to_form_params({name: 'Denmark'}, 'country') + [{ name: "country[name]", value: "Denmark" }], + to_form_params({ name: "Denmark" }, "country") ) end @@ -122,11 +121,11 @@ class UrlHelperTest < ActiveSupport::TestCase end def test_button_to_with_form_class - assert_dom_equal %{<form method="post" action="http://www.example.com" class="custom-class"><input type="submit" value="Hello" /></form>}, button_to("Hello", "http://www.example.com", form_class: 'custom-class') + assert_dom_equal %{<form method="post" action="http://www.example.com" class="custom-class"><input type="submit" value="Hello" /></form>}, button_to("Hello", "http://www.example.com", form_class: "custom-class") end def test_button_to_with_form_class_escapes - assert_dom_equal %{<form method="post" action="http://www.example.com" class="<script>evil_js</script>"><input type="submit" value="Hello" /></form>}, button_to("Hello", "http://www.example.com", form_class: '<script>evil_js</script>') + assert_dom_equal %{<form method="post" action="http://www.example.com" class="<script>evil_js</script>"><input type="submit" value="Hello" /></form>}, button_to("Hello", "http://www.example.com", form_class: "<script>evil_js</script>") end def test_button_to_with_query @@ -211,7 +210,7 @@ class UrlHelperTest < ActiveSupport::TestCase def test_button_to_with_block assert_dom_equal( %{<form method="post" action="http://www.example.com" class="button_to"><button type="submit"><span>Hello</span></button></form>}, - button_to("http://www.example.com") { content_tag(:span, 'Hello') } + button_to("http://www.example.com") { content_tag(:span, "Hello") } ) end @@ -222,17 +221,44 @@ class UrlHelperTest < ActiveSupport::TestCase ) end + class FakeParams + def initialize(permitted = true) + @permitted = permitted + end + + def permitted? + @permitted + end + + def to_h + { foo: :bar, baz: "quux" } + end + end + + def test_button_to_with_permited_strong_params + assert_dom_equal( + %{<form action="http://www.example.com" class="button_to" method="post"><input type="submit" value="Hello" /><input type="hidden" name="baz" value="quux" /><input type="hidden" name="foo" value="bar" /></form>}, + button_to("Hello", "http://www.example.com", params: FakeParams.new) + ) + end + + def test_button_to_with_unpermited_strong_params + assert_raises(ArgumentError) do + button_to("Hello", "http://www.example.com", params: FakeParams.new(false)) + end + end + def test_button_to_with_nested_hash_params assert_dom_equal( %{<form action="http://www.example.com" class="button_to" method="post"><input type="submit" value="Hello" /><input type="hidden" name="foo[bar]" value="baz" /></form>}, - button_to("Hello", "http://www.example.com", params: { foo: { bar: 'baz' } }) + button_to("Hello", "http://www.example.com", params: { foo: { bar: "baz" } }) ) end def test_button_to_with_nested_array_params assert_dom_equal( %{<form action="http://www.example.com" class="button_to" method="post"><input type="submit" value="Hello" /><input type="hidden" name="foo[]" value="bar" /></form>}, - button_to("Hello", "http://www.example.com", params: { foo: ['bar'] }) + button_to("Hello", "http://www.example.com", params: { foo: ["bar"] }) ) end @@ -241,13 +267,13 @@ class UrlHelperTest < ActiveSupport::TestCase end def test_link_tag_without_host_option - assert_dom_equal(%{<a href="/">Test Link</a>}, link_to('Test Link', url_hash)) + assert_dom_equal(%{<a href="/">Test Link</a>}, link_to("Test Link", url_hash)) end def test_link_tag_with_host_option hash = hash_for(host: "www.example.com") expected = %{<a href="http://www.example.com/">Test Link</a>} - assert_dom_equal(expected, link_to('Test Link', hash)) + assert_dom_equal(expected, link_to("Test Link", hash)) end def test_link_tag_with_query @@ -261,15 +287,15 @@ class UrlHelperTest < ActiveSupport::TestCase end def test_link_tag_with_back - env = {"HTTP_REFERER" => "http://www.example.com/referer"} + env = { "HTTP_REFERER" => "http://www.example.com/referer" } @controller = Struct.new(:request).new(Struct.new(:env).new(env)) expected = %{<a href="#{env["HTTP_REFERER"]}">go back</a>} - assert_dom_equal expected, link_to('go back', :back) + assert_dom_equal expected, link_to("go back", :back) end def test_link_tag_with_back_and_no_referer @controller = Struct.new(:request).new(Struct.new(:env).new({})) - link = link_to('go back', :back) + link = link_to("go back", :back) assert_dom_equal %{<a href="javascript:history.back()">go back</a>}, link end @@ -329,7 +355,7 @@ class UrlHelperTest < ActiveSupport::TestCase def test_link_to_with_string_remote_in_non_html_options assert_dom_equal( %{<a href="/" data-remote="true">Hello</a>}, - link_to("Hello", hash_for('remote' => true), {}) + link_to("Hello", hash_for("remote" => true), {}) ) end @@ -350,14 +376,14 @@ class UrlHelperTest < ActiveSupport::TestCase def test_link_tag_using_delete_javascript_and_href assert_dom_equal( %{<a href="\#" rel="nofollow" data-method="delete">Destroy</a>}, - link_to("Destroy", "http://www.example.com", method: :delete, href: '#') + link_to("Destroy", "http://www.example.com", method: :delete, href: "#") ) end def test_link_tag_using_post_javascript_and_rel assert_dom_equal( %{<a href="http://www.example.com" data-method="post" rel="example nofollow">Hello</a>}, - link_to("Hello", "http://www.example.com", method: :post, rel: 'example') + link_to("Hello", "http://www.example.com", method: :post, rel: "example") ) end @@ -371,24 +397,24 @@ class UrlHelperTest < ActiveSupport::TestCase def test_link_tag_using_delete_javascript_and_href_and_confirm assert_dom_equal( %{<a href="\#" rel="nofollow" data-confirm="Are you serious?" data-method="delete">Destroy</a>}, - link_to("Destroy", "http://www.example.com", method: :delete, href: '#', data: { confirm: "Are you serious?" }) + link_to("Destroy", "http://www.example.com", method: :delete, href: "#", data: { confirm: "Are you serious?" }) ) end def test_link_tag_with_block assert_dom_equal %{<a href="/"><span>Example site</span></a>}, - link_to('/') { content_tag(:span, 'Example site') } + link_to("/") { content_tag(:span, "Example site") } end def test_link_tag_with_block_and_html_options assert_dom_equal %{<a class="special" href="/"><span>Example site</span></a>}, - link_to('/', class: "special") { content_tag(:span, 'Example site') } + link_to("/", class: "special") { content_tag(:span, "Example site") } end def test_link_tag_using_block_and_hash assert_dom_equal( %{<a href="/"><span>Example site</span></a>}, - link_to(url_hash) { content_tag(:span, 'Example site') } + link_to(url_hash) { content_tag(:span, "Example site") } ) end @@ -452,7 +478,7 @@ class UrlHelperTest < ActiveSupport::TestCase end def test_current_page_with_http_head_method - @request = request_for_url("/", :method => :head) + @request = request_for_url("/", method: :head) assert current_page?(url_hash) assert current_page?("http://www.example.com/") end @@ -480,19 +506,19 @@ class UrlHelperTest < ActiveSupport::TestCase def test_current_page_with_not_get_verb @request = request_for_url("/events", method: :post) - assert !current_page?('/events') + assert !current_page?("/events") end def test_current_page_with_escaped_params @request = request_for_url("/category/administra%c3%a7%c3%a3o") - assert current_page?(controller: 'foo', action: 'category', category: 'administração') + assert current_page?(controller: "foo", action: "category", category: "administração") end def test_current_page_with_escaped_params_with_different_encoding @request = request_for_url("/") @request.stub(:path, "/category/administra%c3%a7%c3%a3o".force_encoding(Encoding::ASCII_8BIT)) do - assert current_page?(:controller => 'foo', :action => 'category', category: 'administração') + assert current_page?(controller: "foo", action: "category", category: "administração") assert current_page?("http://www.example.com/category/administra%c3%a7%c3%a3o") end end @@ -500,7 +526,13 @@ class UrlHelperTest < ActiveSupport::TestCase def test_current_page_with_double_escaped_params @request = request_for_url("/category/administra%c3%a7%c3%a3o?callback_url=http%3a%2f%2fexample.com%2ffoo") - assert current_page?(controller: 'foo', action: 'category', category: 'administração', callback_url: 'http://example.com/foo') + assert current_page?(controller: "foo", action: "category", category: "administração", callback_url: "http://example.com/foo") + end + + def test_current_page_with_trailing_slash + @request = request_for_url("/posts") + + assert current_page?("/posts/") end def test_link_unless_current @@ -521,7 +553,7 @@ class UrlHelperTest < ActiveSupport::TestCase @request = request_for_url("/?order=desc&page=1") assert_equal "Showing", - link_to_unless_current("Showing", hash_for(order: 'desc', page: '1')) + link_to_unless_current("Showing", hash_for(order: "desc", page: "1")) assert_equal "Showing", link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=1") @@ -577,13 +609,13 @@ class UrlHelperTest < ActiveSupport::TestCase assert_dom_equal( %{<a href="mailto:me@example.com?body=This%20is%20the%20body%20of%20the%20message.&subject=This%20is%20an%20example%20email">My email</a>}, - mail_to("me@example.com", "My email", cc: '', bcc: '', subject: "This is an example email", body: "This is the body of the message.") + mail_to("me@example.com", "My email", cc: "", bcc: "", subject: "This is an example email", body: "This is the body of the message.") ) end def test_mail_to_with_img assert_dom_equal %{<a href="mailto:feedback@example.com"><img src="/feedback.png" /></a>}, - mail_to('feedback@example.com', raw('<img src="/feedback.png" />')) + mail_to("feedback@example.com", raw('<img src="/feedback.png" />')) end def test_mail_to_with_html_safe_string @@ -606,22 +638,22 @@ class UrlHelperTest < ActiveSupport::TestCase def test_mail_to_with_block assert_dom_equal %{<a href="mailto:me@example.com"><span>Email me</span></a>}, - mail_to('me@example.com') { content_tag(:span, 'Email me') } + mail_to("me@example.com") { content_tag(:span, "Email me") } end def test_mail_to_with_block_and_options assert_dom_equal %{<a class="special" href="mailto:me@example.com?cc=ccaddress%40example.com"><span>Email me</span></a>}, - mail_to('me@example.com', cc: "ccaddress@example.com", class: "special") { content_tag(:span, 'Email me') } + mail_to("me@example.com", cc: "ccaddress@example.com", class: "special") { content_tag(:span, "Email me") } end def test_mail_to_does_not_modify_html_options_hash - options = { class: 'special' } - mail_to 'me@example.com', 'ME!', options - assert_equal({ class: 'special' }, options) + options = { class: "special" } + mail_to "me@example.com", "ME!", options + assert_equal({ class: "special" }, options) end def protect_against_forgery? - self.request_forgery + request_forgery end def form_authenticity_token(*args) @@ -634,8 +666,8 @@ class UrlHelperTest < ActiveSupport::TestCase private def sort_query_string_params(uri) - path, qs = uri.split('?') - qs = qs.split('&').sort.join('&') if qs + path, qs = uri.split("?") + qs = qs.split("&").sort.join("&") if qs qs ? "#{path}?#{qs}" : path end end @@ -643,34 +675,34 @@ end class UrlHelperControllerTest < ActionController::TestCase class UrlHelperController < ActionController::Base test_routes do - get 'url_helper_controller_test/url_helper/show/:id', - to: 'url_helper_controller_test/url_helper#show', + get "url_helper_controller_test/url_helper/show/:id", + to: "url_helper_controller_test/url_helper#show", as: :show - get 'url_helper_controller_test/url_helper/profile/:name', - to: 'url_helper_controller_test/url_helper#show', + get "url_helper_controller_test/url_helper/profile/:name", + to: "url_helper_controller_test/url_helper#show", as: :profile - get 'url_helper_controller_test/url_helper/show_named_route', - to: 'url_helper_controller_test/url_helper#show_named_route', + get "url_helper_controller_test/url_helper/show_named_route", + to: "url_helper_controller_test/url_helper#show_named_route", as: :show_named_route ActiveSupport::Deprecation.silence do get "/:controller(/:action(/:id))" end - get 'url_helper_controller_test/url_helper/normalize_recall_params', + get "url_helper_controller_test/url_helper/normalize_recall_params", to: UrlHelperController.action(:normalize_recall), as: :normalize_recall_params - get '/url_helper_controller_test/url_helper/override_url_helper/default', - to: 'url_helper_controller_test/url_helper#override_url_helper', + get "/url_helper_controller_test/url_helper/override_url_helper/default", + to: "url_helper_controller_test/url_helper#override_url_helper", as: :override_url_helper end def show if params[:name] - render inline: 'ok' + render inline: "ok" else redirect_to profile_path(params[:id]) end @@ -685,23 +717,23 @@ class UrlHelperControllerTest < ActionController::TestCase end def nil_url_for - render inline: '<%= url_for(nil) %>' + render inline: "<%= url_for(nil) %>" end def normalize_recall_params - render inline: '<%= normalize_recall_params_path %>' + render inline: "<%= normalize_recall_params_path %>" end def recall_params_not_changed - render inline: '<%= url_for(action: :show_url_for) %>' + render inline: "<%= url_for(action: :show_url_for) %>" end def override_url_helper - render inline: '<%= override_url_helper_path %>' + render inline: "<%= override_url_helper_path %>" end def override_url_helper_path - '/url_helper_controller_test/url_helper/override_url_helper/override' + "/url_helper_controller_test/url_helper/override_url_helper/override" end helper_method :override_url_helper_path end @@ -710,58 +742,58 @@ class UrlHelperControllerTest < ActionController::TestCase def test_url_for_shows_only_path get :show_url_for - assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body + assert_equal "/url_helper_controller_test/url_helper/show_url_for", @response.body end def test_named_route_url_shows_host_and_path - get :show_named_route, params: { kind: 'url' } - assert_equal 'http://test.host/url_helper_controller_test/url_helper/show_named_route', + get :show_named_route, params: { kind: "url" } + assert_equal "http://test.host/url_helper_controller_test/url_helper/show_named_route", @response.body end def test_named_route_path_shows_only_path - get :show_named_route, params: { kind: 'path' } - assert_equal '/url_helper_controller_test/url_helper/show_named_route', @response.body + get :show_named_route, params: { kind: "path" } + assert_equal "/url_helper_controller_test/url_helper/show_named_route", @response.body end def test_url_for_nil_returns_current_path get :nil_url_for - assert_equal '/url_helper_controller_test/url_helper/nil_url_for', @response.body + assert_equal "/url_helper_controller_test/url_helper/nil_url_for", @response.body end def test_named_route_should_show_host_and_path_using_controller_default_url_options class << @controller def default_url_options - { host: 'testtwo.host' } + { host: "testtwo.host" } end end - get :show_named_route, params: { kind: 'url' } - assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body + get :show_named_route, params: { kind: "url" } + assert_equal "http://testtwo.host/url_helper_controller_test/url_helper/show_named_route", @response.body end def test_recall_params_should_be_normalized get :normalize_recall_params - assert_equal '/url_helper_controller_test/url_helper/normalize_recall_params', @response.body + assert_equal "/url_helper_controller_test/url_helper/normalize_recall_params", @response.body end def test_recall_params_should_not_be_changed get :recall_params_not_changed - assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body + assert_equal "/url_helper_controller_test/url_helper/show_url_for", @response.body end def test_recall_params_should_normalize_id - get :show, params: { id: '123' } + get :show, params: { id: "123" } assert_equal 302, @response.status - assert_equal 'http://test.host/url_helper_controller_test/url_helper/profile/123', @response.location + assert_equal "http://test.host/url_helper_controller_test/url_helper/profile/123", @response.location - get :show, params: { name: '123' } - assert_equal 'ok', @response.body + get :show, params: { name: "123" } + assert_equal "ok", @response.body end def test_url_helper_can_be_overridden get :override_url_helper - assert_equal '/url_helper_controller_test/url_helper/override_url_helper/override', @response.body + assert_equal "/url_helper_controller_test/url_helper/override_url_helper/override", @response.body end end diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md index 5e72c67aea..5e8d8cb5c9 100644 --- a/activejob/CHANGELOG.md +++ b/activejob/CHANGELOG.md @@ -1,2 +1,41 @@ +* Removed deprecated support to passing the adapter class to `.queue_adapter`. + + *Rafael Mendonça França* + +* Removed deprecated `#original_exception` in `ActiveJob::DeserializationError`. + + *Rafael Mendonça França* + +* Added instance variable `@queue` to JobWrapper. + + This will fix issues in [resque-scheduler](https://github.com/resque/resque-scheduler) `#job_to_hash` method, + so we can use `#enqueue_delayed_selection`, `#remove_delayed` method in resque-scheduler smoothly. + + *mu29* + +* Yield the job instance so you have access to things like `job.arguments` on the custom logic after retries fail. + + *DHH* + +* Added declarative exception handling via `ActiveJob::Base.retry_on` and `ActiveJob::Base.discard_on`. + + Examples: + + class RemoteServiceJob < ActiveJob::Base + retry_on CustomAppException # defaults to 3s wait, 5 attempts + retry_on AnotherCustomAppException, wait: ->(executions) { executions * 2 } + retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3 + retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10 + discard_on ActiveJob::DeserializationError + + def perform(*args) + # Might raise CustomAppException or AnotherCustomAppException for something domain specific + # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected + # Might raise Net::OpenTimeout when the remote service is down + end + end + + *DHH* + Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/activejob/CHANGELOG.md) for previous changes. diff --git a/activejob/Rakefile b/activejob/Rakefile index e47f17b740..3953116061 100644 --- a/activejob/Rakefile +++ b/activejob/Rakefile @@ -1,41 +1,41 @@ -require 'rake/testtask' +require "rake/testtask" #TODO: add qu back to the list after it support Rails 5.1 ACTIVEJOB_ADAPTERS = %w(async inline delayed_job que queue_classic resque sidekiq sneakers sucker_punch backburner test) ACTIVEJOB_ADAPTERS -= %w(queue_classic) if defined?(JRUBY_VERSION) task default: :test -task test: 'test:default' +task test: "test:default" task :package namespace :test do - desc 'Run all adapter tests' + desc "Run all adapter tests" task :default do run_without_aborting ACTIVEJOB_ADAPTERS.map { |a| "test:#{a}" } end - desc 'Run all adapter tests in isolation' + desc "Run all adapter tests in isolation" task :isolated do run_without_aborting ACTIVEJOB_ADAPTERS.map { |a| "test:isolated:#{a}" } end - desc 'Run integration tests for all adapters' + desc "Run integration tests for all adapters" task :integration do - run_without_aborting (ACTIVEJOB_ADAPTERS - ['test']).map { |a| "test:integration:#{a}" } + run_without_aborting (ACTIVEJOB_ADAPTERS - ["test"]).map { |a| "test:integration:#{a}" } end - task 'env:integration' do - ENV['AJ_INTEGRATION_TESTS'] = "1" + task "env:integration" do + ENV["AJ_INTEGRATION_TESTS"] = "1" end ACTIVEJOB_ADAPTERS.each do |adapter| - task("env:#{adapter}") { ENV['AJ_ADAPTER'] = adapter } + task("env:#{adapter}") { ENV["AJ_ADAPTER"] = adapter } Rake::TestTask.new(adapter => "test:env:#{adapter}") do |t| t.description = "Run adapter tests for #{adapter}" - t.libs << 'test' - t.test_files = FileList['test/cases/**/*_test.rb'] + t.libs << "test" + t.test_files = FileList["test/cases/**/*_test.rb"] t.verbose = true t.warning = false t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) @@ -45,16 +45,16 @@ namespace :test do task adapter => "test:env:#{adapter}" do dir = File.dirname(__FILE__) Dir.glob("#{dir}/test/cases/**/*_test.rb").all? do |file| - sh(Gem.ruby, '-w', "-I#{dir}/lib", "-I#{dir}/test", file) - end or raise 'Failures' + sh(Gem.ruby, "-w", "-I#{dir}/lib", "-I#{dir}/test", file) + end || raise("Failures") end end namespace :integration do - Rake::TestTask.new(adapter => ["test:env:#{adapter}", 'test:env:integration']) do |t| + Rake::TestTask.new(adapter => ["test:env:#{adapter}", "test:env:integration"]) do |t| t.description = "Run integration tests for #{adapter}" - t.libs << 'test' - t.test_files = FileList['test/integration/**/*_test.rb'] + t.libs << "test" + t.test_files = FileList["test/integration/**/*_test.rb"] t.verbose = true t.warning = false t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) diff --git a/activejob/activejob.gemspec b/activejob/activejob.gemspec index e97bb40abf..2547e91262 100644 --- a/activejob/activejob.gemspec +++ b/activejob/activejob.gemspec @@ -1,23 +1,23 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'activejob' + s.name = "activejob" s.version = version - s.summary = 'Job framework with pluggable queues.' - s.description = 'Declare job classes that can be run by a variety of queueing backends.' + s.summary = "Job framework with pluggable queues." + s.description = "Declare job classes that can be run by a variety of queueing backends." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.md', 'lib/**/*'] - s.require_path = 'lib' + s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.md", "lib/**/*"] + s.require_path = "lib" - s.add_dependency 'activesupport', version - s.add_dependency 'globalid', '>= 0.3.6' + s.add_dependency "activesupport", version + s.add_dependency "globalid", ">= 0.3.6" end diff --git a/activejob/lib/active_job.rb b/activejob/lib/active_job.rb index 4b9065cf50..20ca7085c6 100644 --- a/activejob/lib/active_job.rb +++ b/activejob/lib/active_job.rb @@ -21,10 +21,10 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'active_support' -require 'active_support/rails' -require 'active_job/version' -require 'global_id' +require "active_support" +require "active_support/rails" +require "active_job/version" +require "global_id" module ActiveJob extend ActiveSupport::Autoload diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb index a5c749e5e7..523a0e7f33 100644 --- a/activejob/lib/active_job/arguments.rb +++ b/activejob/lib/active_job/arguments.rb @@ -1,26 +1,14 @@ -require 'active_support/core_ext/hash' +require "active_support/core_ext/hash" module ActiveJob # Raised when an exception is raised during job arguments deserialization. # # Wraps the original exception raised as +cause+. class DeserializationError < StandardError - def initialize(e = nil) #:nodoc: - if e - ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ - "Exceptions will automatically capture the original exception.", caller) - end - + def initialize #:nodoc: super("Error while trying to deserialize arguments: #{$!.message}") set_backtrace $!.backtrace end - - # The original exception that was raised during deserialization of job - # arguments. - def original_exception - ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) - cause - end end # Raised when an unsupported argument type is set as a job argument. We @@ -34,8 +22,8 @@ module ActiveJob module Arguments extend self # :nodoc: - # Calls #uniq since Integer, Fixnum, and Bignum are all the same class on Ruby 2.4+ - TYPE_WHITELIST = [ NilClass, String, Integer, Fixnum, Bignum, Float, BigDecimal, TrueClass, FalseClass ].uniq + TYPE_WHITELIST = [ NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass ] + TYPE_WHITELIST.push(Fixnum, Bignum) unless 1.class == Integer # Serializes a set of arguments. Whitelisted types are returned # as-is. Arrays/Hashes are serialized element by element. @@ -55,11 +43,11 @@ module ActiveJob private # :nodoc: - GLOBALID_KEY = '_aj_globalid'.freeze + GLOBALID_KEY = "_aj_globalid".freeze # :nodoc: - SYMBOL_KEYS_KEY = '_aj_symbol_keys'.freeze + SYMBOL_KEYS_KEY = "_aj_symbol_keys".freeze # :nodoc: - WITH_INDIFFERENT_ACCESS_KEY = '_aj_hash_with_indifferent_access'.freeze + WITH_INDIFFERENT_ACCESS_KEY = "_aj_hash_with_indifferent_access".freeze private_constant :GLOBALID_KEY, :SYMBOL_KEYS_KEY, :WITH_INDIFFERENT_ACCESS_KEY def serialize_argument(argument) @@ -104,7 +92,7 @@ module ActiveJob end def serialized_global_id?(hash) - hash.size == 1 and hash.include?(GLOBALID_KEY) + hash.size == 1 && hash.include?(GLOBALID_KEY) end def deserialize_global_id(hash) diff --git a/activejob/lib/active_job/base.rb b/activejob/lib/active_job/base.rb index ff5c69ddc6..18e8641e50 100644 --- a/activejob/lib/active_job/base.rb +++ b/activejob/lib/active_job/base.rb @@ -1,12 +1,13 @@ -require 'active_job/core' -require 'active_job/queue_adapter' -require 'active_job/queue_name' -require 'active_job/queue_priority' -require 'active_job/enqueuing' -require 'active_job/execution' -require 'active_job/callbacks' -require 'active_job/logging' -require 'active_job/translation' +require "active_job/core" +require "active_job/queue_adapter" +require "active_job/queue_name" +require "active_job/queue_priority" +require "active_job/enqueuing" +require "active_job/execution" +require "active_job/callbacks" +require "active_job/exceptions" +require "active_job/logging" +require "active_job/translation" module ActiveJob #:nodoc: # = Active Job @@ -62,6 +63,7 @@ module ActiveJob #:nodoc: include Enqueuing include Execution include Callbacks + include Exceptions include Logging include Translation diff --git a/activejob/lib/active_job/callbacks.rb b/activejob/lib/active_job/callbacks.rb index b206522a60..d5b17de8b5 100644 --- a/activejob/lib/active_job/callbacks.rb +++ b/activejob/lib/active_job/callbacks.rb @@ -1,4 +1,4 @@ -require 'active_support/callbacks' +require "active_support/callbacks" module ActiveJob # = Active Job Callbacks diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb index f7f882c998..a338061766 100644 --- a/activejob/lib/active_job/core.rb +++ b/activejob/lib/active_job/core.rb @@ -24,6 +24,9 @@ module ActiveJob # ID optionally provided by adapter attr_accessor :provider_job_id + # Number of times this job has been executed (which increments on every retry, like after an exception). + attr_accessor :executions + # I18n.locale to be used during the job. attr_accessor :locale end @@ -33,7 +36,7 @@ module ActiveJob module ClassMethods # Creates a new job instance from a hash created with +serialize+ def deserialize(job_data) - job = job_data['job_class'].constantize.new + job = job_data["job_class"].constantize.new job.deserialize(job_data) job end @@ -68,18 +71,20 @@ module ActiveJob @job_id = SecureRandom.uuid @queue_name = self.class.queue_name @priority = self.class.priority + @executions = 0 end # Returns a hash with the job data that can safely be passed to the # queueing adapter. def serialize { - 'job_class' => self.class.name, - 'job_id' => job_id, - 'queue_name' => queue_name, - 'priority' => priority, - 'arguments' => serialize_arguments(arguments), - 'locale' => I18n.locale.to_s + "job_class" => self.class.name, + "job_id" => job_id, + "queue_name" => queue_name, + "priority" => priority, + "arguments" => serialize_arguments(arguments), + "executions" => executions, + "locale" => I18n.locale.to_s } end @@ -104,11 +109,13 @@ module ActiveJob # end # end def deserialize(job_data) - self.job_id = job_data['job_id'] - self.queue_name = job_data['queue_name'] - self.priority = job_data['priority'] - self.serialized_arguments = job_data['arguments'] - self.locale = job_data['locale'] || I18n.locale.to_s + self.job_id = job_data["job_id"] + self.provider_job_id = job_data["provider_job_id"] + self.queue_name = job_data["queue_name"] + self.priority = job_data["priority"] + self.serialized_arguments = job_data["arguments"] + self.executions = job_data["executions"] + self.locale = job_data["locale"] || I18n.locale.to_s end private diff --git a/activejob/lib/active_job/enqueuing.rb b/activejob/lib/active_job/enqueuing.rb index 9dc3c0fa57..18051a7d65 100644 --- a/activejob/lib/active_job/enqueuing.rb +++ b/activejob/lib/active_job/enqueuing.rb @@ -1,7 +1,7 @@ -require 'active_job/arguments' +require "active_job/arguments" module ActiveJob - # Provides behavior for enqueuing and retrying jobs. + # Provides behavior for enqueuing jobs. module Enqueuing extend ActiveSupport::Concern @@ -24,31 +24,6 @@ module ActiveJob end end - # Reschedules the job to be re-executed. This is useful in combination - # with the +rescue_from+ option. When you rescue an exception from your job - # you can ask Active Job to retry performing your job. - # - # ==== Options - # * <tt>:wait</tt> - Enqueues the job with the specified delay - # * <tt>:wait_until</tt> - Enqueues the job at the time specified - # * <tt>:queue</tt> - Enqueues the job on the specified queue - # * <tt>:priority</tt> - Enqueues the job with the specified priority - # - # ==== Examples - # - # class SiteScraperJob < ActiveJob::Base - # rescue_from(ErrorLoadingSite) do - # retry_job queue: :low_priority - # end - # - # def perform(*args) - # # raise ErrorLoadingSite if cannot scrape - # end - # end - def retry_job(options={}) - enqueue options - end - # Enqueues the job to be performed by the queue adapter. # # ==== Options @@ -70,8 +45,8 @@ module ActiveJob self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue] self.priority = options[:priority].to_i if options[:priority] run_callbacks :enqueue do - if self.scheduled_at - self.class.queue_adapter.enqueue_at self, self.scheduled_at + if scheduled_at + self.class.queue_adapter.enqueue_at self, scheduled_at else self.class.queue_adapter.enqueue self end diff --git a/activejob/lib/active_job/exceptions.rb b/activejob/lib/active_job/exceptions.rb new file mode 100644 index 0000000000..c759068f9e --- /dev/null +++ b/activejob/lib/active_job/exceptions.rb @@ -0,0 +1,122 @@ +require "active_support/core_ext/numeric/time" + +module ActiveJob + # Provides behavior for retrying and discarding jobs on exceptions. + module Exceptions + extend ActiveSupport::Concern + + module ClassMethods + # Catch the exception and reschedule job for re-execution after so many seconds, for a specific number of attempts. + # If the exception keeps getting raised beyond the specified number of attempts, the exception is allowed to + # bubble up to the underlying queuing system, which may have its own retry mechanism or place it in a + # holding queue for inspection. + # + # You can also pass a block that'll be invoked if the retry attempts fail for custom logic rather than letting + # the exception bubble up. This block is yielded with the job instance as the first and the error instance as the second parameter. + # + # ==== Options + # * <tt>:wait</tt> - Re-enqueues the job with a delay specified either in seconds (default: 3 seconds), + # as a computing proc that the number of executions so far as an argument, or as a symbol reference of + # <tt>:exponentially_longer</tt>, which applies the wait algorithm of <tt>(executions ** 4) + 2</tt> + # (first wait 3s, then 18s, then 83s, etc) + # * <tt>:attempts</tt> - Re-enqueues the job the specified number of times (default: 5 attempts) + # * <tt>:queue</tt> - Re-enqueues the job on a different queue + # * <tt>:priority</tt> - Re-enqueues the job with a different priority + # + # ==== Examples + # + # class RemoteServiceJob < ActiveJob::Base + # retry_on CustomAppException # defaults to 3s wait, 5 attempts + # retry_on AnotherCustomAppException, wait: ->(executions) { executions * 2 } + # retry_on(YetAnotherCustomAppException) do |job, exception| + # ExceptionNotifier.caught(exception) + # end + # retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3 + # retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10 + # + # def perform(*args) + # # Might raise CustomAppException, AnotherCustomAppException, or YetAnotherCustomAppException for something domain specific + # # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected + # # Might raise Net::OpenTimeout when the remote service is down + # end + # end + def retry_on(exception, wait: 3.seconds, attempts: 5, queue: nil, priority: nil) + rescue_from exception do |error| + if executions < attempts + logger.error "Retrying #{self.class} in #{wait} seconds, due to a #{exception}. The original exception was #{error.cause.inspect}." + retry_job wait: determine_delay(wait), queue: queue, priority: priority + else + if block_given? + yield self, exception + else + logger.error "Stopped retrying #{self.class} due to a #{exception}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}." + raise error + end + end + end + end + + # Discard the job with no attempts to retry, if the exception is raised. This is useful when the subject of the job, + # like an Active Record, is no longer available, and the job is thus no longer relevant. + # + # ==== Example + # + # class SearchIndexingJob < ActiveJob::Base + # discard_on ActiveJob::DeserializationError + # + # def perform(record) + # # Will raise ActiveJob::DeserializationError if the record can't be deserialized + # end + # end + def discard_on(exception) + rescue_from exception do |error| + logger.error "Discarded #{self.class} due to a #{exception}. The original exception was #{error.cause.inspect}." + end + end + end + + # Reschedules the job to be re-executed. This is useful in combination + # with the +rescue_from+ option. When you rescue an exception from your job + # you can ask Active Job to retry performing your job. + # + # ==== Options + # * <tt>:wait</tt> - Enqueues the job with the specified delay in seconds + # * <tt>:wait_until</tt> - Enqueues the job at the time specified + # * <tt>:queue</tt> - Enqueues the job on the specified queue + # * <tt>:priority</tt> - Enqueues the job with the specified priority + # + # ==== Examples + # + # class SiteScraperJob < ActiveJob::Base + # rescue_from(ErrorLoadingSite) do + # retry_job queue: :low_priority + # end + # + # def perform(*args) + # # raise ErrorLoadingSite if cannot scrape + # end + # end + def retry_job(options = {}) + enqueue options + end + + private + def determine_delay(seconds_or_duration_or_algorithm) + case seconds_or_duration_or_algorithm + when :exponentially_longer + (executions ** 4) + 2 + when ActiveSupport::Duration + duration = seconds_or_duration_or_algorithm + duration.to_i + when Integer + seconds = seconds_or_duration_or_algorithm + seconds + when Proc + algorithm = seconds_or_duration_or_algorithm + algorithm.call(executions) + else + raise "Couldn't determine a delay based on #{seconds_or_duration_or_algorithm.inspect}" + end + end + end +end diff --git a/activejob/lib/active_job/execution.rb b/activejob/lib/active_job/execution.rb index 4e4acfc2c2..94d30c8eaf 100644 --- a/activejob/lib/active_job/execution.rb +++ b/activejob/lib/active_job/execution.rb @@ -1,5 +1,5 @@ -require 'active_support/rescuable' -require 'active_job/arguments' +require "active_support/rescuable" +require "active_job/arguments" module ActiveJob module Execution @@ -31,6 +31,9 @@ module ActiveJob def perform_now deserialize_arguments_if_needed run_callbacks :perform do + # Guard against jobs that were persisted before we started counting executions by zeroing out nil counters + self.executions = (executions || 0) + 1 + perform(*arguments) end rescue => exception diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb index d5c7920131..aa97ab2e22 100644 --- a/activejob/lib/active_job/logging.rb +++ b/activejob/lib/active_job/logging.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/hash/transform_values' -require 'active_support/core_ext/string/filters' -require 'active_support/tagged_logging' -require 'active_support/logger' +require "active_support/core_ext/hash/transform_values" +require "active_support/core_ext/string/filters" +require "active_support/tagged_logging" +require "active_support/logger" module ActiveJob module Logging #:nodoc: @@ -18,7 +18,7 @@ module ActiveJob around_perform do |job, block, _| tag_logger(job.class.name, job.job_id) do - payload = {adapter: job.class.queue_adapter, job: job} + payload = { adapter: job.class.queue_adapter, job: job } ActiveSupport::Notifications.instrument("perform_start.active_job", payload.dup) ActiveSupport::Notifications.instrument("perform.active_job", payload) do block.call @@ -41,7 +41,7 @@ module ActiveJob def tag_logger(*tags) if logger.respond_to?(:tagged) tags.unshift "ActiveJob" unless logger_tagged_by_active_job? - logger.tagged(*tags){ yield } + logger.tagged(*tags) { yield } else yield end @@ -51,70 +51,70 @@ module ActiveJob logger.formatter.current_tags.include?("ActiveJob") end - class LogSubscriber < ActiveSupport::LogSubscriber #:nodoc: - def enqueue(event) - info do - job = event.payload[:job] - "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job) + class LogSubscriber < ActiveSupport::LogSubscriber #:nodoc: + def enqueue(event) + info do + job = event.payload[:job] + "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job) + end end - end - def enqueue_at(event) - info do - job = event.payload[:job] - "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job) + def enqueue_at(event) + info do + job = event.payload[:job] + "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job) + end end - end - def perform_start(event) - info do - job = event.payload[:job] - "Performing #{job.class.name} from #{queue_name(event)}" + args_info(job) + def perform_start(event) + info do + job = event.payload[:job] + "Performing #{job.class.name} from #{queue_name(event)}" + args_info(job) + end end - end - def perform(event) - info do - job = event.payload[:job] - "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2)}ms" + def perform(event) + info do + job = event.payload[:job] + "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2)}ms" + end end - end - private - def queue_name(event) - event.payload[:adapter].class.name.demodulize.remove('Adapter') + "(#{event.payload[:job].queue_name})" - end + private + def queue_name(event) + event.payload[:adapter].class.name.demodulize.remove("Adapter") + "(#{event.payload[:job].queue_name})" + end - def args_info(job) - if job.arguments.any? - ' with arguments: ' + - job.arguments.map { |arg| format(arg).inspect }.join(', ') - else - '' + def args_info(job) + if job.arguments.any? + " with arguments: " + + job.arguments.map { |arg| format(arg).inspect }.join(", ") + else + "" + end end - end - def format(arg) - case arg - when Hash - arg.transform_values { |value| format(value) } - when Array - arg.map { |value| format(value) } - when GlobalID::Identification - arg.to_global_id rescue arg - else - arg + def format(arg) + case arg + when Hash + arg.transform_values { |value| format(value) } + when Array + arg.map { |value| format(value) } + when GlobalID::Identification + arg.to_global_id rescue arg + else + arg + end end - end - def scheduled_at(event) - Time.at(event.payload[:job].scheduled_at).utc - end + def scheduled_at(event) + Time.at(event.payload[:job].scheduled_at).utc + end - def logger - ActiveJob::Base.logger - end - end + def logger + ActiveJob::Base.logger + end + end end end diff --git a/activejob/lib/active_job/queue_adapter.rb b/activejob/lib/active_job/queue_adapter.rb index 72e4ebf935..2e9f1e61be 100644 --- a/activejob/lib/active_job/queue_adapter.rb +++ b/activejob/lib/active_job/queue_adapter.rb @@ -1,6 +1,6 @@ -require 'active_job/queue_adapters/inline_adapter' -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/string/inflections' +require "active_job/queue_adapters/inline_adapter" +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/string/inflections" module ActiveJob # The <tt>ActiveJob::QueueAdapter</tt> module is used to load the @@ -30,34 +30,24 @@ module ActiveJob private - def interpret_adapter(name_or_adapter_or_class) - case name_or_adapter_or_class - when Symbol, String - ActiveJob::QueueAdapters.lookup(name_or_adapter_or_class).new - else - if queue_adapter?(name_or_adapter_or_class) - name_or_adapter_or_class - elsif queue_adapter_class?(name_or_adapter_or_class) - ActiveSupport::Deprecation.warn "Passing an adapter class is deprecated " \ - "and will be removed in Rails 5.1. Please pass an adapter name " \ - "(.queue_adapter = :#{name_or_adapter_or_class.name.demodulize.remove('Adapter').underscore}) " \ - "or an instance (.queue_adapter = #{name_or_adapter_or_class.name}.new) instead." - name_or_adapter_or_class.new + def interpret_adapter(name_or_adapter_or_class) + case name_or_adapter_or_class + when Symbol, String + ActiveJob::QueueAdapters.lookup(name_or_adapter_or_class).new else - raise ArgumentError + if queue_adapter?(name_or_adapter_or_class) + name_or_adapter_or_class + else + raise ArgumentError + end end end - end - - QUEUE_ADAPTER_METHODS = [:enqueue, :enqueue_at].freeze - def queue_adapter?(object) - QUEUE_ADAPTER_METHODS.all? { |meth| object.respond_to?(meth) } - end + QUEUE_ADAPTER_METHODS = [:enqueue, :enqueue_at].freeze - def queue_adapter_class?(object) - object.is_a?(Class) && QUEUE_ADAPTER_METHODS.all? { |meth| object.public_method_defined?(meth) } - end + def queue_adapter?(object) + QUEUE_ADAPTER_METHODS.all? { |meth| object.respond_to?(meth) } + end end end end diff --git a/activejob/lib/active_job/queue_adapters.rb b/activejob/lib/active_job/queue_adapters.rb index 71154d8785..c8eedb6156 100644 --- a/activejob/lib/active_job/queue_adapters.rb +++ b/activejob/lib/active_job/queue_adapters.rb @@ -8,7 +8,7 @@ module ActiveJob # * {Qu}[https://github.com/bkeepers/qu] # * {Que}[https://github.com/chanks/que] # * {queue_classic}[https://github.com/QueueClassic/queue_classic] - # * {Resque 1.x}[https://github.com/resque/resque/tree/1-x-stable] + # * {Resque}[https://github.com/resque/resque] # * {Sidekiq}[http://sidekiq.org] # * {Sneakers}[https://github.com/jondot/sneakers] # * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch] @@ -121,7 +121,7 @@ module ActiveJob autoload :SuckerPunchAdapter autoload :TestAdapter - ADAPTER = 'Adapter'.freeze + ADAPTER = "Adapter".freeze private_constant :ADAPTER class << self diff --git a/activejob/lib/active_job/queue_adapters/async_adapter.rb b/activejob/lib/active_job/queue_adapters/async_adapter.rb index 922bc4afce..e2bff9e646 100644 --- a/activejob/lib/active_job/queue_adapters/async_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/async_adapter.rb @@ -1,7 +1,7 @@ -require 'securerandom' -require 'concurrent/scheduled_task' -require 'concurrent/executor/thread_pool_executor' -require 'concurrent/utility/processor_counter' +require "securerandom" +require "concurrent/scheduled_task" +require "concurrent/executor/thread_pool_executor" +require "concurrent/utility/processor_counter" module ActiveJob module QueueAdapters diff --git a/activejob/lib/active_job/queue_adapters/backburner_adapter.rb b/activejob/lib/active_job/queue_adapters/backburner_adapter.rb index 17703e3e41..e3eccce62b 100644 --- a/activejob/lib/active_job/queue_adapters/backburner_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/backburner_adapter.rb @@ -1,4 +1,4 @@ -require 'backburner' +require "backburner" module ActiveJob module QueueAdapters diff --git a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb index 0a785fad3b..83ad2e767d 100644 --- a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb @@ -1,4 +1,4 @@ -require 'delayed_job' +require "delayed_job" module ActiveJob module QueueAdapters diff --git a/activejob/lib/active_job/queue_adapters/qu_adapter.rb b/activejob/lib/active_job/queue_adapters/qu_adapter.rb index 0e198922fc..20cc97ebc7 100644 --- a/activejob/lib/active_job/queue_adapters/qu_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/qu_adapter.rb @@ -1,4 +1,4 @@ -require 'qu' +require "qu" module ActiveJob module QueueAdapters @@ -20,7 +20,7 @@ module ActiveJob qu_job = Qu::Payload.new(klass: JobWrapper, args: [job.serialize]).tap do |payload| payload.instance_variable_set(:@queue, job.queue_name) end.push - + # qu_job can be nil depending on the configured backend job.provider_job_id = qu_job.id unless qu_job.nil? qu_job diff --git a/activejob/lib/active_job/queue_adapters/que_adapter.rb b/activejob/lib/active_job/queue_adapters/que_adapter.rb index ab13689747..0e698f0d79 100644 --- a/activejob/lib/active_job/queue_adapters/que_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/que_adapter.rb @@ -1,4 +1,4 @@ -require 'que' +require "que" module ActiveJob module QueueAdapters diff --git a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb index 0ee41407d8..1115eb88ae 100644 --- a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb @@ -1,4 +1,4 @@ -require 'queue_classic' +require "queue_classic" module ActiveJob module QueueAdapters @@ -26,9 +26,9 @@ module ActiveJob def enqueue_at(job, timestamp) #:nodoc: queue = build_queue(job.queue_name) unless queue.respond_to?(:enqueue_at) - raise NotImplementedError, 'To be able to schedule jobs with queue_classic ' \ - 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. ' \ - 'You can implement this yourself or you can use the queue_classic-later gem.' + raise NotImplementedError, "To be able to schedule jobs with queue_classic " \ + "the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. " \ + "You can implement this yourself or you can use the queue_classic-later gem." end qc_job = queue.enqueue_at(timestamp, "#{JobWrapper.name}.perform", job.serialize) job.provider_job_id = qc_job["id"] if qc_job.is_a?(Hash) diff --git a/activejob/lib/active_job/queue_adapters/resque_adapter.rb b/activejob/lib/active_job/queue_adapters/resque_adapter.rb index 417854afd8..2df157ef89 100644 --- a/activejob/lib/active_job/queue_adapters/resque_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/resque_adapter.rb @@ -1,12 +1,12 @@ -require 'resque' -require 'active_support/core_ext/enumerable' -require 'active_support/core_ext/array/access' +require "resque" +require "active_support/core_ext/enumerable" +require "active_support/core_ext/array/access" begin - require 'resque-scheduler' + require "resque-scheduler" rescue LoadError begin - require 'resque_scheduler' + require "resque_scheduler" rescue LoadError false end @@ -27,6 +27,7 @@ module ActiveJob # Rails.application.config.active_job.queue_adapter = :resque class ResqueAdapter def enqueue(job) #:nodoc: + JobWrapper.instance_variable_set(:@queue, job.queue_name) Resque.enqueue_to job.queue_name, JobWrapper, job.serialize end diff --git a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb index c321776bf5..895cc1f981 100644 --- a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb @@ -1,4 +1,4 @@ -require 'sidekiq' +require "sidekiq" module ActiveJob module QueueAdapters @@ -18,26 +18,26 @@ module ActiveJob def enqueue(job) #:nodoc: #Sidekiq::Client does not support symbols as keys job.provider_job_id = Sidekiq::Client.push \ - 'class' => JobWrapper, - 'wrapped' => job.class.to_s, - 'queue' => job.queue_name, - 'args' => [ job.serialize ] + "class" => JobWrapper, + "wrapped" => job.class.to_s, + "queue" => job.queue_name, + "args" => [ job.serialize ] end def enqueue_at(job, timestamp) #:nodoc: job.provider_job_id = Sidekiq::Client.push \ - 'class' => JobWrapper, - 'wrapped' => job.class.to_s, - 'queue' => job.queue_name, - 'args' => [ job.serialize ], - 'at' => timestamp + "class" => JobWrapper, + "wrapped" => job.class.to_s, + "queue" => job.queue_name, + "args" => [ job.serialize ], + "at" => timestamp end class JobWrapper #:nodoc: include Sidekiq::Worker def perform(job_data) - Base.execute job_data + Base.execute job_data.merge("provider_job_id" => jid) end end end diff --git a/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb b/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb index d78bdecdcb..f00acfc04a 100644 --- a/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/sneakers_adapter.rb @@ -1,5 +1,5 @@ -require 'sneakers' -require 'monitor' +require "sneakers" +require "monitor" module ActiveJob module QueueAdapters @@ -33,7 +33,7 @@ module ActiveJob class JobWrapper #:nodoc: include Sneakers::Worker - from_queue 'default' + from_queue "default" def work(msg) job_data = ActiveSupport::JSON.decode(msg) diff --git a/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb b/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb index 163c8eb212..dd59a79813 100644 --- a/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/sucker_punch_adapter.rb @@ -1,4 +1,4 @@ -require 'sucker_punch' +require "sucker_punch" module ActiveJob module QueueAdapters @@ -31,7 +31,7 @@ module ActiveJob delay = timestamp - Time.current.to_f JobWrapper.perform_in delay, job.serialize else - raise NotImplementedError, 'sucker_punch 1.0 does not support `enqueued_at`. Please upgrade to version ~> 2.0.0 to enable this behavior.' + raise NotImplementedError, "sucker_punch 1.0 does not support `enqueued_at`. Please upgrade to version ~> 2.0.0 to enable this behavior." end end diff --git a/activejob/lib/active_job/queue_adapters/test_adapter.rb b/activejob/lib/active_job/queue_adapters/test_adapter.rb index 9b7b7139f4..da042cfebf 100644 --- a/activejob/lib/active_job/queue_adapters/test_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/test_adapter.rb @@ -39,22 +39,22 @@ module ActiveJob private - def job_to_hash(job, extras = {}) - { job: job.class, args: job.serialize.fetch('arguments'), queue: job.queue_name }.merge!(extras) - end + def job_to_hash(job, extras = {}) + { job: job.class, args: job.serialize.fetch("arguments"), queue: job.queue_name }.merge!(extras) + end - def enqueue_or_perform(perform, job, job_data) - if perform - performed_jobs << job_data - Base.execute job.serialize - else - enqueued_jobs << job_data + def enqueue_or_perform(perform, job, job_data) + if perform + performed_jobs << job_data + Base.execute job.serialize + else + enqueued_jobs << job_data + end end - end - def filtered?(job) - filter && !Array(filter).include?(job.class) - end + def filtered?(job) + filter && !Array(filter).include?(job.class) + end end end end diff --git a/activejob/lib/active_job/queue_name.rb b/activejob/lib/active_job/queue_name.rb index 65786a49ff..143fac9888 100644 --- a/activejob/lib/active_job/queue_name.rb +++ b/activejob/lib/active_job/queue_name.rb @@ -36,7 +36,7 @@ module ActiveJob class_attribute :queue_name_delimiter, instance_accessor: false self.queue_name = default_queue_name - self.queue_name_delimiter = '_' # set default delimiter to '_' + self.queue_name_delimiter = "_" # set default delimiter to '_' end # Returns the name of the queue the job will be run on. @@ -46,6 +46,5 @@ module ActiveJob end @queue_name end - end end diff --git a/activejob/lib/active_job/queue_priority.rb b/activejob/lib/active_job/queue_priority.rb index 01d84910ff..a48e53b0ef 100644 --- a/activejob/lib/active_job/queue_priority.rb +++ b/activejob/lib/active_job/queue_priority.rb @@ -39,6 +39,5 @@ module ActiveJob end @priority end - end end diff --git a/activejob/lib/active_job/railtie.rb b/activejob/lib/active_job/railtie.rb index a47caa4a7e..e4198a40a5 100644 --- a/activejob/lib/active_job/railtie.rb +++ b/activejob/lib/active_job/railtie.rb @@ -1,12 +1,12 @@ -require 'global_id/railtie' -require 'active_job' +require "global_id/railtie" +require "active_job" module ActiveJob # = Active Job Railtie class Railtie < Rails::Railtie # :nodoc: config.active_job = ActiveSupport::OrderedOptions.new - initializer 'active_job.logger' do + initializer "active_job.logger" do ActiveSupport.on_load(:active_job) { self.logger = ::Rails.logger } end diff --git a/activejob/lib/active_job/test_case.rb b/activejob/lib/active_job/test_case.rb index d894a7b5cd..a5ec45e4a7 100644 --- a/activejob/lib/active_job/test_case.rb +++ b/activejob/lib/active_job/test_case.rb @@ -1,7 +1,9 @@ -require 'active_support/test_case' +require "active_support/test_case" module ActiveJob class TestCase < ActiveSupport::TestCase include ActiveJob::TestHelper + + ActiveSupport.run_load_hooks(:active_job_test_case, self) end end diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb index e16af1947f..1a8b3375ae 100644 --- a/activejob/lib/active_job/test_helper.rb +++ b/activejob/lib/active_job/test_helper.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/class/subclasses' -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/class/subclasses" +require "active_support/core_ext/hash/keys" module ActiveJob # Provides helper methods for testing Active Job @@ -11,7 +11,7 @@ module ActiveJob def before_setup # :nodoc: test_adapter = queue_adapter_for_test - @old_queue_adapters = (ActiveJob::Base.subclasses << ActiveJob::Base).select do |klass| + @old_queue_adapters = (ActiveJob::Base.descendants << ActiveJob::Base).select do |klass| # only override explicitly set adapters, a quirk of `class_attribute` klass.singleton_class.public_instance_methods(false).include?(:_queue_adapter) end.map do |klass| @@ -269,6 +269,25 @@ module ActiveJob instantiate_job(matching_job) end + # Performs all enqueued jobs in the duration of the block. + # + # def test_perform_enqueued_jobs + # perform_enqueued_jobs do + # MyJob.perform_later(1, 2, 3) + # end + # assert_performed_jobs 1 + # end + # + # This method also supports filtering. If the +:only+ option is specified, + # then only the listed job(s) will be performed. + # + # def test_perform_enqueued_jobs_with_only + # perform_enqueued_jobs(only: MyJob) do + # MyJob.perform_later(1, 2, 3) # will be performed + # HelloJob.perform_later(1, 2, 3) # will not be perfomed + # end + # assert_performed_jobs 1 + # end def perform_enqueued_jobs(only: nil) old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs @@ -286,6 +305,11 @@ module ActiveJob end end + # Accesses the queue_adapter set by ActiveJob::Base. + # + # def test_assert_job_has_custom_queue_adapter_set + # assert_instance_of CustomQueueAdapter, HelloJob.queue_adapter + # end def queue_adapter ActiveJob::Base.queue_adapter end diff --git a/activejob/lib/active_job/version.rb b/activejob/lib/active_job/version.rb index 971ba9fe0c..60b463817f 100644 --- a/activejob/lib/active_job/version.rb +++ b/activejob/lib/active_job/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActiveJob # Returns the version of the currently loaded Active Job as a <tt>Gem::Version</tt> diff --git a/activejob/lib/rails/generators/job/job_generator.rb b/activejob/lib/rails/generators/job/job_generator.rb index 6e43e4a269..97c11a9ea6 100644 --- a/activejob/lib/rails/generators/job/job_generator.rb +++ b/activejob/lib/rails/generators/job/job_generator.rb @@ -1,13 +1,13 @@ -require 'rails/generators/named_base' +require "rails/generators/named_base" module Rails # :nodoc: module Generators # :nodoc: class JobGenerator < Rails::Generators::NamedBase # :nodoc: - desc 'This generator creates an active job file at app/jobs' + desc "This generator creates an active job file at app/jobs" - class_option :queue, type: :string, default: 'default', desc: 'The queue name for the generated job' + class_option :queue, type: :string, default: "default", desc: "The queue name for the generated job" - check_class_collision suffix: 'Job' + check_class_collision suffix: "Job" hook_for :test_framework @@ -16,22 +16,22 @@ module Rails # :nodoc: end def create_job_file - template 'job.rb', File.join('app/jobs', class_path, "#{file_name}_job.rb") + template "job.rb", File.join("app/jobs", class_path, "#{file_name}_job.rb") in_root do if self.behavior == :invoke && !File.exist?(application_job_file_name) - template 'application_job.rb', application_job_file_name + template "application_job.rb", application_job_file_name end end end private def application_job_file_name - @application_job_file_name ||= if mountable_engine? - "app/jobs/#{namespaced_path}/application_job.rb" - else - 'app/jobs/application_job.rb' - end + @application_job_file_name ||= if mountable_engine? + "app/jobs/#{namespaced_path}/application_job.rb" + else + "app/jobs/application_job.rb" + end end end end diff --git a/activejob/lib/rails/generators/job/templates/application_job.rb b/activejob/lib/rails/generators/job/templates/application_job.rb index 0b113b950e..f93745a31a 100644 --- a/activejob/lib/rails/generators/job/templates/application_job.rb +++ b/activejob/lib/rails/generators/job/templates/application_job.rb @@ -1,4 +1,9 @@ <% module_namespacing do -%> class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError end <% end -%> diff --git a/activejob/test/adapters/backburner.rb b/activejob/test/adapters/backburner.rb index 65d05f850b..17ba07b802 100644 --- a/activejob/test/adapters/backburner.rb +++ b/activejob/test/adapters/backburner.rb @@ -1,3 +1,3 @@ -require 'support/backburner/inline' +require "support/backburner/inline" -ActiveJob::Base.queue_adapter = :backburner
\ No newline at end of file +ActiveJob::Base.queue_adapter = :backburner diff --git a/activejob/test/adapters/delayed_job.rb b/activejob/test/adapters/delayed_job.rb index afd9c9deb7..5f0ee2418c 100644 --- a/activejob/test/adapters/delayed_job.rb +++ b/activejob/test/adapters/delayed_job.rb @@ -4,4 +4,3 @@ $LOAD_PATH << File.dirname(__FILE__) + "/../support/delayed_job" Delayed::Worker.delay_jobs = false Delayed::Worker.backend = :test - diff --git a/activejob/test/adapters/inline.rb b/activejob/test/adapters/inline.rb index e0092552c4..24113dfa5a 100644 --- a/activejob/test/adapters/inline.rb +++ b/activejob/test/adapters/inline.rb @@ -1 +1 @@ -ActiveJob::Base.queue_adapter = :inline
\ No newline at end of file +ActiveJob::Base.queue_adapter = :inline diff --git a/activejob/test/adapters/qu.rb b/activejob/test/adapters/qu.rb index 7728c843b4..b89c504091 100644 --- a/activejob/test/adapters/qu.rb +++ b/activejob/test/adapters/qu.rb @@ -1,3 +1,3 @@ -require 'qu-immediate' +require "qu-immediate" ActiveJob::Base.queue_adapter = :qu diff --git a/activejob/test/adapters/que.rb b/activejob/test/adapters/que.rb index e6abc57457..0c49274a4e 100644 --- a/activejob/test/adapters/que.rb +++ b/activejob/test/adapters/que.rb @@ -1,4 +1,4 @@ -require 'support/que/inline' +require "support/que/inline" ActiveJob::Base.queue_adapter = :que Que.mode = :sync diff --git a/activejob/test/adapters/queue_classic.rb b/activejob/test/adapters/queue_classic.rb index ad5ced3cc2..e301a7ca96 100644 --- a/activejob/test/adapters/queue_classic.rb +++ b/activejob/test/adapters/queue_classic.rb @@ -1,2 +1,2 @@ -require 'support/queue_classic/inline' +require "support/queue_classic/inline" ActiveJob::Base.queue_adapter = :queue_classic diff --git a/activejob/test/adapters/sidekiq.rb b/activejob/test/adapters/sidekiq.rb index cd9d2034de..8036331ef1 100644 --- a/activejob/test/adapters/sidekiq.rb +++ b/activejob/test/adapters/sidekiq.rb @@ -1,2 +1,2 @@ -require 'sidekiq/testing/inline' +require "sidekiq/testing/inline" ActiveJob::Base.queue_adapter = :sidekiq diff --git a/activejob/test/adapters/sneakers.rb b/activejob/test/adapters/sneakers.rb index 204166a700..159c0d1906 100644 --- a/activejob/test/adapters/sneakers.rb +++ b/activejob/test/adapters/sneakers.rb @@ -1,2 +1,2 @@ -require 'support/sneakers/inline' +require "support/sneakers/inline" ActiveJob::Base.queue_adapter = :sneakers diff --git a/activejob/test/adapters/sucker_punch.rb b/activejob/test/adapters/sucker_punch.rb index d2d1712946..5661b6ee92 100644 --- a/activejob/test/adapters/sucker_punch.rb +++ b/activejob/test/adapters/sucker_punch.rb @@ -1,2 +1,2 @@ -require 'sucker_punch/testing/inline' +require "sucker_punch/testing/inline" ActiveJob::Base.queue_adapter = :sucker_punch diff --git a/activejob/test/cases/adapter_test.rb b/activejob/test/cases/adapter_test.rb index 6d75ae9a7c..caf5d44a5e 100644 --- a/activejob/test/cases/adapter_test.rb +++ b/activejob/test/cases/adapter_test.rb @@ -1,4 +1,4 @@ -require 'helper' +require "helper" class AdapterTest < ActiveSupport::TestCase test "should load #{ENV['AJ_ADAPTER']} adapter" do diff --git a/activejob/test/cases/argument_serialization_test.rb b/activejob/test/cases/argument_serialization_test.rb index 59dc3d7f78..7934d8e556 100644 --- a/activejob/test/cases/argument_serialization_test.rb +++ b/activejob/test/cases/argument_serialization_test.rb @@ -1,25 +1,25 @@ -require 'helper' -require 'active_job/arguments' -require 'models/person' -require 'active_support/core_ext/hash/indifferent_access' -require 'jobs/kwargs_job' +require "helper" +require "active_job/arguments" +require "models/person" +require "active_support/core_ext/hash/indifferent_access" +require "jobs/kwargs_job" class ArgumentSerializationTest < ActiveSupport::TestCase setup do - @person = Person.find('5') + @person = Person.find("5") end [ nil, 1, 1.0, 1_000_000_000_000_000_000_000, - 'a', true, false, BigDecimal.new(5), - [ 1, 'a' ], - { 'a' => 1 } + "a", true, false, BigDecimal.new(5), + [ 1, "a" ], + { "a" => 1 } ].each do |arg| - test "serializes #{arg.class} verbatim" do + test "serializes #{arg.class} - #{arg} verbatim" do assert_arguments_unchanged arg end end - [ :a, Object.new, self, Person.find('5').to_gid ].each do |arg| + [ :a, Object.new, self, Person.find("5").to_gid ].each do |arg| test "does not serialize #{arg.class}" do assert_raises ActiveJob::SerializationError do ActiveJob::Arguments.serialize [ arg ] @@ -31,22 +31,22 @@ class ArgumentSerializationTest < ActiveSupport::TestCase end end - test 'should convert records to Global IDs' do + test "should convert records to Global IDs" do assert_arguments_roundtrip [@person] end - test 'should dive deep into arrays and hashes' do + test "should dive deep into arrays and hashes" do assert_arguments_roundtrip [3, [@person]] - assert_arguments_roundtrip [{ 'a' => @person }] + assert_arguments_roundtrip [{ "a" => @person }] end - test 'should maintain string and symbol keys' do + test "should maintain string and symbol keys" do assert_arguments_roundtrip([a: 1, "b" => 2]) end - test 'should maintain hash with indifferent access' do + test "should maintain hash with indifferent access" do symbol_key = { a: 1 } - string_key = { 'a' => 1 } + string_key = { "a" => 1 } indifferent_access = { a: 1 }.with_indifferent_access assert_not_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([symbol_key]).first @@ -54,26 +54,26 @@ class ArgumentSerializationTest < ActiveSupport::TestCase assert_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([indifferent_access]).first end - test 'should disallow non-string/symbol hash keys' do + test "should disallow non-string/symbol hash keys" do assert_raises ActiveJob::SerializationError do ActiveJob::Arguments.serialize [ { 1 => 2 } ] end assert_raises ActiveJob::SerializationError do - ActiveJob::Arguments.serialize [ { :a => [{ 2 => 3 }] } ] + ActiveJob::Arguments.serialize [ { a: [{ 2 => 3 }] } ] end end - test 'should not allow reserved hash keys' do - ['_aj_globalid', :_aj_globalid, '_aj_symbol_keys', :_aj_symbol_keys, - '_aj_hash_with_indifferent_access', :_aj_hash_with_indifferent_access].each do |key| + test "should not allow reserved hash keys" do + ["_aj_globalid", :_aj_globalid, "_aj_symbol_keys", :_aj_symbol_keys, + "_aj_hash_with_indifferent_access", :_aj_hash_with_indifferent_access].each do |key| assert_raises ActiveJob::SerializationError do ActiveJob::Arguments.serialize [key => 1] end end end - test 'should not allow non-primitive objects' do + test "should not allow non-primitive objects" do assert_raises ActiveJob::SerializationError do ActiveJob::Arguments.serialize [Object.new] end @@ -83,17 +83,17 @@ class ArgumentSerializationTest < ActiveSupport::TestCase end end - test 'allows for keyword arguments' do + test "allows for keyword arguments" do KwargsJob.perform_later(argument: 2) assert_equal "Job with argument: 2", JobBuffer.last_value end - test 'raises a friendly SerializationError for records without ids' do + test "raises a friendly SerializationError for records without ids" do err = assert_raises ActiveJob::SerializationError do ActiveJob::Arguments.serialize [Person.new(nil)] end - assert_match 'Unable to serialize Person without an id.', err.message + assert_match "Unable to serialize Person without an id.", err.message end private diff --git a/activejob/test/cases/callbacks_test.rb b/activejob/test/cases/callbacks_test.rb index 9af2380767..8d1c9c3058 100644 --- a/activejob/test/cases/callbacks_test.rb +++ b/activejob/test/cases/callbacks_test.rb @@ -1,10 +1,10 @@ -require 'helper' -require 'jobs/callback_job' +require "helper" +require "jobs/callback_job" -require 'active_support/core_ext/object/inclusion' +require "active_support/core_ext/object/inclusion" class CallbacksTest < ActiveSupport::TestCase - test 'perform callbacks' do + test "perform callbacks" do performed_callback_job = CallbackJob.new("A-JOB-ID") performed_callback_job.perform_now assert "CallbackJob ran before_perform".in? performed_callback_job.history @@ -13,7 +13,7 @@ class CallbacksTest < ActiveSupport::TestCase assert "CallbackJob ran around_perform_stop".in? performed_callback_job.history end - test 'enqueue callbacks' do + test "enqueue callbacks" do enqueued_callback_job = CallbackJob.perform_later assert "CallbackJob ran before_enqueue".in? enqueued_callback_job.history assert "CallbackJob ran after_enqueue".in? enqueued_callback_job.history diff --git a/activejob/test/cases/exceptions_test.rb b/activejob/test/cases/exceptions_test.rb new file mode 100644 index 0000000000..dbe55f7430 --- /dev/null +++ b/activejob/test/cases/exceptions_test.rb @@ -0,0 +1,107 @@ +require "helper" +require "jobs/retry_job" + +class ExceptionsTest < ActiveJob::TestCase + setup do + JobBuffer.clear + skip if ActiveJob::Base.queue_adapter.is_a?(ActiveJob::QueueAdapters::InlineAdapter) + end + + test "successfully retry job throwing exception against defaults" do + perform_enqueued_jobs do + RetryJob.perform_later "DefaultsError", 5 + + assert_equal [ + "Raised DefaultsError for the 1st time", + "Raised DefaultsError for the 2nd time", + "Raised DefaultsError for the 3rd time", + "Raised DefaultsError for the 4th time", + "Successfully completed job" ], JobBuffer.values + end + end + + test "successfully retry job throwing exception against higher limit" do + perform_enqueued_jobs do + RetryJob.perform_later "ShortWaitTenAttemptsError", 9 + assert_equal 9, JobBuffer.values.count + end + end + + test "failed retry job when exception kept occurring against defaults" do + perform_enqueued_jobs do + begin + RetryJob.perform_later "DefaultsError", 6 + assert_equal "Raised DefaultsError for the 5th time", JobBuffer.last_value + rescue DefaultsError + pass + end + end + end + + test "failed retry job when exception kept occurring against higher limit" do + perform_enqueued_jobs do + begin + RetryJob.perform_later "ShortWaitTenAttemptsError", 11 + assert_equal "Raised ShortWaitTenAttemptsError for the 10th time", JobBuffer.last_value + rescue ShortWaitTenAttemptsError + pass + end + end + end + + test "discard job" do + perform_enqueued_jobs do + RetryJob.perform_later "DiscardableError", 2 + assert_equal "Raised DiscardableError for the 1st time", JobBuffer.last_value + end + end + + test "custom handling of job that exceeds retry attempts" do + perform_enqueued_jobs do + RetryJob.perform_later "CustomCatchError", 6 + assert_equal "Dealt with a job that failed to retry in a custom way after 6 attempts", JobBuffer.last_value + end + end + + test "long wait job" do + travel_to Time.now + + perform_enqueued_jobs do + assert_performed_with at: (Time.now + 3600.seconds).to_i do + RetryJob.perform_later "LongWaitError", 5 + end + end + end + + test "exponentially retrying job" do + travel_to Time.now + + perform_enqueued_jobs do + assert_performed_with at: (Time.now + 3.seconds).to_i do + assert_performed_with at: (Time.now + 18.seconds).to_i do + assert_performed_with at: (Time.now + 83.seconds).to_i do + assert_performed_with at: (Time.now + 258.seconds).to_i do + RetryJob.perform_later "ExponentialWaitTenAttemptsError", 5 + end + end + end + end + end + end + + test "custom wait retrying job" do + travel_to Time.now + + perform_enqueued_jobs do + assert_performed_with at: (Time.now + 2.seconds).to_i do + assert_performed_with at: (Time.now + 4.seconds).to_i do + assert_performed_with at: (Time.now + 6.seconds).to_i do + assert_performed_with at: (Time.now + 8.seconds).to_i do + RetryJob.perform_later "CustomWaitTenAttemptsError", 5 + end + end + end + end + end + end +end diff --git a/activejob/test/cases/job_serialization_test.rb b/activejob/test/cases/job_serialization_test.rb index fa94209889..3f2e300dfa 100644 --- a/activejob/test/cases/job_serialization_test.rb +++ b/activejob/test/cases/job_serialization_test.rb @@ -1,8 +1,8 @@ -require 'helper' -require 'jobs/gid_job' -require 'jobs/hello_job' -require 'models/person' -require 'json' +require "helper" +require "jobs/gid_job" +require "jobs/hello_job" +require "models/person" +require "json" class JobSerializationTest < ActiveSupport::TestCase setup do @@ -10,16 +10,16 @@ class JobSerializationTest < ActiveSupport::TestCase @person = Person.find(5) end - test 'serialize job with gid' do + test "serialize job with gid" do GidJob.perform_later @person assert_equal "Person with ID: 5", JobBuffer.last_value end - test 'serialize includes current locale' do - assert_equal 'en', HelloJob.new.serialize['locale'] + test "serialize includes current locale" do + assert_equal "en", HelloJob.new.serialize["locale"] end - test 'serialize and deserialize are symmetric' do + test "serialize and deserialize are symmetric" do # Round trip a job in memory only h1 = HelloJob.new h1.deserialize(h1.serialize) @@ -33,15 +33,15 @@ class JobSerializationTest < ActiveSupport::TestCase assert_equal h1.serialize, h2.serialize end - test 'deserialize sets locale' do + test "deserialize sets locale" do job = HelloJob.new - job.deserialize 'locale' => 'es' - assert_equal 'es', job.locale + job.deserialize "locale" => "es" + assert_equal "es", job.locale end - test 'deserialize sets default locale' do + test "deserialize sets default locale" do job = HelloJob.new job.deserialize({}) - assert_equal 'en', job.locale + assert_equal "en", job.locale end end diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb index bf8a66432a..954974b2a5 100644 --- a/activejob/test/cases/logging_test.rb +++ b/activejob/test/cases/logging_test.rb @@ -1,11 +1,11 @@ -require 'helper' +require "helper" require "active_support/log_subscriber/test_helper" -require 'active_support/core_ext/numeric/time' -require 'jobs/hello_job' -require 'jobs/logging_job' -require 'jobs/overridden_logging_job' -require 'jobs/nested_job' -require 'models/person' +require "active_support/core_ext/numeric/time" +require "jobs/hello_job" +require "jobs/logging_job" +require "jobs/overridden_logging_job" +require "jobs/nested_job" +require "models/person" class LoggingTest < ActiveSupport::TestCase include ActiveSupport::LogSubscriber::TestHelper diff --git a/activejob/test/cases/queue_adapter_test.rb b/activejob/test/cases/queue_adapter_test.rb index fb3fdc392f..f1e0cf78ad 100644 --- a/activejob/test/cases/queue_adapter_test.rb +++ b/activejob/test/cases/queue_adapter_test.rb @@ -1,4 +1,4 @@ -require 'helper' +require "helper" module ActiveJob module QueueAdapters @@ -15,25 +15,12 @@ module ActiveJob end class QueueAdapterTest < ActiveJob::TestCase - test 'should forbid nonsense arguments' do + test "should forbid nonsense arguments" do assert_raises(ArgumentError) { ActiveJob::Base.queue_adapter = Mutex } assert_raises(ArgumentError) { ActiveJob::Base.queue_adapter = Mutex.new } end - test 'should warn on passing an adapter class' do - klass = Class.new do - def self.name - 'fake' - end - - def enqueue(*); end - def enqueue_at(*); end - end - - assert_deprecated { ActiveJob::Base.queue_adapter = klass } - end - - test 'should allow overriding the queue_adapter at the child class level without affecting the parent or its sibling' do + test "should allow overriding the queue_adapter at the child class level without affecting the parent or its sibling" do base_queue_adapter = ActiveJob::Base.queue_adapter child_job_one = Class.new(ActiveJob::Base) diff --git a/activejob/test/cases/queue_naming_test.rb b/activejob/test/cases/queue_naming_test.rb index 898016a704..7777e557c9 100644 --- a/activejob/test/cases/queue_naming_test.rb +++ b/activejob/test/cases/queue_naming_test.rb @@ -1,14 +1,14 @@ -require 'helper' -require 'jobs/hello_job' -require 'jobs/logging_job' -require 'jobs/nested_job' +require "helper" +require "jobs/hello_job" +require "jobs/logging_job" +require "jobs/nested_job" class QueueNamingTest < ActiveSupport::TestCase - test 'name derived from base' do + test "name derived from base" do assert_equal "default", HelloJob.queue_name end - test 'uses given queue name job' do + test "uses given queue name job" do original_queue_name = HelloJob.queue_name begin @@ -19,7 +19,7 @@ class QueueNamingTest < ActiveSupport::TestCase end end - test 'allows a blank queue name' do + test "allows a blank queue name" do original_queue_name = HelloJob.queue_name begin @@ -30,7 +30,7 @@ class QueueNamingTest < ActiveSupport::TestCase end end - test 'does not use a nil queue name' do + test "does not use a nil queue name" do original_queue_name = HelloJob.queue_name begin @@ -41,7 +41,7 @@ class QueueNamingTest < ActiveSupport::TestCase end end - test 'evals block given to queue_as to determine queue' do + test "evals block given to queue_as to determine queue" do original_queue_name = HelloJob.queue_name begin @@ -52,42 +52,42 @@ class QueueNamingTest < ActiveSupport::TestCase end end - test 'can use arguments to determine queue_name in queue_as block' do + test "can use arguments to determine queue_name in queue_as block" do original_queue_name = HelloJob.queue_name begin - HelloJob.queue_as { self.arguments.first=='1' ? :one : :two } - assert_equal "one", HelloJob.new('1').queue_name - assert_equal "two", HelloJob.new('3').queue_name + HelloJob.queue_as { self.arguments.first=="1" ? :one : :two } + assert_equal "one", HelloJob.new("1").queue_name + assert_equal "two", HelloJob.new("3").queue_name ensure HelloJob.queue_name = original_queue_name end end - test 'queue_name_prefix prepended to the queue name with default delimiter' do + test "queue_name_prefix prepended to the queue name with default delimiter" do original_queue_name_prefix = ActiveJob::Base.queue_name_prefix original_queue_name = HelloJob.queue_name begin - ActiveJob::Base.queue_name_prefix = 'aj' + ActiveJob::Base.queue_name_prefix = "aj" HelloJob.queue_as :low - assert_equal 'aj_low', HelloJob.queue_name + assert_equal "aj_low", HelloJob.queue_name ensure ActiveJob::Base.queue_name_prefix = original_queue_name_prefix HelloJob.queue_name = original_queue_name end end - test 'queue_name_prefix prepended to the queue name with custom delimiter' do + test "queue_name_prefix prepended to the queue name with custom delimiter" do original_queue_name_prefix = ActiveJob::Base.queue_name_prefix original_queue_name_delimiter = ActiveJob::Base.queue_name_delimiter original_queue_name = HelloJob.queue_name begin - ActiveJob::Base.queue_name_delimiter = '.' - ActiveJob::Base.queue_name_prefix = 'aj' + ActiveJob::Base.queue_name_delimiter = "." + ActiveJob::Base.queue_name_prefix = "aj" HelloJob.queue_as :low - assert_equal 'aj.low', HelloJob.queue_name + assert_equal "aj.low", HelloJob.queue_name ensure ActiveJob::Base.queue_name_prefix = original_queue_name_prefix ActiveJob::Base.queue_name_delimiter = original_queue_name_delimiter @@ -95,7 +95,7 @@ class QueueNamingTest < ActiveSupport::TestCase end end - test 'uses queue passed to #set' do + test "uses queue passed to #set" do job = HelloJob.set(queue: :some_queue).perform_later assert_equal "some_queue", job.queue_name end diff --git a/activejob/test/cases/queue_priority_test.rb b/activejob/test/cases/queue_priority_test.rb index ca17b51dad..ab4a1bdf7b 100644 --- a/activejob/test/cases/queue_priority_test.rb +++ b/activejob/test/cases/queue_priority_test.rb @@ -1,12 +1,12 @@ -require 'helper' -require 'jobs/hello_job' +require "helper" +require "jobs/hello_job" class QueuePriorityTest < ActiveSupport::TestCase - test 'priority unset by default' do + test "priority unset by default" do assert_equal nil, HelloJob.priority end - test 'uses given priority' do + test "uses given priority" do original_priority = HelloJob.priority begin @@ -17,7 +17,7 @@ class QueuePriorityTest < ActiveSupport::TestCase end end - test 'evals block given to priority to determine priority' do + test "evals block given to priority to determine priority" do original_priority = HelloJob.priority begin @@ -28,19 +28,19 @@ class QueuePriorityTest < ActiveSupport::TestCase end end - test 'can use arguments to determine priority in priority block' do + test "can use arguments to determine priority in priority block" do original_priority = HelloJob.priority begin - HelloJob.queue_with_priority { self.arguments.first=='1' ? 99 : 11 } - assert_equal 99, HelloJob.new('1').priority - assert_equal 11, HelloJob.new('3').priority + HelloJob.queue_with_priority { self.arguments.first=="1" ? 99 : 11 } + assert_equal 99, HelloJob.new("1").priority + assert_equal 11, HelloJob.new("3").priority ensure HelloJob.priority = original_priority end end - test 'uses priority passed to #set' do + test "uses priority passed to #set" do job = HelloJob.set(priority: 123).perform_later assert_equal 123, job.priority end diff --git a/activejob/test/cases/queuing_test.rb b/activejob/test/cases/queuing_test.rb index 0eeabbf693..a3ecb15c31 100644 --- a/activejob/test/cases/queuing_test.rb +++ b/activejob/test/cases/queuing_test.rb @@ -1,24 +1,23 @@ -require 'helper' -require 'jobs/hello_job' -require 'active_support/core_ext/numeric/time' - +require "helper" +require "jobs/hello_job" +require "active_support/core_ext/numeric/time" class QueuingTest < ActiveSupport::TestCase setup do JobBuffer.clear end - test 'run queued job' do + test "run queued job" do HelloJob.perform_later assert_equal "David says hello", JobBuffer.last_value end - test 'run queued job with arguments' do + test "run queued job with arguments" do HelloJob.perform_later "Jamie" assert_equal "Jamie says hello", JobBuffer.last_value end - test 'run queued job later' do + test "run queued job later" do begin result = HelloJob.set(wait_until: 1.second.ago).perform_later "Jamie" assert result @@ -27,13 +26,12 @@ class QueuingTest < ActiveSupport::TestCase end end - test 'job returned by enqueue has the arguments available' do + test "job returned by enqueue has the arguments available" do job = HelloJob.perform_later "Jamie" assert_equal [ "Jamie" ], job.arguments end - - test 'job returned by perform_at has the timestamp available' do + test "job returned by perform_at has the timestamp available" do begin job = HelloJob.set(wait_until: Time.utc(2014, 1, 1)).perform_later assert_equal Time.utc(2014, 1, 1).to_f, job.scheduled_at diff --git a/activejob/test/cases/rescue_test.rb b/activejob/test/cases/rescue_test.rb index 58c9ca8992..afb1b48831 100644 --- a/activejob/test/cases/rescue_test.rb +++ b/activejob/test/cases/rescue_test.rb @@ -1,34 +1,34 @@ -require 'helper' -require 'jobs/rescue_job' -require 'models/person' +require "helper" +require "jobs/rescue_job" +require "models/person" class RescueTest < ActiveSupport::TestCase setup do JobBuffer.clear end - test 'rescue perform exception with retry' do + test "rescue perform exception with retry" do job = RescueJob.new("david") job.perform_now assert_equal [ "rescued from ArgumentError", "performed beautifully" ], JobBuffer.values end - test 'let through unhandled perform exception' do + test "let through unhandled perform exception" do job = RescueJob.new("other") assert_raises(RescueJob::OtherError) do job.perform_now end end - test 'rescue from deserialization errors' do + test "rescue from deserialization errors" do RescueJob.perform_later Person.new(404) - assert_includes JobBuffer.values, 'rescued from DeserializationError' - assert_includes JobBuffer.values, 'DeserializationError original exception was Person::RecordNotFound' - assert_not_includes JobBuffer.values, 'performed beautifully' + assert_includes JobBuffer.values, "rescued from DeserializationError" + assert_includes JobBuffer.values, "DeserializationError original exception was Person::RecordNotFound" + assert_not_includes JobBuffer.values, "performed beautifully" end test "should not wrap DeserializationError in DeserializationError" do RescueJob.perform_later [Person.new(404)] - assert_includes JobBuffer.values, 'DeserializationError original exception was Person::RecordNotFound' + assert_includes JobBuffer.values, "DeserializationError original exception was Person::RecordNotFound" end end diff --git a/activejob/test/cases/test_case_test.rb b/activejob/test/cases/test_case_test.rb index 616454a4b6..3db2d9dec7 100644 --- a/activejob/test/cases/test_case_test.rb +++ b/activejob/test/cases/test_case_test.rb @@ -1,7 +1,7 @@ -require 'helper' -require 'jobs/hello_job' -require 'jobs/logging_job' -require 'jobs/nested_job' +require "helper" +require "jobs/hello_job" +require "jobs/logging_job" +require "jobs/nested_job" class ActiveJobTestCaseTest < ActiveJob::TestCase # this tests that this job class doesn't get its adapter set. @@ -9,7 +9,7 @@ class ActiveJobTestCaseTest < ActiveJob::TestCase # the `class_attribute` inheritance class TestClassAttributeInheritanceJob < ActiveJob::Base def self.queue_adapter=(*) - raise 'Attempting to break `class_attribute` inheritance, bad!' + raise "Attempting to break `class_attribute` inheritance, bad!" end end @@ -18,6 +18,6 @@ class ActiveJobTestCaseTest < ActiveJob::TestCase end def test_set_test_adapter - assert_kind_of ActiveJob::QueueAdapters::TestAdapter, self.queue_adapter + assert_kind_of ActiveJob::QueueAdapters::TestAdapter, queue_adapter end end diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb index 3d863f5e65..685c93da2d 100644 --- a/activejob/test/cases/test_helper_test.rb +++ b/activejob/test/cases/test_helper_test.rb @@ -1,17 +1,18 @@ -require 'helper' -require 'active_support/core_ext/time' -require 'active_support/core_ext/date' -require 'jobs/hello_job' -require 'jobs/logging_job' -require 'jobs/nested_job' -require 'jobs/rescue_job' -require 'models/person' +require "helper" +require "active_support/core_ext/time" +require "active_support/core_ext/date" +require "jobs/hello_job" +require "jobs/logging_job" +require "jobs/nested_job" +require "jobs/rescue_job" +require "jobs/inherited_job" +require "models/person" class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs assert_nothing_raised do assert_enqueued_jobs 1 do - HelloJob.perform_later('david') + HelloJob.perform_later("david") end end end @@ -19,23 +20,23 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_repeated_enqueued_jobs_calls assert_nothing_raised do assert_enqueued_jobs 1 do - HelloJob.perform_later('abdelkader') + HelloJob.perform_later("abdelkader") end end assert_nothing_raised do assert_enqueued_jobs 2 do - HelloJob.perform_later('sean') - HelloJob.perform_later('yves') + HelloJob.perform_later("sean") + HelloJob.perform_later("yves") end end end def test_assert_enqueued_jobs_message - HelloJob.perform_later('sean') + HelloJob.perform_later("sean") e = assert_raises Minitest::Assertion do assert_enqueued_jobs 2 do - HelloJob.perform_later('sean') + HelloJob.perform_later("sean") end end assert_match "Expected: 2", e.message @@ -44,13 +45,13 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs_with_no_block assert_nothing_raised do - HelloJob.perform_later('rafael') + HelloJob.perform_later("rafael") assert_enqueued_jobs 1 end assert_nothing_raised do - HelloJob.perform_later('aaron') - HelloJob.perform_later('matthew') + HelloJob.perform_later("aaron") + HelloJob.perform_later("matthew") assert_enqueued_jobs 3 end end @@ -72,7 +73,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs_too_few_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_enqueued_jobs 2 do - HelloJob.perform_later('xavier') + HelloJob.perform_later("xavier") end end @@ -82,8 +83,8 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs_too_many_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_enqueued_jobs 1 do - HelloJob.perform_later('cristian') - HelloJob.perform_later('guillermo') + HelloJob.perform_later("cristian") + HelloJob.perform_later("guillermo") end end @@ -93,7 +94,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_no_enqueued_jobs_failure error = assert_raise ActiveSupport::TestCase::Assertion do assert_no_enqueued_jobs do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") end end @@ -103,7 +104,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs_with_only_option assert_nothing_raised do assert_enqueued_jobs 1, only: HelloJob do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") LoggingJob.perform_later end end @@ -122,7 +123,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs_with_only_option_and_too_few_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_enqueued_jobs 5, only: HelloJob do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") 4.times { LoggingJob.perform_later } end end @@ -133,7 +134,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs_with_only_option_and_too_many_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_enqueued_jobs 1, only: HelloJob do - 2.times { HelloJob.perform_later('jeremy') } + 2.times { HelloJob.perform_later("jeremy") } end end @@ -143,9 +144,9 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_enqueued_jobs_with_only_option_as_array assert_nothing_raised do assert_enqueued_jobs 2, only: [HelloJob, LoggingJob] do - HelloJob.perform_later('jeremy') - LoggingJob.perform_later('stewie') - RescueJob.perform_later('david') + HelloJob.perform_later("jeremy") + LoggingJob.perform_later("stewie") + RescueJob.perform_later("david") end end end @@ -161,7 +162,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase def test_assert_no_enqueued_jobs_with_only_option_failure error = assert_raise ActiveSupport::TestCase::Assertion do assert_no_enqueued_jobs only: HelloJob do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") LoggingJob.perform_later end end @@ -178,7 +179,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase end def test_assert_enqueued_job - assert_enqueued_with(job: LoggingJob, queue: 'default') do + assert_enqueued_with(job: LoggingJob, queue: "default") do LoggingJob.set(wait_until: Date.tomorrow.noon).perform_later end end @@ -190,19 +191,19 @@ class EnqueuedJobsTest < ActiveJob::TestCase assert_instance_of LoggingJob, job assert_in_delta 5.minutes.from_now, job.scheduled_at, 1 - assert_equal 'default', job.queue_name + assert_equal "default", job.queue_name assert_equal [1, 2, 3], job.arguments end def test_assert_enqueued_job_failure assert_raise ActiveSupport::TestCase::Assertion do - assert_enqueued_with(job: LoggingJob, queue: 'default') do + assert_enqueued_with(job: LoggingJob, queue: "default") do NestedJob.perform_later end end error = assert_raise ActiveSupport::TestCase::Assertion do - assert_enqueued_with(job: NestedJob, queue: 'low') do + assert_enqueued_with(job: NestedJob, queue: "low") do NestedJob.perform_later end end @@ -249,7 +250,7 @@ class EnqueuedJobsTest < ActiveJob::TestCase HelloJob.perform_later end - assert_equal 2, ActiveJob::Base.queue_adapter.enqueued_jobs.count + assert_equal 2, queue_adapter.enqueued_jobs.count end end @@ -265,7 +266,7 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs assert_nothing_raised do assert_performed_jobs 1 do - HelloJob.perform_later('david') + HelloJob.perform_later("david") end end end @@ -273,23 +274,23 @@ class PerformedJobsTest < ActiveJob::TestCase def test_repeated_performed_jobs_calls assert_nothing_raised do assert_performed_jobs 1 do - HelloJob.perform_later('abdelkader') + HelloJob.perform_later("abdelkader") end end assert_nothing_raised do assert_performed_jobs 2 do - HelloJob.perform_later('sean') - HelloJob.perform_later('yves') + HelloJob.perform_later("sean") + HelloJob.perform_later("yves") end end end def test_assert_performed_jobs_message - HelloJob.perform_later('sean') + HelloJob.perform_later("sean") e = assert_raises Minitest::Assertion do assert_performed_jobs 2 do - HelloJob.perform_later('sean') + HelloJob.perform_later("sean") end end assert_match "Expected: 2", e.message @@ -299,15 +300,15 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs_with_no_block assert_nothing_raised do perform_enqueued_jobs do - HelloJob.perform_later('rafael') + HelloJob.perform_later("rafael") end assert_performed_jobs 1 end assert_nothing_raised do perform_enqueued_jobs do - HelloJob.perform_later('aaron') - HelloJob.perform_later('matthew') + HelloJob.perform_later("aaron") + HelloJob.perform_later("matthew") assert_performed_jobs 3 end end @@ -330,7 +331,7 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs_too_few_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_performed_jobs 2 do - HelloJob.perform_later('xavier') + HelloJob.perform_later("xavier") end end @@ -340,8 +341,8 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs_too_many_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_performed_jobs 1 do - HelloJob.perform_later('cristian') - HelloJob.perform_later('guillermo') + HelloJob.perform_later("cristian") + HelloJob.perform_later("guillermo") end end @@ -351,7 +352,7 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_no_performed_jobs_failure error = assert_raise ActiveSupport::TestCase::Assertion do assert_no_performed_jobs do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") end end @@ -361,7 +362,7 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs_with_only_option assert_nothing_raised do assert_performed_jobs 1, only: HelloJob do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") LoggingJob.perform_later end end @@ -370,9 +371,9 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs_with_only_option_as_array assert_nothing_raised do assert_performed_jobs 2, only: [HelloJob, LoggingJob] do - HelloJob.perform_later('jeremy') - LoggingJob.perform_later('stewie') - RescueJob.perform_later('david') + HelloJob.perform_later("jeremy") + LoggingJob.perform_later("stewie") + RescueJob.perform_later("david") end end end @@ -390,7 +391,7 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs_with_only_option_and_too_few_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_performed_jobs 5, only: HelloJob do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") 4.times { LoggingJob.perform_later } end end @@ -401,7 +402,7 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_performed_jobs_with_only_option_and_too_many_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_performed_jobs 1, only: HelloJob do - 2.times { HelloJob.perform_later('jeremy') } + 2.times { HelloJob.perform_later("jeremy") } end end @@ -427,7 +428,7 @@ class PerformedJobsTest < ActiveJob::TestCase def test_assert_no_performed_jobs_with_only_option_failure error = assert_raise ActiveSupport::TestCase::Assertion do assert_no_performed_jobs only: HelloJob do - HelloJob.perform_later('jeremy') + HelloJob.perform_later("jeremy") LoggingJob.perform_later end end @@ -436,20 +437,20 @@ class PerformedJobsTest < ActiveJob::TestCase end def test_assert_performed_job - assert_performed_with(job: NestedJob, queue: 'default') do + assert_performed_with(job: NestedJob, queue: "default") do NestedJob.perform_later end end def test_assert_performed_job_returns - job = assert_performed_with(job: NestedJob, queue: 'default') do + job = assert_performed_with(job: NestedJob, queue: "default") do NestedJob.perform_later end assert_instance_of NestedJob, job assert_nil job.scheduled_at assert_equal [], job.arguments - assert_equal 'default', job.queue_name + assert_equal "default", job.queue_name end def test_assert_performed_job_failure @@ -460,8 +461,8 @@ class PerformedJobsTest < ActiveJob::TestCase end assert_raise ActiveSupport::TestCase::Assertion do - assert_performed_with(job: HelloJob, queue: 'low') do - HelloJob.set(queue: 'important').perform_later + assert_performed_with(job: HelloJob, queue: "low") do + HelloJob.set(queue: "important").perform_later end end end @@ -506,7 +507,7 @@ class PerformedJobsTest < ActiveJob::TestCase HelloJob.perform_later end - assert_equal 2, ActiveJob::Base.queue_adapter.performed_jobs.count + assert_equal 2, queue_adapter.performed_jobs.count end end @@ -521,3 +522,9 @@ class OverrideQueueAdapterTest < ActiveJob::TestCase assert_instance_of CustomQueueAdapter, HelloJob.queue_adapter end end + +class InheritedJobTest < ActiveJob::TestCase + def test_queue_adapter_is_test_adapter + assert_instance_of ActiveJob::QueueAdapters::TestAdapter, InheritedJob.queue_adapter + end +end diff --git a/activejob/test/cases/translation_test.rb b/activejob/test/cases/translation_test.rb index d5e3aaf9e3..27bfd50985 100644 --- a/activejob/test/cases/translation_test.rb +++ b/activejob/test/cases/translation_test.rb @@ -1,18 +1,18 @@ -require 'helper' -require 'jobs/translated_hello_job' +require "helper" +require "jobs/translated_hello_job" class TranslationTest < ActiveSupport::TestCase setup do JobBuffer.clear I18n.available_locales = [:en, :de] - @job = TranslatedHelloJob.new('Johannes') + @job = TranslatedHelloJob.new("Johannes") end teardown do I18n.available_locales = [:en] end - test 'it performs the job in the given locale' do + test "it performs the job in the given locale" do @job.locale = :de @job.perform_now assert_equal "Johannes says Guten Tag", JobBuffer.last_value diff --git a/activejob/test/helper.rb b/activejob/test/helper.rb index 54b6076f09..dbc7dad109 100644 --- a/activejob/test/helper.rb +++ b/activejob/test/helper.rb @@ -1,16 +1,16 @@ -require 'active_job' -require 'support/job_buffer' +require "active_job" +require "support/job_buffer" ActiveSupport.halt_callback_chains_on_return_false = false -GlobalID.app = 'aj' +GlobalID.app = "aj" -@adapter = ENV['AJ_ADAPTER'] || 'inline' +@adapter = ENV["AJ_ADAPTER"] || "inline" -if ENV['AJ_INTEGRATION_TESTS'] - require 'support/integration/helper' +if ENV["AJ_INTEGRATION_TESTS"] + require "support/integration/helper" else ActiveJob::Base.logger = Logger.new(nil) require "adapters/#{@adapter}" end -require 'active_support/testing/autorun' +require "active_support/testing/autorun" diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb index 40f27500a5..2669c52a1c 100644 --- a/activejob/test/integration/queuing_test.rb +++ b/activejob/test/integration/queuing_test.rb @@ -1,16 +1,17 @@ -require 'helper' -require 'jobs/logging_job' -require 'jobs/hello_job' -require 'active_support/core_ext/numeric/time' +require "helper" +require "jobs/logging_job" +require "jobs/hello_job" +require "jobs/provider_jid_job" +require "active_support/core_ext/numeric/time" class QueuingTest < ActiveSupport::TestCase - test 'should run jobs enqueued on a listening queue' do + test "should run jobs enqueued on a listening queue" do TestJob.perform_later @id wait_for_jobs_to_finish_for(5.seconds) assert job_executed end - test 'should not run jobs queued on a non-listening queue' do + test "should not run jobs queued on a non-listening queue" do skip if adapter_is?(:inline, :async, :sucker_punch, :que) old_queue = TestJob.queue_name @@ -24,17 +25,32 @@ class QueuingTest < ActiveSupport::TestCase end end - test 'should supply a wrapped class name to Sidekiq' do + test "should supply a wrapped class name to Sidekiq" do skip unless adapter_is?(:sidekiq) Sidekiq::Testing.fake! do ::HelloJob.perform_later hash = ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper.jobs.first - assert_equal "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper", hash['class'] - assert_equal "HelloJob", hash['wrapped'] + assert_equal "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper", hash["class"] + assert_equal "HelloJob", hash["wrapped"] end end - test 'should not run job enqueued in the future' do + test "should access provider_job_id inside Sidekiq job" do + skip unless adapter_is?(:sidekiq) + Sidekiq::Testing.inline! do + job = ::ProviderJidJob.perform_later + assert_equal "Provider Job ID: #{job.provider_job_id}", JobBuffer.last_value + end + end + + test "resque JobWrapper should have instance variable queue" do + skip unless adapter_is?(:resque) + job = ::HelloJob.set(wait: 5.seconds).perform_later + hash = Resque.decode(Resque.find_delayed_selection { true }[0]) + assert_equal hash["queue"], job.queue_name + end + + test "should not run job enqueued in the future" do begin TestJob.set(wait: 10.minutes).perform_later @id wait_for_jobs_to_finish_for(5.seconds) @@ -44,7 +60,7 @@ class QueuingTest < ActiveSupport::TestCase end end - test 'should run job enqueued in the future at the specified time' do + test "should run job enqueued in the future at the specified time" do begin TestJob.set(wait: 5.seconds).perform_later @id wait_for_jobs_to_finish_for(2.seconds) @@ -56,19 +72,19 @@ class QueuingTest < ActiveSupport::TestCase end end - test 'should supply a provider_job_id when available for immediate jobs' do + test "should supply a provider_job_id when available for immediate jobs" do skip unless adapter_is?(:async, :delayed_job, :sidekiq, :qu, :que, :queue_classic) test_job = TestJob.perform_later @id - assert test_job.provider_job_id, 'Provider job id should be set by provider' + assert test_job.provider_job_id, "Provider job id should be set by provider" end - test 'should supply a provider_job_id when available for delayed jobs' do + test "should supply a provider_job_id when available for delayed jobs" do skip unless adapter_is?(:async, :delayed_job, :sidekiq, :que, :queue_classic) delayed_test_job = TestJob.set(wait: 1.minute).perform_later @id - assert delayed_test_job.provider_job_id, 'Provider job id should by set for delayed jobs by provider' + assert delayed_test_job.provider_job_id, "Provider job id should by set for delayed jobs by provider" end - test 'current locale is kept while running perform_later' do + test "current locale is kept while running perform_later" do skip if adapter_is?(:inline) begin @@ -78,14 +94,14 @@ class QueuingTest < ActiveSupport::TestCase TestJob.perform_later @id wait_for_jobs_to_finish_for(5.seconds) assert job_executed - assert_equal 'de', job_executed_in_locale + assert_equal "de", job_executed_in_locale ensure I18n.available_locales = [:en] I18n.locale = :en end end - test 'should run job with higher priority first' do + test "should run job with higher priority first" do skip unless adapter_is?(:delayed_job, :que) wait_until = Time.now + 3.seconds diff --git a/activejob/test/jobs/application_job.rb b/activejob/test/jobs/application_job.rb new file mode 100644 index 0000000000..4a78b890ec --- /dev/null +++ b/activejob/test/jobs/application_job.rb @@ -0,0 +1,4 @@ +require_relative "../support/job_buffer" + +class ApplicationJob < ActiveJob::Base +end diff --git a/activejob/test/jobs/callback_job.rb b/activejob/test/jobs/callback_job.rb index 891ed9464e..ca2a8e031a 100644 --- a/activejob/test/jobs/callback_job.rb +++ b/activejob/test/jobs/callback_job.rb @@ -17,7 +17,6 @@ class CallbackJob < ActiveJob::Base job.history << "CallbackJob ran around_enqueue_stop" end - def perform(person = "david") # NOTHING! end @@ -25,5 +24,4 @@ class CallbackJob < ActiveJob::Base def history @history ||= [] end - end diff --git a/activejob/test/jobs/gid_job.rb b/activejob/test/jobs/gid_job.rb index e485bfa2dd..c7cfa6e7a2 100644 --- a/activejob/test/jobs/gid_job.rb +++ b/activejob/test/jobs/gid_job.rb @@ -1,8 +1,7 @@ -require_relative '../support/job_buffer' +require_relative "../support/job_buffer" class GidJob < ActiveJob::Base def perform(person) JobBuffer.add("Person with ID: #{person.id}") end end - diff --git a/activejob/test/jobs/hello_job.rb b/activejob/test/jobs/hello_job.rb index 022fa58e4a..126fefae00 100644 --- a/activejob/test/jobs/hello_job.rb +++ b/activejob/test/jobs/hello_job.rb @@ -1,4 +1,4 @@ -require_relative '../support/job_buffer' +require_relative "../support/job_buffer" class HelloJob < ActiveJob::Base def perform(greeter = "David") diff --git a/activejob/test/jobs/inherited_job.rb b/activejob/test/jobs/inherited_job.rb new file mode 100644 index 0000000000..60fca66f88 --- /dev/null +++ b/activejob/test/jobs/inherited_job.rb @@ -0,0 +1,5 @@ +require_relative "application_job" + +class InheritedJob < ApplicationJob + self.queue_adapter = :inline +end diff --git a/activejob/test/jobs/kwargs_job.rb b/activejob/test/jobs/kwargs_job.rb index 2df17d15ae..9f9d809673 100644 --- a/activejob/test/jobs/kwargs_job.rb +++ b/activejob/test/jobs/kwargs_job.rb @@ -1,4 +1,4 @@ -require_relative '../support/job_buffer' +require_relative "../support/job_buffer" class KwargsJob < ActiveJob::Base def perform(argument: 1) diff --git a/activejob/test/jobs/logging_job.rb b/activejob/test/jobs/logging_job.rb index d84ed8589b..119b32fa67 100644 --- a/activejob/test/jobs/logging_job.rb +++ b/activejob/test/jobs/logging_job.rb @@ -7,4 +7,3 @@ class LoggingJob < ActiveJob::Base "LOGGING-JOB-ID" end end - diff --git a/activejob/test/jobs/nested_job.rb b/activejob/test/jobs/nested_job.rb index 8c4ec549a6..21b7692cd1 100644 --- a/activejob/test/jobs/nested_job.rb +++ b/activejob/test/jobs/nested_job.rb @@ -7,4 +7,3 @@ class NestedJob < ActiveJob::Base "NESTED-JOB-ID" end end - diff --git a/activejob/test/jobs/provider_jid_job.rb b/activejob/test/jobs/provider_jid_job.rb new file mode 100644 index 0000000000..0c8ba040f5 --- /dev/null +++ b/activejob/test/jobs/provider_jid_job.rb @@ -0,0 +1,7 @@ +require_relative "../support/job_buffer" + +class ProviderJidJob < ActiveJob::Base + def perform + JobBuffer.add("Provider Job ID: #{provider_job_id}") + end +end diff --git a/activejob/test/jobs/queue_as_job.rb b/activejob/test/jobs/queue_as_job.rb index 897aef52e5..7dc318e736 100644 --- a/activejob/test/jobs/queue_as_job.rb +++ b/activejob/test/jobs/queue_as_job.rb @@ -1,4 +1,4 @@ -require_relative '../support/job_buffer' +require_relative "../support/job_buffer" class QueueAsJob < ActiveJob::Base MY_QUEUE = :low_priority diff --git a/activejob/test/jobs/rescue_job.rb b/activejob/test/jobs/rescue_job.rb index 4f6376c850..ef8f777437 100644 --- a/activejob/test/jobs/rescue_job.rb +++ b/activejob/test/jobs/rescue_job.rb @@ -1,16 +1,16 @@ -require_relative '../support/job_buffer' +require_relative "../support/job_buffer" class RescueJob < ActiveJob::Base class OtherError < StandardError; end rescue_from(ArgumentError) do - JobBuffer.add('rescued from ArgumentError') + JobBuffer.add("rescued from ArgumentError") arguments[0] = "DIFFERENT!" retry_job end rescue_from(ActiveJob::DeserializationError) do |e| - JobBuffer.add('rescued from DeserializationError') + JobBuffer.add("rescued from DeserializationError") JobBuffer.add("DeserializationError original exception was #{e.cause.class.name}") end @@ -21,7 +21,7 @@ class RescueJob < ActiveJob::Base when "other" raise OtherError else - JobBuffer.add('performed beautifully') + JobBuffer.add("performed beautifully") end end end diff --git a/activejob/test/jobs/retry_job.rb b/activejob/test/jobs/retry_job.rb new file mode 100644 index 0000000000..c02febc50c --- /dev/null +++ b/activejob/test/jobs/retry_job.rb @@ -0,0 +1,29 @@ +require_relative "../support/job_buffer" +require "active_support/core_ext/integer/inflections" + +class DefaultsError < StandardError; end +class LongWaitError < StandardError; end +class ShortWaitTenAttemptsError < StandardError; end +class ExponentialWaitTenAttemptsError < StandardError; end +class CustomWaitTenAttemptsError < StandardError; end +class CustomCatchError < StandardError; end +class DiscardableError < StandardError; end + +class RetryJob < ActiveJob::Base + retry_on DefaultsError + retry_on LongWaitError, wait: 1.hour, attempts: 10 + retry_on ShortWaitTenAttemptsError, wait: 1.second, attempts: 10 + retry_on ExponentialWaitTenAttemptsError, wait: :exponentially_longer, attempts: 10 + retry_on CustomWaitTenAttemptsError, wait: ->(executions) { executions * 2 }, attempts: 10 + retry_on(CustomCatchError) { |job, exception| JobBuffer.add("Dealt with a job that failed to retry in a custom way after #{job.arguments.second} attempts") } + discard_on DiscardableError + + def perform(raising, attempts) + if executions < attempts + JobBuffer.add("Raised #{raising} for the #{executions.ordinalize} time") + raise raising.constantize + else + JobBuffer.add("Successfully completed job") + end + end +end diff --git a/activejob/test/jobs/translated_hello_job.rb b/activejob/test/jobs/translated_hello_job.rb index 9657cd3f54..56e9f147b9 100644 --- a/activejob/test/jobs/translated_hello_job.rb +++ b/activejob/test/jobs/translated_hello_job.rb @@ -1,8 +1,8 @@ -require_relative '../support/job_buffer' +require_relative "../support/job_buffer" class TranslatedHelloJob < ActiveJob::Base def perform(greeter = "David") - translations = { en: 'Hello', de: 'Guten Tag' } + translations = { en: "Hello", de: "Guten Tag" } hello = translations[I18n.locale] JobBuffer.add("#{greeter} says #{hello}") diff --git a/activejob/test/support/backburner/inline.rb b/activejob/test/support/backburner/inline.rb index f761b53e27..647dbf317f 100644 --- a/activejob/test/support/backburner/inline.rb +++ b/activejob/test/support/backburner/inline.rb @@ -1,8 +1,8 @@ -require 'backburner' +require "backburner" Backburner::Worker.class_eval do class << self; alias_method :original_enqueue, :enqueue; end def self.enqueue(job_class, args=[], opts={}) job_class.perform(*args) end -end
\ No newline at end of file +end diff --git a/activejob/test/support/delayed_job/delayed/backend/test.rb b/activejob/test/support/delayed_job/delayed/backend/test.rb index f80ec3a5a6..a900b18e2a 100644 --- a/activejob/test/support/delayed_job/delayed/backend/test.rb +++ b/activejob/test/support/delayed_job/delayed/backend/test.rb @@ -1,5 +1,5 @@ #copied from https://github.com/collectiveidea/delayed_job/blob/master/spec/delayed/backend/test.rb -require 'ostruct' +require "ostruct" # An in-memory backend suitable only for testing. Tries to behave as if it were an ORM. module Delayed @@ -26,7 +26,7 @@ module Delayed self.attempts = 0 self.priority = 0 self.id = (self.class.id += 1) - hash.each{|k,v| send(:"#{k}=", v)} + hash.each { |k,v| send(:"#{k}=", v) } end @jobs = [] @@ -49,7 +49,7 @@ module Delayed def self.create!(*args); create(*args); end def self.clear_locks!(worker_name) - all.select{|j| j.locked_by == worker_name}.each {|j| j.locked_by = nil; j.locked_at = nil} + all.select { |j| j.locked_by == worker_name }.each { |j| j.locked_by = nil; j.locked_at = nil } end # Find a few candidate jobs to run (in case some immediately get locked by others). @@ -60,10 +60,10 @@ module Delayed !j.failed? end - jobs = jobs.select{|j| Worker.queues.include?(j.queue)} if Worker.queues.any? - jobs = jobs.select{|j| j.priority >= Worker.min_priority} if Worker.min_priority - jobs = jobs.select{|j| j.priority <= Worker.max_priority} if Worker.max_priority - jobs.sort_by{|j| [j.priority, j.run_at]}[0..limit-1] + jobs = jobs.select { |j| Worker.queues.include?(j.queue) } if Worker.queues.any? + jobs = jobs.select { |j| j.priority >= Worker.min_priority } if Worker.min_priority + jobs = jobs.select { |j| j.priority <= Worker.max_priority } if Worker.max_priority + jobs.sort_by { |j| [j.priority, j.run_at] }[0..limit-1] end # Lock this job for this worker. @@ -84,7 +84,7 @@ module Delayed end def update_attributes(attrs = {}) - attrs.each{|k,v| send(:"#{k}=", v)} + attrs.each { |k,v| send(:"#{k}=", v) } save end diff --git a/activejob/test/support/integration/adapters/backburner.rb b/activejob/test/support/integration/adapters/backburner.rb index 2e82562948..263097c792 100644 --- a/activejob/test/support/integration/adapters/backburner.rb +++ b/activejob/test/support/integration/adapters/backburner.rb @@ -35,4 +35,3 @@ module BackburnerJobsManager true end end - diff --git a/activejob/test/support/integration/adapters/delayed_job.rb b/activejob/test/support/integration/adapters/delayed_job.rb index 0b591964bc..2adbbcd88f 100644 --- a/activejob/test/support/integration/adapters/delayed_job.rb +++ b/activejob/test/support/integration/adapters/delayed_job.rb @@ -1,5 +1,5 @@ -require 'delayed_job' -require 'delayed_job_active_record' +require "delayed_job" +require "delayed_job_active_record" module DelayedJobJobsManager def setup diff --git a/activejob/test/support/integration/adapters/inline.rb b/activejob/test/support/integration/adapters/inline.rb index 83c38f706f..e06b34c976 100644 --- a/activejob/test/support/integration/adapters/inline.rb +++ b/activejob/test/support/integration/adapters/inline.rb @@ -12,4 +12,3 @@ module InlineJobsManager def stop_workers end end - diff --git a/activejob/test/support/integration/adapters/qu.rb b/activejob/test/support/integration/adapters/qu.rb index 256ddb3cf3..71819f5a55 100644 --- a/activejob/test/support/integration/adapters/qu.rb +++ b/activejob/test/support/integration/adapters/qu.rb @@ -1,9 +1,9 @@ module QuJobsManager def setup - require 'qu-rails' - require 'qu-redis' + require "qu-rails" + require "qu-redis" ActiveJob::Base.queue_adapter = :qu - ENV['REDISTOGO_URL'] = "redis://127.0.0.1:6379/12" + ENV["REDISTOGO_URL"] = "redis://127.0.0.1:6379/12" backend = Qu::Backend::Redis.new backend.namespace = "active_jobs_int_test" Qu.backend = backend diff --git a/activejob/test/support/integration/adapters/que.rb b/activejob/test/support/integration/adapters/que.rb index 0cd8952a28..3d35a0439f 100644 --- a/activejob/test/support/integration/adapters/que.rb +++ b/activejob/test/support/integration/adapters/que.rb @@ -1,6 +1,6 @@ module QueJobsManager def setup - require 'sequel' + require "sequel" ActiveJob::Base.queue_adapter = :que Que.mode = :off Que.worker_count = 1 @@ -11,9 +11,9 @@ module QueJobsManager end def start_workers - que_url = ENV['QUE_DATABASE_URL'] || 'postgres:///active_jobs_que_int_test' + que_url = ENV["QUE_DATABASE_URL"] || "postgres:///active_jobs_que_int_test" uri = URI.parse(que_url) - user = uri.user||ENV['USER'] + user = uri.user||ENV["USER"] pass = uri.password db = uri.path[1..-1] %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database if exists "#{db}"' -U #{user} -t template1} diff --git a/activejob/test/support/integration/adapters/queue_classic.rb b/activejob/test/support/integration/adapters/queue_classic.rb index 29c04bf625..b5d831428e 100644 --- a/activejob/test/support/integration/adapters/queue_classic.rb +++ b/activejob/test/support/integration/adapters/queue_classic.rb @@ -1,8 +1,8 @@ module QueueClassicJobsManager def setup - ENV['QC_DATABASE_URL'] ||= 'postgres:///active_jobs_qc_int_test' - ENV['QC_RAILS_DATABASE'] = 'false' - ENV['QC_LISTEN_TIME'] = "0.5" + ENV["QC_DATABASE_URL"] ||= "postgres:///active_jobs_qc_int_test" + ENV["QC_RAILS_DATABASE"] = "false" + ENV["QC_LISTEN_TIME"] = "0.5" ActiveJob::Base.queue_adapter = :queue_classic end @@ -11,8 +11,8 @@ module QueueClassicJobsManager end def start_workers - uri = URI.parse(ENV['QC_DATABASE_URL']) - user = uri.user||ENV['USER'] + uri = URI.parse(ENV["QC_DATABASE_URL"]) + user = uri.user||ENV["USER"] pass = uri.password db = uri.path[1..-1] %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database if exists "#{db}"' -U #{user} -t template1} @@ -22,7 +22,7 @@ module QueueClassicJobsManager QC.default_conn_adapter.disconnect QC.default_conn_adapter = nil @pid = fork do - worker = QC::Worker.new(q_name: 'integration_tests') + worker = QC::Worker.new(q_name: "integration_tests") worker.start end @@ -32,6 +32,6 @@ module QueueClassicJobsManager end def stop_workers - Process.kill 'HUP', @pid + Process.kill "HUP", @pid end end diff --git a/activejob/test/support/integration/adapters/resque.rb b/activejob/test/support/integration/adapters/resque.rb index 912f4bc387..a21a1786c9 100644 --- a/activejob/test/support/integration/adapters/resque.rb +++ b/activejob/test/support/integration/adapters/resque.rb @@ -1,7 +1,7 @@ module ResqueJobsManager def setup ActiveJob::Base.queue_adapter = :resque - Resque.redis = Redis::Namespace.new 'active_jobs_int_test', redis: Redis.connect(url: "redis://127.0.0.1:6379/12", :thread_safe => true) + Resque.redis = Redis::Namespace.new "active_jobs_int_test", redis: Redis.connect(url: "redis://127.0.0.1:6379/12", thread_safe: true) Resque.logger = Rails.logger unless can_run? puts "Cannot run integration tests for resque. To be able to run integration tests for resque you need to install and start redis.\n" diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb index 2f19d7dacc..bbb575f6da 100644 --- a/activejob/test/support/integration/adapters/sidekiq.rb +++ b/activejob/test/support/integration/adapters/sidekiq.rb @@ -1,10 +1,9 @@ -require 'sidekiq/api' +require "sidekiq/api" -require 'sidekiq/testing' +require "sidekiq/testing" Sidekiq::Testing.disable! module SidekiqJobsManager - def setup ActiveJob::Base.queue_adapter = :sidekiq unless can_run? @@ -29,7 +28,7 @@ module SidekiqJobsManager # Sidekiq is not warning-clean :( $VERBOSE = false - $stdin.reopen('/dev/null') + $stdin.reopen("/dev/null") $stdout.sync = true $stderr.sync = true @@ -49,12 +48,11 @@ module SidekiqJobsManager self_write.puts("TERM") end - require 'sidekiq/launcher' - sidekiq = Sidekiq::Launcher.new({queues: ["integration_tests"], + require "sidekiq/launcher" + sidekiq = Sidekiq::Launcher.new(queues: ["integration_tests"], environment: "test", concurrency: 1, - timeout: 1, - }) + timeout: 1) Sidekiq.average_scheduled_poll_interval = 0.5 Sidekiq.options[:poll_interval_average] = 1 begin @@ -79,7 +77,7 @@ module SidekiqJobsManager def stop_workers if @pid - Process.kill 'TERM', @pid + Process.kill "TERM", @pid Process.wait @pid end end diff --git a/activejob/test/support/integration/adapters/sneakers.rb b/activejob/test/support/integration/adapters/sneakers.rb index 875803a2d8..08743c1f05 100644 --- a/activejob/test/support/integration/adapters/sneakers.rb +++ b/activejob/test/support/integration/adapters/sneakers.rb @@ -1,6 +1,6 @@ -require 'sneakers/runner' -require 'sneakers/publisher' -require 'timeout' +require "sneakers/runner" +require "sneakers/publisher" +require "timeout" module Sneakers class Publisher @@ -12,20 +12,19 @@ module Sneakers end end - module SneakersJobsManager def setup ActiveJob::Base.queue_adapter = :sneakers - Sneakers.configure :heartbeat => 2, - :amqp => 'amqp://guest:guest@localhost:5672', - :vhost => '/', - :exchange => 'active_jobs_sneakers_int_test', - :exchange_type => :direct, - :daemonize => true, - :threads => 1, - :workers => 1, - :pid_path => Rails.root.join("tmp/sneakers.pid").to_s, - :log => Rails.root.join("log/sneakers.log").to_s + Sneakers.configure heartbeat: 2, + amqp: "amqp://guest:guest@localhost:5672", + vhost: "/", + exchange: "active_jobs_sneakers_int_test", + exchange_type: :direct, + daemonize: true, + threads: 1, + workers: 1, + pid_path: Rails.root.join("tmp/sneakers.pid").to_s, + log: Rails.root.join("log/sneakers.log").to_s unless can_run? puts "Cannot run integration tests for sneakers. To be able to run integration tests for sneakers you need to install and start rabbitmq.\n" exit @@ -60,8 +59,8 @@ module SneakersJobsManager end def stop_workers - Process.kill 'TERM', @pid - Process.kill 'TERM', File.open(Rails.root.join("tmp/sneakers.pid").to_s).read.to_i + Process.kill "TERM", @pid + Process.kill "TERM", File.open(Rails.root.join("tmp/sneakers.pid").to_s).read.to_i rescue end @@ -86,5 +85,4 @@ module SneakersJobsManager def bunny_queue @queue ||= bunny_publisher.exchange.channel.queue "integration_tests", durable: true end - end diff --git a/activejob/test/support/integration/dummy_app_template.rb b/activejob/test/support/integration/dummy_app_template.rb index a0ef38b0b2..62f6fa13f6 100644 --- a/activejob/test/support/integration/dummy_app_template.rb +++ b/activejob/test/support/integration/dummy_app_template.rb @@ -1,19 +1,19 @@ -if ENV['AJ_ADAPTER'] == 'delayed_job' +if ENV["AJ_ADAPTER"] == "delayed_job" generate "delayed_job:active_record", "--quiet" end rails_command("db:migrate") -initializer 'activejob.rb', <<-CODE +initializer "activejob.rb", <<-CODE require "#{File.expand_path("../jobs_manager.rb", __FILE__)}" JobsManager.current_manager.setup CODE -initializer 'i18n.rb', <<-CODE +initializer "i18n.rb", <<-CODE I18n.available_locales = [:en, :de] CODE -file 'app/jobs/test_job.rb', <<-CODE +file "app/jobs/test_job.rb", <<-CODE class TestJob < ActiveJob::Base queue_as :integration_tests diff --git a/activejob/test/support/integration/helper.rb b/activejob/test/support/integration/helper.rb index 4a1b0bfbcb..1aaee2c809 100644 --- a/activejob/test/support/integration/helper.rb +++ b/activejob/test/support/integration/helper.rb @@ -3,7 +3,7 @@ puts "\n\n*** rake aj:integration:#{ENV['AJ_ADAPTER']} ***\n" ENV["RAILS_ENV"] = "test" ActiveJob::Base.queue_name_prefix = nil -require 'rails/generators/rails/app/app_generator' +require "rails/generators/rails/app/app_generator" dummy_app_path = Dir.mktmpdir + "/dummy" dummy_app_template = File.expand_path("../dummy_app_template.rb", __FILE__) @@ -14,12 +14,12 @@ Rails::Generators::AppGenerator.start args require "#{dummy_app_path}/config/environment.rb" -ActiveRecord::Migrator.migrations_paths = [ Rails.root.join('db/migrate').to_s ] -require 'rails/test_help' +ActiveRecord::Migrator.migrations_paths = [ Rails.root.join("db/migrate").to_s ] +require "rails/test_help" Rails.backtrace_cleaner.remove_silencers! -require_relative 'test_case_helpers' +require_relative "test_case_helpers" ActiveSupport::TestCase.include(TestCaseHelpers) JobsManager.current_manager.start_workers diff --git a/activejob/test/support/integration/jobs_manager.rb b/activejob/test/support/integration/jobs_manager.rb index 78d48e8d9a..488756437b 100644 --- a/activejob/test/support/integration/jobs_manager.rb +++ b/activejob/test/support/integration/jobs_manager.rb @@ -3,7 +3,7 @@ class JobsManager attr :adapter_name def self.current_manager - @@managers[ENV['AJ_ADAPTER']] ||= new(ENV['AJ_ADAPTER']) + @@managers[ENV["AJ_ADAPTER"]] ||= new(ENV["AJ_ADAPTER"]) end def initialize(adapter_name) diff --git a/activejob/test/support/integration/test_case_helpers.rb b/activejob/test/support/integration/test_case_helpers.rb index fdf25c67a1..4c4c56c9da 100644 --- a/activejob/test/support/integration/test_case_helpers.rb +++ b/activejob/test/support/integration/test_case_helpers.rb @@ -1,6 +1,6 @@ -require 'active_support/concern' -require 'active_support/core_ext/string/inflections' -require 'support/integration/jobs_manager' +require "active_support/concern" +require "active_support/core_ext/string/inflections" +require "support/integration/jobs_manager" module TestCaseHelpers extend ActiveSupport::Concern @@ -29,7 +29,7 @@ module TestCaseHelpers end def adapter_is?(*adapter_class_symbols) - adapter = ActiveJob::Base.queue_adapter.class.name.demodulize.chomp('Adapter').underscore + adapter = ActiveJob::Base.queue_adapter.class.name.demodulize.chomp("Adapter").underscore adapter_class_symbols.map(&:to_s).include? adapter end diff --git a/activejob/test/support/que/inline.rb b/activejob/test/support/que/inline.rb index 0950e52d28..55eb0d01ef 100644 --- a/activejob/test/support/que/inline.rb +++ b/activejob/test/support/que/inline.rb @@ -1,4 +1,4 @@ -require 'que' +require "que" Que::Job.class_eval do class << self; alias_method :original_enqueue, :enqueue; end @@ -9,6 +9,6 @@ Que::Job.class_eval do options.delete(:priority) args << options unless options.empty? end - self.run(*args) + run(*args) end end diff --git a/activejob/test/support/queue_classic/inline.rb b/activejob/test/support/queue_classic/inline.rb index 5743d5bbb5..dcd834ecce 100644 --- a/activejob/test/support/queue_classic/inline.rb +++ b/activejob/test/support/queue_classic/inline.rb @@ -1,21 +1,21 @@ -require 'queue_classic' +require "queue_classic" module QC class Queue def enqueue(method, *args) - receiver_str, _, message = method.rpartition('.') + receiver_str, _, message = method.rpartition(".") receiver = eval(receiver_str) receiver.send(message, *args) end def enqueue_in(seconds, method, *args) - receiver_str, _, message = method.rpartition('.') + receiver_str, _, message = method.rpartition(".") receiver = eval(receiver_str) receiver.send(message, *args) end def enqueue_at(not_before, method, *args) - receiver_str, _, message = method.rpartition('.') + receiver_str, _, message = method.rpartition(".") receiver = eval(receiver_str) receiver.send(message, *args) end diff --git a/activejob/test/support/sneakers/inline.rb b/activejob/test/support/sneakers/inline.rb index 16d9b830fa..3cdc54e6d5 100644 --- a/activejob/test/support/sneakers/inline.rb +++ b/activejob/test/support/sneakers/inline.rb @@ -1,4 +1,4 @@ -require 'sneakers' +require "sneakers" module Sneakers module Worker diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 206699c036..10f1de6706 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,2 +1,12 @@ +* Removed deprecated `:tokenizer` in the length validator. + + *Rafael Mendonça França* + +* Removed deprecated methods in `ActiveModel::Errors`. + + `#get`, `#set`, `[]=`, `add_on_empty` and `add_on_blank`. + + *Rafael Mendonça França* + Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/activemodel/CHANGELOG.md) for previous changes. diff --git a/activemodel/Rakefile b/activemodel/Rakefile index 036815a987..c7f97a4258 100644 --- a/activemodel/Rakefile +++ b/activemodel/Rakefile @@ -1,8 +1,8 @@ -require 'rake/testtask' +require "rake/testtask" dir = File.dirname(__FILE__) -task :default => :test +task default: :test task :package @@ -17,7 +17,7 @@ end namespace :test do task :isolated do Dir.glob("#{dir}/test/**/*_test.rb").all? do |file| - sh(Gem.ruby, '-w', "-I#{dir}/lib", "-I#{dir}/test", file) - end or raise "Failures" + sh(Gem.ruby, "-w", "-I#{dir}/lib", "-I#{dir}/test", file) + end || raise("Failures") end end diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec index 1c3997b864..fd715f6ba9 100644 --- a/activemodel/activemodel.gemspec +++ b/activemodel/activemodel.gemspec @@ -1,22 +1,22 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'activemodel' + s.name = "activemodel" s.version = version - s.summary = 'A toolkit for building modeling frameworks (part of Rails).' - s.description = 'A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, serialization, internationalization, and testing.' + s.summary = "A toolkit for building modeling frameworks (part of Rails)." + s.description = "A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, serialization, internationalization, and testing." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*'] - s.require_path = 'lib' + s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.rdoc", "lib/**/*"] + s.require_path = "lib" - s.add_dependency 'activesupport', version + s.add_dependency "activesupport", version end diff --git a/activemodel/bin/test b/activemodel/bin/test index 404cabba51..84a05bba08 100755 --- a/activemodel/bin/test +++ b/activemodel/bin/test @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -COMPONENT_ROOT = File.expand_path("../../", __FILE__) + +COMPONENT_ROOT = File.expand_path("..", __dir__) require File.expand_path("../tools/test", COMPONENT_ROOT) + exit Minitest.run(ARGV) diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index 7de259a60d..a9b0663940 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -21,24 +21,24 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'active_support' -require 'active_support/rails' -require 'active_model/version' +require "active_support" +require "active_support/rails" +require "active_model/version" module ActiveModel extend ActiveSupport::Autoload autoload :AttributeAssignment autoload :AttributeMethods - autoload :BlockValidator, 'active_model/validator' + autoload :BlockValidator, "active_model/validator" autoload :Callbacks autoload :Conversion autoload :Dirty - autoload :EachValidator, 'active_model/validator' + autoload :EachValidator, "active_model/validator" autoload :ForbiddenAttributesProtection autoload :Lint autoload :Model - autoload :Name, 'active_model/naming' + autoload :Name, "active_model/naming" autoload :Naming autoload :SecurePassword autoload :Serialization @@ -49,9 +49,9 @@ module ActiveModel eager_autoload do autoload :Errors - autoload :RangeError, 'active_model/errors' - autoload :StrictValidationFailed, 'active_model/errors' - autoload :UnknownAttributeError, 'active_model/errors' + autoload :RangeError, "active_model/errors" + autoload :StrictValidationFailed, "active_model/errors" + autoload :UnknownAttributeError, "active_model/errors" end module Serializers @@ -69,5 +69,5 @@ module ActiveModel end ActiveSupport.on_load(:i18n) do - I18n.load_path << File.dirname(__FILE__) + '/active_model/locale/en.yml' + I18n.load_path << File.dirname(__FILE__) + "/active_model/locale/en.yml" end diff --git a/activemodel/lib/active_model/attribute_assignment.rb b/activemodel/lib/active_model/attribute_assignment.rb index 62014cd1cd..7dad3b6dff 100644 --- a/activemodel/lib/active_model/attribute_assignment.rb +++ b/activemodel/lib/active_model/attribute_assignment.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/hash/keys" module ActiveModel module AttributeAssignment @@ -35,18 +35,18 @@ module ActiveModel private - def _assign_attributes(attributes) - attributes.each do |k, v| - _assign_attribute(k, v) + def _assign_attributes(attributes) + attributes.each do |k, v| + _assign_attribute(k, v) + end end - end - def _assign_attribute(k, v) - if respond_to?("#{k}=") - public_send("#{k}=", v) - else - raise UnknownAttributeError.new(self, k) + def _assign_attribute(k, v) + if respond_to?("#{k}=") + public_send("#{k}=", v) + else + raise UnknownAttributeError.new(self, k) + end end - end end end diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index cc6285f932..96709486f3 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -1,5 +1,6 @@ -require 'concurrent/map' -require 'mutex_m' +require "concurrent/map" +require "mutex_m" +require "active_support/core_ext/regexp" module ActiveModel # Raised when an attribute is not defined. @@ -366,7 +367,7 @@ module ActiveModel # using the given `extra` args. This falls back on `define_method` # and `send` if the given names cannot be compiled. def define_proxy_call(include_private, mod, name, send, *extra) #:nodoc: - defn = if name =~ NAME_COMPILABLE_REGEXP + defn = if NAME_COMPILABLE_REGEXP.match?(name) "def #{name}(*args)" else "define_method(:'#{name}') do |*args|" @@ -374,7 +375,7 @@ module ActiveModel extra = (extra.map!(&:inspect) << "*args").join(", ".freeze) - target = if send =~ CALL_COMPILABLE_REGEXP + target = if CALL_COMPILABLE_REGEXP.match?(send) "#{"self." unless include_private}#{send}(#{extra})" else "send(:'#{send}', #{extra})" @@ -393,7 +394,7 @@ module ActiveModel AttributeMethodMatch = Struct.new(:target, :attr_name, :method_name) def initialize(options = {}) - @prefix, @suffix = options.fetch(:prefix, ''), options.fetch(:suffix, '') + @prefix, @suffix = options.fetch(:prefix, ""), options.fetch(:suffix, "") @regex = /^(?:#{Regexp.escape(@prefix)})(.*)(?:#{Regexp.escape(@suffix)})$/ @method_missing_target = "#{@prefix}attribute#{@suffix}" @method_name = "#{prefix}%s#{suffix}" diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb index 0d6a3dc52d..283090e380 100644 --- a/activemodel/lib/active_model/callbacks.rb +++ b/activemodel/lib/active_model/callbacks.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/array/extract_options" module ActiveModel # == Active \Model \Callbacks @@ -122,28 +122,28 @@ module ActiveModel private - def _define_before_model_callback(klass, callback) #:nodoc: - klass.define_singleton_method("before_#{callback}") do |*args, &block| - set_callback(:"#{callback}", :before, *args, &block) + def _define_before_model_callback(klass, callback) #:nodoc: + klass.define_singleton_method("before_#{callback}") do |*args, &block| + set_callback(:"#{callback}", :before, *args, &block) + end end - end - def _define_around_model_callback(klass, callback) #:nodoc: - klass.define_singleton_method("around_#{callback}") do |*args, &block| - set_callback(:"#{callback}", :around, *args, &block) + def _define_around_model_callback(klass, callback) #:nodoc: + klass.define_singleton_method("around_#{callback}") do |*args, &block| + set_callback(:"#{callback}", :around, *args, &block) + end end - end - def _define_after_model_callback(klass, callback) #:nodoc: - klass.define_singleton_method("after_#{callback}") do |*args, &block| - options = args.extract_options! - options[:prepend] = true - conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v| - v != false - } - options[:if] = Array(options[:if]) << conditional - set_callback(:"#{callback}", :after, *(args << options), &block) + def _define_after_model_callback(klass, callback) #:nodoc: + klass.define_singleton_method("after_#{callback}") do |*args, &block| + options = args.extract_options! + options[:prepend] = true + conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v| + v != false + } + options[:if] = Array(options[:if]) << conditional + set_callback(:"#{callback}", :after, *(args << options), &block) + end end - end end end diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index a932ada45c..12687c70d3 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -46,9 +46,13 @@ module ActiveModel # class Person # include ActiveModel::Conversion # attr_accessor :id + # + # def initialize(id) + # @id = id + # end # end # - # person = Person.create(id: 1) + # person = Person.new(1) # person.to_key # => [1] def to_key key = respond_to?(:id) && id @@ -61,15 +65,20 @@ module ActiveModel # class Person # include ActiveModel::Conversion # attr_accessor :id + # + # def initialize(id) + # @id = id + # end + # # def persisted? # true # end # end # - # person = Person.create(id: 1) + # person = Person.new(1) # person.to_param # => "1" def to_param - (persisted? && key = to_key) ? key.join('-') : nil + (persisted? && key = to_key) ? key.join("-") : nil end # Returns a +string+ identifying the path associated with the object. diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index 90047c3c12..6e0af99ad7 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -1,5 +1,5 @@ -require 'active_support/hash_with_indifferent_access' -require 'active_support/core_ext/object/duplicable' +require "active_support/hash_with_indifferent_access" +require "active_support/core_ext/object/duplicable" module ActiveModel # == Active \Model \Dirty @@ -26,8 +26,8 @@ module ActiveModel # # define_attribute_methods :name # - # def initialize(name) - # @name = name + # def initialize + # @name = nil # end # # def name @@ -58,7 +58,7 @@ module ActiveModel # # A newly instantiated +Person+ object is unchanged: # - # person = Person.new("Uncle Bob") + # person = Person.new # person.changed? # => false # # Change the name: @@ -66,11 +66,11 @@ module ActiveModel # person.name = 'Bob' # person.changed? # => true # person.name_changed? # => true - # person.name_changed?(from: "Uncle Bob", to: "Bob") # => true - # person.name_was # => "Uncle Bob" - # person.name_change # => ["Uncle Bob", "Bob"] + # person.name_changed?(from: nil, to: "Bob") # => true + # person.name_was # => nil + # person.name_change # => [nil, "Bob"] # person.name = 'Bill' - # person.name_change # => ["Uncle Bob", "Bill"] + # person.name_change # => [nil, "Bill"] # # Save the changes: # @@ -80,9 +80,9 @@ module ActiveModel # # Reset the changes: # - # person.previous_changes # => {"name" => ["Uncle Bob", "Bill"]} + # person.previous_changes # => {"name" => [nil, "Bill"]} # person.name_previously_changed? # => true - # person.name_previous_change # => ["Uncle Bob", "Bill"] + # person.name_previous_change # => [nil, "Bill"] # person.reload! # person.previous_changes # => {} # @@ -123,9 +123,9 @@ module ActiveModel private_constant :OPTION_NOT_GIVEN included do - attribute_method_suffix '_changed?', '_change', '_will_change!', '_was' - attribute_method_suffix '_previously_changed?', '_previous_change' - attribute_method_affix prefix: 'restore_', suffix: '!' + attribute_method_suffix "_changed?", "_change", "_will_change!", "_was" + attribute_method_suffix "_previously_changed?", "_previous_change" + attribute_method_affix prefix: "restore_", suffix: "!" end # Returns +true+ if any of the attributes have unsaved changes, +false+ otherwise. diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 6f2c8c1c53..17ed5de420 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/array/conversions' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/object/deep_dup' -require 'active_support/core_ext/string/filters' +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/object/deep_dup" +require "active_support/core_ext/string/filters" module ActiveModel # == Active \Model \Errors @@ -115,41 +115,11 @@ module ActiveModel alias :has_key? :include? alias :key? :include? - # Get messages for +key+. - # - # person.errors.messages # => {:name=>["cannot be nil"]} - # person.errors.get(:name) # => ["cannot be nil"] - # person.errors.get(:age) # => [] - def get(key) - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - ActiveModel::Errors#get is deprecated and will be removed in Rails 5.1. - - To achieve the same use model.errors[:#{key}]. - MESSAGE - - messages[key] - end - - # Set messages for +key+ to +value+. - # - # person.errors[:name] # => ["cannot be nil"] - # person.errors.set(:name, ["can't be nil"]) - # person.errors[:name] # => ["can't be nil"] - def set(key, value) - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - ActiveModel::Errors#set is deprecated and will be removed in Rails 5.1. - - Use model.errors.add(:#{key}, #{value.inspect}) instead. - MESSAGE - - messages[key] = value - end - # Delete messages for +key+. Returns the deleted messages. # - # person.errors[:name] # => ["cannot be nil"] + # person.errors[:name] # => ["cannot be nil"] # person.errors.delete(:name) # => ["cannot be nil"] - # person.errors[:name] # => [] + # person.errors[:name] # => [] def delete(key) details.delete(key) messages.delete(key) @@ -173,20 +143,6 @@ module ActiveModel messages[attribute.to_sym] end - # Adds to the supplied attribute the supplied error message. - # - # person.errors[:name] = "must be set" - # person.errors[:name] # => ['must be set'] - def []=(attribute, error) - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - ActiveModel::Errors#[]= is deprecated and will be removed in Rails 5.1. - - Use model.errors.add(:#{attribute}, #{error.inspect}) instead. - MESSAGE - - messages[attribute.to_sym] << error - end - # Iterates through each error key, value pair in the error messages hash. # Yields the attribute and the error for that attribute. If the attribute # has more than one error message, yields once for each error message. @@ -276,11 +232,11 @@ module ActiveModel # person.errors.to_hash(true) # => {:name=>["name cannot be nil"]} def to_hash(full_messages = false) if full_messages - self.messages.each_with_object({}) do |(attribute, array), messages| + messages.each_with_object({}) do |(attribute, array), messages| messages[attribute] = array.map { |message| full_message(attribute, message) } end else - self.messages.dup + without_default_proc(messages) end end @@ -338,54 +294,22 @@ module ActiveModel messages[attribute.to_sym] << message end - # Will add an error message to each of the attributes in +attributes+ - # that is empty. - # - # person.errors.add_on_empty(:name) - # person.errors.messages - # # => {:name=>["can't be empty"]} - def add_on_empty(attributes, options = {}) - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - ActiveModel::Errors#add_on_empty is deprecated and will be removed in Rails 5.1. - - To achieve the same use: - - errors.add(attribute, :empty, options) if value.nil? || value.empty? - MESSAGE - - Array(attributes).each do |attribute| - value = @base.send(:read_attribute_for_validation, attribute) - is_empty = value.respond_to?(:empty?) ? value.empty? : false - add(attribute, :empty, options) if value.nil? || is_empty - end - end - - # Will add an error message to each of the attributes in +attributes+ that - # is blank (using Object#blank?). - # - # person.errors.add_on_blank(:name) - # person.errors.messages - # # => {:name=>["can't be blank"]} - def add_on_blank(attributes, options = {}) - ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) - ActiveModel::Errors#add_on_blank is deprecated and will be removed in Rails 5.1. - - To achieve the same use: - - errors.add(attribute, :empty, options) if value.blank? - MESSAGE - - Array(attributes).each do |attribute| - value = @base.send(:read_attribute_for_validation, attribute) - add(attribute, :blank, options) if value.blank? - end - end - # Returns +true+ if an error on the attribute with the given message is - # present, +false+ otherwise. +message+ is treated the same as for +add+. + # present, or +false+ otherwise. +message+ is treated the same as for +add+. # # person.errors.add :name, :blank - # person.errors.added? :name, :blank # => true + # person.errors.added? :name, :blank # => true + # person.errors.added? :name, "can't be blank" # => true + # + # If the error message requires an option, then it returns +true+ with + # the correct option, or +false+ with an incorrect or missing option. + # + # person.errors.add :name, :too_long, { count: 25 } + # person.errors.added? :name, :too_long, count: 25 # => true + # person.errors.added? :name, "is too long (maximum is 25 characters)" # => true + # person.errors.added? :name, :too_long, count: 24 # => false + # person.errors.added? :name, :too_long # => false + # person.errors.added? :name, "is too long" # => false def added?(attribute, message = :invalid, options = {}) message = message.call if message.respond_to?(:call) message = normalize_message(attribute, message, options) @@ -426,13 +350,12 @@ module ActiveModel # person.errors.full_message(:name, 'is invalid') # => "Name is invalid" def full_message(attribute, message) return message if attribute == :base - attr_name = attribute.to_s.tr('.', '_').humanize + attr_name = attribute.to_s.tr(".", "_").humanize attr_name = @base.class.human_attribute_name(attribute, default: attr_name) - I18n.t(:"errors.format", { + I18n.t(:"errors.format", default: "%{attribute} %{message}", attribute: attr_name, - message: message - }) + message: message) end # Translates an error message in its default scope diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb index 010eaeb170..291a545528 100644 --- a/activemodel/lib/active_model/lint.rb +++ b/activemodel/lib/active_model/lint.rb @@ -20,7 +20,6 @@ module ActiveModel # to <tt>to_model</tt>. It is perfectly fine for <tt>to_model</tt> to return # +self+. module Tests - # Passes if the object's model responds to <tt>to_key</tt> and if calling # this method returns +nil+ when the object is not persisted. # Fails otherwise. diff --git a/activemodel/lib/active_model/model.rb b/activemodel/lib/active_model/model.rb index dac8d549a7..f5765c0c54 100644 --- a/activemodel/lib/active_model/model.rb +++ b/activemodel/lib/active_model/model.rb @@ -1,5 +1,4 @@ module ActiveModel - # == Active \Model \Basic \Model # # Includes the required interface for an object to interact with diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index d86ef6224e..3830d1486d 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/module/introspection' -require 'active_support/core_ext/module/remove_method' -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/hash/except" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/module/delegation" module ActiveModel class Name @@ -149,7 +149,7 @@ module ActiveModel raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank? - @unnamespaced = @name.sub(/^#{namespace.name}::/, '') if namespace + @unnamespaced = @name.sub(/^#{namespace.name}::/, "") if namespace @klass = klass @singular = _singularize(@name) @plural = ActiveSupport::Inflector.pluralize(@singular) @@ -191,9 +191,9 @@ module ActiveModel private - def _singularize(string) - ActiveSupport::Inflector.underscore(string).tr('/'.freeze, '_'.freeze) - end + def _singularize(string) + ActiveSupport::Inflector.underscore(string).tr("/".freeze, "_".freeze) + end end # == Active \Model \Naming diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb index 89da74efa8..1c0fe92bc0 100644 --- a/activemodel/lib/active_model/secure_password.rb +++ b/activemodel/lib/active_model/secure_password.rb @@ -55,7 +55,7 @@ module ActiveModel # This is to avoid ActiveModel (and by extension the entire framework) # being dependent on a binary library. begin - require 'bcrypt' + require "bcrypt" rescue LoadError $stderr.puts "You don't have bcrypt installed in your application. Please add it to your Gemfile and run bundle install" raise diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb index 70e10fa06d..77834f26fc 100644 --- a/activemodel/lib/active_model/serialization.rb +++ b/activemodel/lib/active_model/serialization.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/slice' +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" module ActiveModel # == Active \Model \Serialization diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb index b64a8299e6..b5e030a59b 100644 --- a/activemodel/lib/active_model/serializers/json.rb +++ b/activemodel/lib/active_model/serializers/json.rb @@ -1,4 +1,4 @@ -require 'active_support/json' +require "active_support/json" module ActiveModel module Serializers diff --git a/activemodel/lib/active_model/translation.rb b/activemodel/lib/active_model/translation.rb index 8470915abb..b8cf43cc10 100644 --- a/activemodel/lib/active_model/translation.rb +++ b/activemodel/lib/active_model/translation.rb @@ -1,5 +1,4 @@ module ActiveModel - # == Active \Model \Translation # # Provides integration between your object and the Rails internationalization @@ -31,7 +30,7 @@ module ActiveModel # ActiveModel::Errors#full_messages and # ActiveModel::Translation#human_attribute_name. def lookup_ancestors - self.ancestors.select { |x| x.respond_to?(:model_name) } + ancestors.select { |x| x.respond_to?(:model_name) } end # Transforms attribute names into a more human format, such as "First name" diff --git a/activemodel/lib/active_model/type.rb b/activemodel/lib/active_model/type.rb index 6ec3452478..0d3349e236 100644 --- a/activemodel/lib/active_model/type.rb +++ b/activemodel/lib/active_model/type.rb @@ -1,22 +1,22 @@ -require 'active_model/type/helpers' -require 'active_model/type/value' +require "active_model/type/helpers" +require "active_model/type/value" -require 'active_model/type/big_integer' -require 'active_model/type/binary' -require 'active_model/type/boolean' -require 'active_model/type/date' -require 'active_model/type/date_time' -require 'active_model/type/decimal' -require 'active_model/type/decimal_without_scale' -require 'active_model/type/float' -require 'active_model/type/immutable_string' -require 'active_model/type/integer' -require 'active_model/type/string' -require 'active_model/type/text' -require 'active_model/type/time' -require 'active_model/type/unsigned_integer' +require "active_model/type/big_integer" +require "active_model/type/binary" +require "active_model/type/boolean" +require "active_model/type/date" +require "active_model/type/date_time" +require "active_model/type/decimal" +require "active_model/type/decimal_without_scale" +require "active_model/type/float" +require "active_model/type/immutable_string" +require "active_model/type/integer" +require "active_model/type/string" +require "active_model/type/text" +require "active_model/type/time" +require "active_model/type/unsigned_integer" -require 'active_model/type/registry' +require "active_model/type/registry" module ActiveModel module Type @@ -27,7 +27,7 @@ module ActiveModel delegate :add_modifier, to: :registry # Add a new type to the registry, allowing it to be referenced as a - # symbol by ActiveModel::Attributes::ClassMethods#attribute. If your + # symbol by ActiveRecord::Attributes::ClassMethods#attribute. If your # type is only meant to be used with a specific database adapter, you can # do so by passing +adapter: :postgresql+. If your type has the same # name as a native type for the current adapter, an exception will be diff --git a/activemodel/lib/active_model/type/big_integer.rb b/activemodel/lib/active_model/type/big_integer.rb index 4168cbfce7..3b629682fe 100644 --- a/activemodel/lib/active_model/type/big_integer.rb +++ b/activemodel/lib/active_model/type/big_integer.rb @@ -1,13 +1,13 @@ -require 'active_model/type/integer' +require "active_model/type/integer" module ActiveModel module Type class BigInteger < Integer # :nodoc: private - def max_value - ::Float::INFINITY - end + def max_value + ::Float::INFINITY + end end end end diff --git a/activemodel/lib/active_model/type/binary.rb b/activemodel/lib/active_model/type/binary.rb index a0cc45b4c3..819e4e4a96 100644 --- a/activemodel/lib/active_model/type/binary.rb +++ b/activemodel/lib/active_model/type/binary.rb @@ -38,7 +38,7 @@ module ActiveModel alias_method :to_str, :to_s def hex - @value.unpack('H*')[0] + @value.unpack("H*")[0] end def ==(other) diff --git a/activemodel/lib/active_model/type/boolean.rb b/activemodel/lib/active_model/type/boolean.rb index c1bce98c87..f2a47370a3 100644 --- a/activemodel/lib/active_model/type/boolean.rb +++ b/activemodel/lib/active_model/type/boolean.rb @@ -1,21 +1,32 @@ module ActiveModel module Type - class Boolean < Value # :nodoc: - FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set + # == Active \Model \Type \Boolean + # + # A class that behaves like a boolean type, including rules for coercion of user input. + # + # === Coercion + # Values set from user input will first be coerced into the appropriate ruby type. + # Coercion behavior is roughly mapped to Ruby's boolean semantics. + # + # - "false", "f" , "0", +0+ or any other value in +FALSE_VALUES+ will be coerced to +false+ + # - Empty strings are coerced to +nil+ + # - All other values will be coerced to +true+ + class Boolean < Value + FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"].to_set - def type + def type # :nodoc: :boolean end private - def cast_value(value) - if value == '' - nil - else - !FALSE_VALUES.include?(value) + def cast_value(value) + if value == "" + nil + else + !FALSE_VALUES.include?(value) + end end - end end end end diff --git a/activemodel/lib/active_model/type/date.rb b/activemodel/lib/active_model/type/date.rb index f74243a22c..6e313fbca8 100644 --- a/activemodel/lib/active_model/type/date.rb +++ b/activemodel/lib/active_model/type/date.rb @@ -7,44 +7,48 @@ module ActiveModel :date end + def serialize(value) + cast(value) + end + def type_cast_for_schema(value) "'#{value.to_s(:db)}'" end private - def cast_value(value) - if value.is_a?(::String) - return if value.empty? - fast_string_to_date(value) || fallback_string_to_date(value) - elsif value.respond_to?(:to_date) - value.to_date - else - value + def cast_value(value) + if value.is_a?(::String) + return if value.empty? + fast_string_to_date(value) || fallback_string_to_date(value) + elsif value.respond_to?(:to_date) + value.to_date + else + value + end end - end - ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/ - def fast_string_to_date(string) - if string =~ ISO_DATE - new_date $1.to_i, $2.to_i, $3.to_i + ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/ + def fast_string_to_date(string) + if string =~ ISO_DATE + new_date $1.to_i, $2.to_i, $3.to_i + end end - end - def fallback_string_to_date(string) - new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday)) - end + def fallback_string_to_date(string) + new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday)) + end - def new_date(year, mon, mday) - if year && year != 0 - ::Date.new(year, mon, mday) rescue nil + def new_date(year, mon, mday) + if year && year != 0 + ::Date.new(year, mon, mday) rescue nil + end end - end - def value_from_multiparameter_assignment(*) - time = super - time && time.to_date - end + def value_from_multiparameter_assignment(*) + time = super + time && time.to_date + end end end end diff --git a/activemodel/lib/active_model/type/date_time.rb b/activemodel/lib/active_model/type/date_time.rb index 2f2df4320f..5cb0077e45 100644 --- a/activemodel/lib/active_model/type/date_time.rb +++ b/activemodel/lib/active_model/type/date_time.rb @@ -12,33 +12,33 @@ module ActiveModel private - def cast_value(value) - return apply_seconds_precision(value) unless value.is_a?(::String) - return if value.empty? + def cast_value(value) + return apply_seconds_precision(value) unless value.is_a?(::String) + return if value.empty? - fast_string_to_time(value) || fallback_string_to_time(value) - end + fast_string_to_time(value) || fallback_string_to_time(value) + end - # '0.123456' -> 123456 - # '1.123456' -> 123456 - def microseconds(time) - time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0 - end + # '0.123456' -> 123456 + # '1.123456' -> 123456 + def microseconds(time) + time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0 + end - def fallback_string_to_time(string) - time_hash = ::Date._parse(string) - time_hash[:sec_fraction] = microseconds(time_hash) + def fallback_string_to_time(string) + time_hash = ::Date._parse(string) + time_hash[:sec_fraction] = microseconds(time_hash) - new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)) - end + new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)) + end - def value_from_multiparameter_assignment(values_hash) - missing_parameter = (1..3).detect { |key| !values_hash.key?(key) } - if missing_parameter - raise ArgumentError, missing_parameter + def value_from_multiparameter_assignment(values_hash) + missing_parameter = (1..3).detect { |key| !values_hash.key?(key) } + if missing_parameter + raise ArgumentError, missing_parameter + end + super end - super - end end end end diff --git a/activemodel/lib/active_model/type/decimal.rb b/activemodel/lib/active_model/type/decimal.rb index 11ea327026..6c5c0451c6 100644 --- a/activemodel/lib/active_model/type/decimal.rb +++ b/activemodel/lib/active_model/type/decimal.rb @@ -15,46 +15,47 @@ module ActiveModel private - def cast_value(value) - casted_value = case value - when ::Float - convert_float_to_big_decimal(value) - when ::Numeric, ::String - BigDecimal(value, precision.to_i) - else - if value.respond_to?(:to_d) - value.to_d + def cast_value(value) + casted_value = \ + case value + when ::Float + convert_float_to_big_decimal(value) + when ::Numeric, ::String + BigDecimal(value, precision.to_i) + else + if value.respond_to?(:to_d) + value.to_d + else + cast_value(value.to_s) + end + end + + apply_scale(casted_value) + end + + def convert_float_to_big_decimal(value) + if precision + BigDecimal(apply_scale(value), float_precision) else - cast_value(value.to_s) + value.to_d end end - apply_scale(casted_value) - end - - def convert_float_to_big_decimal(value) - if precision - BigDecimal(apply_scale(value), float_precision) - else - value.to_d - end - end - - def float_precision - if precision.to_i > ::Float::DIG + 1 - ::Float::DIG + 1 - else - precision.to_i + def float_precision + if precision.to_i > ::Float::DIG + 1 + ::Float::DIG + 1 + else + precision.to_i + end end - end - def apply_scale(value) - if scale - value.round(scale) - else - value + def apply_scale(value) + if scale + value.round(scale) + else + value + end end - end end end end diff --git a/activemodel/lib/active_model/type/decimal_without_scale.rb b/activemodel/lib/active_model/type/decimal_without_scale.rb index 129baa0c10..985e1038ed 100644 --- a/activemodel/lib/active_model/type/decimal_without_scale.rb +++ b/activemodel/lib/active_model/type/decimal_without_scale.rb @@ -1,4 +1,4 @@ -require 'active_model/type/big_integer' +require "active_model/type/big_integer" module ActiveModel module Type diff --git a/activemodel/lib/active_model/type/float.rb b/activemodel/lib/active_model/type/float.rb index 0f925bc7e1..4d0d2771a0 100644 --- a/activemodel/lib/active_model/type/float.rb +++ b/activemodel/lib/active_model/type/float.rb @@ -7,19 +7,28 @@ module ActiveModel :float end + def type_cast_for_schema(value) + return "::Float::NAN" if value.try(:nan?) + case value + when ::Float::INFINITY then "::Float::INFINITY" + when -::Float::INFINITY then "-::Float::INFINITY" + else super + end + end + alias serialize cast private - def cast_value(value) - case value - when ::Float then value - when "Infinity" then ::Float::INFINITY - when "-Infinity" then -::Float::INFINITY - when "NaN" then ::Float::NAN - else value.to_f + def cast_value(value) + case value + when ::Float then value + when "Infinity" then ::Float::INFINITY + when "-Infinity" then -::Float::INFINITY + when "NaN" then ::Float::NAN + else value.to_f + end end - end end end end diff --git a/activemodel/lib/active_model/type/helpers.rb b/activemodel/lib/active_model/type/helpers.rb index a805a359ab..82cd9ebe98 100644 --- a/activemodel/lib/active_model/type/helpers.rb +++ b/activemodel/lib/active_model/type/helpers.rb @@ -1,4 +1,4 @@ -require 'active_model/type/helpers/accepts_multiparameter_time' -require 'active_model/type/helpers/numeric' -require 'active_model/type/helpers/mutable' -require 'active_model/type/helpers/time_value' +require "active_model/type/helpers/accepts_multiparameter_time" +require "active_model/type/helpers/numeric" +require "active_model/type/helpers/mutable" +require "active_model/type/helpers/time_value" diff --git a/activemodel/lib/active_model/type/helpers/numeric.rb b/activemodel/lib/active_model/type/helpers/numeric.rb index c883010506..98533f8771 100644 --- a/activemodel/lib/active_model/type/helpers/numeric.rb +++ b/activemodel/lib/active_model/type/helpers/numeric.rb @@ -3,12 +3,13 @@ module ActiveModel module Helpers module Numeric # :nodoc: def cast(value) - value = case value - when true then 1 - when false then 0 - when ::String then value.presence - else value - end + value = \ + case value + when true then 1 + when false then 0 + when ::String then value.presence + else value + end super(value) end @@ -18,16 +19,16 @@ module ActiveModel private - def number_to_non_number?(old_value, new_value_before_type_cast) - old_value != nil && non_numeric_string?(new_value_before_type_cast) - end + def number_to_non_number?(old_value, new_value_before_type_cast) + old_value != nil && non_numeric_string?(new_value_before_type_cast) + end - def non_numeric_string?(value) - # 'wibble'.to_i will give zero, we want to make sure - # that we aren't marking int zero to string zero as - # changed. - value.to_s !~ /\A-?\d+\.?\d*\z/ - end + def non_numeric_string?(value) + # 'wibble'.to_i will give zero, we want to make sure + # that we aren't marking int zero to string zero as + # changed. + value.to_s !~ /\A-?\d+\.?\d*\z/ + end end end end diff --git a/activemodel/lib/active_model/type/helpers/time_value.rb b/activemodel/lib/active_model/type/helpers/time_value.rb index 63993c0d93..d8c5d929a3 100644 --- a/activemodel/lib/active_model/type/helpers/time_value.rb +++ b/activemodel/lib/active_model/type/helpers/time_value.rb @@ -19,7 +19,7 @@ module ActiveModel end def is_utc? - ::Time.zone_default.nil? || ::Time.zone_default =~ 'UTC' + ::Time.zone_default.nil? || ::Time.zone_default =~ "UTC" end def default_timezone @@ -47,30 +47,30 @@ module ActiveModel private - def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil) - # Treat 0000-00-00 00:00:00 as nil. - return if year.nil? || (year == 0 && mon == 0 && mday == 0) + def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil) + # Treat 0000-00-00 00:00:00 as nil. + return if year.nil? || (year == 0 && mon == 0 && mday == 0) - if offset - time = ::Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil - return unless time + if offset + time = ::Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil + return unless time - time -= offset - is_utc? ? time : time.getlocal - else - ::Time.public_send(default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil + time -= offset + is_utc? ? time : time.getlocal + else + ::Time.public_send(default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil + end end - end - ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/ + ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/ - # Doesn't handle time zones. - def fast_string_to_time(string) - if string =~ ISO_DATETIME - microsec = ($7.to_r * 1_000_000).to_i - new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec + # Doesn't handle time zones. + def fast_string_to_time(string) + if string =~ ISO_DATETIME + microsec = ($7.to_r * 1_000_000).to_i + new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec + end end - end end end end diff --git a/activemodel/lib/active_model/type/immutable_string.rb b/activemodel/lib/active_model/type/immutable_string.rb index 20b8ca0cc4..58268540e5 100644 --- a/activemodel/lib/active_model/type/immutable_string.rb +++ b/activemodel/lib/active_model/type/immutable_string.rb @@ -16,14 +16,15 @@ module ActiveModel private - def cast_value(value) - result = case value - when true then "t" - when false then "f" - else value.to_s - end - result.freeze - end + def cast_value(value) + result = \ + case value + when true then "t" + when false then "f" + else value.to_s + end + result.freeze + end end end end diff --git a/activemodel/lib/active_model/type/integer.rb b/activemodel/lib/active_model/type/integer.rb index eea2280b22..41dd655a5c 100644 --- a/activemodel/lib/active_model/type/integer.rb +++ b/activemodel/lib/active_model/type/integer.rb @@ -31,36 +31,36 @@ module ActiveModel protected - attr_reader :range + attr_reader :range private - def cast_value(value) - case value - when true then 1 - when false then 0 - else - value.to_i rescue nil + def cast_value(value) + case value + when true then 1 + when false then 0 + else + value.to_i rescue nil + end end - end - def ensure_in_range(value) - unless range.cover?(value) - raise ActiveModel::RangeError, "#{value} is out of range for #{self.class} with limit #{_limit}" + def ensure_in_range(value) + unless range.cover?(value) + raise ActiveModel::RangeError, "#{value} is out of range for #{self.class} with limit #{_limit}" + end end - end - def max_value - 1 << (_limit * 8 - 1) # 8 bits per byte with one bit for sign - end + def max_value + 1 << (_limit * 8 - 1) # 8 bits per byte with one bit for sign + end - def min_value - -max_value - end + def min_value + -max_value + end - def _limit - self.limit || DEFAULT_LIMIT - end + def _limit + limit || DEFAULT_LIMIT + end end end end diff --git a/activemodel/lib/active_model/type/registry.rb b/activemodel/lib/active_model/type/registry.rb index adc88eb624..d25f1a129e 100644 --- a/activemodel/lib/active_model/type/registry.rb +++ b/activemodel/lib/active_model/type/registry.rb @@ -23,17 +23,17 @@ module ActiveModel protected - attr_reader :registrations + attr_reader :registrations private - def registration_klass - Registration - end + def registration_klass + Registration + end - def find_registration(symbol, *args) - registrations.find { |r| r.matches?(symbol, *args) } - end + def find_registration(symbol, *args) + registrations.find { |r| r.matches?(symbol, *args) } + end end class Registration @@ -57,7 +57,7 @@ module ActiveModel protected - attr_reader :name, :block + attr_reader :name, :block end end # :startdoc: diff --git a/activemodel/lib/active_model/type/string.rb b/activemodel/lib/active_model/type/string.rb index 8a91410998..c7e0208a5a 100644 --- a/activemodel/lib/active_model/type/string.rb +++ b/activemodel/lib/active_model/type/string.rb @@ -11,9 +11,9 @@ module ActiveModel private - def cast_value(value) - ::String.new(super) - end + def cast_value(value) + ::String.new(super) + end end end end diff --git a/activemodel/lib/active_model/type/text.rb b/activemodel/lib/active_model/type/text.rb index 1ad04daba4..7c0d647706 100644 --- a/activemodel/lib/active_model/type/text.rb +++ b/activemodel/lib/active_model/type/text.rb @@ -1,4 +1,4 @@ -require 'active_model/type/string' +require "active_model/type/string" module ActiveModel module Type diff --git a/activemodel/lib/active_model/type/time.rb b/activemodel/lib/active_model/type/time.rb index 34e09f0aba..54d6214e81 100644 --- a/activemodel/lib/active_model/type/time.rb +++ b/activemodel/lib/active_model/type/time.rb @@ -25,22 +25,22 @@ module ActiveModel private - def cast_value(value) - return value unless value.is_a?(::String) - return if value.empty? - - if value =~ /^2000-01-01/ - dummy_time_value = value - else - dummy_time_value = "2000-01-01 #{value}" + def cast_value(value) + return value unless value.is_a?(::String) + return if value.empty? + + if value.start_with?("2000-01-01") + dummy_time_value = value + else + dummy_time_value = "2000-01-01 #{value}" + end + + fast_string_to_time(dummy_time_value) || begin + time_hash = ::Date._parse(dummy_time_value) + return if time_hash[:hour].nil? + new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)) + end end - - fast_string_to_time(dummy_time_value) || begin - time_hash = ::Date._parse(dummy_time_value) - return if time_hash[:hour].nil? - new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)) - end - end end end end diff --git a/activemodel/lib/active_model/type/unsigned_integer.rb b/activemodel/lib/active_model/type/unsigned_integer.rb index 3f49f9f5f7..288fa23efe 100644 --- a/activemodel/lib/active_model/type/unsigned_integer.rb +++ b/activemodel/lib/active_model/type/unsigned_integer.rb @@ -3,13 +3,13 @@ module ActiveModel class UnsignedInteger < Integer # :nodoc: private - def max_value - super * 2 - end + def max_value + super * 2 + end - def min_value - 0 - end + def min_value + 0 + end end end end diff --git a/activemodel/lib/active_model/type/value.rb b/activemodel/lib/active_model/type/value.rb index 0d2d6873a8..7e9ae92245 100644 --- a/activemodel/lib/active_model/type/value.rb +++ b/activemodel/lib/active_model/type/value.rb @@ -105,12 +105,12 @@ module ActiveModel private - # Convenience method for types which do not need separate type casting - # behavior for user and database inputs. Called by Value#cast for - # values except +nil+. - def cast_value(value) # :doc: - value - end + # Convenience method for types which do not need separate type casting + # behavior for user and database inputs. Called by Value#cast for + # values except +nil+. + def cast_value(value) # :doc: + value + end end end end diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index a10d2285a2..df6d3f2bcb 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -1,9 +1,8 @@ -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/hash/except' +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/hash/except" module ActiveModel - # == Active \Model \Validations # # Provides a full validation framework to your objects. diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index a04e5f347e..4fadc795cd 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -1,5 +1,4 @@ module ActiveModel - module Validations class AcceptanceValidator < EachValidator # :nodoc: def initialize(options) @@ -15,58 +14,58 @@ module ActiveModel private - def setup!(klass) - klass.include(LazilyDefineAttributes.new(AttributeDefinition.new(attributes))) - end + def setup!(klass) + klass.include(LazilyDefineAttributes.new(AttributeDefinition.new(attributes))) + end - def acceptable_option?(value) - Array(options[:accept]).include?(value) - end + def acceptable_option?(value) + Array(options[:accept]).include?(value) + end - class LazilyDefineAttributes < Module - def initialize(attribute_definition) - define_method(:respond_to_missing?) do |method_name, include_private=false| - super(method_name, include_private) || attribute_definition.matches?(method_name) - end + class LazilyDefineAttributes < Module + def initialize(attribute_definition) + define_method(:respond_to_missing?) do |method_name, include_private=false| + super(method_name, include_private) || attribute_definition.matches?(method_name) + end - define_method(:method_missing) do |method_name, *args, &block| - if attribute_definition.matches?(method_name) - attribute_definition.define_on(self.class) - send(method_name, *args, &block) - else - super(method_name, *args, &block) + define_method(:method_missing) do |method_name, *args, &block| + if attribute_definition.matches?(method_name) + attribute_definition.define_on(self.class) + send(method_name, *args, &block) + else + super(method_name, *args, &block) + end end end end - end - class AttributeDefinition - def initialize(attributes) - @attributes = attributes.map(&:to_s) - end + class AttributeDefinition + def initialize(attributes) + @attributes = attributes.map(&:to_s) + end - def matches?(method_name) - attr_name = convert_to_reader_name(method_name) - attributes.include?(attr_name) - end + def matches?(method_name) + attr_name = convert_to_reader_name(method_name) + attributes.include?(attr_name) + end - def define_on(klass) - attr_readers = attributes.reject { |name| klass.attribute_method?(name) } - attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") } - klass.send(:attr_reader, *attr_readers) - klass.send(:attr_writer, *attr_writers) - end + def define_on(klass) + attr_readers = attributes.reject { |name| klass.attribute_method?(name) } + attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") } + klass.send(:attr_reader, *attr_readers) + klass.send(:attr_writer, *attr_writers) + end - protected + protected - attr_reader :attributes + attr_reader :attributes - private + private - def convert_to_reader_name(method_name) - method_name.to_s.chomp('=') + def convert_to_reader_name(method_name) + method_name.to_s.chomp("=") + end end - end end module HelperMethods diff --git a/activemodel/lib/active_model/validations/clusivity.rb b/activemodel/lib/active_model/validations/clusivity.rb index d49af603bb..18f1056e2b 100644 --- a/activemodel/lib/active_model/validations/clusivity.rb +++ b/activemodel/lib/active_model/validations/clusivity.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/range' +require "active_support/core_ext/range" module ActiveModel module Validations @@ -16,12 +16,12 @@ module ActiveModel def include?(record, value) members = if delimiter.respond_to?(:call) - delimiter.call(record) - elsif delimiter.respond_to?(:to_sym) - record.send(delimiter) - else - delimiter - end + delimiter.call(record) + elsif delimiter.respond_to?(:to_sym) + record.send(delimiter) + else + delimiter + end members.send(inclusion_method(members), value) end diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index 8f8ade90bb..33ca6f6946 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -1,5 +1,4 @@ module ActiveModel - module Validations class ConfirmationValidator < EachValidator # :nodoc: def initialize(options) @@ -17,23 +16,23 @@ module ActiveModel end private - def setup!(klass) - klass.send(:attr_reader, *attributes.map do |attribute| - :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation") - end.compact) + def setup!(klass) + klass.send(:attr_reader, *attributes.map do |attribute| + :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation") + end.compact) - klass.send(:attr_writer, *attributes.map do |attribute| - :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=") - end.compact) - end + klass.send(:attr_writer, *attributes.map do |attribute| + :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=") + end.compact) + end - def confirmation_value_equal?(record, attribute, value, confirmed) - if !options[:case_sensitive] && value.is_a?(String) - value.casecmp(confirmed) == 0 - else - value == confirmed + def confirmation_value_equal?(record, attribute, value, confirmed) + if !options[:case_sensitive] && value.is_a?(String) + value.casecmp(confirmed) == 0 + else + value == confirmed + end end - end end module HelperMethods diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index 6f4276cc2a..82a1893823 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -1,7 +1,6 @@ require "active_model/validations/clusivity" module ActiveModel - module Validations class ExclusionValidator < EachValidator # :nodoc: include Clusivity diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index 46a2e54fba..e4ea42f8f4 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -1,5 +1,6 @@ -module ActiveModel +require "active_support/core_ext/regexp" +module ActiveModel module Validations class FormatValidator < EachValidator # :nodoc: def validate_each(record, attribute, value) @@ -8,7 +9,7 @@ module ActiveModel record_error(record, attribute, :with, value) if value.to_s !~ regexp elsif options[:without] regexp = option_call(record, :without) - record_error(record, attribute, :without, value) if value.to_s =~ regexp + record_error(record, attribute, :without, value) if regexp.match?(value.to_s) end end @@ -23,33 +24,33 @@ module ActiveModel private - def option_call(record, name) - option = options[name] - option.respond_to?(:call) ? option.call(record) : option - end + def option_call(record, name) + option = options[name] + option.respond_to?(:call) ? option.call(record) : option + end - def record_error(record, attribute, name, value) - record.errors.add(attribute, :invalid, options.except(name).merge!(value: value)) - end + def record_error(record, attribute, name, value) + record.errors.add(attribute, :invalid, options.except(name).merge!(value: value)) + end - def check_options_validity(name) - if option = options[name] - if option.is_a?(Regexp) - if options[:multiline] != true && regexp_using_multiline_anchors?(option) - raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \ - "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \ - ":multiline => true option?" + def check_options_validity(name) + if option = options[name] + if option.is_a?(Regexp) + if options[:multiline] != true && regexp_using_multiline_anchors?(option) + raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \ + "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \ + ":multiline => true option?" + end + elsif !option.respond_to?(:call) + raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}" end - elsif !option.respond_to?(:call) - raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}" end end - end - def regexp_using_multiline_anchors?(regexp) - source = regexp.source - source.start_with?("^") || (source.end_with?("$") && !source.end_with?("\\$")) - end + def regexp_using_multiline_anchors?(regexp) + source = regexp.source + source.start_with?("^") || (source.end_with?("$") && !source.end_with?("\\$")) + end end module HelperMethods diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 03e0ef56d8..0ea6012a5d 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -1,7 +1,6 @@ require "active_model/validations/clusivity" module ActiveModel - module Validations class InclusionValidator < EachValidator # :nodoc: include Clusivity diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 79297ac119..f73f16830f 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -6,7 +6,7 @@ module ActiveModel MESSAGES = { is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze CHECKS = { is: :==, minimum: :>=, maximum: :<= }.freeze - RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long] + RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :too_short, :too_long] def initialize(options) if range = (options.delete(:in) || options.delete(:within)) @@ -18,27 +18,6 @@ module ActiveModel options[:minimum] = 1 end - if options[:tokenizer] - ActiveSupport::Deprecation.warn(<<-EOS.strip_heredoc) - The `:tokenizer` option is deprecated, and will be removed in Rails 5.1. - You can achieve the same functionality by defining an instance method - with the value that you want to validate the length of. For example, - - validates_length_of :essay, minimum: 100, - tokenizer: ->(str) { str.scan(/\w+/) } - - should be written as - - validates_length_of :words_in_essay, minimum: 100 - - private - - def words_in_essay - essay.scan(/\w+/) - end - EOS - end - super end @@ -46,7 +25,7 @@ module ActiveModel keys = CHECKS.keys & options.keys if keys.empty? - raise ArgumentError, 'Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.' + raise ArgumentError, "Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option." end keys.each do |key| @@ -59,7 +38,6 @@ module ActiveModel end def validate_each(record, attribute, value) - value = tokenize(record, value) value_length = value.respond_to?(:length) ? value.length : value.to_s.length errors_options = options.except(*RESERVED_OPTIONS) @@ -80,24 +58,12 @@ module ActiveModel end private - def tokenize(record, value) - tokenizer = options[:tokenizer] - if tokenizer && value.kind_of?(String) - if tokenizer.kind_of?(Proc) - tokenizer.call(value) - elsif record.respond_to?(tokenizer) - record.send(tokenizer, value) - end - end || value - end - - def skip_nil_check?(key) - key == :maximum && options[:allow_nil].nil? && options[:allow_blank].nil? - end + def skip_nil_check?(key) + key == :maximum && options[:allow_nil].nil? && options[:allow_blank].nil? + end end module HelperMethods - # Validates that the specified attributes match the length restrictions # supplied. Only one constraint option can be used at a time apart from # +:minimum+ and +:maximum+ that can be combined together: diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 9a0a0655de..48e0e5c9f6 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -1,5 +1,4 @@ module ActiveModel - module Validations class NumericalityValidator < EachValidator # :nodoc: CHECKS = { greater_than: :>, greater_than_or_equal_to: :>=, @@ -27,8 +26,6 @@ module ActiveModel raw_value = value end - return if options[:allow_nil] && raw_value.nil? - unless is_number?(raw_value) record.errors.add(attr_name, :not_a_number, filtered_options(raw_value)) return @@ -99,10 +96,10 @@ module ActiveModel private - def record_attribute_changed_in_place?(record, attr_name) - record.respond_to?(:attribute_changed_in_place?) && - record.attribute_changed_in_place?(attr_name.to_s) - end + def record_attribute_changed_in_place?(record, attr_name) + record.respond_to?(:attribute_changed_in_place?) && + record.attribute_changed_in_place?(attr_name.to_s) + end end module HelperMethods diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb index 5d593274eb..0c11cf4265 100644 --- a/activemodel/lib/active_model/validations/presence.rb +++ b/activemodel/lib/active_model/validations/presence.rb @@ -1,6 +1,5 @@ module ActiveModel - module Validations class PresenceValidator < EachValidator # :nodoc: def validate_each(record, attr_name, value) diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index 1da4df21e7..c3cbb6e291 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/slice' +require "active_support/core_ext/hash/slice" module ActiveModel module Validations @@ -115,7 +115,7 @@ module ActiveModel key = "#{key.to_s.camelize}Validator" begin - validator = key.include?('::'.freeze) ? key.constantize : const_get(key) + validator = key.include?("::".freeze) ? key.constantize : const_get(key) rescue NameError raise ArgumentError, "Unknown validator: '#{key}'" end diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb index 6de01b3392..6ae9630d82 100644 --- a/activemodel/lib/active_model/validations/with.rb +++ b/activemodel/lib/active_model/validations/with.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/array/extract_options" + module ActiveModel module Validations class WithValidator < EachValidator # :nodoc: diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index 699f74ed17..9c6065f61f 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -1,7 +1,6 @@ require "active_support/core_ext/module/anonymous" module ActiveModel - # == Active \Model \Validator # # A simple base class that can be used along with @@ -100,7 +99,7 @@ module ActiveModel # PresenceValidator.kind # => :presence # UniquenessValidator.kind # => :uniqueness def self.kind - @kind ||= name.split('::').last.underscore.chomp('_validator').to_sym unless anonymous? + @kind ||= name.split("::").last.underscore.chomp("_validator").to_sym unless anonymous? end # Accepts options that will be made available through the +options+ reader. @@ -175,8 +174,8 @@ module ActiveModel private - def validate_each(record, attribute, value) - @block.call(record, attribute, value) - end + def validate_each(record, attribute, value) + @block.call(record, attribute, value) + end end end diff --git a/activemodel/lib/active_model/version.rb b/activemodel/lib/active_model/version.rb index 6da3b4117b..6e7fd227fd 100644 --- a/activemodel/lib/active_model/version.rb +++ b/activemodel/lib/active_model/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActiveModel # Returns the version of the currently loaded \Active \Model as a <tt>Gem::Version</tt> diff --git a/activemodel/test/cases/attribute_assignment_test.rb b/activemodel/test/cases/attribute_assignment_test.rb index 287bea719c..8eb389d331 100644 --- a/activemodel/test/cases/attribute_assignment_test.rb +++ b/activemodel/test/cases/attribute_assignment_test.rb @@ -18,7 +18,7 @@ class AttributeAssignmentTest < ActiveModel::TestCase protected - attr_writer :metadata + attr_writer :metadata end class ErrorFromAttributeWriter < StandardError diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb index e81b7ac424..4767accb7c 100644 --- a/activemodel/test/cases/attribute_methods_test.rb +++ b/activemodel/test/cases/attribute_methods_test.rb @@ -1,16 +1,16 @@ -require 'cases/helper' +require "cases/helper" class ModelWithAttributes include ActiveModel::AttributeMethods class << self define_method(:bar) do - 'original bar' + "original bar" end end def attributes - { foo: 'value of foo', baz: 'value of baz' } + { foo: "value of foo", baz: "value of baz" } end private @@ -24,7 +24,7 @@ class ModelWithAttributes2 attr_accessor :attributes - attribute_method_suffix '_test' + attribute_method_suffix "_test" private def attribute(name) @@ -48,7 +48,7 @@ class ModelWithAttributesWithSpaces include ActiveModel::AttributeMethods def attributes - { :'foo bar' => 'value of foo bar'} + { 'foo bar': "value of foo bar" } end private @@ -62,12 +62,12 @@ class ModelWithWeirdNamesAttributes class << self define_method(:'c?d') do - 'original c?d' + "original c?d" end end def attributes - { :'a?b' => 'value of a?b' } + { 'a?b': "value of a?b" } end private @@ -80,7 +80,7 @@ class ModelWithRubyKeywordNamedAttributes include ActiveModel::AttributeMethods def attributes - { begin: 'value of begin', end: 'value of end' } + { begin: "value of begin", end: "value of end" } end private @@ -94,16 +94,16 @@ class ModelWithoutAttributesMethod end class AttributeMethodsTest < ActiveModel::TestCase - test 'method missing works correctly even if attributes method is not defined' do + test "method missing works correctly even if attributes method is not defined" do assert_raises(NoMethodError) { ModelWithoutAttributesMethod.new.foo } end - test 'unrelated classes should not share attribute method matchers' do + test "unrelated classes should not share attribute method matchers" do assert_not_equal ModelWithAttributes.send(:attribute_method_matchers), ModelWithAttributes2.send(:attribute_method_matchers) end - test '#define_attribute_method generates attribute method' do + test "#define_attribute_method generates attribute method" do begin ModelWithAttributes.define_attribute_method(:foo) @@ -114,19 +114,19 @@ class AttributeMethodsTest < ActiveModel::TestCase end end - test '#define_attribute_method does not generate attribute method if already defined in attribute module' do + test "#define_attribute_method does not generate attribute method if already defined in attribute module" do klass = Class.new(ModelWithAttributes) klass.generated_attribute_methods.module_eval do def foo - '<3' + "<3" end end klass.define_attribute_method(:foo) - assert_equal '<3', klass.new.foo + assert_equal "<3", klass.new.foo end - test '#define_attribute_method generates a method that is already defined on the host' do + test "#define_attribute_method generates a method that is already defined on the host" do klass = Class.new(ModelWithAttributes) do def foo super @@ -134,21 +134,21 @@ class AttributeMethodsTest < ActiveModel::TestCase end klass.define_attribute_method(:foo) - assert_equal 'value of foo', klass.new.foo + assert_equal "value of foo", klass.new.foo end - test '#define_attribute_method generates attribute method with invalid identifier characters' do + test "#define_attribute_method generates attribute method with invalid identifier characters" do begin ModelWithWeirdNamesAttributes.define_attribute_method(:'a?b') assert_respond_to ModelWithWeirdNamesAttributes.new, :'a?b' - assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.send('a?b') + assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.send("a?b") ensure ModelWithWeirdNamesAttributes.undefine_attribute_methods end end - test '#define_attribute_methods works passing multiple arguments' do + test "#define_attribute_methods works passing multiple arguments" do begin ModelWithAttributes.define_attribute_methods(:foo, :baz) @@ -159,7 +159,7 @@ class AttributeMethodsTest < ActiveModel::TestCase end end - test '#define_attribute_methods generates attribute methods' do + test "#define_attribute_methods generates attribute methods" do begin ModelWithAttributes.define_attribute_methods(:foo) @@ -170,7 +170,7 @@ class AttributeMethodsTest < ActiveModel::TestCase end end - test '#alias_attribute generates attribute_aliases lookup hash' do + test "#alias_attribute generates attribute_aliases lookup hash" do klass = Class.new(ModelWithAttributes) do define_attribute_methods :foo alias_attribute :bar, :foo @@ -179,7 +179,7 @@ class AttributeMethodsTest < ActiveModel::TestCase assert_equal({ "bar" => "foo" }, klass.attribute_aliases) end - test '#define_attribute_methods generates attribute methods with spaces in their names' do + test "#define_attribute_methods generates attribute methods with spaces in their names" do begin ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar') @@ -190,7 +190,7 @@ class AttributeMethodsTest < ActiveModel::TestCase end end - test '#alias_attribute works with attributes with spaces in their names' do + test "#alias_attribute works with attributes with spaces in their names" do begin ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar') ModelWithAttributesWithSpaces.alias_attribute(:'foo_bar', :'foo bar') @@ -201,7 +201,7 @@ class AttributeMethodsTest < ActiveModel::TestCase end end - test '#alias_attribute works with attributes named as a ruby keyword' do + test "#alias_attribute works with attributes named as a ruby keyword" do begin ModelWithRubyKeywordNamedAttributes.define_attribute_methods([:begin, :end]) ModelWithRubyKeywordNamedAttributes.alias_attribute(:from, :begin) @@ -214,7 +214,7 @@ class AttributeMethodsTest < ActiveModel::TestCase end end - test '#undefine_attribute_methods removes attribute methods' do + test "#undefine_attribute_methods removes attribute methods" do ModelWithAttributes.define_attribute_methods(:foo) ModelWithAttributes.undefine_attribute_methods @@ -222,21 +222,21 @@ class AttributeMethodsTest < ActiveModel::TestCase assert_raises(NoMethodError) { ModelWithAttributes.new.foo } end - test 'accessing a suffixed attribute' do + test "accessing a suffixed attribute" do m = ModelWithAttributes2.new - m.attributes = { 'foo' => 'bar' } + m.attributes = { "foo" => "bar" } - assert_equal 'bar', m.foo - assert_equal 'bar', m.foo_test + assert_equal "bar", m.foo + assert_equal "bar", m.foo_test end - test 'should not interfere with method_missing if the attr has a private/protected method' do + test "should not interfere with method_missing if the attr has a private/protected method" do m = ModelWithAttributes2.new - m.attributes = { 'private_method' => '<3', 'protected_method' => 'O_o' } + m.attributes = { "private_method" => "<3", "protected_method" => "O_o" } # dispatches to the *method*, not the attribute - assert_equal '<3 <3', m.send(:private_method) - assert_equal 'O_o O_o', m.send(:protected_method) + assert_equal "<3 <3", m.send(:private_method) + assert_equal "O_o O_o", m.send(:protected_method) # sees that a method is already defined, so doesn't intervene assert_raises(NoMethodError) { m.private_method } @@ -245,13 +245,13 @@ class AttributeMethodsTest < ActiveModel::TestCase class ClassWithProtected protected - def protected_method - end + def protected_method + end end - test 'should not interfere with respond_to? if the attribute has a private/protected method' do + test "should not interfere with respond_to? if the attribute has a private/protected method" do m = ModelWithAttributes2.new - m.attributes = { 'private_method' => '<3', 'protected_method' => 'O_o' } + m.attributes = { "private_method" => "<3", "protected_method" => "O_o" } assert !m.respond_to?(:private_method) assert m.respond_to?(:private_method, true) @@ -264,9 +264,9 @@ class AttributeMethodsTest < ActiveModel::TestCase assert m.respond_to?(:protected_method, true) end - test 'should use attribute_missing to dispatch a missing attribute' do + test "should use attribute_missing to dispatch a missing attribute" do m = ModelWithAttributes2.new - m.attributes = { 'foo' => 'bar' } + m.attributes = { "foo" => "bar" } def m.attribute_missing(match, *args, &block) match @@ -274,8 +274,8 @@ class AttributeMethodsTest < ActiveModel::TestCase match = m.foo_test - assert_equal 'foo', match.attr_name - assert_equal 'attribute_test', match.target - assert_equal 'foo_test', match.method_name + assert_equal "foo", match.attr_name + assert_equal "attribute_test", match.target + assert_equal "foo_test", match.method_name end end diff --git a/activemodel/test/cases/callbacks_test.rb b/activemodel/test/cases/callbacks_test.rb index e4ecc0adb4..63b6c56f8c 100644 --- a/activemodel/test/cases/callbacks_test.rb +++ b/activemodel/test/cases/callbacks_test.rb @@ -1,7 +1,6 @@ require "cases/helper" class CallbacksTest < ActiveModel::TestCase - class CallbackValidator def around_create(model) model.callbacks << :before_around_create @@ -110,8 +109,8 @@ class CallbacksTest < ActiveModel::TestCase end extend ActiveModel::Callbacks define_model_callbacks :create - def callback1; self.history << 'callback1'; end - def callback2; self.history << 'callback2'; end + def callback1; history << "callback1"; end + def callback2; history << "callback2"; end def create run_callbacks(:create) {} self @@ -131,5 +130,4 @@ class CallbacksTest < ActiveModel::TestCase test "after_create callbacks with both callbacks declared in different lines" do assert_equal ["callback1", "callback2"], Violin2.new.create.history end - end diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb index 800cad6d9a..4a93347abc 100644 --- a/activemodel/test/cases/conversion_test.rb +++ b/activemodel/test/cases/conversion_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/contact' -require 'models/helicopter' +require "cases/helper" +require "models/contact" +require "models/helicopter" class ConversionTest < ActiveModel::TestCase test "to_model default implementation returns self" do diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb index d17a12ad12..fdd18d7601 100644 --- a/activemodel/test/cases/dirty_test.rb +++ b/activemodel/test/cases/dirty_test.rb @@ -62,13 +62,13 @@ class DirtyTest < ActiveModel::TestCase test "list of changed attribute keys" do assert_equal [], @model.changed @model.name = "Paul" - assert_equal ['name'], @model.changed + assert_equal ["name"], @model.changed end test "changes to attribute values" do - assert !@model.changes['name'] + assert !@model.changes["name"] @model.name = "John" - assert_equal [nil, "John"], @model.changes['name'] + assert_equal [nil, "John"], @model.changes["name"] end test "checking if an attribute has changed to a particular value" do @@ -84,14 +84,14 @@ class DirtyTest < ActiveModel::TestCase test "changes accessible through both strings and symbols" do @model.name = "David" assert_not_nil @model.changes[:name] - assert_not_nil @model.changes['name'] + assert_not_nil @model.changes["name"] end test "be consistent with symbols arguments after the changes are applied" do @model.name = "David" assert @model.attribute_changed?(:name) @model.save - @model.name = 'Rafael' + @model.name = "Rafael" assert @model.attribute_changed?(:name) end @@ -134,7 +134,7 @@ class DirtyTest < ActiveModel::TestCase test "saving should preserve previous changes" do @model.name = "Jericho Cane" @model.save - assert_equal [nil, "Jericho Cane"], @model.previous_changes['name'] + assert_equal [nil, "Jericho Cane"], @model.previous_changes["name"] end test "setting new attributes should not affect previous changes" do @@ -176,13 +176,13 @@ class DirtyTest < ActiveModel::TestCase end test "reload should reset all changes" do - @model.name = 'Dmitry' + @model.name = "Dmitry" @model.name_changed? @model.save - @model.name = 'Bob' + @model.name = "Bob" - assert_equal [nil, 'Dmitry'], @model.previous_changes['name'] - assert_equal 'Dmitry', @model.changed_attributes['name'] + assert_equal [nil, "Dmitry"], @model.previous_changes["name"] + assert_equal "Dmitry", @model.changed_attributes["name"] @model.reload @@ -191,30 +191,30 @@ class DirtyTest < ActiveModel::TestCase end test "restore_attributes should restore all previous data" do - @model.name = 'Dmitry' - @model.color = 'Red' + @model.name = "Dmitry" + @model.color = "Red" @model.save - @model.name = 'Bob' - @model.color = 'White' + @model.name = "Bob" + @model.color = "White" @model.restore_attributes assert_not @model.changed? - assert_equal 'Dmitry', @model.name - assert_equal 'Red', @model.color + assert_equal "Dmitry", @model.name + assert_equal "Red", @model.color end test "restore_attributes can restore only some attributes" do - @model.name = 'Dmitry' - @model.color = 'Red' + @model.name = "Dmitry" + @model.color = "Red" @model.save - @model.name = 'Bob' - @model.color = 'White' + @model.name = "Bob" + @model.color = "White" - @model.restore_attributes(['name']) + @model.restore_attributes(["name"]) assert @model.changed? - assert_equal 'Dmitry', @model.name - assert_equal 'White', @model.color + assert_equal "Dmitry", @model.name + assert_equal "White", @model.color end end diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index c90ee7021c..605ad64e4d 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -29,45 +29,45 @@ class ErrorsTest < ActiveModel::TestCase def test_delete errors = ActiveModel::Errors.new(self) - errors[:foo] << 'omg' + errors[:foo] << "omg" errors.delete(:foo) assert_empty errors[:foo] end def test_include? errors = ActiveModel::Errors.new(self) - errors[:foo] << 'omg' - assert errors.include?(:foo), 'errors should include :foo' + errors[:foo] << "omg" + assert_includes errors, :foo, "errors should include :foo" end def test_dup errors = ActiveModel::Errors.new(self) - errors[:foo] << 'bar' + errors[:foo] << "bar" errors_dup = errors.dup - errors_dup[:bar] << 'omg' + errors_dup[:bar] << "omg" assert_not_same errors_dup.messages, errors.messages end def test_has_key? errors = ActiveModel::Errors.new(self) - errors[:foo] << 'omg' - assert_equal true, errors.has_key?(:foo), 'errors should have key :foo' + errors[:foo] << "omg" + assert_equal true, errors.has_key?(:foo), "errors should have key :foo" end def test_has_no_key errors = ActiveModel::Errors.new(self) - assert_equal false, errors.has_key?(:name), 'errors should not have key :name' + assert_equal false, errors.has_key?(:name), "errors should not have key :name" end def test_key? errors = ActiveModel::Errors.new(self) - errors[:foo] << 'omg' - assert_equal true, errors.key?(:foo), 'errors should have key :foo' + errors[:foo] << "omg" + assert_equal true, errors.key?(:foo), "errors should have key :foo" end def test_no_key errors = ActiveModel::Errors.new(self) - assert_equal false, errors.key?(:name), 'errors should not have key :name' + assert_equal false, errors.key?(:name), "errors should not have key :name" end test "clear errors" do @@ -79,24 +79,6 @@ class ErrorsTest < ActiveModel::TestCase assert person.errors.empty? end - test "get returns the errors for the provided key" do - errors = ActiveModel::Errors.new(self) - errors[:foo] << "omg" - - assert_deprecated do - assert_equal ["omg"], errors.get(:foo) - end - end - - test "sets the error with the provided key" do - errors = ActiveModel::Errors.new(self) - assert_deprecated do - errors.set(:foo, "omg") - end - - assert_equal({ foo: "omg" }, errors.messages) - end - test "error access is indifferent" do errors = ActiveModel::Errors.new(self) errors[:foo] << "omg" @@ -125,7 +107,7 @@ class ErrorsTest < ActiveModel::TestCase person.errors[:foo] assert person.errors.empty? assert person.errors.blank? - assert !person.errors.include?(:foo) + assert_not_includes person.errors, :foo end test "include? does not add a key to messages hash" do @@ -142,14 +124,6 @@ class ErrorsTest < ActiveModel::TestCase assert_equal ["cannot be nil"], person.errors[:name] end - test "assign error" do - person = Person.new - assert_deprecated do - person.errors[:name] = 'should not be nil' - end - assert_equal ["should not be nil"], person.errors[:name] - end - test "add an error message on a specific attribute" do person = Person.new person.errors.add(:name, "cannot be blank") @@ -219,6 +193,12 @@ class ErrorsTest < ActiveModel::TestCase assert !person.errors.added?(:name, "cannot be blank") end + test "added? returns false when checking for an error, but not providing message arguments" do + person = Person.new + person.errors.add(:name, "cannot be blank") + assert !person.errors.added?(:name) + end + test "size calculates the number of error messages" do person = Person.new person.errors.add(:name, "cannot be blank") @@ -244,6 +224,16 @@ class ErrorsTest < ActiveModel::TestCase assert_equal({ name: ["cannot be blank"] }, person.errors.to_hash) end + test "to_hash returns a hash without default proc" do + person = Person.new + assert_nil person.errors.to_hash.default_proc + end + + test "as_json returns a hash without default proc" do + person = Person.new + assert_nil person.errors.as_json.default_proc + end + test "full_messages creates a list of error messages with the attribute name included" do person = Person.new person.errors.add(:name, "cannot be blank") @@ -304,72 +294,6 @@ class ErrorsTest < ActiveModel::TestCase } end - test "add_on_empty generates message" do - person = Person.new - assert_called_with(person.errors, :generate_message, [:name, :empty, {}]) do - assert_deprecated do - person.errors.add_on_empty :name - end - end - end - - test "add_on_empty generates message for multiple attributes" do - person = Person.new - expected_calls = [ [:name, :empty, {}], [:age, :empty, {}] ] - assert_called_with(person.errors, :generate_message, expected_calls) do - assert_deprecated do - person.errors.add_on_empty [:name, :age] - end - end - end - - test "add_on_empty generates message with custom default message" do - person = Person.new - assert_called_with(person.errors, :generate_message, [:name, :empty, { message: 'custom' }]) do - assert_deprecated do - person.errors.add_on_empty :name, message: 'custom' - end - end - end - - test "add_on_empty generates message with empty string value" do - person = Person.new - person.name = '' - assert_called_with(person.errors, :generate_message, [:name, :empty, {}]) do - assert_deprecated do - person.errors.add_on_empty :name - end - end - end - - test "add_on_blank generates message" do - person = Person.new - assert_called_with(person.errors, :generate_message, [:name, :blank, {}]) do - assert_deprecated do - person.errors.add_on_blank :name - end - end - end - - test "add_on_blank generates message for multiple attributes" do - person = Person.new - expected_calls = [ [:name, :blank, {}], [:age, :blank, {}] ] - assert_called_with(person.errors, :generate_message, expected_calls) do - assert_deprecated do - person.errors.add_on_blank [:name, :age] - end - end - end - - test "add_on_blank generates message with custom default message" do - person = Person.new - assert_called_with(person.errors, :generate_message, [:name, :blank, { message: 'custom' }]) do - assert_deprecated do - person.errors.add_on_blank :name, message: 'custom' - end - end - end - test "details returns added error detail" do person = Person.new person.errors.add(:name, :invalid) diff --git a/activemodel/test/cases/forbidden_attributes_protection_test.rb b/activemodel/test/cases/forbidden_attributes_protection_test.rb index d8d757f52a..d8cc72e662 100644 --- a/activemodel/test/cases/forbidden_attributes_protection_test.rb +++ b/activemodel/test/cases/forbidden_attributes_protection_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'active_support/core_ext/hash/indifferent_access' -require 'models/account' +require "cases/helper" +require "active_support/core_ext/hash/indifferent_access" +require "models/account" class ProtectedParams attr_accessor :permitted @@ -25,18 +25,18 @@ end class ActiveModelMassUpdateProtectionTest < ActiveSupport::TestCase test "forbidden attributes cannot be used for mass updating" do - params = ProtectedParams.new({ "a" => "b" }) + params = ProtectedParams.new("a" => "b") assert_raises(ActiveModel::ForbiddenAttributesError) do Account.new.sanitize_for_mass_assignment(params) end end test "permitted attributes can be used for mass updating" do - params = ProtectedParams.new({ "a" => "b" }).permit! + params = ProtectedParams.new("a" => "b").permit! assert_equal({ "a" => "b" }, Account.new.sanitize_for_mass_assignment(params)) end test "regular attributes should still be allowed" do - assert_equal({ a: "b" }, Account.new.sanitize_for_mass_assignment(a: "b")) + assert_equal({ a: "b" }, Account.new.sanitize_for_mass_assignment(a: "b")) end end diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb index c589fd2c33..4e9f43ad86 100644 --- a/activemodel/test/cases/helper.rb +++ b/activemodel/test/cases/helper.rb @@ -1,4 +1,4 @@ -require 'active_model' +require "active_model" # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true @@ -6,15 +6,15 @@ ActiveSupport::Deprecation.debug = true # Disable available locale checks to avoid warnings running the test suite. I18n.enforce_available_locales = false -require 'active_support/testing/autorun' -require 'active_support/testing/method_call_assertions' +require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" # Skips the current run on Rubinius using Minitest::Assertions#skip -def rubinius_skip(message = '') - skip message if RUBY_ENGINE == 'rbx' +def rubinius_skip(message = "") + skip message if RUBY_ENGINE == "rbx" end # Skips the current run on JRuby using Minitest::Assertions#skip -def jruby_skip(message = '') +def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end diff --git a/activemodel/test/cases/lint_test.rb b/activemodel/test/cases/lint_test.rb index 8faf93c056..7a817d7c01 100644 --- a/activemodel/test/cases/lint_test.rb +++ b/activemodel/test/cases/lint_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" class LintTest < ActiveModel::TestCase include ActiveModel::Lint::Tests diff --git a/activemodel/test/cases/model_test.rb b/activemodel/test/cases/model_test.rb index 3017f3541b..ba87cd1506 100644 --- a/activemodel/test/cases/model_test.rb +++ b/activemodel/test/cases/model_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" class ModelTest < ActiveModel::TestCase include ActiveModel::Lint::Tests @@ -9,7 +9,7 @@ class ModelTest < ActiveModel::TestCase end def initialize(*args) - @attr ||= 'default value' + @attr ||= "default value" super end end @@ -50,7 +50,7 @@ class ModelTest < ActiveModel::TestCase BasicModel.new() BasicModel.new(nil) BasicModel.new({}) - SimpleModel.new(attr: 'value') + SimpleModel.new(attr: "value") end end @@ -61,17 +61,17 @@ class ModelTest < ActiveModel::TestCase def test_mixin_inclusion_chain object = BasicModel.new - assert_equal 'default value', object.attr + assert_equal "default value", object.attr end def test_mixin_initializer_when_args_exist - object = BasicModel.new(hello: 'world') - assert_equal 'world', object.hello + object = BasicModel.new(hello: "world") + assert_equal "world", object.hello end def test_mixin_initializer_when_args_dont_exist assert_raises(ActiveModel::UnknownAttributeError) do - SimpleModel.new(hello: 'world') + SimpleModel.new(hello: "world") end end end diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb index 7b8287edbf..d5cb1a62bc 100644 --- a/activemodel/test/cases/naming_test.rb +++ b/activemodel/test/cases/naming_test.rb @@ -1,8 +1,8 @@ -require 'cases/helper' -require 'models/contact' -require 'models/sheep' -require 'models/track_back' -require 'models/blog_post' +require "cases/helper" +require "models/contact" +require "models/sheep" +require "models/track_back" +require "models/blog_post" class NamingTest < ActiveModel::TestCase def setup @@ -10,31 +10,31 @@ class NamingTest < ActiveModel::TestCase end def test_singular - assert_equal 'post_track_back', @model_name.singular + assert_equal "post_track_back", @model_name.singular end def test_plural - assert_equal 'post_track_backs', @model_name.plural + assert_equal "post_track_backs", @model_name.plural end def test_element - assert_equal 'track_back', @model_name.element + assert_equal "track_back", @model_name.element end def test_collection - assert_equal 'post/track_backs', @model_name.collection + assert_equal "post/track_backs", @model_name.collection end def test_human - assert_equal 'Track back', @model_name.human + assert_equal "Track back", @model_name.human end def test_route_key - assert_equal 'post_track_backs', @model_name.route_key + assert_equal "post_track_backs", @model_name.route_key end def test_param_key - assert_equal 'post_track_back', @model_name.param_key + assert_equal "post_track_back", @model_name.param_key end def test_i18n_key @@ -48,31 +48,31 @@ class NamingWithNamespacedModelInIsolatedNamespaceTest < ActiveModel::TestCase end def test_singular - assert_equal 'blog_post', @model_name.singular + assert_equal "blog_post", @model_name.singular end def test_plural - assert_equal 'blog_posts', @model_name.plural + assert_equal "blog_posts", @model_name.plural end def test_element - assert_equal 'post', @model_name.element + assert_equal "post", @model_name.element end def test_collection - assert_equal 'blog/posts', @model_name.collection + assert_equal "blog/posts", @model_name.collection end def test_human - assert_equal 'Post', @model_name.human + assert_equal "Post", @model_name.human end def test_route_key - assert_equal 'posts', @model_name.route_key + assert_equal "posts", @model_name.route_key end def test_param_key - assert_equal 'post', @model_name.param_key + assert_equal "post", @model_name.param_key end def test_i18n_key @@ -86,31 +86,31 @@ class NamingWithNamespacedModelInSharedNamespaceTest < ActiveModel::TestCase end def test_singular - assert_equal 'blog_post', @model_name.singular + assert_equal "blog_post", @model_name.singular end def test_plural - assert_equal 'blog_posts', @model_name.plural + assert_equal "blog_posts", @model_name.plural end def test_element - assert_equal 'post', @model_name.element + assert_equal "post", @model_name.element end def test_collection - assert_equal 'blog/posts', @model_name.collection + assert_equal "blog/posts", @model_name.collection end def test_human - assert_equal 'Post', @model_name.human + assert_equal "Post", @model_name.human end def test_route_key - assert_equal 'blog_posts', @model_name.route_key + assert_equal "blog_posts", @model_name.route_key end def test_param_key - assert_equal 'blog_post', @model_name.param_key + assert_equal "blog_post", @model_name.param_key end def test_i18n_key @@ -120,35 +120,35 @@ end class NamingWithSuppliedModelNameTest < ActiveModel::TestCase def setup - @model_name = ActiveModel::Name.new(Blog::Post, nil, 'Article') + @model_name = ActiveModel::Name.new(Blog::Post, nil, "Article") end def test_singular - assert_equal 'article', @model_name.singular + assert_equal "article", @model_name.singular end def test_plural - assert_equal 'articles', @model_name.plural + assert_equal "articles", @model_name.plural end def test_element - assert_equal 'article', @model_name.element + assert_equal "article", @model_name.element end def test_collection - assert_equal 'articles', @model_name.collection + assert_equal "articles", @model_name.collection end def test_human - assert_equal 'Article', @model_name.human + assert_equal "Article", @model_name.human end def test_route_key - assert_equal 'articles', @model_name.route_key + assert_equal "articles", @model_name.route_key end def test_param_key - assert_equal 'article', @model_name.param_key + assert_equal "article", @model_name.param_key end def test_i18n_key @@ -162,31 +162,31 @@ class NamingUsingRelativeModelNameTest < ActiveModel::TestCase end def test_singular - assert_equal 'blog_post', @model_name.singular + assert_equal "blog_post", @model_name.singular end def test_plural - assert_equal 'blog_posts', @model_name.plural + assert_equal "blog_posts", @model_name.plural end def test_element - assert_equal 'post', @model_name.element + assert_equal "post", @model_name.element end def test_collection - assert_equal 'blog/posts', @model_name.collection + assert_equal "blog/posts", @model_name.collection end def test_human - assert_equal 'Post', @model_name.human + assert_equal "Post", @model_name.human end def test_route_key - assert_equal 'posts', @model_name.route_key + assert_equal "posts", @model_name.route_key end def test_param_key - assert_equal 'post', @model_name.param_key + assert_equal "post", @model_name.param_key end def test_i18n_key @@ -198,16 +198,16 @@ class NamingHelpersTest < ActiveModel::TestCase def setup @klass = Contact @record = @klass.new - @singular = 'contact' - @plural = 'contacts' + @singular = "contact" + @plural = "contacts" @uncountable = Sheep - @singular_route_key = 'contact' - @route_key = 'contacts' - @param_key = 'contact' + @singular_route_key = "contact" + @route_key = "contacts" + @param_key = "contact" end def test_to_model_called_on_record - assert_equal 'post_named_track_backs', plural(Post::TrackBack.new) + assert_equal "post_named_track_backs", plural(Post::TrackBack.new) end def test_singular diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb index 96b3b07e50..a56b26b5ee 100644 --- a/activemodel/test/cases/railtie_test.rb +++ b/activemodel/test/cases/railtie_test.rb @@ -1,11 +1,11 @@ -require 'cases/helper' -require 'active_support/testing/isolation' +require "cases/helper" +require "active_support/testing/isolation" class RailtieTest < ActiveModel::TestCase include ActiveSupport::Testing::Isolation def setup - require 'active_model/railtie' + require "active_model/railtie" # Set a fake logger to avoid creating the log directory automatically fake_logger = Logger.new(nil) @@ -16,15 +16,15 @@ class RailtieTest < ActiveModel::TestCase end end - test 'secure password min_cost is false in the development environment' do - Rails.env = 'development' + test "secure password min_cost is false in the development environment" do + Rails.env = "development" @app.initialize! assert_equal false, ActiveModel::SecurePassword.min_cost end - test 'secure password min_cost is true in the test environment' do - Rails.env = 'test' + test "secure password min_cost is true in the test environment" do + Rails.env = "test" @app.initialize! assert_equal true, ActiveModel::SecurePassword.min_cost diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb index 6d56c8344a..9423df2c09 100644 --- a/activemodel/test/cases/secure_password_test.rb +++ b/activemodel/test/cases/secure_password_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/user' -require 'models/visitor' +require "cases/helper" +require "models/user" +require "models/visitor" class SecurePasswordTest < ActiveModel::TestCase setup do @@ -13,7 +13,7 @@ class SecurePasswordTest < ActiveModel::TestCase # Simulate loading an existing user from the DB @existing_user = User.new - @existing_user.password_digest = BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST) + @existing_user.password_digest = BCrypt::Password.create("password", cost: BCrypt::Engine::MIN_COST) end teardown do @@ -29,152 +29,152 @@ class SecurePasswordTest < ActiveModel::TestCase end test "create a new user with validations and valid password/confirmation" do - @user.password = 'password' - @user.password_confirmation = 'password' + @user.password = "password" + @user.password_confirmation = "password" - assert @user.valid?(:create), 'user should be valid' + assert @user.valid?(:create), "user should be valid" - @user.password = 'a' * 72 - @user.password_confirmation = 'a' * 72 + @user.password = "a" * 72 + @user.password_confirmation = "a" * 72 - assert @user.valid?(:create), 'user should be valid' + assert @user.valid?(:create), "user should be valid" end test "create a new user with validation and a spaces only password" do - @user.password = ' ' * 72 - assert @user.valid?(:create), 'user should be valid' + @user.password = " " * 72 + assert @user.valid?(:create), "user should be valid" end test "create a new user with validation and a blank password" do - @user.password = '' - assert !@user.valid?(:create), 'user should be invalid' + @user.password = "" + assert !@user.valid?(:create), "user should be invalid" assert_equal 1, @user.errors.count assert_equal ["can't be blank"], @user.errors[:password] end test "create a new user with validation and a nil password" do @user.password = nil - assert !@user.valid?(:create), 'user should be invalid' + assert !@user.valid?(:create), "user should be invalid" assert_equal 1, @user.errors.count assert_equal ["can't be blank"], @user.errors[:password] end - test 'create a new user with validation and password length greater than 72' do - @user.password = 'a' * 73 - @user.password_confirmation = 'a' * 73 - assert !@user.valid?(:create), 'user should be invalid' + test "create a new user with validation and password length greater than 72" do + @user.password = "a" * 73 + @user.password_confirmation = "a" * 73 + assert !@user.valid?(:create), "user should be invalid" assert_equal 1, @user.errors.count assert_equal ["is too long (maximum is 72 characters)"], @user.errors[:password] end test "create a new user with validation and a blank password confirmation" do - @user.password = 'password' - @user.password_confirmation = '' - assert !@user.valid?(:create), 'user should be invalid' + @user.password = "password" + @user.password_confirmation = "" + assert !@user.valid?(:create), "user should be invalid" assert_equal 1, @user.errors.count assert_equal ["doesn't match Password"], @user.errors[:password_confirmation] end test "create a new user with validation and a nil password confirmation" do - @user.password = 'password' + @user.password = "password" @user.password_confirmation = nil - assert @user.valid?(:create), 'user should be valid' + assert @user.valid?(:create), "user should be valid" end test "create a new user with validation and an incorrect password confirmation" do - @user.password = 'password' - @user.password_confirmation = 'something else' - assert !@user.valid?(:create), 'user should be invalid' + @user.password = "password" + @user.password_confirmation = "something else" + assert !@user.valid?(:create), "user should be invalid" assert_equal 1, @user.errors.count assert_equal ["doesn't match Password"], @user.errors[:password_confirmation] end test "update an existing user with validation and no change in password" do - assert @existing_user.valid?(:update), 'user should be valid' + assert @existing_user.valid?(:update), "user should be valid" end test "update an existing user with validations and valid password/confirmation" do - @existing_user.password = 'password' - @existing_user.password_confirmation = 'password' + @existing_user.password = "password" + @existing_user.password_confirmation = "password" - assert @existing_user.valid?(:update), 'user should be valid' + assert @existing_user.valid?(:update), "user should be valid" - @existing_user.password = 'a' * 72 - @existing_user.password_confirmation = 'a' * 72 + @existing_user.password = "a" * 72 + @existing_user.password_confirmation = "a" * 72 - assert @existing_user.valid?(:update), 'user should be valid' + assert @existing_user.valid?(:update), "user should be valid" end test "updating an existing user with validation and a blank password" do - @existing_user.password = '' - assert @existing_user.valid?(:update), 'user should be valid' + @existing_user.password = "" + assert @existing_user.valid?(:update), "user should be valid" end test "updating an existing user with validation and a spaces only password" do - @user.password = ' ' * 72 - assert @user.valid?(:update), 'user should be valid' + @user.password = " " * 72 + assert @user.valid?(:update), "user should be valid" end test "updating an existing user with validation and a blank password and password_confirmation" do - @existing_user.password = '' - @existing_user.password_confirmation = '' - assert @existing_user.valid?(:update), 'user should be valid' + @existing_user.password = "" + @existing_user.password_confirmation = "" + assert @existing_user.valid?(:update), "user should be valid" end test "updating an existing user with validation and a nil password" do @existing_user.password = nil - assert !@existing_user.valid?(:update), 'user should be invalid' + assert !@existing_user.valid?(:update), "user should be invalid" assert_equal 1, @existing_user.errors.count assert_equal ["can't be blank"], @existing_user.errors[:password] end - test 'updating an existing user with validation and password length greater than 72' do - @existing_user.password = 'a' * 73 - @existing_user.password_confirmation = 'a' * 73 - assert !@existing_user.valid?(:update), 'user should be invalid' + test "updating an existing user with validation and password length greater than 72" do + @existing_user.password = "a" * 73 + @existing_user.password_confirmation = "a" * 73 + assert !@existing_user.valid?(:update), "user should be invalid" assert_equal 1, @existing_user.errors.count assert_equal ["is too long (maximum is 72 characters)"], @existing_user.errors[:password] end test "updating an existing user with validation and a blank password confirmation" do - @existing_user.password = 'password' - @existing_user.password_confirmation = '' - assert !@existing_user.valid?(:update), 'user should be invalid' + @existing_user.password = "password" + @existing_user.password_confirmation = "" + assert !@existing_user.valid?(:update), "user should be invalid" assert_equal 1, @existing_user.errors.count assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation] end test "updating an existing user with validation and a nil password confirmation" do - @existing_user.password = 'password' + @existing_user.password = "password" @existing_user.password_confirmation = nil - assert @existing_user.valid?(:update), 'user should be valid' + assert @existing_user.valid?(:update), "user should be valid" end test "updating an existing user with validation and an incorrect password confirmation" do - @existing_user.password = 'password' - @existing_user.password_confirmation = 'something else' - assert !@existing_user.valid?(:update), 'user should be invalid' + @existing_user.password = "password" + @existing_user.password_confirmation = "something else" + assert !@existing_user.valid?(:update), "user should be invalid" assert_equal 1, @existing_user.errors.count assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation] end test "updating an existing user with validation and a blank password digest" do - @existing_user.password_digest = '' - assert !@existing_user.valid?(:update), 'user should be invalid' + @existing_user.password_digest = "" + assert !@existing_user.valid?(:update), "user should be invalid" assert_equal 1, @existing_user.errors.count assert_equal ["can't be blank"], @existing_user.errors[:password] end test "updating an existing user with validation and a nil password digest" do @existing_user.password_digest = nil - assert !@existing_user.valid?(:update), 'user should be invalid' + assert !@existing_user.valid?(:update), "user should be invalid" assert_equal 1, @existing_user.errors.count assert_equal ["can't be blank"], @existing_user.errors[:password] end test "setting a blank password should not change an existing password" do - @existing_user.password = '' - assert @existing_user.password_digest == 'password' + @existing_user.password = "" + assert @existing_user.password_digest == "password" end test "setting a nil password should clear an existing password" do diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb index 8d3165cd78..5ee53285a3 100644 --- a/activemodel/test/cases/serialization_test.rb +++ b/activemodel/test/cases/serialization_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'active_support/core_ext/object/instance_variables' +require "active_support/core_ext/object/instance_variables" class SerializationTest < ActiveModel::TestCase class User @@ -18,14 +18,14 @@ class SerializationTest < ActiveModel::TestCase def method_missing(method_name, *args) if method_name == :bar - 'i_am_bar' + "i_am_bar" else super end end def foo - 'i_am_foo' + "i_am_foo" end end @@ -40,43 +40,43 @@ class SerializationTest < ActiveModel::TestCase end setup do - @user = User.new('David', 'david@example.com', 'male') + @user = User.new("David", "david@example.com", "male") @user.address = Address.new @user.address.street = "123 Lane" @user.address.city = "Springfield" @user.address.state = "CA" @user.address.zip = 11111 - @user.friends = [User.new('Joe', 'joe@example.com', 'male'), - User.new('Sue', 'sue@example.com', 'female')] + @user.friends = [User.new("Joe", "joe@example.com", "male"), + User.new("Sue", "sue@example.com", "female")] end def test_method_serializable_hash_should_work - expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com"} + expected = { "name"=>"David", "gender"=>"male", "email"=>"david@example.com" } assert_equal expected, @user.serializable_hash end def test_method_serializable_hash_should_work_with_only_option - expected = {"name"=>"David"} + expected = { "name"=>"David" } assert_equal expected, @user.serializable_hash(only: [:name]) end def test_method_serializable_hash_should_work_with_except_option - expected = {"gender"=>"male", "email"=>"david@example.com"} + expected = { "gender"=>"male", "email"=>"david@example.com" } assert_equal expected, @user.serializable_hash(except: [:name]) end def test_method_serializable_hash_should_work_with_methods_option - expected = {"name"=>"David", "gender"=>"male", "foo"=>"i_am_foo", "bar"=>"i_am_bar", "email"=>"david@example.com"} + expected = { "name"=>"David", "gender"=>"male", "foo"=>"i_am_foo", "bar"=>"i_am_bar", "email"=>"david@example.com" } assert_equal expected, @user.serializable_hash(methods: [:foo, :bar]) end def test_method_serializable_hash_should_work_with_only_and_methods - expected = {"foo"=>"i_am_foo", "bar"=>"i_am_bar"} + expected = { "foo"=>"i_am_foo", "bar"=>"i_am_bar" } assert_equal expected, @user.serializable_hash(only: [], methods: [:foo, :bar]) end def test_method_serializable_hash_should_work_with_except_and_methods - expected = {"gender"=>"male", "foo"=>"i_am_foo", "bar"=>"i_am_bar"} + expected = { "gender"=>"male", "foo"=>"i_am_foo", "bar"=>"i_am_bar" } assert_equal expected, @user.serializable_hash(except: [:name, :email], methods: [:foo, :bar]) end @@ -94,21 +94,21 @@ class SerializationTest < ActiveModel::TestCase end def test_include_option_with_singular_association - expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com", - "address"=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111}} + expected = { "name"=>"David", "gender"=>"male", "email"=>"david@example.com", + "address"=>{ "street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111 } } assert_equal expected, @user.serializable_hash(include: :address) end def test_include_option_with_plural_association - expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", - "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, - {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} + expected = { "email"=>"david@example.com", "gender"=>"male", "name"=>"David", + "friends"=>[{ "name"=>"Joe", "email"=>"joe@example.com", "gender"=>"male" }, + { "name"=>"Sue", "email"=>"sue@example.com", "gender"=>"female" }] } assert_equal expected, @user.serializable_hash(include: :friends) end def test_include_option_with_empty_association @user.friends = [] - expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", "friends"=>[]} + expected = { "email"=>"david@example.com", "gender"=>"male", "name"=>"David", "friends"=>[] } assert_equal expected, @user.serializable_hash(include: :friends) end @@ -124,52 +124,52 @@ class SerializationTest < ActiveModel::TestCase def test_include_option_with_ary @user.friends = FriendList.new(@user.friends) - expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", - "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, - {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} + expected = { "email"=>"david@example.com", "gender"=>"male", "name"=>"David", + "friends"=>[{ "name"=>"Joe", "email"=>"joe@example.com", "gender"=>"male" }, + { "name"=>"Sue", "email"=>"sue@example.com", "gender"=>"female" }] } assert_equal expected, @user.serializable_hash(include: :friends) end def test_multiple_includes - expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", - "address"=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111}, - "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, - {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} + expected = { "email"=>"david@example.com", "gender"=>"male", "name"=>"David", + "address"=>{ "street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111 }, + "friends"=>[{ "name"=>"Joe", "email"=>"joe@example.com", "gender"=>"male" }, + { "name"=>"Sue", "email"=>"sue@example.com", "gender"=>"female" }] } assert_equal expected, @user.serializable_hash(include: [:address, :friends]) end def test_include_with_options - expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", - "address"=>{"street"=>"123 Lane"}} + expected = { "email"=>"david@example.com", "gender"=>"male", "name"=>"David", + "address"=>{ "street"=>"123 Lane" } } assert_equal expected, @user.serializable_hash(include: { address: { only: "street" } }) end def test_nested_include @user.friends.first.friends = [@user] - expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", - "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male', - "friends"=> [{"email"=>"david@example.com", "gender"=>"male", "name"=>"David"}]}, - {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female', "friends"=> []}]} + expected = { "email"=>"david@example.com", "gender"=>"male", "name"=>"David", + "friends"=>[{ "name"=>"Joe", "email"=>"joe@example.com", "gender"=>"male", + "friends"=> [{ "email"=>"david@example.com", "gender"=>"male", "name"=>"David" }] }, + { "name"=>"Sue", "email"=>"sue@example.com", "gender"=>"female", "friends"=> [] }] } assert_equal expected, @user.serializable_hash(include: { friends: { include: :friends } }) end def test_only_include - expected = {"name"=>"David", "friends" => [{"name" => "Joe"}, {"name" => "Sue"}]} + expected = { "name"=>"David", "friends" => [{ "name" => "Joe" }, { "name" => "Sue" }] } assert_equal expected, @user.serializable_hash(only: :name, include: { friends: { only: :name } }) end def test_except_include - expected = {"name"=>"David", "email"=>"david@example.com", - "friends"=> [{"name" => 'Joe', "email" => 'joe@example.com'}, - {"name" => "Sue", "email" => 'sue@example.com'}]} + expected = { "name"=>"David", "email"=>"david@example.com", + "friends"=> [{ "name" => "Joe", "email" => "joe@example.com" }, + { "name" => "Sue", "email" => "sue@example.com" }] } assert_equal expected, @user.serializable_hash(except: :gender, include: { friends: { except: :gender } }) end def test_multiple_includes_with_options - expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", - "address"=>{"street"=>"123 Lane"}, - "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, - {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} - assert_equal expected, @user.serializable_hash(include: [{ address: {only: "street" } }, :friends]) + expected = { "email"=>"david@example.com", "gender"=>"male", "name"=>"David", + "address"=>{ "street"=>"123 Lane" }, + "friends"=>[{ "name"=>"Joe", "email"=>"joe@example.com", "gender"=>"male" }, + { "name"=>"Sue", "email"=>"sue@example.com", "gender"=>"female" }] } + assert_equal expected, @user.serializable_hash(include: [{ address: { only: "street" } }, :friends]) end end diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index d765a47636..d15ba64eb0 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -1,15 +1,15 @@ -require 'cases/helper' -require 'models/contact' -require 'active_support/core_ext/object/instance_variables' +require "cases/helper" +require "models/contact" +require "active_support/core_ext/object/instance_variables" class JsonSerializationTest < ActiveModel::TestCase def setup @contact = Contact.new - @contact.name = 'Konata Izumi' + @contact.name = "Konata Izumi" @contact.age = 16 @contact.created_at = Time.utc(2006, 8, 1) @contact.awesome = true - @contact.preferences = { 'shows' => 'anime' } + @contact.preferences = { "shows" => "anime" } end test "should not include root in json (class method)" do @@ -18,7 +18,7 @@ class JsonSerializationTest < ActiveModel::TestCase assert_no_match %r{^\{"contact":\{}, json assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -32,7 +32,7 @@ class JsonSerializationTest < ActiveModel::TestCase assert_match %r{^\{"contact":\{}, json assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json ensure @@ -53,12 +53,12 @@ class JsonSerializationTest < ActiveModel::TestCase end test "should include custom root in json" do - json = @contact.to_json(root: 'json_contact') + json = @contact.to_json(root: "json_contact") assert_match %r{^\{"json_contact":\{}, json assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -68,7 +68,7 @@ class JsonSerializationTest < ActiveModel::TestCase assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -79,7 +79,7 @@ class JsonSerializationTest < ActiveModel::TestCase assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json assert_no_match %r{"awesome":true}, json - assert !json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_not_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_no_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -89,7 +89,7 @@ class JsonSerializationTest < ActiveModel::TestCase assert_no_match %r{"name":"Konata Izumi"}, json assert_no_match %r{"age":16}, json assert_match %r{"awesome":true}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -134,9 +134,9 @@ class JsonSerializationTest < ActiveModel::TestCase json = @contact.as_json assert_kind_of Hash, json - assert_kind_of Hash, json['contact'] + assert_kind_of Hash, json["contact"] %w(name age created_at awesome preferences).each do |field| - assert_equal @contact.send(field), json['contact'][field] + assert_equal @contact.send(field), json["contact"][field] end ensure Contact.include_root_in_json = original_include_root_in_json diff --git a/activemodel/test/cases/translation_test.rb b/activemodel/test/cases/translation_test.rb index 2c89388f14..9972f9daea 100644 --- a/activemodel/test/cases/translation_test.rb +++ b/activemodel/test/cases/translation_test.rb @@ -1,8 +1,7 @@ -require 'cases/helper' -require 'models/person' +require "cases/helper" +require "models/person" class ActiveModelI18nTests < ActiveModel::TestCase - def setup I18n.backend = I18n::Backend::Simple.new end @@ -12,102 +11,101 @@ class ActiveModelI18nTests < ActiveModel::TestCase end def test_translated_model_attributes - I18n.backend.store_translations 'en', activemodel: { attributes: { person: { name: 'person name attribute' } } } - assert_equal 'person name attribute', Person.human_attribute_name('name') + I18n.backend.store_translations "en", activemodel: { attributes: { person: { name: "person name attribute" } } } + assert_equal "person name attribute", Person.human_attribute_name("name") end def test_translated_model_attributes_with_default - I18n.backend.store_translations 'en', attributes: { name: 'name default attribute' } - assert_equal 'name default attribute', Person.human_attribute_name('name') + I18n.backend.store_translations "en", attributes: { name: "name default attribute" } + assert_equal "name default attribute", Person.human_attribute_name("name") end def test_translated_model_attributes_using_default_option - assert_equal 'name default attribute', Person.human_attribute_name('name', default: "name default attribute") + assert_equal "name default attribute", Person.human_attribute_name("name", default: "name default attribute") end def test_translated_model_attributes_using_default_option_as_symbol - I18n.backend.store_translations 'en', default_name: 'name default attribute' - assert_equal 'name default attribute', Person.human_attribute_name('name', default: :default_name) + I18n.backend.store_translations "en", default_name: "name default attribute" + assert_equal "name default attribute", Person.human_attribute_name("name", default: :default_name) end def test_translated_model_attributes_falling_back_to_default - assert_equal 'Name', Person.human_attribute_name('name') + assert_equal "Name", Person.human_attribute_name("name") end def test_translated_model_attributes_using_default_option_as_symbol_and_falling_back_to_default - assert_equal 'Name', Person.human_attribute_name('name', default: :default_name) + assert_equal "Name", Person.human_attribute_name("name", default: :default_name) end def test_translated_model_attributes_with_symbols - I18n.backend.store_translations 'en', activemodel: { attributes: { person: { name: 'person name attribute'} } } - assert_equal 'person name attribute', Person.human_attribute_name(:name) + I18n.backend.store_translations "en", activemodel: { attributes: { person: { name: "person name attribute" } } } + assert_equal "person name attribute", Person.human_attribute_name(:name) end def test_translated_model_attributes_with_ancestor - I18n.backend.store_translations 'en', activemodel: { attributes: { child: { name: 'child name attribute'} } } - assert_equal 'child name attribute', Child.human_attribute_name('name') + I18n.backend.store_translations "en", activemodel: { attributes: { child: { name: "child name attribute" } } } + assert_equal "child name attribute", Child.human_attribute_name("name") end def test_translated_model_attributes_with_ancestors_fallback - I18n.backend.store_translations 'en', activemodel: { attributes: { person: { name: 'person name attribute'} } } - assert_equal 'person name attribute', Child.human_attribute_name('name') + I18n.backend.store_translations "en", activemodel: { attributes: { person: { name: "person name attribute" } } } + assert_equal "person name attribute", Child.human_attribute_name("name") end def test_translated_model_attributes_with_attribute_matching_namespaced_model_name - I18n.backend.store_translations 'en', activemodel: { attributes: { - person: { gender: 'person gender'}, - :"person/gender" => { attribute: 'person gender attribute' } + I18n.backend.store_translations "en", activemodel: { attributes: { + person: { gender: "person gender" }, + "person/gender": { attribute: "person gender attribute" } } } - assert_equal 'person gender', Person.human_attribute_name('gender') - assert_equal 'person gender attribute', Person::Gender.human_attribute_name('attribute') + assert_equal "person gender", Person.human_attribute_name("gender") + assert_equal "person gender attribute", Person::Gender.human_attribute_name("attribute") end def test_translated_deeply_nested_model_attributes - I18n.backend.store_translations 'en', activemodel: { attributes: { :"person/contacts/addresses" => { street: 'Deeply Nested Address Street' } } } - assert_equal 'Deeply Nested Address Street', Person.human_attribute_name('contacts.addresses.street') + I18n.backend.store_translations "en", activemodel: { attributes: { "person/contacts/addresses": { street: "Deeply Nested Address Street" } } } + assert_equal "Deeply Nested Address Street", Person.human_attribute_name("contacts.addresses.street") end def test_translated_nested_model_attributes - I18n.backend.store_translations 'en', activemodel: { attributes: { :"person/addresses" => { street: 'Person Address Street' } } } - assert_equal 'Person Address Street', Person.human_attribute_name('addresses.street') + I18n.backend.store_translations "en", activemodel: { attributes: { "person/addresses": { street: "Person Address Street" } } } + assert_equal "Person Address Street", Person.human_attribute_name("addresses.street") end def test_translated_nested_model_attributes_with_namespace_fallback - I18n.backend.store_translations 'en', activemodel: { attributes: { addresses: { street: 'Cool Address Street' } } } - assert_equal 'Cool Address Street', Person.human_attribute_name('addresses.street') + I18n.backend.store_translations "en", activemodel: { attributes: { addresses: { street: "Cool Address Street" } } } + assert_equal "Cool Address Street", Person.human_attribute_name("addresses.street") end def test_translated_model_names - I18n.backend.store_translations 'en', activemodel: { models: { person: 'person model' } } - assert_equal 'person model', Person.model_name.human + I18n.backend.store_translations "en", activemodel: { models: { person: "person model" } } + assert_equal "person model", Person.model_name.human end def test_translated_model_names_with_sti - I18n.backend.store_translations 'en', activemodel: { models: { child: 'child model' } } - assert_equal 'child model', Child.model_name.human + I18n.backend.store_translations "en", activemodel: { models: { child: "child model" } } + assert_equal "child model", Child.model_name.human end def test_translated_model_with_namespace - I18n.backend.store_translations 'en', activemodel: { models: { 'person/gender': 'gender model' } } - assert_equal 'gender model', Person::Gender.model_name.human + I18n.backend.store_translations "en", activemodel: { models: { 'person/gender': "gender model" } } + assert_equal "gender model", Person::Gender.model_name.human end def test_translated_model_names_with_ancestors_fallback - I18n.backend.store_translations 'en', activemodel: { models: { person: 'person model' } } - assert_equal 'person model', Child.model_name.human + I18n.backend.store_translations "en", activemodel: { models: { person: "person model" } } + assert_equal "person model", Child.model_name.human end def test_human_does_not_modify_options - options = { default: 'person model' } + options = { default: "person model" } Person.model_name.human(options) - assert_equal({ default: 'person model' }, options) + assert_equal({ default: "person model" }, options) end def test_human_attribute_name_does_not_modify_options - options = { default: 'Cool gender' } - Person.human_attribute_name('gender', options) - assert_equal({ default: 'Cool gender' }, options) + options = { default: "Cool gender" } + Person.human_attribute_name("gender", options) + assert_equal({ default: "Cool gender" }, options) end end - diff --git a/activemodel/test/cases/type/big_integer_test.rb b/activemodel/test/cases/type/big_integer_test.rb new file mode 100644 index 0000000000..db1d215083 --- /dev/null +++ b/activemodel/test/cases/type/big_integer_test.rb @@ -0,0 +1,24 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class BigIntegerTest < ActiveModel::TestCase + def test_type_cast_big_integer + type = Type::BigInteger.new + assert_equal 1, type.cast(1) + assert_equal 1, type.cast("1") + end + + def test_small_values + type = Type::BigInteger.new + assert_equal -9999999999999999999999999999999, type.serialize(-9999999999999999999999999999999) + end + + def test_large_values + type = Type::BigInteger.new + assert_equal 9999999999999999999999999999999, type.serialize(9999999999999999999999999999999) + end + end + end +end diff --git a/activemodel/test/cases/type/binary_test.rb b/activemodel/test/cases/type/binary_test.rb new file mode 100644 index 0000000000..e6a32dbeec --- /dev/null +++ b/activemodel/test/cases/type/binary_test.rb @@ -0,0 +1,15 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class BinaryTest < ActiveModel::TestCase + def test_type_cast_binary + type = Type::Binary.new + assert_equal nil, type.cast(nil) + assert_equal "1", type.cast("1") + assert_equal 1, type.cast(1) + end + end + end +end diff --git a/activemodel/test/cases/type/boolean_test.rb b/activemodel/test/cases/type/boolean_test.rb new file mode 100644 index 0000000000..92e5aebfb7 --- /dev/null +++ b/activemodel/test/cases/type/boolean_test.rb @@ -0,0 +1,39 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class BooleanTest < ActiveModel::TestCase + def test_type_cast_boolean + type = Type::Boolean.new + assert type.cast("").nil? + assert type.cast(nil).nil? + + assert type.cast(true) + assert type.cast(1) + assert type.cast("1") + assert type.cast("t") + assert type.cast("T") + assert type.cast("true") + assert type.cast("TRUE") + assert type.cast("on") + assert type.cast("ON") + assert type.cast(" ") + assert type.cast("\u3000\r\n") + assert type.cast("\u0000") + assert type.cast("SOMETHING RANDOM") + + # explicitly check for false vs nil + assert_equal false, type.cast(false) + assert_equal false, type.cast(0) + assert_equal false, type.cast("0") + assert_equal false, type.cast("f") + assert_equal false, type.cast("F") + assert_equal false, type.cast("false") + assert_equal false, type.cast("FALSE") + assert_equal false, type.cast("off") + assert_equal false, type.cast("OFF") + end + end + end +end diff --git a/activemodel/test/cases/type/date_test.rb b/activemodel/test/cases/type/date_test.rb new file mode 100644 index 0000000000..44e20a327b --- /dev/null +++ b/activemodel/test/cases/type/date_test.rb @@ -0,0 +1,19 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class DateTest < ActiveModel::TestCase + def test_type_cast_date + type = Type::Date.new + assert_equal nil, type.cast(nil) + assert_equal nil, type.cast("") + assert_equal nil, type.cast(" ") + assert_equal nil, type.cast("ABC") + + date_string = ::Time.now.utc.strftime("%F") + assert_equal date_string, type.cast(date_string).strftime("%F") + end + end + end +end diff --git a/activemodel/test/cases/type/date_time_test.rb b/activemodel/test/cases/type/date_time_test.rb new file mode 100644 index 0000000000..fb82260d2b --- /dev/null +++ b/activemodel/test/cases/type/date_time_test.rb @@ -0,0 +1,38 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class DateTimeTest < ActiveModel::TestCase + def test_type_cast_datetime_and_timestamp + type = Type::DateTime.new + assert_equal nil, type.cast(nil) + assert_equal nil, type.cast("") + assert_equal nil, type.cast(" ") + assert_equal nil, type.cast("ABC") + + datetime_string = ::Time.now.utc.strftime("%FT%T") + assert_equal datetime_string, type.cast(datetime_string).strftime("%FT%T") + end + + def test_string_to_time_with_timezone + ["UTC", "US/Eastern"].each do |zone| + with_timezone_config default: zone do + type = Type::DateTime.new + assert_equal ::Time.utc(2013, 9, 4, 0, 0, 0), type.cast("Wed, 04 Sep 2013 03:00:00 EAT") + end + end + end + + private + + def with_timezone_config(default:) + old_zone_default = ::Time.zone_default + ::Time.zone_default = ::Time.find_zone(default) + yield + ensure + ::Time.zone_default = old_zone_default + end + end + end +end diff --git a/activemodel/test/cases/type/decimal_test.rb b/activemodel/test/cases/type/decimal_test.rb index 1950566c0e..46a913258e 100644 --- a/activemodel/test/cases/type/decimal_test.rb +++ b/activemodel/test/cases/type/decimal_test.rb @@ -48,9 +48,9 @@ module ActiveModel def test_changed? type = Decimal.new - assert type.changed?(5.0, 5.0, '5.0wibble') - assert_not type.changed?(5.0, 5.0, '5.0') - assert_not type.changed?(-5.0, -5.0, '-5.0') + assert type.changed?(5.0, 5.0, "5.0wibble") + assert_not type.changed?(5.0, 5.0, "5.0") + assert_not type.changed?(-5.0, -5.0, "-5.0") end def test_scale_is_applied_before_precision_to_prevent_rounding_errors diff --git a/activemodel/test/cases/type/float_test.rb b/activemodel/test/cases/type/float_test.rb new file mode 100644 index 0000000000..2e34f57f7e --- /dev/null +++ b/activemodel/test/cases/type/float_test.rb @@ -0,0 +1,22 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class FloatTest < ActiveModel::TestCase + def test_type_cast_float + type = Type::Float.new + assert_equal 1.0, type.cast("1") + end + + def test_changing_float + type = Type::Float.new + + assert type.changed?(5.0, 5.0, "5wibble") + assert_not type.changed?(5.0, 5.0, "5") + assert_not type.changed?(5.0, 5.0, "5.0") + assert_not type.changed?(nil, nil, nil) + end + end + end +end diff --git a/activemodel/test/cases/type/immutable_string_test.rb b/activemodel/test/cases/type/immutable_string_test.rb new file mode 100644 index 0000000000..23e58974fb --- /dev/null +++ b/activemodel/test/cases/type/immutable_string_test.rb @@ -0,0 +1,21 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class ImmutableStringTest < ActiveModel::TestCase + test "cast strings are frozen" do + s = "foo" + type = Type::ImmutableString.new + assert_equal true, type.cast(s).frozen? + end + + test "immutable strings are not duped coming out" do + s = "foo" + type = Type::ImmutableString.new + assert_same s, type.cast(s) + assert_same s, type.deserialize(s) + end + end + end +end diff --git a/activemodel/test/cases/type/integer_test.rb b/activemodel/test/cases/type/integer_test.rb index 6603f25c9a..d81ce189e6 100644 --- a/activemodel/test/cases/type/integer_test.rb +++ b/activemodel/test/cases/type/integer_test.rb @@ -1,5 +1,6 @@ require "cases/helper" require "active_model/type" +require "active_support/core_ext/numeric/time" module ActiveModel module Type @@ -7,10 +8,10 @@ module ActiveModel test "simple values" do type = Type::Integer.new assert_equal 1, type.cast(1) - assert_equal 1, type.cast('1') - assert_equal 1, type.cast('1ignore') - assert_equal 0, type.cast('bad1') - assert_equal 0, type.cast('bad') + assert_equal 1, type.cast("1") + assert_equal 1, type.cast("1ignore") + assert_equal 0, type.cast("bad1") + assert_equal 0, type.cast("bad") assert_equal 1, type.cast(1.7) assert_equal 0, type.cast(false) assert_equal 1, type.cast(true) @@ -20,7 +21,7 @@ module ActiveModel test "random objects cast to nil" do type = Type::Integer.new assert_nil type.cast([1,2]) - assert_nil type.cast({1 => 2}) + assert_nil type.cast(1 => 2) assert_nil type.cast(1..2) end @@ -41,14 +42,20 @@ module ActiveModel assert_equal 0, type.serialize(false) end + test "casting duration" do + type = Type::Integer.new + assert_equal 1800, type.cast(30.minutes) + assert_equal 7200, type.cast(2.hours) + end + test "changed?" do type = Type::Integer.new - assert type.changed?(5, 5, '5wibble') - assert_not type.changed?(5, 5, '5') - assert_not type.changed?(5, 5, '5.0') - assert_not type.changed?(-5, -5, '-5') - assert_not type.changed?(-5, -5, '-5.0') + assert type.changed?(5, 5, "5wibble") + assert_not type.changed?(5, 5, "5") + assert_not type.changed?(5, 5, "5.0") + assert_not type.changed?(-5, -5, "-5") + assert_not type.changed?(-5, -5, "-5.0") assert_not type.changed?(nil, nil, nil) end diff --git a/activemodel/test/cases/type/registry_test.rb b/activemodel/test/cases/type/registry_test.rb index 2a48998a62..927b6d0307 100644 --- a/activemodel/test/cases/type/registry_test.rb +++ b/activemodel/test/cases/type/registry_test.rb @@ -2,38 +2,40 @@ require "cases/helper" require "active_model/type" module ActiveModel - class RegistryTest < ActiveModel::TestCase - test "a class can be registered for a symbol" do - registry = Type::Registry.new - registry.register(:foo, ::String) - registry.register(:bar, ::Array) + module Type + class RegistryTest < ActiveModel::TestCase + test "a class can be registered for a symbol" do + registry = Type::Registry.new + registry.register(:foo, ::String) + registry.register(:bar, ::Array) - assert_equal "", registry.lookup(:foo) - assert_equal [], registry.lookup(:bar) - end - - test "a block can be registered" do - registry = Type::Registry.new - registry.register(:foo) do |*args| - [*args, "block for foo"] + assert_equal "", registry.lookup(:foo) + assert_equal [], registry.lookup(:bar) end - registry.register(:bar) do |*args| - [*args, "block for bar"] + + test "a block can be registered" do + registry = Type::Registry.new + registry.register(:foo) do |*args| + [*args, "block for foo"] + end + registry.register(:bar) do |*args| + [*args, "block for bar"] + end + + assert_equal [:foo, 1, "block for foo"], registry.lookup(:foo, 1) + assert_equal [:foo, 2, "block for foo"], registry.lookup(:foo, 2) + assert_equal [:bar, 1, 2, 3, "block for bar"], registry.lookup(:bar, 1, 2, 3) end - assert_equal [:foo, 1, "block for foo"], registry.lookup(:foo, 1) - assert_equal [:foo, 2, "block for foo"], registry.lookup(:foo, 2) - assert_equal [:bar, 1, 2, 3, "block for bar"], registry.lookup(:bar, 1, 2, 3) - end + test "a reasonable error is given when no type is found" do + registry = Type::Registry.new - test "a reasonable error is given when no type is found" do - registry = Type::Registry.new + e = assert_raises(ArgumentError) do + registry.lookup(:foo) + end - e = assert_raises(ArgumentError) do - registry.lookup(:foo) + assert_equal "Unknown type :foo", e.message end - - assert_equal "Unknown type :foo", e.message end end end diff --git a/activemodel/test/cases/type/string_test.rb b/activemodel/test/cases/type/string_test.rb index 7b25a1ef74..222083817e 100644 --- a/activemodel/test/cases/type/string_test.rb +++ b/activemodel/test/cases/type/string_test.rb @@ -2,26 +2,27 @@ require "cases/helper" require "active_model/type" module ActiveModel - class StringTypeTest < ActiveModel::TestCase - test "type casting" do - type = Type::String.new - assert_equal "t", type.cast(true) - assert_equal "f", type.cast(false) - assert_equal "123", type.cast(123) - end + module Type + class StringTest < ActiveModel::TestCase + test "type casting" do + type = Type::String.new + assert_equal "t", type.cast(true) + assert_equal "f", type.cast(false) + assert_equal "123", type.cast(123) + end - test "immutable strings are not duped coming out" do - s = "foo" - type = Type::ImmutableString.new - assert_same s, type.cast(s) - assert_same s, type.deserialize(s) - end + test "cast strings are mutable" do + s = "foo" + type = Type::String.new + assert_equal false, type.cast(s).frozen? + end - test "values are duped coming out" do - s = "foo" - type = Type::String.new - assert_not_same s, type.cast(s) - assert_not_same s, type.deserialize(s) + test "values are duped coming out" do + s = "foo" + type = Type::String.new + assert_not_same s, type.cast(s) + assert_not_same s, type.deserialize(s) + end end end end diff --git a/activemodel/test/cases/type/time_test.rb b/activemodel/test/cases/type/time_test.rb new file mode 100644 index 0000000000..a6a79833e6 --- /dev/null +++ b/activemodel/test/cases/type/time_test.rb @@ -0,0 +1,21 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class TimeTest < ActiveModel::TestCase + def test_type_cast_time + type = Type::Time.new + assert_equal nil, type.cast(nil) + assert_equal nil, type.cast("") + assert_equal nil, type.cast("ABC") + + time_string = ::Time.now.utc.strftime("%T") + assert_equal time_string, type.cast(time_string).strftime("%T") + + assert_equal ::Time.utc(2000, 1, 1, 16, 45, 54), type.cast("2015-06-13T19:45:54+03:00") + assert_equal ::Time.utc(1999, 12, 31, 21, 7, 8), type.cast("06:07:08+09:00") + end + end + end +end diff --git a/activemodel/test/cases/type/value_test.rb b/activemodel/test/cases/type/value_test.rb new file mode 100644 index 0000000000..d8b3e7f164 --- /dev/null +++ b/activemodel/test/cases/type/value_test.rb @@ -0,0 +1,14 @@ +require "cases/helper" +require "active_model/type" + +module ActiveModel + module Type + class ValueTest < ActiveModel::TestCase + def test_type_equality + assert_equal Type::Value.new, Type::Value.new + assert_not_equal Type::Value.new, Type::Integer.new + assert_not_equal Type::Value.new(precision: 1), Type::Value.new(precision: 2) + end + end + end +end diff --git a/activemodel/test/cases/types_test.rb b/activemodel/test/cases/types_test.rb deleted file mode 100644 index 558c56f157..0000000000 --- a/activemodel/test/cases/types_test.rb +++ /dev/null @@ -1,125 +0,0 @@ -require "cases/helper" -require "active_model/type" -require "active_support/core_ext/numeric/time" - -module ActiveModel - class TypesTest < ActiveModel::TestCase - def test_type_cast_boolean - type = Type::Boolean.new - assert type.cast('').nil? - assert type.cast(nil).nil? - - assert type.cast(true) - assert type.cast(1) - assert type.cast('1') - assert type.cast('t') - assert type.cast('T') - assert type.cast('true') - assert type.cast('TRUE') - assert type.cast('on') - assert type.cast('ON') - assert type.cast(' ') - assert type.cast("\u3000\r\n") - assert type.cast("\u0000") - assert type.cast('SOMETHING RANDOM') - - # explicitly check for false vs nil - assert_equal false, type.cast(false) - assert_equal false, type.cast(0) - assert_equal false, type.cast('0') - assert_equal false, type.cast('f') - assert_equal false, type.cast('F') - assert_equal false, type.cast('false') - assert_equal false, type.cast('FALSE') - assert_equal false, type.cast('off') - assert_equal false, type.cast('OFF') - end - - def test_type_cast_float - type = Type::Float.new - assert_equal 1.0, type.cast("1") - end - - def test_changing_float - type = Type::Float.new - - assert type.changed?(5.0, 5.0, '5wibble') - assert_not type.changed?(5.0, 5.0, '5') - assert_not type.changed?(5.0, 5.0, '5.0') - assert_not type.changed?(nil, nil, nil) - end - - def test_type_cast_binary - type = Type::Binary.new - assert_equal nil, type.cast(nil) - assert_equal "1", type.cast("1") - assert_equal 1, type.cast(1) - end - - def test_type_cast_time - type = Type::Time.new - assert_equal nil, type.cast(nil) - assert_equal nil, type.cast('') - assert_equal nil, type.cast('ABC') - - time_string = Time.now.utc.strftime("%T") - assert_equal time_string, type.cast(time_string).strftime("%T") - - assert_equal ::Time.utc(2000, 1, 1, 16, 45, 54), type.cast('2015-06-13T19:45:54+03:00') - assert_equal ::Time.utc(1999, 12, 31, 21, 7, 8), type.cast('06:07:08+09:00') - end - - def test_type_cast_datetime_and_timestamp - type = Type::DateTime.new - assert_equal nil, type.cast(nil) - assert_equal nil, type.cast('') - assert_equal nil, type.cast(' ') - assert_equal nil, type.cast('ABC') - - datetime_string = Time.now.utc.strftime("%FT%T") - assert_equal datetime_string, type.cast(datetime_string).strftime("%FT%T") - end - - def test_type_cast_date - type = Type::Date.new - assert_equal nil, type.cast(nil) - assert_equal nil, type.cast('') - assert_equal nil, type.cast(' ') - assert_equal nil, type.cast('ABC') - - date_string = Time.now.utc.strftime("%F") - assert_equal date_string, type.cast(date_string).strftime("%F") - end - - def test_type_cast_duration_to_integer - type = Type::Integer.new - assert_equal 1800, type.cast(30.minutes) - assert_equal 7200, type.cast(2.hours) - end - - def test_string_to_time_with_timezone - ["UTC", "US/Eastern"].each do |zone| - with_timezone_config default: zone do - type = Type::DateTime.new - assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.cast("Wed, 04 Sep 2013 03:00:00 EAT") - end - end - end - - def test_type_equality - assert_equal Type::Value.new, Type::Value.new - assert_not_equal Type::Value.new, Type::Integer.new - assert_not_equal Type::Value.new(precision: 1), Type::Value.new(precision: 2) - end - - private - - def with_timezone_config(default:) - old_zone_default = ::Time.zone_default - ::Time.zone_default = ::Time.find_zone(default) - yield - ensure - ::Time.zone_default = old_zone_default - end - end -end diff --git a/activemodel/test/cases/validations/absence_validation_test.rb b/activemodel/test/cases/validations/absence_validation_test.rb index 9cbc77dfb5..3e48e591e9 100644 --- a/activemodel/test/cases/validations/absence_validation_test.rb +++ b/activemodel/test/cases/validations/absence_validation_test.rb @@ -1,7 +1,7 @@ -require 'cases/helper' -require 'models/topic' -require 'models/person' -require 'models/custom_reader' +require "cases/helper" +require "models/topic" +require "models/person" +require "models/custom_reader" class AbsenceValidationTest < ActiveModel::TestCase teardown do diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb index d3995ad5af..55ab213498 100644 --- a/activemodel/test/cases/validations/acceptance_validation_test.rb +++ b/activemodel/test/cases/validations/acceptance_validation_test.rb @@ -1,11 +1,10 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' -require 'models/reply' -require 'models/person' +require "models/topic" +require "models/reply" +require "models/person" class AcceptanceValidationTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end diff --git a/activemodel/test/cases/validations/callbacks_test.rb b/activemodel/test/cases/validations/callbacks_test.rb index 75eb18e795..83e8ac9522 100644 --- a/activemodel/test/cases/validations/callbacks_test.rb +++ b/activemodel/test/cases/validations/callbacks_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" class Dog include ActiveModel::Validations @@ -15,37 +15,37 @@ class DogWithMethodCallbacks < Dog before_validation :set_before_validation_marker after_validation :set_after_validation_marker - def set_before_validation_marker; self.history << 'before_validation_marker'; end - def set_after_validation_marker; self.history << 'after_validation_marker' ; end + def set_before_validation_marker; history << "before_validation_marker"; end + def set_after_validation_marker; history << "after_validation_marker" ; end end class DogValidatorsAreProc < Dog - before_validation { self.history << 'before_validation_marker' } - after_validation { self.history << 'after_validation_marker' } + before_validation { history << "before_validation_marker" } + after_validation { history << "after_validation_marker" } end class DogWithTwoValidators < Dog - before_validation { self.history << 'before_validation_marker1' } - before_validation { self.history << 'before_validation_marker2' } + before_validation { history << "before_validation_marker1" } + before_validation { history << "before_validation_marker2" } end class DogDeprecatedBeforeValidatorReturningFalse < Dog before_validation { false } - before_validation { self.history << 'before_validation_marker2' } + before_validation { history << "before_validation_marker2" } end class DogBeforeValidatorThrowingAbort < Dog before_validation { throw :abort } - before_validation { self.history << 'before_validation_marker2' } + before_validation { history << "before_validation_marker2" } end class DogAfterValidatorReturningFalse < Dog after_validation { false } - after_validation { self.history << 'after_validation_marker' } + after_validation { history << "after_validation_marker" } end class DogWithMissingName < Dog - before_validation { self.history << 'before_validation_marker' } + before_validation { history << "before_validation_marker" } validates_presence_of :name end @@ -53,8 +53,8 @@ class DogValidatorWithOnCondition < Dog before_validation :set_before_validation_marker, on: :create after_validation :set_after_validation_marker, on: :create - def set_before_validation_marker; self.history << 'before_validation_marker'; end - def set_after_validation_marker; self.history << 'after_validation_marker' ; end + def set_before_validation_marker; history << "before_validation_marker"; end + def set_after_validation_marker; history << "after_validation_marker" ; end end class DogValidatorWithIfCondition < Dog @@ -64,16 +64,14 @@ class DogValidatorWithIfCondition < Dog after_validation :set_after_validation_marker1, if: -> { true } after_validation :set_after_validation_marker2, if: -> { false } - def set_before_validation_marker1; self.history << 'before_validation_marker1'; end - def set_before_validation_marker2; self.history << 'before_validation_marker2' ; end + def set_before_validation_marker1; history << "before_validation_marker1"; end + def set_before_validation_marker2; history << "before_validation_marker2" ; end - def set_after_validation_marker1; self.history << 'after_validation_marker1'; end - def set_after_validation_marker2; self.history << 'after_validation_marker2' ; end + def set_after_validation_marker1; history << "after_validation_marker1"; end + def set_after_validation_marker2; history << "after_validation_marker2" ; end end - class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase - def test_if_condition_is_respected_for_before_validation d = DogValidatorWithIfCondition.new d.valid? @@ -101,19 +99,19 @@ class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase def test_before_validation_and_after_validation_callbacks_should_be_called d = DogWithMethodCallbacks.new d.valid? - assert_equal ['before_validation_marker', 'after_validation_marker'], d.history + assert_equal ["before_validation_marker", "after_validation_marker"], d.history end def test_before_validation_and_after_validation_callbacks_should_be_called_with_proc d = DogValidatorsAreProc.new d.valid? - assert_equal ['before_validation_marker', 'after_validation_marker'], d.history + assert_equal ["before_validation_marker", "after_validation_marker"], d.history end def test_before_validation_and_after_validation_callbacks_should_be_called_in_declared_order d = DogWithTwoValidators.new d.valid? - assert_equal ['before_validation_marker1', 'before_validation_marker2'], d.history + assert_equal ["before_validation_marker1", "before_validation_marker2"], d.history end def test_further_callbacks_should_not_be_called_if_before_validation_throws_abort @@ -135,14 +133,13 @@ class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase def test_further_callbacks_should_be_called_if_after_validation_returns_false d = DogAfterValidatorReturningFalse.new d.valid? - assert_equal ['after_validation_marker'], d.history + assert_equal ["after_validation_marker"], d.history end def test_validation_test_should_be_done d = DogWithMissingName.new output = d.valid? - assert_equal ['before_validation_marker'], d.history + assert_equal ["before_validation_marker"], d.history assert_equal false, output end - end diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb index 296d3b4407..5e81083b63 100644 --- a/activemodel/test/cases/validations/conditional_validation_test.rb +++ b/activemodel/test/cases/validations/conditional_validation_test.rb @@ -1,9 +1,8 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' +require "models/topic" class ConditionalValidationTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end @@ -98,7 +97,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_if_validation_using_block_false # When the block returns false Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", - if: Proc.new { |r| r.title != "uhohuhoh"}) + if: Proc.new { |r| r.title != "uhohuhoh" }) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert_empty t.errors[:title] @@ -107,7 +106,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_unless_validation_using_block_false # When the block returns false Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", - unless: Proc.new { |r| r.title != "uhohuhoh"} ) + unless: Proc.new { |r| r.title != "uhohuhoh" } ) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb index c56bf1c0ad..b88e1c4ca4 100644 --- a/activemodel/test/cases/validations/confirmation_validation_test.rb +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -1,10 +1,9 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' -require 'models/person' +require "models/topic" +require "models/person" class ConfirmationValidationTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end @@ -56,10 +55,9 @@ class ConfirmationValidationTest < ActiveModel::TestCase @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations('en', { + I18n.backend.store_translations("en", errors: { messages: { confirmation: "doesn't match %{attribute}" } }, - activemodel: { attributes: { topic: { title: 'Test Title'} } } - }) + activemodel: { attributes: { topic: { title: "Test Title" } } }) Topic.validates_confirmation_of(:title) diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb index 005bc15df5..06ae4fbecd 100644 --- a/activemodel/test/cases/validations/exclusion_validation_test.rb +++ b/activemodel/test/cases/validations/exclusion_validation_test.rb @@ -1,11 +1,10 @@ -require 'cases/helper' -require 'active_support/core_ext/numeric/time' +require "cases/helper" +require "active_support/core_ext/numeric/time" -require 'models/topic' -require 'models/person' +require "models/topic" +require "models/person" class ExclusionValidationTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end @@ -68,8 +67,8 @@ class ExclusionValidationTest < ActiveModel::TestCase def test_validates_exclusion_of_with_range Topic.validates_exclusion_of :content, in: ("a".."g") - assert Topic.new(content: 'g').invalid? - assert Topic.new(content: 'h').valid? + assert Topic.new(content: "g").invalid? + assert Topic.new(content: "h").valid? end def test_validates_exclusion_of_with_time_range diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb index ea4c2ee7df..d7e6bf3707 100644 --- a/activemodel/test/cases/validations/format_validation_test.rb +++ b/activemodel/test/cases/validations/format_validation_test.rb @@ -1,10 +1,9 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' -require 'models/person' +require "models/topic" +require "models/person" class PresenceValidationTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end @@ -63,7 +62,7 @@ class PresenceValidationTest < ActiveModel::TestCase def test_validate_format_with_formatted_message Topic.validates_format_of(:title, with: /\AValid Title\z/, message: "can't be %{value}") - t = Topic.new(title: 'Invalid title') + t = Topic.new(title: "Invalid title") assert t.invalid? assert_equal ["can't be Invalid title"], t.errors[:title] end diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb index da63df9152..f049ee26e8 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'models/person' +require "models/person" class I18nGenerateMessageValidationTest < ActiveModel::TestCase def setup @@ -10,29 +10,29 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase # validates_inclusion_of: generate_message(attr_name, :inclusion, message: custom_message, value: value) def test_generate_message_inclusion_with_default_message - assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, value: 'title') + assert_equal "is not included in the list", @person.errors.generate_message(:title, :inclusion, value: "title") end def test_generate_message_inclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :inclusion, message: "custom message %{value}", value: "title") end # validates_exclusion_of: generate_message(attr_name, :exclusion, message: custom_message, value: value) def test_generate_message_exclusion_with_default_message - assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, value: 'title') + assert_equal "is reserved", @person.errors.generate_message(:title, :exclusion, value: "title") end def test_generate_message_exclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :exclusion, message: "custom message %{value}", value: "title") end # validates_format_of: generate_message(attr_name, :invalid, message: custom_message, value: value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, value: 'title') + assert_equal "is invalid", @person.errors.generate_message(:title, :invalid, value: "title") end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :invalid, message: "custom message %{value}", value: "title") end # validates_confirmation_of: generate_message(attr_name, :confirmation, message: custom_message) @@ -41,7 +41,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_confirmation_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :confirmation, message: "custom message") end # validates_acceptance_of: generate_message(attr_name, :accepted, message: custom_message) @@ -50,7 +50,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_accepted_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :accepted, message: "custom message") end # add_on_empty: generate_message(attr, :empty, message: custom_message) @@ -59,7 +59,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_empty_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :empty, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :empty, message: "custom message") end # validates_presence_of: generate_message(attr, :blank, message: custom_message) @@ -68,7 +68,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_blank_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :blank, message: 'custom message') + assert_equal "custom message", @person.errors.generate_message(:title, :blank, message: "custom message") end # validates_length_of: generate_message(attr, :too_long, message: custom_message, count: option_value.end) @@ -81,7 +81,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_too_long_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, message: 'custom message %{count}', count: 10) + assert_equal "custom message 10", @person.errors.generate_message(:title, :too_long, message: "custom message %{count}", count: 10) end # validates_length_of: generate_message(attr, :too_short, default: custom_message, count: option_value.begin) @@ -94,7 +94,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_too_short_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, message: 'custom message %{count}', count: 10) + assert_equal "custom message 10", @person.errors.generate_message(:title, :too_short, message: "custom message %{count}", count: 10) end # validates_length_of: generate_message(attr, :wrong_length, message: custom_message, count: option_value) @@ -107,44 +107,44 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_wrong_length_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, message: 'custom message %{count}', count: 10) + assert_equal "custom message 10", @person.errors.generate_message(:title, :wrong_length, message: "custom message %{count}", count: 10) end # validates_numericality_of: generate_message(attr_name, :not_a_number, value: raw_value, message: custom_message) def test_generate_message_not_a_number_with_default_message - assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, value: 'title') + assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, value: "title") end def test_generate_message_not_a_number_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, message: 'custom message %{value}', value: 'title') + assert_equal "custom message title", @person.errors.generate_message(:title, :not_a_number, message: "custom message %{value}", value: "title") end # validates_numericality_of: generate_message(attr_name, option, value: raw_value, default: custom_message) def test_generate_message_greater_than_with_default_message - assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, value: 'title', count: 10) + assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, value: "title", count: 10) end def test_generate_message_greater_than_or_equal_to_with_default_message - assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, value: 'title', count: 10) + assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, value: "title", count: 10) end def test_generate_message_equal_to_with_default_message - assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, value: 'title', count: 10) + assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, value: "title", count: 10) end def test_generate_message_less_than_with_default_message - assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, value: 'title', count: 10) + assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, value: "title", count: 10) end def test_generate_message_less_than_or_equal_to_with_default_message - assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, value: 'title', count: 10) + assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, value: "title", count: 10) end def test_generate_message_odd_with_default_message - assert_equal "must be odd", @person.errors.generate_message(:title, :odd, value: 'title', count: 10) + assert_equal "must be odd", @person.errors.generate_message(:title, :odd, value: "title", count: 10) end def test_generate_message_even_with_default_message - assert_equal "must be even", @person.errors.generate_message(:title, :even, value: 'title', count: 10) + assert_equal "must be even", @person.errors.generate_message(:title, :even, value: "title", count: 10) end end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 09d7226b5a..f28cfc0ef5 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -1,8 +1,7 @@ require "cases/helper" -require 'models/person' +require "models/person" class I18nValidationTest < ActiveModel::TestCase - def setup Person.clear_validators! @person = Person.new @@ -10,7 +9,7 @@ class I18nValidationTest < ActiveModel::TestCase @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations('en', errors: { messages: { custom: nil } }) + I18n.backend.store_translations("en", errors: { messages: { custom: nil } }) end def teardown @@ -21,23 +20,23 @@ class I18nValidationTest < ActiveModel::TestCase end def test_full_message_encoding - I18n.backend.store_translations('en', errors: { - messages: { too_short: '猫舌' } }) + I18n.backend.store_translations("en", errors: { + messages: { too_short: "猫舌" } }) Person.validates_length_of :title, within: 3..5 @person.valid? - assert_equal ['Title 猫舌'], @person.errors.full_messages + assert_equal ["Title 猫舌"], @person.errors.full_messages end def test_errors_full_messages_translates_human_attribute_name_for_model_attributes - @person.errors.add(:name, 'not found') - assert_called_with(Person, :human_attribute_name, [:name, default: 'Name'], returns: "Person's name") do + @person.errors.add(:name, "not found") + assert_called_with(Person, :human_attribute_name, [:name, default: "Name"], returns: "Person's name") do assert_equal ["Person's name not found"], @person.errors.full_messages end end def test_errors_full_messages_uses_format - I18n.backend.store_translations('en', errors: { format: "Field %{attribute} %{message}" }) - @person.errors.add('name', 'empty') + I18n.backend.store_translations("en", errors: { format: "Field %{attribute} %{message}" }) + @person.errors.add("name", "empty") assert_equal ["Field Name empty"], @person.errors.full_messages end @@ -47,19 +46,19 @@ class I18nValidationTest < ActiveModel::TestCase # are used to generate tests to keep things DRY # COMMON_CASES = [ - # [ case, validation_options, generate_message_options] + # [ case, validation_options, generate_message_options] [ "given no options", {}, {}], [ "given custom message", { message: "custom" }, { message: "custom" }], - [ "given if condition", { if: lambda { true }}, {}], - [ "given unless condition", { unless: lambda { false }}, {}], + [ "given if condition", { if: lambda { true } }, {}], + [ "given unless condition", { unless: lambda { false } }, {}], [ "given option that is not reserved", { format: "jpg" }, { format: "jpg" }] ] COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_confirmation_of on generated message #{name}" do Person.validates_confirmation_of :title, validation_options - @person.title_confirmation = 'foo' - call = [:title_confirmation, :confirmation, generate_message_options.merge(attribute: 'Title')] + @person.title_confirmation = "foo" + call = [:title_confirmation, :confirmation, generate_message_options.merge(attribute: "Title")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -99,7 +98,7 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_length_of for :too_long generated message #{name}" do Person.validates_length_of :title, validation_options.merge(within: 3..5) - @person.title = 'this title is too long' + @person.title = "this title is too long" call = [:title, :too_long, generate_message_options.merge(count: 5)] assert_called_with(@person.errors, :generate_message, call) do @person.valid? @@ -120,8 +119,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_format_of on generated message #{name}" do Person.validates_format_of :title, validation_options.merge(with: /\A[1-9][0-9]*\z/) - @person.title = '72x' - call = [:title, :invalid, generate_message_options.merge(value: '72x')] + @person.title = "72x" + call = [:title, :invalid, generate_message_options.merge(value: "72x")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -131,8 +130,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_inclusion_of on generated message #{name}" do Person.validates_inclusion_of :title, validation_options.merge(in: %w(a b c)) - @person.title = 'z' - call = [:title, :inclusion, generate_message_options.merge(value: 'z')] + @person.title = "z" + call = [:title, :inclusion, generate_message_options.merge(value: "z")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -142,8 +141,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_inclusion_of using :within on generated message #{name}" do Person.validates_inclusion_of :title, validation_options.merge(within: %w(a b c)) - @person.title = 'z' - call = [:title, :inclusion, generate_message_options.merge(value: 'z')] + @person.title = "z" + call = [:title, :inclusion, generate_message_options.merge(value: "z")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -153,8 +152,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_exclusion_of generated message #{name}" do Person.validates_exclusion_of :title, validation_options.merge(in: %w(a b c)) - @person.title = 'a' - call = [:title, :exclusion, generate_message_options.merge(value: 'a')] + @person.title = "a" + call = [:title, :exclusion, generate_message_options.merge(value: "a")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -164,8 +163,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_exclusion_of using :within generated message #{name}" do Person.validates_exclusion_of :title, validation_options.merge(within: %w(a b c)) - @person.title = 'a' - call = [:title, :exclusion, generate_message_options.merge(value: 'a')] + @person.title = "a" + call = [:title, :exclusion, generate_message_options.merge(value: "a")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -175,8 +174,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_numericality_of generated message #{name}" do Person.validates_numericality_of :title, validation_options - @person.title = 'a' - call = [:title, :not_a_number, generate_message_options.merge(value: 'a')] + @person.title = "a" + call = [:title, :not_a_number, generate_message_options.merge(value: "a")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -186,8 +185,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_numericality_of for :only_integer on generated message #{name}" do Person.validates_numericality_of :title, validation_options.merge(only_integer: true) - @person.title = '0.0' - call = [:title, :not_an_integer, generate_message_options.merge(value: '0.0')] + @person.title = "0.0" + call = [:title, :not_an_integer, generate_message_options.merge(value: "0.0")] assert_called_with(@person.errors, :generate_message, call) do @person.valid? end @@ -225,35 +224,35 @@ class I18nValidationTest < ActiveModel::TestCase end test "#{validation} finds custom model key translation when #{error_type}" do - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => 'custom message' } } } } } } - I18n.backend.store_translations 'en', errors: { messages: { error_type => 'global message'}} + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => "custom message" } } } } } } + I18n.backend.store_translations "en", errors: { messages: { error_type => "global message" } } yield(@person, {}) @person.valid? - assert_equal ['custom message'], @person.errors[attribute] + assert_equal ["custom message"], @person.errors[attribute] end test "#{validation} finds custom model key translation with interpolation when #{error_type}" do - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => 'custom message with %{extra}' } } } } } } - I18n.backend.store_translations 'en', errors: { messages: {error_type => 'global message'} } + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => "custom message with %{extra}" } } } } } } + I18n.backend.store_translations "en", errors: { messages: { error_type => "global message" } } yield(@person, { extra: "extra information" }) @person.valid? - assert_equal ['custom message with extra information'], @person.errors[attribute] + assert_equal ["custom message with extra information"], @person.errors[attribute] end test "#{validation} finds global default key translation when #{error_type}" do - I18n.backend.store_translations 'en', errors: { messages: {error_type => 'global message'} } + I18n.backend.store_translations "en", errors: { messages: { error_type => "global message" } } yield(@person, {}) @person.valid? - assert_equal ['global message'], @person.errors[attribute] + assert_equal ["global message"], @person.errors[attribute] end end set_expectations_for_validation "validates_confirmation_of", :confirmation do |person, options_to_merge| Person.validates_confirmation_of :title, options_to_merge - person.title_confirmation = 'foo' + person.title_confirmation = "foo" end set_expectations_for_validation "validates_acceptance_of", :accepted do |person, options_to_merge| @@ -287,17 +286,17 @@ class I18nValidationTest < ActiveModel::TestCase set_expectations_for_validation "validates_exclusion_of", :exclusion do |person, options_to_merge| Person.validates_exclusion_of :title, options_to_merge.merge(in: %w(a b c)) - person.title = 'a' + person.title = "a" end set_expectations_for_validation "validates_numericality_of", :not_a_number do |person, options_to_merge| Person.validates_numericality_of :title, options_to_merge - person.title = 'a' + person.title = "a" end set_expectations_for_validation "validates_numericality_of", :not_an_integer do |person, options_to_merge| Person.validates_numericality_of :title, options_to_merge.merge(only_integer: true) - person.title = '1.0' + person.title = "1.0" end set_expectations_for_validation "validates_numericality_of", :odd do |person, options_to_merge| @@ -311,7 +310,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validations_with_message_symbol_must_translate - I18n.backend.store_translations 'en', errors: { messages: { custom_error: "I am a custom error" } } + I18n.backend.store_translations "en", errors: { messages: { custom_error: "I am a custom error" } } Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? @@ -319,7 +318,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validates_with_message_symbol_must_translate_per_attribute - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { title: { custom_error: "I am a custom error" } } } } } } + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { attributes: { title: { custom_error: "I am a custom error" } } } } } } Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? @@ -327,7 +326,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_validates_with_message_symbol_must_translate_per_model - I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { custom_error: "I am a custom error" } } } } + I18n.backend.store_translations "en", activemodel: { errors: { models: { person: { custom_error: "I am a custom error" } } } } Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb index 9bd44175a6..5aa43ea4a9 100644 --- a/activemodel/test/cases/validations/inclusion_validation_test.rb +++ b/activemodel/test/cases/validations/inclusion_validation_test.rb @@ -1,17 +1,16 @@ -require 'cases/helper' -require 'active_support/all' +require "cases/helper" +require "active_support/all" -require 'models/topic' -require 'models/person' +require "models/topic" +require "models/person" class InclusionValidationTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end def test_validates_inclusion_of_range - Topic.validates_inclusion_of(:title, in: 'aaa'..'bbb') + Topic.validates_inclusion_of(:title, in: "aaa".."bbb") assert Topic.new("title" => "bbc", "content" => "abc").invalid? assert Topic.new("title" => "aa", "content" => "abc").invalid? assert Topic.new("title" => "aaab", "content" => "abc").invalid? @@ -24,35 +23,35 @@ class InclusionValidationTest < ActiveModel::TestCase range_begin = 1.year.ago range_end = Time.now Topic.validates_inclusion_of(:created_at, in: range_begin..range_end) - assert Topic.new(title: 'aaa', created_at: 2.years.ago).invalid? - assert Topic.new(title: 'aaa', created_at: 3.months.ago).valid? - assert Topic.new(title: 'aaa', created_at: 37.weeks.from_now).invalid? - assert Topic.new(title: 'aaa', created_at: range_begin).valid? - assert Topic.new(title: 'aaa', created_at: range_end).valid? + assert Topic.new(title: "aaa", created_at: 2.years.ago).invalid? + assert Topic.new(title: "aaa", created_at: 3.months.ago).valid? + assert Topic.new(title: "aaa", created_at: 37.weeks.from_now).invalid? + assert Topic.new(title: "aaa", created_at: range_begin).valid? + assert Topic.new(title: "aaa", created_at: range_end).valid? end def test_validates_inclusion_of_date_range range_begin = 1.year.until(Date.today) range_end = Date.today Topic.validates_inclusion_of(:created_at, in: range_begin..range_end) - assert Topic.new(title: 'aaa', created_at: 2.years.until(Date.today)).invalid? - assert Topic.new(title: 'aaa', created_at: 3.months.until(Date.today)).valid? - assert Topic.new(title: 'aaa', created_at: 37.weeks.since(Date.today)).invalid? - assert Topic.new(title: 'aaa', created_at: 1.year.until(Date.today)).valid? - assert Topic.new(title: 'aaa', created_at: Date.today).valid? - assert Topic.new(title: 'aaa', created_at: range_begin).valid? - assert Topic.new(title: 'aaa', created_at: range_end).valid? + assert Topic.new(title: "aaa", created_at: 2.years.until(Date.today)).invalid? + assert Topic.new(title: "aaa", created_at: 3.months.until(Date.today)).valid? + assert Topic.new(title: "aaa", created_at: 37.weeks.since(Date.today)).invalid? + assert Topic.new(title: "aaa", created_at: 1.year.until(Date.today)).valid? + assert Topic.new(title: "aaa", created_at: Date.today).valid? + assert Topic.new(title: "aaa", created_at: range_begin).valid? + assert Topic.new(title: "aaa", created_at: range_end).valid? end def test_validates_inclusion_of_date_time_range range_begin = 1.year.until(DateTime.current) range_end = DateTime.current Topic.validates_inclusion_of(:created_at, in: range_begin..range_end) - assert Topic.new(title: 'aaa', created_at: 2.years.until(DateTime.current)).invalid? - assert Topic.new(title: 'aaa', created_at: 3.months.until(DateTime.current)).valid? - assert Topic.new(title: 'aaa', created_at: 37.weeks.since(DateTime.current)).invalid? - assert Topic.new(title: 'aaa', created_at: range_begin).valid? - assert Topic.new(title: 'aaa', created_at: range_end).valid? + assert Topic.new(title: "aaa", created_at: 2.years.until(DateTime.current)).invalid? + assert Topic.new(title: "aaa", created_at: 3.months.until(DateTime.current)).valid? + assert Topic.new(title: "aaa", created_at: 37.weeks.since(DateTime.current)).invalid? + assert Topic.new(title: "aaa", created_at: range_begin).valid? + assert Topic.new(title: "aaa", created_at: range_end).valid? end def test_validates_inclusion_of @@ -122,7 +121,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_with_lambda - Topic.validates_inclusion_of :title, in: lambda{ |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } + Topic.validates_inclusion_of :title, in: lambda { |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } t = Topic.new t.title = "wasabi" diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb index 11dce1df20..62d9eaa346 100644 --- a/activemodel/test/cases/validations/length_validation_test.rb +++ b/activemodel/test/cases/validations/length_validation_test.rb @@ -1,7 +1,7 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' -require 'models/person' +require "models/topic" +require "models/person" class LengthValidationTest < ActiveModel::TestCase def teardown @@ -125,7 +125,7 @@ class LengthValidationTest < ActiveModel::TestCase def test_optionally_validates_length_of_using_within Topic.validates_length_of :title, :content, within: 3..5, allow_nil: true - t = Topic.new('title' => 'abc', 'content' => 'abcd') + t = Topic.new("title" => "abc", "content" => "abcd") assert t.valid? t.title = nil @@ -228,17 +228,17 @@ class LengthValidationTest < ActiveModel::TestCase end def test_validates_length_of_custom_errors_for_both_too_short_and_too_long - Topic.validates_length_of :title, minimum: 3, maximum: 5, too_short: 'too short', too_long: 'too long' + Topic.validates_length_of :title, minimum: 3, maximum: 5, too_short: "too short", too_long: "too long" - t = Topic.new(title: 'a') + t = Topic.new(title: "a") assert t.invalid? assert t.errors[:title].any? - assert_equal ['too short'], t.errors['title'] + assert_equal ["too short"], t.errors["title"] - t = Topic.new(title: 'aaaaaa') + t = Topic.new(title: "aaaaaa") assert t.invalid? assert t.errors[:title].any? - assert_equal ['too long'], t.errors['title'] + assert_equal ["too long"], t.errors["title"] end def test_validates_length_of_custom_errors_for_is_with_message @@ -318,43 +318,6 @@ class LengthValidationTest < ActiveModel::TestCase assert_equal ["is the wrong length (should be 5 characters)"], t.errors["title"] end - def test_validates_length_of_with_block - assert_deprecated do - Topic.validates_length_of( - :content, - minimum: 5, - too_short: "Your essay must be at least %{count} words.", - tokenizer: lambda {|str| str.scan(/\w+/) }, - ) - end - t = Topic.new(content: "this content should be long enough") - assert t.valid? - - t.content = "not long enough" - assert t.invalid? - assert t.errors[:content].any? - assert_equal ["Your essay must be at least 5 words."], t.errors[:content] - end - - - def test_validates_length_of_with_symbol - assert_deprecated do - Topic.validates_length_of( - :content, - minimum: 5, - too_short: "Your essay must be at least %{count} words.", - tokenizer: :my_word_tokenizer, - ) - end - t = Topic.new(content: "this content should be long enough") - assert t.valid? - - t.content = "not long enough" - assert t.invalid? - assert t.errors[:content].any? - assert_equal ["Your essay must be at least 5 words."], t.errors[:content] - end - def test_validates_length_of_for_integer Topic.validates_length_of(:approved, is: 4) diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 74a048537d..fefab29f15 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -1,13 +1,12 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' -require 'models/person' +require "models/topic" +require "models/person" -require 'bigdecimal' -require 'active_support/core_ext/big_decimal' +require "bigdecimal" +require "active_support/core_ext/big_decimal" class NumericalityValidationTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end @@ -36,6 +35,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!(NIL + FLOATS + INTEGERS + BIGDECIMAL + INFINITY) end + def test_validates_numericality_of_with_blank_allowed + Topic.validates_numericality_of :approved, allow_blank: true + + invalid!(JUNK) + valid!(NIL + BLANK + FLOATS + INTEGERS + BIGDECIMAL + INFINITY) + end + def test_validates_numericality_of_with_integer_only Topic.validates_numericality_of :approved, only_integer: true @@ -68,119 +74,119 @@ class NumericalityValidationTest < ActiveModel::TestCase def test_validates_numericality_with_greater_than Topic.validates_numericality_of :approved, greater_than: 10 - invalid!([-10, 10], 'must be greater than 10') + invalid!([-10, 10], "must be greater than 10") valid!([11]) end def test_validates_numericality_with_greater_than_using_differing_numeric_types - Topic.validates_numericality_of :approved, greater_than: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, greater_than: BigDecimal.new("97.18") - invalid!([-97.18, BigDecimal.new('97.18'), BigDecimal('-97.18')], 'must be greater than 97.18') - valid!([97.18, 98, BigDecimal.new('98')]) # Notice the 97.18 as a float is greater than 97.18 as a BigDecimal due to floating point precision + invalid!([-97.18, BigDecimal.new("97.18"), BigDecimal("-97.18")], "must be greater than 97.18") + valid!([97.18, 98, BigDecimal.new("98")]) # Notice the 97.18 as a float is greater than 97.18 as a BigDecimal due to floating point precision end def test_validates_numericality_with_greater_than_using_string_value Topic.validates_numericality_of :approved, greater_than: 10 - invalid!(['-10', '9', '9.9', '10'], 'must be greater than 10') - valid!(['10.1', '11']) + invalid!(["-10", "9", "9.9", "10"], "must be greater than 10") + valid!(["10.1", "11"]) end def test_validates_numericality_with_greater_than_or_equal Topic.validates_numericality_of :approved, greater_than_or_equal_to: 10 - invalid!([-9, 9], 'must be greater than or equal to 10') + invalid!([-9, 9], "must be greater than or equal to 10") valid!([10]) end def test_validates_numericality_with_greater_than_or_equal_using_differing_numeric_types - Topic.validates_numericality_of :approved, greater_than_or_equal_to: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, greater_than_or_equal_to: BigDecimal.new("97.18") - invalid!([-97.18, 97.17, 97, BigDecimal.new('97.17'), BigDecimal.new('-97.18')], 'must be greater than or equal to 97.18') - valid!([97.18, 98, BigDecimal.new('97.19')]) + invalid!([-97.18, 97.17, 97, BigDecimal.new("97.17"), BigDecimal.new("-97.18")], "must be greater than or equal to 97.18") + valid!([97.18, 98, BigDecimal.new("97.19")]) end def test_validates_numericality_with_greater_than_or_equal_using_string_value Topic.validates_numericality_of :approved, greater_than_or_equal_to: 10 - invalid!(['-10', '9', '9.9'], 'must be greater than or equal to 10') - valid!(['10', '10.1', '11']) + invalid!(["-10", "9", "9.9"], "must be greater than or equal to 10") + valid!(["10", "10.1", "11"]) end def test_validates_numericality_with_equal_to Topic.validates_numericality_of :approved, equal_to: 10 - invalid!([-10, 11] + INFINITY, 'must be equal to 10') + invalid!([-10, 11] + INFINITY, "must be equal to 10") valid!([10]) end def test_validates_numericality_with_equal_to_using_differing_numeric_types - Topic.validates_numericality_of :approved, equal_to: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, equal_to: BigDecimal.new("97.18") - invalid!([-97.18, 97.18], 'must be equal to 97.18') - valid!([BigDecimal.new('97.18')]) + invalid!([-97.18, 97.18], "must be equal to 97.18") + valid!([BigDecimal.new("97.18")]) end def test_validates_numericality_with_equal_to_using_string_value Topic.validates_numericality_of :approved, equal_to: 10 - invalid!(['-10', '9', '9.9', '10.1', '11'], 'must be equal to 10') - valid!(['10']) + invalid!(["-10", "9", "9.9", "10.1", "11"], "must be equal to 10") + valid!(["10"]) end def test_validates_numericality_with_less_than Topic.validates_numericality_of :approved, less_than: 10 - invalid!([10], 'must be less than 10') + invalid!([10], "must be less than 10") valid!([-9, 9]) end def test_validates_numericality_with_less_than_using_differing_numeric_types - Topic.validates_numericality_of :approved, less_than: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, less_than: BigDecimal.new("97.18") - invalid!([97.18, BigDecimal.new('97.18')], 'must be less than 97.18') - valid!([-97.0, 97.0, -97, 97, BigDecimal.new('-97'), BigDecimal.new('97')]) + invalid!([97.18, BigDecimal.new("97.18")], "must be less than 97.18") + valid!([-97.0, 97.0, -97, 97, BigDecimal.new("-97"), BigDecimal.new("97")]) end def test_validates_numericality_with_less_than_using_string_value Topic.validates_numericality_of :approved, less_than: 10 - invalid!(['10', '10.1', '11'], 'must be less than 10') - valid!(['-10', '9', '9.9']) + invalid!(["10", "10.1", "11"], "must be less than 10") + valid!(["-10", "9", "9.9"]) end def test_validates_numericality_with_less_than_or_equal_to Topic.validates_numericality_of :approved, less_than_or_equal_to: 10 - invalid!([11], 'must be less than or equal to 10') + invalid!([11], "must be less than or equal to 10") valid!([-10, 10]) end def test_validates_numericality_with_less_than_or_equal_to_using_differing_numeric_types - Topic.validates_numericality_of :approved, less_than_or_equal_to: BigDecimal.new('97.18') + Topic.validates_numericality_of :approved, less_than_or_equal_to: BigDecimal.new("97.18") - invalid!([97.18, 98], 'must be less than or equal to 97.18') - valid!([-97.18, BigDecimal.new('-97.18'), BigDecimal.new('97.18')]) + invalid!([97.18, 98], "must be less than or equal to 97.18") + valid!([-97.18, BigDecimal.new("-97.18"), BigDecimal.new("97.18")]) end def test_validates_numericality_with_less_than_or_equal_using_string_value Topic.validates_numericality_of :approved, less_than_or_equal_to: 10 - invalid!(['10.1', '11'], 'must be less than or equal to 10') - valid!(['-10', '9', '9.9', '10']) + invalid!(["10.1", "11"], "must be less than or equal to 10") + valid!(["-10", "9", "9.9", "10"]) end def test_validates_numericality_with_odd Topic.validates_numericality_of :approved, odd: true - invalid!([-2, 2], 'must be odd') + invalid!([-2, 2], "must be odd") valid!([-1, 1]) end def test_validates_numericality_with_even Topic.validates_numericality_of :approved, even: true - invalid!([-1, 1], 'must be even') + invalid!([-1, 1], "must be even") valid!([-2, 2]) end @@ -201,8 +207,8 @@ class NumericalityValidationTest < ActiveModel::TestCase def test_validates_numericality_with_other_than_using_string_value Topic.validates_numericality_of :approved, other_than: 0 - invalid!(['0', '0.0']) - valid!(['-1', '1.1', '42']) + invalid!(["0", "0.0"]) + valid!(["-1", "1.1", "42"]) end def test_validates_numericality_with_proc @@ -255,34 +261,34 @@ class NumericalityValidationTest < ActiveModel::TestCase end def test_validates_numericality_with_invalid_args - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, greater_than_or_equal_to: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, less_than_or_equal_to: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, greater_than: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, less_than: "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, equal_to: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, greater_than_or_equal_to: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, less_than_or_equal_to: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, greater_than: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, less_than: "foo" } + assert_raise(ArgumentError) { Topic.validates_numericality_of :approved, equal_to: "foo" } end private - def invalid!(values, error = nil) - with_each_topic_approved_value(values) do |topic, value| - assert topic.invalid?, "#{value.inspect} not rejected as a number" - assert topic.errors[:approved].any?, "FAILED for #{value.inspect}" - assert_equal error, topic.errors[:approved].first if error + def invalid!(values, error = nil) + with_each_topic_approved_value(values) do |topic, value| + assert topic.invalid?, "#{value.inspect} not rejected as a number" + assert topic.errors[:approved].any?, "FAILED for #{value.inspect}" + assert_equal error, topic.errors[:approved].first if error + end end - end - def valid!(values) - with_each_topic_approved_value(values) do |topic, value| - assert topic.valid?, "#{value.inspect} not accepted as a number with validation error: #{topic.errors[:approved].first}" + def valid!(values) + with_each_topic_approved_value(values) do |topic, value| + assert topic.valid?, "#{value.inspect} not accepted as a number with validation error: #{topic.errors[:approved].first}" + end end - end - def with_each_topic_approved_value(values) - topic = Topic.new(title: "numeric test", content: "whatever") - values.each do |value| - topic.approved = value - yield topic, value + def with_each_topic_approved_value(values) + topic = Topic.new(title: "numeric test", content: "whatever") + values.each do |value| + topic.approved = value + yield topic, value + end end - end end diff --git a/activemodel/test/cases/validations/presence_validation_test.rb b/activemodel/test/cases/validations/presence_validation_test.rb index 59b9db0795..feda817698 100644 --- a/activemodel/test/cases/validations/presence_validation_test.rb +++ b/activemodel/test/cases/validations/presence_validation_test.rb @@ -1,11 +1,10 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' -require 'models/person' -require 'models/custom_reader' +require "models/topic" +require "models/person" +require "models/custom_reader" class PresenceValidationTest < ActiveModel::TestCase - teardown do Topic.clear_validators! Person.clear_validators! diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb index 04101f3545..011033606e 100644 --- a/activemodel/test/cases/validations/validates_test.rb +++ b/activemodel/test/cases/validations/validates_test.rb @@ -1,8 +1,8 @@ -require 'cases/helper' -require 'models/person' -require 'models/topic' -require 'models/person_with_validator' -require 'validators/namespace/email_validator' +require "cases/helper" +require "models/person" +require "models/topic" +require "models/person_with_validator" +require "validators/namespace/email_validator" class ValidatesTest < ActiveModel::TestCase setup :reset_callbacks @@ -17,21 +17,21 @@ class ValidatesTest < ActiveModel::TestCase def test_validates_with_messages_empty Person.validates :title, presence: { message: "" } person = Person.new - assert !person.valid?, 'person should not be valid.' + assert !person.valid?, "person should not be valid." end def test_validates_with_built_in_validation Person.validates :title, numericality: true person = Person.new person.valid? - assert_equal ['is not a number'], person.errors[:title] + assert_equal ["is not a number"], person.errors[:title] end def test_validates_with_attribute_specified_as_string Person.validates "title", numericality: true person = Person.new person.valid? - assert_equal ['is not a number'], person.errors[:title] + assert_equal ["is not a number"], person.errors[:title] person = Person.new person.title = 123 @@ -39,24 +39,24 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_built_in_validation_and_options - Person.validates :salary, numericality: { message: 'my custom message' } + Person.validates :salary, numericality: { message: "my custom message" } person = Person.new person.valid? - assert_equal ['my custom message'], person.errors[:salary] + assert_equal ["my custom message"], person.errors[:salary] end def test_validates_with_validator_class Person.validates :karma, email: true person = Person.new person.valid? - assert_equal ['is not an email'], person.errors[:karma] + assert_equal ["is not an email"], person.errors[:karma] end def test_validates_with_namespaced_validator_class - Person.validates :karma, :'namespace/email' => true + Person.validates :karma, 'namespace/email': true person = Person.new person.valid? - assert_equal ['is not an email'], person.errors[:karma] + assert_equal ["is not an email"], person.errors[:karma] end def test_validates_with_if_as_local_conditions @@ -89,7 +89,7 @@ class ValidatesTest < ActiveModel::TestCase Person.validates :karma, format: /positive|negative/ person = Person.new assert person.invalid? - assert_equal ['is invalid'], person.errors[:karma] + assert_equal ["is invalid"], person.errors[:karma] person.karma = "positive" assert person.valid? end @@ -98,7 +98,7 @@ class ValidatesTest < ActiveModel::TestCase Person.validates :gender, inclusion: %w(m f) person = Person.new assert person.invalid? - assert_equal ['is not included in the list'], person.errors[:gender] + assert_equal ["is not included in the list"], person.errors[:gender] person.gender = "m" assert person.valid? end @@ -107,16 +107,16 @@ class ValidatesTest < ActiveModel::TestCase Person.validates :karma, length: 6..20 person = Person.new assert person.invalid? - assert_equal ['is too short (minimum is 6 characters)'], person.errors[:karma] - person.karma = 'something' + assert_equal ["is too short (minimum is 6 characters)"], person.errors[:karma] + person.karma = "something" assert person.valid? end def test_validates_with_validator_class_and_options - Person.validates :karma, email: { message: 'my custom message' } + Person.validates :karma, email: { message: "my custom message" } person = Person.new person.valid? - assert_equal ['my custom message'], person.errors[:karma] + assert_equal ["my custom message"], person.errors[:karma] end def test_validates_with_unknown_validator @@ -127,14 +127,14 @@ class ValidatesTest < ActiveModel::TestCase PersonWithValidator.validates :title, presence: true person = PersonWithValidator.new person.valid? - assert_equal ['Local validator'], person.errors[:title] + assert_equal ["Local validator"], person.errors[:title] end def test_validates_with_included_validator_and_options - PersonWithValidator.validates :title, presence: { custom: ' please' } + PersonWithValidator.validates :title, presence: { custom: " please" } person = PersonWithValidator.new person.valid? - assert_equal ['Local validator please'], person.errors[:title] + assert_equal ["Local validator please"], person.errors[:title] end def test_validates_with_included_validator_and_wildcard_shortcut @@ -143,15 +143,15 @@ class ValidatesTest < ActiveModel::TestCase person = PersonWithValidator.new person.title = "Ms. Pacman" person.valid? - assert_equal ['does not appear to be like Mr.'], person.errors[:title] + assert_equal ["does not appear to be like Mr."], person.errors[:title] end def test_defining_extra_default_keys_for_validates - Topic.validates :title, confirmation: true, message: 'Y U NO CONFIRM' + Topic.validates :title, confirmation: true, message: "Y U NO CONFIRM" topic = Topic.new topic.title = "What's happening" topic.title_confirmation = "Not this" assert !topic.valid? - assert_equal ['Y U NO CONFIRM'], topic.errors[:title_confirmation] + assert_equal ["Y U NO CONFIRM"], topic.errors[:title_confirmation] end end diff --git a/activemodel/test/cases/validations/validations_context_test.rb b/activemodel/test/cases/validations/validations_context_test.rb index b901a1523e..25c37a572f 100644 --- a/activemodel/test/cases/validations/validations_context_test.rb +++ b/activemodel/test/cases/validations/validations_context_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' +require "models/topic" class ValidationsContextTest < ActiveModel::TestCase def teardown @@ -38,7 +38,7 @@ class ValidationsContextTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatAddsErrors, on: :create) topic = Topic.new assert topic.invalid?(:create), "Validation does run on create if 'on' is set to create" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "with a class that adds errors on multiple contexts and validating a new model" do @@ -48,10 +48,10 @@ class ValidationsContextTest < ActiveModel::TestCase assert topic.valid?, "Validation ran with no context given when 'on' is set to context1 and context2" assert topic.invalid?(:context1), "Validation did not run on context1 when 'on' is set to context1 and context2" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE assert topic.invalid?(:context2), "Validation did not run on context2 when 'on' is set to context1 and context2" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "with a class that validating a model for a multiple contexts" do @@ -62,7 +62,7 @@ class ValidationsContextTest < ActiveModel::TestCase assert topic.valid?, "Validation ran with no context given when 'on' is set to context1 and context2" assert topic.invalid?([:context1, :context2]), "Validation did not run on context1 when 'on' is set to context1 and context2" - assert topic.errors[:base].include?(ERROR_MESSAGE) - assert topic.errors[:base].include?(ANOTHER_ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE + assert_includes topic.errors[:base], ANOTHER_ERROR_MESSAGE end end diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb index c73580138d..20c11dd852 100644 --- a/activemodel/test/cases/validations/with_validation_test.rb +++ b/activemodel/test/cases/validations/with_validation_test.rb @@ -1,9 +1,8 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' +require "models/topic" class ValidatesWithTest < ActiveModel::TestCase - def teardown Topic.clear_validators! end @@ -52,7 +51,7 @@ class ValidatesWithTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatAddsErrors) topic = Topic.new assert topic.invalid?, "A class that adds errors causes the record to be invalid" - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "with a class that returns valid" do @@ -65,8 +64,8 @@ class ValidatesWithTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatAddsErrors, OtherValidatorThatAddsErrors) topic = Topic.new assert topic.invalid? - assert topic.errors[:base].include?(ERROR_MESSAGE) - assert topic.errors[:base].include?(OTHER_ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE + assert_includes topic.errors[:base], OTHER_ERROR_MESSAGE end test "with if statements that return false" do @@ -79,7 +78,7 @@ class ValidatesWithTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatAddsErrors, if: "1 == 1") topic = Topic.new assert topic.invalid? - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "with unless statements that return true" do @@ -92,13 +91,13 @@ class ValidatesWithTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatAddsErrors, unless: "1 == 2") topic = Topic.new assert topic.invalid? - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "passes all configuration options to the validator class" do topic = Topic.new validator = Minitest::Mock.new - validator.expect(:new, validator, [{foo: :bar, if: "1 == 1", class: Topic}]) + validator.expect(:new, validator, [{ foo: :bar, if: "1 == 1", class: Topic }]) validator.expect(:validate, nil, [topic]) validator.expect(:is_a?, false, [Symbol]) validator.expect(:is_a?, false, [String]) @@ -112,7 +111,7 @@ class ValidatesWithTest < ActiveModel::TestCase Topic.validates_with(ValidatorThatValidatesOptions, field: :first_name) topic = Topic.new assert topic.invalid? - assert topic.errors[:base].include?(ERROR_MESSAGE) + assert_includes topic.errors[:base], ERROR_MESSAGE end test "validates_with each validator" do @@ -160,7 +159,7 @@ class ValidatesWithTest < ActiveModel::TestCase topic = Topic.new assert !topic.valid? - assert_equal ['is missing'], topic.errors[:title] + assert_equal ["is missing"], topic.errors[:title] end test "optionally pass in the attribute being validated when validating with an instance method" do @@ -169,6 +168,6 @@ class ValidatesWithTest < ActiveModel::TestCase topic = Topic.new title: "foo" assert !topic.valid? assert topic.errors[:title].empty? - assert_equal ['is missing'], topic.errors[:content] + assert_equal ["is missing"], topic.errors[:content] end end diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 2a4e9f842f..6647191205 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -1,11 +1,11 @@ -require 'cases/helper' +require "cases/helper" -require 'models/topic' -require 'models/reply' -require 'models/custom_reader' +require "models/topic" +require "models/reply" +require "models/custom_reader" -require 'active_support/json' -require 'active_support/xml_mini' +require "active_support/json" +require "active_support/xml_mini" class ValidationsTest < ActiveModel::TestCase class CustomStrictValidationException < StandardError; end @@ -51,10 +51,10 @@ class ValidationsTest < ActiveModel::TestCase r = Reply.new r.valid? - errors = r.errors.collect {|attr, messages| [attr.to_s, messages]} + errors = r.errors.collect { |attr, messages| [attr.to_s, messages] } - assert errors.include?(["title", "is Empty"]) - assert errors.include?(["content", "is Empty"]) + assert_includes errors, ["title", "is Empty"] + assert_includes errors, ["content", "is Empty"] end def test_multiple_errors_per_attr_iteration_with_full_error_composition @@ -86,8 +86,8 @@ class ValidationsTest < ActiveModel::TestCase assert_equal ["Reply is not dignifying"], r.errors[:base] - assert errors.include?("Title is Empty") - assert errors.include?("Reply is not dignifying") + assert_includes errors, "Title is Empty" + assert_includes errors, "Reply is not dignifying" assert_equal 2, r.errors.count end @@ -101,8 +101,8 @@ class ValidationsTest < ActiveModel::TestCase assert_equal ["is invalid"], r.errors[:base] - assert errors.include?("Title is Empty") - assert errors.include?("is invalid") + assert_includes errors, "Title is Empty" + assert_includes errors, "is invalid" assert_equal 2, r.errors.count end @@ -116,7 +116,7 @@ class ValidationsTest < ActiveModel::TestCase def test_validates_each hits = 0 Topic.validates_each(:title, :content, [:title, :content]) do |record, attr| - record.errors.add attr, 'gotcha' + record.errors.add attr, "gotcha" hits += 1 end t = Topic.new("title" => "valid", "content" => "whatever") @@ -129,7 +129,7 @@ class ValidationsTest < ActiveModel::TestCase def test_validates_each_custom_reader hits = 0 CustomReader.validates_each(:title, :content, [:title, :content]) do |record, attr| - record.errors.add attr, 'gotcha' + record.errors.add attr, "gotcha" hits += 1 end t = CustomReader.new("title" => "valid", "content" => "whatever") @@ -170,7 +170,7 @@ class ValidationsTest < ActiveModel::TestCase # A common mistake -- we meant to call 'validates' Topic.validate :title, presence: true end - message = 'Unknown key: :presence. Valid keys are: :on, :if, :unless, :prepend. Perhaps you meant to call `validates` instead of `validate`?' + message = "Unknown key: :presence. Valid keys are: :on, :if, :unless, :prepend. Perhaps you meant to call `validates` instead of `validate`?" assert_equal message, error.message end @@ -198,9 +198,9 @@ class ValidationsTest < ActiveModel::TestCase end assert_nothing_raised do - klass.validate :validator_a, if: ->{ true } + klass.validate :validator_a, if: -> { true } klass.validate :validator_b, prepend: true - klass.validate :validator_c, unless: ->{ true } + klass.validate :validator_c, unless: -> { true } end t = klass.new @@ -233,25 +233,25 @@ class ValidationsTest < ActiveModel::TestCase assert t.invalid? assert_equal "can't be blank", t.errors["title"].first Topic.validates_presence_of :title, :author_name - Topic.validate {errors.add('author_email_address', 'will never be valid')} + Topic.validate { errors.add("author_email_address", "will never be valid") } Topic.validates_length_of :title, :content, minimum: 2 - t = Topic.new title: '' + t = Topic.new title: "" assert t.invalid? assert_equal :title, key = t.errors.keys[0] assert_equal "can't be blank", t.errors[key][0] - assert_equal 'is too short (minimum is 2 characters)', t.errors[key][1] + assert_equal "is too short (minimum is 2 characters)", t.errors[key][1] assert_equal :author_name, key = t.errors.keys[1] assert_equal "can't be blank", t.errors[key][0] assert_equal :author_email_address, key = t.errors.keys[2] - assert_equal 'will never be valid', t.errors[key][0] + assert_equal "will never be valid", t.errors[key][0] assert_equal :content, key = t.errors.keys[3] - assert_equal 'is too short (minimum is 2 characters)', t.errors[key][0] + assert_equal "is too short (minimum is 2 characters)", t.errors[key][0] end def test_validation_with_if_and_on - Topic.validates_presence_of :title, if: Proc.new{|x| x.author_name = "bad"; true }, on: :update + Topic.validates_presence_of :title, if: Proc.new { |x| x.author_name = "bad"; true }, on: :update t = Topic.new(title: "") @@ -271,7 +271,7 @@ class ValidationsTest < ActiveModel::TestCase assert t.invalid? assert t.errors[:title].any? - t.title = 'Things are going to change' + t.title = "Things are going to change" assert !t.invalid? end @@ -332,9 +332,9 @@ class ValidationsTest < ActiveModel::TestCase assert topic.invalid? assert_equal 3, topic.errors.size - topic.title = 'Some Title' - topic.author_name = 'Some Author' - topic.content = 'Some Content Whose Length is more than 10.' + topic.title = "Some Title" + topic.author_name = "Some Author" + topic.content = "Some Content Whose Length is more than 10." assert topic.valid? end @@ -440,7 +440,7 @@ class ValidationsTest < ActiveModel::TestCase assert duped.invalid? topic.title = nil - duped.title = 'Mathematics' + duped.title = "Mathematics" assert topic.invalid? assert duped.valid? end @@ -448,7 +448,7 @@ class ValidationsTest < ActiveModel::TestCase def test_validation_with_message_as_proc_that_takes_a_record_as_a_parameter Topic.validates_presence_of(:title, message: proc { |record| "You have failed me for the last time, #{record.author_name}." }) - t = Topic.new(author_name: 'Admiral') + t = Topic.new(author_name: "Admiral") assert t.invalid? assert_equal ["You have failed me for the last time, Admiral."], t.errors[:title] end @@ -456,7 +456,7 @@ class ValidationsTest < ActiveModel::TestCase def test_validation_with_message_as_proc_that_takes_record_and_data_as_a_parameters Topic.validates_presence_of(:title, message: proc { |record, data| "#{data[:attribute]} is missing. You have failed me for the last time, #{record.author_name}." }) - t = Topic.new(author_name: 'Admiral') + t = Topic.new(author_name: "Admiral") assert t.invalid? assert_equal ["Title is missing. You have failed me for the last time, Admiral."], t.errors[:title] end diff --git a/activemodel/test/models/custom_reader.rb b/activemodel/test/models/custom_reader.rb index 2fbcf79c3d..dc26bb10ff 100644 --- a/activemodel/test/models/custom_reader.rb +++ b/activemodel/test/models/custom_reader.rb @@ -12,4 +12,4 @@ class CustomReader def read_attribute_for_validation(key) @data[key] end -end
\ No newline at end of file +end diff --git a/activemodel/test/models/reply.rb b/activemodel/test/models/reply.rb index b77910e671..3fe11043d2 100644 --- a/activemodel/test/models/reply.rb +++ b/activemodel/test/models/reply.rb @@ -1,4 +1,4 @@ -require 'models/topic' +require "models/topic" class Reply < Topic validate :errors_on_empty_content diff --git a/activemodel/test/models/topic.rb b/activemodel/test/models/topic.rb index fed50bc361..192786c096 100644 --- a/activemodel/test/models/topic.rb +++ b/activemodel/test/models/topic.rb @@ -36,9 +36,4 @@ class Topic def my_validation_with_arg(attr) errors.add attr, "is missing" unless send(attr) end - - def my_word_tokenizer(str) - str.scan(/\w+/) - end - end diff --git a/activemodel/test/models/track_back.rb b/activemodel/test/models/track_back.rb index 768c96ecf0..357ee37d6d 100644 --- a/activemodel/test/models/track_back.rb +++ b/activemodel/test/models/track_back.rb @@ -8,4 +8,4 @@ class Post class NamedTrackBack extend ActiveModel::Naming end -end
\ No newline at end of file +end diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb index 1ec6001c48..6556b1a7d9 100644 --- a/activemodel/test/models/user.rb +++ b/activemodel/test/models/user.rb @@ -1,7 +1,7 @@ class User extend ActiveModel::Callbacks include ActiveModel::SecurePassword - + define_model_callbacks :create has_secure_password diff --git a/activemodel/test/validators/email_validator.rb b/activemodel/test/validators/email_validator.rb index cff47ac230..43011b277b 100644 --- a/activemodel/test/validators/email_validator.rb +++ b/activemodel/test/validators/email_validator.rb @@ -1,6 +1,8 @@ +require "active_support/core_ext/regexp" + class EmailValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) record.errors[attribute] << (options[:message] || "is not an email") unless - value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i + /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value) end -end
\ No newline at end of file +end diff --git a/activemodel/test/validators/namespace/email_validator.rb b/activemodel/test/validators/namespace/email_validator.rb index 57e2793ce2..8639045b0d 100644 --- a/activemodel/test/validators/namespace/email_validator.rb +++ b/activemodel/test/validators/namespace/email_validator.rb @@ -1,4 +1,4 @@ -require 'validators/email_validator' +require "validators/email_validator" module Namespace class EmailValidator < ::EmailValidator diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 0bd3c2e78c..487195a2e0 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,4 +1,232 @@ +* Deprecate passing arguments and block at the same time to + `ActiveRecord::QueryMethods#select`. + + *Prathamesh Sonpatki* + +* Optimistic locking: Added ability update locking_column value. + Ignore optimistic locking if update with new locking_column value. + + *bogdanvlviv* + +* Fixed: Optimistic locking does not work well with null in the database. + + Fixes #26024 + + *bogdanvlviv* + +* Fixed support for case insensitive comparisons of `text` columns in + PostgreSQL. + + *Edho Arief* + +* Serialize JSON attribute value `nil` as SQL `NULL`, not JSON `null` + + *Trung Duc Tran* + +* Return `true` from `update_attribute` when the value of the attribute + to be updated is unchanged. + + Fixes #26593. + + *Prathamesh Sonpatki* + +* Always store errors details information with symbols. + + When the association is autosaved we were storing the details with + string keys. This was creating inconsistency with other details that are + added using the `Errors#add` method. It was also inconsistent with the + `Errors#messages` storage. + + To fix this inconsistency we are always storing with symbols. This will + cause a small breaking change because in those cases the details could + be accessed as strings keys but now it can not. + + Fix #26499. + + *Rafael Mendonça França*, *Marcus Vieira* + +* Calling `touch` on a model using optimistic locking will now leave the model + in a non-dirty state with no attribute changes. + + Fixes #26496. + + *Jakob Skjerning* + +* Using a mysql2 connection after it fails to reconnect will now have an error message + saying the connection is closed rather than an undefined method error message. + + *Dylan Thacker-Smith* + +* PostgreSQL array columns will now respect the encoding of strings contained + in the array. + + Fixes #26326. + + *Sean Griffin* + +* Inverse association instances will now be set before `after_find` or + `after_initialize` callbacks are run. + + Fixes #26320. + + *Sean Griffin* + +* Remove unnecessarily association load when a `belongs_to` association has already been + loaded then the foreign key is changed directly and the record saved. + + *James Coleman* + +* Remove standardized column types/arguments spaces in schema dump. + + *Tim Petricola* + +* Avoid loading records from database when they are already loaded using + the `pluck` method on a collection. + + Fixes #25921. + + *Ryuta Kamizono* + +* Remove text default treated as an empty string in non-strict mode for + consistency with other types. + + Strict mode controls how MySQL handles invalid or missing values in + data-change statements such as INSERT or UPDATE. If strict mode is not + in effect, MySQL inserts adjusted values for invalid or missing values + and produces warnings. + + def test_mysql_not_null_defaults_non_strict + using_strict(false) do + with_mysql_not_null_table do |klass| + record = klass.new + assert_nil record.non_null_integer + assert_nil record.non_null_string + assert_nil record.non_null_text + assert_nil record.non_null_blob + + record.save! + record.reload + + assert_equal 0, record.non_null_integer + assert_equal "", record.non_null_string + assert_equal "", record.non_null_text + assert_equal "", record.non_null_blob + end + end + end + + https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-strict + + *Ryuta Kamizono* + +* Sqlite3 migrations to add a column to an existing table can now be + successfully rolled back when the column was given and invalid column + type. + + Fixes #26087 + + *Travis O'Neill* + +* Deprecate `sanitize_conditions`. Use `sanitize_sql` instead. + + *Ryuta Kamizono* + +* Doing count on relations that contain LEFT OUTER JOIN Arel node no longer + force a DISTINCT. This solves issues when using count after a left_joins. + + *Maxime Handfield Lapointe* + +* RecordNotFound raised by association.find exposes `id`, `primary_key` and + `model` methods to be consistent with RecordNotFound raised by Record.find. + + *Michel Pigassou* + +* Hashes can once again be passed to setters of `composed_of`, if all of the + mapping methods are methods implemented on `Hash`. + + Fixes #25978. + + *Sean Griffin* + +* Fix the SELECT statement in `#table_comment` for MySQL. + + *Takeshi Akima* + +* Virtual attributes will no longer raise when read on models loaded from the + database + + *Sean Griffin* + +* Support calling the method `merge` in `scope`'s lambda. + + *Yasuhiro Sugino* + +* Fixes multi-parameter attributes conversion with invalid params. + + *Hiroyuki Ishii* + +* Add newline between each migration in `structure.sql`. + + Keeps schema migration inserts as a single commit, but allows for easier + git diffing. + + Fixes #25504. + + *Grey Baker*, *Norberto Lopes* + +* The flag `error_on_ignored_order_or_limit` has been deprecated in favor of + the current `error_on_ignored_order`. + + *Xavier Noria* + +* Batch processing methods support `limit`: + + Post.limit(10_000).find_each do |post| + # ... + end + + It also works in `find_in_batches` and `in_batches`. + + *Xavier Noria* + +* Using `group` with an attribute that has a custom type will properly cast + the hash keys after calling a calculation method like `count`. + + Fixes #25595. + + *Sean Griffin* + +* Fix the generated `#to_param` method to use `omission: ''` so that + the resulting output is actually up to 20 characters, not + effectively 17 to leave room for the default "...". + Also call `#parameterize` before `#truncate` and make the + `separator: /-/` to maximize the information included in the + output. + + Fixes #23635. + + *Rob Biedenharn* + +* Ensure concurrent invocations of the connection reaper cannot allocate the + same connection to two threads. + + Fixes #25585. + + *Matthew Draper* + +* Inspecting an object with an associated array of over 10 elements no longer + truncates the array, preventing `inspect` from looping infinitely in some + cases. + + *Kevin McPhillips* + +* Removed the unused methods `ActiveRecord::Base.connection_id` and + `ActiveRecord::Base.connection_id=`. + + *Sean Griffin* + * Ensure hashes can be assigned to attributes created using `composed_of`. + Fixes #25210. *Sean Griffin* @@ -13,15 +241,15 @@ *Johannes Opper* -* Introduce ActiveRecord::TransactionSerializationError for catching +* Introduce `ActiveRecord::TransactionSerializationError` for catching transaction serialization failures or deadlocks. *Erol Fornoles* -* PostgreSQL: Fix db:structure:load silent failure on SQL error +* PostgreSQL: Fix `db:structure:load` silent failure on SQL error. - The command line flag "-v ON_ERROR_STOP=1" should be used - when invoking psql to make sure errors are not suppressed. + The command line flag `-v ON_ERROR_STOP=1` should be used + when invoking `psql` to make sure errors are not suppressed. Example: diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 012db35765..e077d345d6 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -1,4 +1,4 @@ -require 'rake/testtask' +require "rake/testtask" require File.expand_path(File.dirname(__FILE__)) + "/test/config" require File.expand_path(File.dirname(__FILE__)) + "/test/support/config" @@ -17,12 +17,12 @@ def run_without_aborting(*tasks) abort "Errors running #{errors.join(', ')}" if errors.any? end -desc 'Run mysql2, sqlite, and postgresql tests by default' -task :default => :test +desc "Run mysql2, sqlite, and postgresql tests by default" +task default: :test task :package -desc 'Run mysql2, sqlite, and postgresql tests' +desc "Run mysql2, sqlite, and postgresql tests" task :test do tasks = defined?(JRUBY_VERSION) ? %w(test_jdbcmysql test_jdbcsqlite3 test_jdbcpostgresql) : @@ -39,19 +39,19 @@ namespace :test do end end -desc 'Build MySQL and PostgreSQL test databases' +desc "Build MySQL and PostgreSQL test databases" namespace :db do - task :create => ['db:mysql:build', 'db:postgresql:build'] - task :drop => ['db:mysql:drop', 'db:postgresql:drop'] + task create: ["db:mysql:build", "db:postgresql:build"] + task drop: ["db:mysql:drop", "db:postgresql:drop"] end %w( mysql2 postgresql sqlite3 sqlite3_mem db2 oracle jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb ).each do |adapter| namespace :test do Rake::TestTask.new(adapter => "#{adapter}:env") { |t| - adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z0-9]+/] - t.libs << 'test' + adapter_short = adapter == "db2" ? adapter : adapter[/^[a-z0-9]+/] + t.libs << "test" t.test_files = (Dir.glob( "test/cases/**/*_test.rb" ).reject { - |x| x =~ /\/adapters\// + |x| x.include?("/adapters/") } + Dir.glob("test/cases/adapters/#{adapter_short}/**/*_test.rb")) t.warning = true @@ -61,23 +61,23 @@ end namespace :isolated do task adapter => "#{adapter}:env" do - adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z0-9]+/] + adapter_short = adapter == "db2" ? adapter : adapter[/^[a-z0-9]+/] puts [adapter, adapter_short].inspect (Dir["test/cases/**/*_test.rb"].reject { - |x| x =~ /\/adapters\// + |x| x.include?("/adapters/") } + Dir["test/cases/adapters/#{adapter_short}/**/*_test.rb"]).all? do |file| - sh(Gem.ruby, '-w' ,"-Itest", file) - end or raise "Failures" + sh(Gem.ruby, "-w" ,"-Itest", file) + end || raise("Failures") end end end namespace adapter do - task :test => "test_#{adapter}" - task :isolated_test => "isolated_test_#{adapter}" + task test: "test_#{adapter}" + task isolated_test: "isolated_test_#{adapter}" # Set the connection environment for the adapter - task(:env) { ENV['ARCONN'] = adapter } + task(:env) { ENV["ARCONN"] = adapter } end # Make sure the adapter test evaluates the env setting task @@ -87,30 +87,30 @@ end namespace :db do namespace :mysql do - desc 'Build the MySQL test databases' + desc "Build the MySQL test databases" task :build do - config = ARTest.config['connections']['mysql2'] - %x( mysql --user=#{config['arunit']['username']} --password=#{config['arunit']['password']} -e "create DATABASE #{config['arunit']['database']} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci ") - %x( mysql --user=#{config['arunit2']['username']} --password=#{config['arunit2']['password']} -e "create DATABASE #{config['arunit2']['database']} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci ") + config = ARTest.config["connections"]["mysql2"] + %x( mysql --user=#{config["arunit"]["username"]} --password=#{config["arunit"]["password"]} -e "create DATABASE #{config["arunit"]["database"]} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci ") + %x( mysql --user=#{config["arunit2"]["username"]} --password=#{config["arunit2"]["password"]} -e "create DATABASE #{config["arunit2"]["database"]} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci ") end - desc 'Drop the MySQL test databases' + desc "Drop the MySQL test databases" task :drop do - config = ARTest.config['connections']['mysql2'] - %x( mysqladmin --user=#{config['arunit']['username']} --password=#{config['arunit']['password']} -f drop #{config['arunit']['database']} ) - %x( mysqladmin --user=#{config['arunit2']['username']} --password=#{config['arunit2']['password']} -f drop #{config['arunit2']['database']} ) + config = ARTest.config["connections"]["mysql2"] + %x( mysqladmin --user=#{config["arunit"]["username"]} --password=#{config["arunit"]["password"]} -f drop #{config["arunit"]["database"]} ) + %x( mysqladmin --user=#{config["arunit2"]["username"]} --password=#{config["arunit2"]["password"]} -f drop #{config["arunit2"]["database"]} ) end - desc 'Rebuild the MySQL test databases' - task :rebuild => [:drop, :build] + desc "Rebuild the MySQL test databases" + task rebuild: [:drop, :build] end namespace :postgresql do - desc 'Build the PostgreSQL test databases' + desc "Build the PostgreSQL test databases" task :build do - config = ARTest.config['connections']['postgresql'] - %x( createdb -E UTF8 -T template0 #{config['arunit']['database']} ) - %x( createdb -E UTF8 -T template0 #{config['arunit2']['database']} ) + config = ARTest.config["connections"]["postgresql"] + %x( createdb -E UTF8 -T template0 #{config["arunit"]["database"]} ) + %x( createdb -E UTF8 -T template0 #{config["arunit2"]["database"]} ) # prepare hstore if %x( createdb --version ).strip.gsub(/(.*)(\d\.\d\.\d)$/, "\\2") < "9.1.0" @@ -118,28 +118,28 @@ namespace :db do end end - desc 'Drop the PostgreSQL test databases' + desc "Drop the PostgreSQL test databases" task :drop do - config = ARTest.config['connections']['postgresql'] - %x( dropdb #{config['arunit']['database']} ) - %x( dropdb #{config['arunit2']['database']} ) + config = ARTest.config["connections"]["postgresql"] + %x( dropdb #{config["arunit"]["database"]} ) + %x( dropdb #{config["arunit2"]["database"]} ) end - desc 'Rebuild the PostgreSQL test databases' - task :rebuild => [:drop, :build] + desc "Rebuild the PostgreSQL test databases" + task rebuild: [:drop, :build] end end -task :build_mysql_databases => 'db:mysql:build' -task :drop_mysql_databases => 'db:mysql:drop' -task :rebuild_mysql_databases => 'db:mysql:rebuild' +task build_mysql_databases: "db:mysql:build" +task drop_mysql_databases: "db:mysql:drop" +task rebuild_mysql_databases: "db:mysql:rebuild" -task :build_postgresql_databases => 'db:postgresql:build' -task :drop_postgresql_databases => 'db:postgresql:drop' -task :rebuild_postgresql_databases => 'db:postgresql:rebuild' +task build_postgresql_databases: "db:postgresql:build" +task drop_postgresql_databases: "db:postgresql:drop" +task rebuild_postgresql_databases: "db:postgresql:rebuild" task :lines do - load File.expand_path('..', File.dirname(__FILE__)) + '/tools/line_statistics' + load File.expand_path("..", File.dirname(__FILE__)) + "/tools/line_statistics" files = FileList["lib/active_record/**/*.rb"] CodeTools::LineStatistics.new(files).print_loc end diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index 881dee13e4..2cd8f179dd 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -1,28 +1,28 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'activerecord' + s.name = "activerecord" s.version = version - s.summary = 'Object-relational mapper framework (part of Rails).' - s.description = 'Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in.' + s.summary = "Object-relational mapper framework (part of Rails)." + s.description = "Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'examples/**/*', 'lib/**/*'] - s.require_path = 'lib' + s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.rdoc", "examples/**/*", "lib/**/*"] + s.require_path = "lib" s.extra_rdoc_files = %w(README.rdoc) - s.rdoc_options.concat ['--main', 'README.rdoc'] + s.rdoc_options.concat ["--main", "README.rdoc"] - s.add_dependency 'activesupport', version - s.add_dependency 'activemodel', version + s.add_dependency "activesupport", version + s.add_dependency "activemodel", version - s.add_dependency 'arel', '~> 7.0' + s.add_dependency "arel", "~> 7.0" end diff --git a/activerecord/bin/test b/activerecord/bin/test index 7417b068bf..23add35d45 100755 --- a/activerecord/bin/test +++ b/activerecord/bin/test @@ -1,6 +1,8 @@ #!/usr/bin/env ruby -COMPONENT_ROOT = File.expand_path("../../", __FILE__) + +COMPONENT_ROOT = File.expand_path("..", __dir__) require File.expand_path("../tools/test", COMPONENT_ROOT) + module Minitest def self.plugin_active_record_options(opts, options) opts.separator "" @@ -14,6 +16,6 @@ module Minitest end end -Minitest.extensions.unshift 'active_record' +Minitest.extensions.unshift "active_record" exit Minitest.run(ARGV) diff --git a/activerecord/examples/performance.rb b/activerecord/examples/performance.rb index c3c46c19c5..f2fe8875b9 100644 --- a/activerecord/examples/performance.rb +++ b/activerecord/examples/performance.rb @@ -1,10 +1,10 @@ require "active_record" -require 'benchmark/ips' +require "benchmark/ips" -TIME = (ENV['BENCHMARK_TIME'] || 20).to_i -RECORDS = (ENV['BENCHMARK_RECORDS'] || TIME*1000).to_i +TIME = (ENV["BENCHMARK_TIME"] || 20).to_i +RECORDS = (ENV["BENCHMARK_RECORDS"] || TIME*1000).to_i -conn = { adapter: 'sqlite3', database: ':memory:' } +conn = { adapter: "sqlite3", database: ":memory:" } ActiveRecord::Base.establish_connection(conn) @@ -44,24 +44,24 @@ end def progress_bar(int); print "." if (int%100).zero? ; end -puts 'Generating data...' +puts "Generating data..." module ActiveRecord class Faker - LOREM = %Q{Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse non aliquet diam. Curabitur vel urna metus, quis malesuada elit. + LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse non aliquet diam. Curabitur vel urna metus, quis malesuada elit. Integer consequat tincidunt felis. Etiam non erat dolor. Vivamus imperdiet nibh sit amet diam eleifend id posuere diam malesuada. Mauris at accumsan sem. Donec id lorem neque. Fusce erat lorem, ornare eu congue vitae, malesuada quis neque. Maecenas vel urna a velit pretium fermentum. Donec tortor enim, tempor venenatis egestas a, tempor sed ipsum. Ut arcu justo, faucibus non imperdiet ac, interdum at diam. Pellentesque ipsum enim, venenatis ut iaculis vitae, varius vitae sem. Sed rutrum quam ac elit euismod bibendum. Donec ultricies ultricies magna, at lacinia libero mollis aliquam. Sed ac arcu in tortor elementum tincidunt vel interdum sem. Curabitur eget erat arcu. Praesent eget eros leo. Nam magna enim, sollicitudin vehicula scelerisque in, vulputate ut libero. - Praesent varius tincidunt commodo}.split + Praesent varius tincidunt commodo".split def self.name - LOREM.grep(/^\w*$/).sort_by { rand }.first(2).join ' ' + LOREM.grep(/^\w*$/).sort_by { rand }.first(2).join " " end def self.email - LOREM.grep(/^\w*$/).sort_by { rand }.first(2).join('@') + ".com" + LOREM.grep(/^\w*$/).sort_by { rand }.first(2).join("@") + ".com" end end end @@ -72,7 +72,7 @@ end # Using the same paragraph for all exhibits because it is very slow # to generate unique paragraphs for all exhibits. -notes = ActiveRecord::Faker::LOREM.join ' ' +notes = ActiveRecord::Faker::LOREM.join " " today = Date.today puts "Inserting #{RECORDS} users and exhibits..." @@ -95,9 +95,9 @@ puts "Done!\n" Benchmark.ips(TIME) do |x| ar_obj = Exhibit.find(1) - attrs = { name: 'sam' } - attrs_first = { name: 'sam' } - attrs_second = { name: 'tom' } + attrs = { name: "sam" } + attrs_first = { name: "sam" } + attrs_second = { name: "tom" } exhibit = { name: ActiveRecord::Faker.name, notes: notes, @@ -108,22 +108,22 @@ Benchmark.ips(TIME) do |x| ar_obj.id end - x.report 'Model.new (instantiation)' do + x.report "Model.new (instantiation)" do Exhibit.new end - x.report 'Model.new (setting attributes)' do + x.report "Model.new (setting attributes)" do Exhibit.new(attrs) end - x.report 'Model.first' do + x.report "Model.first" do Exhibit.first.look end - x.report 'Model.take' do + x.report "Model.take" do Exhibit.take end - + x.report("Model.all limit(100)") do Exhibit.look Exhibit.limit(100) end @@ -140,36 +140,36 @@ Benchmark.ips(TIME) do |x| Exhibit.look Exhibit.limit(10000) end - x.report 'Model.named_scope' do + x.report "Model.named_scope" do Exhibit.limit(10).with_name.with_notes end - x.report 'Model.create' do + x.report "Model.create" do Exhibit.create(exhibit) end - x.report 'Resource#attributes=' do + x.report "Resource#attributes=" do e = Exhibit.new(attrs_first) e.attributes = attrs_second end - x.report 'Resource#update' do - Exhibit.first.update(name: 'bob') + x.report "Resource#update" do + Exhibit.first.update(name: "bob") end - x.report 'Resource#destroy' do + x.report "Resource#destroy" do Exhibit.first.destroy end - x.report 'Model.transaction' do + x.report "Model.transaction" do Exhibit.transaction { Exhibit.new } end - x.report 'Model.find(id)' do + x.report "Model.find(id)" do User.find(1) end - x.report 'Model.find_by_sql' do + x.report "Model.find_by_sql" do Exhibit.find_by_sql("SELECT * FROM exhibits WHERE id = #{(rand * 1000 + 1).to_i}").first end diff --git a/activerecord/examples/simple.rb b/activerecord/examples/simple.rb index 5a041e8417..c3648fee48 100644 --- a/activerecord/examples/simple.rb +++ b/activerecord/examples/simple.rb @@ -1,13 +1,13 @@ -require 'active_record' +require "active_record" class Person < ActiveRecord::Base - establish_connection adapter: 'sqlite3', database: 'foobar.db' + establish_connection adapter: "sqlite3", database: "foobar.db" connection.create_table table_name, force: true do |t| t.string :name end end -bob = Person.create!(name: 'bob') +bob = Person.create!(name: "bob") puts Person.all.inspect bob.destroy puts Person.all.inspect diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index baa497dc98..3b5dab16cb 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -21,13 +21,13 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'active_support' -require 'active_support/rails' -require 'active_model' -require 'arel' +require "active_support" +require "active_support/rails" +require "active_model" +require "arel" -require 'active_record/version' -require 'active_record/attribute_set' +require "active_record/version" +require "active_record/attribute_set" module ActiveRecord extend ActiveSupport::Autoload @@ -46,7 +46,7 @@ module ActiveRecord autoload :Integration autoload :LegacyYamlAdapter autoload :Migration - autoload :Migrator, 'active_record/migration' + autoload :Migrator, "active_record/migration" autoload :ModelSchema autoload :NestedAttributes autoload :NoTouching @@ -56,7 +56,7 @@ module ActiveRecord autoload :Querying autoload :CollectionCacheKey autoload :ReadonlyAttributes - autoload :RecordInvalid, 'active_record/validations' + autoload :RecordInvalid, "active_record/validations" autoload :Reflection autoload :RuntimeRegistry autoload :Sanitization @@ -68,7 +68,6 @@ module ActiveRecord autoload :StatementCache autoload :Store autoload :Suppressor - autoload :TableMetadata autoload :Timestamp autoload :Transactions autoload :Translation @@ -76,9 +75,9 @@ module ActiveRecord autoload :SecureToken eager_autoload do - autoload :ActiveRecordError, 'active_record/errors' - autoload :ConnectionNotEstablished, 'active_record/errors' - autoload :ConnectionAdapters, 'active_record/connection_adapters/abstract_adapter' + autoload :ActiveRecordError, "active_record/errors" + autoload :ConnectionNotEstablished, "active_record/errors" + autoload :ConnectionAdapters, "active_record/connection_adapters/abstract_adapter" autoload :Aggregations autoload :Associations @@ -90,7 +89,7 @@ module ActiveRecord autoload :AssociationRelation autoload :NullRelation - autoload_under 'relation' do + autoload_under "relation" do autoload :QueryMethods autoload :FinderMethods autoload :Calculations @@ -101,11 +100,12 @@ module ActiveRecord end autoload :Result + autoload :TableMetadata end module Coders - autoload :YAMLColumn, 'active_record/coders/yaml_column' - autoload :JSON, 'active_record/coders/json' + autoload :YAMLColumn, "active_record/coders/yaml_column" + autoload :JSON, "active_record/coders/json" end module AttributeMethods @@ -153,13 +153,13 @@ module ActiveRecord extend ActiveSupport::Autoload autoload :DatabaseTasks - autoload :SQLiteDatabaseTasks, 'active_record/tasks/sqlite_database_tasks' - autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks' + autoload :SQLiteDatabaseTasks, "active_record/tasks/sqlite_database_tasks" + autoload :MySQLDatabaseTasks, "active_record/tasks/mysql_database_tasks" autoload :PostgreSQLDatabaseTasks, - 'active_record/tasks/postgresql_database_tasks' + "active_record/tasks/postgresql_database_tasks" end - autoload :TestFixtures, 'active_record/fixtures' + autoload :TestFixtures, "active_record/fixtures" def self.eager_load! super @@ -176,5 +176,5 @@ ActiveSupport.on_load(:active_record) do end ActiveSupport.on_load(:i18n) do - I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' + I18n.load_path << File.dirname(__FILE__) + "/active_record/locale/en.yml" end diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 8bed5bca28..5ca8fe576e 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -24,257 +24,259 @@ module ActiveRecord super end - # Active Record implements aggregation through a macro-like class method called #composed_of - # for representing attributes as value objects. It expresses relationships like "Account [is] - # composed of Money [among other things]" or "Person [is] composed of [an] address". Each call - # to the macro adds a description of how the value objects are created from the attributes of - # the entity object (when the entity is initialized either as a new object or from finding an - # existing object) and how it can be turned back into attributes (when the entity is saved to - # the database). - # - # class Customer < ActiveRecord::Base - # composed_of :balance, class_name: "Money", mapping: %w(amount currency) - # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ] - # end - # - # The customer class now has the following methods to manipulate the value objects: - # * <tt>Customer#balance, Customer#balance=(money)</tt> - # * <tt>Customer#address, Customer#address=(address)</tt> - # - # These methods will operate with value objects like the ones described below: - # - # class Money - # include Comparable - # attr_reader :amount, :currency - # EXCHANGE_RATES = { "USD_TO_DKK" => 6 } - # - # def initialize(amount, currency = "USD") - # @amount, @currency = amount, currency - # end - # - # def exchange_to(other_currency) - # exchanged_amount = (amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor - # Money.new(exchanged_amount, other_currency) - # end - # - # def ==(other_money) - # amount == other_money.amount && currency == other_money.currency - # end - # - # def <=>(other_money) - # if currency == other_money.currency - # amount <=> other_money.amount - # else - # amount <=> other_money.exchange_to(currency).amount - # end - # end - # end - # - # class Address - # attr_reader :street, :city - # def initialize(street, city) - # @street, @city = street, city - # end - # - # def close_to?(other_address) - # city == other_address.city - # end - # - # def ==(other_address) - # city == other_address.city && street == other_address.street - # end - # end - # - # Now it's possible to access attributes from the database through the value objects instead. If - # you choose to name the composition the same as the attribute's name, it will be the only way to - # access that attribute. That's the case with our +balance+ attribute. You interact with the value - # objects just like you would with any other attribute: - # - # customer.balance = Money.new(20) # sets the Money value object and the attribute - # customer.balance # => Money value object - # customer.balance.exchange_to("DKK") # => Money.new(120, "DKK") - # customer.balance > Money.new(10) # => true - # customer.balance == Money.new(20) # => true - # customer.balance < Money.new(5) # => false - # - # Value objects can also be composed of multiple attributes, such as the case of Address. The order - # of the mappings will determine the order of the parameters. - # - # customer.address_street = "Hyancintvej" - # customer.address_city = "Copenhagen" - # customer.address # => Address.new("Hyancintvej", "Copenhagen") - # - # customer.address = Address.new("May Street", "Chicago") - # customer.address_street # => "May Street" - # customer.address_city # => "Chicago" - # - # == Writing value objects - # - # Value objects are immutable and interchangeable objects that represent a given value, such as - # a Money object representing $5. Two Money objects both representing $5 should be equal (through - # methods such as <tt>==</tt> and <tt><=></tt> from Comparable if ranking makes sense). This is - # unlike entity objects where equality is determined by identity. An entity class such as Customer can - # easily have two different objects that both have an address on Hyancintvej. Entity identity is - # determined by object or relational unique identifiers (such as primary keys). Normal - # ActiveRecord::Base classes are entity objects. - # - # It's also important to treat the value objects as immutable. Don't allow the Money object to have - # its amount changed after creation. Create a new Money object with the new value instead. The - # <tt>Money#exchange_to</tt> method is an example of this. It returns a new value object instead of changing - # its own values. Active Record won't persist value objects that have been changed through means - # other than the writer method. - # - # The immutable requirement is enforced by Active Record by freezing any object assigned as a value - # object. Attempting to change it afterwards will result in a +RuntimeError+. - # - # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not - # keeping value objects immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable - # - # == Custom constructors and converters - # - # By default value objects are initialized by calling the <tt>new</tt> constructor of the value - # class passing each of the mapped attributes, in the order specified by the <tt>:mapping</tt> - # option, as arguments. If the value class doesn't support this convention then #composed_of allows - # a custom constructor to be specified. - # - # When a new value is assigned to the value object, the default assumption is that the new value - # is an instance of the value class. Specifying a custom converter allows the new value to be automatically - # converted to an instance of value class if necessary. - # - # For example, the +NetworkResource+ model has +network_address+ and +cidr_range+ attributes that should be - # aggregated using the +NetAddr::CIDR+ value class (http://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR). - # The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter. - # New values can be assigned to the value object using either another +NetAddr::CIDR+ object, a string - # or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet - # these requirements: - # - # class NetworkResource < ActiveRecord::Base - # composed_of :cidr, - # class_name: 'NetAddr::CIDR', - # mapping: [ %w(network_address network), %w(cidr_range bits) ], - # allow_nil: true, - # constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") }, - # converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) } - # end - # - # # This calls the :constructor - # network_resource = NetworkResource.new(network_address: '192.168.0.1', cidr_range: 24) - # - # # These assignments will both use the :converter - # network_resource.cidr = [ '192.168.2.1', 8 ] - # network_resource.cidr = '192.168.0.1/24' - # - # # This assignment won't use the :converter as the value is already an instance of the value class - # network_resource.cidr = NetAddr::CIDR.create('192.168.2.1/8') - # - # # Saving and then reloading will use the :constructor on reload - # network_resource.save - # network_resource.reload - # - # == Finding records by a value object - # - # Once a #composed_of relationship is specified for a model, records can be loaded from the database - # by specifying an instance of the value object in the conditions hash. The following example - # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD": - # - # Customer.where(balance: Money.new(20, "USD")) - # - module ClassMethods - # Adds reader and writer methods for manipulating a value object: - # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods. - # - # Options are: - # * <tt>:class_name</tt> - Specifies the class name of the association. Use it only if that name - # can't be inferred from the part id. So <tt>composed_of :address</tt> will by default be linked - # to the Address class, but if the real class name is +CompanyAddress+, you'll have to specify it - # with this option. - # * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value - # object. Each mapping is represented as an array where the first item is the name of the - # entity attribute and the second item is the name of the attribute in the value object. The - # order in which mappings are defined determines the order in which attributes are sent to the - # value class constructor. - # * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped - # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all - # mapped attributes. - # This defaults to +false+. - # * <tt>:constructor</tt> - A symbol specifying the name of the constructor method or a Proc that - # is called to initialize the value object. The constructor is passed all of the mapped attributes, - # in the order that they are defined in the <tt>:mapping option</tt>, as arguments and uses them - # to instantiate a <tt>:class_name</tt> object. - # The default is <tt>:new</tt>. - # * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt> - # or a Proc that is called when a new value is assigned to the value object. The converter is - # passed the single value that is used in the assignment and is only called if the new value is - # not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter - # can return nil to skip the assignment. - # - # Option examples: - # composed_of :temperature, mapping: %w(reading celsius) - # composed_of :balance, class_name: "Money", mapping: %w(balance amount), - # converter: Proc.new { |balance| balance.to_money } - # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ] - # composed_of :gps_location - # composed_of :gps_location, allow_nil: true - # composed_of :ip_address, - # class_name: 'IPAddr', - # mapping: %w(ip to_i), - # constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) }, - # converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) } - # - def composed_of(part_id, options = {}) - options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter) + # Active Record implements aggregation through a macro-like class method called #composed_of + # for representing attributes as value objects. It expresses relationships like "Account [is] + # composed of Money [among other things]" or "Person [is] composed of [an] address". Each call + # to the macro adds a description of how the value objects are created from the attributes of + # the entity object (when the entity is initialized either as a new object or from finding an + # existing object) and how it can be turned back into attributes (when the entity is saved to + # the database). + # + # class Customer < ActiveRecord::Base + # composed_of :balance, class_name: "Money", mapping: %w(amount currency) + # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ] + # end + # + # The customer class now has the following methods to manipulate the value objects: + # * <tt>Customer#balance, Customer#balance=(money)</tt> + # * <tt>Customer#address, Customer#address=(address)</tt> + # + # These methods will operate with value objects like the ones described below: + # + # class Money + # include Comparable + # attr_reader :amount, :currency + # EXCHANGE_RATES = { "USD_TO_DKK" => 6 } + # + # def initialize(amount, currency = "USD") + # @amount, @currency = amount, currency + # end + # + # def exchange_to(other_currency) + # exchanged_amount = (amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor + # Money.new(exchanged_amount, other_currency) + # end + # + # def ==(other_money) + # amount == other_money.amount && currency == other_money.currency + # end + # + # def <=>(other_money) + # if currency == other_money.currency + # amount <=> other_money.amount + # else + # amount <=> other_money.exchange_to(currency).amount + # end + # end + # end + # + # class Address + # attr_reader :street, :city + # def initialize(street, city) + # @street, @city = street, city + # end + # + # def close_to?(other_address) + # city == other_address.city + # end + # + # def ==(other_address) + # city == other_address.city && street == other_address.street + # end + # end + # + # Now it's possible to access attributes from the database through the value objects instead. If + # you choose to name the composition the same as the attribute's name, it will be the only way to + # access that attribute. That's the case with our +balance+ attribute. You interact with the value + # objects just like you would with any other attribute: + # + # customer.balance = Money.new(20) # sets the Money value object and the attribute + # customer.balance # => Money value object + # customer.balance.exchange_to("DKK") # => Money.new(120, "DKK") + # customer.balance > Money.new(10) # => true + # customer.balance == Money.new(20) # => true + # customer.balance < Money.new(5) # => false + # + # Value objects can also be composed of multiple attributes, such as the case of Address. The order + # of the mappings will determine the order of the parameters. + # + # customer.address_street = "Hyancintvej" + # customer.address_city = "Copenhagen" + # customer.address # => Address.new("Hyancintvej", "Copenhagen") + # + # customer.address = Address.new("May Street", "Chicago") + # customer.address_street # => "May Street" + # customer.address_city # => "Chicago" + # + # == Writing value objects + # + # Value objects are immutable and interchangeable objects that represent a given value, such as + # a Money object representing $5. Two Money objects both representing $5 should be equal (through + # methods such as <tt>==</tt> and <tt><=></tt> from Comparable if ranking makes sense). This is + # unlike entity objects where equality is determined by identity. An entity class such as Customer can + # easily have two different objects that both have an address on Hyancintvej. Entity identity is + # determined by object or relational unique identifiers (such as primary keys). Normal + # ActiveRecord::Base classes are entity objects. + # + # It's also important to treat the value objects as immutable. Don't allow the Money object to have + # its amount changed after creation. Create a new Money object with the new value instead. The + # <tt>Money#exchange_to</tt> method is an example of this. It returns a new value object instead of changing + # its own values. Active Record won't persist value objects that have been changed through means + # other than the writer method. + # + # The immutable requirement is enforced by Active Record by freezing any object assigned as a value + # object. Attempting to change it afterwards will result in a +RuntimeError+. + # + # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not + # keeping value objects immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable + # + # == Custom constructors and converters + # + # By default value objects are initialized by calling the <tt>new</tt> constructor of the value + # class passing each of the mapped attributes, in the order specified by the <tt>:mapping</tt> + # option, as arguments. If the value class doesn't support this convention then #composed_of allows + # a custom constructor to be specified. + # + # When a new value is assigned to the value object, the default assumption is that the new value + # is an instance of the value class. Specifying a custom converter allows the new value to be automatically + # converted to an instance of value class if necessary. + # + # For example, the +NetworkResource+ model has +network_address+ and +cidr_range+ attributes that should be + # aggregated using the +NetAddr::CIDR+ value class (http://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR). + # The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter. + # New values can be assigned to the value object using either another +NetAddr::CIDR+ object, a string + # or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet + # these requirements: + # + # class NetworkResource < ActiveRecord::Base + # composed_of :cidr, + # class_name: 'NetAddr::CIDR', + # mapping: [ %w(network_address network), %w(cidr_range bits) ], + # allow_nil: true, + # constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") }, + # converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) } + # end + # + # # This calls the :constructor + # network_resource = NetworkResource.new(network_address: '192.168.0.1', cidr_range: 24) + # + # # These assignments will both use the :converter + # network_resource.cidr = [ '192.168.2.1', 8 ] + # network_resource.cidr = '192.168.0.1/24' + # + # # This assignment won't use the :converter as the value is already an instance of the value class + # network_resource.cidr = NetAddr::CIDR.create('192.168.2.1/8') + # + # # Saving and then reloading will use the :constructor on reload + # network_resource.save + # network_resource.reload + # + # == Finding records by a value object + # + # Once a #composed_of relationship is specified for a model, records can be loaded from the database + # by specifying an instance of the value object in the conditions hash. The following example + # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD": + # + # Customer.where(balance: Money.new(20, "USD")) + # + module ClassMethods + # Adds reader and writer methods for manipulating a value object: + # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods. + # + # Options are: + # * <tt>:class_name</tt> - Specifies the class name of the association. Use it only if that name + # can't be inferred from the part id. So <tt>composed_of :address</tt> will by default be linked + # to the Address class, but if the real class name is +CompanyAddress+, you'll have to specify it + # with this option. + # * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value + # object. Each mapping is represented as an array where the first item is the name of the + # entity attribute and the second item is the name of the attribute in the value object. The + # order in which mappings are defined determines the order in which attributes are sent to the + # value class constructor. + # * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped + # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all + # mapped attributes. + # This defaults to +false+. + # * <tt>:constructor</tt> - A symbol specifying the name of the constructor method or a Proc that + # is called to initialize the value object. The constructor is passed all of the mapped attributes, + # in the order that they are defined in the <tt>:mapping option</tt>, as arguments and uses them + # to instantiate a <tt>:class_name</tt> object. + # The default is <tt>:new</tt>. + # * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt> + # or a Proc that is called when a new value is assigned to the value object. The converter is + # passed the single value that is used in the assignment and is only called if the new value is + # not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter + # can return nil to skip the assignment. + # + # Option examples: + # composed_of :temperature, mapping: %w(reading celsius) + # composed_of :balance, class_name: "Money", mapping: %w(balance amount), + # converter: Proc.new { |balance| balance.to_money } + # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ] + # composed_of :gps_location + # composed_of :gps_location, allow_nil: true + # composed_of :ip_address, + # class_name: 'IPAddr', + # mapping: %w(ip to_i), + # constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) }, + # converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) } + # + def composed_of(part_id, options = {}) + options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter) - name = part_id.id2name - class_name = options[:class_name] || name.camelize - mapping = options[:mapping] || [ name, name ] - mapping = [ mapping ] unless mapping.first.is_a?(Array) - allow_nil = options[:allow_nil] || false - constructor = options[:constructor] || :new - converter = options[:converter] + name = part_id.id2name + class_name = options[:class_name] || name.camelize + mapping = options[:mapping] || [ name, name ] + mapping = [ mapping ] unless mapping.first.is_a?(Array) + allow_nil = options[:allow_nil] || false + constructor = options[:constructor] || :new + converter = options[:converter] - reader_method(name, class_name, mapping, allow_nil, constructor) - writer_method(name, class_name, mapping, allow_nil, converter) + reader_method(name, class_name, mapping, allow_nil, constructor) + writer_method(name, class_name, mapping, allow_nil, converter) - reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self) - Reflection.add_aggregate_reflection self, part_id, reflection - end + reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self) + Reflection.add_aggregate_reflection self, part_id, reflection + end - private - def reader_method(name, class_name, mapping, allow_nil, constructor) - define_method(name) do - if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !_read_attribute(key).nil? }) - attrs = mapping.collect {|key, _| _read_attribute(key)} - object = constructor.respond_to?(:call) ? - constructor.call(*attrs) : - class_name.constantize.send(constructor, *attrs) - @aggregation_cache[name] = object + private + def reader_method(name, class_name, mapping, allow_nil, constructor) + define_method(name) do + if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? { |key, _| !_read_attribute(key).nil? }) + attrs = mapping.collect { |key, _| _read_attribute(key) } + object = constructor.respond_to?(:call) ? + constructor.call(*attrs) : + class_name.constantize.send(constructor, *attrs) + @aggregation_cache[name] = object + end + @aggregation_cache[name] end - @aggregation_cache[name] end - end - def writer_method(name, class_name, mapping, allow_nil, converter) - define_method("#{name}=") do |part| - klass = class_name.constantize + def writer_method(name, class_name, mapping, allow_nil, converter) + define_method("#{name}=") do |part| + klass = class_name.constantize - unless part.is_a?(klass) || converter.nil? || part.nil? - part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part) - end + unless part.is_a?(klass) || converter.nil? || part.nil? + part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part) + end - if part.is_a?(Hash) - raise ArgumentError unless part.size == part.keys.max - part = klass.new(*part.sort.map(&:last)) - end + hash_from_multiparameter_assignment = part.is_a?(Hash) && + part.each_key.all? { |k| k.is_a?(Integer) } + if hash_from_multiparameter_assignment + raise ArgumentError unless part.size == part.each_key.max + part = klass.new(*part.sort.map(&:last)) + end - if part.nil? && allow_nil - mapping.each { |key, _| self[key] = nil } - @aggregation_cache[name] = nil - else - mapping.each { |key, value| self[key] = part.send(value) } - @aggregation_cache[name] = part.freeze + if part.nil? && allow_nil + mapping.each { |key, _| self[key] = nil } + @aggregation_cache[name] = nil + else + mapping.each { |key, value| self[key] = part.send(value) } + @aggregation_cache[name] = part.freeze + end end end - end - end + end end end diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb index c18e88e4cf..de2d03cd0b 100644 --- a/activerecord/lib/active_record/association_relation.rb +++ b/activerecord/lib/active_record/association_relation.rb @@ -28,8 +28,11 @@ module ActiveRecord private - def exec_queries - super.each { |r| @association.set_inverse_instance r } - end + def exec_queries + super do |r| + @association.set_inverse_instance r + yield r if block_given? + end + end end end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 3729e22e64..b5f1f1980a 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/enumerable' -require 'active_support/core_ext/string/conversions' -require 'active_support/core_ext/module/remove_method' -require 'active_record/errors' +require "active_support/core_ext/enumerable" +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/module/remove_method" +require "active_record/errors" module ActiveRecord class AssociationNotFoundError < ConfigurationError #:nodoc: @@ -90,7 +90,7 @@ module ActiveRecord through_reflection = reflection.through_reflection source_reflection_names = reflection.source_reflection_names source_associations = reflection.through_reflection.klass._reflections.keys - super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)}?") + super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ', locale: :en)} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ', locale: :en)}?") else super("Could not find the source association(s).") end @@ -207,14 +207,14 @@ module ActiveRecord autoload :ThroughAssociation module Builder #:nodoc: - autoload :Association, 'active_record/associations/builder/association' - autoload :SingularAssociation, 'active_record/associations/builder/singular_association' - autoload :CollectionAssociation, 'active_record/associations/builder/collection_association' + autoload :Association, "active_record/associations/builder/association" + autoload :SingularAssociation, "active_record/associations/builder/singular_association" + autoload :CollectionAssociation, "active_record/associations/builder/collection_association" - autoload :BelongsTo, 'active_record/associations/builder/belongs_to' - autoload :HasOne, 'active_record/associations/builder/has_one' - autoload :HasMany, 'active_record/associations/builder/has_many' - autoload :HasAndBelongsToMany, 'active_record/associations/builder/has_and_belongs_to_many' + autoload :BelongsTo, "active_record/associations/builder/belongs_to" + autoload :HasOne, "active_record/associations/builder/has_one" + autoload :HasMany, "active_record/associations/builder/has_many" + autoload :HasAndBelongsToMany, "active_record/associations/builder/has_and_belongs_to_many" end eager_autoload do @@ -274,1560 +274,1561 @@ module ActiveRecord @association_cache[name] = association end - # \Associations are a set of macro-like class methods for tying objects together through - # foreign keys. They express relationships like "Project has one Project Manager" - # or "Project belongs to a Portfolio". Each macro adds a number of methods to the - # class which are specialized according to the collection or association symbol and the - # options hash. It works much the same way as Ruby's own <tt>attr*</tt> - # methods. - # - # class Project < ActiveRecord::Base - # belongs_to :portfolio - # has_one :project_manager - # has_many :milestones - # has_and_belongs_to_many :categories - # end - # - # The project class now has the following methods (and more) to ease the traversal and - # manipulation of its relationships: - # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt> - # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt> - # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt> - # <tt>Project#milestones.delete(milestone), Project#milestones.destroy(milestone), Project#milestones.find(milestone_id),</tt> - # <tt>Project#milestones.build, Project#milestones.create</tt> - # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt> - # <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt> - # - # === A word of warning - # - # Don't create associations that have the same name as {instance methods}[rdoc-ref:ActiveRecord::Core] of - # <tt>ActiveRecord::Base</tt>. Since the association adds a method with that name to - # its model, using an association with the same name as one provided by <tt>ActiveRecord::Base</tt> will override the method inherited through <tt>ActiveRecord::Base</tt> and will break things. - # For instance, +attributes+ and +connection+ would be bad choices for association names, because those names already exist in the list of <tt>ActiveRecord::Base</tt> instance methods. - # - # == Auto-generated methods - # See also Instance Public methods below for more details. - # - # === Singular associations (one-to-one) - # | | belongs_to | - # generated methods | belongs_to | :polymorphic | has_one - # ----------------------------------+------------+--------------+--------- - # other(force_reload=false) | X | X | X - # other=(other) | X | X | X - # build_other(attributes={}) | X | | X - # create_other(attributes={}) | X | | X - # create_other!(attributes={}) | X | | X - # - # === Collection associations (one-to-many / many-to-many) - # | | | has_many - # generated methods | habtm | has_many | :through - # ----------------------------------+-------+----------+---------- - # others(force_reload=false) | X | X | X - # others=(other,other,...) | X | X | X - # other_ids | X | X | X - # other_ids=(id,id,...) | X | X | X - # others<< | X | X | X - # others.push | X | X | X - # others.concat | X | X | X - # others.build(attributes={}) | X | X | X - # others.create(attributes={}) | X | X | X - # others.create!(attributes={}) | X | X | X - # others.size | X | X | X - # others.length | X | X | X - # others.count | X | X | X - # others.sum(*args) | X | X | X - # others.empty? | X | X | X - # others.clear | X | X | X - # others.delete(other,other,...) | X | X | X - # others.delete_all | X | X | X - # others.destroy(other,other,...) | X | X | X - # others.destroy_all | X | X | X - # others.find(*args) | X | X | X - # others.exists? | X | X | X - # others.distinct | X | X | X - # others.reset | X | X | X - # - # === Overriding generated methods - # - # Association methods are generated in a module that is included into the model class, - # which allows you to easily override with your own methods and call the original - # generated method with +super+. For example: - # - # class Car < ActiveRecord::Base - # belongs_to :owner - # belongs_to :old_owner - # def owner=(new_owner) - # self.old_owner = self.owner - # super - # end - # end - # - # If your model class is <tt>Project</tt>, the module is - # named <tt>Project::GeneratedAssociationMethods</tt>. The +GeneratedAssociationMethods+ module is - # included in the model class immediately after the (anonymous) generated attributes methods - # module, meaning an association will override the methods for an attribute with the same name. - # - # == Cardinality and associations - # - # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many - # relationships between models. Each model uses an association to describe its role in - # the relation. The #belongs_to association is always used in the model that has - # the foreign key. - # - # === One-to-one - # - # Use #has_one in the base, and #belongs_to in the associated model. - # - # class Employee < ActiveRecord::Base - # has_one :office - # end - # class Office < ActiveRecord::Base - # belongs_to :employee # foreign key - employee_id - # end - # - # === One-to-many - # - # Use #has_many in the base, and #belongs_to in the associated model. - # - # class Manager < ActiveRecord::Base - # has_many :employees - # end - # class Employee < ActiveRecord::Base - # belongs_to :manager # foreign key - manager_id - # end - # - # === Many-to-many - # - # There are two ways to build a many-to-many relationship. - # - # The first way uses a #has_many association with the <tt>:through</tt> option and a join model, so - # there are two stages of associations. - # - # class Assignment < ActiveRecord::Base - # belongs_to :programmer # foreign key - programmer_id - # belongs_to :project # foreign key - project_id - # end - # class Programmer < ActiveRecord::Base - # has_many :assignments - # has_many :projects, through: :assignments - # end - # class Project < ActiveRecord::Base - # has_many :assignments - # has_many :programmers, through: :assignments - # end - # - # For the second way, use #has_and_belongs_to_many in both models. This requires a join table - # that has no corresponding model or primary key. - # - # class Programmer < ActiveRecord::Base - # has_and_belongs_to_many :projects # foreign keys in the join table - # end - # class Project < ActiveRecord::Base - # has_and_belongs_to_many :programmers # foreign keys in the join table - # end - # - # Choosing which way to build a many-to-many relationship is not always simple. - # If you need to work with the relationship model as its own entity, - # use #has_many <tt>:through</tt>. Use #has_and_belongs_to_many when working with legacy schemas or when - # you never work directly with the relationship itself. - # - # == Is it a #belongs_to or #has_one association? - # - # Both express a 1-1 relationship. The difference is mostly where to place the foreign - # key, which goes on the table for the class declaring the #belongs_to relationship. - # - # class User < ActiveRecord::Base - # # I reference an account. - # belongs_to :account - # end - # - # class Account < ActiveRecord::Base - # # One user references me. - # has_one :user - # end - # - # The tables for these classes could look something like: - # - # CREATE TABLE users ( - # id int NOT NULL auto_increment, - # account_id int default NULL, - # name varchar default NULL, - # PRIMARY KEY (id) - # ) - # - # CREATE TABLE accounts ( - # id int NOT NULL auto_increment, - # name varchar default NULL, - # PRIMARY KEY (id) - # ) - # - # == Unsaved objects and associations - # - # You can manipulate objects and associations before they are saved to the database, but - # there is some special behavior you should be aware of, mostly involving the saving of - # associated objects. - # - # You can set the <tt>:autosave</tt> option on a #has_one, #belongs_to, - # #has_many, or #has_and_belongs_to_many association. Setting it - # to +true+ will _always_ save the members, whereas setting it to +false+ will - # _never_ save the members. More details about <tt>:autosave</tt> option is available at - # AutosaveAssociation. - # - # === One-to-one associations - # - # * Assigning an object to a #has_one association automatically saves that object and - # the object being replaced (if there is one), in order to update their foreign - # keys - except if the parent object is unsaved (<tt>new_record? == true</tt>). - # * If either of these saves fail (due to one of the objects being invalid), an - # ActiveRecord::RecordNotSaved exception is raised and the assignment is - # cancelled. - # * If you wish to assign an object to a #has_one association without saving it, - # use the <tt>#build_association</tt> method (documented below). The object being - # replaced will still be saved to update its foreign key. - # * Assigning an object to a #belongs_to association does not save the object, since - # the foreign key field belongs on the parent. It does not save the parent either. - # - # === Collections - # - # * Adding an object to a collection (#has_many or #has_and_belongs_to_many) automatically - # saves that object, except if the parent object (the owner of the collection) is not yet - # stored in the database. - # * If saving any of the objects being added to a collection (via <tt>push</tt> or similar) - # fails, then <tt>push</tt> returns +false+. - # * If saving fails while replacing the collection (via <tt>association=</tt>), an - # ActiveRecord::RecordNotSaved exception is raised and the assignment is - # cancelled. - # * You can add an object to a collection without automatically saving it by using the - # <tt>collection.build</tt> method (documented below). - # * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically - # saved when the parent is saved. - # - # == Customizing the query - # - # \Associations are built from <tt>Relation</tt> objects, and you can use the Relation syntax - # to customize them. For example, to add a condition: - # - # class Blog < ActiveRecord::Base - # has_many :published_posts, -> { where(published: true) }, class_name: 'Post' - # end - # - # Inside the <tt>-> { ... }</tt> block you can use all of the usual Relation methods. - # - # === Accessing the owner object - # - # Sometimes it is useful to have access to the owner object when building the query. The owner - # is passed as a parameter to the block. For example, the following association would find all - # events that occur on the user's birthday: - # - # class User < ActiveRecord::Base - # has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event' - # end - # - # Note: Joining, eager loading and preloading of these associations is not fully possible. - # These operations happen before instance creation and the scope will be called with a +nil+ argument. - # This can lead to unexpected behavior and is deprecated. - # - # == Association callbacks - # - # Similar to the normal callbacks that hook into the life cycle of an Active Record object, - # you can also define callbacks that get triggered when you add an object to or remove an - # object from an association collection. - # - # class Project - # has_and_belongs_to_many :developers, after_add: :evaluate_velocity - # - # def evaluate_velocity(developer) - # ... - # end - # end - # - # It's possible to stack callbacks by passing them as an array. Example: - # - # class Project - # has_and_belongs_to_many :developers, - # after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}] - # end - # - # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+. - # - # If any of the +before_add+ callbacks throw an exception, the object will not be - # added to the collection. - # - # Similarly, if any of the +before_remove+ callbacks throw an exception, the object - # will not be removed from the collection. - # - # == Association extensions - # - # The proxy objects that control the access to associations can be extended through anonymous - # modules. This is especially beneficial for adding new finders, creators, and other - # factory-type methods that are only used as part of this association. - # - # class Account < ActiveRecord::Base - # has_many :people do - # def find_or_create_by_name(name) - # first_name, last_name = name.split(" ", 2) - # find_or_create_by(first_name: first_name, last_name: last_name) - # end - # end - # end - # - # person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson") - # person.first_name # => "David" - # person.last_name # => "Heinemeier Hansson" - # - # If you need to share the same extensions between many associations, you can use a named - # extension module. - # - # module FindOrCreateByNameExtension - # def find_or_create_by_name(name) - # first_name, last_name = name.split(" ", 2) - # find_or_create_by(first_name: first_name, last_name: last_name) - # end - # end - # - # class Account < ActiveRecord::Base - # has_many :people, -> { extending FindOrCreateByNameExtension } - # end - # - # class Company < ActiveRecord::Base - # has_many :people, -> { extending FindOrCreateByNameExtension } - # end - # - # Some extensions can only be made to work with knowledge of the association's internals. - # Extensions can access relevant state using the following methods (where +items+ is the - # name of the association): - # - # * <tt>record.association(:items).owner</tt> - Returns the object the association is part of. - # * <tt>record.association(:items).reflection</tt> - Returns the reflection object that describes the association. - # * <tt>record.association(:items).target</tt> - Returns the associated object for #belongs_to and #has_one, or - # the collection of associated objects for #has_many and #has_and_belongs_to_many. - # - # However, inside the actual extension code, you will not have access to the <tt>record</tt> as - # above. In this case, you can access <tt>proxy_association</tt>. For example, - # <tt>record.association(:items)</tt> and <tt>record.items.proxy_association</tt> will return - # the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside - # association extensions. - # - # == Association Join Models - # - # Has Many associations can be configured with the <tt>:through</tt> option to use an - # explicit join model to retrieve the data. This operates similarly to a - # #has_and_belongs_to_many association. The advantage is that you're able to add validations, - # callbacks, and extra attributes on the join model. Consider the following schema: - # - # class Author < ActiveRecord::Base - # has_many :authorships - # has_many :books, through: :authorships - # end - # - # class Authorship < ActiveRecord::Base - # belongs_to :author - # belongs_to :book - # end - # - # @author = Author.first - # @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to - # @author.books # selects all books by using the Authorship join model - # - # You can also go through a #has_many association on the join model: - # - # class Firm < ActiveRecord::Base - # has_many :clients - # has_many :invoices, through: :clients - # end - # - # class Client < ActiveRecord::Base - # belongs_to :firm - # has_many :invoices - # end - # - # class Invoice < ActiveRecord::Base - # belongs_to :client - # end - # - # @firm = Firm.first - # @firm.clients.flat_map { |c| c.invoices } # select all invoices for all clients of the firm - # @firm.invoices # selects all invoices by going through the Client join model - # - # Similarly you can go through a #has_one association on the join model: - # - # class Group < ActiveRecord::Base - # has_many :users - # has_many :avatars, through: :users - # end - # - # class User < ActiveRecord::Base - # belongs_to :group - # has_one :avatar - # end - # - # class Avatar < ActiveRecord::Base - # belongs_to :user - # end - # - # @group = Group.first - # @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group - # @group.avatars # selects all avatars by going through the User join model. - # - # An important caveat with going through #has_one or #has_many associations on the - # join model is that these associations are *read-only*. For example, the following - # would not work following the previous example: - # - # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around - # @group.avatars.delete(@group.avatars.last) # so would this - # - # == Setting Inverses - # - # If you are using a #belongs_to on the join model, it is a good idea to set the - # <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example - # works correctly (where <tt>tags</tt> is a #has_many <tt>:through</tt> association): - # - # @post = Post.first - # @tag = @post.tags.build name: "ruby" - # @tag.save - # - # The last line ought to save the through record (a <tt>Tagging</tt>). This will only work if the - # <tt>:inverse_of</tt> is set: - # - # class Tagging < ActiveRecord::Base - # belongs_to :post - # belongs_to :tag, inverse_of: :taggings - # end - # - # If you do not set the <tt>:inverse_of</tt> record, the association will - # do its best to match itself up with the correct inverse. Automatic - # inverse detection only works on #has_many, #has_one, and - # #belongs_to associations. - # - # Extra options on the associations, as defined in the - # <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will - # also prevent the association's inverse from being found automatically. - # - # The automatic guessing of the inverse association uses a heuristic based - # on the name of the class, so it may not work for all associations, - # especially the ones with non-standard names. - # - # You can turn off the automatic detection of inverse associations by setting - # the <tt>:inverse_of</tt> option to <tt>false</tt> like so: - # - # class Tagging < ActiveRecord::Base - # belongs_to :tag, inverse_of: false - # end - # - # == Nested \Associations - # - # You can actually specify *any* association with the <tt>:through</tt> option, including an - # association which has a <tt>:through</tt> option itself. For example: - # - # class Author < ActiveRecord::Base - # has_many :posts - # has_many :comments, through: :posts - # has_many :commenters, through: :comments - # end - # - # class Post < ActiveRecord::Base - # has_many :comments - # end - # - # class Comment < ActiveRecord::Base - # belongs_to :commenter - # end - # - # @author = Author.first - # @author.commenters # => People who commented on posts written by the author - # - # An equivalent way of setting up this association this would be: - # - # class Author < ActiveRecord::Base - # has_many :posts - # has_many :commenters, through: :posts - # end - # - # class Post < ActiveRecord::Base - # has_many :comments - # has_many :commenters, through: :comments - # end - # - # class Comment < ActiveRecord::Base - # belongs_to :commenter - # end - # - # When using a nested association, you will not be able to modify the association because there - # is not enough information to know what modification to make. For example, if you tried to - # add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the - # intermediate <tt>Post</tt> and <tt>Comment</tt> objects. - # - # == Polymorphic \Associations - # - # Polymorphic associations on models are not restricted on what types of models they - # can be associated with. Rather, they specify an interface that a #has_many association - # must adhere to. - # - # class Asset < ActiveRecord::Base - # belongs_to :attachable, polymorphic: true - # end - # - # class Post < ActiveRecord::Base - # has_many :assets, as: :attachable # The :as option specifies the polymorphic interface to use. - # end - # - # @asset.attachable = @post - # - # This works by using a type column in addition to a foreign key to specify the associated - # record. In the Asset example, you'd need an +attachable_id+ integer column and an - # +attachable_type+ string column. - # - # Using polymorphic associations in combination with single table inheritance (STI) is - # a little tricky. In order for the associations to work as expected, ensure that you - # store the base model for the STI models in the type column of the polymorphic - # association. To continue with the asset example above, suppose there are guest posts - # and member posts that use the posts table for STI. In this case, there must be a +type+ - # column in the posts table. - # - # Note: The <tt>attachable_type=</tt> method is being called when assigning an +attachable+. - # The +class_name+ of the +attachable+ is passed as a String. - # - # class Asset < ActiveRecord::Base - # belongs_to :attachable, polymorphic: true - # - # def attachable_type=(class_name) - # super(class_name.constantize.base_class.to_s) - # end - # end - # - # class Post < ActiveRecord::Base - # # because we store "Post" in attachable_type now dependent: :destroy will work - # has_many :assets, as: :attachable, dependent: :destroy - # end - # - # class GuestPost < Post - # end - # - # class MemberPost < Post - # end - # - # == Caching - # - # All of the methods are built on a simple caching principle that will keep the result - # of the last query around unless specifically instructed not to. The cache is even - # shared across methods to make it even cheaper to use the macro-added methods without - # worrying too much about performance at the first go. - # - # project.milestones # fetches milestones from the database - # project.milestones.size # uses the milestone cache - # project.milestones.empty? # uses the milestone cache - # project.milestones(true).size # fetches milestones from the database - # project.milestones # uses the milestone cache - # - # == Eager loading of associations - # - # Eager loading is a way to find objects of a certain class and a number of named associations. - # It is one of the easiest ways to prevent the dreaded N+1 problem in which fetching 100 - # posts that each need to display their author triggers 101 database queries. Through the - # use of eager loading, the number of queries will be reduced from 101 to 2. - # - # class Post < ActiveRecord::Base - # belongs_to :author - # has_many :comments - # end - # - # Consider the following loop using the class above: - # - # Post.all.each do |post| - # puts "Post: " + post.title - # puts "Written by: " + post.author.name - # puts "Last comment on: " + post.comments.first.created_on - # end - # - # To iterate over these one hundred posts, we'll generate 201 database queries. Let's - # first just optimize it for retrieving the author: - # - # Post.includes(:author).each do |post| - # - # This references the name of the #belongs_to association that also used the <tt>:author</tt> - # symbol. After loading the posts, find will collect the +author_id+ from each one and load - # all the referenced authors with one query. Doing so will cut down the number of queries - # from 201 to 102. - # - # We can improve upon the situation further by referencing both associations in the finder with: - # - # Post.includes(:author, :comments).each do |post| - # - # This will load all comments with a single query. This reduces the total number of queries - # to 3. In general, the number of queries will be 1 plus the number of associations - # named (except if some of the associations are polymorphic #belongs_to - see below). - # - # To include a deep hierarchy of associations, use a hash: - # - # Post.includes(:author, { comments: { author: :gravatar } }).each do |post| - # - # The above code will load all the comments and all of their associated - # authors and gravatars. You can mix and match any combination of symbols, - # arrays, and hashes to retrieve the associations you want to load. - # - # All of this power shouldn't fool you into thinking that you can pull out huge amounts - # of data with no performance penalty just because you've reduced the number of queries. - # The database still needs to send all the data to Active Record and it still needs to - # be processed. So it's no catch-all for performance problems, but it's a great way to - # cut down on the number of queries in a situation as the one described above. - # - # Since only one table is loaded at a time, conditions or orders cannot reference tables - # other than the main one. If this is the case, Active Record falls back to the previously - # used LEFT OUTER JOIN based strategy. For example: - # - # Post.includes([:author, :comments]).where(['comments.approved = ?', true]) - # - # This will result in a single SQL query with joins along the lines of: - # <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and - # <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions - # like this can have unintended consequences. - # In the above example posts with no approved comments are not returned at all, because - # the conditions apply to the SQL statement as a whole and not just to the association. - # - # You must disambiguate column references for this fallback to happen, for example - # <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not. - # - # If you want to load all posts (including posts with no approved comments) then write - # your own LEFT OUTER JOIN query using ON - # - # Post.joins("LEFT OUTER JOIN comments ON comments.post_id = posts.id AND comments.approved = '1'") - # - # In this case it is usually more natural to include an association which has conditions defined on it: - # - # class Post < ActiveRecord::Base - # has_many :approved_comments, -> { where(approved: true) }, class_name: 'Comment' - # end - # - # Post.includes(:approved_comments) - # - # This will load posts and eager load the +approved_comments+ association, which contains - # only those comments that have been approved. - # - # If you eager load an association with a specified <tt>:limit</tt> option, it will be ignored, - # returning all the associated objects: - # - # class Picture < ActiveRecord::Base - # has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment' - # end - # - # Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments. - # - # Eager loading is supported with polymorphic associations. - # - # class Address < ActiveRecord::Base - # belongs_to :addressable, polymorphic: true - # end - # - # A call that tries to eager load the addressable model - # - # Address.includes(:addressable) - # - # This will execute one query to load the addresses and load the addressables with one - # query per addressable type. - # For example if all the addressables are either of class Person or Company then a total - # of 3 queries will be executed. The list of addressable types to load is determined on - # the back of the addresses loaded. This is not supported if Active Record has to fallback - # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. - # The reason is that the parent model's type is a column value so its corresponding table - # name cannot be put in the +FROM+/+JOIN+ clauses of that query. - # - # == Table Aliasing - # - # Active Record uses table aliasing in the case that a table is referenced multiple times - # in a join. If a table is referenced only once, the standard table name is used. The - # second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>. - # Indexes are appended for any more successive uses of the table name. - # - # Post.joins(:comments) - # # => SELECT ... FROM posts INNER JOIN comments ON ... - # Post.joins(:special_comments) # STI - # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment' - # Post.joins(:comments, :special_comments) # special_comments is the reflection name, posts is the parent table name - # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts - # - # Acts as tree example: - # - # TreeMixin.joins(:children) - # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... - # TreeMixin.joins(children: :parent) - # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... - # INNER JOIN parents_mixins ... - # TreeMixin.joins(children: {parent: :children}) - # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... - # INNER JOIN parents_mixins ... - # INNER JOIN mixins childrens_mixins_2 - # - # Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix: - # - # Post.joins(:categories) - # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... - # Post.joins(categories: :posts) - # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... - # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories - # Post.joins(categories: {posts: :categories}) - # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... - # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories - # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2 - # - # If you wish to specify your own custom joins using ActiveRecord::QueryMethods#joins method, those table - # names will take precedence over the eager associations: - # - # Post.joins(:comments).joins("inner join comments ...") - # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ... - # Post.joins(:comments, :special_comments).joins("inner join comments ...") - # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ... - # INNER JOIN comments special_comments_posts ... - # INNER JOIN comments ... - # - # Table aliases are automatically truncated according to the maximum length of table identifiers - # according to the specific database. - # - # == Modules - # - # By default, associations will look for objects within the current module scope. Consider: - # - # module MyApplication - # module Business - # class Firm < ActiveRecord::Base - # has_many :clients - # end - # - # class Client < ActiveRecord::Base; end - # end - # end - # - # When <tt>Firm#clients</tt> is called, it will in turn call - # <tt>MyApplication::Business::Client.find_all_by_firm_id(firm.id)</tt>. - # If you want to associate with a class in another module scope, this can be done by - # specifying the complete class name. - # - # module MyApplication - # module Business - # class Firm < ActiveRecord::Base; end - # end - # - # module Billing - # class Account < ActiveRecord::Base - # belongs_to :firm, class_name: "MyApplication::Business::Firm" - # end - # end - # end - # - # == Bi-directional associations - # - # When you specify an association there is usually an association on the associated model - # that specifies the same relationship in reverse. For example, with the following models: - # - # class Dungeon < ActiveRecord::Base - # has_many :traps - # has_one :evil_wizard - # end - # - # class Trap < ActiveRecord::Base - # belongs_to :dungeon - # end - # - # class EvilWizard < ActiveRecord::Base - # belongs_to :dungeon - # end - # - # The +traps+ association on +Dungeon+ and the +dungeon+ association on +Trap+ are - # the inverse of each other and the inverse of the +dungeon+ association on +EvilWizard+ - # is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default, - # Active Record can guess the inverse of the association based on the name - # of the class. The result is the following: - # - # d = Dungeon.first - # t = d.traps.first - # d.object_id == t.dungeon.object_id # => true - # - # The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to - # the same in-memory instance since the association matches the name of the class. - # The result would be the same if we added +:inverse_of+ to our model definitions: - # - # class Dungeon < ActiveRecord::Base - # has_many :traps, inverse_of: :dungeon - # has_one :evil_wizard, inverse_of: :dungeon - # end - # - # class Trap < ActiveRecord::Base - # belongs_to :dungeon, inverse_of: :traps - # end - # - # class EvilWizard < ActiveRecord::Base - # belongs_to :dungeon, inverse_of: :evil_wizard - # end - # - # There are limitations to <tt>:inverse_of</tt> support: - # - # * does not work with <tt>:through</tt> associations. - # * does not work with <tt>:polymorphic</tt> associations. - # * for #belongs_to associations #has_many inverse associations are ignored. - # - # For more information, see the documentation for the +:inverse_of+ option. - # - # == Deleting from associations - # - # === Dependent associations - # - # #has_many, #has_one and #belongs_to associations support the <tt>:dependent</tt> option. - # This allows you to specify that associated records should be deleted when the owner is - # deleted. - # - # For example: - # - # class Author - # has_many :posts, dependent: :destroy - # end - # Author.find(1).destroy # => Will destroy all of the author's posts, too - # - # The <tt>:dependent</tt> option can have different values which specify how the deletion - # is done. For more information, see the documentation for this option on the different - # specific association types. When no option is given, the behavior is to do nothing - # with the associated records when destroying a record. - # - # Note that <tt>:dependent</tt> is implemented using Rails' callback - # system, which works by processing callbacks in order. Therefore, other - # callbacks declared either before or after the <tt>:dependent</tt> option - # can affect what it does. - # - # Note that <tt>:dependent</tt> option is ignored for #has_one <tt>:through</tt> associations. - # - # === Delete or destroy? - # - # #has_many and #has_and_belongs_to_many associations have the methods <tt>destroy</tt>, - # <tt>delete</tt>, <tt>destroy_all</tt> and <tt>delete_all</tt>. - # - # For #has_and_belongs_to_many, <tt>delete</tt> and <tt>destroy</tt> are the same: they - # cause the records in the join table to be removed. - # - # For #has_many, <tt>destroy</tt> and <tt>destroy_all</tt> will always call the <tt>destroy</tt> method of the - # record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either - # do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or - # if no <tt>:dependent</tt> option is given, then it will follow the default strategy. - # The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for - # #has_many <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete - # the join records, without running their callbacks). - # - # There is also a <tt>clear</tt> method which is the same as <tt>delete_all</tt>, except that - # it returns the association rather than the records which have been deleted. - # - # === What gets deleted? - # - # There is a potential pitfall here: #has_and_belongs_to_many and #has_many <tt>:through</tt> - # associations have records in join tables, as well as the associated records. So when we - # call one of these deletion methods, what exactly should be deleted? - # - # The answer is that it is assumed that deletion on an association is about removing the - # <i>link</i> between the owner and the associated object(s), rather than necessarily the - # associated objects themselves. So with #has_and_belongs_to_many and #has_many - # <tt>:through</tt>, the join records will be deleted, but the associated records won't. - # - # This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.find_by(name: 'food'))</tt> - # you would want the 'food' tag to be unlinked from the post, rather than for the tag itself - # to be removed from the database. - # - # However, there are examples where this strategy doesn't make sense. For example, suppose - # a person has many projects, and each project has many tasks. If we deleted one of a person's - # tasks, we would probably not want the project to be deleted. In this scenario, the delete method - # won't actually work: it can only be used if the association on the join model is a - # #belongs_to. In other situations you are expected to perform operations directly on - # either the associated records or the <tt>:through</tt> association. - # - # With a regular #has_many there is no distinction between the "associated records" - # and the "link", so there is only one choice for what gets deleted. - # - # With #has_and_belongs_to_many and #has_many <tt>:through</tt>, if you want to delete the - # associated records themselves, you can always do something along the lines of - # <tt>person.tasks.each(&:destroy)</tt>. - # - # == Type safety with ActiveRecord::AssociationTypeMismatch - # - # If you attempt to assign an object to an association that doesn't match the inferred - # or specified <tt>:class_name</tt>, you'll get an ActiveRecord::AssociationTypeMismatch. - # - # == Options - # - # All of the association macros can be specialized through options. This makes cases - # more complex than the simple and guessable ones possible. - module ClassMethods - # Specifies a one-to-many association. The following methods for retrieval and query of - # collections of associated objects will be added: - # - # +collection+ is a placeholder for the symbol passed as the +name+ argument, so - # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>. - # - # [collection(force_reload = false)] - # Returns an array of all the associated objects. - # An empty array is returned if none are found. - # [collection<<(object, ...)] - # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. - # Note that this operation instantly fires update SQL without waiting for the save or update call on the - # parent object, unless the parent object is a new record. - # This will also run validations and callbacks of associated object(s). - # [collection.delete(object, ...)] - # Removes one or more objects from the collection by setting their foreign keys to +NULL+. - # Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>, - # and deleted if they're associated with <tt>dependent: :delete_all</tt>. - # - # If the <tt>:through</tt> option is used, then the join records are deleted (rather than - # nullified) by default, but you can specify <tt>dependent: :destroy</tt> or - # <tt>dependent: :nullify</tt> to override this. - # [collection.destroy(object, ...)] - # Removes one or more objects from the collection by running <tt>destroy</tt> on - # each record, regardless of any dependent option, ensuring callbacks are run. - # - # If the <tt>:through</tt> option is used, then the join records are destroyed - # instead, not the objects themselves. - # [collection=objects] - # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt> - # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is - # direct by default. You can specify <tt>dependent: :destroy</tt> or - # <tt>dependent: :nullify</tt> to override this. - # [collection_singular_ids] - # Returns an array of the associated objects' ids - # [collection_singular_ids=ids] - # Replace the collection with the objects identified by the primary keys in +ids+. This - # method loads the models and calls <tt>collection=</tt>. See above. - # [collection.clear] - # Removes every object from the collection. This destroys the associated objects if they - # are associated with <tt>dependent: :destroy</tt>, deletes them directly from the - # database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+. - # If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models. - # Join models are directly deleted. - # [collection.empty?] - # Returns +true+ if there are no associated objects. - # [collection.size] - # Returns the number of associated objects. - # [collection.find(...)] - # Finds an associated object according to the same rules as ActiveRecord::FinderMethods#find. - # [collection.exists?(...)] - # Checks whether an associated object with the given conditions exists. - # Uses the same rules as ActiveRecord::FinderMethods#exists?. - # [collection.build(attributes = {}, ...)] - # Returns one or more new objects of the collection type that have been instantiated - # with +attributes+ and linked to this object through a foreign key, but have not yet - # been saved. - # [collection.create(attributes = {})] - # Returns a new object of the collection type that has been instantiated - # with +attributes+, linked to this object through a foreign key, and that has already - # been saved (if it passed the validation). *Note*: This only works if the base model - # already exists in the DB, not if it is a new (unsaved) record! - # [collection.create!(attributes = {})] - # Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid - # if the record is invalid. - # - # === Example - # - # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add: - # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>) - # * <tt>Firm#clients<<</tt> - # * <tt>Firm#clients.delete</tt> - # * <tt>Firm#clients.destroy</tt> - # * <tt>Firm#clients=</tt> - # * <tt>Firm#client_ids</tt> - # * <tt>Firm#client_ids=</tt> - # * <tt>Firm#clients.clear</tt> - # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>) - # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>) - # * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>) - # * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>) - # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>) - # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>) - # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>) - # The declaration can also include an +options+ hash to specialize the behavior of the association. - # - # === Scopes - # - # You can pass a second argument +scope+ as a callable (i.e. proc or - # lambda) to retrieve a specific set of records or customize the generated - # query when you access the associated collection. - # - # Scope examples: - # has_many :comments, -> { where(author_id: 1) } - # has_many :employees, -> { joins(:address) } - # has_many :posts, ->(post) { where("max_post_length > ?", post.length) } - # - # === Extensions - # - # The +extension+ argument allows you to pass a block into a has_many - # association. This is useful for adding new finders, creators and other - # factory-type methods to be used as part of the association. - # - # Extension examples: - # has_many :employees do - # def find_or_create_by_name(name) - # first_name, last_name = name.split(" ", 2) - # find_or_create_by(first_name: first_name, last_name: last_name) + # \Associations are a set of macro-like class methods for tying objects together through + # foreign keys. They express relationships like "Project has one Project Manager" + # or "Project belongs to a Portfolio". Each macro adds a number of methods to the + # class which are specialized according to the collection or association symbol and the + # options hash. It works much the same way as Ruby's own <tt>attr*</tt> + # methods. + # + # class Project < ActiveRecord::Base + # belongs_to :portfolio + # has_one :project_manager + # has_many :milestones + # has_and_belongs_to_many :categories + # end + # + # The project class now has the following methods (and more) to ease the traversal and + # manipulation of its relationships: + # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt> + # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt> + # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt> + # <tt>Project#milestones.delete(milestone), Project#milestones.destroy(milestone), Project#milestones.find(milestone_id),</tt> + # <tt>Project#milestones.build, Project#milestones.create</tt> + # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt> + # <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt> + # + # === A word of warning + # + # Don't create associations that have the same name as {instance methods}[rdoc-ref:ActiveRecord::Core] of + # <tt>ActiveRecord::Base</tt>. Since the association adds a method with that name to + # its model, using an association with the same name as one provided by <tt>ActiveRecord::Base</tt> will override the method inherited through <tt>ActiveRecord::Base</tt> and will break things. + # For instance, +attributes+ and +connection+ would be bad choices for association names, because those names already exist in the list of <tt>ActiveRecord::Base</tt> instance methods. + # + # == Auto-generated methods + # See also Instance Public methods below for more details. + # + # === Singular associations (one-to-one) + # | | belongs_to | + # generated methods | belongs_to | :polymorphic | has_one + # ----------------------------------+------------+--------------+--------- + # other(force_reload=false) | X | X | X + # other=(other) | X | X | X + # build_other(attributes={}) | X | | X + # create_other(attributes={}) | X | | X + # create_other!(attributes={}) | X | | X + # + # === Collection associations (one-to-many / many-to-many) + # | | | has_many + # generated methods | habtm | has_many | :through + # ----------------------------------+-------+----------+---------- + # others(force_reload=false) | X | X | X + # others=(other,other,...) | X | X | X + # other_ids | X | X | X + # other_ids=(id,id,...) | X | X | X + # others<< | X | X | X + # others.push | X | X | X + # others.concat | X | X | X + # others.build(attributes={}) | X | X | X + # others.create(attributes={}) | X | X | X + # others.create!(attributes={}) | X | X | X + # others.size | X | X | X + # others.length | X | X | X + # others.count | X | X | X + # others.sum(*args) | X | X | X + # others.empty? | X | X | X + # others.clear | X | X | X + # others.delete(other,other,...) | X | X | X + # others.delete_all | X | X | X + # others.destroy(other,other,...) | X | X | X + # others.destroy_all | X | X | X + # others.find(*args) | X | X | X + # others.exists? | X | X | X + # others.distinct | X | X | X + # others.reset | X | X | X + # + # === Overriding generated methods + # + # Association methods are generated in a module that is included into the model class, + # which allows you to easily override with your own methods and call the original + # generated method with +super+. For example: + # + # class Car < ActiveRecord::Base + # belongs_to :owner + # belongs_to :old_owner + # def owner=(new_owner) + # self.old_owner = self.owner + # super # end # end # - # === Options - # [:class_name] - # Specify the class name of the association. Use it only if that name can't be inferred - # from the association name. So <tt>has_many :products</tt> will by default be linked - # to the +Product+ class, but if the real class name is +SpecialProduct+, you'll have to - # specify it with this option. - # [:foreign_key] - # Specify the foreign key used for the association. By default this is guessed to be the name - # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_many - # association will use "person_id" as the default <tt>:foreign_key</tt>. - # [:foreign_type] - # Specify the column used to store the associated object's type, if this is a polymorphic - # association. By default this is guessed to be the name of the polymorphic association - # specified on "as" option with a "_type" suffix. So a class that defines a - # <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the - # default <tt>:foreign_type</tt>. - # [:primary_key] - # Specify the name of the column to use as the primary key for the association. By default this is +id+. - # [:dependent] - # Controls what happens to the associated objects when - # their owner is destroyed. Note that these are implemented as - # callbacks, and Rails executes callbacks in order. Therefore, other - # similar callbacks may affect the <tt>:dependent</tt> behavior, and the - # <tt>:dependent</tt> behavior may affect other callbacks. - # - # * <tt>:destroy</tt> causes all the associated objects to also be destroyed. - # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed). - # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed. - # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records. - # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects. - # - # If using with the <tt>:through</tt> option, the association on the join model must be - # a #belongs_to, and the records which get deleted are the join records, rather than - # the associated records. - # [:counter_cache] - # This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option, - # when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association. - # [:as] - # Specifies a polymorphic interface (See #belongs_to). - # [:through] - # Specifies an association through which to perform the query. This can be any other type - # of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>, - # <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the - # source reflection. - # - # If the association on the join model is a #belongs_to, the collection can be modified - # and the records on the <tt>:through</tt> model will be automatically created and removed - # as appropriate. Otherwise, the collection is read-only, so you should manipulate the - # <tt>:through</tt> association directly. - # - # If you are going to modify the association (rather than just read from it), then it is - # a good idea to set the <tt>:inverse_of</tt> option on the source association on the - # join model. This allows associated records to be built which will automatically create - # the appropriate join model records when they are saved. (See the 'Association Join Models' - # section above.) - # [:source] - # Specifies the source association name used by #has_many <tt>:through</tt> queries. - # Only use it if the name cannot be inferred from the association. - # <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or - # <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given. - # [:source_type] - # Specifies type of the source association used by #has_many <tt>:through</tt> queries where the source - # association is a polymorphic #belongs_to. - # [:validate] - # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default. - # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. - # [:autosave] - # If true, always save the associated objects or destroy them if marked for destruction, - # when saving the parent object. If false, never save or destroy the associated objects. - # By default, only save associated objects that are new records. This option is implemented as a - # +before_save+ callback. Because callbacks are run in the order they are defined, associated objects - # may need to be explicitly saved in any user-defined +before_save+ callbacks. - # - # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets - # <tt>:autosave</tt> to <tt>true</tt>. - # [:inverse_of] - # Specifies the name of the #belongs_to association on the associated object - # that is the inverse of this #has_many association. Does not work in combination - # with <tt>:through</tt> or <tt>:as</tt> options. - # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. - # [:extend] - # Specifies a module or array of modules that will be extended into the association object returned. - # Useful for defining methods on associations, especially when they should be shared between multiple - # association objects. - # - # Option examples: - # has_many :comments, -> { order("posted_on") } - # has_many :comments, -> { includes(:author) } - # has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person" - # has_many :tracks, -> { order("position") }, dependent: :destroy - # has_many :comments, dependent: :nullify - # has_many :tags, as: :taggable - # has_many :reports, -> { readonly } - # has_many :subscribers, through: :subscriptions, source: :user - def has_many(name, scope = nil, options = {}, &extension) - reflection = Builder::HasMany.build(self, name, scope, options, &extension) - Reflection.add_reflection self, name, reflection - end - - # Specifies a one-to-one association with another class. This method should only be used - # if the other class contains the foreign key. If the current class contains the foreign key, - # then you should use #belongs_to instead. See also ActiveRecord::Associations::ClassMethods's overview - # on when to use #has_one and when to use #belongs_to. - # - # The following methods for retrieval and query of a single associated object will be added: - # - # +association+ is a placeholder for the symbol passed as the +name+ argument, so - # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>. - # - # [association(force_reload = false)] - # Returns the associated object. +nil+ is returned if none is found. - # [association=(associate)] - # Assigns the associate object, extracts the primary key, sets it as the foreign key, - # and saves the associate object. To avoid database inconsistencies, permanently deletes an existing - # associated object when assigning a new one, even if the new one isn't saved to database. - # [build_association(attributes = {})] - # Returns a new object of the associated type that has been instantiated - # with +attributes+ and linked to this object through a foreign key, but has not - # yet been saved. - # [create_association(attributes = {})] - # Returns a new object of the associated type that has been instantiated - # with +attributes+, linked to this object through a foreign key, and that - # has already been saved (if it passed the validation). - # [create_association!(attributes = {})] - # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid - # if the record is invalid. - # - # === Example - # - # An Account class declares <tt>has_one :beneficiary</tt>, which will add: - # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>) - # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>) - # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>) - # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>) - # * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>) - # - # === Scopes - # - # You can pass a second argument +scope+ as a callable (i.e. proc or - # lambda) to retrieve a specific record or customize the generated query - # when you access the associated object. - # - # Scope examples: - # has_one :author, -> { where(comment_id: 1) } - # has_one :employer, -> { joins(:company) } - # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) } - # - # === Options - # - # The declaration can also include an +options+ hash to specialize the behavior of the association. - # - # Options are: - # [:class_name] - # Specify the class name of the association. Use it only if that name can't be inferred - # from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but - # if the real class name is Person, you'll have to specify it with this option. - # [:dependent] - # Controls what happens to the associated object when - # its owner is destroyed: - # - # * <tt>:destroy</tt> causes the associated object to also be destroyed - # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute) - # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed. - # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record - # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object - # - # Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option. - # [:foreign_key] - # Specify the foreign key used for the association. By default this is guessed to be the name - # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_one association - # will use "person_id" as the default <tt>:foreign_key</tt>. - # [:foreign_type] - # Specify the column used to store the associated object's type, if this is a polymorphic - # association. By default this is guessed to be the name of the polymorphic association - # specified on "as" option with a "_type" suffix. So a class that defines a - # <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the - # default <tt>:foreign_type</tt>. - # [:primary_key] - # Specify the method that returns the primary key used for the association. By default this is +id+. - # [:as] - # Specifies a polymorphic interface (See #belongs_to). - # [:through] - # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>, - # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the - # source reflection. You can only use a <tt>:through</tt> query through a #has_one - # or #belongs_to association on the join model. - # [:source] - # Specifies the source association name used by #has_one <tt>:through</tt> queries. - # Only use it if the name cannot be inferred from the association. - # <tt>has_one :favorite, through: :favorites</tt> will look for a - # <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given. - # [:source_type] - # Specifies type of the source association used by #has_one <tt>:through</tt> queries where the source - # association is a polymorphic #belongs_to. - # [:validate] - # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default. - # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. - # [:autosave] - # If true, always save the associated object or destroy it if marked for destruction, - # when saving the parent object. If false, never save or destroy the associated object. - # By default, only save the associated object if it's a new record. - # - # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets - # <tt>:autosave</tt> to <tt>true</tt>. - # [:inverse_of] - # Specifies the name of the #belongs_to association on the associated object - # that is the inverse of this #has_one association. Does not work in combination - # with <tt>:through</tt> or <tt>:as</tt> options. - # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. - # [:required] - # When set to +true+, the association will also have its presence validated. - # This will validate the association itself, not the id. You can use - # +:inverse_of+ to avoid an extra query during validation. - # - # Option examples: - # has_one :credit_card, dependent: :destroy # destroys the associated credit card - # has_one :credit_card, dependent: :nullify # updates the associated records foreign - # # key value to NULL rather than destroying it - # has_one :last_comment, -> { order('posted_on') }, class_name: "Comment" - # has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person" - # has_one :attachment, as: :attachable - # has_one :boss, -> { readonly } - # has_one :club, through: :membership - # has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable - # has_one :credit_card, required: true - def has_one(name, scope = nil, options = {}) - reflection = Builder::HasOne.build(self, name, scope, options) - Reflection.add_reflection self, name, reflection - end - - # Specifies a one-to-one association with another class. This method should only be used - # if this class contains the foreign key. If the other class contains the foreign key, - # then you should use #has_one instead. See also ActiveRecord::Associations::ClassMethods's overview - # on when to use #has_one and when to use #belongs_to. - # - # Methods will be added for retrieval and query for a single associated object, for which - # this object holds an id: - # - # +association+ is a placeholder for the symbol passed as the +name+ argument, so - # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>. - # - # [association(force_reload = false)] - # Returns the associated object. +nil+ is returned if none is found. - # [association=(associate)] - # Assigns the associate object, extracts the primary key, and sets it as the foreign key. - # [build_association(attributes = {})] - # Returns a new object of the associated type that has been instantiated - # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. - # [create_association(attributes = {})] - # Returns a new object of the associated type that has been instantiated - # with +attributes+, linked to this object through a foreign key, and that - # has already been saved (if it passed the validation). - # [create_association!(attributes = {})] - # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid - # if the record is invalid. - # - # === Example - # - # A Post class declares <tt>belongs_to :author</tt>, which will add: - # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>) - # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>) - # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>) - # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>) - # * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>) - # The declaration can also include an +options+ hash to specialize the behavior of the association. - # - # === Scopes - # - # You can pass a second argument +scope+ as a callable (i.e. proc or - # lambda) to retrieve a specific record or customize the generated query - # when you access the associated object. - # - # Scope examples: - # belongs_to :firm, -> { where(id: 2) } - # belongs_to :user, -> { joins(:friends) } - # belongs_to :level, ->(level) { where("game_level > ?", level.current) } - # - # === Options - # - # [:class_name] - # Specify the class name of the association. Use it only if that name can't be inferred - # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but - # if the real class name is Person, you'll have to specify it with this option. - # [:foreign_key] - # Specify the foreign key used for the association. By default this is guessed to be the name - # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt> - # association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly, - # <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key - # of "favorite_person_id". - # [:foreign_type] - # Specify the column used to store the associated object's type, if this is a polymorphic - # association. By default this is guessed to be the name of the association with a "_type" - # suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt> - # association will use "taggable_type" as the default <tt>:foreign_type</tt>. - # [:primary_key] - # Specify the method that returns the primary key of associated object used for the association. - # By default this is id. - # [:dependent] - # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to - # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. - # This option should not be specified when #belongs_to is used in conjunction with - # a #has_many relationship on another class because of the potential to leave - # orphaned records behind. - # [:counter_cache] - # Caches the number of belonging objects on the associate class through the use of CounterCache::ClassMethods#increment_counter - # and CounterCache::ClassMethods#decrement_counter. The counter cache is incremented when an object of this - # class is created and decremented when it's destroyed. This requires that a column - # named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class) - # is used on the associate class (such as a Post class) - that is the migration for - # <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will - # return the count cached, see note below). You can also specify a custom counter - # cache column by providing a column name instead of a +true+/+false+ value to this - # option (e.g., <tt>counter_cache: :my_custom_counter</tt>.) - # Note: Specifying a counter cache will add it to that model's list of readonly attributes - # using +attr_readonly+. - # [:polymorphic] - # Specify this association is a polymorphic association by passing +true+. - # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute - # to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>). - # [:validate] - # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default. - # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. - # [:autosave] - # If true, always save the associated object or destroy it if marked for destruction, when - # saving the parent object. - # If false, never save or destroy the associated object. - # By default, only save the associated object if it's a new record. - # - # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for - # sets <tt>:autosave</tt> to <tt>true</tt>. - # [:touch] - # If true, the associated object will be touched (the updated_at/on attributes set to current time) - # when this record is either saved or destroyed. If you specify a symbol, that attribute - # will be updated with the current time in addition to the updated_at/on attribute. - # Please note that with touching no validation is performed and only the +after_touch+, - # +after_commit+ and +after_rollback+ callbacks are executed. - # [:inverse_of] - # Specifies the name of the #has_one or #has_many association on the associated - # object that is the inverse of this #belongs_to association. Does not work in - # combination with the <tt>:polymorphic</tt> options. - # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. - # [:optional] - # When set to +true+, the association will not have its presence validated. - # [:required] - # When set to +true+, the association will also have its presence validated. - # This will validate the association itself, not the id. You can use - # +:inverse_of+ to avoid an extra query during validation. - # NOTE: <tt>required</tt> is set to <tt>true</tt> by default and is deprecated. If - # you don't want to have association presence validated, use <tt>optional: true</tt>. - # - # Option examples: - # belongs_to :firm, foreign_key: "client_of" - # belongs_to :person, primary_key: "name", foreign_key: "person_name" - # belongs_to :author, class_name: "Person", foreign_key: "author_id" - # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count }, - # class_name: "Coupon", foreign_key: "coupon_id" - # belongs_to :attachable, polymorphic: true - # belongs_to :project, -> { readonly } - # belongs_to :post, counter_cache: true - # belongs_to :comment, touch: true - # belongs_to :company, touch: :employees_last_updated_at - # belongs_to :user, optional: true - def belongs_to(name, scope = nil, options = {}) - reflection = Builder::BelongsTo.build(self, name, scope, options) - Reflection.add_reflection self, name, reflection - end - - # Specifies a many-to-many relationship with another class. This associates two classes via an - # intermediate join table. Unless the join table is explicitly specified as an option, it is - # guessed using the lexical order of the class names. So a join between Developer and Project - # will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically. - # Note that this precedence is calculated using the <tt><</tt> operator for String. This - # means that if the strings are of different lengths, and the strings are equal when compared - # up to the shortest length, then the longer string is considered of higher - # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" - # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", - # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the - # custom <tt>:join_table</tt> option if you need to. - # If your tables share a common prefix, it will only appear once at the beginning. For example, - # the tables "catalog_categories" and "catalog_products" generate a join table name of "catalog_categories_products". - # - # The join table should not have a primary key or a model associated with it. You must manually generate the - # join table with a migration such as this: - # - # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[5.0] - # def change - # create_join_table :developers, :projects + # If your model class is <tt>Project</tt>, then the module is + # named <tt>Project::GeneratedAssociationMethods</tt>. The +GeneratedAssociationMethods+ module is + # included in the model class immediately after the (anonymous) generated attributes methods + # module, meaning an association will override the methods for an attribute with the same name. + # + # == Cardinality and associations + # + # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many + # relationships between models. Each model uses an association to describe its role in + # the relation. The #belongs_to association is always used in the model that has + # the foreign key. + # + # === One-to-one + # + # Use #has_one in the base, and #belongs_to in the associated model. + # + # class Employee < ActiveRecord::Base + # has_one :office + # end + # class Office < ActiveRecord::Base + # belongs_to :employee # foreign key - employee_id + # end + # + # === One-to-many + # + # Use #has_many in the base, and #belongs_to in the associated model. + # + # class Manager < ActiveRecord::Base + # has_many :employees + # end + # class Employee < ActiveRecord::Base + # belongs_to :manager # foreign key - manager_id + # end + # + # === Many-to-many + # + # There are two ways to build a many-to-many relationship. + # + # The first way uses a #has_many association with the <tt>:through</tt> option and a join model, so + # there are two stages of associations. + # + # class Assignment < ActiveRecord::Base + # belongs_to :programmer # foreign key - programmer_id + # belongs_to :project # foreign key - project_id + # end + # class Programmer < ActiveRecord::Base + # has_many :assignments + # has_many :projects, through: :assignments + # end + # class Project < ActiveRecord::Base + # has_many :assignments + # has_many :programmers, through: :assignments + # end + # + # For the second way, use #has_and_belongs_to_many in both models. This requires a join table + # that has no corresponding model or primary key. + # + # class Programmer < ActiveRecord::Base + # has_and_belongs_to_many :projects # foreign keys in the join table + # end + # class Project < ActiveRecord::Base + # has_and_belongs_to_many :programmers # foreign keys in the join table + # end + # + # Choosing which way to build a many-to-many relationship is not always simple. + # If you need to work with the relationship model as its own entity, + # use #has_many <tt>:through</tt>. Use #has_and_belongs_to_many when working with legacy schemas or when + # you never work directly with the relationship itself. + # + # == Is it a #belongs_to or #has_one association? + # + # Both express a 1-1 relationship. The difference is mostly where to place the foreign + # key, which goes on the table for the class declaring the #belongs_to relationship. + # + # class User < ActiveRecord::Base + # # I reference an account. + # belongs_to :account + # end + # + # class Account < ActiveRecord::Base + # # One user references me. + # has_one :user + # end + # + # The tables for these classes could look something like: + # + # CREATE TABLE users ( + # id int NOT NULL auto_increment, + # account_id int default NULL, + # name varchar default NULL, + # PRIMARY KEY (id) + # ) + # + # CREATE TABLE accounts ( + # id int NOT NULL auto_increment, + # name varchar default NULL, + # PRIMARY KEY (id) + # ) + # + # == Unsaved objects and associations + # + # You can manipulate objects and associations before they are saved to the database, but + # there is some special behavior you should be aware of, mostly involving the saving of + # associated objects. + # + # You can set the <tt>:autosave</tt> option on a #has_one, #belongs_to, + # #has_many, or #has_and_belongs_to_many association. Setting it + # to +true+ will _always_ save the members, whereas setting it to +false+ will + # _never_ save the members. More details about <tt>:autosave</tt> option is available at + # AutosaveAssociation. + # + # === One-to-one associations + # + # * Assigning an object to a #has_one association automatically saves that object and + # the object being replaced (if there is one), in order to update their foreign + # keys - except if the parent object is unsaved (<tt>new_record? == true</tt>). + # * If either of these saves fail (due to one of the objects being invalid), an + # ActiveRecord::RecordNotSaved exception is raised and the assignment is + # cancelled. + # * If you wish to assign an object to a #has_one association without saving it, + # use the <tt>#build_association</tt> method (documented below). The object being + # replaced will still be saved to update its foreign key. + # * Assigning an object to a #belongs_to association does not save the object, since + # the foreign key field belongs on the parent. It does not save the parent either. + # + # === Collections + # + # * Adding an object to a collection (#has_many or #has_and_belongs_to_many) automatically + # saves that object, except if the parent object (the owner of the collection) is not yet + # stored in the database. + # * If saving any of the objects being added to a collection (via <tt>push</tt> or similar) + # fails, then <tt>push</tt> returns +false+. + # * If saving fails while replacing the collection (via <tt>association=</tt>), an + # ActiveRecord::RecordNotSaved exception is raised and the assignment is + # cancelled. + # * You can add an object to a collection without automatically saving it by using the + # <tt>collection.build</tt> method (documented below). + # * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically + # saved when the parent is saved. + # + # == Customizing the query + # + # \Associations are built from <tt>Relation</tt> objects, and you can use the Relation syntax + # to customize them. For example, to add a condition: + # + # class Blog < ActiveRecord::Base + # has_many :published_posts, -> { where(published: true) }, class_name: 'Post' + # end + # + # Inside the <tt>-> { ... }</tt> block you can use all of the usual Relation methods. + # + # === Accessing the owner object + # + # Sometimes it is useful to have access to the owner object when building the query. The owner + # is passed as a parameter to the block. For example, the following association would find all + # events that occur on the user's birthday: + # + # class User < ActiveRecord::Base + # has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event' + # end + # + # Note: Joining, eager loading and preloading of these associations is not fully possible. + # These operations happen before instance creation and the scope will be called with a +nil+ argument. + # This can lead to unexpected behavior and is deprecated. + # + # == Association callbacks + # + # Similar to the normal callbacks that hook into the life cycle of an Active Record object, + # you can also define callbacks that get triggered when you add an object to or remove an + # object from an association collection. + # + # class Project + # has_and_belongs_to_many :developers, after_add: :evaluate_velocity + # + # def evaluate_velocity(developer) + # ... # end # end # - # It's also a good idea to add indexes to each of those columns to speed up the joins process. - # However, in MySQL it is advised to add a compound index for both of the columns as MySQL only - # uses one index per table during the lookup. - # - # Adds the following methods for retrieval and query: - # - # +collection+ is a placeholder for the symbol passed as the +name+ argument, so - # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>. - # - # [collection(force_reload = false)] - # Returns an array of all the associated objects. - # An empty array is returned if none are found. - # [collection<<(object, ...)] - # Adds one or more objects to the collection by creating associations in the join table - # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method). - # Note that this operation instantly fires update SQL without waiting for the save or update call on the - # parent object, unless the parent object is a new record. - # [collection.delete(object, ...)] - # Removes one or more objects from the collection by removing their associations from the join table. - # This does not destroy the objects. - # [collection.destroy(object, ...)] - # Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option. - # This does not destroy the objects. - # [collection=objects] - # Replaces the collection's content by deleting and adding objects as appropriate. - # [collection_singular_ids] - # Returns an array of the associated objects' ids. - # [collection_singular_ids=ids] - # Replace the collection by the objects identified by the primary keys in +ids+. - # [collection.clear] - # Removes every object from the collection. This does not destroy the objects. - # [collection.empty?] - # Returns +true+ if there are no associated objects. - # [collection.size] - # Returns the number of associated objects. - # [collection.find(id)] - # Finds an associated object responding to the +id+ and that - # meets the condition that it has to be associated with this object. - # Uses the same rules as ActiveRecord::FinderMethods#find. - # [collection.exists?(...)] - # Checks whether an associated object with the given conditions exists. - # Uses the same rules as ActiveRecord::FinderMethods#exists?. - # [collection.build(attributes = {})] - # Returns a new object of the collection type that has been instantiated - # with +attributes+ and linked to this object through the join table, but has not yet been saved. - # [collection.create(attributes = {})] - # Returns a new object of the collection type that has been instantiated - # with +attributes+, linked to this object through the join table, and that has already been - # saved (if it passed the validation). - # - # === Example - # - # A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add: - # * <tt>Developer#projects</tt> - # * <tt>Developer#projects<<</tt> - # * <tt>Developer#projects.delete</tt> - # * <tt>Developer#projects.destroy</tt> - # * <tt>Developer#projects=</tt> - # * <tt>Developer#project_ids</tt> - # * <tt>Developer#project_ids=</tt> - # * <tt>Developer#projects.clear</tt> - # * <tt>Developer#projects.empty?</tt> - # * <tt>Developer#projects.size</tt> - # * <tt>Developer#projects.find(id)</tt> - # * <tt>Developer#projects.exists?(...)</tt> - # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>) - # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>) - # The declaration may include an +options+ hash to specialize the behavior of the association. - # - # === Scopes - # - # You can pass a second argument +scope+ as a callable (i.e. proc or - # lambda) to retrieve a specific set of records or customize the generated - # query when you access the associated collection. - # - # Scope examples: - # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) } - # has_and_belongs_to_many :categories, ->(category) { - # where("default_category = ?", category.name) - # } - # - # === Extensions - # - # The +extension+ argument allows you to pass a block into a - # has_and_belongs_to_many association. This is useful for adding new - # finders, creators and other factory-type methods to be used as part of - # the association. - # - # Extension examples: - # has_and_belongs_to_many :contractors do + # It's possible to stack callbacks by passing them as an array. Example: + # + # class Project + # has_and_belongs_to_many :developers, + # after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}] + # end + # + # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+. + # + # If any of the +before_add+ callbacks throw an exception, the object will not be + # added to the collection. + # + # Similarly, if any of the +before_remove+ callbacks throw an exception, the object + # will not be removed from the collection. + # + # == Association extensions + # + # The proxy objects that control the access to associations can be extended through anonymous + # modules. This is especially beneficial for adding new finders, creators, and other + # factory-type methods that are only used as part of this association. + # + # class Account < ActiveRecord::Base + # has_many :people do + # def find_or_create_by_name(name) + # first_name, last_name = name.split(" ", 2) + # find_or_create_by(first_name: first_name, last_name: last_name) + # end + # end + # end + # + # person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson") + # person.first_name # => "David" + # person.last_name # => "Heinemeier Hansson" + # + # If you need to share the same extensions between many associations, you can use a named + # extension module. + # + # module FindOrCreateByNameExtension # def find_or_create_by_name(name) # first_name, last_name = name.split(" ", 2) # find_or_create_by(first_name: first_name, last_name: last_name) # end # end # - # === Options - # - # [:class_name] - # Specify the class name of the association. Use it only if that name can't be inferred - # from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the - # Project class, but if the real class name is SuperProject, you'll have to specify it with this option. - # [:join_table] - # Specify the name of the join table if the default based on lexical order isn't what you want. - # <b>WARNING:</b> If you're overwriting the table name of either class, the +table_name+ method - # MUST be declared underneath any #has_and_belongs_to_many declaration in order to work. - # [:foreign_key] - # Specify the foreign key used for the association. By default this is guessed to be the name - # of this class in lower-case and "_id" suffixed. So a Person class that makes - # a #has_and_belongs_to_many association to Project will use "person_id" as the - # default <tt>:foreign_key</tt>. - # [:association_foreign_key] - # Specify the foreign key used for the association on the receiving side of the association. - # By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed. - # So if a Person class makes a #has_and_belongs_to_many association to Project, - # the association will use "project_id" as the default <tt>:association_foreign_key</tt>. - # [:validate] - # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default. - # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. - # [:autosave] - # If true, always save the associated objects or destroy them if marked for destruction, when - # saving the parent object. - # If false, never save or destroy the associated objects. - # By default, only save associated objects that are new records. - # - # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets - # <tt>:autosave</tt> to <tt>true</tt>. - # - # Option examples: - # has_and_belongs_to_many :projects - # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) } - # has_and_belongs_to_many :nations, class_name: "Country" - # has_and_belongs_to_many :categories, join_table: "prods_cats" - # has_and_belongs_to_many :categories, -> { readonly } - def has_and_belongs_to_many(name, scope = nil, options = {}, &extension) - if scope.is_a?(Hash) - options = scope - scope = nil + # class Account < ActiveRecord::Base + # has_many :people, -> { extending FindOrCreateByNameExtension } + # end + # + # class Company < ActiveRecord::Base + # has_many :people, -> { extending FindOrCreateByNameExtension } + # end + # + # Some extensions can only be made to work with knowledge of the association's internals. + # Extensions can access relevant state using the following methods (where +items+ is the + # name of the association): + # + # * <tt>record.association(:items).owner</tt> - Returns the object the association is part of. + # * <tt>record.association(:items).reflection</tt> - Returns the reflection object that describes the association. + # * <tt>record.association(:items).target</tt> - Returns the associated object for #belongs_to and #has_one, or + # the collection of associated objects for #has_many and #has_and_belongs_to_many. + # + # However, inside the actual extension code, you will not have access to the <tt>record</tt> as + # above. In this case, you can access <tt>proxy_association</tt>. For example, + # <tt>record.association(:items)</tt> and <tt>record.items.proxy_association</tt> will return + # the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside + # association extensions. + # + # == Association Join Models + # + # Has Many associations can be configured with the <tt>:through</tt> option to use an + # explicit join model to retrieve the data. This operates similarly to a + # #has_and_belongs_to_many association. The advantage is that you're able to add validations, + # callbacks, and extra attributes on the join model. Consider the following schema: + # + # class Author < ActiveRecord::Base + # has_many :authorships + # has_many :books, through: :authorships + # end + # + # class Authorship < ActiveRecord::Base + # belongs_to :author + # belongs_to :book + # end + # + # @author = Author.first + # @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to + # @author.books # selects all books by using the Authorship join model + # + # You can also go through a #has_many association on the join model: + # + # class Firm < ActiveRecord::Base + # has_many :clients + # has_many :invoices, through: :clients + # end + # + # class Client < ActiveRecord::Base + # belongs_to :firm + # has_many :invoices + # end + # + # class Invoice < ActiveRecord::Base + # belongs_to :client + # end + # + # @firm = Firm.first + # @firm.clients.flat_map { |c| c.invoices } # select all invoices for all clients of the firm + # @firm.invoices # selects all invoices by going through the Client join model + # + # Similarly you can go through a #has_one association on the join model: + # + # class Group < ActiveRecord::Base + # has_many :users + # has_many :avatars, through: :users + # end + # + # class User < ActiveRecord::Base + # belongs_to :group + # has_one :avatar + # end + # + # class Avatar < ActiveRecord::Base + # belongs_to :user + # end + # + # @group = Group.first + # @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group + # @group.avatars # selects all avatars by going through the User join model. + # + # An important caveat with going through #has_one or #has_many associations on the + # join model is that these associations are *read-only*. For example, the following + # would not work following the previous example: + # + # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around + # @group.avatars.delete(@group.avatars.last) # so would this + # + # == Setting Inverses + # + # If you are using a #belongs_to on the join model, it is a good idea to set the + # <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example + # works correctly (where <tt>tags</tt> is a #has_many <tt>:through</tt> association): + # + # @post = Post.first + # @tag = @post.tags.build name: "ruby" + # @tag.save + # + # The last line ought to save the through record (a <tt>Tagging</tt>). This will only work if the + # <tt>:inverse_of</tt> is set: + # + # class Tagging < ActiveRecord::Base + # belongs_to :post + # belongs_to :tag, inverse_of: :taggings + # end + # + # If you do not set the <tt>:inverse_of</tt> record, the association will + # do its best to match itself up with the correct inverse. Automatic + # inverse detection only works on #has_many, #has_one, and + # #belongs_to associations. + # + # Extra options on the associations, as defined in the + # <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will + # also prevent the association's inverse from being found automatically. + # + # The automatic guessing of the inverse association uses a heuristic based + # on the name of the class, so it may not work for all associations, + # especially the ones with non-standard names. + # + # You can turn off the automatic detection of inverse associations by setting + # the <tt>:inverse_of</tt> option to <tt>false</tt> like so: + # + # class Tagging < ActiveRecord::Base + # belongs_to :tag, inverse_of: false + # end + # + # == Nested \Associations + # + # You can actually specify *any* association with the <tt>:through</tt> option, including an + # association which has a <tt>:through</tt> option itself. For example: + # + # class Author < ActiveRecord::Base + # has_many :posts + # has_many :comments, through: :posts + # has_many :commenters, through: :comments + # end + # + # class Post < ActiveRecord::Base + # has_many :comments + # end + # + # class Comment < ActiveRecord::Base + # belongs_to :commenter + # end + # + # @author = Author.first + # @author.commenters # => People who commented on posts written by the author + # + # An equivalent way of setting up this association this would be: + # + # class Author < ActiveRecord::Base + # has_many :posts + # has_many :commenters, through: :posts + # end + # + # class Post < ActiveRecord::Base + # has_many :comments + # has_many :commenters, through: :comments + # end + # + # class Comment < ActiveRecord::Base + # belongs_to :commenter + # end + # + # When using a nested association, you will not be able to modify the association because there + # is not enough information to know what modification to make. For example, if you tried to + # add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the + # intermediate <tt>Post</tt> and <tt>Comment</tt> objects. + # + # == Polymorphic \Associations + # + # Polymorphic associations on models are not restricted on what types of models they + # can be associated with. Rather, they specify an interface that a #has_many association + # must adhere to. + # + # class Asset < ActiveRecord::Base + # belongs_to :attachable, polymorphic: true + # end + # + # class Post < ActiveRecord::Base + # has_many :assets, as: :attachable # The :as option specifies the polymorphic interface to use. + # end + # + # @asset.attachable = @post + # + # This works by using a type column in addition to a foreign key to specify the associated + # record. In the Asset example, you'd need an +attachable_id+ integer column and an + # +attachable_type+ string column. + # + # Using polymorphic associations in combination with single table inheritance (STI) is + # a little tricky. In order for the associations to work as expected, ensure that you + # store the base model for the STI models in the type column of the polymorphic + # association. To continue with the asset example above, suppose there are guest posts + # and member posts that use the posts table for STI. In this case, there must be a +type+ + # column in the posts table. + # + # Note: The <tt>attachable_type=</tt> method is being called when assigning an +attachable+. + # The +class_name+ of the +attachable+ is passed as a String. + # + # class Asset < ActiveRecord::Base + # belongs_to :attachable, polymorphic: true + # + # def attachable_type=(class_name) + # super(class_name.constantize.base_class.to_s) + # end + # end + # + # class Post < ActiveRecord::Base + # # because we store "Post" in attachable_type now dependent: :destroy will work + # has_many :assets, as: :attachable, dependent: :destroy + # end + # + # class GuestPost < Post + # end + # + # class MemberPost < Post + # end + # + # == Caching + # + # All of the methods are built on a simple caching principle that will keep the result + # of the last query around unless specifically instructed not to. The cache is even + # shared across methods to make it even cheaper to use the macro-added methods without + # worrying too much about performance at the first go. + # + # project.milestones # fetches milestones from the database + # project.milestones.size # uses the milestone cache + # project.milestones.empty? # uses the milestone cache + # project.milestones(true).size # fetches milestones from the database + # project.milestones # uses the milestone cache + # + # == Eager loading of associations + # + # Eager loading is a way to find objects of a certain class and a number of named associations. + # It is one of the easiest ways to prevent the dreaded N+1 problem in which fetching 100 + # posts that each need to display their author triggers 101 database queries. Through the + # use of eager loading, the number of queries will be reduced from 101 to 2. + # + # class Post < ActiveRecord::Base + # belongs_to :author + # has_many :comments + # end + # + # Consider the following loop using the class above: + # + # Post.all.each do |post| + # puts "Post: " + post.title + # puts "Written by: " + post.author.name + # puts "Last comment on: " + post.comments.first.created_on + # end + # + # To iterate over these one hundred posts, we'll generate 201 database queries. Let's + # first just optimize it for retrieving the author: + # + # Post.includes(:author).each do |post| + # + # This references the name of the #belongs_to association that also used the <tt>:author</tt> + # symbol. After loading the posts, +find+ will collect the +author_id+ from each one and load + # all of the referenced authors with one query. Doing so will cut down the number of queries + # from 201 to 102. + # + # We can improve upon the situation further by referencing both associations in the finder with: + # + # Post.includes(:author, :comments).each do |post| + # + # This will load all comments with a single query. This reduces the total number of queries + # to 3. In general, the number of queries will be 1 plus the number of associations + # named (except if some of the associations are polymorphic #belongs_to - see below). + # + # To include a deep hierarchy of associations, use a hash: + # + # Post.includes(:author, { comments: { author: :gravatar } }).each do |post| + # + # The above code will load all the comments and all of their associated + # authors and gravatars. You can mix and match any combination of symbols, + # arrays, and hashes to retrieve the associations you want to load. + # + # All of this power shouldn't fool you into thinking that you can pull out huge amounts + # of data with no performance penalty just because you've reduced the number of queries. + # The database still needs to send all the data to Active Record and it still needs to + # be processed. So it's no catch-all for performance problems, but it's a great way to + # cut down on the number of queries in a situation as the one described above. + # + # Since only one table is loaded at a time, conditions or orders cannot reference tables + # other than the main one. If this is the case, Active Record falls back to the previously + # used <tt>LEFT OUTER JOIN</tt> based strategy. For example: + # + # Post.includes([:author, :comments]).where(['comments.approved = ?', true]) + # + # This will result in a single SQL query with joins along the lines of: + # <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and + # <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions + # like this can have unintended consequences. + # In the above example, posts with no approved comments are not returned at all because + # the conditions apply to the SQL statement as a whole and not just to the association. + # + # You must disambiguate column references for this fallback to happen, for example + # <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not. + # + # If you want to load all posts (including posts with no approved comments), then write + # your own <tt>LEFT OUTER JOIN</tt> query using <tt>ON</tt>: + # + # Post.joins("LEFT OUTER JOIN comments ON comments.post_id = posts.id AND comments.approved = '1'") + # + # In this case, it is usually more natural to include an association which has conditions defined on it: + # + # class Post < ActiveRecord::Base + # has_many :approved_comments, -> { where(approved: true) }, class_name: 'Comment' + # end + # + # Post.includes(:approved_comments) + # + # This will load posts and eager load the +approved_comments+ association, which contains + # only those comments that have been approved. + # + # If you eager load an association with a specified <tt>:limit</tt> option, it will be ignored, + # returning all the associated objects: + # + # class Picture < ActiveRecord::Base + # has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment' + # end + # + # Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments. + # + # Eager loading is supported with polymorphic associations. + # + # class Address < ActiveRecord::Base + # belongs_to :addressable, polymorphic: true + # end + # + # A call that tries to eager load the addressable model + # + # Address.includes(:addressable) + # + # This will execute one query to load the addresses and load the addressables with one + # query per addressable type. + # For example, if all the addressables are either of class Person or Company, then a total + # of 3 queries will be executed. The list of addressable types to load is determined on + # the back of the addresses loaded. This is not supported if Active Record has to fallback + # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. + # The reason is that the parent model's type is a column value so its corresponding table + # name cannot be put in the +FROM+/+JOIN+ clauses of that query. + # + # == Table Aliasing + # + # Active Record uses table aliasing in the case that a table is referenced multiple times + # in a join. If a table is referenced only once, the standard table name is used. The + # second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>. + # Indexes are appended for any more successive uses of the table name. + # + # Post.joins(:comments) + # # => SELECT ... FROM posts INNER JOIN comments ON ... + # Post.joins(:special_comments) # STI + # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment' + # Post.joins(:comments, :special_comments) # special_comments is the reflection name, posts is the parent table name + # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts + # + # Acts as tree example: + # + # TreeMixin.joins(:children) + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # TreeMixin.joins(children: :parent) + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # TreeMixin.joins(children: {parent: :children}) + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # INNER JOIN mixins childrens_mixins_2 + # + # Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix: + # + # Post.joins(:categories) + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # Post.joins(categories: :posts) + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # Post.joins(categories: {posts: :categories}) + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2 + # + # If you wish to specify your own custom joins using ActiveRecord::QueryMethods#joins method, those table + # names will take precedence over the eager associations: + # + # Post.joins(:comments).joins("inner join comments ...") + # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ... + # Post.joins(:comments, :special_comments).joins("inner join comments ...") + # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ... + # INNER JOIN comments special_comments_posts ... + # INNER JOIN comments ... + # + # Table aliases are automatically truncated according to the maximum length of table identifiers + # according to the specific database. + # + # == Modules + # + # By default, associations will look for objects within the current module scope. Consider: + # + # module MyApplication + # module Business + # class Firm < ActiveRecord::Base + # has_many :clients + # end + # + # class Client < ActiveRecord::Base; end + # end + # end + # + # When <tt>Firm#clients</tt> is called, it will in turn call + # <tt>MyApplication::Business::Client.find_all_by_firm_id(firm.id)</tt>. + # If you want to associate with a class in another module scope, this can be done by + # specifying the complete class name. + # + # module MyApplication + # module Business + # class Firm < ActiveRecord::Base; end + # end + # + # module Billing + # class Account < ActiveRecord::Base + # belongs_to :firm, class_name: "MyApplication::Business::Firm" + # end + # end + # end + # + # == Bi-directional associations + # + # When you specify an association, there is usually an association on the associated model + # that specifies the same relationship in reverse. For example, with the following models: + # + # class Dungeon < ActiveRecord::Base + # has_many :traps + # has_one :evil_wizard + # end + # + # class Trap < ActiveRecord::Base + # belongs_to :dungeon + # end + # + # class EvilWizard < ActiveRecord::Base + # belongs_to :dungeon + # end + # + # The +traps+ association on +Dungeon+ and the +dungeon+ association on +Trap+ are + # the inverse of each other, and the inverse of the +dungeon+ association on +EvilWizard+ + # is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default, + # Active Record can guess the inverse of the association based on the name + # of the class. The result is the following: + # + # d = Dungeon.first + # t = d.traps.first + # d.object_id == t.dungeon.object_id # => true + # + # The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to + # the same in-memory instance since the association matches the name of the class. + # The result would be the same if we added +:inverse_of+ to our model definitions: + # + # class Dungeon < ActiveRecord::Base + # has_many :traps, inverse_of: :dungeon + # has_one :evil_wizard, inverse_of: :dungeon + # end + # + # class Trap < ActiveRecord::Base + # belongs_to :dungeon, inverse_of: :traps + # end + # + # class EvilWizard < ActiveRecord::Base + # belongs_to :dungeon, inverse_of: :evil_wizard + # end + # + # There are limitations to <tt>:inverse_of</tt> support: + # + # * does not work with <tt>:through</tt> associations. + # * does not work with <tt>:polymorphic</tt> associations. + # * inverse associations for #belongs_to associations #has_many are ignored. + # + # For more information, see the documentation for the +:inverse_of+ option. + # + # == Deleting from associations + # + # === Dependent associations + # + # #has_many, #has_one, and #belongs_to associations support the <tt>:dependent</tt> option. + # This allows you to specify that associated records should be deleted when the owner is + # deleted. + # + # For example: + # + # class Author + # has_many :posts, dependent: :destroy + # end + # Author.find(1).destroy # => Will destroy all of the author's posts, too + # + # The <tt>:dependent</tt> option can have different values which specify how the deletion + # is done. For more information, see the documentation for this option on the different + # specific association types. When no option is given, the behavior is to do nothing + # with the associated records when destroying a record. + # + # Note that <tt>:dependent</tt> is implemented using Rails' callback + # system, which works by processing callbacks in order. Therefore, other + # callbacks declared either before or after the <tt>:dependent</tt> option + # can affect what it does. + # + # Note that <tt>:dependent</tt> option is ignored for #has_one <tt>:through</tt> associations. + # + # === Delete or destroy? + # + # #has_many and #has_and_belongs_to_many associations have the methods <tt>destroy</tt>, + # <tt>delete</tt>, <tt>destroy_all</tt> and <tt>delete_all</tt>. + # + # For #has_and_belongs_to_many, <tt>delete</tt> and <tt>destroy</tt> are the same: they + # cause the records in the join table to be removed. + # + # For #has_many, <tt>destroy</tt> and <tt>destroy_all</tt> will always call the <tt>destroy</tt> method of the + # record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either + # do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or + # if no <tt>:dependent</tt> option is given, then it will follow the default strategy. + # The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for + # #has_many <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete + # the join records, without running their callbacks). + # + # There is also a <tt>clear</tt> method which is the same as <tt>delete_all</tt>, except that + # it returns the association rather than the records which have been deleted. + # + # === What gets deleted? + # + # There is a potential pitfall here: #has_and_belongs_to_many and #has_many <tt>:through</tt> + # associations have records in join tables, as well as the associated records. So when we + # call one of these deletion methods, what exactly should be deleted? + # + # The answer is that it is assumed that deletion on an association is about removing the + # <i>link</i> between the owner and the associated object(s), rather than necessarily the + # associated objects themselves. So with #has_and_belongs_to_many and #has_many + # <tt>:through</tt>, the join records will be deleted, but the associated records won't. + # + # This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.find_by(name: 'food'))</tt> + # you would want the 'food' tag to be unlinked from the post, rather than for the tag itself + # to be removed from the database. + # + # However, there are examples where this strategy doesn't make sense. For example, suppose + # a person has many projects, and each project has many tasks. If we deleted one of a person's + # tasks, we would probably not want the project to be deleted. In this scenario, the delete method + # won't actually work: it can only be used if the association on the join model is a + # #belongs_to. In other situations you are expected to perform operations directly on + # either the associated records or the <tt>:through</tt> association. + # + # With a regular #has_many there is no distinction between the "associated records" + # and the "link", so there is only one choice for what gets deleted. + # + # With #has_and_belongs_to_many and #has_many <tt>:through</tt>, if you want to delete the + # associated records themselves, you can always do something along the lines of + # <tt>person.tasks.each(&:destroy)</tt>. + # + # == Type safety with ActiveRecord::AssociationTypeMismatch + # + # If you attempt to assign an object to an association that doesn't match the inferred + # or specified <tt>:class_name</tt>, you'll get an ActiveRecord::AssociationTypeMismatch. + # + # == Options + # + # All of the association macros can be specialized through options. This makes cases + # more complex than the simple and guessable ones possible. + module ClassMethods + # Specifies a one-to-many association. The following methods for retrieval and query of + # collections of associated objects will be added: + # + # +collection+ is a placeholder for the symbol passed as the +name+ argument, so + # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>. + # + # [collection(force_reload = false)] + # Returns an array of all the associated objects. + # An empty array is returned if none are found. + # [collection<<(object, ...)] + # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. + # Note that this operation instantly fires update SQL without waiting for the save or update call on the + # parent object, unless the parent object is a new record. + # This will also run validations and callbacks of associated object(s). + # [collection.delete(object, ...)] + # Removes one or more objects from the collection by setting their foreign keys to +NULL+. + # Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>, + # and deleted if they're associated with <tt>dependent: :delete_all</tt>. + # + # If the <tt>:through</tt> option is used, then the join records are deleted (rather than + # nullified) by default, but you can specify <tt>dependent: :destroy</tt> or + # <tt>dependent: :nullify</tt> to override this. + # [collection.destroy(object, ...)] + # Removes one or more objects from the collection by running <tt>destroy</tt> on + # each record, regardless of any dependent option, ensuring callbacks are run. + # + # If the <tt>:through</tt> option is used, then the join records are destroyed + # instead, not the objects themselves. + # [collection=objects] + # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt> + # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is + # direct by default. You can specify <tt>dependent: :destroy</tt> or + # <tt>dependent: :nullify</tt> to override this. + # [collection_singular_ids] + # Returns an array of the associated objects' ids + # [collection_singular_ids=ids] + # Replace the collection with the objects identified by the primary keys in +ids+. This + # method loads the models and calls <tt>collection=</tt>. See above. + # [collection.clear] + # Removes every object from the collection. This destroys the associated objects if they + # are associated with <tt>dependent: :destroy</tt>, deletes them directly from the + # database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+. + # If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models. + # Join models are directly deleted. + # [collection.empty?] + # Returns +true+ if there are no associated objects. + # [collection.size] + # Returns the number of associated objects. + # [collection.find(...)] + # Finds an associated object according to the same rules as ActiveRecord::FinderMethods#find. + # [collection.exists?(...)] + # Checks whether an associated object with the given conditions exists. + # Uses the same rules as ActiveRecord::FinderMethods#exists?. + # [collection.build(attributes = {}, ...)] + # Returns one or more new objects of the collection type that have been instantiated + # with +attributes+ and linked to this object through a foreign key, but have not yet + # been saved. + # [collection.create(attributes = {})] + # Returns a new object of the collection type that has been instantiated + # with +attributes+, linked to this object through a foreign key, and that has already + # been saved (if it passed the validation). *Note*: This only works if the base model + # already exists in the DB, not if it is a new (unsaved) record! + # [collection.create!(attributes = {})] + # Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid + # if the record is invalid. + # + # === Example + # + # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add: + # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>) + # * <tt>Firm#clients<<</tt> + # * <tt>Firm#clients.delete</tt> + # * <tt>Firm#clients.destroy</tt> + # * <tt>Firm#clients=</tt> + # * <tt>Firm#client_ids</tt> + # * <tt>Firm#client_ids=</tt> + # * <tt>Firm#clients.clear</tt> + # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>) + # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>) + # * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>) + # * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>) + # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>) + # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>) + # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>) + # The declaration can also include an +options+ hash to specialize the behavior of the association. + # + # === Scopes + # + # You can pass a second argument +scope+ as a callable (i.e. proc or + # lambda) to retrieve a specific set of records or customize the generated + # query when you access the associated collection. + # + # Scope examples: + # has_many :comments, -> { where(author_id: 1) } + # has_many :employees, -> { joins(:address) } + # has_many :posts, ->(post) { where("max_post_length > ?", post.length) } + # + # === Extensions + # + # The +extension+ argument allows you to pass a block into a has_many + # association. This is useful for adding new finders, creators and other + # factory-type methods to be used as part of the association. + # + # Extension examples: + # has_many :employees do + # def find_or_create_by_name(name) + # first_name, last_name = name.split(" ", 2) + # find_or_create_by(first_name: first_name, last_name: last_name) + # end + # end + # + # === Options + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred + # from the association name. So <tt>has_many :products</tt> will by default be linked + # to the +Product+ class, but if the real class name is +SpecialProduct+, you'll have to + # specify it with this option. + # [:foreign_key] + # Specify the foreign key used for the association. By default this is guessed to be the name + # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_many + # association will use "person_id" as the default <tt>:foreign_key</tt>. + # [:foreign_type] + # Specify the column used to store the associated object's type, if this is a polymorphic + # association. By default this is guessed to be the name of the polymorphic association + # specified on "as" option with a "_type" suffix. So a class that defines a + # <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the + # default <tt>:foreign_type</tt>. + # [:primary_key] + # Specify the name of the column to use as the primary key for the association. By default this is +id+. + # [:dependent] + # Controls what happens to the associated objects when + # their owner is destroyed. Note that these are implemented as + # callbacks, and Rails executes callbacks in order. Therefore, other + # similar callbacks may affect the <tt>:dependent</tt> behavior, and the + # <tt>:dependent</tt> behavior may affect other callbacks. + # + # * <tt>:destroy</tt> causes all the associated objects to also be destroyed. + # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed). + # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed. + # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records. + # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects. + # + # If using with the <tt>:through</tt> option, the association on the join model must be + # a #belongs_to, and the records which get deleted are the join records, rather than + # the associated records. + # + # If using <tt>dependent: :destroy</tt> on a scoped association, only the scoped objects are destroyed. + # For example, if a Post model defines + # <tt>has_many :comments, -> { where published: true }, dependent: :destroy</tt> and <tt>destroy</tt> is + # called on a post, only published comments are destroyed. This means that any unpublished comments in the + # database would still contain a foreign key pointing to the now deleted post. + # [:counter_cache] + # This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option, + # when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association. + # [:as] + # Specifies a polymorphic interface (See #belongs_to). + # [:through] + # Specifies an association through which to perform the query. This can be any other type + # of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>, + # <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the + # source reflection. + # + # If the association on the join model is a #belongs_to, the collection can be modified + # and the records on the <tt>:through</tt> model will be automatically created and removed + # as appropriate. Otherwise, the collection is read-only, so you should manipulate the + # <tt>:through</tt> association directly. + # + # If you are going to modify the association (rather than just read from it), then it is + # a good idea to set the <tt>:inverse_of</tt> option on the source association on the + # join model. This allows associated records to be built which will automatically create + # the appropriate join model records when they are saved. (See the 'Association Join Models' + # section above.) + # [:source] + # Specifies the source association name used by #has_many <tt>:through</tt> queries. + # Only use it if the name cannot be inferred from the association. + # <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or + # <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given. + # [:source_type] + # Specifies type of the source association used by #has_many <tt>:through</tt> queries where the source + # association is a polymorphic #belongs_to. + # [:validate] + # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default. + # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. + # [:autosave] + # If true, always save the associated objects or destroy them if marked for destruction, + # when saving the parent object. If false, never save or destroy the associated objects. + # By default, only save associated objects that are new records. This option is implemented as a + # +before_save+ callback. Because callbacks are run in the order they are defined, associated objects + # may need to be explicitly saved in any user-defined +before_save+ callbacks. + # + # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets + # <tt>:autosave</tt> to <tt>true</tt>. + # [:inverse_of] + # Specifies the name of the #belongs_to association on the associated object + # that is the inverse of this #has_many association. Does not work in combination + # with <tt>:through</tt> or <tt>:as</tt> options. + # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. + # [:extend] + # Specifies a module or array of modules that will be extended into the association object returned. + # Useful for defining methods on associations, especially when they should be shared between multiple + # association objects. + # + # Option examples: + # has_many :comments, -> { order("posted_on") } + # has_many :comments, -> { includes(:author) } + # has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person" + # has_many :tracks, -> { order("position") }, dependent: :destroy + # has_many :comments, dependent: :nullify + # has_many :tags, as: :taggable + # has_many :reports, -> { readonly } + # has_many :subscribers, through: :subscriptions, source: :user + def has_many(name, scope = nil, options = {}, &extension) + reflection = Builder::HasMany.build(self, name, scope, options, &extension) + Reflection.add_reflection self, name, reflection end - habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self) + # Specifies a one-to-one association with another class. This method should only be used + # if the other class contains the foreign key. If the current class contains the foreign key, + # then you should use #belongs_to instead. See also ActiveRecord::Associations::ClassMethods's overview + # on when to use #has_one and when to use #belongs_to. + # + # The following methods for retrieval and query of a single associated object will be added: + # + # +association+ is a placeholder for the symbol passed as the +name+ argument, so + # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>. + # + # [association(force_reload = false)] + # Returns the associated object. +nil+ is returned if none is found. + # [association=(associate)] + # Assigns the associate object, extracts the primary key, sets it as the foreign key, + # and saves the associate object. To avoid database inconsistencies, permanently deletes an existing + # associated object when assigning a new one, even if the new one isn't saved to database. + # [build_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated + # with +attributes+ and linked to this object through a foreign key, but has not + # yet been saved. + # [create_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated + # with +attributes+, linked to this object through a foreign key, and that + # has already been saved (if it passed the validation). + # [create_association!(attributes = {})] + # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid + # if the record is invalid. + # + # === Example + # + # An Account class declares <tt>has_one :beneficiary</tt>, which will add: + # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>) + # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>) + # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>) + # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>) + # * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>) + # + # === Scopes + # + # You can pass a second argument +scope+ as a callable (i.e. proc or + # lambda) to retrieve a specific record or customize the generated query + # when you access the associated object. + # + # Scope examples: + # has_one :author, -> { where(comment_id: 1) } + # has_one :employer, -> { joins(:company) } + # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) } + # + # === Options + # + # The declaration can also include an +options+ hash to specialize the behavior of the association. + # + # Options are: + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred + # from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but + # if the real class name is Person, you'll have to specify it with this option. + # [:dependent] + # Controls what happens to the associated object when + # its owner is destroyed: + # + # * <tt>:destroy</tt> causes the associated object to also be destroyed + # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute) + # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed. + # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record + # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object + # + # Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option. + # [:foreign_key] + # Specify the foreign key used for the association. By default this is guessed to be the name + # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_one association + # will use "person_id" as the default <tt>:foreign_key</tt>. + # [:foreign_type] + # Specify the column used to store the associated object's type, if this is a polymorphic + # association. By default this is guessed to be the name of the polymorphic association + # specified on "as" option with a "_type" suffix. So a class that defines a + # <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the + # default <tt>:foreign_type</tt>. + # [:primary_key] + # Specify the method that returns the primary key used for the association. By default this is +id+. + # [:as] + # Specifies a polymorphic interface (See #belongs_to). + # [:through] + # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>, + # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the + # source reflection. You can only use a <tt>:through</tt> query through a #has_one + # or #belongs_to association on the join model. + # [:source] + # Specifies the source association name used by #has_one <tt>:through</tt> queries. + # Only use it if the name cannot be inferred from the association. + # <tt>has_one :favorite, through: :favorites</tt> will look for a + # <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given. + # [:source_type] + # Specifies type of the source association used by #has_one <tt>:through</tt> queries where the source + # association is a polymorphic #belongs_to. + # [:validate] + # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default. + # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. + # [:autosave] + # If true, always save the associated object or destroy it if marked for destruction, + # when saving the parent object. If false, never save or destroy the associated object. + # By default, only save the associated object if it's a new record. + # + # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets + # <tt>:autosave</tt> to <tt>true</tt>. + # [:inverse_of] + # Specifies the name of the #belongs_to association on the associated object + # that is the inverse of this #has_one association. Does not work in combination + # with <tt>:through</tt> or <tt>:as</tt> options. + # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. + # [:required] + # When set to +true+, the association will also have its presence validated. + # This will validate the association itself, not the id. You can use + # +:inverse_of+ to avoid an extra query during validation. + # + # Option examples: + # has_one :credit_card, dependent: :destroy # destroys the associated credit card + # has_one :credit_card, dependent: :nullify # updates the associated records foreign + # # key value to NULL rather than destroying it + # has_one :last_comment, -> { order('posted_on') }, class_name: "Comment" + # has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person" + # has_one :attachment, as: :attachable + # has_one :boss, -> { readonly } + # has_one :club, through: :membership + # has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable + # has_one :credit_card, required: true + def has_one(name, scope = nil, options = {}) + reflection = Builder::HasOne.build(self, name, scope, options) + Reflection.add_reflection self, name, reflection + end - builder = Builder::HasAndBelongsToMany.new name, self, options + # Specifies a one-to-one association with another class. This method should only be used + # if this class contains the foreign key. If the other class contains the foreign key, + # then you should use #has_one instead. See also ActiveRecord::Associations::ClassMethods's overview + # on when to use #has_one and when to use #belongs_to. + # + # Methods will be added for retrieval and query for a single associated object, for which + # this object holds an id: + # + # +association+ is a placeholder for the symbol passed as the +name+ argument, so + # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>. + # + # [association(force_reload = false)] + # Returns the associated object. +nil+ is returned if none is found. + # [association=(associate)] + # Assigns the associate object, extracts the primary key, and sets it as the foreign key. + # [build_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated + # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. + # [create_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated + # with +attributes+, linked to this object through a foreign key, and that + # has already been saved (if it passed the validation). + # [create_association!(attributes = {})] + # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid + # if the record is invalid. + # + # === Example + # + # A Post class declares <tt>belongs_to :author</tt>, which will add: + # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>) + # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>) + # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>) + # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>) + # * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>) + # The declaration can also include an +options+ hash to specialize the behavior of the association. + # + # === Scopes + # + # You can pass a second argument +scope+ as a callable (i.e. proc or + # lambda) to retrieve a specific record or customize the generated query + # when you access the associated object. + # + # Scope examples: + # belongs_to :firm, -> { where(id: 2) } + # belongs_to :user, -> { joins(:friends) } + # belongs_to :level, ->(level) { where("game_level > ?", level.current) } + # + # === Options + # + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred + # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but + # if the real class name is Person, you'll have to specify it with this option. + # [:foreign_key] + # Specify the foreign key used for the association. By default this is guessed to be the name + # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt> + # association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly, + # <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key + # of "favorite_person_id". + # [:foreign_type] + # Specify the column used to store the associated object's type, if this is a polymorphic + # association. By default this is guessed to be the name of the association with a "_type" + # suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt> + # association will use "taggable_type" as the default <tt>:foreign_type</tt>. + # [:primary_key] + # Specify the method that returns the primary key of associated object used for the association. + # By default this is id. + # [:dependent] + # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to + # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. + # This option should not be specified when #belongs_to is used in conjunction with + # a #has_many relationship on another class because of the potential to leave + # orphaned records behind. + # [:counter_cache] + # Caches the number of belonging objects on the associate class through the use of CounterCache::ClassMethods#increment_counter + # and CounterCache::ClassMethods#decrement_counter. The counter cache is incremented when an object of this + # class is created and decremented when it's destroyed. This requires that a column + # named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class) + # is used on the associate class (such as a Post class) - that is the migration for + # <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will + # return the count cached, see note below). You can also specify a custom counter + # cache column by providing a column name instead of a +true+/+false+ value to this + # option (e.g., <tt>counter_cache: :my_custom_counter</tt>.) + # Note: Specifying a counter cache will add it to that model's list of readonly attributes + # using +attr_readonly+. + # [:polymorphic] + # Specify this association is a polymorphic association by passing +true+. + # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute + # to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>). + # [:validate] + # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default. + # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. + # [:autosave] + # If true, always save the associated object or destroy it if marked for destruction, when + # saving the parent object. + # If false, never save or destroy the associated object. + # By default, only save the associated object if it's a new record. + # + # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for + # sets <tt>:autosave</tt> to <tt>true</tt>. + # [:touch] + # If true, the associated object will be touched (the updated_at/on attributes set to current time) + # when this record is either saved or destroyed. If you specify a symbol, that attribute + # will be updated with the current time in addition to the updated_at/on attribute. + # Please note that with touching no validation is performed and only the +after_touch+, + # +after_commit+ and +after_rollback+ callbacks are executed. + # [:inverse_of] + # Specifies the name of the #has_one or #has_many association on the associated + # object that is the inverse of this #belongs_to association. Does not work in + # combination with the <tt>:polymorphic</tt> options. + # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. + # [:optional] + # When set to +true+, the association will not have its presence validated. + # [:required] + # When set to +true+, the association will also have its presence validated. + # This will validate the association itself, not the id. You can use + # +:inverse_of+ to avoid an extra query during validation. + # NOTE: <tt>required</tt> is set to <tt>true</tt> by default and is deprecated. If + # you don't want to have association presence validated, use <tt>optional: true</tt>. + # + # Option examples: + # belongs_to :firm, foreign_key: "client_of" + # belongs_to :person, primary_key: "name", foreign_key: "person_name" + # belongs_to :author, class_name: "Person", foreign_key: "author_id" + # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count }, + # class_name: "Coupon", foreign_key: "coupon_id" + # belongs_to :attachable, polymorphic: true + # belongs_to :project, -> { readonly } + # belongs_to :post, counter_cache: true + # belongs_to :comment, touch: true + # belongs_to :company, touch: :employees_last_updated_at + # belongs_to :user, optional: true + def belongs_to(name, scope = nil, options = {}) + reflection = Builder::BelongsTo.build(self, name, scope, options) + Reflection.add_reflection self, name, reflection + end - join_model = builder.through_model + # Specifies a many-to-many relationship with another class. This associates two classes via an + # intermediate join table. Unless the join table is explicitly specified as an option, it is + # guessed using the lexical order of the class names. So a join between Developer and Project + # will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically. + # Note that this precedence is calculated using the <tt><</tt> operator for String. This + # means that if the strings are of different lengths, and the strings are equal when compared + # up to the shortest length, then the longer string is considered of higher + # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" + # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", + # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the + # custom <tt>:join_table</tt> option if you need to. + # If your tables share a common prefix, it will only appear once at the beginning. For example, + # the tables "catalog_categories" and "catalog_products" generate a join table name of "catalog_categories_products". + # + # The join table should not have a primary key or a model associated with it. You must manually generate the + # join table with a migration such as this: + # + # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[5.0] + # def change + # create_join_table :developers, :projects + # end + # end + # + # It's also a good idea to add indexes to each of those columns to speed up the joins process. + # However, in MySQL it is advised to add a compound index for both of the columns as MySQL only + # uses one index per table during the lookup. + # + # Adds the following methods for retrieval and query: + # + # +collection+ is a placeholder for the symbol passed as the +name+ argument, so + # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>. + # + # [collection(force_reload = false)] + # Returns an array of all the associated objects. + # An empty array is returned if none are found. + # [collection<<(object, ...)] + # Adds one or more objects to the collection by creating associations in the join table + # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method). + # Note that this operation instantly fires update SQL without waiting for the save or update call on the + # parent object, unless the parent object is a new record. + # [collection.delete(object, ...)] + # Removes one or more objects from the collection by removing their associations from the join table. + # This does not destroy the objects. + # [collection.destroy(object, ...)] + # Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option. + # This does not destroy the objects. + # [collection=objects] + # Replaces the collection's content by deleting and adding objects as appropriate. + # [collection_singular_ids] + # Returns an array of the associated objects' ids. + # [collection_singular_ids=ids] + # Replace the collection by the objects identified by the primary keys in +ids+. + # [collection.clear] + # Removes every object from the collection. This does not destroy the objects. + # [collection.empty?] + # Returns +true+ if there are no associated objects. + # [collection.size] + # Returns the number of associated objects. + # [collection.find(id)] + # Finds an associated object responding to the +id+ and that + # meets the condition that it has to be associated with this object. + # Uses the same rules as ActiveRecord::FinderMethods#find. + # [collection.exists?(...)] + # Checks whether an associated object with the given conditions exists. + # Uses the same rules as ActiveRecord::FinderMethods#exists?. + # [collection.build(attributes = {})] + # Returns a new object of the collection type that has been instantiated + # with +attributes+ and linked to this object through the join table, but has not yet been saved. + # [collection.create(attributes = {})] + # Returns a new object of the collection type that has been instantiated + # with +attributes+, linked to this object through the join table, and that has already been + # saved (if it passed the validation). + # + # === Example + # + # A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add: + # * <tt>Developer#projects</tt> + # * <tt>Developer#projects<<</tt> + # * <tt>Developer#projects.delete</tt> + # * <tt>Developer#projects.destroy</tt> + # * <tt>Developer#projects=</tt> + # * <tt>Developer#project_ids</tt> + # * <tt>Developer#project_ids=</tt> + # * <tt>Developer#projects.clear</tt> + # * <tt>Developer#projects.empty?</tt> + # * <tt>Developer#projects.size</tt> + # * <tt>Developer#projects.find(id)</tt> + # * <tt>Developer#projects.exists?(...)</tt> + # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>) + # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>) + # The declaration may include an +options+ hash to specialize the behavior of the association. + # + # === Scopes + # + # You can pass a second argument +scope+ as a callable (i.e. proc or + # lambda) to retrieve a specific set of records or customize the generated + # query when you access the associated collection. + # + # Scope examples: + # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) } + # has_and_belongs_to_many :categories, ->(category) { + # where("default_category = ?", category.name) + # } + # + # === Extensions + # + # The +extension+ argument allows you to pass a block into a + # has_and_belongs_to_many association. This is useful for adding new + # finders, creators and other factory-type methods to be used as part of + # the association. + # + # Extension examples: + # has_and_belongs_to_many :contractors do + # def find_or_create_by_name(name) + # first_name, last_name = name.split(" ", 2) + # find_or_create_by(first_name: first_name, last_name: last_name) + # end + # end + # + # === Options + # + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred + # from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the + # Project class, but if the real class name is SuperProject, you'll have to specify it with this option. + # [:join_table] + # Specify the name of the join table if the default based on lexical order isn't what you want. + # <b>WARNING:</b> If you're overwriting the table name of either class, the +table_name+ method + # MUST be declared underneath any #has_and_belongs_to_many declaration in order to work. + # [:foreign_key] + # Specify the foreign key used for the association. By default this is guessed to be the name + # of this class in lower-case and "_id" suffixed. So a Person class that makes + # a #has_and_belongs_to_many association to Project will use "person_id" as the + # default <tt>:foreign_key</tt>. + # [:association_foreign_key] + # Specify the foreign key used for the association on the receiving side of the association. + # By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed. + # So if a Person class makes a #has_and_belongs_to_many association to Project, + # the association will use "project_id" as the default <tt>:association_foreign_key</tt>. + # [:validate] + # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default. + # If you want to ensure associated objects are revalidated on every update, use +validates_associated+. + # [:autosave] + # If true, always save the associated objects or destroy them if marked for destruction, when + # saving the parent object. + # If false, never save or destroy the associated objects. + # By default, only save associated objects that are new records. + # + # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets + # <tt>:autosave</tt> to <tt>true</tt>. + # + # Option examples: + # has_and_belongs_to_many :projects + # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) } + # has_and_belongs_to_many :nations, class_name: "Country" + # has_and_belongs_to_many :categories, join_table: "prods_cats" + # has_and_belongs_to_many :categories, -> { readonly } + def has_and_belongs_to_many(name, scope = nil, **options, &extension) + habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self) - const_set join_model.name, join_model - private_constant join_model.name + builder = Builder::HasAndBelongsToMany.new name, self, options - middle_reflection = builder.middle_reflection join_model + join_model = builder.through_model - Builder::HasMany.define_callbacks self, middle_reflection - Reflection.add_reflection self, middle_reflection.name, middle_reflection - middle_reflection.parent_reflection = habtm_reflection + const_set join_model.name, join_model + private_constant join_model.name - include Module.new { - class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def destroy_associations - association(:#{middle_reflection.name}).delete_all(:delete_all) - association(:#{name}).reset - super - end - RUBY - } + middle_reflection = builder.middle_reflection join_model - hm_options = {} - hm_options[:through] = middle_reflection.name - hm_options[:source] = join_model.right_reflection.name + Builder::HasMany.define_callbacks self, middle_reflection + Reflection.add_reflection self, middle_reflection.name, middle_reflection + middle_reflection.parent_reflection = habtm_reflection - [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k| - hm_options[k] = options[k] if options.key? k - end + include Module.new { + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def destroy_associations + association(:#{middle_reflection.name}).delete_all(:delete_all) + association(:#{name}).reset + super + end + RUBY + } + + hm_options = {} + hm_options[:through] = middle_reflection.name + hm_options[:source] = join_model.right_reflection.name + + [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k| + hm_options[k] = options[k] if options.key? k + end - has_many name, scope, hm_options, &extension - self._reflections[name.to_s].parent_reflection = habtm_reflection + has_many name, scope, hm_options, &extension + self._reflections[name.to_s].parent_reflection = habtm_reflection + end end - end end end diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index 021bc32237..3963008a76 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/conversions' +require "active_support/core_ext/string/conversions" module ActiveRecord module Associations diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 62e867a353..f506614591 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/array/wrap' +require "active_support/core_ext/array/wrap" module ActiveRecord module Associations @@ -19,7 +19,7 @@ module ActiveRecord attr_reader :owner, :target, :reflection attr_accessor :inversed - delegate :options, :to => :reflection + delegate :options, to: :reflection def initialize(owner, reflection) reflection.check_validity! @@ -173,6 +173,14 @@ module ActiveRecord set_inverse_instance(record) end + def create(attributes = {}, &block) + _create_record(attributes, &block) + end + + def create!(attributes = {}, &block) + _create_record(attributes, true, &block) + end + private def find_target? diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index 15844de0bc..12f8c1ccd4 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -51,115 +51,115 @@ module ActiveRecord protected - attr_reader :value_transformation + attr_reader :value_transformation private - def join(table, constraint) - table.create_join(table, table.create_on(constraint), join_type) - end + def join(table, constraint) + table.create_join(table, table.create_on(constraint), join_type) + end + + def last_chain_scope(scope, table, reflection, owner, association_klass) + join_keys = reflection.join_keys(association_klass) + key = join_keys.key + foreign_key = join_keys.foreign_key - def last_chain_scope(scope, table, reflection, owner, association_klass) - join_keys = reflection.join_keys(association_klass) - key = join_keys.key - foreign_key = join_keys.foreign_key + value = transform_value(owner[foreign_key]) + scope = scope.where(table.name => { key => value }) - value = transform_value(owner[foreign_key]) - scope = scope.where(table.name => { key => value }) + if reflection.type + polymorphic_type = transform_value(owner.class.base_class.name) + scope = scope.where(table.name => { reflection.type => polymorphic_type }) + end - if reflection.type - polymorphic_type = transform_value(owner.class.base_class.name) - scope = scope.where(table.name => { reflection.type => polymorphic_type }) + scope end - scope - end + def transform_value(value) + value_transformation.call(value) + end - def transform_value(value) - value_transformation.call(value) - end + def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection) + join_keys = reflection.join_keys(association_klass) + key = join_keys.key + foreign_key = join_keys.foreign_key - def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection) - join_keys = reflection.join_keys(association_klass) - key = join_keys.key - foreign_key = join_keys.foreign_key + constraint = table[key].eq(foreign_table[foreign_key]) - constraint = table[key].eq(foreign_table[foreign_key]) + if reflection.type + value = transform_value(next_reflection.klass.base_class.name) + scope = scope.where(table.name => { reflection.type => value }) + end - if reflection.type - value = transform_value(next_reflection.klass.base_class.name) - scope = scope.where(table.name => { reflection.type => value }) + scope = scope.joins(join(foreign_table, constraint)) end - scope = scope.joins(join(foreign_table, constraint)) - end + class ReflectionProxy < SimpleDelegator # :nodoc: + attr_accessor :next + attr_reader :alias_name - class ReflectionProxy < SimpleDelegator # :nodoc: - attr_accessor :next - attr_reader :alias_name + def initialize(reflection, alias_name) + super(reflection) + @alias_name = alias_name + end - def initialize(reflection, alias_name) - super(reflection) - @alias_name = alias_name + def all_includes; nil; end end - def all_includes; nil; end - end - - def get_chain(reflection, association, tracker) - name = reflection.name - runtime_reflection = Reflection::RuntimeReflection.new(reflection, association) - previous_reflection = runtime_reflection - reflection.chain.drop(1).each do |refl| - alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name)) - proxy = ReflectionProxy.new(refl, alias_name) - previous_reflection.next = proxy - previous_reflection = proxy + def get_chain(reflection, association, tracker) + name = reflection.name + runtime_reflection = Reflection::RuntimeReflection.new(reflection, association) + previous_reflection = runtime_reflection + reflection.chain.drop(1).each do |refl| + alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name)) + proxy = ReflectionProxy.new(refl, alias_name) + previous_reflection.next = proxy + previous_reflection = proxy + end + [runtime_reflection, previous_reflection] end - [runtime_reflection, previous_reflection] - end - def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail) - owner_reflection = chain_tail - table = owner_reflection.alias_name - scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass) + def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail) + owner_reflection = chain_tail + table = owner_reflection.alias_name + scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass) - reflection = chain_head - while reflection - table = reflection.alias_name + reflection = chain_head + while reflection + table = reflection.alias_name - unless reflection == chain_tail - next_reflection = reflection.next - foreign_table = next_reflection.alias_name - scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection) - end + unless reflection == chain_tail + next_reflection = reflection.next + foreign_table = next_reflection.alias_name + scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection) + end - # Exclude the scope of the association itself, because that - # was already merged in the #scope method. - reflection.constraints.each do |scope_chain_item| - item = eval_scope(reflection.klass, scope_chain_item, owner) + # Exclude the scope of the association itself, because that + # was already merged in the #scope method. + reflection.constraints.each do |scope_chain_item| + item = eval_scope(reflection.klass, scope_chain_item, owner) - if scope_chain_item == refl.scope - scope.merge! item.except(:where, :includes) - end + if scope_chain_item == refl.scope + scope.merge! item.except(:where, :includes) + end + + reflection.all_includes do + scope.includes! item.includes_values + end - reflection.all_includes do - scope.includes! item.includes_values + scope.unscope!(*item.unscope_values) + scope.where_clause += item.where_clause + scope.order_values |= item.order_values end - scope.unscope!(*item.unscope_values) - scope.where_clause += item.where_clause - scope.order_values |= item.order_values + reflection = reflection.next end - reflection = reflection.next + scope end - scope - end - - def eval_scope(klass, scope, owner) - klass.unscoped.instance_exec(owner, &scope) - end + def eval_scope(klass, scope, owner) + klass.unscoped.instance_exec(owner, &scope) + end end end end diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 24997370b2..64b2311911 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -2,7 +2,6 @@ module ActiveRecord # = Active Record Belongs To Association module Associations class BelongsToAssociation < SingularAssociation #:nodoc: - def handle_dependency target.send(options[:dependent]) if load_target end diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb index f25bd7ca9f..edeb6491bd 100644 --- a/activerecord/lib/active_record/associations/builder/collection_association.rb +++ b/activerecord/lib/active_record/associations/builder/collection_association.rb @@ -1,10 +1,9 @@ # This class is inherited by the has_many and has_many_and_belongs_to_many association classes -require 'active_record/associations' +require "active_record/associations" module ActiveRecord::Associations::Builder # :nodoc: class CollectionAssociation < Association #:nodoc: - CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove] def self.valid_options(options) diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index 5fbd79d118..047292b2bd 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -16,9 +16,9 @@ module ActiveRecord::Associations::Builder # :nodoc: private - def klass - @lhs_class.send(:compute_type, @rhs_class_name) - end + def klass + @lhs_class.send(:compute_type, @rhs_class_name) + end end def self.build(lhs_class, name, options) @@ -76,8 +76,10 @@ module ActiveRecord::Associations::Builder # :nodoc: left_model.retrieve_connection end - def self.primary_key - false + private + + def self.suppress_composite_primary_key(pk) + pk unless pk.is_a?(Array) end } @@ -92,7 +94,7 @@ module ActiveRecord::Associations::Builder # :nodoc: def middle_reflection(join_model) middle_name = [lhs_model.name.downcase.pluralize, - association_name].join('_'.freeze).gsub('::'.freeze, '_'.freeze).to_sym + association_name].join("_".freeze).gsub("::".freeze, "_".freeze).to_sym middle_options = middle_options join_model HasMany.create_reflection(lhs_model, @@ -103,29 +105,29 @@ module ActiveRecord::Associations::Builder # :nodoc: private - def middle_options(join_model) - middle_options = {} - middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}" - middle_options[:source] = join_model.left_reflection.name - if options.key? :foreign_key - middle_options[:foreign_key] = options[:foreign_key] + def middle_options(join_model) + middle_options = {} + middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}" + middle_options[:source] = join_model.left_reflection.name + if options.key? :foreign_key + middle_options[:foreign_key] = options[:foreign_key] + end + middle_options end - middle_options - end - def belongs_to_options(options) - rhs_options = {} + def belongs_to_options(options) + rhs_options = {} - if options.key? :class_name - rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key - rhs_options[:class_name] = options[:class_name] - end + if options.key? :class_name + rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key + rhs_options[:class_name] = options[:class_name] + end - if options.key? :association_foreign_key - rhs_options[:foreign_key] = options[:association_foreign_key] - end + if options.key? :association_foreign_key + rhs_options[:foreign_key] = options[:association_foreign_key] + end - rhs_options - end + rhs_options + end end end diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 0eaa0a4f36..278c95e27b 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -24,7 +24,6 @@ module ActiveRecord # If you need to work on all current children, new and existing records, # +load_target+ and the +loaded+ flag are your friends. class CollectionAssociation < Association #:nodoc: - # Implements the reader method, e.g. foo.items for Foo.has_many :items def reader(force_reload = false) if force_reload @@ -83,14 +82,6 @@ module ActiveRecord @target = [] end - def select(*fields) - if block_given? - load_target.select.each { |e| yield e } - else - scope.select(*fields) - end - end - def find(*args) if block_given? load_target.find(*args) { |*block_args| yield(*block_args) } @@ -112,52 +103,6 @@ module ActiveRecord end end - def first(*args) - first_nth_or_last(:first, *args) - end - - def second(*args) - first_nth_or_last(:second, *args) - end - - def third(*args) - first_nth_or_last(:third, *args) - end - - def fourth(*args) - first_nth_or_last(:fourth, *args) - end - - def fifth(*args) - first_nth_or_last(:fifth, *args) - end - - def forty_two(*args) - first_nth_or_last(:forty_two, *args) - end - - def third_to_last(*args) - first_nth_or_last(:third_to_last, *args) - end - - def second_to_last(*args) - first_nth_or_last(:second_to_last, *args) - end - - def last(*args) - first_nth_or_last(:last, *args) - end - - def take(n = nil) - if loaded? - n ? target.take(n) : target.first - else - scope.take(n).tap do |record| - set_inverse_instance record if record.is_a? ActiveRecord::Base - end - end - end - def build(attributes = {}, &block) if attributes.is_a?(Array) attributes.collect { |attr| build(attr, &block) } @@ -168,14 +113,6 @@ module ActiveRecord end end - def create(attributes = {}, &block) - _create_record(attributes, &block) - end - - def create!(attributes = {}, &block) - _create_record(attributes, true, &block) - end - # Add +records+ to this association. Returns +self+ so method calls may # be chained. Since << flattens its argument list and inserts each record, # +push+ and +concat+ behave identically. @@ -223,12 +160,12 @@ module ActiveRecord end dependent = if dependent - dependent - elsif options[:dependent] == :destroy - :delete_all - else - options[:dependent] - end + dependent + elsif options[:dependent] == :destroy + :delete_all + else + options[:dependent] + end delete_or_nullify_all_records(dependent).tap do reset @@ -246,31 +183,6 @@ module ActiveRecord end end - # Returns the number of records. If no arguments are given, it counts all - # columns using SQL. If one argument is given, it counts only the passed - # column using SQL. If a block is given, it counts the number of records - # yielding a true value. - def count(column_name = nil) - return super if block_given? - relation = scope - if association_scope.distinct_value - # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL. - column_name ||= reflection.klass.primary_key - relation = relation.distinct - end - - value = relation.count(column_name) - - limit = options[:limit] - offset = options[:offset] - - if limit || offset - [ [value - offset.to_i, 0].max, limit.to_i ].min - else - value - end - end - # Removes +records+ from this association calling +before_remove+ and # +after_remove+ callbacks. # @@ -315,9 +227,9 @@ module ActiveRecord else target.size end - elsif !loaded? && !association_scope.group_values.empty? + elsif !association_scope.group_values.empty? load_target.size - elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array) + elsif !association_scope.distinct_value && target.is_a?(Array) unsaved_records = target.select(&:new_record?) unsaved_records.size + count_records else @@ -325,15 +237,6 @@ module ActiveRecord end end - # Returns the size of the collection calling +size+ on the target. - # - # If the collection has been already loaded +length+ and +size+ are - # equivalent. If not and you are going to need the records anyway this - # method will take one less query. Otherwise +size+ is more efficient. - def length - load_target.size - end - # Returns true if the collection is empty. # # If the collection has been loaded @@ -350,35 +253,12 @@ module ActiveRecord end end - # Returns true if the collections is not empty. - # If block given, loads all records and checks for one or more matches. - # Otherwise, equivalent to +!collection.empty?+. - def any? - if block_given? - load_target.any? { |*block_args| yield(*block_args) } - else - !empty? - end - end - - # Returns true if the collection has more than 1 record. - # If block given, loads all records and checks for two or more matches. - # Otherwise, equivalent to +collection.size > 1+. - def many? - if block_given? - load_target.many? { |*block_args| yield(*block_args) } - else - size > 1 - end - end - def distinct seen = {} load_target.find_all do |record| seen[record.id] = true unless seen.key?(record.id) end end - alias uniq distinct # Replace this collection with +other_array+. This will perform a diff # and delete/add only records that have changed. @@ -429,15 +309,12 @@ module ActiveRecord def replace_on_target(record, index, skip_callbacks) callback(:before_add, record) unless skip_callbacks - was_loaded = loaded? yield(record) if block_given? - unless !was_loaded && loaded? - if index - @target[index] = record - else - @target << record - end + if index + @target[index] = record + else + append_record(record) end callback(:after_add, record) unless skip_callbacks @@ -456,26 +333,29 @@ module ActiveRecord owner.new_record? && !foreign_key_present? end - private - def get_records - return scope.to_a if skip_statement_cache? - - conn = klass.connection - sc = reflection.association_scope_cache(conn, owner) do - StatementCache.create(conn) { |params| - as = AssociationScope.create { params.bind } - target_scope.merge as.scope(self, conn) - } - end - - binds = AssociationScope.get_bind_values(owner, reflection.chain) - sc.execute binds, klass, klass.connection + def find_from_target? + loaded? || + owner.new_record? || + target.any? { |record| record.new_record? || record.changed? } end + private + def find_target - records = get_records - records.each { |record| set_inverse_instance(record) } - records + return scope.to_a if skip_statement_cache? + + conn = klass.connection + sc = reflection.association_scope_cache(conn, owner) do + StatementCache.create(conn) { |params| + as = AssociationScope.create { params.bind } + target_scope.merge as.scope(self, conn) + } + end + + binds = AssociationScope.get_bind_values(owner, reflection.chain) + sc.execute(binds, klass, conn) do |record| + set_inverse_instance(record) + end end # We have some records loaded from the database (persisted) and some that are @@ -605,25 +485,6 @@ module ActiveRecord owner.class.send(full_callback_name) end - # Should we deal with assoc.first or assoc.last by issuing an independent query to - # the database, or by getting the target, and then taking the first/last item from that? - # - # If the args is just a non-empty options hash, go to the database. - # - # Otherwise, go to the database only if none of the following are true: - # * target already loaded - # * owner is new record - # * target contains new or changed record(s) - def fetch_first_nth_or_last_using_find?(args) - if args.first.is_a?(Hash) - true - else - !(loaded? || - owner.new_record? || - target.any? { |record| record.new_record? || record.changed? }) - end - end - def include_in_memory?(record) if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) assoc = owner.association(reflection.through_reflection.name) @@ -651,14 +512,8 @@ module ActiveRecord end end - # Fetches the first/last using SQL if possible, otherwise from the target array. - def first_nth_or_last(type, *args) - args.shift if args.first.is_a?(Hash) && args.first.empty? - - collection = fetch_first_nth_or_last_using_find?(args) ? scope : load_target - collection.send(type, *args).tap do |record| - set_inverse_instance record if record.is_a? ActiveRecord::Base - end + def append_record(record) + @target << record unless @target.include?(record) end end end diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 5d1e7ffb73..0800639c24 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -28,8 +28,7 @@ module ActiveRecord # is computed directly through SQL and does not trigger by itself the # instantiation of the actual post records. class CollectionProxy < Relation - delegate(*(ActiveRecord::Calculations.public_instance_methods - [:count]), to: :scope) - delegate :find_nth, to: :scope + delegate :exists?, :update_all, :arel, to: :scope def initialize(klass, association) #:nodoc: @association = association @@ -54,6 +53,12 @@ module ActiveRecord @association.loaded? end + ## + # :method: select + # + # :call-seq: + # select(*fields, &block) + # # Works in two ways. # # *First:* Specify a subset of fields to be selected from the result set. @@ -101,15 +106,6 @@ module ActiveRecord # # #<Pet id: 2, name: "Spook", person_id: 1>, # # #<Pet id: 3, name: "Choo-Choo", person_id: 1> # # ] - # - # person.pets.select(:name) { |pet| pet.name =~ /oo/ } - # # => [ - # # #<Pet id: 2, name: "Spook">, - # # #<Pet id: 3, name: "Choo-Choo"> - # # ] - def select(*fields, &block) - @association.select(*fields, &block) - end # Finds an object in the collection responding to the +id+. Uses the same # rules as ActiveRecord::Base.find. Returns ActiveRecord::RecordNotFound @@ -141,6 +137,12 @@ module ActiveRecord @association.find(*args, &block) end + ## + # :method: first + # + # :call-seq: + # first(limit = nil) + # # Returns the first record, or the first +n+ records, from the collection. # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. @@ -167,45 +169,63 @@ module ActiveRecord # another_person_without.pets # => [] # another_person_without.pets.first # => nil # another_person_without.pets.first(3) # => [] - def first(*args) - @association.first(*args) - end + ## + # :method: second + # + # :call-seq: + # second() + # # Same as #first except returns only the second record. - def second(*args) - @association.second(*args) - end + ## + # :method: third + # + # :call-seq: + # third() + # # Same as #first except returns only the third record. - def third(*args) - @association.third(*args) - end + ## + # :method: fourth + # + # :call-seq: + # fourth() + # # Same as #first except returns only the fourth record. - def fourth(*args) - @association.fourth(*args) - end + ## + # :method: fifth + # + # :call-seq: + # fifth() + # # Same as #first except returns only the fifth record. - def fifth(*args) - @association.fifth(*args) - end + ## + # :method: forty_two + # + # :call-seq: + # forty_two() + # # Same as #first except returns only the forty second record. # Also known as accessing "the reddit". - def forty_two(*args) - @association.forty_two(*args) - end + ## + # :method: third_to_last + # + # :call-seq: + # third_to_last() + # # Same as #first except returns only the third-to-last record. - def third_to_last(*args) - @association.third_to_last(*args) - end + ## + # :method: second_to_last + # + # :call-seq: + # second_to_last() + # # Same as #first except returns only the second-to-last record. - def second_to_last(*args) - @association.second_to_last(*args) - end # Returns the last record, or the last +n+ records, from the collection. # If the collection is empty, the first form returns +nil+, and the second @@ -233,8 +253,9 @@ module ActiveRecord # another_person_without.pets # => [] # another_person_without.pets.last # => nil # another_person_without.pets.last(3) # => [] - def last(*args) - @association.last(*args) + def last(limit = nil) + load_target if find_from_target? + super end # Gives a record (or N records if a parameter is supplied) from the collection @@ -262,8 +283,9 @@ module ActiveRecord # another_person_without.pets # => [] # another_person_without.pets.take # => nil # another_person_without.pets.take(2) # => [] - def take(n = nil) - @association.take(n) + def take(limit = nil) + load_target if find_from_target? + super end # Returns a new object of the collection type that has been instantiated @@ -715,6 +737,20 @@ module ActiveRecord end alias uniq distinct + def calculate(operation, column_name) + null_scope? ? scope.calculate(operation, column_name) : super + end + + def pluck(*column_names) + null_scope? ? scope.pluck(*column_names) : super + end + + ## + # :method: count + # + # :call-seq: + # count(column_name = nil, &block) + # # Count all records. # # class Person < ActiveRecord::Base @@ -734,9 +770,6 @@ module ActiveRecord # perform the count using Ruby. # # person.pets.count { |pet| pet.name.include?('-') } # => 2 - def count(column_name = nil, &block) - @association.count(column_name, &block) - end # Returns the size of the collection. If the collection hasn't been loaded, # it executes a <tt>SELECT COUNT(*)</tt> query. Else it calls <tt>collection.size</tt>. @@ -766,6 +799,12 @@ module ActiveRecord @association.size end + ## + # :method: length + # + # :call-seq: + # length() + # # Returns the size of the collection calling +size+ on the target. # If the collection has been already loaded, +length+ and +size+ are # equivalent. If not and you are going to need the records anyway this @@ -786,14 +825,11 @@ module ActiveRecord # # #<Pet id: 2, name: "Spook", person_id: 1>, # # #<Pet id: 3, name: "Choo-Choo", person_id: 1> # # ] - def length - @association.length - end # Returns +true+ if the collection is empty. If the collection has been # loaded it is equivalent # to <tt>collection.size.zero?</tt>. If the collection has not been loaded, - # it is equivalent to <tt>collection.exists?</tt>. If the collection has + # it is equivalent to <tt>!collection.exists?</tt>. If the collection has # not already been loaded and you are going to fetch the records anyway it # is better to check <tt>collection.length.zero?</tt>. # @@ -812,6 +848,12 @@ module ActiveRecord @association.empty? end + ## + # :method: any? + # + # :call-seq: + # any?() + # # Returns +true+ if the collection is not empty. # # class Person < ActiveRecord::Base @@ -841,10 +883,13 @@ module ActiveRecord # pet.group == 'dogs' # end # # => true - def any?(&block) - @association.any?(&block) - end + ## + # :method: many? + # + # :call-seq: + # many?() + # # Returns true if the collection has more than one record. # Equivalent to <tt>collection.size > 1</tt>. # @@ -879,9 +924,6 @@ module ActiveRecord # pet.group == 'cats' # end # # => true - def many?(&block) - @association.many?(&block) - end # Returns +true+ if the given +record+ is present in the collection. # @@ -897,10 +939,6 @@ module ActiveRecord !!@association.include?(record) end - def arel #:nodoc: - scope.arel - end - def proxy_association @association end @@ -1074,6 +1112,32 @@ module ActiveRecord proxy_association.reset_scope self end + + protected + + def find_nth_with_limit(index, limit) + load_target if find_from_target? + super + end + + def find_nth_from_last(index) + load_target if find_from_target? + super + end + + private + + def null_scope? + @association.null_scope? + end + + def find_from_target? + @association.find_from_target? + end + + def exec_queries + load_target + end end end end diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index a9f6aaafef..d1d0cc4c49 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -27,14 +27,12 @@ module ActiveRecord throw(:abort) end + when :destroy + # No point in executing the counter update since we're going to destroy the parent anyway + load_target.each { |t| t.destroyed_by_association = reflection } + destroy_all else - if options[:dependent] == :destroy - # No point in executing the counter update since we're going to destroy the parent anyway - load_target.each { |t| t.destroyed_by_association = reflection } - destroy_all - else - delete_all - end + delete_all end end @@ -43,9 +41,9 @@ module ActiveRecord set_inverse_instance(record) if raise - record.save!(:validate => validate) + record.save!(validate: validate) else - record.save(:validate => validate) + record.save(validate: validate) end end @@ -82,7 +80,7 @@ module ActiveRecord # If there's nothing in the database and @target has no new records # we are certain the current target is an empty array. This is a # documented side-effect of the method that may avoid an extra SELECT. - @target ||= [] and loaded! if count == 0 + (@target ||= []) && loaded! if count == 0 [association_scope.limit_value, count].compact.min end diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 36fc381343..1f264d325a 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -39,9 +39,9 @@ module ActiveRecord ensure_not_nested if raise - record.save!(:validate => validate) + record.save!(validate: validate) else - return unless record.save(:validate => validate) + return unless record.save(validate: validate) end save_through_record(record) @@ -146,7 +146,7 @@ module ActiveRecord stmt.from scope.klass.arel_table stmt.wheres = arel.constraints - count = scope.klass.connection.delete(stmt, 'SQL', scope.bound_attributes) + count = scope.klass.connection.delete(stmt, "SQL", scope.bound_attributes) end when :nullify count = scope.update_all(source_reflection.foreign_key => nil) @@ -196,13 +196,17 @@ module ActiveRecord def find_target return [] unless target_reflection_has_associated_record? - get_records + super end # NOTE - not sure that we can actually cope with inverses here def invertible_for?(record) false end + + def append_record(record) + @target << record + end end end end diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 0fe9b2e81b..5ea9577301 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -32,7 +32,7 @@ module ActiveRecord raise_on_type_mismatch!(record) if record load_target - return self.target if !(target || record) + return target unless target || record assigning_another_record = target != record if assigning_another_record || record.changed? @@ -60,12 +60,12 @@ module ActiveRecord def delete(method = options[:dependent]) if load_target case method - when :delete - target.delete - when :destroy - target.destroy - when :nullify - target.update_columns(reflection.foreign_key => nil) if target.persisted? + when :delete + target.delete + when :destroy + target.destroy + when :nullify + target.update_columns(reflection.foreign_key => nil) if target.persisted? end end end @@ -82,18 +82,18 @@ module ActiveRecord def remove_target!(method) case method - when :delete - target.delete - when :destroy - target.destroy + when :delete + target.delete + when :destroy + target.destroy else - nullify_owner_attributes(target) + nullify_owner_attributes(target) - if target.persisted? && owner.persisted? && !target.save - set_owner_attributes(target) - raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " + - "The record failed to save after its foreign key was set to nil." - end + if target.persisted? && owner.persisted? && !target.save + set_owner_attributes(target) + raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " + + "The record failed to save after its foreign key was set to nil." + end end end diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb index 08e0ec691f..604904abcc 100644 --- a/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -15,7 +15,7 @@ module ActiveRecord ensure_not_nested through_proxy = owner.association(through_reflection.name) - through_record = through_proxy.send(:load_target) + through_record = through_proxy.load_target if through_record && !record through_record.destroy diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index 491152bbcb..c26c469c1e 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -1,8 +1,8 @@ module ActiveRecord module Associations class JoinDependency # :nodoc: - autoload :JoinBase, 'active_record/associations/join_dependency/join_base' - autoload :JoinAssociation, 'active_record/associations/join_dependency/join_association' + autoload :JoinBase, "active_record/associations/join_dependency/join_base" + autoload :JoinAssociation, "active_record/associations/join_dependency/join_association" class Aliases # :nodoc: def initialize(tables) @@ -154,7 +154,7 @@ module ActiveRecord class_name: join_root.base_klass.name } - message_bus.instrument('instantiation.active_record', payload) do + message_bus.instrument("instantiation.active_record", payload) do result_set.each { |row_hash| parent_key = primary_key ? row_hash[primary_key] : row_hash parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases) @@ -167,134 +167,140 @@ module ActiveRecord private - def make_constraints(parent, child, tables, join_type) - chain = child.reflection.chain - foreign_table = parent.table - foreign_klass = parent.base_klass - child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, child.reflection.scope_chain, chain) - end + def make_constraints(parent, child, tables, join_type) + chain = child.reflection.chain + foreign_table = parent.table + foreign_klass = parent.base_klass + child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, child.reflection.scope_chain, chain) + end - def make_outer_joins(parent, child) - tables = table_aliases_for(parent, child) - join_type = Arel::Nodes::OuterJoin - info = make_constraints parent, child, tables, join_type + def make_outer_joins(parent, child) + tables = table_aliases_for(parent, child) + join_type = Arel::Nodes::OuterJoin + info = make_constraints parent, child, tables, join_type - [info] + child.children.flat_map { |c| make_outer_joins(child, c) } - end + [info] + child.children.flat_map { |c| make_outer_joins(child, c) } + end - def make_left_outer_joins(parent, child) - tables = child.tables - join_type = Arel::Nodes::OuterJoin - info = make_constraints parent, child, tables, join_type + def make_left_outer_joins(parent, child) + tables = child.tables + join_type = Arel::Nodes::OuterJoin + info = make_constraints parent, child, tables, join_type - [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) } - end - - def make_inner_joins(parent, child) - tables = child.tables - join_type = Arel::Nodes::InnerJoin - info = make_constraints parent, child, tables, join_type + [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) } + end - [info] + child.children.flat_map { |c| make_inner_joins(child, c) } - end + def make_inner_joins(parent, child) + tables = child.tables + join_type = Arel::Nodes::InnerJoin + info = make_constraints parent, child, tables, join_type - def table_aliases_for(parent, node) - node.reflection.chain.map { |reflection| - alias_tracker.aliased_table_for( - reflection.table_name, - table_alias_for(reflection, parent, reflection != node.reflection) - ) - } - end + [info] + child.children.flat_map { |c| make_inner_joins(child, c) } + end - def construct_tables!(parent, node) - node.tables = table_aliases_for(parent, node) - node.children.each { |child| construct_tables! node, child } - end + def table_aliases_for(parent, node) + node.reflection.chain.map { |reflection| + alias_tracker.aliased_table_for( + reflection.table_name, + table_alias_for(reflection, parent, reflection != node.reflection) + ) + } + end - def table_alias_for(reflection, parent, join) - name = "#{reflection.plural_name}_#{parent.table_name}" - name << "_join" if join - name - end + def construct_tables!(parent, node) + node.tables = table_aliases_for(parent, node) + node.children.each { |child| construct_tables! node, child } + end - def walk(left, right) - intersection, missing = right.children.map { |node1| - [left.children.find { |node2| node1.match? node2 }, node1] - }.partition(&:first) + def table_alias_for(reflection, parent, join) + name = "#{reflection.plural_name}_#{parent.table_name}" + name << "_join" if join + name + end - ojs = missing.flat_map { |_,n| make_outer_joins left, n } - intersection.flat_map { |l,r| walk l, r }.concat ojs - end + def walk(left, right) + intersection, missing = right.children.map { |node1| + [left.children.find { |node2| node1.match? node2 }, node1] + }.partition(&:first) - def find_reflection(klass, name) - klass._reflect_on_association(name) or - raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?" - end + ojs = missing.flat_map { |_,n| make_outer_joins left, n } + intersection.flat_map { |l,r| walk l, r }.concat ojs + end - def build(associations, base_klass) - associations.map do |name, right| - reflection = find_reflection base_klass, name - reflection.check_validity! - reflection.check_eager_loadable! + def find_reflection(klass, name) + klass._reflect_on_association(name) || + raise(ConfigurationError, "Can't join '#{klass.name}' to association named '#{name}'; perhaps you misspelled it?") + end - if reflection.polymorphic? - next unless @eager_loading - raise EagerLoadPolymorphicError.new(reflection) - end + def build(associations, base_klass) + associations.map do |name, right| + reflection = find_reflection base_klass, name + reflection.check_validity! + reflection.check_eager_loadable! - JoinAssociation.new reflection, build(right, reflection.klass) - end.compact - end + if reflection.polymorphic? + next unless @eager_loading + raise EagerLoadPolymorphicError.new(reflection) + end - def construct(ar_parent, parent, row, rs, seen, model_cache, aliases) - return if ar_parent.nil? + JoinAssociation.new reflection, build(right, reflection.klass) + end.compact + end - parent.children.each do |node| - if node.reflection.collection? - other = ar_parent.association(node.reflection.name) - other.loaded! - elsif ar_parent.association_cached?(node.reflection.name) - model = ar_parent.association(node.reflection.name).target - construct(model, node, row, rs, seen, model_cache, aliases) - next + def construct(ar_parent, parent, row, rs, seen, model_cache, aliases) + return if ar_parent.nil? + + parent.children.each do |node| + if node.reflection.collection? + other = ar_parent.association(node.reflection.name) + other.loaded! + elsif ar_parent.association_cached?(node.reflection.name) + model = ar_parent.association(node.reflection.name).target + construct(model, node, row, rs, seen, model_cache, aliases) + next + end + + key = aliases.column_alias(node, node.primary_key) + id = row[key] + if id.nil? + nil_association = ar_parent.association(node.reflection.name) + nil_association.loaded! + next + end + + model = seen[ar_parent.object_id][node.base_klass][id] + + if model + construct(model, node, row, rs, seen, model_cache, aliases) + else + model = construct_model(ar_parent, node, row, model_cache, id, aliases) + + if node.reflection.scope_for(node.base_klass).readonly_value + model.readonly! + end + + seen[ar_parent.object_id][node.base_klass][id] = model + construct(model, node, row, rs, seen, model_cache, aliases) + end end + end - key = aliases.column_alias(node, node.primary_key) - id = row[key] - if id.nil? - nil_association = ar_parent.association(node.reflection.name) - nil_association.loaded! - next - end + def construct_model(record, node, row, model_cache, id, aliases) + other = record.association(node.reflection.name) - model = seen[ar_parent.object_id][node.base_klass][id] + model = model_cache[node][id] ||= + node.instantiate(row, aliases.column_aliases(node)) do |m| + other.set_inverse_instance(m) + end - if model - construct(model, node, row, rs, seen, model_cache, aliases) + if node.reflection.collection? + other.target.push(model) else - model = construct_model(ar_parent, node, row, model_cache, id, aliases) - model.readonly! - seen[ar_parent.object_id][node.base_klass][id] = model - construct(model, node, row, rs, seen, model_cache, aliases) + other.target = model end - end - end - def construct_model(record, node, row, model_cache, id, aliases) - model = model_cache[node][id] ||= node.instantiate(row, - aliases.column_aliases(node)) - other = record.association(node.reflection.name) - - if node.reflection.collection? - other.target.push(model) - else - other.target = model + model end - - other.set_inverse_instance(model) - model - end end end end diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index c5fbe0d1d1..a5705951f3 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -1,4 +1,4 @@ -require 'active_record/associations/join_dependency/join_part' +require "active_record/associations/join_dependency/join_part" module ActiveRecord module Associations @@ -56,7 +56,9 @@ module ActiveRecord klass_scope = if klass.current_scope - klass.current_scope.clone + klass.current_scope.clone.tap { |scope| + scope.joins_values = [] + } else relation = ActiveRecord::Relation.create( klass, diff --git a/activerecord/lib/active_record/associations/join_dependency/join_base.rb b/activerecord/lib/active_record/associations/join_dependency/join_base.rb index 3a26c25737..fca20514d1 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_base.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_base.rb @@ -1,4 +1,4 @@ -require 'active_record/associations/join_dependency/join_part' +require "active_record/associations/join_dependency/join_part" module ActiveRecord module Associations diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb index 9c6573f913..61cec5403a 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb @@ -15,7 +15,7 @@ module ActiveRecord # association. attr_reader :base_klass, :children - delegate :table_name, :column_names, :primary_key, :to => :base_klass + delegate :table_name, :column_names, :primary_key, to: :base_klass def initialize(base_klass, children) @base_klass = base_klass @@ -62,8 +62,8 @@ module ActiveRecord hash end - def instantiate(row, aliases) - base_klass.instantiate(extract_record(row, aliases)) + def instantiate(row, aliases, &block) + base_klass.instantiate(extract_record(row, aliases), &block) end end end diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index e64af84e1a..9f77f38b35 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -42,16 +42,16 @@ module ActiveRecord extend ActiveSupport::Autoload eager_autoload do - autoload :Association, 'active_record/associations/preloader/association' - autoload :SingularAssociation, 'active_record/associations/preloader/singular_association' - autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association' - autoload :ThroughAssociation, 'active_record/associations/preloader/through_association' - - autoload :HasMany, 'active_record/associations/preloader/has_many' - autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through' - autoload :HasOne, 'active_record/associations/preloader/has_one' - autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through' - autoload :BelongsTo, 'active_record/associations/preloader/belongs_to' + autoload :Association, "active_record/associations/preloader/association" + autoload :SingularAssociation, "active_record/associations/preloader/singular_association" + autoload :CollectionAssociation, "active_record/associations/preloader/collection_association" + autoload :ThroughAssociation, "active_record/associations/preloader/through_association" + + autoload :HasMany, "active_record/associations/preloader/has_many" + autoload :HasManyThrough, "active_record/associations/preloader/has_many_through" + autoload :HasOne, "active_record/associations/preloader/has_one" + autoload :HasOneThrough, "active_record/associations/preloader/has_one_through" + autoload :BelongsTo, "active_record/associations/preloader/belongs_to" end NULL_RELATION = Struct.new(:values, :where_clause, :joins_values).new({}, Relation::WhereClause.empty, []) @@ -106,108 +106,108 @@ module ActiveRecord private - # Loads all the given data into +records+ for the +association+. - def preloaders_on(association, records, scope) - case association - when Hash - preloaders_for_hash(association, records, scope) - when Symbol - preloaders_for_one(association, records, scope) - when String - preloaders_for_one(association.to_sym, records, scope) - else - raise ArgumentError, "#{association.inspect} was not recognized for preload" + # Loads all the given data into +records+ for the +association+. + def preloaders_on(association, records, scope) + case association + when Hash + preloaders_for_hash(association, records, scope) + when Symbol + preloaders_for_one(association, records, scope) + when String + preloaders_for_one(association.to_sym, records, scope) + else + raise ArgumentError, "#{association.inspect} was not recognized for preload" + end end - end - def preloaders_for_hash(association, records, scope) - association.flat_map { |parent, child| - loaders = preloaders_for_one parent, records, scope + def preloaders_for_hash(association, records, scope) + association.flat_map { |parent, child| + loaders = preloaders_for_one parent, records, scope - recs = loaders.flat_map(&:preloaded_records).uniq - loaders.concat Array.wrap(child).flat_map { |assoc| - preloaders_on assoc, recs, scope + recs = loaders.flat_map(&:preloaded_records).uniq + loaders.concat Array.wrap(child).flat_map { |assoc| + preloaders_on assoc, recs, scope + } + loaders } - loaders - } - end + end - # Loads all the given data into +records+ for a singular +association+. - # - # Functions by instantiating a preloader class such as Preloader::HasManyThrough and - # call the +run+ method for each passed in class in the +records+ argument. - # - # Not all records have the same class, so group then preload group on the reflection - # itself so that if various subclass share the same association then we do not split - # them unnecessarily - # - # Additionally, polymorphic belongs_to associations can have multiple associated - # classes, depending on the polymorphic_type field. So we group by the classes as - # well. - def preloaders_for_one(association, records, scope) - grouped_records(association, records).flat_map do |reflection, klasses| - klasses.map do |rhs_klass, rs| - loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope) - loader.run self - loader + # Loads all the given data into +records+ for a singular +association+. + # + # Functions by instantiating a preloader class such as Preloader::HasManyThrough and + # call the +run+ method for each passed in class in the +records+ argument. + # + # Not all records have the same class, so group then preload group on the reflection + # itself so that if various subclass share the same association then we do not split + # them unnecessarily + # + # Additionally, polymorphic belongs_to associations can have multiple associated + # classes, depending on the polymorphic_type field. So we group by the classes as + # well. + def preloaders_for_one(association, records, scope) + grouped_records(association, records).flat_map do |reflection, klasses| + klasses.map do |rhs_klass, rs| + loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope) + loader.run self + loader + end end end - end - def grouped_records(association, records) - h = {} - records.each do |record| - next unless record - assoc = record.association(association) - klasses = h[assoc.reflection] ||= {} - (klasses[assoc.klass] ||= []) << record + def grouped_records(association, records) + h = {} + records.each do |record| + next unless record + assoc = record.association(association) + klasses = h[assoc.reflection] ||= {} + (klasses[assoc.klass] ||= []) << record + end + h end - h - end - class AlreadyLoaded # :nodoc: - attr_reader :owners, :reflection + class AlreadyLoaded # :nodoc: + attr_reader :owners, :reflection - def initialize(klass, owners, reflection, preload_scope) - @owners = owners - @reflection = reflection - end + def initialize(klass, owners, reflection, preload_scope) + @owners = owners + @reflection = reflection + end - def run(preloader); end + def run(preloader); end - def preloaded_records - owners.flat_map { |owner| owner.association(reflection.name).target } + def preloaded_records + owners.flat_map { |owner| owner.association(reflection.name).target } + end end - end - class NullPreloader # :nodoc: - def self.new(klass, owners, reflection, preload_scope); self; end - def self.run(preloader); end - def self.preloaded_records; []; end - def self.owners; []; end - end + class NullPreloader # :nodoc: + def self.new(klass, owners, reflection, preload_scope); self; end + def self.run(preloader); end + def self.preloaded_records; []; end + def self.owners; []; end + end - # Returns a class containing the logic needed to load preload the data - # and attach it to a relation. For example +Preloader::Association+ or - # +Preloader::HasManyThrough+. The class returned implements a `run` method - # that accepts a preloader. - def preloader_for(reflection, owners, rhs_klass) - return NullPreloader unless rhs_klass + # Returns a class containing the logic needed to load preload the data + # and attach it to a relation. For example +Preloader::Association+ or + # +Preloader::HasManyThrough+. The class returned implements a `run` method + # that accepts a preloader. + def preloader_for(reflection, owners, rhs_klass) + return NullPreloader unless rhs_klass - if owners.first.association(reflection.name).loaded? - return AlreadyLoaded - end - reflection.check_preloadable! - - case reflection.macro - when :has_many - reflection.options[:through] ? HasManyThrough : HasMany - when :has_one - reflection.options[:through] ? HasOneThrough : HasOne - when :belongs_to - BelongsTo + if owners.first.association(reflection.name).loaded? + return AlreadyLoaded + end + reflection.check_preloadable! + + case reflection.macro + when :has_many + reflection.options[:through] ? HasManyThrough : HasMany + when :has_one + reflection.options[:through] ? HasOneThrough : HasOne + when :belongs_to + BelongsTo + end end - end end end end diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 3032bc786e..c79efca920 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -28,10 +28,6 @@ module ActiveRecord end def records_for(ids) - query_scope(ids) - end - - def query_scope(ids) scope.where(association_key_name => ids) end @@ -61,99 +57,113 @@ module ActiveRecord private - def associated_records_by_owner(preloader) - records = load_records - owners.each_with_object({}) do |owner, result| - result[owner] = records[convert_key(owner[owner_key_name])] || [] + def associated_records_by_owner(preloader) + records = load_records do |record| + owner = owners_by_key[convert_key(record[association_key_name])] + association = owner.association(reflection.name) + association.set_inverse_instance(record) + end + + owners.each_with_object({}) do |owner, result| + result[owner] = records[convert_key(owner[owner_key_name])] || [] + end end - end - def owner_keys - unless defined?(@owner_keys) - @owner_keys = owners.map do |owner| - owner[owner_key_name] + def owner_keys + unless defined?(@owner_keys) + @owner_keys = owners.map do |owner| + owner[owner_key_name] + end + @owner_keys.uniq! + @owner_keys.compact! end - @owner_keys.uniq! - @owner_keys.compact! + @owner_keys end - @owner_keys - end - def key_conversion_required? - @key_conversion_required ||= association_key_type != owner_key_type - end + def owners_by_key + unless defined?(@owners_by_key) + @owners_by_key = owners.each_with_object({}) do |owner, h| + h[convert_key(owner[owner_key_name])] = owner + end + end + @owners_by_key + end - def convert_key(key) - if key_conversion_required? - key.to_s - else - key + def key_conversion_required? + @key_conversion_required ||= association_key_type != owner_key_type end - end - def association_key_type - @klass.type_for_attribute(association_key_name.to_s).type - end + def convert_key(key) + if key_conversion_required? + key.to_s + else + key + end + end - def owner_key_type - @model.type_for_attribute(owner_key_name.to_s).type - end + def association_key_type + @klass.type_for_attribute(association_key_name.to_s).type + end + + def owner_key_type + @model.type_for_attribute(owner_key_name.to_s).type + end - def load_records - return {} if owner_keys.empty? - # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000) - # Make several smaller queries if necessary or make one query if the adapter supports it - slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size) - @preloaded_records = slices.flat_map do |slice| - records_for(slice) + def load_records(&block) + return {} if owner_keys.empty? + # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000) + # Make several smaller queries if necessary or make one query if the adapter supports it + slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size) + @preloaded_records = slices.flat_map do |slice| + records_for(slice).load(&block) + end + @preloaded_records.group_by do |record| + convert_key(record[association_key_name]) + end end - @preloaded_records.group_by do |record| - convert_key(record[association_key_name]) + + def reflection_scope + @reflection_scope ||= reflection.scope_for(klass) end - end - def reflection_scope - @reflection_scope ||= reflection.scope ? klass.unscoped.instance_exec(nil, &reflection.scope) : klass.unscoped - end + def build_scope + scope = klass.unscoped - def build_scope - scope = klass.unscoped + values = reflection_scope.values + preload_values = preload_scope.values - values = reflection_scope.values - preload_values = preload_scope.values + scope.where_clause = reflection_scope.where_clause + preload_scope.where_clause + scope.references_values = Array(values[:references]) + Array(preload_values[:references]) - scope.where_clause = reflection_scope.where_clause + preload_scope.where_clause - scope.references_values = Array(values[:references]) + Array(preload_values[:references]) + if preload_values[:select] || values[:select] + scope._select!(preload_values[:select] || values[:select]) + end + scope.includes! preload_values[:includes] || values[:includes] + if preload_scope.joins_values.any? + scope.joins!(preload_scope.joins_values) + else + scope.joins!(reflection_scope.joins_values) + end - if preload_values[:select] || values[:select] - scope._select!(preload_values[:select] || values[:select]) - end - scope.includes! preload_values[:includes] || values[:includes] - if preload_scope.joins_values.any? - scope.joins!(preload_scope.joins_values) - else - scope.joins!(reflection_scope.joins_values) - end + if order_values = preload_values[:order] || values[:order] + scope.order!(order_values) + end - if order_values = preload_values[:order] || values[:order] - scope.order!(order_values) - end + if preload_values[:reordering] || values[:reordering] + scope.reordering_value = true + end - if preload_values[:reordering] || values[:reordering] - scope.reordering_value = true - end + if preload_values[:readonly] || values[:readonly] + scope.readonly! + end - if preload_values[:readonly] || values[:readonly] - scope.readonly! - end + if options[:as] + scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name }) + end - if options[:as] - scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name }) + scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope]) + klass.default_scoped.merge(scope) end - - scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope]) - klass.default_scoped.merge(scope) - end end end end diff --git a/activerecord/lib/active_record/associations/preloader/belongs_to.rb b/activerecord/lib/active_record/associations/preloader/belongs_to.rb index 5091d4717a..38e231826c 100644 --- a/activerecord/lib/active_record/associations/preloader/belongs_to.rb +++ b/activerecord/lib/active_record/associations/preloader/belongs_to.rb @@ -2,7 +2,6 @@ module ActiveRecord module Associations class Preloader class BelongsTo < SingularAssociation #:nodoc: - def association_key_name reflection.options[:primary_key] || klass && klass.primary_key end @@ -10,7 +9,6 @@ module ActiveRecord def owner_key_name reflection.foreign_key end - end end end diff --git a/activerecord/lib/active_record/associations/preloader/collection_association.rb b/activerecord/lib/active_record/associations/preloader/collection_association.rb index 9939280fa4..26690bf16d 100644 --- a/activerecord/lib/active_record/associations/preloader/collection_association.rb +++ b/activerecord/lib/active_record/associations/preloader/collection_association.rb @@ -4,14 +4,13 @@ module ActiveRecord class CollectionAssociation < Association #:nodoc: private - def preload(preloader) - associated_records_by_owner(preloader).each do |owner, records| - association = owner.association(reflection.name) - association.loaded! - association.target.concat(records) - records.each { |record| association.set_inverse_instance(record) } + def preload(preloader) + associated_records_by_owner(preloader).each do |owner, records| + association = owner.association(reflection.name) + association.loaded! + association.target.concat(records) + end end - end end end end diff --git a/activerecord/lib/active_record/associations/preloader/has_many.rb b/activerecord/lib/active_record/associations/preloader/has_many.rb index 3ea91a8c11..20df1cc19a 100644 --- a/activerecord/lib/active_record/associations/preloader/has_many.rb +++ b/activerecord/lib/active_record/associations/preloader/has_many.rb @@ -2,7 +2,6 @@ module ActiveRecord module Associations class Preloader class HasMany < CollectionAssociation #:nodoc: - def association_key_name reflection.foreign_key end @@ -10,7 +9,6 @@ module ActiveRecord def owner_key_name reflection.active_record_primary_key end - end end end diff --git a/activerecord/lib/active_record/associations/preloader/singular_association.rb b/activerecord/lib/active_record/associations/preloader/singular_association.rb index f60647a81e..5c5828262e 100644 --- a/activerecord/lib/active_record/associations/preloader/singular_association.rb +++ b/activerecord/lib/active_record/associations/preloader/singular_association.rb @@ -2,19 +2,16 @@ module ActiveRecord module Associations class Preloader class SingularAssociation < Association #:nodoc: - private - def preload(preloader) - associated_records_by_owner(preloader).each do |owner, associated_records| - record = associated_records.first + def preload(preloader) + associated_records_by_owner(preloader).each do |owner, associated_records| + record = associated_records.first - association = owner.association(reflection.name) - association.target = record - association.set_inverse_instance(record) if record + association = owner.association(reflection.name) + association.target = record + end end - end - end end end diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index b0203909ce..be9dfe7686 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -61,48 +61,47 @@ module ActiveRecord private - def id_to_index_map(ids) - id_map = {} - ids.each_with_index { |id, index| id_map[id] = index } - id_map - end + def id_to_index_map(ids) + id_map = {} + ids.each_with_index { |id, index| id_map[id] = index } + id_map + end - def reset_association(owners, association_name) - should_reset = (through_scope != through_reflection.klass.unscoped) || - (reflection.options[:source_type] && through_reflection.collection?) + def reset_association(owners, association_name) + should_reset = (through_scope != through_reflection.klass.unscoped) || + (reflection.options[:source_type] && through_reflection.collection?) - # Don't cache the association - we would only be caching a subset - if should_reset - owners.each { |owner| - owner.association(association_name).reset - } + # Don't cache the association - we would only be caching a subset + if should_reset + owners.each { |owner| + owner.association(association_name).reset + } + end end - end + def through_scope + scope = through_reflection.klass.unscoped - def through_scope - scope = through_reflection.klass.unscoped + if options[:source_type] + scope.where! reflection.foreign_type => options[:source_type] + else + unless reflection_scope.where_clause.empty? + scope.includes_values = Array(reflection_scope.values[:includes] || options[:source]) + scope.where_clause = reflection_scope.where_clause + end - if options[:source_type] - scope.where! reflection.foreign_type => options[:source_type] - else - unless reflection_scope.where_clause.empty? - scope.includes_values = Array(reflection_scope.values[:includes] || options[:source]) - scope.where_clause = reflection_scope.where_clause + scope.references! reflection_scope.values[:references] + if scope.eager_loading? && order_values = reflection_scope.values[:order] + scope = scope.order(order_values) + end end - scope.references! reflection_scope.values[:references] - if scope.eager_loading? && order_values = reflection_scope.values[:order] - scope = scope.order(order_values) - end + scope end - scope - end - - def target_records_from_association(association) - association.loaded? ? association.target : association.reader - end + def target_records_from_association(association) + association.loaded? ? association.target : association.reader + end end end end diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb index f913f0852a..e386cc0e4c 100644 --- a/activerecord/lib/active_record/associations/singular_association.rb +++ b/activerecord/lib/active_record/associations/singular_association.rb @@ -23,14 +23,6 @@ module ActiveRecord replace(record) end - def create(attributes = {}, &block) - _create_record(attributes, &block) - end - - def create!(attributes = {}, &block) - _create_record(attributes, true, &block) - end - def build(attributes = {}) record = build_record(attributes) yield(record) if block_given? @@ -44,8 +36,8 @@ module ActiveRecord scope.scope_for_create.stringify_keys.except(klass.primary_key) end - def get_records - return scope.limit(1).records if skip_statement_cache? + def find_target + return scope.take if skip_statement_cache? conn = klass.connection sc = reflection.association_scope_cache(conn, owner) do @@ -56,13 +48,9 @@ module ActiveRecord end binds = AssociationScope.get_bind_values(owner, reflection.chain) - sc.execute binds, klass, klass.connection - end - - def find_target - if record = get_records.first + sc.execute(binds, klass, conn) do |record| set_inverse_instance record - end + end.first end def replace(record) diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index d0ec3e8015..f4129edc5a 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -2,8 +2,7 @@ module ActiveRecord # = Active Record Through Association module Associations module ThroughAssociation #:nodoc: - - delegate :source_reflection, :through_reflection, :to => :reflection + delegate :source_reflection, :through_reflection, to: :reflection protected diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb index 9530f134d0..0b08c2a39b 100644 --- a/activerecord/lib/active_record/attribute.rb +++ b/activerecord/lib/active_record/attribute.rb @@ -65,7 +65,7 @@ module ActiveRecord def with_value_from_user(value) type.assert_valid_value(value) - self.class.from_user(name, value, type, self) + self.class.from_user(name, value, type, original_attribute || self) end def with_value_from_database(value) @@ -130,108 +130,108 @@ module ActiveRecord protected - attr_reader :original_attribute - alias_method :assigned?, :original_attribute + attr_reader :original_attribute + alias_method :assigned?, :original_attribute - def initialize_dup(other) - if defined?(@value) && @value.duplicable? - @value = @value.dup + def initialize_dup(other) + if defined?(@value) && @value.duplicable? + @value = @value.dup + end end - end - - def changed_from_assignment? - assigned? && type.changed?(original_value, value, value_before_type_cast) - end - def original_value_for_database - if assigned? - original_attribute.original_value_for_database - else - _original_value_for_database + def changed_from_assignment? + assigned? && type.changed?(original_value, value, value_before_type_cast) end - end - - def _original_value_for_database - value_for_database - end - class FromDatabase < Attribute # :nodoc: - def type_cast(value) - type.deserialize(value) + def original_value_for_database + if assigned? + original_attribute.original_value_for_database + else + _original_value_for_database + end end def _original_value_for_database - value_before_type_cast + type.serialize(original_value) end - end - class FromUser < Attribute # :nodoc: - def type_cast(value) - type.cast(value) - end + class FromDatabase < Attribute # :nodoc: + def type_cast(value) + type.deserialize(value) + end - def came_from_user? - true + def _original_value_for_database + value_before_type_cast + end end - end - class WithCastValue < Attribute # :nodoc: - def type_cast(value) - value - end + class FromUser < Attribute # :nodoc: + def type_cast(value) + type.cast(value) + end - def changed_in_place_from?(old_value) - false + def came_from_user? + true + end end - end - class Null < Attribute # :nodoc: - def initialize(name) - super(name, nil, Type::Value.new) - end + class WithCastValue < Attribute # :nodoc: + def type_cast(value) + value + end - def type_cast(*) - nil + def changed_in_place? + false + end end - def with_type(type) - self.class.with_cast_value(name, nil, type) - end + class Null < Attribute # :nodoc: + def initialize(name) + super(name, nil, Type.default_value) + end - def with_value_from_database(value) - raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`" - end - alias_method :with_value_from_user, :with_value_from_database - end + def type_cast(*) + nil + end - class Uninitialized < Attribute # :nodoc: - UNINITIALIZED_ORIGINAL_VALUE = Object.new + def with_type(type) + self.class.with_cast_value(name, nil, type) + end - def initialize(name, type) - super(name, nil, type) + def with_value_from_database(value) + raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`" + end + alias_method :with_value_from_user, :with_value_from_database end - def value - if block_given? - yield name + class Uninitialized < Attribute # :nodoc: + UNINITIALIZED_ORIGINAL_VALUE = Object.new + + def initialize(name, type) + super(name, nil, type) end - end - def original_value - UNINITIALIZED_ORIGINAL_VALUE - end + def value + if block_given? + yield name + end + end - def value_for_database - end + def original_value + UNINITIALIZED_ORIGINAL_VALUE + end - def initialized? - false - end + def value_for_database + end + + def initialized? + false + end - def with_type(type) - self.class.new(name, type) + def with_type(type) + self.class.new(name, type) + end end - end - private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue + private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue end end diff --git a/activerecord/lib/active_record/attribute/user_provided_default.rb b/activerecord/lib/active_record/attribute/user_provided_default.rb index 4580813364..a4e2c2ec85 100644 --- a/activerecord/lib/active_record/attribute/user_provided_default.rb +++ b/activerecord/lib/active_record/attribute/user_provided_default.rb @@ -1,4 +1,4 @@ -require 'active_record/attribute' +require "active_record/attribute" module ActiveRecord class Attribute # :nodoc: @@ -22,7 +22,7 @@ module ActiveRecord protected - attr_reader :user_provided_value + attr_reader :user_provided_value end end end diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb index b96d8e9352..9843e0ca66 100644 --- a/activerecord/lib/active_record/attribute_assignment.rb +++ b/activerecord/lib/active_record/attribute_assignment.rb @@ -1,4 +1,4 @@ -require 'active_model/forbidden_attributes_protection' +require "active_model/forbidden_attributes_protection" module ActiveRecord module AttributeAssignment @@ -12,80 +12,80 @@ module ActiveRecord private - def _assign_attributes(attributes) # :nodoc: - multi_parameter_attributes = {} - nested_parameter_attributes = {} + def _assign_attributes(attributes) # :nodoc: + multi_parameter_attributes = {} + nested_parameter_attributes = {} - attributes.each do |k, v| - if k.include?("(") - multi_parameter_attributes[k] = attributes.delete(k) - elsif v.is_a?(Hash) - nested_parameter_attributes[k] = attributes.delete(k) + attributes.each do |k, v| + if k.include?("(") + multi_parameter_attributes[k] = attributes.delete(k) + elsif v.is_a?(Hash) + nested_parameter_attributes[k] = attributes.delete(k) + end end - end - super(attributes) + super(attributes) - assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty? - assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty? - end + assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty? + assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty? + end - # Assign any deferred nested attributes after the base attributes have been set. - def assign_nested_parameter_attributes(pairs) - pairs.each { |k, v| _assign_attribute(k, v) } - end + # Assign any deferred nested attributes after the base attributes have been set. + def assign_nested_parameter_attributes(pairs) + pairs.each { |k, v| _assign_attribute(k, v) } + end - # Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done - # by calling new on the column type or aggregation type (through composed_of) object with these parameters. - # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate - # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the - # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Integer and - # f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+. - def assign_multiparameter_attributes(pairs) - execute_callstack_for_multiparameter_attributes( - extract_callstack_for_multiparameter_attributes(pairs) - ) - end + # Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done + # by calling new on the column type or aggregation type (through composed_of) object with these parameters. + # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate + # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the + # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Integer and + # f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+. + def assign_multiparameter_attributes(pairs) + execute_callstack_for_multiparameter_attributes( + extract_callstack_for_multiparameter_attributes(pairs) + ) + end - def execute_callstack_for_multiparameter_attributes(callstack) - errors = [] - callstack.each do |name, values_with_empty_parameters| - begin - if values_with_empty_parameters.each_value.all?(&:nil?) - values = nil - else - values = values_with_empty_parameters + def execute_callstack_for_multiparameter_attributes(callstack) + errors = [] + callstack.each do |name, values_with_empty_parameters| + begin + if values_with_empty_parameters.each_value.all?(&:nil?) + values = nil + else + values = values_with_empty_parameters + end + send("#{name}=", values) + rescue => ex + errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name) end - send("#{name}=", values) - rescue => ex - errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name) + end + unless errors.empty? + error_descriptions = errors.map(&:message).join(",") + raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]" end end - unless errors.empty? - error_descriptions = errors.map(&:message).join(",") - raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]" - end - end - def extract_callstack_for_multiparameter_attributes(pairs) - attributes = {} + def extract_callstack_for_multiparameter_attributes(pairs) + attributes = {} - pairs.each do |(multiparameter_name, value)| - attribute_name = multiparameter_name.split("(").first - attributes[attribute_name] ||= {} + pairs.each do |(multiparameter_name, value)| + attribute_name = multiparameter_name.split("(").first + attributes[attribute_name] ||= {} - parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value) - attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value - end + parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value) + attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value + end - attributes - end + attributes + end - def type_cast_attribute_value(multiparameter_name, value) - multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value - end + def type_cast_attribute_value(multiparameter_name, value) + multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value + end - def find_parameter_position(multiparameter_name) - multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i - end + def find_parameter_position(multiparameter_name) + multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i + end end end diff --git a/activerecord/lib/active_record/attribute_decorators.rb b/activerecord/lib/active_record/attribute_decorators.rb index 7d0ae32411..340dfe11cf 100644 --- a/activerecord/lib/active_record/attribute_decorators.rb +++ b/activerecord/lib/active_record/attribute_decorators.rb @@ -24,13 +24,13 @@ module ActiveRecord private - def load_schema! - super - attribute_types.each do |name, type| - decorated_type = attribute_type_decorations.apply(name, type) - define_attribute(name, decorated_type) + def load_schema! + super + attribute_types.each do |name, type| + decorated_type = attribute_type_decorations.apply(name, type) + define_attribute(name, decorated_type) + end end - end end class TypeDecorator # :nodoc: @@ -53,15 +53,15 @@ module ActiveRecord private - def decorators_for(name, type) - matching(name, type).map(&:last) - end + def decorators_for(name, type) + matching(name, type).map(&:last) + end - def matching(name, type) - @decorations.values.select do |(matcher, _)| - matcher.call(name, type) + def matching(name, type) + @decorations.values.select do |(matcher, _)| + matcher.call(name, type) + end end - end end end end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 1fb5eb28cd..1ed1deec55 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/enumerable' -require 'active_support/core_ext/string/filters' -require 'mutex_m' -require 'concurrent/map' +require "active_support/core_ext/enumerable" +require "active_support/core_ext/string/filters" +require "mutex_m" +require "concurrent/map" module ActiveRecord # = Active Record Attribute Methods @@ -148,7 +148,7 @@ module ActiveRecord # Person.attribute_method?(:age=) # => true # Person.attribute_method?(:nothing) # => false def attribute_method?(attribute) - super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, ''))) + super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, ""))) end # Returns an array of column names as strings if it's not an abstract class and @@ -161,10 +161,10 @@ module ActiveRecord # # => ["id", "created_at", "updated_at", "name", "age"] def attribute_names @attribute_names ||= if !abstract_class? && table_exists? - attribute_types.keys - else - [] - end + attribute_types.keys + else + [] + end end # Returns true if the given attribute exists, otherwise false. @@ -209,13 +209,13 @@ module ActiveRecord # end # # person = Person.new - # person.respond_to(:name) # => true - # person.respond_to(:name=) # => true - # person.respond_to(:name?) # => true - # person.respond_to('age') # => true - # person.respond_to('age=') # => true - # person.respond_to('age?') # => true - # person.respond_to(:nothing) # => false + # person.respond_to?(:name) # => true + # person.respond_to?(:name=) # => true + # person.respond_to?(:name?) # => true + # person.respond_to?('age') # => true + # person.respond_to?('age=') # => true + # person.respond_to?('age?') # => true + # person.respond_to?(:nothing) # => false def respond_to?(name, include_private = false) return false unless super @@ -279,9 +279,8 @@ module ActiveRecord # Returns an <tt>#inspect</tt>-like string for the value of the # attribute +attr_name+. String attributes are truncated up to 50 # characters, Date and Time attributes are returned in the - # <tt>:db</tt> format, Array attributes are truncated up to 10 values. - # Other attributes return the value of <tt>#inspect</tt> without - # modification. + # <tt>:db</tt> format. Other attributes return the value of + # <tt>#inspect</tt> without modification. # # person = Person.create!(name: 'David Heinemeier Hansson ' * 3) # @@ -292,7 +291,7 @@ module ActiveRecord # # => "\"2012-10-22 00:15:07\"" # # person.attribute_for_inspect(:tag_ids) - # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]" + # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]" def attribute_for_inspect(attr_name) value = read_attribute(attr_name) @@ -300,9 +299,6 @@ module ActiveRecord "#{value[0, 50]}...".inspect elsif value.is_a?(Date) || value.is_a?(Time) %("#{value.to_s(:db)}") - elsif value.is_a?(Array) && value.size > 10 - inspected = value.first(10).inspect - %(#{inspected[0...-1]}, ...]) else value.inspect end @@ -398,65 +394,65 @@ module ActiveRecord protected - def clone_attribute_value(reader_method, attribute_name) # :nodoc: - value = send(reader_method, attribute_name) - value.duplicable? ? value.clone : value - rescue TypeError, NoMethodError - value - end + def clone_attribute_value(reader_method, attribute_name) # :nodoc: + value = send(reader_method, attribute_name) + value.duplicable? ? value.clone : value + rescue TypeError, NoMethodError + value + end - def arel_attributes_with_values_for_create(attribute_names) # :nodoc: - arel_attributes_with_values(attributes_for_create(attribute_names)) - end + def arel_attributes_with_values_for_create(attribute_names) # :nodoc: + arel_attributes_with_values(attributes_for_create(attribute_names)) + end - def arel_attributes_with_values_for_update(attribute_names) # :nodoc: - arel_attributes_with_values(attributes_for_update(attribute_names)) - end + def arel_attributes_with_values_for_update(attribute_names) # :nodoc: + arel_attributes_with_values(attributes_for_update(attribute_names)) + end - def attribute_method?(attr_name) # :nodoc: - # We check defined? because Syck calls respond_to? before actually calling initialize. - defined?(@attributes) && @attributes.key?(attr_name) - end + def attribute_method?(attr_name) # :nodoc: + # We check defined? because Syck calls respond_to? before actually calling initialize. + defined?(@attributes) && @attributes.key?(attr_name) + end private - # Returns a Hash of the Arel::Attributes and attribute values that have been - # typecasted for use in an Arel insert/update method. - def arel_attributes_with_values(attribute_names) - attrs = {} - arel_table = self.class.arel_table + # Returns a Hash of the Arel::Attributes and attribute values that have been + # typecasted for use in an Arel insert/update method. + def arel_attributes_with_values(attribute_names) + attrs = {} + arel_table = self.class.arel_table - attribute_names.each do |name| - attrs[arel_table[name]] = typecasted_attribute_value(name) + attribute_names.each do |name| + attrs[arel_table[name]] = typecasted_attribute_value(name) + end + attrs end - attrs - end - # Filters the primary keys and readonly attributes from the attribute names. - def attributes_for_update(attribute_names) - attribute_names.reject do |name| - readonly_attribute?(name) + # Filters the primary keys and readonly attributes from the attribute names. + def attributes_for_update(attribute_names) + attribute_names.reject do |name| + readonly_attribute?(name) + end end - end - # Filters out the primary keys, from the attribute names, when the primary - # key is to be generated (e.g. the id attribute has no value). - def attributes_for_create(attribute_names) - attribute_names.reject do |name| - pk_attribute?(name) && id.nil? + # Filters out the primary keys, from the attribute names, when the primary + # key is to be generated (e.g. the id attribute has no value). + def attributes_for_create(attribute_names) + attribute_names.reject do |name| + pk_attribute?(name) && id.nil? + end end - end - def readonly_attribute?(name) - self.class.readonly_attributes.include?(name) - end + def readonly_attribute?(name) + self.class.readonly_attributes.include?(name) + end - def pk_attribute?(name) - name == self.class.primary_key - end + def pk_attribute?(name) + name == self.class.primary_key + end - def typecasted_attribute_value(name) - _read_attribute(name) - end + def typecasted_attribute_value(name) + _read_attribute(name) + end end end diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb index 1db6776688..115eb1ef3f 100644 --- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb +++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb @@ -63,14 +63,14 @@ module ActiveRecord private - # Handle *_before_type_cast for method_missing. - def attribute_before_type_cast(attribute_name) - read_attribute_before_type_cast(attribute_name) - end + # Handle *_before_type_cast for method_missing. + def attribute_before_type_cast(attribute_name) + read_attribute_before_type_cast(attribute_name) + end - def attribute_came_from_user?(attribute_name) - @attributes[attribute_name].came_from_user? - end + def attribute_came_from_user?(attribute_name) + @attributes[attribute_name].came_from_user? + end end end end diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 0bcfa5f00d..c9638bf70b 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'active_record/attribute_mutation_tracker' +require "active_support/core_ext/module/attribute_accessors" +require "active_record/attribute_mutation_tracker" module ActiveRecord module AttributeMethods @@ -100,52 +100,52 @@ module ActiveRecord private - def mutation_tracker - unless defined?(@mutation_tracker) - @mutation_tracker = nil + def mutation_tracker + unless defined?(@mutation_tracker) + @mutation_tracker = nil + end + @mutation_tracker ||= AttributeMutationTracker.new(@attributes) end - @mutation_tracker ||= AttributeMutationTracker.new(@attributes) - end - def changes_include?(attr_name) - super || mutation_tracker.changed?(attr_name) - end + def changes_include?(attr_name) + super || mutation_tracker.changed?(attr_name) + end - def clear_attribute_change(attr_name) - mutation_tracker.forget_change(attr_name) - end + def clear_attribute_change(attr_name) + mutation_tracker.forget_change(attr_name) + end - def _update_record(*) - partial_writes? ? super(keys_for_partial_write) : super - end + def _update_record(*) + partial_writes? ? super(keys_for_partial_write) : super + end - def _create_record(*) - partial_writes? ? super(keys_for_partial_write) : super - end + def _create_record(*) + partial_writes? ? super(keys_for_partial_write) : super + end - def keys_for_partial_write - changed & self.class.column_names - end + def keys_for_partial_write + changed & self.class.column_names + end - def store_original_attributes - @attributes = @attributes.map(&:forgetting_assignment) - @mutation_tracker = nil - end + def store_original_attributes + @attributes = @attributes.map(&:forgetting_assignment) + @mutation_tracker = nil + end - def previous_mutation_tracker - @previous_mutation_tracker ||= NullMutationTracker.instance - end + def previous_mutation_tracker + @previous_mutation_tracker ||= NullMutationTracker.instance + end - def cache_changed_attributes - @cached_changed_attributes = changed_attributes - yield - ensure - clear_changed_attributes_cache - end + def cache_changed_attributes + @cached_changed_attributes = changed_attributes + yield + ensure + clear_changed_attributes_cache + end - def clear_changed_attributes_cache - remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes) - end + def clear_changed_attributes_cache + remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes) + end end end end diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 0d5cb8b37c..6243398a52 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -1,4 +1,4 @@ -require 'set' +require "set" module ActiveRecord module AttributeMethods @@ -47,82 +47,95 @@ module ActiveRecord protected - def attribute_method?(attr_name) - attr_name == 'id' || super - end + def attribute_method?(attr_name) + attr_name == "id" || super + end - module ClassMethods - def define_method_attribute(attr_name) - super + module ClassMethods + def define_method_attribute(attr_name) + super - if attr_name == primary_key && attr_name != 'id' - generated_attribute_methods.send(:alias_method, :id, primary_key) + if attr_name == primary_key && attr_name != "id" + generated_attribute_methods.send(:alias_method, :id, primary_key) + end end - end - ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was).to_set + ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was).to_set - def dangerous_attribute_method?(method_name) - super && !ID_ATTRIBUTE_METHODS.include?(method_name) - end + def dangerous_attribute_method?(method_name) + super && !ID_ATTRIBUTE_METHODS.include?(method_name) + end - # Defines the primary key field -- can be overridden in subclasses. - # Overwriting will negate any effect of the +primary_key_prefix_type+ - # setting, though. - def primary_key - @primary_key = reset_primary_key unless defined? @primary_key - @primary_key - end + # Defines the primary key field -- can be overridden in subclasses. + # Overwriting will negate any effect of the +primary_key_prefix_type+ + # setting, though. + def primary_key + @primary_key = reset_primary_key unless defined? @primary_key + @primary_key + end - # Returns a quoted version of the primary key name, used to construct - # SQL statements. - def quoted_primary_key - @quoted_primary_key ||= connection.quote_column_name(primary_key) - end + # Returns a quoted version of the primary key name, used to construct + # SQL statements. + def quoted_primary_key + @quoted_primary_key ||= connection.quote_column_name(primary_key) + end - def reset_primary_key #:nodoc: - if self == base_class - self.primary_key = get_primary_key(base_class.name) - else - self.primary_key = base_class.primary_key + def reset_primary_key #:nodoc: + if self == base_class + self.primary_key = get_primary_key(base_class.name) + else + self.primary_key = base_class.primary_key + end end - end - def get_primary_key(base_name) #:nodoc: - if base_name && primary_key_prefix_type == :table_name - base_name.foreign_key(false) - elsif base_name && primary_key_prefix_type == :table_name_with_underscore - base_name.foreign_key - else - if ActiveRecord::Base != self && table_exists? - connection.schema_cache.primary_keys(table_name) + def get_primary_key(base_name) #:nodoc: + if base_name && primary_key_prefix_type == :table_name + base_name.foreign_key(false) + elsif base_name && primary_key_prefix_type == :table_name_with_underscore + base_name.foreign_key else - 'id' + if ActiveRecord::Base != self && table_exists? + pk = connection.schema_cache.primary_keys(table_name) + suppress_composite_primary_key(pk) + else + "id" + end end end - end - # Sets the name of the primary key column. - # - # class Project < ActiveRecord::Base - # self.primary_key = 'sysid' - # end - # - # You can also define the #primary_key method yourself: - # - # class Project < ActiveRecord::Base - # def self.primary_key - # 'foo_' + super - # end - # end - # - # Project.primary_key # => "foo_id" - def primary_key=(value) - @primary_key = value && value.to_s - @quoted_primary_key = nil - @attributes_builder = nil + # Sets the name of the primary key column. + # + # class Project < ActiveRecord::Base + # self.primary_key = 'sysid' + # end + # + # You can also define the #primary_key method yourself: + # + # class Project < ActiveRecord::Base + # def self.primary_key + # 'foo_' + super + # end + # end + # + # Project.primary_key # => "foo_id" + def primary_key=(value) + @primary_key = value && value.to_s + @quoted_primary_key = nil + @attributes_builder = nil + end + + private + + def suppress_composite_primary_key(pk) + return pk unless pk.is_a?(Array) + + warn <<-WARNING.strip_heredoc + WARNING: Active Record does not support composite primary key. + + #{table_name} has composite primary key. Composite primary key is ignored. + WARNING + end end - end end end end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index ab2ecaa7c5..30f7750884 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -6,42 +6,42 @@ module ActiveRecord module ClassMethods protected - # We want to generate the methods via module_eval rather than - # define_method, because define_method is slower on dispatch. - # Evaluating many similar methods may use more memory as the instruction - # sequences are duplicated and cached (in MRI). define_method may - # be slower on dispatch, but if you're careful about the closure - # created, then define_method will consume much less memory. - # - # But sometimes the database might return columns with - # characters that are not allowed in normal method names (like - # 'my_column(omg)'. So to work around this we first define with - # the __temp__ identifier, and then use alias method to rename - # it to what we want. - # - # We are also defining a constant to hold the frozen string of - # the attribute name. Using a constant means that we do not have - # to allocate an object on each call to the attribute method. - # Making it frozen means that it doesn't get duped when used to - # key the @attributes in read_attribute. - def define_method_attribute(name) - safe_name = name.unpack('h*'.freeze).first - temp_method = "__temp__#{safe_name}" + # We want to generate the methods via module_eval rather than + # define_method, because define_method is slower on dispatch. + # Evaluating many similar methods may use more memory as the instruction + # sequences are duplicated and cached (in MRI). define_method may + # be slower on dispatch, but if you're careful about the closure + # created, then define_method will consume much less memory. + # + # But sometimes the database might return columns with + # characters that are not allowed in normal method names (like + # 'my_column(omg)'. So to work around this we first define with + # the __temp__ identifier, and then use alias method to rename + # it to what we want. + # + # We are also defining a constant to hold the frozen string of + # the attribute name. Using a constant means that we do not have + # to allocate an object on each call to the attribute method. + # Making it frozen means that it doesn't get duped when used to + # key the @attributes in read_attribute. + def define_method_attribute(name) + safe_name = name.unpack("h*".freeze).first + temp_method = "__temp__#{safe_name}" - ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name + ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name - generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 - def #{temp_method} - name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} - _read_attribute(name) { |n| missing_attribute(n, caller) } - end - STR + generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 + def #{temp_method} + name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} + _read_attribute(name) { |n| missing_attribute(n, caller) } + end + STR - generated_attribute_methods.module_eval do - alias_method name, temp_method - undef_method temp_method + generated_attribute_methods.module_eval do + alias_method name, temp_method + undef_method temp_method + end end - end end # Returns the value of the attribute identified by <tt>attr_name</tt> after @@ -49,7 +49,7 @@ module ActiveRecord # to a date object, like Date.new(2004, 12, 12)). def read_attribute(attr_name, &block) name = attr_name.to_s - name = self.class.primary_key if name == 'id'.freeze + name = self.class.primary_key if name == "id".freeze _read_attribute(name, &block) end @@ -69,7 +69,6 @@ module ActiveRecord alias :attribute :_read_attribute private :attribute - end end end diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 65978aea2a..945192fe04 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -26,7 +26,7 @@ module ActiveRecord # ==== Parameters # # * +attr_name+ - The field name that should be serialized. - # * +class_name_or_coder+ - Optional, a coder object, which responds to `.load` / `.dump` + # * +class_name_or_coder+ - Optional, a coder object, which responds to +.load+ and +.dump+ # or a class name that the object type should be equal to. # # ==== Example @@ -50,12 +50,12 @@ module ActiveRecord # to ensure special objects (e.g. Active Record models) are dumped correctly # using the #as_json hook. coder = if class_name_or_coder == ::JSON - Coders::JSON - elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) } - class_name_or_coder - else - Coders::YAMLColumn.new(class_name_or_coder) - end + Coders::JSON + elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) } + class_name_or_coder + else + Coders::YAMLColumn.new(class_name_or_coder) + end decorate_attribute_type(attr_name, :serialize) do |type| Type::Serialized.new(type, coder) diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index e160460286..bea1514cdf 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/strip' +require "active_support/core_ext/string/strip" module ActiveRecord module AttributeMethods @@ -26,31 +26,31 @@ module ActiveRecord private - def convert_time_to_time_zone(value) - return if value.nil? + def convert_time_to_time_zone(value) + return if value.nil? - if value.acts_like?(:time) - value.in_time_zone - elsif value.is_a?(::Float) - value - else - map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) } + if value.acts_like?(:time) + value.in_time_zone + elsif value.is_a?(::Float) + value + else + map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) } + end end - end - def set_time_zone_without_conversion(value) - ::Time.zone.local_to_utc(value).in_time_zone - end + def set_time_zone_without_conversion(value) + ::Time.zone.local_to_utc(value).in_time_zone if value + end - def map_avoiding_infinite_recursion(value) - map(value) do |v| - if value.equal?(v) - nil - else - yield(v) + def map_avoiding_infinite_recursion(value) + map(value) do |v| + if value.equal?(v) + nil + else + yield(v) + end end end - end end extend ActiveSupport::Concern @@ -69,47 +69,47 @@ module ActiveRecord module ClassMethods private - def inherited(subclass) - # We need to apply this decorator here, rather than on module inclusion. The closure - # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the - # sub class being decorated. As such, changes to `time_zone_aware_attributes`, or - # `skip_time_zone_conversion_for_attributes` would not be picked up. - subclass.class_eval do - matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) } - decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type| - TimeZoneConverter.new(type) + def inherited(subclass) + # We need to apply this decorator here, rather than on module inclusion. The closure + # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the + # sub class being decorated. As such, changes to `time_zone_aware_attributes`, or + # `skip_time_zone_conversion_for_attributes` would not be picked up. + subclass.class_eval do + matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) } + decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type| + TimeZoneConverter.new(type) + end end + super end - super - end - def create_time_zone_conversion_attribute?(name, cast_type) - enabled_for_column = time_zone_aware_attributes && - !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) - result = enabled_for_column && - time_zone_aware_types.include?(cast_type.type) + def create_time_zone_conversion_attribute?(name, cast_type) + enabled_for_column = time_zone_aware_attributes && + !skip_time_zone_conversion_for_attributes.include?(name.to_sym) + result = enabled_for_column && + time_zone_aware_types.include?(cast_type.type) - if enabled_for_column && - !result && - cast_type.type == :time && - time_zone_aware_types.include?(:not_explicitly_configured) - ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) - Time columns will become time zone aware in Rails 5.1. This - still causes `String`s to be parsed as if they were in `Time.zone`, - and `Time`s to be converted to `Time.zone`. + if enabled_for_column && + !result && + cast_type.type == :time && + time_zone_aware_types.include?(:not_explicitly_configured) + ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) + Time columns will become time zone aware in Rails 5.1. This + still causes `String`s to be parsed as if they were in `Time.zone`, + and `Time`s to be converted to `Time.zone`. - To keep the old behavior, you must add the following to your initializer: + To keep the old behavior, you must add the following to your initializer: - config.active_record.time_zone_aware_types = [:datetime] + config.active_record.time_zone_aware_types = [:datetime] - To silence this deprecation warning, add the following: + To silence this deprecation warning, add the following: - config.active_record.time_zone_aware_types = [:datetime, :time] - MESSAGE - end + config.active_record.time_zone_aware_types = [:datetime, :time] + MESSAGE + end - result - end + result + end end end end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 70c2d2f25d..f65c297e01 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -10,19 +10,19 @@ module ActiveRecord module ClassMethods protected - def define_method_attribute=(name) - safe_name = name.unpack('h*'.freeze).first - ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name - - generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 - def __temp__#{safe_name}=(value) - name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} - write_attribute(name, value) - end - alias_method #{(name + '=').inspect}, :__temp__#{safe_name}= - undef_method :__temp__#{safe_name}= - STR - end + def define_method_attribute=(name) + safe_name = name.unpack("h*".freeze).first + ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name + + generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 + def __temp__#{safe_name}=(value) + name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} + write_attribute(name, value) + end + alias_method #{(name + '=').inspect}, :__temp__#{safe_name}= + undef_method :__temp__#{safe_name}= + STR + end end # Updates the attribute identified by <tt>attr_name</tt> with the @@ -37,23 +37,23 @@ module ActiveRecord end private - # Handle *= for method_missing. - def attribute=(attribute_name, value) - write_attribute(attribute_name, value) - end + # Handle *= for method_missing. + def attribute=(attribute_name, value) + write_attribute(attribute_name, value) + end - def write_attribute_with_type_cast(attr_name, value, should_type_cast) - attr_name = attr_name.to_s - attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key + def write_attribute_with_type_cast(attr_name, value, should_type_cast) + attr_name = attr_name.to_s + attr_name = self.class.primary_key if attr_name == "id" && self.class.primary_key - if should_type_cast - @attributes.write_from_user(attr_name, value) - else - @attributes.write_cast_value(attr_name, value) - end + if should_type_cast + @attributes.write_from_user(attr_name, value) + else + @attributes.write_cast_value(attr_name, value) + end - value - end + value + end end end end diff --git a/activerecord/lib/active_record/attribute_mutation_tracker.rb b/activerecord/lib/active_record/attribute_mutation_tracker.rb index 0133b4d0be..c257aef52f 100644 --- a/activerecord/lib/active_record/attribute_mutation_tracker.rb +++ b/activerecord/lib/active_record/attribute_mutation_tracker.rb @@ -36,13 +36,13 @@ module ActiveRecord protected - attr_reader :attributes + attr_reader :attributes private - def attr_names - attributes.keys - end + def attr_names + attributes.keys + end end class NullMutationTracker # :nodoc: diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb index 720d5f8b7c..5bde1f107c 100644 --- a/activerecord/lib/active_record/attribute_set.rb +++ b/activerecord/lib/active_record/attribute_set.rb @@ -1,9 +1,9 @@ -require 'active_record/attribute_set/builder' -require 'active_record/attribute_set/yaml_encoder' +require "active_record/attribute_set/builder" +require "active_record/attribute_set/yaml_encoder" module ActiveRecord class AttributeSet # :nodoc: - delegate :each_value, to: :attributes + delegate :each_value, :fetch, to: :attributes def initialize(attributes) @attributes = attributes @@ -100,12 +100,12 @@ module ActiveRecord protected - attr_reader :attributes + attr_reader :attributes private - def initialized_attributes - attributes.select { |_, attr| attr.initialized? } - end + def initialized_attributes + attributes.select { |_, attr| attr.initialized? } + end end end diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb index 24a255efc1..661f996e1a 100644 --- a/activerecord/lib/active_record/attribute_set/builder.rb +++ b/activerecord/lib/active_record/attribute_set/builder.rb @@ -1,13 +1,14 @@ -require 'active_record/attribute' +require "active_record/attribute" module ActiveRecord class AttributeSet # :nodoc: class Builder # :nodoc: - attr_reader :types, :always_initialized + attr_reader :types, :always_initialized, :default - def initialize(types, always_initialized = nil) + def initialize(types, always_initialized = nil, &default) @types = types @always_initialized = always_initialized + @default = default end def build_from_database(values = {}, additional_types = {}) @@ -15,21 +16,22 @@ module ActiveRecord values[always_initialized] = nil end - attributes = LazyAttributeHash.new(types, values, additional_types) + attributes = LazyAttributeHash.new(types, values, additional_types, &default) AttributeSet.new(attributes) end end end class LazyAttributeHash # :nodoc: - delegate :transform_values, :each_key, :each_value, to: :materialize + delegate :transform_values, :each_key, :each_value, :fetch, to: :materialize - def initialize(types, values, additional_types) + def initialize(types, values, additional_types, &default) @types = types @values = values @additional_types = additional_types @materialized = false @delegate_hash = {} + @default = default || proc {} end def key?(key) @@ -76,33 +78,45 @@ module ActiveRecord end end + def marshal_dump + materialize + end + + def marshal_load(delegate_hash) + @delegate_hash = delegate_hash + @types = {} + @values = {} + @additional_types = {} + @materialized = true + end + protected - attr_reader :types, :values, :additional_types, :delegate_hash + attr_reader :types, :values, :additional_types, :delegate_hash, :default - def materialize - unless @materialized - values.each_key { |key| self[key] } - types.each_key { |key| self[key] } - unless frozen? - @materialized = true + def materialize + unless @materialized + values.each_key { |key| self[key] } + types.each_key { |key| self[key] } + unless frozen? + @materialized = true + end end + delegate_hash end - delegate_hash - end private - def assign_default_value(name) - type = additional_types.fetch(name, types[name]) - value_present = true - value = values.fetch(name) { value_present = false } + def assign_default_value(name) + type = additional_types.fetch(name, types[name]) + value_present = true + value = values.fetch(name) { value_present = false } - if value_present - delegate_hash[name] = Attribute.from_database(name, value, type) - elsif types.key?(name) - delegate_hash[name] = Attribute.uninitialized(name, type) + if value_present + delegate_hash[name] = Attribute.from_database(name, value, type) + elsif types.key?(name) + delegate_hash[name] = default.call(name) || Attribute.uninitialized(name, type) + end end - end end end diff --git a/activerecord/lib/active_record/attribute_set/yaml_encoder.rb b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb index 6208048231..c86cfc4263 100644 --- a/activerecord/lib/active_record/attribute_set/yaml_encoder.rb +++ b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb @@ -2,13 +2,13 @@ module ActiveRecord class AttributeSet # Attempts to do more intelligent YAML dumping of an # ActiveRecord::AttributeSet to reduce the size of the resulting string - class YAMLEncoder + class YAMLEncoder # :nodoc: def initialize(default_types) @default_types = default_types end def encode(attribute_set, coder) - coder['concise_attributes'] = attribute_set.each_value.map do |attr| + coder["concise_attributes"] = attribute_set.each_value.map do |attr| if attr.type.equal?(default_types[attr.name]) attr.with_type(nil) else @@ -18,10 +18,10 @@ module ActiveRecord end def decode(coder) - if coder['attributes'] - coder['attributes'] + if coder["attributes"] + coder["attributes"] else - attributes_hash = Hash[coder['concise_attributes'].map do |attr| + attributes_hash = Hash[coder["concise_attributes"].map do |attr| if attr.type.nil? attr = attr.with_type(default_types[attr.name]) end @@ -33,7 +33,7 @@ module ActiveRecord protected - attr_reader :default_types + attr_reader :default_types end end end diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb index 519de271c3..dcbfca1c04 100644 --- a/activerecord/lib/active_record/attributes.rb +++ b/activerecord/lib/active_record/attributes.rb @@ -1,4 +1,4 @@ -require 'active_record/attribute/user_provided_default' +require "active_record/attribute/user_provided_default" module ActiveRecord # See ActiveRecord::Attributes::ClassMethods for documentation @@ -34,10 +34,10 @@ module ActiveRecord # is not passed, the previous default value (if any) will be used. # Otherwise, the default will be +nil+. # - # +array+ (PG only) specifies that the type should be an array (see the + # +array+ (PostgreSQL only) specifies that the type should be an array (see the # examples below). # - # +range+ (PG only) specifies that the type should be a range (see the + # +range+ (PostgreSQL only) specifies that the type should be a range (see the # examples below). # # ==== Examples @@ -116,7 +116,7 @@ module ActiveRecord # Users may also define their own custom types, as long as they respond # to the methods defined on the value type. The method +deserialize+ or # +cast+ will be called on your type object, with raw input from the - # database or from your controllers. See ActiveRecord::Type::Value for the + # database or from your controllers. See ActiveModel::Type::Value for the # expected API. It is recommended that your type objects inherit from an # existing type, or from ActiveRecord::Type::Value # @@ -143,7 +143,7 @@ module ActiveRecord # store_listing.price_in_cents # => 1000 # # For more details on creating custom types, see the documentation for - # ActiveRecord::Type::Value. For more details on registering your types + # ActiveModel::Type::Value. For more details on registering your types # to be referenced by a symbol, see ActiveRecord::Type.register. You can # also pass a type object directly, in place of a symbol. # @@ -190,7 +190,7 @@ module ActiveRecord # The type of an attribute is given the opportunity to change how dirty # tracking is performed. The methods +changed?+ and +changed_in_place?+ # will be called from ActiveModel::Dirty. See the documentation for those - # methods in ActiveRecord::Type::Value for more details. + # methods in ActiveModel::Type::Value for more details. def attribute(name, cast_type, **options) name = name.to_s reload_schema_from_cache @@ -242,24 +242,24 @@ module ActiveRecord private - NO_DEFAULT_PROVIDED = Object.new # :nodoc: - private_constant :NO_DEFAULT_PROVIDED + NO_DEFAULT_PROVIDED = Object.new # :nodoc: + private_constant :NO_DEFAULT_PROVIDED - def define_default_attribute(name, value, type, from_user:) - if value == NO_DEFAULT_PROVIDED - default_attribute = _default_attributes[name].with_type(type) - elsif from_user - default_attribute = Attribute::UserProvidedDefault.new( - name, - value, - type, - _default_attributes[name], - ) - else - default_attribute = Attribute.from_database(name, value, type) + def define_default_attribute(name, value, type, from_user:) + if value == NO_DEFAULT_PROVIDED + default_attribute = _default_attributes[name].with_type(type) + elsif from_user + default_attribute = Attribute::UserProvidedDefault.new( + name, + value, + type, + _default_attributes.fetch(name.to_s) { nil }, + ) + else + default_attribute = Attribute.from_database(name, value, type) + end + _default_attributes[name] = default_attribute end - _default_attributes[name] = default_attribute - end end end end diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 06c7482bf9..d3e0dee731 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -329,26 +329,20 @@ module ActiveRecord return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?) validation_context = self.validation_context unless [:create, :update].include?(self.validation_context) + unless valid = record.valid?(validation_context) if reflection.options[:autosave] indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors) record.errors.each do |attribute, message| - if indexed_attribute - attribute = "#{reflection.name}[#{index}].#{attribute}" - else - attribute = "#{reflection.name}.#{attribute}" - end + attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute) errors[attribute] << message errors[attribute].uniq! end record.errors.details.each_key do |attribute| - if indexed_attribute - reflection_attribute = "#{reflection.name}[#{index}].#{attribute}" - else - reflection_attribute = "#{reflection.name}.#{attribute}" - end + reflection_attribute = + normalize_reflection_attribute(indexed_attribute, reflection, index, attribute).to_sym record.errors.details[attribute].each do |error| errors.details[reflection_attribute] << error @@ -362,6 +356,14 @@ module ActiveRecord valid end + def normalize_reflection_attribute(indexed_attribute, reflection, index, attribute) + if indexed_attribute + "#{reflection.name}[#{index}].#{attribute}" + else + "#{reflection.name}.#{attribute}" + end + end + # Is used as a before_save callback to check while saving a collection # association whether or not the parent was a new record before saving. def before_save_collection_association @@ -400,7 +402,7 @@ module ActiveRecord association.insert_record(record) unless reflection.nested? end elsif autosave - saved = record.save(:validate => false) + saved = record.save(validate: false) end raise ActiveRecord::Rollback unless saved @@ -437,7 +439,7 @@ module ActiveRecord record[reflection.foreign_key] = key end - saved = record.save(:validate => !autosave) + saved = record.save(validate: !autosave) raise ActiveRecord::Rollback if !saved && autosave saved end @@ -457,7 +459,9 @@ module ActiveRecord # In addition, it will destroy the association if it was marked for destruction. def save_belongs_to_association(reflection) association = association_instance_get(reflection.name) - record = association && association.load_target + return unless association && association.loaded? && !association.stale_target? + + record = association.load_target if record && !record.destroyed? autosave = reflection.options[:autosave] @@ -465,7 +469,7 @@ module ActiveRecord self[reflection.foreign_key] = nil record.destroy elsif autosave != false - saved = record.save(:validate => !autosave) if record.new_record? || (autosave && record.changed_for_autosave?) + saved = record.save(validate: !autosave) if record.new_record? || (autosave && record.changed_for_autosave?) if association.updated? association_id = record.send(reflection.options[:primary_key] || :id) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 6a1a27ce41..1e7e939097 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1,25 +1,25 @@ -require 'yaml' -require 'active_support/benchmarkable' -require 'active_support/dependencies' -require 'active_support/descendants_tracker' -require 'active_support/time' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/hash/transform_values' -require 'active_support/core_ext/string/behavior' -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/introspection' -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/class/subclasses' -require 'active_record/attribute_decorators' -require 'active_record/errors' -require 'active_record/log_subscriber' -require 'active_record/explain_subscriber' -require 'active_record/relation/delegation' -require 'active_record/attributes' -require 'active_record/type_caster' +require "yaml" +require "active_support/benchmarkable" +require "active_support/dependencies" +require "active_support/descendants_tracker" +require "active_support/time" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/hash/transform_values" +require "active_support/core_ext/string/behavior" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/class/subclasses" +require "active_record/attribute_decorators" +require "active_record/errors" +require "active_record/log_subscriber" +require "active_record/explain_subscriber" +require "active_record/relation/delegation" +require "active_record/attributes" +require "active_record/type_caster" module ActiveRecord #:nodoc: # = Active Record @@ -312,8 +312,8 @@ module ActiveRecord #:nodoc: include NestedAttributes include Aggregations include Transactions - include NoTouching include TouchLater + include NoTouching include Reflection include Serialization include Store diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 95de6937af..c616733aa4 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -272,7 +272,7 @@ module ActiveRecord included do include ActiveModel::Validations::Callbacks - define_model_callbacks :initialize, :find, :touch, :only => :after + define_model_callbacks :initialize, :find, :touch, only: :after define_model_callbacks :save, :create, :update, :destroy end diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb index 2456b8ad8c..1c8c9fa272 100644 --- a/activerecord/lib/active_record/coders/yaml_column.rb +++ b/activerecord/lib/active_record/coders/yaml_column.rb @@ -1,9 +1,9 @@ -require 'yaml' +require "yaml" +require "active_support/core_ext/regexp" module ActiveRecord module Coders # :nodoc: class YAMLColumn # :nodoc: - attr_accessor :object_class def initialize(object_class = Object) @@ -20,7 +20,7 @@ module ActiveRecord def load(yaml) return object_class.new if object_class != Object && yaml.nil? - return yaml unless yaml.is_a?(String) && yaml =~ /^---/ + return yaml unless yaml.is_a?(String) && /^---/.match?(yaml) obj = YAML.load(yaml) assert_valid_value(obj) @@ -38,13 +38,13 @@ module ActiveRecord private - def check_arity_of_constructor - begin - load(nil) - rescue ArgumentError - raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor." + def check_arity_of_constructor + begin + load(nil) + rescue ArgumentError + raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor." + end end - end end end end diff --git a/activerecord/lib/active_record/collection_cache_key.rb b/activerecord/lib/active_record/collection_cache_key.rb index 8d41c0d799..43784b70e3 100644 --- a/activerecord/lib/active_record/collection_cache_key.rb +++ b/activerecord/lib/active_record/collection_cache_key.rb @@ -1,6 +1,5 @@ module ActiveRecord module CollectionCacheKey - def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc: query_signature = Digest::MD5.hexdigest(collection.to_sql) key = "#{collection.model_name.cache_key}/query-#{query_signature}" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index c341773be1..2d62fd8d50 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -1,6 +1,6 @@ -require 'thread' -require 'concurrent/map' -require 'monitor' +require "thread" +require "concurrent/map" +require "monitor" module ActiveRecord # Raised when a connection could not be obtained within the connection @@ -74,7 +74,7 @@ module ActiveRecord #-- # Synchronization policy: # * all public methods can be called outside +synchronize+ - # * access to these i-vars needs to be in +synchronize+: + # * access to these instance variables needs to be in +synchronize+: # * @connections # * @now_connecting # * private methods that require being called in a +synchronize+ blocks @@ -150,61 +150,61 @@ module ActiveRecord private - def internal_poll(timeout) - no_wait_poll || (timeout && wait_poll(timeout)) - end + def internal_poll(timeout) + no_wait_poll || (timeout && wait_poll(timeout)) + end - def synchronize(&block) - @lock.synchronize(&block) - end + def synchronize(&block) + @lock.synchronize(&block) + end - # Test if the queue currently contains any elements. - def any? - !@queue.empty? - end + # Test if the queue currently contains any elements. + def any? + !@queue.empty? + end - # A thread can remove an element from the queue without - # waiting if and only if the number of currently available - # connections is strictly greater than the number of waiting - # threads. - def can_remove_no_wait? - @queue.size > @num_waiting - end + # A thread can remove an element from the queue without + # waiting if and only if the number of currently available + # connections is strictly greater than the number of waiting + # threads. + def can_remove_no_wait? + @queue.size > @num_waiting + end - # Removes and returns the head of the queue if possible, or nil. - def remove - @queue.shift - end + # Removes and returns the head of the queue if possible, or nil. + def remove + @queue.shift + end - # Remove and return the head the queue if the number of - # available elements is strictly greater than the number of - # threads currently waiting. Otherwise, return nil. - def no_wait_poll - remove if can_remove_no_wait? - end + # Remove and return the head the queue if the number of + # available elements is strictly greater than the number of + # threads currently waiting. Otherwise, return nil. + def no_wait_poll + remove if can_remove_no_wait? + end - # Waits on the queue up to +timeout+ seconds, then removes and - # returns the head of the queue. - def wait_poll(timeout) - @num_waiting += 1 + # Waits on the queue up to +timeout+ seconds, then removes and + # returns the head of the queue. + def wait_poll(timeout) + @num_waiting += 1 - t0 = Time.now - elapsed = 0 - loop do - @cond.wait(timeout - elapsed) + t0 = Time.now + elapsed = 0 + loop do + @cond.wait(timeout - elapsed) - return remove if any? + return remove if any? - elapsed = Time.now - t0 - if elapsed >= timeout - msg = 'could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use' % - [timeout, elapsed] - raise ConnectionTimeoutError, msg + elapsed = Time.now - t0 + if elapsed >= timeout + msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" % + [timeout, elapsed] + raise ConnectionTimeoutError, msg + end end + ensure + @num_waiting -= 1 end - ensure - @num_waiting -= 1 - end end # Adds the ability to turn a basic fair FIFO queue into one @@ -274,11 +274,11 @@ module ActiveRecord include BiasableQueue private - def internal_poll(timeout) - conn = super - conn.lease if conn - conn - end + def internal_poll(timeout) + conn = super + conn.lease if conn + conn + end end # Every +frequency+ seconds, the reaper will call +reap+ on +pool+. @@ -329,17 +329,17 @@ module ActiveRecord # default max pool size to 5 @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5 - # The cache of threads mapped to reserved connections, the sole purpose - # of the cache is to speed-up +connection+ method, it is not the authoritative - # registry of which thread owns which connection, that is tracked by - # +connection.owner+ attr on each +connection+ instance. + # This variable tracks the cache of threads mapped to reserved connections, with the + # sole purpose of speeding up the +connection+ method. It is not the authoritative + # registry of which thread owns which connection. Connection ownership is tracked by + # the +connection.owner+ attr on each +connection+ instance. # The invariant works like this: if there is mapping of <tt>thread => conn</tt>, - # then that +thread+ does indeed own that +conn+, however an absence of a such - # mapping does not mean that the +thread+ doesn't own the said connection, in + # then that +thread+ does indeed own that +conn+. However, an absence of a such + # mapping does not mean that the +thread+ doesn't own the said connection. In # that case +conn.owner+ attr should be consulted. # Access and modification of +@thread_cached_conns+ does not require # synchronization. - @thread_cached_conns = Concurrent::Map.new(:initial_capacity => @size) + @thread_cached_conns = Concurrent::Map.new(initial_capacity: @size) @connections = [] @automatic_reconnect = true @@ -364,10 +364,10 @@ module ActiveRecord @thread_cached_conns[connection_cache_key(Thread.current)] ||= checkout end - # Is there an open connection that is being used for the current thread? + # Returns true if there is an open connection being used for the current thread. # # This method only works for connections that have been obtained through - # #connection or #with_connection methods, connections obtained through + # #connection or #with_connection methods. Connections obtained through # #checkout will not be detected by #active_connection? def active_connection? @thread_cached_conns[connection_cache_key(Thread.current)] @@ -415,7 +415,10 @@ module ActiveRecord with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do synchronize do @connections.each do |conn| - checkin conn + if conn.in_use? + conn.steal! + checkin conn + end conn.disconnect! end @connections = [] @@ -426,9 +429,9 @@ module ActiveRecord # Disconnects all connections in the pool, and clears the pool. # - # The pool first tries to gain ownership of all connections, if unable to + # The pool first tries to gain ownership of all connections. If unable to # do so within a timeout interval (default duration is - # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), the pool is forcefully + # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), then the pool is forcefully # disconnected without any regard for other connection owning threads. def disconnect! disconnect(false) @@ -447,7 +450,10 @@ module ActiveRecord with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do synchronize do @connections.each do |conn| - checkin conn + if conn.in_use? + conn.steal! + checkin conn + end conn.disconnect! if conn.requires_reloading? end @connections.delete_if(&:requires_reloading?) @@ -474,9 +480,9 @@ module ActiveRecord # Clears the cache which maps classes and re-connects connections that # require reloading. # - # The pool first tries to gain ownership of all connections, if unable to + # The pool first tries to gain ownership of all connections. If unable to # do so within a timeout interval (default duration is - # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), the pool forcefully + # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), then the pool forcefully # clears the cache and reloads connections without any regard for other # connection owning threads. def clear_reloadable_connections! @@ -530,20 +536,20 @@ module ActiveRecord @available.delete conn # @available.any_waiting? => true means that prior to removing this - # conn, the pool was at its max size (@connections.size == @size) - # this would mean that any threads stuck waiting in the queue wouldn't + # conn, the pool was at its max size (@connections.size == @size). + # This would mean that any threads stuck waiting in the queue wouldn't # know they could checkout_new_connection, so let's do it for them. # Because condition-wait loop is encapsulated in the Queue class # (that in turn is oblivious to ConnectionPool implementation), threads - # that are "stuck" there are helpless, they have no way of creating + # that are "stuck" there are helpless. They have no way of creating # new connections and are completely reliant on us feeding available # connections into the Queue. needs_new_connection = @available.any_waiting? end # This is intentionally done outside of the synchronized section as we - # would like not to hold the main mutex while checking out new connections, - # thus there is some chance that needs_new_connection information is now + # would like not to hold the main mutex while checking out new connections. + # Thus there is some chance that needs_new_connection information is now # stale, we can live with that (bulk_make_new_connections will make # sure not to exceed the pool's @size limit). bulk_make_new_connections(1) if needs_new_connection @@ -556,17 +562,17 @@ module ActiveRecord stale_connections = synchronize do @connections.select do |conn| conn.in_use? && !conn.owner.alive? + end.each do |conn| + conn.steal! end end stale_connections.each do |conn| - synchronize do - if conn.active? - conn.reset! - checkin conn - else - remove conn - end + if conn.active? + conn.reset! + checkin conn + else + remove conn end end end @@ -576,205 +582,205 @@ module ActiveRecord end private - #-- - # this is unfortunately not concurrent - def bulk_make_new_connections(num_new_conns_needed) - num_new_conns_needed.times do - # try_to_checkout_new_connection will not exceed pool's @size limit - if new_conn = try_to_checkout_new_connection - # make the new_conn available to the starving threads stuck @available Queue - checkin(new_conn) + #-- + # this is unfortunately not concurrent + def bulk_make_new_connections(num_new_conns_needed) + num_new_conns_needed.times do + # try_to_checkout_new_connection will not exceed pool's @size limit + if new_conn = try_to_checkout_new_connection + # make the new_conn available to the starving threads stuck @available Queue + checkin(new_conn) + end end end - end - #-- - # From the discussion on GitHub: - # https://github.com/rails/rails/pull/14938#commitcomment-6601951 - # This hook-in method allows for easier monkey-patching fixes needed by - # JRuby users that use Fibers. - def connection_cache_key(thread) - thread - end - - # Take control of all existing connections so a "group" action such as - # reload/disconnect can be performed safely. It is no longer enough to - # wrap it in +synchronize+ because some pool's actions are allowed - # to be performed outside of the main +synchronize+ block. - def with_exclusively_acquired_all_connections(raise_on_acquisition_timeout = true) - with_new_connections_blocked do - attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout) - yield + #-- + # From the discussion on GitHub: + # https://github.com/rails/rails/pull/14938#commitcomment-6601951 + # This hook-in method allows for easier monkey-patching fixes needed by + # JRuby users that use Fibers. + def connection_cache_key(thread) + thread end - end - def attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout = true) - collected_conns = synchronize do - # account for our own connections - @connections.select {|conn| conn.owner == Thread.current} + # Take control of all existing connections so a "group" action such as + # reload/disconnect can be performed safely. It is no longer enough to + # wrap it in +synchronize+ because some pool's actions are allowed + # to be performed outside of the main +synchronize+ block. + def with_exclusively_acquired_all_connections(raise_on_acquisition_timeout = true) + with_new_connections_blocked do + attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout) + yield + end end - newly_checked_out = [] - timeout_time = Time.now + (@checkout_timeout * 2) + def attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout = true) + collected_conns = synchronize do + # account for our own connections + @connections.select { |conn| conn.owner == Thread.current } + end + + newly_checked_out = [] + timeout_time = Time.now + (@checkout_timeout * 2) - @available.with_a_bias_for(Thread.current) do - loop do - synchronize do - return if collected_conns.size == @connections.size && @now_connecting == 0 - remaining_timeout = timeout_time - Time.now - remaining_timeout = 0 if remaining_timeout < 0 - conn = checkout_for_exclusive_access(remaining_timeout) - collected_conns << conn - newly_checked_out << conn + @available.with_a_bias_for(Thread.current) do + loop do + synchronize do + return if collected_conns.size == @connections.size && @now_connecting == 0 + remaining_timeout = timeout_time - Time.now + remaining_timeout = 0 if remaining_timeout < 0 + conn = checkout_for_exclusive_access(remaining_timeout) + collected_conns << conn + newly_checked_out << conn + end end end - end - rescue ExclusiveConnectionTimeoutError - # <tt>raise_on_acquisition_timeout == false</tt> means we are directed to ignore any - # timeouts and are expected to just give up: we've obtained as many connections - # as possible, note that in a case like that we don't return any of the - # +newly_checked_out+ connections. - - if raise_on_acquisition_timeout + rescue ExclusiveConnectionTimeoutError + # <tt>raise_on_acquisition_timeout == false</tt> means we are directed to ignore any + # timeouts and are expected to just give up: we've obtained as many connections + # as possible, note that in a case like that we don't return any of the + # +newly_checked_out+ connections. + + if raise_on_acquisition_timeout + release_newly_checked_out = true + raise + end + rescue Exception # if something else went wrong + # this can't be a "naked" rescue, because we have should return conns + # even for non-StandardErrors release_newly_checked_out = true raise + ensure + if release_newly_checked_out && newly_checked_out + # releasing only those conns that were checked out in this method, conns + # checked outside this method (before it was called) are not for us to release + newly_checked_out.each { |conn| checkin(conn) } + end end - rescue Exception # if something else went wrong - # this can't be a "naked" rescue, because we have should return conns - # even for non-StandardErrors - release_newly_checked_out = true - raise - ensure - if release_newly_checked_out && newly_checked_out - # releasing only those conns that were checked out in this method, conns - # checked outside this method (before it was called) are not for us to release - newly_checked_out.each {|conn| checkin(conn)} - end - end - #-- - # Must be called in a synchronize block. - def checkout_for_exclusive_access(checkout_timeout) - checkout(checkout_timeout) - rescue ConnectionTimeoutError - # this block can't be easily moved into attempt_to_checkout_all_existing_connections's - # rescue block, because doing so would put it outside of synchronize section, without - # being in a critical section thread_report might become inaccurate - msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds" - - thread_report = [] - @connections.each do |conn| - unless conn.owner == Thread.current - thread_report << "#{conn} is owned by #{conn.owner}" + #-- + # Must be called in a synchronize block. + def checkout_for_exclusive_access(checkout_timeout) + checkout(checkout_timeout) + rescue ConnectionTimeoutError + # this block can't be easily moved into attempt_to_checkout_all_existing_connections's + # rescue block, because doing so would put it outside of synchronize section, without + # being in a critical section thread_report might become inaccurate + msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds" + + thread_report = [] + @connections.each do |conn| + unless conn.owner == Thread.current + thread_report << "#{conn} is owned by #{conn.owner}" + end end - end - msg << " (#{thread_report.join(', ')})" if thread_report.any? + msg << " (#{thread_report.join(', ')})" if thread_report.any? - raise ExclusiveConnectionTimeoutError, msg - end + raise ExclusiveConnectionTimeoutError, msg + end - def with_new_connections_blocked - previous_value = nil - synchronize do - previous_value, @new_cons_enabled = @new_cons_enabled, false + def with_new_connections_blocked + previous_value = nil + synchronize do + previous_value, @new_cons_enabled = @new_cons_enabled, false + end + yield + ensure + synchronize { @new_cons_enabled = previous_value } end - yield - ensure - synchronize { @new_cons_enabled = previous_value } - end - # Acquire a connection by one of 1) immediately removing one - # from the queue of available connections, 2) creating a new - # connection if the pool is not at capacity, 3) waiting on the - # queue for a connection to become available. - # - # Raises: - # - ActiveRecord::ConnectionTimeoutError if a connection could not be acquired - # - #-- - # Implementation detail: the connection returned by +acquire_connection+ - # will already be "+connection.lease+ -ed" to the current thread. - def acquire_connection(checkout_timeout) - # NOTE: we rely on +@available.poll+ and +try_to_checkout_new_connection+ to - # +conn.lease+ the returned connection (and to do this in a +synchronized+ - # section), this is not the cleanest implementation, as ideally we would - # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to +@available.poll+ - # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections - # of the said methods and avoid an additional +synchronize+ overhead. - if conn = @available.poll || try_to_checkout_new_connection - conn - else - reap - @available.poll(checkout_timeout) + # Acquire a connection by one of 1) immediately removing one + # from the queue of available connections, 2) creating a new + # connection if the pool is not at capacity, 3) waiting on the + # queue for a connection to become available. + # + # Raises: + # - ActiveRecord::ConnectionTimeoutError if a connection could not be acquired + # + #-- + # Implementation detail: the connection returned by +acquire_connection+ + # will already be "+connection.lease+ -ed" to the current thread. + def acquire_connection(checkout_timeout) + # NOTE: we rely on +@available.poll+ and +try_to_checkout_new_connection+ to + # +conn.lease+ the returned connection (and to do this in a +synchronized+ + # section). This is not the cleanest implementation, as ideally we would + # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to +@available.poll+ + # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections + # of the said methods and avoid an additional +synchronize+ overhead. + if conn = @available.poll || try_to_checkout_new_connection + conn + else + reap + @available.poll(checkout_timeout) + end end - end - #-- - # if owner_thread param is omitted, this must be called in synchronize block - def remove_connection_from_thread_cache(conn, owner_thread = conn.owner) - @thread_cached_conns.delete_pair(connection_cache_key(owner_thread), conn) - end - alias_method :release, :remove_connection_from_thread_cache + #-- + # if owner_thread param is omitted, this must be called in synchronize block + def remove_connection_from_thread_cache(conn, owner_thread = conn.owner) + @thread_cached_conns.delete_pair(connection_cache_key(owner_thread), conn) + end + alias_method :release, :remove_connection_from_thread_cache - def new_connection - Base.send(spec.adapter_method, spec.config).tap do |conn| - conn.schema_cache = schema_cache.dup if schema_cache + def new_connection + Base.send(spec.adapter_method, spec.config).tap do |conn| + conn.schema_cache = schema_cache.dup if schema_cache + end end - end - # If the pool is not at a +@size+ limit, establish new connection. Connecting - # to the DB is done outside main synchronized section. - #-- - # Implementation constraint: a newly established connection returned by this - # method must be in the +.leased+ state. - def try_to_checkout_new_connection - # first in synchronized section check if establishing new conns is allowed - # and increment @now_connecting, to prevent overstepping this pool's @size - # constraint - do_checkout = synchronize do - if @new_cons_enabled && (@connections.size + @now_connecting) < @size - @now_connecting += 1 - end - end - if do_checkout - begin - # if successfully incremented @now_connecting establish new connection - # outside of synchronized section - conn = checkout_new_connection - ensure - synchronize do - if conn - adopt_connection(conn) - # returned conn needs to be already leased - conn.lease + # If the pool is not at a +@size+ limit, establish new connection. Connecting + # to the DB is done outside main synchronized section. + #-- + # Implementation constraint: a newly established connection returned by this + # method must be in the +.leased+ state. + def try_to_checkout_new_connection + # first in synchronized section check if establishing new conns is allowed + # and increment @now_connecting, to prevent overstepping this pool's @size + # constraint + do_checkout = synchronize do + if @new_cons_enabled && (@connections.size + @now_connecting) < @size + @now_connecting += 1 + end + end + if do_checkout + begin + # if successfully incremented @now_connecting establish new connection + # outside of synchronized section + conn = checkout_new_connection + ensure + synchronize do + if conn + adopt_connection(conn) + # returned conn needs to be already leased + conn.lease + end + @now_connecting -= 1 end - @now_connecting -= 1 end end end - end - def adopt_connection(conn) - conn.pool = self - @connections << conn - end + def adopt_connection(conn) + conn.pool = self + @connections << conn + end - def checkout_new_connection - raise ConnectionNotEstablished unless @automatic_reconnect - new_connection - end + def checkout_new_connection + raise ConnectionNotEstablished unless @automatic_reconnect + new_connection + end - def checkout_and_verify(c) - c._run_checkout_callbacks do - c.verify! + def checkout_and_verify(c) + c._run_checkout_callbacks do + c.verify! + end + c + rescue + remove c + c.disconnect! + raise end - c - rescue - remove c - c.disconnect! - raise - end end # ConnectionHandler is a collection of ConnectionPool objects. It is used @@ -822,13 +828,13 @@ module ActiveRecord # should use. # # The ConnectionHandler class is not coupled with the Active models, as it has no knowlodge - # about the model. The model, needs to pass a specification name to the handler, + # about the model. The model needs to pass a specification name to the handler, # in order to lookup the correct connection pool. class ConnectionHandler def initialize # These caches are keyed by spec.name (ConnectionSpecification#name). - @owner_to_pool = Concurrent::Map.new(:initial_capacity => 2) do |h,k| - h[k] = Concurrent::Map.new(:initial_capacity => 2) + @owner_to_pool = Concurrent::Map.new(initial_capacity: 2) do |h,k| + h[k] = Concurrent::Map.new(initial_capacity: 2) end end @@ -842,7 +848,21 @@ module ActiveRecord spec = resolver.spec(config) remove_connection(spec.name) - owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec) + + message_bus = ActiveSupport::Notifications.instrumenter + payload = { + connection_id: object_id + } + if spec + payload[:spec_name] = spec.name + payload[:config] = spec.config + end + + message_bus.instrument("!connection.active_record", payload) do + owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec) + end + + owner_to_pool[spec.name] end # Returns true if there are any active connections among the connection @@ -875,7 +895,7 @@ module ActiveRecord # for (not necessarily the current class). def retrieve_connection(spec_name) #:nodoc: pool = retrieve_connection_pool(spec_name) - raise ConnectionNotEstablished, "No connection pool with id '#{spec_name}' found." unless pool + raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool conn = pool.connection raise ConnectionNotEstablished, "No connection for '#{spec_name}' in connection pool" unless conn conn @@ -890,7 +910,7 @@ module ActiveRecord # Remove the connection for this class. This will close the active # connection and the defined connection (if they exist). The result - # can be used as an argument for establish_connection, for easily + # can be used as an argument for #establish_connection, for easily # re-establishing the connection. def remove_connection(spec_name) if pool = owner_to_pool.delete(spec_name) @@ -922,14 +942,14 @@ module ActiveRecord private - def owner_to_pool - @owner_to_pool[Process.pid] - end + def owner_to_pool + @owner_to_pool[Process.pid] + end - def pool_from_any_process_for(spec_name) - owner_to_pool = @owner_to_pool.values.find { |v| v[spec_name] } - owner_to_pool && owner_to_pool[spec_name] - end + def pool_from_any_process_for(spec_name) + owner_to_pool = @owner_to_pool.values.find { |v| v[spec_name] } + owner_to_pool && owner_to_pool[spec_name] + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb index 6711049588..95c72f1e20 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb @@ -1,7 +1,6 @@ module ActiveRecord module ConnectionAdapters # :nodoc: module DatabaseLimits - # Returns the maximum length of a table alias. def table_alias_length 255 @@ -61,7 +60,6 @@ module ActiveRecord def joins_per_query 256 end - end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 507a925d32..aa2dfdd573 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -10,7 +10,7 @@ module ActiveRecord def to_sql(arel, binds = []) if arel.respond_to?(:ast) collected = visitor.accept(arel.ast, collector) - collected.compile(binds.dup, self) + collected.compile(binds, self) else arel end @@ -18,11 +18,12 @@ module ActiveRecord # This is used in the StatementCache object. It returns an object that # can be used to query the database repeatedly. - def cacheable_query(arel) # :nodoc: + def cacheable_query(klass, arel) # :nodoc: + collected = visitor.accept(arel.ast, collector) if prepared_statements - ActiveRecord::StatementCache.query visitor, arel.ast + klass.query(collected.value) else - ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector + klass.partial_query(collected.value) end end @@ -81,21 +82,22 @@ module ActiveRecord # Executes +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. - def exec_query(sql, name = 'SQL', binds = [], prepare: false) + def exec_query(sql, name = "SQL", binds = [], prepare: false) raise NotImplementedError end # Executes insert +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. - def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) + def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) + sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds) exec_query(sql, name, binds) end # Executes delete +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. - def exec_delete(sql, name, binds) + def exec_delete(sql, name = nil, binds = []) exec_query(sql, name, binds) end @@ -107,7 +109,7 @@ module ActiveRecord # Executes update +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. - def exec_update(sql, name, binds) + def exec_update(sql, name = nil, binds = []) exec_query(sql, name, binds) end @@ -120,8 +122,7 @@ module ActiveRecord # If the next id was calculated in advance (as in Oracle), it should be # passed in as +id_value+. def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) - sql, binds, pk, sequence_name = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds) - value = exec_insert(sql, name, binds, pk, sequence_name) + value = exec_insert(to_sql(arel, binds), name, binds, pk, sequence_name) id_value || last_inserted_id(value) end alias create insert @@ -244,7 +245,7 @@ module ActiveRecord end def reset_transaction #:nodoc: - @transaction_manager = TransactionManager.new(self) + @transaction_manager = ConnectionAdapters::TransactionManager.new(self) end # Register a record with the current transaction so that its after_commit and after_rollback callbacks @@ -315,7 +316,7 @@ module ActiveRecord end end key_list = fixture.keys.map { |name| quote_column_name(name) } - value_list = prepare_binds_for_database(binds).map do |value| + value_list = binds.map(&:value_for_database).map do |value| begin quote(value) rescue TypeError @@ -323,7 +324,7 @@ module ActiveRecord end end - execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert' + execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", "Fixture Insert" end def empty_insert_statement_value @@ -342,8 +343,8 @@ module ActiveRecord def sanitize_limit(limit) if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral) limit - elsif limit.to_s.include?(',') - Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',') + elsif limit.to_s.include?(",") + Arel.sql limit.to_s.split(",").map { |i| Integer(i) }.join(",") else Integer(limit) end @@ -378,7 +379,7 @@ module ActiveRecord end def sql_for_insert(sql, pk, id_value, sequence_name, binds) - [sql, binds, pk, sequence_name] + [sql, binds] end def last_inserted_id(result) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 0bdfd4f900..2f8a89e88e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -65,7 +65,7 @@ module ActiveRecord if @query_cache_enabled && !locked?(arel) arel, binds = binds_from_relation arel, binds sql = to_sql(arel, binds) - cache_sql(sql, binds) { super(sql, name, binds, preparable: preparable) } + cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) } else super end @@ -73,23 +73,29 @@ module ActiveRecord private - def cache_sql(sql, binds) - result = - if @query_cache[sql].key?(binds) - ActiveSupport::Notifications.instrument("sql.active_record", - :sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id) - @query_cache[sql][binds] - else - @query_cache[sql][binds] = yield - end - result.dup - end + def cache_sql(sql, name, binds) + result = + if @query_cache[sql].key?(binds) + ActiveSupport::Notifications.instrument( + "sql.active_record", + sql: sql, + binds: binds, + name: name, + connection_id: object_id, + cached: true, + ) + @query_cache[sql][binds] + else + @query_cache[sql][binds] = yield + end + result.dup + end - # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such - # queries should not be cached. - def locked?(arel) - arel.respond_to?(:locked) && arel.locked - end + # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such + # queries should not be cached. + def locked?(arel) + arel.respond_to?(:locked) && arel.locked + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index 860ef17dca..bbd52b8a91 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/big_decimal/conversions' +require "active_support/core_ext/big_decimal/conversions" module ActiveRecord module ConnectionAdapters # :nodoc: @@ -112,19 +112,19 @@ module ActiveRecord end def quoted_true - "'t'" + "'t'".freeze end def unquoted_true - 't' + "t".freeze end def quoted_false - "'f'" + "'f'".freeze end def unquoted_false - 'f' + "f".freeze end # Quote date/time values for use in SQL input. Includes microseconds @@ -147,52 +147,52 @@ module ActiveRecord end def quoted_time(value) # :nodoc: - quoted_date(value).sub(/\A2000-01-01 /, '') - end - - def prepare_binds_for_database(binds) # :nodoc: - binds.map(&:value_for_database) + quoted_date(value).sub(/\A2000-01-01 /, "") end private - def types_which_need_no_typecasting - [nil, Numeric, String] - end - - def _quote(value) - case value - when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data - "'#{quote_string(value.to_s)}'" - when true then quoted_true - when false then quoted_false - when nil then "NULL" - # BigDecimals need to be put in a non-normalized form and quoted. - when BigDecimal then value.to_s('F') - when Numeric, ActiveSupport::Duration then value.to_s - when Type::Time::Value then "'#{quoted_time(value)}'" - when Date, Time then "'#{quoted_date(value)}'" - when Symbol then "'#{quote_string(value.to_s)}'" - when Class then "'#{value}'" - else raise TypeError, "can't quote #{value.class.name}" + def type_casted_binds(binds) + binds.map { |attr| type_cast(attr.value_for_database) } end - end - def _type_cast(value) - case value - when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data - value.to_s - when true then unquoted_true - when false then unquoted_false - # BigDecimals need to be put in a non-normalized form and quoted. - when BigDecimal then value.to_s('F') - when Type::Time::Value then quoted_time(value) - when Date, Time then quoted_date(value) - when *types_which_need_no_typecasting - value - else raise TypeError + def types_which_need_no_typecasting + [nil, Numeric, String] + end + + def _quote(value) + case value + when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data + "'#{quote_string(value.to_s)}'" + when true then quoted_true + when false then quoted_false + when nil then "NULL" + # BigDecimals need to be put in a non-normalized form and quoted. + when BigDecimal then value.to_s("F") + when Numeric, ActiveSupport::Duration then value.to_s + when Type::Time::Value then "'#{quoted_time(value)}'" + when Date, Time then "'#{quoted_date(value)}'" + when Symbol then "'#{quote_string(value.to_s)}'" + when Class then "'#{value}'" + else raise TypeError, "can't quote #{value.class.name}" + end + end + + def _type_cast(value) + case value + when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data + value.to_s + when true then unquoted_true + when false then unquoted_false + # BigDecimals need to be put in a non-normalized form and quoted. + when BigDecimal then value.to_s("F") + when Type::Time::Value then quoted_time(value) + when Date, Time then quoted_date(value) + when *types_which_need_no_typecasting + value + else raise TypeError + end end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb index 6add697eeb..322684672f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/strip' +require "active_support/core_ext/string/strip" module ActiveRecord module ConnectionAdapters @@ -23,9 +23,9 @@ module ActiveRecord def visit_AlterTable(o) sql = "ALTER TABLE #{quote_table_name(o.name)} " - sql << o.adds.map { |col| accept col }.join(' ') - sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ') - sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ') + sql << o.adds.map { |col| accept col }.join(" ") + sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ") + sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ") end def visit_ColumnDefinition(o) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 8dbafc5a4b..83d1d7cd01 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -11,7 +11,6 @@ module ActiveRecord # +columns+ attribute of said TableDefinition object, in order to be used # for generating a number of table creation or table changing SQL statements. class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type, :comment) #:nodoc: - def primary_key? primary_key || type.to_sym == :primary_key end @@ -61,9 +60,9 @@ module ActiveRecord end private - def default_primary_key - "id" - end + def default_primary_key + "id" + end end class ReferenceDefinition # :nodoc: @@ -103,51 +102,51 @@ module ActiveRecord protected - attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options + attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options private - def as_options(value, default = {}) - if value.is_a?(Hash) - value - else - default + def as_options(value, default = {}) + if value.is_a?(Hash) + value + else + default + end end - end - def polymorphic_options - as_options(polymorphic, options) - end + def polymorphic_options + as_options(polymorphic, options) + end - def index_options - as_options(index) - end + def index_options + as_options(index) + end - def foreign_key_options - as_options(foreign_key).merge(column: column_name) - end + def foreign_key_options + as_options(foreign_key).merge(column: column_name) + end - def columns - result = [[column_name, type, options]] - if polymorphic - result.unshift(["#{name}_type", :string, polymorphic_options]) + def columns + result = [[column_name, type, options]] + if polymorphic + result.unshift(["#{name}_type", :string, polymorphic_options]) + end + result end - result - end - def column_name - "#{name}_id" - end + def column_name + "#{name}_id" + end - def column_names - columns.map(&:first) - end + def column_names + columns.map(&:first) + end - def foreign_table_name - foreign_key_options.fetch(:to_table) do - Base.pluralize_table_names ? name.to_s.pluralize : name + def foreign_table_name + foreign_key_options.fetch(:to_table) do + Base.pluralize_table_names ? name.to_s.pluralize : name + end end - end end module ColumnMethods @@ -212,7 +211,7 @@ module ActiveRecord def initialize(name, temporary = false, options = nil, as = nil, comment: nil) @columns_hash = {} - @indexes = {} + @indexes = [] @foreign_keys = [] @primary_keys = nil @temporary = temporary @@ -304,7 +303,7 @@ module ActiveRecord # end def column(name, type, options = {}) name = name.to_s - type = type.to_sym + type = type.to_sym if type options = options.dup if @columns_hash[name] && @columns_hash[name].primary_key? @@ -328,7 +327,7 @@ module ActiveRecord # # index(:account_id, name: 'index_projects_on_account_id') def index(column_name, options = {}) - indexes[column_name] = options + indexes << [column_name, options] end def foreign_key(table_name, options = {}) # :nodoc: @@ -342,9 +341,7 @@ module ActiveRecord # <tt>:updated_at</tt> to the table. See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps] # # t.timestamps null: false - def timestamps(*args) - options = args.extract_options! - + def timestamps(**options) options[:null] = false if options[:null].nil? column(:created_at, :datetime, options) @@ -383,13 +380,13 @@ module ActiveRecord end private - def create_column_definition(name, type) - ColumnDefinition.new name, type - end + def create_column_definition(name, type) + ColumnDefinition.new name, type + end - def aliased_types(name, fallback) - 'timestamp' == name ? :datetime : fallback - end + def aliased_types(name, fallback) + "timestamp" == name ? :datetime : fallback + end end class AlterTable # :nodoc: @@ -478,7 +475,7 @@ module ActiveRecord # Checks to see if a column exists. # - # t.string(:name) unless t.column_exists?(:name, :string) + # t.string(:name) unless t.column_exists?(:name, :string) # # See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?] def column_exists?(column_name, type = nil, options = {}) @@ -499,9 +496,9 @@ module ActiveRecord # Checks to see if an index exists. # - # unless t.index_exists?(:branch_id) - # t.index(:branch_id) - # end + # unless t.index_exists?(:branch_id) + # t.index(:branch_id) + # end # # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?] def index_exists?(column_name, options = {}) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb index 677a4c6bd0..06c89ca072 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb @@ -7,10 +7,7 @@ module ActiveRecord # Adapter level by over-writing this code inside the database specific adapters module ColumnDumper def column_spec(column) - spec = Hash[prepare_column_options(column).map { |k, v| [k, "#{k}: #{v}"] }] - spec[:name] = column.name.inspect - spec[:type] = schema_type(column).to_s - spec + [schema_type(column), prepare_column_options(column)] end def column_spec_for_primary_key(column) @@ -40,7 +37,7 @@ module ActiveRecord default = schema_default(column) if column.has_default? spec[:default] = default unless default.nil? - spec[:null] = 'false' unless column.null + spec[:null] = "false" unless column.null if collation = schema_collation(column) spec[:collation] = collation @@ -53,53 +50,53 @@ module ActiveRecord # Lists the valid migration options def migration_keys - [:name, :limit, :precision, :scale, :default, :null, :collation, :comment] + [:limit, :precision, :scale, :default, :null, :collation, :comment] end private - def default_primary_key?(column) - schema_type(column) == :integer - end + def default_primary_key?(column) + schema_type(column) == :integer + end - def schema_type(column) - if column.bigint? - :bigint - else - column.type + def schema_type(column) + if column.bigint? + :bigint + else + column.type + end end - end - def schema_limit(column) - limit = column.limit unless column.bigint? - limit.inspect if limit && limit != native_database_types[column.type][:limit] - end + def schema_limit(column) + limit = column.limit unless column.bigint? + limit.inspect if limit && limit != native_database_types[column.type][:limit] + end - def schema_precision(column) - column.precision.inspect if column.precision - end + def schema_precision(column) + column.precision.inspect if column.precision + end - def schema_scale(column) - column.scale.inspect if column.scale - end + def schema_scale(column) + column.scale.inspect if column.scale + end - def schema_default(column) - type = lookup_cast_type_from_column(column) - default = type.deserialize(column.default) - if default.nil? - schema_expression(column) - else - type.type_cast_for_schema(default) + def schema_default(column) + type = lookup_cast_type_from_column(column) + default = type.deserialize(column.default) + if default.nil? + schema_expression(column) + else + type.type_cast_for_schema(default) + end end - end - def schema_expression(column) - "-> { #{column.default_function.inspect} }" if column.default_function - end + def schema_expression(column) + "-> { #{column.default_function.inspect} }" if column.default_function + end - def schema_collation(column) - column.collation.inspect if column.collation - end + def schema_collation(column) + column.collation.inspect if column.collation + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index eec0bc8518..1df20a0c56 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -1,6 +1,6 @@ -require 'active_record/migration/join_table' -require 'active_support/core_ext/string/access' -require 'digest' +require "active_record/migration/join_table" +require "active_support/core_ext/string/access" +require "digest" module ActiveRecord module ConnectionAdapters # :nodoc: @@ -25,7 +25,7 @@ module ActiveRecord # Truncates a table alias according to the limits of the current adapter. def table_alias_for(table_name) - table_name[0...table_alias_length].tr('.', '_') + table_name[0...table_alias_length].tr(".", "_") end # Returns the relation names useable to back Active Record models. @@ -120,7 +120,7 @@ module ActiveRecord checks = [] checks << lambda { |c| c.name == column_name } checks << lambda { |c| c.type == type } if type - (migration_keys - [:name]).each do |attr| + migration_keys.each do |attr| checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr) end @@ -129,14 +129,9 @@ module ActiveRecord # Returns just a table's primary key def primary_key(table_name) - pks = primary_keys(table_name) - warn <<-WARNING.strip_heredoc if pks.count > 1 - WARNING: Rails does not support composite primary key. - - #{table_name} has composite primary key. Composite primary key is ignored. - WARNING - - pks.first if pks.one? + pk = primary_keys(table_name) + pk = pk.first unless pk.size > 1 + pk end # Creates a new table with the name +table_name+. +table_name+ may either @@ -179,7 +174,7 @@ module ActiveRecord # A Symbol can be used to specify the type of the generated primary key column. # [<tt>:primary_key</tt>] # The name of the primary key, if one is to be added automatically. - # Defaults to +id+. If <tt>:id</tt> is false this option is ignored. + # Defaults to +id+. If <tt>:id</tt> is false, then this option is ignored. # # Note that Active Record models will automatically detect their # primary key. This can be avoided by using @@ -283,16 +278,16 @@ module ActiveRecord result = execute schema_creation.accept td unless supports_indexes_in_create? - td.indexes.each_pair do |column_name, index_options| + td.indexes.each do |column_name, index_options| add_index(table_name, column_name, index_options) end end if supports_comments? && !supports_comments_in_create? - change_table_comment(table_name, comment) if comment + change_table_comment(table_name, comment) if comment.present? td.columns.each do |column| - change_column_comment(table_name, column.name, column.comment) if column.comment + change_column_comment(table_name, column.name, column.comment) if column.comment.present? end end @@ -305,9 +300,9 @@ module ActiveRecord # # Creates a table called 'assemblies_parts' with no id. # create_join_table(:assemblies, :parts) # - # You can pass a +options+ hash can include the following keys: + # You can pass an +options+ hash which can include the following keys: # [<tt>:table_name</tt>] - # Sets the table name overriding the default + # Sets the table name, overriding the default. # [<tt>:column_options</tt>] # Any extra options you want appended to the columns definition. # [<tt>:options</tt>] @@ -344,7 +339,7 @@ module ActiveRecord column_options.reverse_merge!(null: false) type = column_options.delete(:type) || :integer - t1_column, t2_column = [table_1, table_2].map{ |t| t.to_s.singularize.foreign_key } + t1_column, t2_column = [table_1, table_2].map { |t| t.to_s.singularize.foreign_key } create_table(join_table_name, options.merge!(id: false)) do |td| td.send type, t1_column, column_options @@ -433,7 +428,7 @@ module ActiveRecord # t.remove_index :company_id # end # - # See also Table for details on all of the various column transformation. + # See also Table for details on all of the various column transformations. def change_table(table_name, options = {}) if supports_bulk_alter? && options[:bulk] recorder = ActiveRecord::Migration::CommandRecorder.new(self) @@ -483,10 +478,10 @@ module ActiveRecord # # Available options are (none of these exists by default): # * <tt>:limit</tt> - - # Requests a maximum column length. This is number of characters for a <tt>:string</tt> column + # Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column # and number of bytes for <tt>:text</tt>, <tt>:binary</tt> and <tt>:integer</tt> columns. # * <tt>:default</tt> - - # The column's default value. Use nil for NULL. + # The column's default value. Use +nil+ for +NULL+. # * <tt>:null</tt> - # Allows or disallows +NULL+ values in the column. This option could # have been named <tt>:null_allowed</tt>. @@ -495,7 +490,7 @@ module ActiveRecord # * <tt>:scale</tt> - # Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns. # - # Note: The precision is the total number of significant digits + # Note: The precision is the total number of significant digits, # and the scale is the number of digits that can be stored following # the decimal point. For example, the number 123.45 has a precision of 5 # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can @@ -516,7 +511,7 @@ module ActiveRecord # Default is (38,0). # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62]. # Default unknown. - # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38]. + # * SqlServer: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38]. # Default (38,0). # # == Examples @@ -538,6 +533,10 @@ module ActiveRecord # add_column(:measurements, :huge_integer, :decimal, precision: 30) # # ALTER TABLE "measurements" ADD "huge_integer" decimal(30) # + # # Defines a column that stores an array of a type. + # add_column(:users, :skills, :text, array: true) + # # ALTER TABLE "users" ADD "skills" text[] + # # # Defines a column with a database-specific type. # add_column(:shapes, :triangle, 'polygon') # # ALTER TABLE "shapes" ADD "triangle" polygon @@ -564,7 +563,7 @@ module ActiveRecord # # The +type+ and +options+ parameters will be ignored if present. It can be helpful # to provide these in a migration's +change+ method so it can be reverted. - # In that case, +type+ and +options+ will be used by add_column. + # In that case, +type+ and +options+ will be used by #add_column. def remove_column(table_name, column_name, type = nil, options = {}) execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}" end @@ -767,7 +766,7 @@ module ActiveRecord raise ArgumentError, "You must specify the index name" end else - index_name(table_name, :column => options) + index_name(table_name, column: options) end end @@ -790,7 +789,7 @@ module ActiveRecord # [<tt>:type</tt>] # The reference column type. Defaults to +:integer+. # [<tt>:index</tt>] - # Add an appropriate index. Defaults to false. + # Add an appropriate index. Defaults to true. # See #add_index for usage of this option. # [<tt>:foreign_key</tt>] # Add an appropriate foreign key constraint. Defaults to false. @@ -952,13 +951,13 @@ module ActiveRecord # Checks to see if a foreign key exists on a table for a given foreign key definition. # - # # Check a foreign key exists + # # Checks to see if a foreign key exists. # foreign_key_exists?(:accounts, :branches) # - # # Check a foreign key on a specified column exists + # # Checks to see if a foreign key on a specified column exists. # foreign_key_exists?(:accounts, column: :owner_id) # - # # Check a foreign key with a custom name exists + # # Checks to see if a foreign key with a custom name exists. # foreign_key_exists?(:accounts, name: "special_fk_name") # def foreign_key_exists?(from_table, options_or_to_table = {}) @@ -967,12 +966,12 @@ module ActiveRecord def foreign_key_for(from_table, options_or_to_table = {}) # :nodoc: return unless supports_foreign_keys? - foreign_keys(from_table).detect {|fk| fk.defined_for? options_or_to_table } + foreign_keys(from_table).detect { |fk| fk.defined_for? options_or_to_table } end def foreign_key_for!(from_table, options_or_to_table = {}) # :nodoc: - foreign_key_for(from_table, options_or_to_table) or \ - raise ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}" + foreign_key_for(from_table, options_or_to_table) || \ + raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}") end def foreign_key_column_for(table_name) # :nodoc: @@ -990,7 +989,7 @@ module ActiveRecord end def dump_schema_information #:nodoc: - versions = ActiveRecord::SchemaMigration.order('version').pluck(:version) + versions = ActiveRecord::SchemaMigration.order("version").pluck(:version) insert_versions_sql(versions) end @@ -998,8 +997,8 @@ module ActiveRecord sm_table = ActiveRecord::Migrator.schema_migrations_table_name if supports_multi_insert? - sql = "INSERT INTO #{sm_table} (version) VALUES " - sql << versions.map {|v| "('#{v}')" }.join(', ') + sql = "INSERT INTO #{sm_table} (version) VALUES\n" + sql << versions.map { |v| "('#{v}')" }.join(",\n") sql << ";\n\n" sql else @@ -1029,18 +1028,18 @@ module ActiveRecord sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name) migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i) - paths = migrations_paths.map {|p| "#{p}/[0-9]*_*.rb" } + paths = migrations_paths.map { |p| "#{p}/[0-9]*_*.rb" } versions = Dir[*paths].map do |filename| - filename.split('/').last.split('_').first.to_i + filename.split("/").last.split("_").first.to_i end unless migrated.include?(version) execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')" end - inserting = (versions - migrated).select {|v| v < version} + inserting = (versions - migrated).select { |v| v < version } if inserting.any? - if (duplicate = inserting.detect {|v| inserting.count(v) > 1}) + if (duplicate = inserting.detect { |v| inserting.count(v) > 1 }) raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict." end execute insert_versions_sql(inserting) @@ -1048,7 +1047,8 @@ module ActiveRecord end def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc: - if native = native_database_types[type.to_sym] + type = type.to_sym if type + if native = native_database_types[type] column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup if type == :decimal # ignore limit, use precision and scale @@ -1081,7 +1081,7 @@ module ActiveRecord end # Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT. - # PostgreSQL, MySQL, and Oracle overrides this for custom DISTINCT syntax - they + # PostgreSQL, MySQL, and Oracle override this for custom DISTINCT syntax - they # require the order columns appear in the SELECT. # # columns_for_distinct("posts.id", ["posts.created_at desc"]) @@ -1166,31 +1166,34 @@ module ActiveRecord end protected - def add_index_sort_order(option_strings, column_names, options = {}) - if options.is_a?(Hash) && order = options[:order] + + def add_index_sort_order(quoted_columns, **options) + if order = options[:order] case order when Hash - column_names.each {|name| option_strings[name] += " #{order[name].upcase}" if order.has_key?(name)} + quoted_columns.each { |name, column| column << " #{order[name].upcase}" if order[name].present? } when String - column_names.each {|name| option_strings[name] += " #{order.upcase}"} + quoted_columns.each { |name, column| column << " #{order.upcase}" if order.present? } end end - return option_strings + quoted_columns end # Overridden by the MySQL adapter for supporting index lengths - def quoted_columns_for_index(column_names, options = {}) - return [column_names] if column_names.is_a?(String) - - option_strings = Hash[column_names.map {|name| [name, '']}] - - # add index sort order if supported + def add_options_for_index_columns(quoted_columns, **options) if supports_index_sort_order? - option_strings = add_index_sort_order(option_strings, column_names, options) + quoted_columns = add_index_sort_order(quoted_columns, options) end - column_names.map {|name| quote_column_name(name) + option_strings[name]} + quoted_columns + end + + def quoted_columns_for_index(column_names, **options) + return [column_names] if column_names.is_a?(String) + + quoted_columns = Hash[column_names.map { |name| [name.to_sym, quote_column_name(name).dup] }] + add_options_for_index_columns(quoted_columns, options).values end def index_name_for_remove(table_name, options = {}) @@ -1210,10 +1213,10 @@ module ActiveRecord end if column_names.any? - checks << lambda { |i| i.columns.join('_and_') == column_names.join('_and_') } + checks << lambda { |i| i.columns.join("_and_") == column_names.join("_and_") } end - raise ArgumentError "No name or columns specified" if checks.none? + raise ArgumentError, "No name or columns specified" if checks.none? matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } } @@ -1250,49 +1253,49 @@ module ActiveRecord end private - def create_table_definition(*args) - TableDefinition.new(*args) - end - - def create_alter_table(name) - AlterTable.new create_table_definition(name) - end + def create_table_definition(*args) + TableDefinition.new(*args) + end - def index_name_options(column_names) # :nodoc: - if column_names.is_a?(String) - column_names = column_names.scan(/\w+/).join('_') + def create_alter_table(name) + AlterTable.new create_table_definition(name) end - { column: column_names } - end + def index_name_options(column_names) # :nodoc: + if column_names.is_a?(String) + column_names = column_names.scan(/\w+/).join("_") + end - def foreign_key_name(table_name, options) # :nodoc: - identifier = "#{table_name}_#{options.fetch(:column)}_fk" - hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10) - options.fetch(:name) do - "fk_rails_#{hashed_identifier}" + { column: column_names } end - end - def validate_index_length!(table_name, new_name, internal = false) # :nodoc: - max_index_length = internal ? index_name_length : allowed_index_name_length + def foreign_key_name(table_name, options) # :nodoc: + identifier = "#{table_name}_#{options.fetch(:column)}_fk" + hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10) + options.fetch(:name) do + "fk_rails_#{hashed_identifier}" + end + end + + def validate_index_length!(table_name, new_name, internal = false) # :nodoc: + max_index_length = internal ? index_name_length : allowed_index_name_length - if new_name.length > max_index_length - raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters" + if new_name.length > max_index_length + raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters" + end end - end - def extract_new_default_value(default_or_changes) - if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to) - default_or_changes[:to] - else - default_or_changes + def extract_new_default_value(default_or_changes) + if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to) + default_or_changes[:to] + else + default_or_changes + end end - end - def can_remove_index_by_name?(options) - options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty? - end + def can_remove_index_by_name?(options) + options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty? + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index ca795cb1ad..6bb072dd73 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -41,7 +41,6 @@ module ActiveRecord end class Transaction #:nodoc: - attr_reader :connection, :state, :records, :savepoint_name attr_writer :joinable @@ -101,7 +100,6 @@ module ActiveRecord end class SavepointTransaction < Transaction - def initialize(connection, savepoint_name, options, *args) super(connection, options, *args) if options[:isolation] @@ -124,7 +122,6 @@ module ActiveRecord end class RealTransaction < Transaction - def initialize(connection, options, *args) super if options[:isolation] @@ -195,7 +192,7 @@ module ActiveRecord raise ensure unless error - if Thread.current.status == 'aborting' + if Thread.current.status == "aborting" rollback_transaction if transaction else begin @@ -226,7 +223,6 @@ module ActiveRecord return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired) @connection.clear_cache! end - end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index d4b9e301bc..0c7197a002 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -1,11 +1,11 @@ -require 'active_record/type' -require 'active_record/connection_adapters/determine_if_preparable_visitor' -require 'active_record/connection_adapters/schema_cache' -require 'active_record/connection_adapters/sql_type_metadata' -require 'active_record/connection_adapters/abstract/schema_dumper' -require 'active_record/connection_adapters/abstract/schema_creation' -require 'arel/collectors/bind' -require 'arel/collectors/sql_string' +require "active_record/type" +require "active_record/connection_adapters/determine_if_preparable_visitor" +require "active_record/connection_adapters/schema_cache" +require "active_record/connection_adapters/sql_type_metadata" +require "active_record/connection_adapters/abstract/schema_dumper" +require "active_record/connection_adapters/abstract/schema_creation" +require "arel/collectors/bind" +require "arel/collectors/sql_string" module ActiveRecord module ConnectionAdapters # :nodoc: @@ -14,7 +14,7 @@ module ActiveRecord autoload :Column autoload :ConnectionSpecification - autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do + autoload_at "active_record/connection_adapters/abstract/schema_definitions" do autoload :IndexDefinition autoload :ColumnDefinition autoload :ChangeColumnDefinition @@ -25,11 +25,11 @@ module ActiveRecord autoload :ReferenceDefinition end - autoload_at 'active_record/connection_adapters/abstract/connection_pool' do + autoload_at "active_record/connection_adapters/abstract/connection_pool" do autoload :ConnectionHandler end - autoload_under 'abstract' do + autoload_under "abstract" do autoload :SchemaStatements autoload :DatabaseStatements autoload :DatabaseLimits @@ -39,7 +39,7 @@ module ActiveRecord autoload :Savepoints end - autoload_at 'active_record/connection_adapters/abstract/transaction' do + autoload_at "active_record/connection_adapters/abstract/transaction" do autoload :TransactionManager autoload :NullTransaction autoload :RealTransaction @@ -61,7 +61,7 @@ module ActiveRecord # Most of the methods in the adapter are useful during migrations. Most # notably, the instance methods provided by SchemaStatements are very useful. class AbstractAdapter - ADAPTER_NAME = 'Abstract'.freeze + ADAPTER_NAME = "Abstract".freeze include Quoting, DatabaseStatements, SchemaStatements include DatabaseLimits include QueryCache @@ -120,17 +120,17 @@ module ActiveRecord include Comparable def initialize(version_string) - @version = version_string.split('.').map(&:to_i) + @version = version_string.split(".").map(&:to_i) end def <=>(version_string) - @version <=> version_string.split('.').map(&:to_i) + @version <=> version_string.split(".").map(&:to_i) end end class BindCollector < Arel::Collectors::Bind def compile(bvs, conn) - casted_binds = conn.prepare_binds_for_database(bvs) + casted_binds = bvs.map(&:value_for_database) super(casted_binds.map { |value| conn.quote(value) }) end end @@ -164,9 +164,9 @@ module ActiveRecord # this method must only be called while holding connection pool's mutex def lease if in_use? - msg = 'Cannot lease connection, ' + msg = "Cannot lease connection, " if @owner == Thread.current - msg << 'it is already leased by the current thread.' + msg << "it is already leased by the current thread." else msg << "it is already in use by a different thread: #{@owner}. " << "Current thread: #{Thread.current}." @@ -184,7 +184,30 @@ module ActiveRecord # this method must only be called while holding connection pool's mutex def expire - @owner = nil + if in_use? + if @owner != Thread.current + raise ActiveRecordError, "Cannot expire connection, " << + "it is owned by a different thread: #{@owner}. " << + "Current thread: #{Thread.current}." + end + + @owner = nil + else + raise ActiveRecordError, "Cannot expire connection, it is not currently leased." + end + end + + # this method must only be called while holding connection pool's mutex (and a desire for segfaults) + def steal! # :nodoc: + if in_use? + if @owner != Thread.current + pool.send :remove_connection_from_thread_cache, self, @owner + + @owner = Thread.current + end + else + raise ActiveRecordError, "Cannot steal connection, it is not currently leased." + end end def unprepared_statement @@ -411,11 +434,7 @@ module ActiveRecord end def case_sensitive_comparison(table, attribute, column, value) - if value.nil? - table[attribute].eq(value) - else - table[attribute].eq(Arel::Nodes::BindParam.new) - end + table[attribute].eq(Arel::Nodes::BindParam.new) end def case_insensitive_comparison(table, attribute, column, value) @@ -474,114 +493,115 @@ module ActiveRecord protected - def initialize_type_map(m) # :nodoc: - register_class_with_limit m, %r(boolean)i, Type::Boolean - register_class_with_limit m, %r(char)i, Type::String - register_class_with_limit m, %r(binary)i, Type::Binary - register_class_with_limit m, %r(text)i, Type::Text - register_class_with_precision m, %r(date)i, Type::Date - register_class_with_precision m, %r(time)i, Type::Time - register_class_with_precision m, %r(datetime)i, Type::DateTime - register_class_with_limit m, %r(float)i, Type::Float - register_class_with_limit m, %r(int)i, Type::Integer - - m.alias_type %r(blob)i, 'binary' - m.alias_type %r(clob)i, 'text' - m.alias_type %r(timestamp)i, 'datetime' - m.alias_type %r(numeric)i, 'decimal' - m.alias_type %r(number)i, 'decimal' - m.alias_type %r(double)i, 'float' - - m.register_type(%r(decimal)i) do |sql_type| - scale = extract_scale(sql_type) - precision = extract_precision(sql_type) - - if scale == 0 - # FIXME: Remove this class as well - Type::DecimalWithoutScale.new(precision: precision) - else - Type::Decimal.new(precision: precision, scale: scale) + def initialize_type_map(m) # :nodoc: + register_class_with_limit m, %r(boolean)i, Type::Boolean + register_class_with_limit m, %r(char)i, Type::String + register_class_with_limit m, %r(binary)i, Type::Binary + register_class_with_limit m, %r(text)i, Type::Text + register_class_with_precision m, %r(date)i, Type::Date + register_class_with_precision m, %r(time)i, Type::Time + register_class_with_precision m, %r(datetime)i, Type::DateTime + register_class_with_limit m, %r(float)i, Type::Float + register_class_with_limit m, %r(int)i, Type::Integer + + m.alias_type %r(blob)i, "binary" + m.alias_type %r(clob)i, "text" + m.alias_type %r(timestamp)i, "datetime" + m.alias_type %r(numeric)i, "decimal" + m.alias_type %r(number)i, "decimal" + m.alias_type %r(double)i, "float" + + m.register_type(%r(decimal)i) do |sql_type| + scale = extract_scale(sql_type) + precision = extract_precision(sql_type) + + if scale == 0 + # FIXME: Remove this class as well + Type::DecimalWithoutScale.new(precision: precision) + else + Type::Decimal.new(precision: precision, scale: scale) + end end end - end - def reload_type_map # :nodoc: - type_map.clear - initialize_type_map(type_map) - end + def reload_type_map # :nodoc: + type_map.clear + initialize_type_map(type_map) + end - def register_class_with_limit(mapping, key, klass) # :nodoc: - mapping.register_type(key) do |*args| - limit = extract_limit(args.last) - klass.new(limit: limit) + def register_class_with_limit(mapping, key, klass) # :nodoc: + mapping.register_type(key) do |*args| + limit = extract_limit(args.last) + klass.new(limit: limit) + end end - end - def register_class_with_precision(mapping, key, klass) # :nodoc: - mapping.register_type(key) do |*args| - precision = extract_precision(args.last) - klass.new(precision: precision) + def register_class_with_precision(mapping, key, klass) # :nodoc: + mapping.register_type(key) do |*args| + precision = extract_precision(args.last) + klass.new(precision: precision) + end end - end - def extract_scale(sql_type) # :nodoc: - case sql_type + def extract_scale(sql_type) # :nodoc: + case sql_type when /\((\d+)\)/ then 0 when /\((\d+)(,(\d+))\)/ then $3.to_i + end end - end - - def extract_precision(sql_type) # :nodoc: - $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/ - end - def extract_limit(sql_type) # :nodoc: - case sql_type - when /^bigint/i - 8 - when /\((.*)\)/ - $1.to_i + def extract_precision(sql_type) # :nodoc: + $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/ end - end - def translate_exception_class(e, sql) - begin - message = "#{e.class.name}: #{e.message}: #{sql}" - rescue Encoding::CompatibilityError - message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}" + def extract_limit(sql_type) # :nodoc: + case sql_type + when /^bigint/i + 8 + when /\((.*)\)/ + $1.to_i + end end - exception = translate_exception(e, message) - exception.set_backtrace e.backtrace - exception - end + def translate_exception_class(e, sql) + begin + message = "#{e.class.name}: #{e.message}: #{sql}" + rescue Encoding::CompatibilityError + message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}" + end - def log(sql, name = "SQL", binds = [], statement_name = nil) - @instrumenter.instrument( - "sql.active_record", - :sql => sql, - :name => name, - :connection_id => object_id, - :statement_name => statement_name, - :binds => binds) { yield } - rescue => e - raise translate_exception_class(e, sql) - end + exception = translate_exception(e, message) + exception.set_backtrace e.backtrace + exception + end - def translate_exception(exception, message) - # override in derived class - ActiveRecord::StatementInvalid.new(message) - end + def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) + @instrumenter.instrument( + "sql.active_record", + sql: sql, + name: name, + binds: binds, + type_casted_binds: type_casted_binds, + statement_name: statement_name, + connection_id: object_id) { yield } + rescue => e + raise translate_exception_class(e, sql) + end - def without_prepared_statement?(binds) - !prepared_statements || binds.empty? - end + def translate_exception(exception, message) + # override in derived class + ActiveRecord::StatementInvalid.new(message) + end - def column_for(table_name, column_name) # :nodoc: - column_name = column_name.to_s - columns(table_name).detect { |c| c.name == column_name } || - raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}") - end + def without_prepared_statement?(binds) + !prepared_statements || binds.empty? + end + + def column_for(table_name, column_name) # :nodoc: + column_name = column_name.to_s + columns(table_name).detect { |c| c.name == column_name } || + raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}") + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 718a6c5b91..e7bd0e7c12 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -1,14 +1,15 @@ -require 'active_record/connection_adapters/abstract_adapter' -require 'active_record/connection_adapters/statement_pool' -require 'active_record/connection_adapters/mysql/column' -require 'active_record/connection_adapters/mysql/explain_pretty_printer' -require 'active_record/connection_adapters/mysql/quoting' -require 'active_record/connection_adapters/mysql/schema_creation' -require 'active_record/connection_adapters/mysql/schema_definitions' -require 'active_record/connection_adapters/mysql/schema_dumper' -require 'active_record/connection_adapters/mysql/type_metadata' - -require 'active_support/core_ext/string/strip' +require "active_record/connection_adapters/abstract_adapter" +require "active_record/connection_adapters/statement_pool" +require "active_record/connection_adapters/mysql/column" +require "active_record/connection_adapters/mysql/explain_pretty_printer" +require "active_record/connection_adapters/mysql/quoting" +require "active_record/connection_adapters/mysql/schema_creation" +require "active_record/connection_adapters/mysql/schema_definitions" +require "active_record/connection_adapters/mysql/schema_dumper" +require "active_record/connection_adapters/mysql/type_metadata" + +require "active_support/core_ext/string/strip" +require "active_support/core_ext/regexp" module ActiveRecord module ConnectionAdapters @@ -67,16 +68,16 @@ module ActiveRecord @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit])) - if version < '5.0.0' + if version < "5.0.0" raise "Your version of MySQL (#{full_version.match(/^\d+\.\d+\.\d+/)[0]}) is too old. Active Record supports MySQL >= 5.0." end end - CHARSETS_OF_4BYTES_MAXLEN = ['utf8mb4', 'utf16', 'utf16le', 'utf32'] + CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"] def internal_string_options_for_primary_key # :nodoc: super.tap { |options| - options[:collation] = collation.sub(/\A[^_]+/, 'utf8') if CHARSETS_OF_4BYTES_MAXLEN.include?(charset) + options[:collation] = collation.sub(/\A[^_]+/, "utf8") if CHARSETS_OF_4BYTES_MAXLEN.include?(charset) } end @@ -85,7 +86,7 @@ module ActiveRecord end def mariadb? # :nodoc: - full_version =~ /mariadb/i + /mariadb/i.match?(full_version) end # Returns true, since this connection adapter supports migrations. @@ -135,9 +136,9 @@ module ActiveRecord def supports_datetime_with_precision? if mariadb? - version >= '5.3.0' + version >= "5.3.0" else - version >= '5.6.4' + version >= "5.6.4" end end @@ -158,7 +159,7 @@ module ActiveRecord end def index_algorithms - { default: 'ALGORITHM = DEFAULT', copy: 'ALGORITHM = COPY', inplace: 'ALGORITHM = INPLACE' } + { default: "ALGORITHM = DEFAULT", copy: "ALGORITHM = COPY", inplace: "ALGORITHM = INPLACE" } end # HELPER METHODS =========================================== @@ -207,7 +208,7 @@ module ActiveRecord def explain(arel, binds = []) sql = "EXPLAIN #{to_sql(arel, binds)}" start = Time.now - result = exec_query(sql, 'EXPLAIN', binds) + result = exec_query(sql, "EXPLAIN", binds) elapsed = Time.now - start MySQL::ExplainPrettyPrinter.new.pp(result, elapsed) @@ -293,17 +294,17 @@ module ActiveRecord end def current_database - select_value 'SELECT DATABASE() as db' + select_value "SELECT DATABASE() as db" end # Returns the database character set. def charset - show_variable 'character_set_database' + show_variable "character_set_database" end # Returns the database collation strategy. def collation - show_variable 'collation_database' + show_variable "collation_database" end def tables(name = nil) # :nodoc: @@ -326,7 +327,7 @@ module ActiveRecord sql = "SELECT table_name FROM information_schema.tables " sql << "WHERE table_schema = #{quote(@config[:database])}" - select_values(sql, 'SCHEMA') + select_values(sql, "SCHEMA") end def truncate(table_name, name = nil) @@ -352,11 +353,11 @@ module ActiveRecord sql = "SELECT table_name FROM information_schema.tables " sql << "WHERE table_schema = #{quote(schema)} AND table_name = #{quote(name)}" - select_values(sql, 'SCHEMA').any? + select_values(sql, "SCHEMA").any? end def views # :nodoc: - select_values("SHOW FULL TABLES WHERE table_type = 'VIEW'", 'SCHEMA') + select_values("SHOW FULL TABLES WHERE table_type = 'VIEW'", "SCHEMA") end def view_exists?(view_name) # :nodoc: @@ -367,27 +368,27 @@ module ActiveRecord sql = "SELECT table_name FROM information_schema.tables WHERE table_type = 'VIEW'" sql << " AND table_schema = #{quote(schema)} AND table_name = #{quote(name)}" - select_values(sql, 'SCHEMA').any? + select_values(sql, "SCHEMA").any? end # Returns an array of indexes for the given table. def indexes(table_name, name = nil) #:nodoc: indexes = [] current_index = nil - execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result| + execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result| each_hash(result) do |row| if current_index != row[:Key_name] - next if row[:Key_name] == 'PRIMARY' # skip the primary key + next if row[:Key_name] == "PRIMARY" # skip the primary key current_index = row[:Key_name] mysql_index_type = row[:Index_type].downcase.to_sym index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil - indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], [], nil, nil, index_type, index_using, row[:Index_comment].presence) + indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], {}, nil, nil, index_type, index_using, row[:Index_comment].presence) end indexes.last.columns << row[:Column_name] - indexes.last.lengths << row[:Sub_part] + indexes.last.lengths.merge!(row[:Column_name] => row[:Sub_part].to_i) if row[:Sub_part] end end @@ -409,15 +410,18 @@ module ActiveRecord end def table_comment(table_name) # :nodoc: - select_value(<<-SQL.strip_heredoc, 'SCHEMA') + schema, name = extract_schema_qualified_name(table_name) + + select_value(<<-SQL.strip_heredoc, "SCHEMA") SELECT table_comment FROM information_schema.tables - WHERE table_name=#{quote(table_name)} + WHERE table_schema = #{quote(schema)} + AND table_name = #{quote(name)} SQL end def create_table(table_name, **options) #:nodoc: - super(table_name, options: 'ENGINE=InnoDB', **options) + super(table_name, options: "ENGINE=InnoDB", **options) end def bulk_change_table(table_name, operations) #:nodoc: @@ -460,7 +464,6 @@ module ActiveRecord # it can be helpful to provide these in a migration's +change+ method so it can be reverted. # In that case, +options+ and the block will be used by create_table. def drop_table(table_name, options = {}) - create_table_info_cache.delete(table_name) if create_table_info_cache.key?(table_name) execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}" end @@ -477,7 +480,7 @@ module ActiveRecord def change_column_default(table_name, column_name, default_or_changes) #:nodoc: default = extract_new_default_value(default_or_changes) column = column_for(table_name, column_name) - change_column table_name, column_name, column.sql_type, :default => default + change_column table_name, column_name, column.sql_type, default: default end def change_column_null(table_name, column_name, null, default = nil) #:nodoc: @@ -487,7 +490,7 @@ module ActiveRecord execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") end - change_column table_name, column_name, column.sql_type, :null => null + change_column table_name, column_name, column.sql_type, null: null end def change_column(table_name, column_name, type, options = {}) #:nodoc: @@ -506,7 +509,7 @@ module ActiveRecord end def add_sql_comment!(sql, comment) # :nodoc: - sql << " COMMENT #{quote(comment)}" if comment + sql << " COMMENT #{quote(comment)}" if comment.present? sql end @@ -515,74 +518,83 @@ module ActiveRecord schema, name = extract_schema_qualified_name(table_name) - fk_info = select_all <<-SQL.strip_heredoc - SELECT fk.referenced_table_name as 'to_table' - ,fk.referenced_column_name as 'primary_key' - ,fk.column_name as 'column' - ,fk.constraint_name as 'name' + fk_info = select_all(<<-SQL.strip_heredoc, "SCHEMA") + SELECT fk.referenced_table_name AS 'to_table', + fk.referenced_column_name AS 'primary_key', + fk.column_name AS 'column', + fk.constraint_name AS 'name', + rc.update_rule AS 'on_update', + rc.delete_rule AS 'on_delete' FROM information_schema.key_column_usage fk - WHERE fk.referenced_column_name is not null + JOIN information_schema.referential_constraints rc + USING (constraint_schema, constraint_name) + WHERE fk.referenced_column_name IS NOT NULL AND fk.table_schema = #{quote(schema)} AND fk.table_name = #{quote(name)} SQL - create_table_info = create_table_info(table_name) - fk_info.map do |row| options = { - column: row['column'], - name: row['name'], - primary_key: row['primary_key'] + column: row["column"], + name: row["name"], + primary_key: row["primary_key"] } - options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE") - options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE") + options[:on_update] = extract_foreign_key_action(row["on_update"]) + options[:on_delete] = extract_foreign_key_action(row["on_delete"]) - ForeignKeyDefinition.new(table_name, row['to_table'], options) + ForeignKeyDefinition.new(table_name, row["to_table"], options) end end - def table_options(table_name) + def table_options(table_name) # :nodoc: + table_options = {} + create_table_info = create_table_info(table_name) # strip create_definitions and partition_options - raw_table_options = create_table_info.sub(/\A.*\n\) /m, '').sub(/\n\/\*!.*\*\/\n\z/m, '').strip + raw_table_options = create_table_info.sub(/\A.*\n\) /m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip # strip AUTO_INCREMENT raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1') + table_options[:options] = raw_table_options + # strip COMMENT - raw_table_options.sub!(/ COMMENT='.+'/, '') + if raw_table_options.sub!(/ COMMENT='.+'/, "") + table_options[:comment] = table_comment(table_name) + end - raw_table_options + table_options end # Maps logical Rails types to MySQL-specific data types. def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil) - sql = case type.to_s - when 'integer' - integer_to_sql(limit) - when 'text' - text_to_sql(limit) - when 'blob' - binary_to_sql(limit) - when 'binary' - if (0..0xfff) === limit - "varbinary(#{limit})" - else + sql = \ + case type.to_s + when "integer" + integer_to_sql(limit) + when "text" + text_to_sql(limit) + when "blob" binary_to_sql(limit) + when "binary" + if (0..0xfff) === limit + "varbinary(#{limit})" + else + binary_to_sql(limit) + end + else + super(type, limit, precision, scale) end - else - super(type, limit, precision, scale) - end - sql << ' unsigned' if unsigned && type != :primary_key + sql << " unsigned" if unsigned && type != :primary_key sql end # SHOW VARIABLES LIKE 'name' def show_variable(name) - select_value("SELECT @@#{name}", 'SCHEMA') + select_value("SELECT @@#{name}", "SCHEMA") rescue ActiveRecord::StatementInvalid nil end @@ -592,7 +604,7 @@ module ActiveRecord schema, name = extract_schema_qualified_name(table_name) - select_values(<<-SQL.strip_heredoc, 'SCHEMA') + select_values(<<-SQL.strip_heredoc, "SCHEMA") SELECT column_name FROM information_schema.key_column_usage WHERE constraint_name = 'PRIMARY' @@ -603,7 +615,7 @@ module ActiveRecord end def case_sensitive_comparison(table, attribute, column, value) - if !value.nil? && column.collation && !column.case_sensitive? + if column.collation && !column.case_sensitive? table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new)) else super @@ -624,10 +636,10 @@ module ActiveRecord # Convert Arel node to string s = s.to_sql unless s.is_a?(String) # Remove any ASC/DESC modifiers - s.gsub(/\s+(?:ASC|DESC)\b/i, '') + s.gsub(/\s+(?:ASC|DESC)\b/i, "") }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" } - [super, *order_columns].join(', ') + [super, *order_columns].join(", ") end def strict_mode? @@ -640,346 +652,333 @@ module ActiveRecord protected - def initialize_type_map(m) # :nodoc: - super - - register_class_with_limit m, %r(char)i, MysqlString - - m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1) - m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1) - m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1) - m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1) - m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1) - m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1) - m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1) - m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1) - m.register_type %r(^float)i, Type::Float.new(limit: 24) - m.register_type %r(^double)i, Type::Float.new(limit: 53) - m.register_type %r(^json)i, MysqlJson.new - - register_integer_type m, %r(^bigint)i, limit: 8 - register_integer_type m, %r(^int)i, limit: 4 - register_integer_type m, %r(^mediumint)i, limit: 3 - register_integer_type m, %r(^smallint)i, limit: 2 - register_integer_type m, %r(^tinyint)i, limit: 1 + def initialize_type_map(m) # :nodoc: + super - m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans - m.alias_type %r(year)i, 'integer' - m.alias_type %r(bit)i, 'binary' + register_class_with_limit m, %r(char)i, MysqlString + + m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1) + m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1) + m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1) + m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1) + m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1) + m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1) + m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1) + m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1) + m.register_type %r(^float)i, Type::Float.new(limit: 24) + m.register_type %r(^double)i, Type::Float.new(limit: 53) + m.register_type %r(^json)i, MysqlJson.new + + register_integer_type m, %r(^bigint)i, limit: 8 + register_integer_type m, %r(^int)i, limit: 4 + register_integer_type m, %r(^mediumint)i, limit: 3 + register_integer_type m, %r(^smallint)i, limit: 2 + register_integer_type m, %r(^tinyint)i, limit: 1 + + m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans + m.alias_type %r(year)i, "integer" + m.alias_type %r(bit)i, "binary" + + m.register_type(%r(enum)i) do |sql_type| + limit = sql_type[/^enum\((.+)\)/i, 1] + .split(",").map { |enum| enum.strip.length - 2 }.max + MysqlString.new(limit: limit) + end - m.register_type(%r(enum)i) do |sql_type| - limit = sql_type[/^enum\((.+)\)/i, 1] - .split(',').map{|enum| enum.strip.length - 2}.max - MysqlString.new(limit: limit) + m.register_type(%r(^set)i) do |sql_type| + limit = sql_type[/^set\((.+)\)/i, 1] + .split(",").map { |set| set.strip.length - 1 }.sum - 1 + MysqlString.new(limit: limit) + end end - m.register_type(%r(^set)i) do |sql_type| - limit = sql_type[/^set\((.+)\)/i, 1] - .split(',').map{|set| set.strip.length - 1}.sum - 1 - MysqlString.new(limit: limit) + def register_integer_type(mapping, key, options) # :nodoc: + mapping.register_type(key) do |sql_type| + if /\bunsigned\z/ === sql_type + Type::UnsignedInteger.new(options) + else + Type::Integer.new(options) + end + end end - end - def register_integer_type(mapping, key, options) # :nodoc: - mapping.register_type(key) do |sql_type| - if /\bunsigned\z/ === sql_type - Type::UnsignedInteger.new(options) + def extract_precision(sql_type) + if /time/ === sql_type + super || 0 else - Type::Integer.new(options) + super end end - end - def extract_precision(sql_type) - if /time/ === sql_type - super || 0 - else - super + def fetch_type_metadata(sql_type, extra = "") + MySQL::TypeMetadata.new(super(sql_type), extra: extra) end - end - def fetch_type_metadata(sql_type, extra = "") - MySQL::TypeMetadata.new(super(sql_type), extra: extra, strict: strict_mode?) - end - - def add_index_length(option_strings, column_names, options = {}) - if options.is_a?(Hash) && length = options[:length] - case length - when Hash - column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?} - when Integer - column_names.each {|name| option_strings[name] += "(#{length})"} + def add_index_length(quoted_columns, **options) + if length = options[:length] + case length + when Hash + quoted_columns.each { |name, column| column << "(#{length[name]})" if length[name].present? } + when Integer + quoted_columns.each { |name, column| column << "(#{length})" } + end end + + quoted_columns end - return option_strings - end + def add_options_for_index_columns(quoted_columns, **options) + quoted_columns = add_index_length(quoted_columns, options) + super + end - def quoted_columns_for_index(column_names, options = {}) - option_strings = Hash[column_names.map {|name| [name, '']}] + # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html + ER_DUP_ENTRY = 1062 + ER_NO_REFERENCED_ROW_2 = 1452 + ER_DATA_TOO_LONG = 1406 + ER_LOCK_DEADLOCK = 1213 + + def translate_exception(exception, message) + case error_number(exception) + when ER_DUP_ENTRY + RecordNotUnique.new(message) + when ER_NO_REFERENCED_ROW_2 + InvalidForeignKey.new(message) + when ER_DATA_TOO_LONG + ValueTooLong.new(message) + when ER_LOCK_DEADLOCK + Deadlocked.new(message) + else + super + end + end - # add index length - option_strings = add_index_length(option_strings, column_names, options) + def add_column_sql(table_name, column_name, type, options = {}) + td = create_table_definition(table_name) + cd = td.new_column_definition(column_name, type, options) + schema_creation.accept(AddColumnDefinition.new(cd)) + end - # add index sort order - option_strings = add_index_sort_order(option_strings, column_names, options) + def change_column_sql(table_name, column_name, type, options = {}) + column = column_for(table_name, column_name) - column_names.map {|name| quote_column_name(name) + option_strings[name]} - end + unless options_include_default?(options) + options[:default] = column.default + end - # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html - ER_DUP_ENTRY = 1062 - ER_NO_REFERENCED_ROW_2 = 1452 - ER_DATA_TOO_LONG = 1406 - ER_LOCK_DEADLOCK = 1213 + unless options.has_key?(:null) + options[:null] = column.null + end - def translate_exception(exception, message) - case error_number(exception) - when ER_DUP_ENTRY - RecordNotUnique.new(message) - when ER_NO_REFERENCED_ROW_2 - InvalidForeignKey.new(message) - when ER_DATA_TOO_LONG - ValueTooLong.new(message) - when ER_LOCK_DEADLOCK - TransactionSerializationError.new(message) - else - super + td = create_table_definition(table_name) + cd = td.new_column_definition(column.name, type, options) + schema_creation.accept(ChangeColumnDefinition.new(cd, column.name)) end - end - - def add_column_sql(table_name, column_name, type, options = {}) - td = create_table_definition(table_name) - cd = td.new_column_definition(column_name, type, options) - schema_creation.accept(AddColumnDefinition.new(cd)) - end - def change_column_sql(table_name, column_name, type, options = {}) - column = column_for(table_name, column_name) + def rename_column_sql(table_name, column_name, new_column_name) + column = column_for(table_name, column_name) + options = { + default: column.default, + null: column.null, + auto_increment: column.auto_increment? + } - unless options_include_default?(options) - options[:default] = column.default + current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", "SCHEMA")["Type"] + td = create_table_definition(table_name) + cd = td.new_column_definition(new_column_name, current_type, options) + schema_creation.accept(ChangeColumnDefinition.new(cd, column.name)) end - unless options.has_key?(:null) - options[:null] = column.null + def remove_column_sql(table_name, column_name, type = nil, options = {}) + "DROP #{quote_column_name(column_name)}" end - td = create_table_definition(table_name) - cd = td.new_column_definition(column.name, type, options) - schema_creation.accept(ChangeColumnDefinition.new(cd, column.name)) - end - - def rename_column_sql(table_name, column_name, new_column_name) - column = column_for(table_name, column_name) - options = { - default: column.default, - null: column.null, - auto_increment: column.auto_increment? - } - - current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"] - td = create_table_definition(table_name) - cd = td.new_column_definition(new_column_name, current_type, options) - schema_creation.accept(ChangeColumnDefinition.new(cd, column.name)) - end - - def remove_column_sql(table_name, column_name, type = nil, options = {}) - "DROP #{quote_column_name(column_name)}" - end - - def remove_columns_sql(table_name, *column_names) - column_names.map {|column_name| remove_column_sql(table_name, column_name) } - end + def remove_columns_sql(table_name, *column_names) + column_names.map { |column_name| remove_column_sql(table_name, column_name) } + end - def add_index_sql(table_name, column_name, options = {}) - index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options) - index_algorithm[0, 0] = ", " if index_algorithm.present? - "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}" - end + def add_index_sql(table_name, column_name, options = {}) + index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options) + index_algorithm[0, 0] = ", " if index_algorithm.present? + "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}" + end - def remove_index_sql(table_name, options = {}) - index_name = index_name_for_remove(table_name, options) - "DROP INDEX #{index_name}" - end + def remove_index_sql(table_name, options = {}) + index_name = index_name_for_remove(table_name, options) + "DROP INDEX #{index_name}" + end - def add_timestamps_sql(table_name, options = {}) - [add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)] - end + def add_timestamps_sql(table_name, options = {}) + [add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)] + end - def remove_timestamps_sql(table_name, options = {}) - [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)] - end + def remove_timestamps_sql(table_name, options = {}) + [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)] + end private - # MySQL is too stupid to create a temporary table for use subquery, so we have - # to give it some prompting in the form of a subsubquery. Ugh! - def subquery_for(key, select) - subsubselect = select.clone - subsubselect.projections = [key] + # MySQL is too stupid to create a temporary table for use subquery, so we have + # to give it some prompting in the form of a subsubquery. Ugh! + def subquery_for(key, select) + subsubselect = select.clone + subsubselect.projections = [key] - # Materialize subquery by adding distinct - # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on' - subsubselect.distinct unless select.limit || select.offset || select.orders.any? + # Materialize subquery by adding distinct + # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on' + subsubselect.distinct unless select.limit || select.offset || select.orders.any? - subselect = Arel::SelectManager.new(select.engine) - subselect.project Arel.sql(key.name) - subselect.from subsubselect.as('__active_record_temp') - end + subselect = Arel::SelectManager.new(select.engine) + subselect.project Arel.sql(key.name) + subselect.from subsubselect.as("__active_record_temp") + end - def supports_rename_index? - mariadb? ? false : version >= '5.7.6' - end + def supports_rename_index? + mariadb? ? false : version >= "5.7.6" + end - def configure_connection - variables = @config.fetch(:variables, {}).stringify_keys + def configure_connection + variables = @config.fetch(:variables, {}).stringify_keys - # By default, MySQL 'where id is null' selects the last inserted id; Turn this off. - variables['sql_auto_is_null'] = 0 + # By default, MySQL 'where id is null' selects the last inserted id; Turn this off. + variables["sql_auto_is_null"] = 0 - # Increase timeout so the server doesn't disconnect us. - wait_timeout = @config[:wait_timeout] - wait_timeout = 2147483 unless wait_timeout.is_a?(Integer) - variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout) + # Increase timeout so the server doesn't disconnect us. + wait_timeout = @config[:wait_timeout] + wait_timeout = 2147483 unless wait_timeout.is_a?(Integer) + variables["wait_timeout"] = self.class.type_cast_config_to_integer(wait_timeout) - defaults = [':default', :default].to_set + defaults = [":default", :default].to_set - # Make MySQL reject illegal values rather than truncating or blanking them, see - # http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables - # If the user has provided another value for sql_mode, don't replace it. - if sql_mode = variables.delete('sql_mode') - sql_mode = quote(sql_mode) - elsif !defaults.include?(strict_mode?) - if strict_mode? - sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')" - else - sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')" - sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')" - sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')" + # Make MySQL reject illegal values rather than truncating or blanking them, see + # http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables + # If the user has provided another value for sql_mode, don't replace it. + if sql_mode = variables.delete("sql_mode") + sql_mode = quote(sql_mode) + elsif !defaults.include?(strict_mode?) + if strict_mode? + sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')" + else + sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')" + sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')" + sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')" + end + sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')" end - sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')" - end - sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode - - # NAMES does not have an equals sign, see - # http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430 - # (trailing comma because variable_assignments will always have content) - if @config[:encoding] - encoding = "NAMES #{@config[:encoding]}" - encoding << " COLLATE #{@config[:collation]}" if @config[:collation] - encoding << ", " - end - - # Gather up all of the SET variables... - variable_assignments = variables.map do |k, v| - if defaults.include?(v) - "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default - elsif !v.nil? - "@@SESSION.#{k} = #{quote(v)}" + sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode + + # NAMES does not have an equals sign, see + # http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430 + # (trailing comma because variable_assignments will always have content) + if @config[:encoding] + encoding = "NAMES #{@config[:encoding]}" + encoding << " COLLATE #{@config[:collation]}" if @config[:collation] + encoding << ", " end - # or else nil; compact to clear nils out - end.compact.join(', ') - # ...and send them all in one query - @connection.query "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}" - end + # Gather up all of the SET variables... + variable_assignments = variables.map do |k, v| + if defaults.include?(v) + "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default + elsif !v.nil? + "@@SESSION.#{k} = #{quote(v)}" + end + # or else nil; compact to clear nils out + end.compact.join(", ") - def column_definitions(table_name) # :nodoc: - execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result| - each_hash(result) + # ...and send them all in one query + @connection.query "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}" end - end - def extract_foreign_key_action(structure, name, action) # :nodoc: - if structure =~ /CONSTRAINT #{quote_column_name(name)} FOREIGN KEY .* REFERENCES .* ON #{action} (CASCADE|SET NULL|RESTRICT)/ - case $1 - when 'CASCADE'; :cascade - when 'SET NULL'; :nullify + def column_definitions(table_name) # :nodoc: + execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result| + each_hash(result) end end - end - - def create_table_info_cache # :nodoc: - @create_table_info_cache ||= {} - end - - def create_table_info(table_name) # :nodoc: - create_table_info_cache[table_name] ||= select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"] - end - def create_table_definition(*args) # :nodoc: - MySQL::TableDefinition.new(*args) - end + def extract_foreign_key_action(specifier) # :nodoc: + case specifier + when "CASCADE"; :cascade + when "SET NULL"; :nullify + end + end - def extract_schema_qualified_name(string) # :nodoc: - schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/) - schema, name = @config[:database], schema unless name - [schema, name] - end + def create_table_info(table_name) # :nodoc: + select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"] + end - def integer_to_sql(limit) # :nodoc: - case limit - when 1; 'tinyint' - when 2; 'smallint' - when 3; 'mediumint' - when nil, 4; 'int' - when 5..8; 'bigint' - else raise(ActiveRecordError, "No integer type has byte size #{limit}") + def create_table_definition(*args) # :nodoc: + MySQL::TableDefinition.new(*args) end - end - def text_to_sql(limit) # :nodoc: - case limit - when 0..0xff; 'tinytext' - when nil, 0x100..0xffff; 'text' - when 0x10000..0xffffff; 'mediumtext' - when 0x1000000..0xffffffff; 'longtext' - else raise(ActiveRecordError, "No text type has byte length #{limit}") + def extract_schema_qualified_name(string) # :nodoc: + schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/) + schema, name = @config[:database], schema unless name + [schema, name] end - end - def binary_to_sql(limit) # :nodoc: - case limit - when 0..0xff; 'tinyblob' - when nil, 0x100..0xffff; 'blob' - when 0x10000..0xffffff; 'mediumblob' - when 0x1000000..0xffffffff; 'longblob' - else raise(ActiveRecordError, "No binary type has byte length #{limit}") + def integer_to_sql(limit) # :nodoc: + case limit + when 1; "tinyint" + when 2; "smallint" + when 3; "mediumint" + when nil, 4; "int" + when 5..8; "bigint" + else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead.") + end end - end - class MysqlJson < Type::Internal::AbstractJson # :nodoc: - def changed_in_place?(raw_old_value, new_value) - # Normalization is required because MySQL JSON data format includes - # the space between the elements. - super(serialize(deserialize(raw_old_value)), new_value) + def text_to_sql(limit) # :nodoc: + case limit + when 0..0xff; "tinytext" + when nil, 0x100..0xffff; "text" + when 0x10000..0xffffff; "mediumtext" + when 0x1000000..0xffffffff; "longtext" + else raise(ActiveRecordError, "No text type has byte length #{limit}") + end end - end - class MysqlString < Type::String # :nodoc: - def serialize(value) - case value - when true then MySQL::Quoting::QUOTED_TRUE - when false then MySQL::Quoting::QUOTED_FALSE - else super + def binary_to_sql(limit) # :nodoc: + case limit + when 0..0xff; "tinyblob" + when nil, 0x100..0xffff; "blob" + when 0x10000..0xffffff; "mediumblob" + when 0x1000000..0xffffffff; "longblob" + else raise(ActiveRecordError, "No binary type has byte length #{limit}") end end - private + class MysqlJson < Type::Internal::AbstractJson # :nodoc: + def changed_in_place?(raw_old_value, new_value) + # Normalization is required because MySQL JSON data format includes + # the space between the elements. + super(serialize(deserialize(raw_old_value)), new_value) + end + end - def cast_value(value) - case value - when true then MySQL::Quoting::QUOTED_TRUE - when false then MySQL::Quoting::QUOTED_FALSE - else super + class MysqlString < Type::String # :nodoc: + def serialize(value) + case value + when true then MySQL::Quoting::QUOTED_TRUE + when false then MySQL::Quoting::QUOTED_FALSE + else super + end end + + private + + def cast_value(value) + case value + when true then MySQL::Quoting::QUOTED_TRUE + when false then MySQL::Quoting::QUOTED_FALSE + else super + end + end end - end - ActiveRecord::Type.register(:json, MysqlJson, adapter: :mysql2) - ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2) - ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2) + ActiveRecord::Type.register(:json, MysqlJson, adapter: :mysql2) + ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2) + ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2) end end end diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 28f0c8686a..1808173592 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -52,9 +52,9 @@ module ActiveRecord protected - def attributes_for_hash - [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation] - end + def attributes_for_hash + [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation] + end end class NullColumn < Column diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 346916337e..849130ba43 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -1,4 +1,4 @@ -require 'uri' +require "uri" module ActiveRecord module ConnectionAdapters @@ -19,7 +19,6 @@ module ActiveRecord # Expands a connection string into a hash. class ConnectionUrlResolver # :nodoc: - # == Example # # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000" @@ -37,11 +36,11 @@ module ActiveRecord def initialize(url) raise "Database URL cannot be empty" if url.blank? @uri = uri_parser.parse(url) - @adapter = @uri.scheme && @uri.scheme.tr('-', '_') + @adapter = @uri.scheme && @uri.scheme.tr("-", "_") @adapter = "postgresql" if @adapter == "postgres" if @uri.opaque - @uri.opaque, @query = @uri.opaque.split('?', 2) + @uri.opaque, @query = @uri.opaque.split("?", 2) else @query = @uri.query end @@ -56,58 +55,58 @@ module ActiveRecord private - def uri - @uri - end + def uri + @uri + end - def uri_parser - @uri_parser ||= URI::Parser.new - end + def uri_parser + @uri_parser ||= URI::Parser.new + end - # Converts the query parameters of the URI into a hash. - # - # "localhost?pool=5&reaping_frequency=2" - # # => { "pool" => "5", "reaping_frequency" => "2" } - # - # returns empty hash if no query present. - # - # "localhost" - # # => {} - def query_hash - Hash[(@query || '').split("&").map { |pair| pair.split("=") }] - end + # Converts the query parameters of the URI into a hash. + # + # "localhost?pool=5&reaping_frequency=2" + # # => { "pool" => "5", "reaping_frequency" => "2" } + # + # returns empty hash if no query present. + # + # "localhost" + # # => {} + def query_hash + Hash[(@query || "").split("&").map { |pair| pair.split("=") }] + end - def raw_config - if uri.opaque - query_hash.merge({ - "adapter" => @adapter, - "database" => uri.opaque }) - else - query_hash.merge({ - "adapter" => @adapter, - "username" => uri.user, - "password" => uri.password, - "port" => uri.port, - "database" => database_from_path, - "host" => uri.hostname }) + def raw_config + if uri.opaque + query_hash.merge( + "adapter" => @adapter, + "database" => uri.opaque) + else + query_hash.merge( + "adapter" => @adapter, + "username" => uri.user, + "password" => uri.password, + "port" => uri.port, + "database" => database_from_path, + "host" => uri.hostname) + end end - end - # Returns name of the database. - def database_from_path - if @adapter == 'sqlite3' - # 'sqlite3:/foo' is absolute, because that makes sense. The - # corresponding relative version, 'sqlite3:foo', is handled - # elsewhere, as an "opaque". + # Returns name of the database. + def database_from_path + if @adapter == "sqlite3" + # 'sqlite3:/foo' is absolute, because that makes sense. The + # corresponding relative version, 'sqlite3:foo', is handled + # elsewhere, as an "opaque". - uri.path - else - # Only SQLite uses a filename as the "database" name; for - # anything else, a leading slash would be silly. + uri.path + else + # Only SQLite uses a filename as the "database" name; for + # anything else, a leading slash would be silly. - uri.path.sub(%r{^/}, "") + uri.path.sub(%r{^/}, "") + end end - end end ## @@ -193,72 +192,72 @@ module ActiveRecord private - # Returns fully resolved connection, accepts hash, string or symbol. - # Always returns a hash. - # - # == Examples - # - # Symbol representing current environment. - # - # Resolver.new("production" => {}).resolve_connection(:production) - # # => {} - # - # One layer deep hash of connection values. - # - # Resolver.new({}).resolve_connection("adapter" => "sqlite3") - # # => { "adapter" => "sqlite3" } - # - # Connection URL. - # - # Resolver.new({}).resolve_connection("postgresql://localhost/foo") - # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } - # - def resolve_connection(spec) - case spec - when Symbol - resolve_symbol_connection spec - when String - resolve_url_connection spec - when Hash - resolve_hash_connection spec + # Returns fully resolved connection, accepts hash, string or symbol. + # Always returns a hash. + # + # == Examples + # + # Symbol representing current environment. + # + # Resolver.new("production" => {}).resolve_connection(:production) + # # => {} + # + # One layer deep hash of connection values. + # + # Resolver.new({}).resolve_connection("adapter" => "sqlite3") + # # => { "adapter" => "sqlite3" } + # + # Connection URL. + # + # Resolver.new({}).resolve_connection("postgresql://localhost/foo") + # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } + # + def resolve_connection(spec) + case spec + when Symbol + resolve_symbol_connection spec + when String + resolve_url_connection spec + when Hash + resolve_hash_connection spec + end end - end - # Takes the environment such as +:production+ or +:development+. - # This requires that the @configurations was initialized with a key that - # matches. - # - # Resolver.new("production" => {}).resolve_symbol_connection(:production) - # # => {} - # - def resolve_symbol_connection(spec) - if config = configurations[spec.to_s] - resolve_connection(config).merge("name" => spec.to_s) - else - raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}") + # Takes the environment such as +:production+ or +:development+. + # This requires that the @configurations was initialized with a key that + # matches. + # + # Resolver.new("production" => {}).resolve_symbol_connection(:production) + # # => {} + # + def resolve_symbol_connection(spec) + if config = configurations[spec.to_s] + resolve_connection(config).merge("name" => spec.to_s) + else + raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}") + end end - end - # Accepts a hash. Expands the "url" key that contains a - # URL database connection to a full connection - # hash and merges with the rest of the hash. - # Connection details inside of the "url" key win any merge conflicts - def resolve_hash_connection(spec) - if spec["url"] && spec["url"] !~ /^jdbc:/ - connection_hash = resolve_url_connection(spec.delete("url")) - spec.merge!(connection_hash) + # Accepts a hash. Expands the "url" key that contains a + # URL database connection to a full connection + # hash and merges with the rest of the hash. + # Connection details inside of the "url" key win any merge conflicts + def resolve_hash_connection(spec) + if spec["url"] && spec["url"] !~ /^jdbc:/ + connection_hash = resolve_url_connection(spec.delete("url")) + spec.merge!(connection_hash) + end + spec end - spec - end - # Takes a connection URL. - # - # Resolver.new({}).resolve_url_connection("postgresql://localhost/foo") - # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } - # - def resolve_url_connection(url) - ConnectionUrlResolver.new(url).to_hash - end + # Takes a connection URL. + # + # Resolver.new({}).resolve_url_connection("postgresql://localhost/foo") + # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } + # + def resolve_url_connection(url) + ConnectionUrlResolver.new(url).to_hash + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/column.rb b/activerecord/lib/active_record/connection_adapters/mysql/column.rb index 9c45fdd44a..296d9a15f8 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/column.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/column.rb @@ -2,22 +2,7 @@ module ActiveRecord module ConnectionAdapters module MySQL class Column < ConnectionAdapters::Column # :nodoc: - delegate :strict, :extra, to: :sql_type_metadata, allow_nil: true - - def initialize(*) - super - assert_valid_default - extract_default - end - - def has_default? - return false if blob_or_text_column? # MySQL forbids defaults on blob and text columns - super - end - - def blob_or_text_column? - /\A(?:tiny|medium|long)?blob\b/ === sql_type || type == :text - end + delegate :extra, to: :sql_type_metadata, allow_nil: true def unsigned? /\bunsigned\z/ === sql_type @@ -28,21 +13,7 @@ module ActiveRecord end def auto_increment? - extra == 'auto_increment' - end - - private - - def extract_default - if blob_or_text_column? - @default = null || strict ? nil : '' - end - end - - def assert_valid_default - if blob_or_text_column? && default.present? - raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" - end + extra == "auto_increment" end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb index 13c9b6cbd9..56800f7590 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb @@ -13,19 +13,6 @@ module ActiveRecord result end - # Returns a record hash with the column names as keys and column values - # as values. - def select_one(arel, name = nil, binds = []) - arel, binds = binds_from_relation(arel, binds) - @connection.query_options.merge!(as: :hash) - select_result(to_sql(arel, binds), name, binds) do |result| - @connection.next_result while @connection.more_results? - result.first - end - ensure - @connection.query_options.merge!(as: :array) - end - # Returns an array of arrays containing the field values. # Order is the same as that returned by +columns+. def select_rows(sql, name = nil, binds = []) @@ -37,16 +24,14 @@ module ActiveRecord # Executes the SQL statement in the context of this connection. def execute(sql, name = nil) - if @connection - # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been - # made since we established the connection - @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone - end + # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been + # made since we established the connection + @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone super end - def exec_query(sql, name = 'SQL', binds = [], prepare: false) + def exec_query(sql, name = "SQL", binds = [], prepare: false) if without_prepared_statement?(binds) execute_and_free(sql, name) do |result| ActiveRecord::Result.new(result.fields, result.to_a) if result @@ -58,7 +43,7 @@ module ActiveRecord end end - def exec_delete(sql, name, binds) + def exec_delete(sql, name = nil, binds = []) if without_prepared_statement?(binds) execute_and_free(sql, name) { @connection.affected_rows } else @@ -69,56 +54,54 @@ module ActiveRecord protected - def last_inserted_id(result) - @connection.last_id - end + def last_inserted_id(result) + @connection.last_id + end private - def select_result(sql, name = nil, binds = []) - if without_prepared_statement?(binds) - execute_and_free(sql, name) { |result| yield result } - else - exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result } + def select_result(sql, name = nil, binds = []) + if without_prepared_statement?(binds) + execute_and_free(sql, name) { |result| yield result } + else + exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result } + end end - end - def exec_stmt_and_free(sql, name, binds, cache_stmt: false) - if @connection + def exec_stmt_and_free(sql, name, binds, cache_stmt: false) # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been # made since we established the connection @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone - end - - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } - log(sql, name, binds) do - if cache_stmt - cache = @statements[sql] ||= { - stmt: @connection.prepare(sql) - } - stmt = cache[:stmt] - else - stmt = @connection.prepare(sql) - end + type_casted_binds = type_casted_binds(binds) - begin - result = stmt.execute(*type_casted_binds) - rescue Mysql2::Error => e + log(sql, name, binds, type_casted_binds) do if cache_stmt - @statements.delete(sql) + cache = @statements[sql] ||= { + stmt: @connection.prepare(sql) + } + stmt = cache[:stmt] else - stmt.close + stmt = @connection.prepare(sql) + end + + begin + result = stmt.execute(*type_casted_binds) + rescue Mysql2::Error => e + if cache_stmt + @statements.delete(sql) + else + stmt.close + end + raise e end - raise e - end - ret = yield stmt, result - result.free if result - stmt.close unless cache_stmt - ret + ret = yield stmt, result + result.free if result + stmt.close unless cache_stmt + ret + end end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb index 1820853196..925555703d 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb @@ -36,34 +36,34 @@ module ActiveRecord private - def compute_column_widths(result) - [].tap do |widths| - result.columns.each_with_index do |column, i| - cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? 'NULL' : r[i].to_s} - widths << cells_in_column.map(&:length).max + def compute_column_widths(result) + [].tap do |widths| + result.columns.each_with_index do |column, i| + cells_in_column = [column] + result.rows.map { |r| r[i].nil? ? "NULL" : r[i].to_s } + widths << cells_in_column.map(&:length).max + end end end - end - def build_separator(widths) - padding = 1 - '+' + widths.map {|w| '-' * (w + (padding*2))}.join('+') + '+' - end + def build_separator(widths) + padding = 1 + "+" + widths.map { |w| "-" * (w + (padding*2)) }.join("+") + "+" + end - def build_cells(items, widths) - cells = [] - items.each_with_index do |item, i| - item = 'NULL' if item.nil? - justifier = item.is_a?(Numeric) ? 'rjust' : 'ljust' - cells << item.to_s.send(justifier, widths[i]) + def build_cells(items, widths) + cells = [] + items.each_with_index do |item, i| + item = "NULL" if item.nil? + justifier = item.is_a?(Numeric) ? "rjust" : "ljust" + cells << item.to_s.send(justifier, widths[i]) + end + "| " + cells.join(" | ") + " |" end - '| ' + cells.join(' | ') + ' |' - end - def build_footer(nrows, elapsed) - rows_label = nrows == 1 ? 'row' : 'rows' - "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed - end + def build_footer(nrows, elapsed) + rows_label = nrows == 1 ? "row" : "rows" + "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb index fbab654112..9d11ad28d4 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb @@ -2,14 +2,14 @@ module ActiveRecord module ConnectionAdapters module MySQL module Quoting # :nodoc: - QUOTED_TRUE, QUOTED_FALSE = '1', '0' + QUOTED_TRUE, QUOTED_FALSE = "1".freeze, "0".freeze def quote_column_name(name) - @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`" + @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze end def quote_table_name(name) - @quoted_table_names[name] ||= super.gsub('.', '`.`') + @quoted_table_names[name] ||= super.gsub(".", "`.`").freeze end def quoted_true @@ -32,19 +32,19 @@ module ActiveRecord if supports_datetime_with_precision? super else - super.sub(/\.\d{6}\z/, '') + super.sub(/\.\d{6}\z/, "") end end private - def _quote(value) - if value.is_a?(Type::Binary::Data) - "x'#{value.hex}'" - else - super + def _quote(value) + if value.is_a?(Type::Binary::Data) + "x'#{value.hex}'" + else + super + end end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb index fd2dc2aee8..d808b50332 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb @@ -7,60 +7,60 @@ module ActiveRecord private - def visit_DropForeignKey(name) - "DROP FOREIGN KEY #{name}" - end - - def visit_ColumnDefinition(o) - o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.unsigned) - super - end - - def visit_AddColumnDefinition(o) - add_column_position!(super, column_options(o.column)) - end + def visit_DropForeignKey(name) + "DROP FOREIGN KEY #{name}" + end - def visit_ChangeColumnDefinition(o) - change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}" - add_column_position!(change_column_sql, column_options(o.column)) - end + def visit_ColumnDefinition(o) + o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.unsigned) + super + end - def add_table_options!(create_sql, options) - add_sql_comment!(super, options[:comment]) - end + def visit_AddColumnDefinition(o) + add_column_position!(super, column_options(o.column)) + end - def column_options(o) - column_options = super - column_options[:charset] = o.charset - column_options - end + def visit_ChangeColumnDefinition(o) + change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}" + add_column_position!(change_column_sql, column_options(o.column)) + end - def add_column_options!(sql, options) - if charset = options[:charset] - sql << " CHARACTER SET #{charset}" + def add_table_options!(create_sql, options) + add_sql_comment!(super, options[:comment]) end - if collation = options[:collation] - sql << " COLLATE #{collation}" + def column_options(o) + column_options = super + column_options[:charset] = o.charset + column_options end - add_sql_comment!(super, options[:comment]) - end + def add_column_options!(sql, options) + if charset = options[:charset] + sql << " CHARACTER SET #{charset}" + end + + if collation = options[:collation] + sql << " COLLATE #{collation}" + end - def add_column_position!(sql, options) - if options[:first] - sql << " FIRST" - elsif options[:after] - sql << " AFTER #{quote_column_name(options[:after])}" + add_sql_comment!(super, options[:comment]) end - sql - end + def add_column_position!(sql, options) + if options[:first] + sql << " FIRST" + elsif options[:after] + sql << " AFTER #{quote_column_name(options[:after])}" + end - def index_in_create(table_name, column_name, options) - index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options) - add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})", comment) - end + sql + end + + def index_in_create(table_name, column_name, options) + index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options) + add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})", comment) + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb index 157e75dbf7..ce773ed75b 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb @@ -80,9 +80,9 @@ module ActiveRecord private - def create_column_definition(name, type) - MySQL::ColumnDefinition.new(name, type) - end + def create_column_definition(name, type) + MySQL::ColumnDefinition.new(name, type) + end end class Table < ActiveRecord::ConnectionAdapters::Table diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb index 2ba9657f24..39221eeb0c 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb @@ -5,17 +5,17 @@ module ActiveRecord def column_spec_for_primary_key(column) if column.bigint? spec = { id: :bigint.inspect } - spec[:default] = schema_default(column) || 'nil' unless column.auto_increment? + spec[:default] = schema_default(column) || "nil" unless column.auto_increment? else spec = super end - spec[:unsigned] = 'true' if column.unsigned? + spec[:unsigned] = "true" if column.unsigned? spec end def prepare_column_options(column) spec = super - spec[:unsigned] = 'true' if column.unsigned? + spec[:unsigned] = "true" if column.unsigned? spec end @@ -25,29 +25,29 @@ module ActiveRecord private - def default_primary_key?(column) - super && column.auto_increment? - end + def default_primary_key?(column) + super && column.auto_increment? + end - def schema_type(column) - if column.sql_type == 'tinyblob' - :blob - else - super + def schema_type(column) + if column.sql_type == "tinyblob" + :blob + else + super + end end - end - def schema_precision(column) - super unless /time/ === column.sql_type && column.precision == 0 - end + def schema_precision(column) + super unless /time/ === column.sql_type && column.precision == 0 + end - def schema_collation(column) - if column.collation && table_name = column.table_name - @table_collation_cache ||= {} - @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"] - column.collation.inspect if column.collation != @table_collation_cache[table_name] + def schema_collation(column) + if column.collation && table_name = column.table_name + @table_collation_cache ||= {} + @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"] + column.collation.inspect if column.collation != @table_collation_cache[table_name] + end end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb index e1e3f7b472..24dcf852e1 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb @@ -2,13 +2,12 @@ module ActiveRecord module ConnectionAdapters module MySQL class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc: - attr_reader :extra, :strict + attr_reader :extra - def initialize(type_metadata, extra: "", strict: false) + def initialize(type_metadata, extra: "") super(type_metadata) @type_metadata = type_metadata @extra = extra - @strict = strict end def ==(other) @@ -23,9 +22,9 @@ module ActiveRecord protected - def attributes_for_hash - [self.class, @type_metadata, extra, strict] - end + def attributes_for_hash + [self.class, @type_metadata, extra] + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 22d35f1db5..a3e2c913c5 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -1,9 +1,9 @@ -require 'active_record/connection_adapters/abstract_mysql_adapter' -require 'active_record/connection_adapters/mysql/database_statements' +require "active_record/connection_adapters/abstract_mysql_adapter" +require "active_record/connection_adapters/mysql/database_statements" -gem 'mysql2', '>= 0.3.18', '< 0.5' -require 'mysql2' -raise 'mysql2 0.4.3 is not supported. Please upgrade to 0.4.4+' if Mysql2::VERSION == '0.4.3' +gem "mysql2", ">= 0.3.18", "< 0.5" +require "mysql2" +raise "mysql2 0.4.3 is not supported. Please upgrade to 0.4.4+" if Mysql2::VERSION == "0.4.3" module ActiveRecord module ConnectionHandling # :nodoc: @@ -11,7 +11,7 @@ module ActiveRecord def mysql2_connection(config) config = config.symbolize_keys - config[:username] = 'root' if config[:username].nil? + config[:username] = "root" if config[:username].nil? config[:flags] ||= 0 if Mysql2::Client.const_defined? :FOUND_ROWS @@ -35,7 +35,7 @@ module ActiveRecord module ConnectionAdapters class Mysql2Adapter < AbstractMysqlAdapter - ADAPTER_NAME = 'Mysql2'.freeze + ADAPTER_NAME = "Mysql2".freeze include MySQL::DatabaseStatements @@ -46,7 +46,7 @@ module ActiveRecord end def supports_json? - !mariadb? && version >= '5.7.8' + !mariadb? && version >= "5.7.8" end def supports_comments? @@ -65,7 +65,7 @@ module ActiveRecord def each_hash(result) # :nodoc: if block_given? - result.each(:as => :hash, :symbolize_keys => true) do |row| + result.each(as: :hash, symbolize_keys: true) do |row| yield row end else @@ -90,7 +90,6 @@ module ActiveRecord #++ def active? - return false unless @connection @connection.ping end @@ -105,27 +104,24 @@ module ActiveRecord # Otherwise, this method does nothing. def disconnect! super - unless @connection.nil? - @connection.close - @connection = nil - end + @connection.close end private - def connect - @connection = Mysql2::Client.new(@config) - configure_connection - end + def connect + @connection = Mysql2::Client.new(@config) + configure_connection + end - def configure_connection - @connection.query_options.merge!(:as => :array) - super - end + def configure_connection + @connection.query_options.merge!(as: :array) + super + end - def full_version - @full_version ||= @connection.server_info[:version] - end + def full_version + @full_version ||= @connection.server_info[:version] + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb index 6f2e03b370..092543259f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb @@ -4,7 +4,7 @@ module ActiveRecord module DatabaseStatements def explain(arel, binds = []) sql = "EXPLAIN #{to_sql(arel, binds)}" - PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds)) + PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", binds)) end def select_value(arel, name = nil, binds = []) @@ -74,9 +74,9 @@ module ActiveRecord # (2) $12.345.678,12 case data when /^-?\D+[\d,]+\.\d{2}$/ # (1) - data.gsub!(/[^-\d.]/, '') + data.gsub!(/[^-\d.]/, "") when /^-?\D+[\d.]+,\d{2}$/ # (2) - data.gsub!(/[^-\d,]/, '').sub!(/,/, '.') + data.gsub!(/[^-\d,]/, "").sub!(/,/, ".") end end end @@ -89,17 +89,17 @@ module ActiveRecord end end - # Executes an SQL statement, returning a PGresult object on success - # or raising a PGError exception otherwise. - # Note: the PGresult object is manually memory managed; if you don't - # need it specifically, you many want consider the exec_query wrapper. + # Executes an SQL statement, returning a PG::Result object on success + # or raising a PG::Error exception otherwise. + # Note: the PG::Result object is manually memory managed; if you don't + # need it specifically, you may want consider the <tt>exec_query</tt> wrapper. def execute(sql, name = nil) log(sql, name) do @connection.async_exec(sql) end end - def exec_query(sql, name = 'SQL', binds = [], prepare: false) + def exec_query(sql, name = "SQL", binds = [], prepare: false) execute_and_clear(sql, name, binds, prepare: prepare) do |result| types = {} fields = result.fields @@ -112,8 +112,8 @@ module ActiveRecord end end - def exec_delete(sql, name = 'SQL', binds = []) - execute_and_clear(sql, name, binds) {|result| result.cmd_tuples } + def exec_delete(sql, name = nil, binds = []) + execute_and_clear(sql, name, binds) { |result| result.cmd_tuples } end alias :exec_update :exec_delete @@ -124,24 +124,29 @@ module ActiveRecord pk = primary_key(table_ref) if table_ref end - if pk && use_insert_returning? + if pk = suppress_composite_primary_key(pk) sql = "#{sql} RETURNING #{quote_column_name(pk)}" end super end + protected :sql_for_insert - def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) - val = exec_query(sql, name, binds) - if !use_insert_returning? && pk + def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) + if use_insert_returning? || pk == false + super + else + result = exec_query(sql, name, binds) unless sequence_name table_ref = extract_table_ref_from_insert_sql(sql) - sequence_name = default_sequence_name(table_ref, pk) - return val unless sequence_name + if table_ref + pk = primary_key(table_ref) if pk.nil? + pk = suppress_composite_primary_key(pk) + sequence_name = default_sequence_name(table_ref, pk) + end + return result unless sequence_name end last_insert_id_result(sequence_name) - else - val end end @@ -164,6 +169,12 @@ module ActiveRecord def exec_rollback_db_transaction execute "ROLLBACK" end + + private + + def suppress_composite_primary_key(pk) + pk unless pk.is_a?(Array) + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb index 789b88912c..99f3a5bbdf 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb @@ -26,12 +26,12 @@ module ActiveRecord pp = [] pp << header.center(width).rstrip - pp << '-' * width + pp << "-" * width - pp += lines.map {|line| " #{line}"} + pp += lines.map { |line| " #{line}" } nrows = result.rows.length - rows_label = nrows == 1 ? 'row' : 'rows' + rows_label = nrows == 1 ? "row" : "rows" pp << "(#{nrows} #{rows_label})" pp.join("\n") + "\n" diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb index 68752cdd80..0e526f6201 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb @@ -1,25 +1,25 @@ -require 'active_record/connection_adapters/postgresql/oid/array' -require 'active_record/connection_adapters/postgresql/oid/bit' -require 'active_record/connection_adapters/postgresql/oid/bit_varying' -require 'active_record/connection_adapters/postgresql/oid/bytea' -require 'active_record/connection_adapters/postgresql/oid/cidr' -require 'active_record/connection_adapters/postgresql/oid/date_time' -require 'active_record/connection_adapters/postgresql/oid/decimal' -require 'active_record/connection_adapters/postgresql/oid/enum' -require 'active_record/connection_adapters/postgresql/oid/hstore' -require 'active_record/connection_adapters/postgresql/oid/inet' -require 'active_record/connection_adapters/postgresql/oid/json' -require 'active_record/connection_adapters/postgresql/oid/jsonb' -require 'active_record/connection_adapters/postgresql/oid/money' -require 'active_record/connection_adapters/postgresql/oid/point' -require 'active_record/connection_adapters/postgresql/oid/rails_5_1_point' -require 'active_record/connection_adapters/postgresql/oid/range' -require 'active_record/connection_adapters/postgresql/oid/specialized_string' -require 'active_record/connection_adapters/postgresql/oid/uuid' -require 'active_record/connection_adapters/postgresql/oid/vector' -require 'active_record/connection_adapters/postgresql/oid/xml' +require "active_record/connection_adapters/postgresql/oid/array" +require "active_record/connection_adapters/postgresql/oid/bit" +require "active_record/connection_adapters/postgresql/oid/bit_varying" +require "active_record/connection_adapters/postgresql/oid/bytea" +require "active_record/connection_adapters/postgresql/oid/cidr" +require "active_record/connection_adapters/postgresql/oid/date_time" +require "active_record/connection_adapters/postgresql/oid/decimal" +require "active_record/connection_adapters/postgresql/oid/enum" +require "active_record/connection_adapters/postgresql/oid/hstore" +require "active_record/connection_adapters/postgresql/oid/inet" +require "active_record/connection_adapters/postgresql/oid/json" +require "active_record/connection_adapters/postgresql/oid/jsonb" +require "active_record/connection_adapters/postgresql/oid/money" +require "active_record/connection_adapters/postgresql/oid/point" +require "active_record/connection_adapters/postgresql/oid/legacy_point" +require "active_record/connection_adapters/postgresql/oid/range" +require "active_record/connection_adapters/postgresql/oid/specialized_string" +require "active_record/connection_adapters/postgresql/oid/uuid" +require "active_record/connection_adapters/postgresql/oid/vector" +require "active_record/connection_adapters/postgresql/oid/xml" -require 'active_record/connection_adapters/postgresql/oid/type_map_initializer' +require "active_record/connection_adapters/postgresql/oid/type_map_initializer" module ActiveRecord module ConnectionAdapters diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb index 87593ef704..b969503178 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb @@ -8,7 +8,7 @@ module ActiveRecord attr_reader :subtype, :delimiter delegate :type, :user_input_in_time_zone, :limit, to: :subtype - def initialize(subtype, delimiter = ',') + def initialize(subtype, delimiter = ",") @subtype = subtype @delimiter = delimiter @@ -33,7 +33,11 @@ module ActiveRecord def serialize(value) if value.is_a?(::Array) - @pg_encoder.encode(type_cast_array(value, :serialize)) + result = @pg_encoder.encode(type_cast_array(value, :serialize)) + if encoding = determine_encoding_of_strings(value) + result.encode!(encoding) + end + result else super end @@ -56,13 +60,20 @@ module ActiveRecord private - def type_cast_array(value, method) - if value.is_a?(::Array) - value.map { |item| type_cast_array(item, method) } - else - @subtype.public_send(method, value) + def type_cast_array(value, method) + if value.is_a?(::Array) + value.map { |item| type_cast_array(item, method) } + else + @subtype.public_send(method, value) + end + end + + def determine_encoding_of_strings(value) + case value + when ::Array then determine_encoding_of_strings(value.first) + when ::String then value.encoding + end end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb index ea0fa2517f..74bff229ea 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb @@ -7,7 +7,7 @@ module ActiveRecord :bit end - def cast(value) + def cast_value(value) if ::String === value case value when /^0x/i @@ -16,7 +16,7 @@ module ActiveRecord value # Bit-string notation end else - value + value.to_s end end @@ -43,7 +43,7 @@ module ActiveRecord protected - attr_reader :value + attr_reader :value end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb index 838cb63281..5225609e37 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb @@ -1,4 +1,4 @@ -require 'ipaddr' +require "ipaddr" module ActiveRecord module ConnectionAdapters diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb index 424769f765..b7acbf7178 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb @@ -5,8 +5,8 @@ module ActiveRecord class DateTime < Type::DateTime # :nodoc: def cast_value(value) case value - when 'infinity' then ::Float::INFINITY - when '-infinity' then -::Float::INFINITY + when "infinity" then ::Float::INFINITY + when "-infinity" then -::Float::INFINITY when / BC$/ astronomical_year = format("%04d", -value[/^\d+/].to_i + 1) super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year)) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb index 91d339f32c..950d23d516 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb @@ -9,9 +9,9 @@ module ActiveRecord private - def cast_value(value) - value.to_s - end + def cast_value(value) + value.to_s + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb index 9270fc9f21..2d3e6a925d 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb @@ -12,7 +12,7 @@ module ActiveRecord def deserialize(value) if value.is_a?(::String) ::Hash[value.scan(HstorePair).map { |k, v| - v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1') + v = v.upcase == "NULL" ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1') k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1') [k, v] }] @@ -23,7 +23,7 @@ module ActiveRecord def serialize(value) if value.is_a?(::Hash) - value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ') + value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(", ") else value end @@ -35,23 +35,23 @@ module ActiveRecord private - HstorePair = begin - quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/ - unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/ - /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/ - end + HstorePair = begin + quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/ + unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/ + /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/ + end - def escape_hstore(value) - if value.nil? - 'NULL' - else - if value == "" - '""' + def escape_hstore(value) + if value.nil? + "NULL" else - '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1') + if value == "" + '""' + else + '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1') + end end end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb new file mode 100644 index 0000000000..775eecaf85 --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb @@ -0,0 +1,43 @@ +module ActiveRecord + module ConnectionAdapters + module PostgreSQL + module OID # :nodoc: + class LegacyPoint < Type::Value # :nodoc: + include Type::Helpers::Mutable + + def type + :point + end + + def cast(value) + case value + when ::String + if value[0] == "(" && value[-1] == ")" + value = value[1...-1] + end + cast(value.split(",")) + when ::Array + value.map { |v| Float(v) } + else + value + end + end + + def serialize(value) + if value.is_a?(::Array) + "(#{number_for_point(value[0])},#{number_for_point(value[1])})" + else + super + end + end + + private + + def number_for_point(number) + number.to_s.gsub(/\.0$/, "") + end + end + end + end + end +end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb index dcc12ae2a4..7a91272d1c 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/money.rb @@ -25,9 +25,9 @@ module ActiveRecord value.sub!(/^\((.+)\)$/, '-\1') # (4) case value when /^-?\D+[\d,]+\.\d{2}$/ # (1) - value.gsub!(/[^-\d.]/, '') + value.gsub!(/[^-\d.]/, "") when /^-?\D+[\d.]+,\d{2}$/ # (2) - value.gsub!(/[^-\d,]/, '').sub!(/,/, '.') + value.gsub!(/[^-\d,]/, "").sub!(/,/, ".") end super(value) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb index bf565bcf47..7c764e7287 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb @@ -1,4 +1,6 @@ module ActiveRecord + Point = Struct.new(:x, :y) + module ConnectionAdapters module PostgreSQL module OID # :nodoc: @@ -12,20 +14,34 @@ module ActiveRecord def cast(value) case value when ::String - if value[0] == '(' && value[-1] == ')' + return if value.blank? + + if value[0] == "(" && value[-1] == ")" value = value[1...-1] end - cast(value.split(',')) + x, y = value.split(",") + build_point(x, y) when ::Array - value.map { |v| Float(v) } + build_point(*value) else value end end def serialize(value) - if value.is_a?(::Array) - "(#{number_for_point(value[0])},#{number_for_point(value[1])})" + case value + when ActiveRecord::Point + "(#{number_for_point(value.x)},#{number_for_point(value.y)})" + when ::Array + serialize(build_point(*value)) + else + super + end + end + + def type_cast_for_schema(value) + if ActiveRecord::Point === value + [value.x, value.y] else super end @@ -33,9 +49,13 @@ module ActiveRecord private - def number_for_point(number) - number.to_s.gsub(/\.0$/, '') - end + def number_for_point(number) + number.to_s.gsub(/\.0$/, "") + end + + def build_point(x, y) + ActiveRecord::Point.new(Float(x), Float(y)) + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb deleted file mode 100644 index 4da240edb2..0000000000 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +++ /dev/null @@ -1,52 +0,0 @@ -module ActiveRecord - Point = Struct.new(:x, :y) - - module ConnectionAdapters - module PostgreSQL - module OID # :nodoc: - class Rails51Point < Type::Value # :nodoc: - include Type::Helpers::Mutable - - def type - :point - end - - def cast(value) - case value - when ::String - return if value.blank? - - if value[0] == '(' && value[-1] == ')' - value = value[1...-1] - end - x, y = value.split(",") - build_point(x, y) - when ::Array - build_point(*value) - else - value - end - end - - def serialize(value) - if value.is_a?(ActiveRecord::Point) - "(#{number_for_point(value.x)},#{number_for_point(value.y)})" - else - super - end - end - - private - - def number_for_point(number) - number.to_s.gsub(/\.0$/, '') - end - - def build_point(x, y) - ActiveRecord::Point.new(Float(x), Float(y)) - end - end - end - end - end -end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb index a8d2310035..2c714f4018 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/filters' +require "active_support/core_ext/string/filters" module ActiveRecord module ConnectionAdapters @@ -14,11 +14,11 @@ module ActiveRecord end def type_cast_for_schema(value) - value.inspect.gsub('Infinity', '::Float::INFINITY') + value.inspect.gsub("Infinity", "::Float::INFINITY") end def cast_value(value) - return if value == 'empty' + return if value == "empty" return value unless value.is_a?(::String) extracted = extract_bounds(value) @@ -55,37 +55,37 @@ module ActiveRecord private - def type_cast_single(value) - infinity?(value) ? value : @subtype.deserialize(value) - end + def type_cast_single(value) + infinity?(value) ? value : @subtype.deserialize(value) + end - def type_cast_single_for_database(value) - infinity?(value) ? '' : @subtype.serialize(value) - end + def type_cast_single_for_database(value) + infinity?(value) ? "" : @subtype.serialize(value) + end - def extract_bounds(value) - from, to = value[1..-2].split(',') - { - from: (value[1] == ',' || from == '-infinity') ? infinity(negative: true) : from, - to: (value[-2] == ',' || to == 'infinity') ? infinity : to, - exclude_start: (value[0] == '('), - exclude_end: (value[-1] == ')') - } - end + def extract_bounds(value) + from, to = value[1..-2].split(",") + { + from: (value[1] == "," || from == "-infinity") ? infinity(negative: true) : from, + to: (value[-2] == "," || to == "infinity") ? infinity : to, + exclude_start: (value[0] == "("), + exclude_end: (value[-1] == ")") + } + end - def infinity(negative: false) - if subtype.respond_to?(:infinity) - subtype.infinity(negative: negative) - elsif negative - -::Float::INFINITY - else - ::Float::INFINITY + def infinity(negative: false) + if subtype.respond_to?(:infinity) + subtype.infinity(negative: negative) + elsif negative + -::Float::INFINITY + else + ::Float::INFINITY + end end - end - def infinity?(value) - value.respond_to?(:infinite?) && value.infinite? - end + def infinity?(value) + value.respond_to?(:infinite?) && value.infinite? + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb index 6155e53632..d9ae1aa7a2 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb @@ -13,13 +13,13 @@ module ActiveRecord end def run(records) - nodes = records.reject { |row| @store.key? row['oid'].to_i } - mapped, nodes = nodes.partition { |row| @store.key? row['typname'] } - ranges, nodes = nodes.partition { |row| row['typtype'] == 'r'.freeze } - enums, nodes = nodes.partition { |row| row['typtype'] == 'e'.freeze } - domains, nodes = nodes.partition { |row| row['typtype'] == 'd'.freeze } - arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in'.freeze } - composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 } + nodes = records.reject { |row| @store.key? row["oid"].to_i } + mapped, nodes = nodes.partition { |row| @store.key? row["typname"] } + ranges, nodes = nodes.partition { |row| row["typtype"] == "r".freeze } + enums, nodes = nodes.partition { |row| row["typtype"] == "e".freeze } + domains, nodes = nodes.partition { |row| row["typtype"] == "d".freeze } + arrays, nodes = nodes.partition { |row| row["typinput"] == "array_in".freeze } + composites, nodes = nodes.partition { |row| row["typelem"].to_i != 0 } mapped.each { |row| register_mapped_type(row) } enums.each { |row| register_enum_type(row) } @@ -42,66 +42,66 @@ module ActiveRecord end private - def register_mapped_type(row) - alias_type row['oid'], row['typname'] - end + def register_mapped_type(row) + alias_type row["oid"], row["typname"] + end - def register_enum_type(row) - register row['oid'], OID::Enum.new - end + def register_enum_type(row) + register row["oid"], OID::Enum.new + end - def register_array_type(row) - register_with_subtype(row['oid'], row['typelem'].to_i) do |subtype| - OID::Array.new(subtype, row['typdelim']) + def register_array_type(row) + register_with_subtype(row["oid"], row["typelem"].to_i) do |subtype| + OID::Array.new(subtype, row["typdelim"]) + end end - end - def register_range_type(row) - register_with_subtype(row['oid'], row['rngsubtype'].to_i) do |subtype| - OID::Range.new(subtype, row['typname'].to_sym) + def register_range_type(row) + register_with_subtype(row["oid"], row["rngsubtype"].to_i) do |subtype| + OID::Range.new(subtype, row["typname"].to_sym) + end end - end - def register_domain_type(row) - if base_type = @store.lookup(row["typbasetype"].to_i) - register row['oid'], base_type - else - warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}." + def register_domain_type(row) + if base_type = @store.lookup(row["typbasetype"].to_i) + register row["oid"], base_type + else + warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}." + end end - end - def register_composite_type(row) - if subtype = @store.lookup(row['typelem'].to_i) - register row['oid'], OID::Vector.new(row['typdelim'], subtype) + def register_composite_type(row) + if subtype = @store.lookup(row["typelem"].to_i) + register row["oid"], OID::Vector.new(row["typdelim"], subtype) + end end - end - def register(oid, oid_type = nil, &block) - oid = assert_valid_registration(oid, oid_type || block) - if block_given? - @store.register_type(oid, &block) - else - @store.register_type(oid, oid_type) + def register(oid, oid_type = nil, &block) + oid = assert_valid_registration(oid, oid_type || block) + if block_given? + @store.register_type(oid, &block) + else + @store.register_type(oid, oid_type) + end end - end - def alias_type(oid, target) - oid = assert_valid_registration(oid, target) - @store.alias_type(oid, target) - end + def alias_type(oid, target) + oid = assert_valid_registration(oid, target) + @store.alias_type(oid, target) + end - def register_with_subtype(oid, target_oid) - if @store.key?(target_oid) - register(oid) do |_, *args| - yield @store.lookup(target_oid, *args) + def register_with_subtype(oid, target_oid) + if @store.key?(target_oid) + register(oid) do |_, *args| + yield @store.lookup(target_oid, *args) + end end end - end - def assert_valid_registration(oid, oid_type) - raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil? - oid.to_i - end + def assert_valid_registration(oid, oid_type) + raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil? + oid.to_i + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 6414459cd1..b5031d890f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -28,7 +28,7 @@ module ActiveRecord # - "schema.name".table_name # - "schema.name"."table.name" def quote_table_name(name) # :nodoc: - @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted + @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze end # Quotes schema names for use in SQL queries. @@ -42,7 +42,7 @@ module ActiveRecord # Quotes column names for use in SQL queries. def quote_column_name(name) # :nodoc: - @quoted_column_names[name] ||= PGconn.quote_ident(super) + @quoted_column_names[name] ||= PGconn.quote_ident(super).freeze end # Quote date/time values for use in SQL input. @@ -58,7 +58,7 @@ module ActiveRecord def quote_default_expression(value, column) # :nodoc: if value.is_a?(Proc) value.call - elsif column.type == :uuid && value =~ /\(\)/ + elsif column.type == :uuid && value.include?("()") value # Does not quote function default values for UUID columns elsif column.respond_to?(:array?) value = type_cast_from_column(column, value) @@ -74,42 +74,42 @@ module ActiveRecord private - def _quote(value) - case value - when Type::Binary::Data - "'#{escape_bytea(value.to_s)}'" - when OID::Xml::Data - "xml '#{quote_string(value.to_s)}'" - when OID::Bit::Data - if value.binary? - "B'#{value}'" - elsif value.hex? - "X'#{value}'" - end - when Float - if value.infinite? || value.nan? - "'#{value}'" + def _quote(value) + case value + when Type::Binary::Data + "'#{escape_bytea(value.to_s)}'" + when OID::Xml::Data + "xml '#{quote_string(value.to_s)}'" + when OID::Bit::Data + if value.binary? + "B'#{value}'" + elsif value.hex? + "X'#{value}'" + end + when Float + if value.infinite? || value.nan? + "'#{value}'" + else + super + end else super end - else - super end - end - def _type_cast(value) - case value - when Type::Binary::Data - # Return a bind param hash with format as binary. - # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc - # for more information - { value: value.to_s, format: 1 } - when OID::Xml::Data, OID::Bit::Data - value.to_s - else - super + def _type_cast(value) + case value + when Type::Binary::Data + # Return a bind param hash with format as binary. + # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc + # for more information + { value: value.to_s, format: 1 } + when OID::Xml::Data, OID::Bit::Data + value.to_s + else + super + end end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb index 6399bddbee..a11dbe7dce 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb @@ -31,7 +31,7 @@ module ActiveRecord # a record (as primary keys cannot be +nil+). This might be done via the # +SecureRandom.uuid+ method and a +before_save+ callback, for instance. def primary_key(name, type = :primary_key, **options) - options[:default] = options.fetch(:default, 'uuid_generate_v4()') if type == :uuid + options[:default] = options.fetch(:default, "uuid_generate_v4()") if type == :uuid super end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb index a1e10fd364..c20baf655c 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb @@ -5,7 +5,7 @@ module ActiveRecord def column_spec_for_primary_key(column) spec = super if schema_type(column) == :uuid - spec[:default] ||= 'nil' + spec[:default] ||= "nil" end spec end @@ -13,7 +13,7 @@ module ActiveRecord # Adds +:array+ option to the default set def prepare_column_options(column) spec = super - spec[:array] = 'true' if column.array? + spec[:array] = "true" if column.array? spec end @@ -24,23 +24,23 @@ module ActiveRecord private - def default_primary_key?(column) - schema_type(column) == :serial - end + def default_primary_key?(column) + schema_type(column) == :serial + end - def schema_type(column) - return super unless column.serial? + def schema_type(column) + return super unless column.serial? - if column.bigint? - :bigserial - else - :serial + if column.bigint? + :bigserial + else + :serial + end end - end - def schema_expression(column) - super unless column.serial? - end + def schema_expression(column) + super unless column.serial? + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index f6860b9aba..69f797da3a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/strip' +require "active_support/core_ext/string/strip" module ActiveRecord module ConnectionAdapters @@ -6,17 +6,17 @@ module ActiveRecord class SchemaCreation < AbstractAdapter::SchemaCreation private - def visit_ColumnDefinition(o) - o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.array) - super - end + def visit_ColumnDefinition(o) + o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.array) + super + end - def add_column_options!(sql, options) - if options[:collation] - sql << " COLLATE \"#{options[:collation]}\"" + def add_column_options!(sql, options) + if options[:collation] + sql << " COLLATE \"#{options[:collation]}\"" + end + super end - super - end end module SchemaStatements @@ -36,26 +36,26 @@ module ActiveRecord # create_database config[:database], config # create_database 'foo_development', encoding: 'unicode' def create_database(name, options = {}) - options = { encoding: 'utf8' }.merge!(options.symbolize_keys) + options = { encoding: "utf8" }.merge!(options.symbolize_keys) option_string = options.inject("") do |memo, (key, value)| memo += case key - when :owner - " OWNER = \"#{value}\"" - when :template - " TEMPLATE = \"#{value}\"" - when :encoding - " ENCODING = '#{value}'" - when :collation - " LC_COLLATE = '#{value}'" - when :ctype - " LC_CTYPE = '#{value}'" - when :tablespace - " TABLESPACE = \"#{value}\"" - when :connection_limit - " CONNECTION LIMIT = #{value}" + when :owner + " OWNER = \"#{value}\"" + when :template + " TEMPLATE = \"#{value}\"" + when :encoding + " ENCODING = '#{value}'" + when :collation + " LC_COLLATE = '#{value}'" + when :ctype + " LC_CTYPE = '#{value}'" + when :tablespace + " TABLESPACE = \"#{value}\"" + when :connection_limit + " CONNECTION LIMIT = #{value}" else - "" + "" end end @@ -78,15 +78,15 @@ module ActiveRecord MSG end - select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", 'SCHEMA') + select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", "SCHEMA") end def data_sources # :nodoc - select_values(<<-SQL, 'SCHEMA') + select_values(<<-SQL, "SCHEMA") SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace - WHERE c.relkind IN ('r', 'v','m') -- (r)elation/table, (v)iew, (m)aterialized view + WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view AND n.nspname = ANY (current_schemas(false)) SQL end @@ -108,18 +108,18 @@ module ActiveRecord name = Utils.extract_schema_qualified_name(name.to_s) return false unless name.identifier - select_value(<<-SQL, 'SCHEMA').to_i > 0 - SELECT COUNT(*) + select_values(<<-SQL, "SCHEMA").any? + SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view - AND c.relname = '#{name.identifier}' - AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'} + AND c.relname = #{quote(name.identifier)} + AND n.nspname = #{name.schema ? quote(name.schema) : "ANY (current_schemas(false))"} SQL end def views # :nodoc: - select_values(<<-SQL, 'SCHEMA') + select_values(<<-SQL, "SCHEMA") SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace @@ -132,13 +132,13 @@ module ActiveRecord name = Utils.extract_schema_qualified_name(view_name.to_s) return false unless name.identifier - select_values(<<-SQL, 'SCHEMA').any? + select_values(<<-SQL, "SCHEMA").any? SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('v','m') -- (v)iew, (m)aterialized view - AND c.relname = '#{name.identifier}' - AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'} + AND c.relname = #{quote(name.identifier)} + AND n.nspname = #{name.schema ? quote(name.schema) : "ANY (current_schemas(false))"} SQL end @@ -148,7 +148,7 @@ module ActiveRecord # Returns true if schema exists. def schema_exists?(name) - select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0 + select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", "SCHEMA").to_i > 0 end # Verifies existence of an index with a given name. @@ -156,7 +156,7 @@ module ActiveRecord table = Utils.extract_schema_qualified_name(table_name.to_s) index = Utils.extract_schema_qualified_name(index_name.to_s) - select_value(<<-SQL, 'SCHEMA').to_i > 0 + select_value(<<-SQL, "SCHEMA").to_i > 0 SELECT COUNT(*) FROM pg_class t INNER JOIN pg_index d ON t.oid = d.indrelid @@ -173,7 +173,7 @@ module ActiveRecord def indexes(table_name, name = nil) table = Utils.extract_schema_qualified_name(table_name.to_s) - result = query(<<-SQL, 'SCHEMA') + result = query(<<-SQL, "SCHEMA") SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid, pg_catalog.obj_description(i.oid, 'pg_class') AS comment, (SELECT COUNT(*) FROM pg_opclass o @@ -238,11 +238,17 @@ module ActiveRecord PostgreSQLColumn.new(*args) end + def table_options(table_name) # :nodoc: + if comment = table_comment(table_name) + { comment: comment } + end + end + # Returns a comment stored in database for given table def table_comment(table_name) # :nodoc: name = Utils.extract_schema_qualified_name(table_name.to_s) if name.identifier - select_value(<<-SQL.strip_heredoc, 'SCHEMA') + select_value(<<-SQL.strip_heredoc, "SCHEMA") SELECT pg_catalog.obj_description(c.oid, 'pg_class') FROM pg_catalog.pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace @@ -255,32 +261,32 @@ module ActiveRecord # Returns the current database name. def current_database - select_value('select current_database()', 'SCHEMA') + select_value("select current_database()", "SCHEMA") end # Returns the current schema name. def current_schema - select_value('SELECT current_schema', 'SCHEMA') + select_value("SELECT current_schema", "SCHEMA") end # Returns the current database encoding format. def encoding - select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA') + select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA") end # Returns the current database collation. def collation - select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA') + select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA") end # Returns the current database ctype. def ctype - select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA') + select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA") end # Returns an array of schema names. def schema_names - select_values(<<-SQL, 'SCHEMA') + select_values(<<-SQL, "SCHEMA") SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' @@ -290,7 +296,7 @@ module ActiveRecord end # Creates a schema for the given schema name. - def create_schema schema_name + def create_schema(schema_name) execute "CREATE SCHEMA #{quote_schema_name(schema_name)}" end @@ -306,37 +312,37 @@ module ActiveRecord # This should be not be called manually but set in database.yml. def schema_search_path=(schema_csv) if schema_csv - execute("SET search_path TO #{schema_csv}", 'SCHEMA') + execute("SET search_path TO #{schema_csv}", "SCHEMA") @schema_search_path = schema_csv end end # Returns the active schema search path. def schema_search_path - @schema_search_path ||= select_value('SHOW search_path', 'SCHEMA') + @schema_search_path ||= select_value("SHOW search_path", "SCHEMA") end # Returns the current client message level. def client_min_messages - select_value('SHOW client_min_messages', 'SCHEMA') + select_value("SHOW client_min_messages", "SCHEMA") end # Set the client message level. def client_min_messages=(level) - execute("SET client_min_messages TO '#{level}'", 'SCHEMA') + execute("SET client_min_messages TO '#{level}'", "SCHEMA") end # Returns the sequence name for a table's primary key or some other specified key. - def default_sequence_name(table_name, pk = nil) #:nodoc: - result = serial_sequence(table_name, pk || 'id') + def default_sequence_name(table_name, pk = "id") #:nodoc: + result = serial_sequence(table_name, pk) return nil unless result Utils.extract_schema_qualified_name(result).to_s rescue ActiveRecord::StatementInvalid - PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s + PostgreSQL::Name.new(nil, "#{table_name}_#{pk}_seq").to_s end def serial_sequence(table, column) - select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", 'SCHEMA') + select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", "SCHEMA") end # Sets the sequence of a table's primary key to the specified value. @@ -347,7 +353,7 @@ module ActiveRecord if sequence quoted_sequence = quote_table_name(sequence) - select_value("SELECT setval('#{quoted_sequence}', #{value})", 'SCHEMA') + select_value("SELECT setval('#{quoted_sequence}', #{value})", "SCHEMA") else @logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger end @@ -356,7 +362,7 @@ module ActiveRecord # Resets the sequence of a table's primary key to the maximum value. def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc: - unless pk and sequence + unless pk && sequence default_pk, default_sequence = pk_and_sequence_for(table) pk ||= default_pk @@ -370,7 +376,7 @@ module ActiveRecord if pk && sequence quoted_sequence = quote_table_name(sequence) - select_value(<<-end_sql, 'SCHEMA') + select_value(<<-end_sql, "SCHEMA") SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false) end_sql end @@ -380,7 +386,7 @@ module ActiveRecord def pk_and_sequence_for(table) #:nodoc: # First try looking for a sequence with a dependency on the # given table's primary key. - result = query(<<-end_sql, 'SCHEMA')[0] + result = query(<<-end_sql, "SCHEMA")[0] SELECT attr.attname, nsp.nspname, seq.relname FROM pg_class seq, pg_attribute attr, @@ -399,8 +405,8 @@ module ActiveRecord AND dep.refobjid = '#{quote_table_name(table)}'::regclass end_sql - if result.nil? or result.empty? - result = query(<<-end_sql, 'SCHEMA')[0] + if result.nil? || result.empty? + result = query(<<-end_sql, "SCHEMA")[0] SELECT attr.attname, nsp.nspname, CASE WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL @@ -431,11 +437,11 @@ module ActiveRecord end def primary_keys(table_name) # :nodoc: - select_values(<<-SQL.strip_heredoc, 'SCHEMA') + select_values(<<-SQL.strip_heredoc, "SCHEMA") WITH pk_constraint AS ( SELECT conrelid, unnest(conkey) AS connum FROM pg_constraint WHERE contype = 'p' - AND conrelid = '#{quote_table_name(table_name)}'::regclass + AND conrelid = #{quote(quote_table_name(table_name))}::regclass ), cons AS ( SELECT conrelid, connum, row_number() OVER() AS rownum FROM pk_constraint ) @@ -579,7 +585,7 @@ module ActiveRecord end def foreign_keys(table_name) - fk_info = select_all <<-SQL.strip_heredoc + fk_info = select_all(<<-SQL.strip_heredoc, "SCHEMA") SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete FROM pg_constraint c JOIN pg_class t1 ON c.conrelid = t1.oid @@ -595,23 +601,23 @@ module ActiveRecord fk_info.map do |row| options = { - column: row['column'], - name: row['name'], - primary_key: row['primary_key'] + column: row["column"], + name: row["name"], + primary_key: row["primary_key"] } - options[:on_delete] = extract_foreign_key_action(row['on_delete']) - options[:on_update] = extract_foreign_key_action(row['on_update']) + options[:on_delete] = extract_foreign_key_action(row["on_delete"]) + options[:on_update] = extract_foreign_key_action(row["on_update"]) - ForeignKeyDefinition.new(table_name, row['to_table'], options) + ForeignKeyDefinition.new(table_name, row["to_table"], options) end end def extract_foreign_key_action(specifier) # :nodoc: case specifier - when 'c'; :cascade - when 'n'; :nullify - when 'r'; :restrict + when "c"; :cascade + when "n"; :nullify + when "r"; :restrict end end @@ -621,48 +627,49 @@ module ActiveRecord # Maps logical Rails types to PostgreSQL-specific data types. def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil) - sql = case type.to_s - when 'binary' - # PostgreSQL doesn't support limits on binary (bytea) columns. - # The hard limit is 1GB, because of a 32-bit size field, and TOAST. - case limit - when nil, 0..0x3fffffff; super(type) - else raise(ActiveRecordError, "No binary type has byte size #{limit}.") - end - when 'text' - # PostgreSQL doesn't support limits on text columns. - # The hard limit is 1GB, according to section 8.3 in the manual. - case limit - when nil, 0..0x3fffffff; super(type) - else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.") - end - when 'integer' - case limit - when 1, 2; 'smallint' - when nil, 3, 4; 'integer' - when 5..8; 'bigint' - else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.") + sql = \ + case type.to_s + when "binary" + # PostgreSQL doesn't support limits on binary (bytea) columns. + # The hard limit is 1GB, because of a 32-bit size field, and TOAST. + case limit + when nil, 0..0x3fffffff; super(type) + else raise(ActiveRecordError, "No binary type has byte size #{limit}.") + end + when "text" + # PostgreSQL doesn't support limits on text columns. + # The hard limit is 1GB, according to section 8.3 in the manual. + case limit + when nil, 0..0x3fffffff; super(type) + else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.") + end + when "integer" + case limit + when 1, 2; "smallint" + when nil, 3, 4; "integer" + when 5..8; "bigint" + else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.") + end + else + super(type, limit, precision, scale) end - else - super(type, limit, precision, scale) - end - sql << '[]' if array && type != :primary_key + sql << "[]" if array && type != :primary_key sql end # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and # requires that the ORDER BY include the distinct column. def columns_for_distinct(columns, orders) #:nodoc: - order_columns = orders.reject(&:blank?).map{ |s| + order_columns = orders.reject(&:blank?).map { |s| # Convert Arel node to string s = s.to_sql unless s.is_a?(String) # Remove any ASC/DESC modifiers - s.gsub(/\s+(?:ASC|DESC)\b/i, '') - .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '') + s.gsub(/\s+(?:ASC|DESC)\b/i, "") + .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "") }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" } - [super, *order_columns].join(', ') + [super, *order_columns].join(", ") end def fetch_type_metadata(column_name, sql_type, oid, fmod) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb index b2c49989a4..bcef8ac715 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb @@ -27,9 +27,9 @@ module ActiveRecord protected - def attributes_for_hash - [self.class, @type_metadata, oid, fmod] - end + def attributes_for_hash + [self.class, @type_metadata, oid, fmod] + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index ddfc560747..acd1eeace7 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -1,6 +1,6 @@ # Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility -gem 'pg', '~> 0.18' -require 'pg' +gem "pg", "~> 0.18" +require "pg" require "active_record/connection_adapters/abstract_adapter" require "active_record/connection_adapters/postgresql/column" @@ -67,7 +67,7 @@ module ActiveRecord # In addition, default connection parameters of libpq can be set per environment variables. # See http://www.postgresql.org/docs/current/static/libpq-envars.html . class PostgreSQLAdapter < AbstractAdapter - ADAPTER_NAME = 'PostgreSQL'.freeze + ADAPTER_NAME = "PostgreSQL".freeze NATIVE_DATABASE_TYPES = { primary_key: "serial primary key", @@ -173,7 +173,7 @@ module ActiveRecord end def index_algorithms - { concurrently: 'CONCURRENTLY' } + { concurrently: "CONCURRENTLY" } end class StatementPool < ConnectionAdapters::StatementPool @@ -227,7 +227,7 @@ module ActiveRecord @type_map = Type::HashLookupTypeMap.new initialize_type_map(type_map) - @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"] + @local_tz = execute("SHOW TIME ZONE", "SCHEMA").first["TimeZone"] @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true end @@ -242,7 +242,7 @@ module ActiveRecord # Is this connection alive and ready for queries? def active? - @connection.query 'SELECT 1' + @connection.query "SELECT 1" true rescue PGError false @@ -259,9 +259,9 @@ module ActiveRecord clear_cache! reset_transaction unless @connection.transaction_status == ::PG::PQTRANS_IDLE - @connection.query 'ROLLBACK' + @connection.query "ROLLBACK" end - @connection.query 'DISCARD ALL' + @connection.query "DISCARD ALL" configure_connection end @@ -287,7 +287,7 @@ module ActiveRecord end def set_standard_conforming_strings - execute('SET standard_conforming_strings = on', 'SCHEMA') + execute("SET standard_conforming_strings = on", "SCHEMA") end def supports_ddl_transactions? @@ -344,7 +344,7 @@ module ActiveRecord def extension_enabled?(name) if supports_extensions? res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled", - 'SCHEMA' + "SCHEMA" res.cast_values.first end end @@ -359,7 +359,7 @@ module ActiveRecord # Returns the configured supported identifier length supported by PostgreSQL def table_alias_length - @table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i + @table_alias_length ||= query("SHOW max_identifier_length", "SCHEMA")[0][0].to_i end # Set the authorized user for this session @@ -381,7 +381,7 @@ module ActiveRecord end def lookup_cast_type(sql_type) # :nodoc: - oid = execute("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").first['oid'].to_i + oid = execute("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").first["oid"].to_i super(oid) end @@ -407,6 +407,7 @@ module ActiveRecord FOREIGN_KEY_VIOLATION = "23503" UNIQUE_VIOLATION = "23505" SERIALIZATION_FAILURE = "40001" + DEADLOCK_DETECTED = "40P01" def translate_exception(exception, message) return exception unless exception.respond_to?(:result) @@ -419,7 +420,9 @@ module ActiveRecord when VALUE_LIMIT_VIOLATION ValueTooLong.new(message) when SERIALIZATION_FAILURE - TransactionSerializationError.new(message) + SerializationFailure.new(message) + when DEADLOCK_DETECTED + Deadlocked.new(message) else super end @@ -427,65 +430,65 @@ module ActiveRecord private - def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc: + def get_oid_type(oid, fmod, column_name, sql_type = "") # :nodoc: if !type_map.key?(oid) load_additional_types(type_map, [oid]) end type_map.fetch(oid, fmod, sql_type) { warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String." - Type::Value.new.tap do |cast_type| + Type.default_value.tap do |cast_type| type_map.register_type(oid, cast_type) end } end def initialize_type_map(m) # :nodoc: - register_class_with_limit m, 'int2', Type::Integer - register_class_with_limit m, 'int4', Type::Integer - register_class_with_limit m, 'int8', Type::Integer - m.alias_type 'oid', 'int2' - m.register_type 'float4', Type::Float.new - m.alias_type 'float8', 'float4' - m.register_type 'text', Type::Text.new - register_class_with_limit m, 'varchar', Type::String - m.alias_type 'char', 'varchar' - m.alias_type 'name', 'varchar' - m.alias_type 'bpchar', 'varchar' - m.register_type 'bool', Type::Boolean.new - register_class_with_limit m, 'bit', OID::Bit - register_class_with_limit m, 'varbit', OID::BitVarying - m.alias_type 'timestamptz', 'timestamp' - m.register_type 'date', Type::Date.new - - m.register_type 'money', OID::Money.new - m.register_type 'bytea', OID::Bytea.new - m.register_type 'point', OID::Point.new - m.register_type 'hstore', OID::Hstore.new - m.register_type 'json', OID::Json.new - m.register_type 'jsonb', OID::Jsonb.new - m.register_type 'cidr', OID::Cidr.new - m.register_type 'inet', OID::Inet.new - m.register_type 'uuid', OID::Uuid.new - m.register_type 'xml', OID::Xml.new - m.register_type 'tsvector', OID::SpecializedString.new(:tsvector) - m.register_type 'macaddr', OID::SpecializedString.new(:macaddr) - m.register_type 'citext', OID::SpecializedString.new(:citext) - m.register_type 'ltree', OID::SpecializedString.new(:ltree) - m.register_type 'line', OID::SpecializedString.new(:line) - m.register_type 'lseg', OID::SpecializedString.new(:lseg) - m.register_type 'box', OID::SpecializedString.new(:box) - m.register_type 'path', OID::SpecializedString.new(:path) - m.register_type 'polygon', OID::SpecializedString.new(:polygon) - m.register_type 'circle', OID::SpecializedString.new(:circle) + register_class_with_limit m, "int2", Type::Integer + register_class_with_limit m, "int4", Type::Integer + register_class_with_limit m, "int8", Type::Integer + m.alias_type "oid", "int2" + m.register_type "float4", Type::Float.new + m.alias_type "float8", "float4" + m.register_type "text", Type::Text.new + register_class_with_limit m, "varchar", Type::String + m.alias_type "char", "varchar" + m.alias_type "name", "varchar" + m.alias_type "bpchar", "varchar" + m.register_type "bool", Type::Boolean.new + register_class_with_limit m, "bit", OID::Bit + register_class_with_limit m, "varbit", OID::BitVarying + m.alias_type "timestamptz", "timestamp" + m.register_type "date", Type::Date.new + + m.register_type "money", OID::Money.new + m.register_type "bytea", OID::Bytea.new + m.register_type "point", OID::Point.new + m.register_type "hstore", OID::Hstore.new + m.register_type "json", OID::Json.new + m.register_type "jsonb", OID::Jsonb.new + m.register_type "cidr", OID::Cidr.new + m.register_type "inet", OID::Inet.new + m.register_type "uuid", OID::Uuid.new + m.register_type "xml", OID::Xml.new + m.register_type "tsvector", OID::SpecializedString.new(:tsvector) + m.register_type "macaddr", OID::SpecializedString.new(:macaddr) + m.register_type "citext", OID::SpecializedString.new(:citext) + m.register_type "ltree", OID::SpecializedString.new(:ltree) + m.register_type "line", OID::SpecializedString.new(:line) + m.register_type "lseg", OID::SpecializedString.new(:lseg) + m.register_type "box", OID::SpecializedString.new(:box) + m.register_type "path", OID::SpecializedString.new(:path) + m.register_type "polygon", OID::SpecializedString.new(:polygon) + m.register_type "circle", OID::SpecializedString.new(:circle) # FIXME: why are we keeping these types as strings? - m.alias_type 'interval', 'varchar' + m.alias_type "interval", "varchar" - register_class_with_precision m, 'time', Type::Time - register_class_with_precision m, 'timestamp', OID::DateTime + register_class_with_precision m, "time", Type::Time + register_class_with_precision m, "timestamp", OID::DateTime - m.register_type 'numeric' do |_, fmod, sql_type| + m.register_type "numeric" do |_, fmod, sql_type| precision = extract_precision(sql_type) scale = extract_scale(sql_type) @@ -523,26 +526,26 @@ module ActiveRecord def extract_value_from_default(default) # :nodoc: case default # Quoted types - when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m - # The default 'now'::date is CURRENT_DATE - if $1 == "now".freeze && $2 == "date".freeze - nil - else - $1.gsub("''".freeze, "'".freeze) - end + when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m + # The default 'now'::date is CURRENT_DATE + if $1 == "now".freeze && $2 == "date".freeze + nil + else + $1.gsub("''".freeze, "'".freeze) + end # Boolean types - when 'true'.freeze, 'false'.freeze - default + when "true".freeze, "false".freeze + default # Numeric types - when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/ - $1 + when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/ + $1 # Object identifier types - when /\A-?\d+\z/ - $1 - else - # Anything else is blank, some user type, or some function - # and we can't know the value of that, so return nil. - nil + when /\A-?\d+\z/ + $1 + else + # Anything else is blank, some user type, or some function + # and we can't know the value of that, so return nil. + nil end end @@ -576,7 +579,7 @@ module ActiveRecord query += initializer.query_conditions_for_initial_load(type_map) end - execute_and_clear(query, 'SCHEMA', []) do |records| + execute_and_clear(query, "SCHEMA", []) do |records| initializer.run(records) end end @@ -597,15 +600,15 @@ module ActiveRecord end def exec_no_cache(sql, name, binds) - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } - log(sql, name, binds) { @connection.async_exec(sql, type_casted_binds) } + type_casted_binds = type_casted_binds(binds) + log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) } end def exec_cache(sql, name, binds) stmt_key = prepare_statement(sql) - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } + type_casted_binds = type_casted_binds(binds) - log(sql, name, binds, stmt_key) do + log(sql, name, binds, type_casted_binds, stmt_key) do @connection.exec_prepared(stmt_key, type_casted_binds) end rescue ActiveRecord::StatementInvalid => e @@ -631,7 +634,7 @@ module ActiveRecord # # Check here for more details: # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573 - CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze + CACHED_PLAN_HEURISTIC = "cached plan must not change result type".freeze def is_cached_plan_failure?(e) pgerror = e.cause code = pgerror.result.result_error_field(PGresult::PG_DIAG_SQLSTATE) @@ -687,7 +690,7 @@ module ActiveRecord if @config[:encoding] @connection.set_client_encoding(@config[:encoding]) end - self.client_min_messages = @config[:min_messages] || 'warning' + self.client_min_messages = @config[:min_messages] || "warning" self.schema_search_path = @config[:schema_search_path] || @config[:schema_order] # Use standard-conforming strings so we don't have to do the E'...' dance. @@ -697,27 +700,27 @@ module ActiveRecord # TIMESTAMP WITH ZONE types in UTC. # (SET TIME ZONE does not use an equals sign like other SET variables) if ActiveRecord::Base.default_timezone == :utc - execute("SET time zone 'UTC'", 'SCHEMA') + execute("SET time zone 'UTC'", "SCHEMA") elsif @local_tz - execute("SET time zone '#{@local_tz}'", 'SCHEMA') + execute("SET time zone '#{@local_tz}'", "SCHEMA") end # SET statements from :variables config hash # http://www.postgresql.org/docs/current/static/sql-set.html variables = @config[:variables] || {} variables.map do |k, v| - if v == ':default' || v == :default + if v == ":default" || v == :default # Sets the value to the global or compile default - execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA') + execute("SET SESSION #{k} TO DEFAULT", "SCHEMA") elsif !v.nil? - execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA') + execute("SET SESSION #{k} TO #{quote(v)}", "SCHEMA") end end end # Returns the current ID of a table's sequence. def last_insert_id_result(sequence_name) # :nodoc: - exec_query("SELECT currval('#{sequence_name}')", 'SQL') + exec_query("SELECT currval('#{sequence_name}')", "SQL") end # Returns the list of a table's column names, data types, and default values. @@ -739,7 +742,7 @@ module ActiveRecord # - format_type includes the column size constraint, e.g. varchar(50) # - ::regclass is a function that gives the id for a table name def column_definitions(table_name) # :nodoc: - query(<<-end_sql, 'SCHEMA') + query(<<-end_sql, "SCHEMA") SELECT a.attname, format_type(a.atttypid, a.atttypmod), pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod, (SELECT c.collname FROM pg_collation c, pg_type t @@ -747,7 +750,7 @@ module ActiveRecord col_description(a.attrelid, a.attnum) AS comment FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum - WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass + WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum end_sql @@ -768,10 +771,14 @@ module ActiveRecord sql = <<-end_sql SELECT exists( SELECT * FROM pg_proc + WHERE proname = 'lower' + AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector + ) OR exists( + SELECT * FROM pg_proc INNER JOIN pg_cast - ON casttarget::text::oidvector = proargtypes + ON ARRAY[casttarget]::oidvector = proargtypes WHERE proname = 'lower' - AND castsource = '#{column.sql_type}'::regtype::oid + AND castsource = #{quote column.sql_type}::regtype ) end_sql execute_and_clear(sql, "SCHEMA", []) do |result| @@ -791,13 +798,13 @@ module ActiveRecord def add_pg_decoders coders_by_name = { - 'int2' => PG::TextDecoder::Integer, - 'int4' => PG::TextDecoder::Integer, - 'int8' => PG::TextDecoder::Integer, - 'oid' => PG::TextDecoder::Integer, - 'float4' => PG::TextDecoder::Float, - 'float8' => PG::TextDecoder::Float, - 'bool' => PG::TextDecoder::Boolean, + "int2" => PG::TextDecoder::Integer, + "int4" => PG::TextDecoder::Integer, + "int8" => PG::TextDecoder::Integer, + "oid" => PG::TextDecoder::Integer, + "float4" => PG::TextDecoder::Float, + "float8" => PG::TextDecoder::Float, + "bool" => PG::TextDecoder::Boolean, } known_coder_types = coders_by_name.keys.map { |n| quote(n) } query = <<-SQL % known_coder_types.join(", ") @@ -807,7 +814,7 @@ module ActiveRecord SQL coders = execute_and_clear(query, "SCHEMA", []) do |result| result - .map { |row| construct_coder(row, coders_by_name[row['typname']]) } + .map { |row| construct_coder(row, coders_by_name[row["typname"]]) } .compact end @@ -818,7 +825,7 @@ module ActiveRecord def construct_coder(row, coder_class) return unless coder_class - coder_class.new(oid: row['oid'].to_i, name: row['typname']) + coder_class.new(oid: row["oid"].to_i, name: row["typname"]) end ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql) @@ -835,8 +842,8 @@ module ActiveRecord ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql) ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql) ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql) - ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql) - ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql) + ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql) + ActiveRecord::Type.register(:legacy_point, OID::LegacyPoint, adapter: :postgresql) ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql) ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql) ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql) diff --git a/activerecord/lib/active_record/connection_adapters/schema_cache.rb b/activerecord/lib/active_record/connection_adapters/schema_cache.rb index eee142378c..8219f132c3 100644 --- a/activerecord/lib/active_record/connection_adapters/schema_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/schema_cache.rb @@ -33,8 +33,7 @@ module ActiveRecord @data_sources[name] = connection.data_source_exists?(name) end alias table_exists? data_source_exists? - deprecate :table_exists? => "use #data_source_exists? instead" - + deprecate table_exists?: "use #data_source_exists? instead" # Add internal cache for table with +table_name+. def add(table_name) @@ -49,7 +48,7 @@ module ActiveRecord @data_sources[name] end alias tables data_sources - deprecate :tables => "use #data_sources instead" + deprecate tables: "use #data_sources instead" # Get the columns for a table def columns(table_name) @@ -85,7 +84,7 @@ module ActiveRecord @data_sources.delete name end alias clear_table_cache! clear_data_source_cache! - deprecate :clear_table_cache! => "use #clear_data_source_cache! instead" + deprecate clear_table_cache!: "use #clear_data_source_cache! instead" def marshal_dump # if we get current version during initialization, it happens stack over flow. diff --git a/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb b/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb index ccb7e154ee..9e12ae0de8 100644 --- a/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb +++ b/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb @@ -24,9 +24,9 @@ module ActiveRecord protected - def attributes_for_hash - [self.class, sql_type, type, limit, precision, scale] - end + def attributes_for_hash + [self.class, sql_type, type, limit, precision, scale] + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb index a946f5ebd0..6fe3e1211e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb @@ -10,7 +10,7 @@ module ActiveRecord # def pp(result) result.rows.map do |row| - row.join('|') + row.join("|") end.join("\n") + "\n" end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb index d5a181d3e2..f01ed67b0f 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb @@ -11,7 +11,7 @@ module ActiveRecord end def quote_column_name(name) - @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}") + @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}").freeze end def quoted_time(value) @@ -20,28 +20,28 @@ module ActiveRecord private - def _quote(value) - if value.is_a?(Type::Binary::Data) - "x'#{value.hex}'" - else - super + def _quote(value) + if value.is_a?(Type::Binary::Data) + "x'#{value.hex}'" + else + super + end end - end - def _type_cast(value) - case value - when BigDecimal - value.to_f - when String - if value.encoding == Encoding::ASCII_8BIT - super(value.encode(Encoding::UTF_8)) + def _type_cast(value) + case value + when BigDecimal + value.to_f + when String + if value.encoding == Encoding::ASCII_8BIT + super(value.encode(Encoding::UTF_8)) + else + super + end else super end - else - super end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index eb2268157b..ebeac425d0 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -1,11 +1,11 @@ -require 'active_record/connection_adapters/abstract_adapter' -require 'active_record/connection_adapters/statement_pool' -require 'active_record/connection_adapters/sqlite3/explain_pretty_printer' -require 'active_record/connection_adapters/sqlite3/quoting' -require 'active_record/connection_adapters/sqlite3/schema_creation' +require "active_record/connection_adapters/abstract_adapter" +require "active_record/connection_adapters/statement_pool" +require "active_record/connection_adapters/sqlite3/explain_pretty_printer" +require "active_record/connection_adapters/sqlite3/quoting" +require "active_record/connection_adapters/sqlite3/schema_creation" -gem 'sqlite3', '~> 1.3.6' -require 'sqlite3' +gem "sqlite3", "~> 1.3.6" +require "sqlite3" module ActiveRecord module ConnectionHandling # :nodoc: @@ -18,7 +18,7 @@ module ActiveRecord # Allow database path relative to Rails.root, but only if the database # path is not the special path that tells sqlite to build a database only # in memory. - if ':memory:' != config[:database] + if ":memory:" != config[:database] config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root) dirname = File.dirname(config[:database]) Dir.mkdir(dirname) unless File.directory?(dirname) @@ -26,7 +26,7 @@ module ActiveRecord db = SQLite3::Database.new( config[:database].to_s, - :results_as_hash => true + results_as_hash: true ) db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout] @@ -49,12 +49,12 @@ module ActiveRecord # # * <tt>:database</tt> - Path to the database file. class SQLite3Adapter < AbstractAdapter - ADAPTER_NAME = 'SQLite'.freeze + ADAPTER_NAME = "SQLite".freeze include SQLite3::Quoting NATIVE_DATABASE_TYPES = { - primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL', + primary_key: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL", string: { name: "varchar" }, text: { name: "text" }, integer: { name: "integer" }, @@ -70,9 +70,9 @@ module ActiveRecord class StatementPool < ConnectionAdapters::StatementPool private - def dealloc(stmt) - stmt[:stmt].close unless stmt[:stmt].closed? - end + def dealloc(stmt) + stmt[:stmt].close unless stmt[:stmt].closed? + end end def schema_creation # :nodoc: @@ -99,7 +99,7 @@ module ActiveRecord end def supports_partial_index? - sqlite_version >= '3.8.0' + sqlite_version >= "3.8.0" end # Returns true, since this connection adapter supports prepared statement @@ -130,7 +130,7 @@ module ActiveRecord end def supports_multi_insert? - sqlite_version >= '3.7.11' + sqlite_version >= "3.7.11" end def active? @@ -159,7 +159,7 @@ module ActiveRecord end # Returns 62. SQLite supports index names up to 64 - # characters. The rest is used by rails internally to perform + # characters. The rest is used by Rails internally to perform # temporary rename operations def allowed_index_name_length index_name_length - 2 @@ -184,13 +184,13 @@ module ActiveRecord def explain(arel, binds = []) sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}" - SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', [])) + SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", [])) end def exec_query(sql, name = nil, binds = [], prepare: false) - type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } + type_casted_binds = type_casted_binds(binds) - log(sql, name, binds) do + log(sql, name, binds, type_casted_binds) do # Don't cache statements if they are not prepared unless prepare stmt = @connection.prepare(sql) @@ -203,22 +203,22 @@ module ActiveRecord ensure stmt.close end - stmt = records else cache = @statements[sql] ||= { - :stmt => @connection.prepare(sql) + stmt: @connection.prepare(sql) } stmt = cache[:stmt] cols = cache[:cols] ||= stmt.columns stmt.reset! stmt.bind_params(type_casted_binds) + records = stmt.to_a end - ActiveRecord::Result.new(cols, stmt.to_a) + ActiveRecord::Result.new(cols, records) end end - def exec_delete(sql, name = 'SQL', binds = []) + def exec_delete(sql, name = "SQL", binds = []) exec_query(sql, name, binds) @connection.changes end @@ -233,15 +233,15 @@ module ActiveRecord end def begin_db_transaction #:nodoc: - log('begin transaction',nil) { @connection.transaction } + log("begin transaction",nil) { @connection.transaction } end def commit_db_transaction #:nodoc: - log('commit transaction',nil) { @connection.commit } + log("commit transaction",nil) { @connection.commit } end def exec_rollback_db_transaction #:nodoc: - log('rollback transaction',nil) { @connection.rollback } + log("rollback transaction",nil) { @connection.rollback } end # SCHEMA STATEMENTS ======================================== @@ -263,7 +263,7 @@ module ActiveRecord end def data_sources - select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", 'SCHEMA') + select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", "SCHEMA") end def table_exists?(table_name) @@ -282,11 +282,11 @@ module ActiveRecord sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'" sql << " AND name = #{quote(table_name)}" - select_values(sql, 'SCHEMA').any? + select_values(sql, "SCHEMA").any? end def views # :nodoc: - select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", 'SCHEMA') + select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", "SCHEMA") end def view_exists?(view_name) # :nodoc: @@ -295,7 +295,7 @@ module ActiveRecord sql = "SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'" sql << " AND name = #{quote(view_name)}" - select_values(sql, 'SCHEMA').any? + select_values(sql, "SCHEMA").any? end # Returns an array of +Column+ objects for the table specified by +table_name+. @@ -311,16 +311,16 @@ module ActiveRecord field["dflt_value"] = $1.gsub('""', '"') end - collation = field['collation'] - sql_type = field['type'] + collation = field["collation"] + sql_type = field["type"] type_metadata = fetch_type_metadata(sql_type) - new_column(field['name'], field['dflt_value'], type_metadata, field['notnull'].to_i == 0, table_name, nil, collation) + new_column(field["name"], field["dflt_value"], type_metadata, field["notnull"].to_i == 0, table_name, nil, collation) end end # Returns an array of indexes for the given table. def indexes(table_name, name = nil) #:nodoc: - exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row| + exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row| sql = <<-SQL SELECT sql FROM sqlite_master @@ -330,22 +330,22 @@ module ActiveRecord FROM sqlite_temp_master WHERE name=#{quote(row['name'])} AND type='index' SQL - index_sql = exec_query(sql).first['sql'] + index_sql = exec_query(sql).first["sql"] match = /\sWHERE\s+(.+)$/i.match(index_sql) where = match[1] if match IndexDefinition.new( table_name, - row['name'], - row['unique'] != 0, + row["name"], + row["unique"] != 0, exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col| - col['name'] + col["name"] }, nil, nil, where) end end def primary_keys(table_name) # :nodoc: - pks = table_structure(table_name).select { |f| f['pk'] > 0 } - pks.sort_by { |f| f['pk'] }.map { |f| f['name'] } + pks = table_structure(table_name).select { |f| f["pk"] > 0 } + pks.sort_by { |f| f["pk"] }.map { |f| f["name"] } end def remove_index(table_name, options = {}) #:nodoc: @@ -418,25 +418,25 @@ module ActiveRecord def rename_column(table_name, column_name, new_column_name) #:nodoc: column = column_for(table_name, column_name) - alter_table(table_name, rename: {column.name => new_column_name.to_s}) + alter_table(table_name, rename: { column.name => new_column_name.to_s }) rename_column_indexes(table_name, column.name, new_column_name) end protected def table_structure(table_name) - structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA') + structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA") raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty? table_structure_with_collation(table_name, structure) end def alter_table(table_name, options = {}) #:nodoc: altered_table_name = "a#{table_name}" - caller = lambda {|definition| yield definition if block_given?} + caller = lambda { |definition| yield definition if block_given? } transaction do move_table(table_name, altered_table_name, - options.merge(:temporary => true)) + options.merge(temporary: true)) move_table(altered_table_name, table_name, &caller) end end @@ -460,9 +460,9 @@ module ActiveRecord next if column_name == from_primary_key @definition.column(column_name, column.type, - :limit => column.limit, :default => column.default, - :precision => column.precision, :scale => column.scale, - :null => column.null, collation: column.collation) + limit: column.limit, default: column.default, + precision: column.precision, scale: column.scale, + null: column.null, collation: column.collation) end yield @definition if block_given? end @@ -482,7 +482,7 @@ module ActiveRecord end to_column_names = columns(to).map(&:name) - columns = index.columns.map {|c| rename[c] || c }.select do |column| + columns = index.columns.map { |c| rename[c] || c }.select do |column| to_column_names.include?(column) end @@ -496,20 +496,20 @@ module ActiveRecord end def copy_table_contents(from, to, columns, rename = {}) #:nodoc: - column_mappings = Hash[columns.map {|name| [name, name]}] + column_mappings = Hash[columns.map { |name| [name, name] }] rename.each { |a| column_mappings[a.last] = a.first } from_columns = columns(from).collect(&:name) - columns = columns.find_all{|col| from_columns.include?(column_mappings[col])} + columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) } from_columns_to_copy = columns.map { |col| column_mappings[col] } - quoted_columns = columns.map { |col| quote_column_name(col) } * ',' - quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ',' + quoted_columns = columns.map { |col| quote_column_name(col) } * "," + quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * "," exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns}) SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}") end def sqlite_version - @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)')) + @sqlite_version ||= SQLite3Adapter::Version.new(select_value("select sqlite_version(*)")) end def translate_exception(exception, message) @@ -530,32 +530,34 @@ module ActiveRecord def table_structure_with_collation(table_name, basic_structure) collation_hash = {} - sql = "SELECT sql FROM - (SELECT * FROM sqlite_master UNION ALL - SELECT * FROM sqlite_temp_master) - WHERE type='table' and name='#{ table_name }' \;" + sql = <<-SQL + SELECT sql FROM + (SELECT * FROM sqlite_master UNION ALL + SELECT * FROM sqlite_temp_master) + WHERE type = 'table' AND name = #{quote(table_name)} + SQL # Result will have following sample string # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, # "password_digest" varchar COLLATE "NOCASE"); - result = exec_query(sql, 'SCHEMA').first + result = exec_query(sql, "SCHEMA").first if result # Splitting with left parentheses and picking up last will return all # columns separated with comma(,). - columns_string = result["sql"].split('(').last + columns_string = result["sql"].split("(").last - columns_string.split(',').each do |column_string| + columns_string.split(",").each do |column_string| # This regex will match the column name and collation type and will save # the value in $1 and $2 respectively. - collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string) + collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string end basic_structure.map! do |column| - column_name = column['name'] + column_name = column["name"] if collation_hash.has_key? column_name - column['collation'] = collation_hash[column_name] + column["collation"] = collation_hash[column_name] end column diff --git a/activerecord/lib/active_record/connection_adapters/statement_pool.rb b/activerecord/lib/active_record/connection_adapters/statement_pool.rb index 9b0ed3e08b..273b1b0b5c 100644 --- a/activerecord/lib/active_record/connection_adapters/statement_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/statement_pool.rb @@ -47,13 +47,13 @@ module ActiveRecord private - def cache - @cache[Process.pid] - end + def cache + @cache[Process.pid] + end - def dealloc(stmt) - raise NotImplementedError - end + def dealloc(stmt) + raise NotImplementedError + end end end end diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb index 99fdef67d0..2ede92feff 100644 --- a/activerecord/lib/active_record/connection_handling.rb +++ b/activerecord/lib/active_record/connection_handling.rb @@ -73,7 +73,7 @@ module ActiveRecord private def config @raw_config.dup.tap do |cfg| - if url = ENV['DATABASE_URL'] + if url = ENV["DATABASE_URL"] cfg[@env] ||= {} cfg[@env]["url"] ||= url end @@ -98,14 +98,6 @@ module ActiveRecord @connection_specification_name end - def connection_id - ActiveRecord::RuntimeRegistry.connection_id ||= Thread.current.object_id - end - - def connection_id=(connection_id) - ActiveRecord::RuntimeRegistry.connection_id = connection_id - end - # Returns the configuration of the associated connection as a hash: # # ActiveRecord::Base.connection_config @@ -117,7 +109,7 @@ module ActiveRecord end def connection_pool - connection_handler.retrieve_connection_pool(connection_specification_name) or raise ConnectionNotEstablished + connection_handler.retrieve_connection_pool(connection_specification_name) || raise(ConnectionNotEstablished) end def retrieve_connection @@ -146,6 +138,6 @@ module ActiveRecord end delegate :clear_active_connections!, :clear_reloadable_connections!, - :clear_all_connections!, :to => :connection_handler + :clear_all_connections!, to: :connection_handler end end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index de337b24d6..622df0cfc1 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -1,7 +1,7 @@ -require 'thread' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/string/filters' +require "thread" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/string/filters" module ActiveRecord module Core @@ -72,11 +72,31 @@ module ActiveRecord ## # :singleton-method: - # Specifies if an error should be raised on query limit or order being + # Specifies if an error should be raised if the query has an order being # ignored when doing batch queries. Useful in applications where the - # limit or scope being ignored is error-worthy, rather than a warning. - mattr_accessor :error_on_ignored_order_or_limit, instance_writer: false - self.error_on_ignored_order_or_limit = false + # scope being ignored is error-worthy, rather than a warning. + mattr_accessor :error_on_ignored_order, instance_writer: false + self.error_on_ignored_order = false + + def self.error_on_ignored_order_or_limit + ActiveSupport::Deprecation.warn(<<-MSG.squish) + The flag error_on_ignored_order_or_limit is deprecated. Limits are + now supported. Please use error_on_ignored_order instead. + MSG + error_on_ignored_order + end + + def error_on_ignored_order_or_limit + self.class.error_on_ignored_order_or_limit + end + + def self.error_on_ignored_order_or_limit=(value) + ActiveSupport::Deprecation.warn(<<-MSG.squish) + The flag error_on_ignored_order_or_limit is deprecated. Limits are + now supported. Please use error_on_ignored_order= instead. + MSG + self.error_on_ignored_order = value + end ## # :singleton-method: @@ -209,7 +229,7 @@ module ActiveRecord end def find_by!(*args) # :nodoc: - find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name) + find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name)) end def initialize_generated_modules # :nodoc: @@ -233,7 +253,7 @@ module ActiveRecord elsif !connected? "#{super} (call '#{super}.connection' to establish a connection)" elsif table_exists? - attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', ' + attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", " "#{super}(#{attr_list})" else "#{super}(Table doesn't exist)" @@ -248,7 +268,7 @@ module ActiveRecord # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name. # # class Post < ActiveRecord::Base - # scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) } + # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) } # end def arel_table # :nodoc: @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster) @@ -279,26 +299,26 @@ module ActiveRecord private - def cached_find_by_statement(key, &block) # :nodoc: - cache = @find_by_statement_cache[connection.prepared_statements] - cache[key] || cache.synchronize { - cache[key] ||= StatementCache.create(connection, &block) - } - end + def cached_find_by_statement(key, &block) # :nodoc: + cache = @find_by_statement_cache[connection.prepared_statements] + cache[key] || cache.synchronize { + cache[key] ||= StatementCache.create(connection, &block) + } + end - def relation # :nodoc: - relation = Relation.create(self, arel_table, predicate_builder) + def relation # :nodoc: + relation = Relation.create(self, arel_table, predicate_builder) - if finder_needs_type_condition? && !ignore_default_scope? - relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name) - else - relation + if finder_needs_type_condition? && !ignore_default_scope? + relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name) + else + relation + end end - end - def table_metadata # :nodoc: - TableMetadata.new(self, arel_table) - end + def table_metadata # :nodoc: + TableMetadata.new(self, arel_table) + end end # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with @@ -342,10 +362,12 @@ module ActiveRecord init_internals - @new_record = coder['new_record'] + @new_record = coder["new_record"] self.class.define_attribute_methods + yield self if block_given? + _run_find_callbacks _run_initialize_callbacks @@ -405,8 +427,8 @@ module ActiveRecord # coder # => {"attributes" => {"id" => nil, ... }} def encode_with(coder) self.class.yaml_encoder.encode(@attributes, coder) - coder['new_record'] = new_record? - coder['active_record_yaml_version'] = 2 + coder["new_record"] = new_record? + coder["active_record_yaml_version"] = 2 end # Returns true if +comparison_object+ is the same exact object, or +comparison_object+ @@ -430,7 +452,7 @@ module ActiveRecord # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ] def hash if id - [self.class, id].hash + self.class.hash ^ self.id.hash else super end @@ -478,14 +500,15 @@ module ActiveRecord # We check defined?(@attributes) not to issue warnings if the object is # allocated but not initialized. inspection = if defined?(@attributes) && @attributes - self.class.column_names.collect { |name| - if has_attribute?(name) - "#{name}: #{attribute_for_inspect(name)}" - end - }.compact.join(", ") - else - "not initialized" - end + self.class.attribute_names.collect do |name| + if has_attribute?(name) + "#{name}: #{attribute_for_inspect(name)}" + end + end.compact.join(", ") + else + "not initialized" + end + "#<#{self.class} #{inspection}>" end @@ -496,19 +519,19 @@ module ActiveRecord pp.object_address_group(self) do if defined?(@attributes) && @attributes column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? } - pp.seplist(column_names, proc { pp.text ',' }) do |column_name| + pp.seplist(column_names, proc { pp.text "," }) do |column_name| column_value = read_attribute(column_name) - pp.breakable ' ' + pp.breakable " " pp.group(1) do pp.text column_name - pp.text ':' + pp.text ":" pp.breakable pp.pp column_value end end else - pp.breakable ' ' - pp.text 'not initialized' + pp.breakable " " + pp.text "not initialized" end end end @@ -520,40 +543,40 @@ module ActiveRecord private - # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements - # of the array, and then rescues from the possible NoMethodError. If those elements are - # ActiveRecord::Base's, then this triggers the various method_missing's that we have, - # which significantly impacts upon performance. - # - # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here. - # - # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html - def to_ary # :nodoc: - nil - end + # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of + # the array, and then rescues from the possible +NoMethodError+. If those elements are + # +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have, + # which significantly impacts upon performance. + # + # So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here. + # + # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html + def to_ary + nil + end - def init_internals - @readonly = false - @destroyed = false - @marked_for_destruction = false - @destroyed_by_association = nil - @new_record = true - @txn = nil - @_start_transaction_state = {} - @transaction_state = nil - end + def init_internals + @readonly = false + @destroyed = false + @marked_for_destruction = false + @destroyed_by_association = nil + @new_record = true + @txn = nil + @_start_transaction_state = {} + @transaction_state = nil + end - def initialize_internals_callback - end + def initialize_internals_callback + end - def thaw - if frozen? - @attributes = @attributes.dup + def thaw + if frozen? + @attributes = @attributes.dup + end end - end - def custom_inspect_method_defined? - self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner - end + def custom_inspect_method_defined? + self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner + end end end diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb index 1b6817554d..e2da512813 100644 --- a/activerecord/lib/active_record/counter_cache.rb +++ b/activerecord/lib/active_record/counter_cache.rb @@ -26,7 +26,7 @@ module ActiveRecord has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym } counter_association = has_many_association.plural_name if has_many_association end - raise ArgumentError, "'#{self.name}' has no association called '#{counter_association}'" unless has_many_association + raise ArgumentError, "'#{name}' has no association called '#{counter_association}'" unless has_many_association if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection has_many_association = has_many_association.through_reflection @@ -75,12 +75,12 @@ module ActiveRecord # # WHERE id IN (10, 15) def update_counters(id, counters) updates = counters.map do |counter_name, value| - operator = value < 0 ? '-' : '+' + operator = value < 0 ? "-" : "+" quoted_column = connection.quote_column_name(counter_name) "#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}" end - unscoped.where(primary_key => id).update_all updates.join(', ') + unscoped.where(primary_key => id).update_all updates.join(", ") end # Increment a numeric field by one, via a direct SQL update. @@ -159,6 +159,5 @@ module ActiveRecord yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column end end - end end diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb index b6dd6814db..9a7a8d25bb 100644 --- a/activerecord/lib/active_record/dynamic_matchers.rb +++ b/activerecord/lib/active_record/dynamic_matchers.rb @@ -1,6 +1,8 @@ +require "active_support/core_ext/regexp" + module ActiveRecord module DynamicMatchers #:nodoc: - def respond_to?(name, include_private = false) + def respond_to_missing?(name, include_private = false) if self == Base super else @@ -11,111 +13,111 @@ module ActiveRecord private - def method_missing(name, *arguments, &block) - match = Method.match(self, name) + def method_missing(name, *arguments, &block) + match = Method.match(self, name) - if match && match.valid? - match.define - send(name, *arguments, &block) - else - super + if match && match.valid? + match.define + send(name, *arguments, &block) + else + super + end end - end - class Method - @matchers = [] + class Method + @matchers = [] - class << self - attr_reader :matchers + class << self + attr_reader :matchers - def match(model, name) - klass = matchers.find { |k| name =~ k.pattern } - klass.new(model, name) if klass - end + def match(model, name) + klass = matchers.find { |k| k.pattern.match?(name) } + klass.new(model, name) if klass + end - def pattern - @pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/ - end + def pattern + @pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/ + end - def prefix - raise NotImplementedError - end + def prefix + raise NotImplementedError + end - def suffix - '' + def suffix + "" + end end - end - attr_reader :model, :name, :attribute_names + attr_reader :model, :name, :attribute_names - def initialize(model, name) - @model = model - @name = name.to_s - @attribute_names = @name.match(self.class.pattern)[1].split('_and_') - @attribute_names.map! { |n| @model.attribute_aliases[n] || n } - end + def initialize(model, name) + @model = model + @name = name.to_s + @attribute_names = @name.match(self.class.pattern)[1].split("_and_") + @attribute_names.map! { |n| @model.attribute_aliases[n] || n } + end - def valid? - attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) } - end + def valid? + attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) } + end - def define - model.class_eval <<-CODE, __FILE__, __LINE__ + 1 - def self.#{name}(#{signature}) - #{body} - end - CODE - end + def define + model.class_eval <<-CODE, __FILE__, __LINE__ + 1 + def self.#{name}(#{signature}) + #{body} + end + CODE + end - private + private - def body - "#{finder}(#{attributes_hash})" - end + def body + "#{finder}(#{attributes_hash})" + end - # The parameters in the signature may have reserved Ruby words, in order - # to prevent errors, we start each param name with `_`. - def signature - attribute_names.map { |name| "_#{name}" }.join(', ') - end + # The parameters in the signature may have reserved Ruby words, in order + # to prevent errors, we start each param name with `_`. + def signature + attribute_names.map { |name| "_#{name}" }.join(", ") + end - # Given that the parameters starts with `_`, the finder needs to use the - # same parameter name. - def attributes_hash - "{" + attribute_names.map { |name| ":#{name} => _#{name}" }.join(',') + "}" - end + # Given that the parameters starts with `_`, the finder needs to use the + # same parameter name. + def attributes_hash + "{" + attribute_names.map { |name| ":#{name} => _#{name}" }.join(",") + "}" + end - def finder - raise NotImplementedError + def finder + raise NotImplementedError + end end - end - class FindBy < Method - Method.matchers << self + class FindBy < Method + Method.matchers << self - def self.prefix - "find_by" - end + def self.prefix + "find_by" + end - def finder - "find_by" + def finder + "find_by" + end end - end - class FindByBang < Method - Method.matchers << self + class FindByBang < Method + Method.matchers << self - def self.prefix - "find_by" - end + def self.prefix + "find_by" + end - def self.suffix - "!" - end + def self.suffix + "!" + end - def finder - "find_by!" + def finder + "find_by!" + end end - end end end diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index 7be332fb97..0a94ab58dd 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/deep_dup' +require "active_support/core_ext/object/deep_dup" module ActiveRecord # Declare an enum attribute where the values map to integers in the database, @@ -105,6 +105,8 @@ module ActiveRecord end class EnumType < Type::Value # :nodoc: + delegate :type, to: :subtype + def initialize(name, mapping, subtype) @name = name @mapping = mapping @@ -140,7 +142,7 @@ module ActiveRecord protected - attr_reader :name, :mapping, :subtype + attr_reader :name, :mapping, :subtype end def enum(definitions) @@ -159,8 +161,9 @@ module ActiveRecord detect_enum_conflict!(name, name) detect_enum_conflict!(name, "#{name}=") - decorate_attribute_type(name, :enum) do |subtype| - EnumType.new(name, enum_values, subtype) + attr = attribute_alias?(name) ? attribute_alias(name) : name + decorate_attribute_type(attr, :enum) do |subtype| + EnumType.new(attr, enum_values, subtype) end _enum_methods_module.module_eval do @@ -182,15 +185,15 @@ module ActiveRecord # def active?() status == 0 end klass.send(:detect_enum_conflict!, name, "#{value_method_name}?") - define_method("#{value_method_name}?") { self[name] == value.to_s } + define_method("#{value_method_name}?") { self[attr] == value.to_s } # def active!() update! status: :active end klass.send(:detect_enum_conflict!, name, "#{value_method_name}!") - define_method("#{value_method_name}!") { update! name => value } + define_method("#{value_method_name}!") { update!(attr => value) } # scope :active, -> { where status: 0 } klass.send(:detect_enum_conflict!, name, value_method_name, true) - klass.scope value_method_name, -> { where(name => value) } + klass.scope value_method_name, -> { where(attr => value) } end end defined_enums[name.to_s] = enum_values @@ -213,18 +216,18 @@ module ActiveRecord def detect_enum_conflict!(enum_name, method_name, klass_method = false) if klass_method && dangerous_class_method?(method_name) - raise_conflict_error(enum_name, method_name, type: 'class') + raise_conflict_error(enum_name, method_name, type: "class") elsif !klass_method && dangerous_attribute_method?(method_name) raise_conflict_error(enum_name, method_name) elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module) - raise_conflict_error(enum_name, method_name, source: 'another enum') + raise_conflict_error(enum_name, method_name, source: "another enum") end end - def raise_conflict_error(enum_name, method_name, type: 'instance', source: 'Active Record') + def raise_conflict_error(enum_name, method_name, type: "instance", source: "Active Record") raise ArgumentError, ENUM_CONFLICT_MESSAGE % { enum: enum_name, - klass: self.name, + klass: name, type: type, method: method_name, source: source diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 38e4fbec8b..8fbe43e3ec 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -1,5 +1,4 @@ module ActiveRecord - # = Active Record Errors # # Generic Active Record exception class. @@ -96,7 +95,6 @@ module ActiveRecord # # Wraps the underlying database error as +cause+. class StatementInvalid < ActiveRecordError - def initialize(message = nil, original_exception = nil) if original_exception ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ @@ -166,7 +164,6 @@ module ActiveRecord super("Stale object error.") end end - end # Raised when association is being configured improperly or user tries to use @@ -285,14 +282,24 @@ module ActiveRecord class TransactionIsolationError < ActiveRecordError end - # TransactionSerializationError will be raised when a transaction is rolled + # TransactionRollbackError will be raised when a transaction is rolled # back by the database due to a serialization failure or a deadlock. # # See the following: # # * http://www.postgresql.org/docs/current/static/transaction-iso.html # * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock - class TransactionSerializationError < ActiveRecordError + class TransactionRollbackError < StatementInvalid + end + + # SerializationFailure will be raised when a transaction is rolled + # back by the database due to a serialization failure. + class SerializationFailure < TransactionRollbackError + end + + # Deadlocked will be raised when a transaction is rolled + # back by the database when a deadlock is encountered. + class Deadlocked < TransactionRollbackError end # IrreversibleOrderError is raised when a relation's order is too complex for diff --git a/activerecord/lib/active_record/explain.rb b/activerecord/lib/active_record/explain.rb index 727a9befc1..980b8e1baa 100644 --- a/activerecord/lib/active_record/explain.rb +++ b/activerecord/lib/active_record/explain.rb @@ -1,5 +1,5 @@ -require 'active_support/lazy_load_hooks' -require 'active_record/explain_registry' +require "active_support/lazy_load_hooks" +require "active_record/explain_registry" module ActiveRecord module Explain @@ -16,15 +16,14 @@ module ActiveRecord # Makes the adapter execute EXPLAIN for the tuples of queries and bindings. # Returns a formatted string ready to be logged. def exec_explain(queries) # :nodoc: - str = queries.map do |sql, bind| - [].tap do |msg| - msg << "EXPLAIN for: #{sql}" - unless bind.empty? - bind_msg = bind.map {|col, val| [col.name, val]}.inspect - msg.last << " #{bind_msg}" - end - msg << connection.explain(sql, bind) - end.join("\n") + str = queries.map do |sql, binds| + msg = "EXPLAIN for: #{sql}" + unless binds.empty? + msg << " " + msg << binds.map { |attr| render_bind(attr) }.inspect + end + msg << "\n" + msg << connection.explain(sql, binds) end.join("\n") # Overriding inspect to be more human readable, especially in the console. @@ -34,5 +33,17 @@ module ActiveRecord str end + + private + + def render_bind(attr) + value = if attr.type.binary? && attr.value + "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>" + else + connection.type_cast(attr.value_for_database) + end + + [attr.name, value] + end end end diff --git a/activerecord/lib/active_record/explain_registry.rb b/activerecord/lib/active_record/explain_registry.rb index b652932f9c..ef1ce3dc85 100644 --- a/activerecord/lib/active_record/explain_registry.rb +++ b/activerecord/lib/active_record/explain_registry.rb @@ -1,4 +1,4 @@ -require 'active_support/per_thread_registry' +require "active_support/per_thread_registry" module ActiveRecord # This is a thread locals registry for EXPLAIN. For example diff --git a/activerecord/lib/active_record/explain_subscriber.rb b/activerecord/lib/active_record/explain_subscriber.rb index 90bcf5a205..abd8cfc8f2 100644 --- a/activerecord/lib/active_record/explain_subscriber.rb +++ b/activerecord/lib/active_record/explain_subscriber.rb @@ -1,5 +1,5 @@ -require 'active_support/notifications' -require 'active_record/explain_registry' +require "active_support/notifications" +require "active_record/explain_registry" module ActiveRecord class ExplainSubscriber # :nodoc: @@ -18,10 +18,13 @@ module ActiveRecord # # On the other hand, we want to monitor the performance of our real database # queries, not the performance of the access to the query cache. - IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE) + IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN) EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i def ignore_payload?(payload) - payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS + payload[:exception] || + payload[:cached] || + IGNORED_PAYLOADS.include?(payload[:name]) || + payload[:sql] !~ EXPLAINED_SQLS end ActiveSupport::Notifications.subscribe("sql.active_record", new) diff --git a/activerecord/lib/active_record/fixture_set/file.rb b/activerecord/lib/active_record/fixture_set/file.rb index e4a44244e2..5ba354d758 100644 --- a/activerecord/lib/active_record/fixture_set/file.rb +++ b/activerecord/lib/active_record/fixture_set/file.rb @@ -1,5 +1,5 @@ -require 'erb' -require 'yaml' +require "erb" +require "yaml" module ActiveRecord class FixtureSet @@ -24,21 +24,21 @@ module ActiveRecord end def model_class - config_row['model_class'] + config_row["model_class"] end private def rows - @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == '_fixture' } + @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" } end def config_row @config_row ||= begin - row = raw_rows.find { |fixture_name, _| fixture_name == '_fixture' } + row = raw_rows.find { |fixture_name, _| fixture_name == "_fixture" } if row row.last else - {'model_class': nil} + { 'model_class': nil } end end end @@ -66,7 +66,7 @@ module ActiveRecord # Validate our unmarshalled data. def validate(data) unless Hash === data || YAML::Omap === data - raise Fixture::FormatError, 'fixture is not a hash' + raise Fixture::FormatError, "fixture is not a hash" end raise Fixture::FormatError unless data.all? { |name, row| Hash === row } diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 51bf12d0bf..8b47fbdbe4 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -1,11 +1,11 @@ -require 'erb' -require 'yaml' -require 'zlib' -require 'set' -require 'active_support/dependencies' -require 'active_support/core_ext/digest/uuid' -require 'active_record/fixture_set/file' -require 'active_record/errors' +require "erb" +require "yaml" +require "zlib" +require "set" +require "active_support/dependencies" +require "active_support/core_ext/digest/uuid" +require "active_record/fixture_set/file" +require "active_record/errors" module ActiveRecord class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc: @@ -426,9 +426,9 @@ module ActiveRecord end def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc: - "#{ config.table_name_prefix }"\ - "#{ fixture_set_name.tr('/', '_') }"\ - "#{ config.table_name_suffix }".to_sym + "#{ config.table_name_prefix }"\ + "#{ fixture_set_name.tr('/', '_') }"\ + "#{ config.table_name_suffix }".to_sym end def self.reset_cache @@ -494,18 +494,18 @@ module ActiveRecord private - def insert_class(class_names, name, klass) - # We only want to deal with AR objects. - if klass && klass < ActiveRecord::Base - class_names[name] = klass - else - class_names[name] = nil + def insert_class(class_names, name, klass) + # We only want to deal with AR objects. + if klass && klass < ActiveRecord::Base + class_names[name] = klass + else + class_names[name] = nil + end end - end - def default_fixture_model(fs_name, config) - ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config) - end + def default_fixture_model(fs_name, config) + ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config) + end end def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base) @@ -535,7 +535,7 @@ module ActiveRecord update_all_loaded_fixtures fixtures_map - connection.transaction(:requires_new => true) do + connection.transaction(requires_new: true) do deleted_tables = Set.new fixture_sets.each do |fs| conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection @@ -543,7 +543,7 @@ module ActiveRecord table_rows.each_key do |table| unless deleted_tables.include? table - conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete' + conn.delete "DELETE FROM #{conn.quote_table_name(table)}", "Fixture Delete" end deleted_tables << table end @@ -626,7 +626,7 @@ module ActiveRecord now = config.default_timezone == :utc ? Time.now.utc : Time.now # allow a standard key to be used for doing defaults in YAML - fixtures.delete('DEFAULTS') + fixtures.delete("DEFAULTS") # track any join tables we need to insert later rows = Hash.new { |h,table| h[table] = [] } @@ -799,7 +799,6 @@ module ActiveRecord def yaml_file_path(path) "#{path}.yml" end - end class Fixture #:nodoc: @@ -859,7 +858,7 @@ module ActiveRecord end included do - class_attribute :fixture_path, :instance_writer => false + class_attribute :fixture_path, instance_writer: false class_attribute :fixture_table_names class_attribute :fixture_class_names class_attribute :use_transactional_tests @@ -868,7 +867,7 @@ module ActiveRecord class_attribute :pre_loaded_fixtures class_attribute :config - singleton_class.deprecate 'use_transactional_fixtures=' => 'use use_transactional_tests= instead' + singleton_class.deprecate "use_transactional_fixtures=" => "use use_transactional_tests= instead" self.fixture_table_names = [] self.use_instantiated_fixtures = false @@ -903,7 +902,7 @@ module ActiveRecord def fixtures(*fixture_set_names) if fixture_set_names.first == :all - fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"] + fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] } else fixture_set_names = fixture_set_names.flatten.map(&:to_s) @@ -918,7 +917,7 @@ module ActiveRecord methods = Module.new do fixture_set_names.each do |fs_name| fs_name = fs_name.to_s - accessor_name = fs_name.tr('/', '_').to_sym + accessor_name = fs_name.tr("/", "_").to_sym define_method(accessor_name) do |*fixture_names| force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload @@ -962,12 +961,13 @@ module ActiveRecord def setup_fixtures(config = ActiveRecord::Base) if pre_loaded_fixtures && !use_transactional_tests - raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_tests' + raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests" end @fixture_cache = {} @fixture_connections = [] @@already_loaded_fixtures ||= {} + @connection_subscriber = nil # Load fixtures once and begin transaction. if run_in_transaction? @@ -977,10 +977,31 @@ module ActiveRecord @loaded_fixtures = load_fixtures(config) @@already_loaded_fixtures[self.class] = @loaded_fixtures end + + # Begin transactions for connections already established @fixture_connections = enlist_fixture_connections @fixture_connections.each do |connection| connection.begin_transaction joinable: false end + + # When connections are established in the future, begin a transaction too + @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload| + spec_name = payload[:spec_name] if payload.key?(:spec_name) + + if spec_name + begin + connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name) + rescue ConnectionNotEstablished + connection = nil + end + + if connection && !@fixture_connections.include?(connection) + connection.begin_transaction joinable: false + @fixture_connections << connection + end + end + end + # Load fixtures for every test. else ActiveRecord::FixtureSet.reset_cache @@ -995,6 +1016,7 @@ module ActiveRecord def teardown_fixtures # Rollback changes if a transaction is active. if run_in_transaction? + ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber @fixture_connections.each do |connection| connection.rollback_transaction if connection.transaction_open? end @@ -1018,10 +1040,10 @@ module ActiveRecord def instantiate_fixtures if pre_loaded_fixtures - raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty? + raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty? ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?) else - raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil? + raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil? @loaded_fixtures.each_value do |fixture_set| ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?) end diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index 899683ee4f..a1d4f47372 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/indifferent_access' +require "active_support/core_ext/hash/indifferent_access" module ActiveRecord # == Single table inheritance @@ -19,7 +19,7 @@ module ActiveRecord # Be aware that because the type column is an attribute on the record every new # subclass will instantly be marked as dirty and the type column will be included # in the list of changed attributes on the record. This is different from non - # STI classes: + # Single Table Inheritance(STI) classes: # # Company.new.changed? # => false # Firm.new.changed? # => true @@ -37,6 +37,7 @@ module ActiveRecord included do # Determines whether to store the full constant name including namespace when using STI. + # This is true, by default. class_attribute :store_full_sti_class, instance_writer: false self.store_full_sti_class = true end @@ -131,85 +132,85 @@ module ActiveRecord protected - # Returns the class type of the record using the current module as a prefix. So descendants of - # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass. - def compute_type(type_name) - if type_name.match(/^::/) - # If the type is prefixed with a scope operator then we assume that - # the type_name is an absolute reference. - ActiveSupport::Dependencies.constantize(type_name) - else - # Build a list of candidates to search for - candidates = [] - name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" } - candidates << type_name - - candidates.each do |candidate| - constant = ActiveSupport::Dependencies.safe_constantize(candidate) - return constant if candidate == constant.to_s - end + # Returns the class type of the record using the current module as a prefix. So descendants of + # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass. + def compute_type(type_name) + if type_name.match(/^::/) + # If the type is prefixed with a scope operator then we assume that + # the type_name is an absolute reference. + ActiveSupport::Dependencies.constantize(type_name) + else + # Build a list of candidates to search for + candidates = [] + name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" } + candidates << type_name - raise NameError.new("uninitialized constant #{candidates.first}", candidates.first) + candidates.each do |candidate| + constant = ActiveSupport::Dependencies.safe_constantize(candidate) + return constant if candidate == constant.to_s + end + + raise NameError.new("uninitialized constant #{candidates.first}", candidates.first) + end end - end private - # Called by +instantiate+ to decide which class to use for a new - # record instance. For single-table inheritance, we check the record - # for a +type+ column and return the corresponding class. - def discriminate_class_for_record(record) - if using_single_table_inheritance?(record) - find_sti_class(record[inheritance_column]) - else - super + # Called by +instantiate+ to decide which class to use for a new + # record instance. For single-table inheritance, we check the record + # for a +type+ column and return the corresponding class. + def discriminate_class_for_record(record) + if using_single_table_inheritance?(record) + find_sti_class(record[inheritance_column]) + else + super + end end - end - def using_single_table_inheritance?(record) - record[inheritance_column].present? && has_attribute?(inheritance_column) - end + def using_single_table_inheritance?(record) + record[inheritance_column].present? && has_attribute?(inheritance_column) + end - def find_sti_class(type_name) - type_name = base_class.type_for_attribute(inheritance_column).cast(type_name) - subclass = begin - if store_full_sti_class - ActiveSupport::Dependencies.constantize(type_name) - else - compute_type(type_name) + def find_sti_class(type_name) + type_name = base_class.type_for_attribute(inheritance_column).cast(type_name) + subclass = begin + if store_full_sti_class + ActiveSupport::Dependencies.constantize(type_name) + else + compute_type(type_name) + end + rescue NameError + raise SubclassNotFound, + "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \ + "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \ + "Please rename this column if you didn't intend it to be used for storing the inheritance class " \ + "or overwrite #{name}.inheritance_column to use another column for that information." end - rescue NameError - raise SubclassNotFound, - "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \ - "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \ - "Please rename this column if you didn't intend it to be used for storing the inheritance class " \ - "or overwrite #{name}.inheritance_column to use another column for that information." - end - unless subclass == self || descendants.include?(subclass) - raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}" + unless subclass == self || descendants.include?(subclass) + raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}" + end + subclass end - subclass - end - def type_condition(table = arel_table) - sti_column = arel_attribute(inheritance_column, table) - sti_names = ([self] + descendants).map(&:sti_name) + def type_condition(table = arel_table) + sti_column = arel_attribute(inheritance_column, table) + sti_names = ([self] + descendants).map(&:sti_name) - sti_column.in(sti_names) - end + sti_column.in(sti_names) + end - # Detect the subclass from the inheritance column of attrs. If the inheritance column value - # is not self or a valid subclass, raises ActiveRecord::SubclassNotFound - def subclass_from_attributes(attrs) - attrs = attrs.to_h if attrs.respond_to?(:permitted?) - if attrs.is_a?(Hash) - subclass_name = attrs.with_indifferent_access[inheritance_column] + # Detect the subclass from the inheritance column of attrs. If the inheritance column value + # is not self or a valid subclass, raises ActiveRecord::SubclassNotFound + def subclass_from_attributes(attrs) + attrs = attrs.to_h if attrs.respond_to?(:permitted?) + if attrs.is_a?(Hash) + subclass_name = attrs.with_indifferent_access[inheritance_column] - if subclass_name.present? - find_sti_class(subclass_name) + if subclass_name.present? + find_sti_class(subclass_name) + end end end - end end def initialize_dup(other) @@ -219,21 +220,21 @@ module ActiveRecord private - def initialize_internals_callback - super - ensure_proper_type - end + def initialize_internals_callback + super + ensure_proper_type + end - # Sets the attribute used for single table inheritance to this class name if this is not the - # ActiveRecord::Base descendant. - # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to - # do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself. - # No such attribute would be set for objects of the Message class in that example. - def ensure_proper_type - klass = self.class - if klass.finder_needs_type_condition? - write_attribute(klass.inheritance_column, klass.sti_name) + # Sets the attribute used for single table inheritance to this class name if this is not the + # ActiveRecord::Base descendant. + # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to + # do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself. + # No such attribute would be set for objects of the Message class in that example. + def ensure_proper_type + klass = self.class + if klass.finder_needs_type_condition? + write_attribute(klass.inheritance_column, klass.sti_name) + end end - end end end diff --git a/activerecord/lib/active_record/integration.rb b/activerecord/lib/active_record/integration.rb index 466c8509a4..3c54c6048d 100644 --- a/activerecord/lib/active_record/integration.rb +++ b/activerecord/lib/active_record/integration.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/filters' +require "active_support/core_ext/string/filters" module ActiveRecord module Integration @@ -11,7 +11,7 @@ module ActiveRecord # Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>. # # This is +:usec+, by default. - class_attribute :cache_timestamp_format, :instance_writer => false + class_attribute :cache_timestamp_format, instance_writer: false self.cache_timestamp_format = :usec end @@ -53,18 +53,21 @@ module ActiveRecord # # Person.find(5).cache_key(:updated_at, :last_reviewed_at) def cache_key(*timestamp_names) - case - when new_record? + if new_record? "#{model_name.cache_key}/new" - when timestamp_names.any? - timestamp = max_updated_column_timestamp(timestamp_names) - timestamp = timestamp.utc.to_s(cache_timestamp_format) - "#{model_name.cache_key}/#{id}-#{timestamp}" - when timestamp = max_updated_column_timestamp - timestamp = timestamp.utc.to_s(cache_timestamp_format) - "#{model_name.cache_key}/#{id}-#{timestamp}" else - "#{model_name.cache_key}/#{id}" + timestamp = if timestamp_names.any? + max_updated_column_timestamp(timestamp_names) + else + max_updated_column_timestamp + end + + if timestamp + timestamp = timestamp.utc.to_s(cache_timestamp_format) + "#{model_name.cache_key}/#{id}-#{timestamp}" + else + "#{model_name.cache_key}/#{id}" + end end end @@ -86,7 +89,7 @@ module ActiveRecord # # user = User.find_by(name: 'David Heinemeier Hansson') # user.id # => 125 - # user_path(user) # => "/users/125-david" + # user_path(user) # => "/users/125-david-heinemeier" # # Because the generated param begins with the record's +id+, it is # suitable for passing to +find+. In a controller, for example: @@ -100,7 +103,7 @@ module ActiveRecord define_method :to_param do if (default = super()) && (result = send(method_name).to_s).present? && - (param = result.squish.truncate(20, separator: /\s/, omission: nil).parameterize).present? + (param = result.squish.parameterize.truncate(20, separator: /-/, omission: "")).present? "#{default}-#{param}" else default diff --git a/activerecord/lib/active_record/internal_metadata.rb b/activerecord/lib/active_record/internal_metadata.rb index 17a5dc1d1b..20d61dba67 100644 --- a/activerecord/lib/active_record/internal_metadata.rb +++ b/activerecord/lib/active_record/internal_metadata.rb @@ -1,5 +1,5 @@ -require 'active_record/scoping/default' -require 'active_record/scoping/named' +require "active_record/scoping/default" +require "active_record/scoping/named" module ActiveRecord # This class is used to create a table that keeps track of values and keys such @@ -14,10 +14,6 @@ module ActiveRecord "#{table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{table_name_suffix}" end - def original_table_name - "#{table_name_prefix}active_record_internal_metadatas#{table_name_suffix}" - end - def []=(key, value) find_or_initialize_by(key: key).update_attributes!(value: value) end @@ -30,17 +26,8 @@ module ActiveRecord ActiveSupport::Deprecation.silence { connection.table_exists?(table_name) } end - def original_table_exists? - # This method will be removed in Rails 5.1 - # Since it is only necessary when `active_record_internal_metadatas` could exist - ActiveSupport::Deprecation.silence { connection.table_exists?(original_table_name) } - end - # Creates an internal metadata table with columns +key+ and +value+ def create_table - if original_table_exists? - connection.rename_table(original_table_name, table_name) - end unless table_exists? key_options = connection.internal_string_options_for_primary_key diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 67b8efac66..82882469e3 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -47,6 +47,8 @@ module ActiveRecord # self.locking_column = :lock_person # end # + # Please note that the optimistic locking will be ignored if you update the + # locking column's value. module Optimistic extend ActiveSupport::Concern @@ -60,10 +62,11 @@ module ActiveRecord end private + def increment_lock lock_col = self.class.locking_column previous_lock_value = send(lock_col).to_i - send(lock_col + '=', previous_lock_value + 1) + send(lock_col + "=", previous_lock_value + 1) end def _create_record(attribute_names = self.attribute_names, *) # :nodoc: @@ -77,21 +80,24 @@ module ActiveRecord def _update_record(attribute_names = self.attribute_names) #:nodoc: return super unless locking_enabled? - return 0 if attribute_names.empty? lock_col = self.class.locking_column - previous_lock_value = send(lock_col).to_i - increment_lock - attribute_names += [lock_col] - attribute_names.uniq! + return super if attribute_names.include?(lock_col) + return 0 if attribute_names.empty? begin + previous_lock_value = read_attribute_before_type_cast(lock_col) + + increment_lock + + attribute_names.push(lock_col) + relation = self.class.unscoped affected_rows = relation.where( self.class.primary_key => id, - lock_col => previous_lock_value, + lock_col => previous_lock_value ).update_all( attributes_for_update(attribute_names).map do |name| [name, _read_attribute(name)] @@ -104,9 +110,9 @@ module ActiveRecord affected_rows - # If something went wrong, revert the version. + # If something went wrong, revert the locking_column value. rescue Exception - send(lock_col + '=', previous_lock_value) + send(lock_col + "=", previous_lock_value.to_i) raise end end @@ -132,59 +138,58 @@ module ActiveRecord relation end - module ClassMethods - DEFAULT_LOCKING_COLUMN = 'lock_version' + module ClassMethods + DEFAULT_LOCKING_COLUMN = "lock_version" - # Returns true if the +lock_optimistically+ flag is set to true - # (which it is, by default) and the table includes the - # +locking_column+ column (defaults to +lock_version+). - def locking_enabled? - lock_optimistically && columns_hash[locking_column] - end + # Returns true if the +lock_optimistically+ flag is set to true + # (which it is, by default) and the table includes the + # +locking_column+ column (defaults to +lock_version+). + def locking_enabled? + lock_optimistically && columns_hash[locking_column] + end - # Set the column to use for optimistic locking. Defaults to +lock_version+. - def locking_column=(value) - reload_schema_from_cache - @locking_column = value.to_s - end + # Set the column to use for optimistic locking. Defaults to +lock_version+. + def locking_column=(value) + reload_schema_from_cache + @locking_column = value.to_s + end - # The version column used for optimistic locking. Defaults to +lock_version+. - def locking_column - @locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column) - @locking_column - end + # The version column used for optimistic locking. Defaults to +lock_version+. + def locking_column + @locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column) + @locking_column + end - # Reset the column used for optimistic locking back to the +lock_version+ default. - def reset_locking_column - self.locking_column = DEFAULT_LOCKING_COLUMN - end + # Reset the column used for optimistic locking back to the +lock_version+ default. + def reset_locking_column + self.locking_column = DEFAULT_LOCKING_COLUMN + end - # Make sure the lock version column gets updated when counters are - # updated. - def update_counters(id, counters) - counters = counters.merge(locking_column => 1) if locking_enabled? - super - end + # Make sure the lock version column gets updated when counters are + # updated. + def update_counters(id, counters) + counters = counters.merge(locking_column => 1) if locking_enabled? + super + end - private - - # We need to apply this decorator here, rather than on module inclusion. The closure - # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the - # sub class being decorated. As such, changes to `lock_optimistically`, or - # `locking_column` would not be picked up. - def inherited(subclass) - subclass.class_eval do - is_lock_column = ->(name, _) { lock_optimistically && name == locking_column } - decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type| - LockingType.new(type) + private + + # We need to apply this decorator here, rather than on module inclusion. The closure + # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the + # sub class being decorated. As such, changes to `lock_optimistically`, or + # `locking_column` would not be picked up. + def inherited(subclass) + subclass.class_eval do + is_lock_column = ->(name, _) { lock_optimistically && name == locking_column } + decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type| + LockingType.new(type) + end + end + super end - end - super end - end end - # In de/serialize we change `nil` to 0, so that we can allow passing # `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError` # during update record. @@ -198,11 +203,11 @@ module ActiveRecord end def init_with(coder) - __setobj__(coder['subtype']) + __setobj__(coder["subtype"]) end def encode_with(coder) - coder['subtype'] = __getobj__ + coder["subtype"] = __getobj__ end end end diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb index 8ecdf76b72..e73cb4fc12 100644 --- a/activerecord/lib/active_record/locking/pessimistic.rb +++ b/activerecord/lib/active_record/locking/pessimistic.rb @@ -59,7 +59,7 @@ module ActiveRecord # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns # the locked record. def lock!(lock = true) - reload(:lock => lock) if persisted? + reload(lock: lock) if persisted? self end diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb index 8e32af1c49..4b8d8d9105 100644 --- a/activerecord/lib/active_record/log_subscriber.rb +++ b/activerecord/lib/active_record/log_subscriber.rb @@ -15,40 +15,24 @@ module ActiveRecord rt end - def initialize - super - @odd = false - end - - def render_bind(attribute) - value = if attribute.type.binary? && attribute.value - if attribute.value.is_a?(Hash) - "<#{attribute.value_for_database.to_s.bytesize} bytes of binary data>" - else - "<#{attribute.value.bytesize} bytes of binary data>" - end - else - attribute.value_for_database - end - - [attribute.name, value] - end - def sql(event) - return unless logger.debug? - self.class.runtime += event.duration + return unless logger.debug? payload = event.payload return if IGNORE_PAYLOAD_NAMES.include?(payload[:name]) name = "#{payload[:name]} (#{event.duration.round(1)}ms)" + name = "CACHE #{name}" if payload[:cached] sql = payload[:sql] binds = nil unless (payload[:binds] || []).empty? - binds = " " + payload[:binds].map { |attr| render_bind(attr) }.inspect + casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds]) + binds = " " + payload[:binds].zip(casted_params).map { |attr, value| + render_bind(attr, value) + }.inspect end name = colorize_payload_name(name, payload[:name]) @@ -59,16 +43,30 @@ module ActiveRecord private - def colorize_payload_name(name, payload_name) - if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists - color(name, MAGENTA, true) - else - color(name, CYAN, true) + def type_casted_binds(binds, casted_binds) + casted_binds || binds.map { |attr| type_cast attr.value_for_database } + end + + def render_bind(attr, type_casted_value) + value = if attr.type.binary? && attr.value + "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>" + else + type_casted_value + end + + [attr.name, value] + end + + def colorize_payload_name(name, payload_name) + if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists + color(name, MAGENTA, true) + else + color(name, CYAN, true) + end end - end - def sql_color(sql) - case sql + def sql_color(sql) + case sql when /\A\s*rollback/mi RED when /select .*for update/mi, /\A\s*lock/mi @@ -83,14 +81,18 @@ module ActiveRecord RED when /transaction\s*\Z/i CYAN - else + else MAGENTA + end end - end - def logger - ActiveRecord::Base.logger - end + def logger + ActiveRecord::Base.logger + end + + def type_cast(value) + ActiveRecord::Base.connection.type_cast(value) + end end end diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 81fe053fe1..f333769159 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -1,5 +1,7 @@ +require "set" +require "zlib" require "active_support/core_ext/module/attribute_accessors" -require 'set' +require "active_support/core_ext/regexp" module ActiveRecord class MigrationError < ActiveRecordError#:nodoc: @@ -126,9 +128,9 @@ module ActiveRecord class PendingMigrationError < MigrationError#:nodoc: def initialize(message = nil) if !message && defined?(Rails.env) - super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate RAILS_ENV=#{::Rails.env}") + super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}") elsif !message - super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate") + super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate") else super end @@ -145,7 +147,7 @@ module ActiveRecord class NoEnvironmentInSchemaError < MigrationError #:nodoc: def initialize - msg = "Environment data not found in the schema. To resolve this issue, run: \n\n\tbin/rails db:environment:set" + msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set" if defined?(Rails.env) super("#{msg} RAILS_ENV=#{::Rails.env}") else @@ -168,7 +170,7 @@ module ActiveRecord msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n" msg << "You are running in `#{ current }` environment. " msg << "If you are sure you want to continue, first set the environment using:\n\n" - msg << "\tbin/rails db:environment:set" + msg << " bin/rails db:environment:set" if defined?(Rails.env) super("#{msg} RAILS_ENV=#{::Rails.env}\n\n") else @@ -276,8 +278,10 @@ module ActiveRecord # # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes # the column to a different type using the same parameters as add_column. - # * <tt>change_column_default(table_name, column_name, default)</tt>: Sets a - # default value for +column_name+ defined by +default+ on +table_name+. + # * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>: + # Sets a default value for +column_name+ defined by +default_or_changes+ on + # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt> + # as +default_or_changes+ will make this change reversible in the migration. # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>: # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag # indicates whether the value can be +NULL+. See @@ -509,8 +513,8 @@ module ActiveRecord # Remember that you can still open your own transactions, even if you # are in a Migration with <tt>self.disable_ddl_transaction!</tt>. class Migration - autoload :CommandRecorder, 'active_record/migration/command_recorder' - autoload :Compatibility, 'active_record/migration/compatibility' + autoload :CommandRecorder, "active_record/migration/command_recorder" + autoload :Compatibility, "active_record/migration/compatibility" # This must be defined before the inherited hook, below class Current < Migration # :nodoc: @@ -554,9 +558,9 @@ module ActiveRecord private - def connection - ActiveRecord::Base.connection - end + def connection + ActiveRecord::Base.connection + end end class << self @@ -724,7 +728,7 @@ module ActiveRecord # end def reversible helper = ReversibleBlockHelper.new(reverting?) - execute_block{ yield helper } + execute_block { yield helper } end # Runs the given migration classes. @@ -829,7 +833,7 @@ module ActiveRecord end def method_missing(method, *arguments, &block) - arg_list = arguments.map(&:inspect) * ', ' + arg_list = arguments.map(&:inspect) * ", " say_with_time "#{method}(#{arg_list})" do unless connection.respond_to? :revert @@ -921,19 +925,18 @@ module ActiveRecord end private - def execute_block - if connection.respond_to? :execute_block - super # use normal delegation to record the block - else - yield + def execute_block + if connection.respond_to? :execute_block + super # use normal delegation to record the block + else + yield + end end - end end # MigrationProxy is used to defer loading of the actual migration classes # until they are needed class MigrationProxy < Struct.new(:name, :version, :filename, :scope) - def initialize(name, version, filename, scope) super @migration = nil @@ -959,7 +962,6 @@ module ActiveRecord require(File.expand_path(filename)) name.constantize.new(name, version) end - end class NullMigration < MigrationProxy #:nodoc: @@ -1051,13 +1053,13 @@ module ActiveRecord end def migrations_paths - @migrations_paths ||= ['db/migrate'] + @migrations_paths ||= ["db/migrate"] # just to not break things if someone uses: migrations_path = some_string Array(@migrations_paths) end def match_to_migration_filename?(filename) # :nodoc: - File.basename(filename) =~ Migration::MigrationFilenameRegexp + Migration::MigrationFilenameRegexp.match?(File.basename(filename)) end def parse_migration_filename(filename) # :nodoc: @@ -1164,146 +1166,146 @@ module ActiveRecord private - # Used for running a specific migration. - def run_without_lock - migration = migrations.detect { |m| m.version == @target_version } - raise UnknownMigrationVersionError.new(@target_version) if migration.nil? - execute_migration_in_transaction(migration, @direction) - - record_environment - end + # Used for running a specific migration. + def run_without_lock + migration = migrations.detect { |m| m.version == @target_version } + raise UnknownMigrationVersionError.new(@target_version) if migration.nil? + execute_migration_in_transaction(migration, @direction) - # Used for running multiple migrations up to or down to a certain value. - def migrate_without_lock - if invalid_target? - raise UnknownMigrationVersionError.new(@target_version) + record_environment end - runnable.each do |migration| - execute_migration_in_transaction(migration, @direction) - end + # Used for running multiple migrations up to or down to a certain value. + def migrate_without_lock + if invalid_target? + raise UnknownMigrationVersionError.new(@target_version) + end - record_environment - end + runnable.each do |migration| + execute_migration_in_transaction(migration, @direction) + end - # Stores the current environment in the database. - def record_environment - return if down? - ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment - end + record_environment + end - def ran?(migration) - migrated.include?(migration.version.to_i) - end + # Stores the current environment in the database. + def record_environment + return if down? + ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment + end - # Return true if a valid version is not provided. - def invalid_target? - !target && @target_version && @target_version > 0 - end + def ran?(migration) + migrated.include?(migration.version.to_i) + end + + # Return true if a valid version is not provided. + def invalid_target? + !target && @target_version && @target_version > 0 + end - def execute_migration_in_transaction(migration, direction) - return if down? && !migrated.include?(migration.version.to_i) - return if up? && migrated.include?(migration.version.to_i) + def execute_migration_in_transaction(migration, direction) + return if down? && !migrated.include?(migration.version.to_i) + return if up? && migrated.include?(migration.version.to_i) - Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger + Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger - ddl_transaction(migration) do - migration.migrate(direction) - record_version_state_after_migrating(migration.version) + ddl_transaction(migration) do + migration.migrate(direction) + record_version_state_after_migrating(migration.version) + end + rescue => e + msg = "An error has occurred, " + msg << "this and " if use_transaction?(migration) + msg << "all later migrations canceled:\n\n#{e}" + raise StandardError, msg, e.backtrace end - rescue => e - msg = "An error has occurred, " - msg << "this and " if use_transaction?(migration) - msg << "all later migrations canceled:\n\n#{e}" - raise StandardError, msg, e.backtrace - end - def target - migrations.detect { |m| m.version == @target_version } - end + def target + migrations.detect { |m| m.version == @target_version } + end - def finish - migrations.index(target) || migrations.size - 1 - end + def finish + migrations.index(target) || migrations.size - 1 + end - def start - up? ? 0 : (migrations.index(current) || 0) - end + def start + up? ? 0 : (migrations.index(current) || 0) + end - def validate(migrations) - name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 } - raise DuplicateMigrationNameError.new(name) if name + def validate(migrations) + name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 } + raise DuplicateMigrationNameError.new(name) if name - version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 } - raise DuplicateMigrationVersionError.new(version) if version - end + version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 } + raise DuplicateMigrationVersionError.new(version) if version + end - def record_version_state_after_migrating(version) - if down? - migrated.delete(version) - ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all - else - migrated << version - ActiveRecord::SchemaMigration.create!(version: version.to_s) + def record_version_state_after_migrating(version) + if down? + migrated.delete(version) + ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all + else + migrated << version + ActiveRecord::SchemaMigration.create!(version: version.to_s) + end end - end - def self.last_stored_environment - return nil if current_version == 0 - raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists? + def self.last_stored_environment + return nil if current_version == 0 + raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists? - environment = ActiveRecord::InternalMetadata[:environment] - raise NoEnvironmentInSchemaError unless environment - environment - end + environment = ActiveRecord::InternalMetadata[:environment] + raise NoEnvironmentInSchemaError unless environment + environment + end - def self.current_environment - ActiveRecord::ConnectionHandling::DEFAULT_ENV.call - end + def self.current_environment + ActiveRecord::ConnectionHandling::DEFAULT_ENV.call + end - def self.protected_environment? - ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment - end + def self.protected_environment? + ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment + end - def up? - @direction == :up - end + def up? + @direction == :up + end - def down? - @direction == :down - end + def down? + @direction == :down + end - # Wrap the migration in a transaction only if supported by the adapter. - def ddl_transaction(migration) - if use_transaction?(migration) - Base.transaction { yield } - else - yield + # Wrap the migration in a transaction only if supported by the adapter. + def ddl_transaction(migration) + if use_transaction?(migration) + Base.transaction { yield } + else + yield + end end - end - def use_transaction?(migration) - !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions? - end + def use_transaction?(migration) + !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions? + end - def use_advisory_lock? - Base.connection.supports_advisory_locks? - end + def use_advisory_lock? + Base.connection.supports_advisory_locks? + end - def with_advisory_lock - lock_id = generate_migrator_advisory_lock_id - got_lock = Base.connection.get_advisory_lock(lock_id) - raise ConcurrentMigrationError unless got_lock - load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock - yield - ensure - Base.connection.release_advisory_lock(lock_id) if got_lock - end + def with_advisory_lock + lock_id = generate_migrator_advisory_lock_id + got_lock = Base.connection.get_advisory_lock(lock_id) + raise ConcurrentMigrationError unless got_lock + load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock + yield + ensure + Base.connection.release_advisory_lock(lock_id) if got_lock + end - MIGRATOR_SALT = 2053462845 - def generate_migrator_advisory_lock_id - db_name_hash = Zlib.crc32(Base.connection.current_database) - MIGRATOR_SALT * db_name_hash - end + MIGRATOR_SALT = 2053462845 + def generate_migrator_advisory_lock_id + db_name_hash = Zlib.crc32(Base.connection.current_database) + MIGRATOR_SALT * db_name_hash + end end end diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 0fa665c7e0..03103bba98 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -92,7 +92,7 @@ module ActiveRecord send(method, args, &block) end - def respond_to?(*args) # :nodoc: + def respond_to_missing?(*args) # :nodoc: super || delegate.respond_to?(*args) end @@ -112,127 +112,127 @@ module ActiveRecord private - module StraightReversions - private - { transaction: :transaction, - execute_block: :execute_block, - create_table: :drop_table, - create_join_table: :drop_join_table, - add_column: :remove_column, - add_timestamps: :remove_timestamps, - add_reference: :remove_reference, - enable_extension: :disable_extension - }.each do |cmd, inv| - [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse| - class_eval <<-EOV, __FILE__, __LINE__ + 1 - def invert_#{method}(args, &block) # def invert_create_table(args, &block) - [:#{inverse}, args, block] # [:drop_table, args, block] - end # end - EOV - end + module StraightReversions + private + { transaction: :transaction, + execute_block: :execute_block, + create_table: :drop_table, + create_join_table: :drop_join_table, + add_column: :remove_column, + add_timestamps: :remove_timestamps, + add_reference: :remove_reference, + enable_extension: :disable_extension + }.each do |cmd, inv| + [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse| + class_eval <<-EOV, __FILE__, __LINE__ + 1 + def invert_#{method}(args, &block) # def invert_create_table(args, &block) + [:#{inverse}, args, block] # [:drop_table, args, block] + end # end + EOV + end + end end - end - include StraightReversions + include StraightReversions - def invert_drop_table(args, &block) - if args.size == 1 && block == nil - raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)." + def invert_drop_table(args, &block) + if args.size == 1 && block == nil + raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)." + end + super end - super - end - def invert_rename_table(args) - [:rename_table, args.reverse] - end + def invert_rename_table(args) + [:rename_table, args.reverse] + end - def invert_remove_column(args) - raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2 - super - end + def invert_remove_column(args) + raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2 + super + end - def invert_rename_index(args) - [:rename_index, [args.first] + args.last(2).reverse] - end + def invert_rename_index(args) + [:rename_index, [args.first] + args.last(2).reverse] + end - def invert_rename_column(args) - [:rename_column, [args.first] + args.last(2).reverse] - end + def invert_rename_column(args) + [:rename_column, [args.first] + args.last(2).reverse] + end - def invert_add_index(args) - table, columns, options = *args - options ||= {} + def invert_add_index(args) + table, columns, options = *args + options ||= {} - index_name = options[:name] - options_hash = index_name ? { name: index_name } : { column: columns } + index_name = options[:name] + options_hash = index_name ? { name: index_name } : { column: columns } - [:remove_index, [table, options_hash]] - end + [:remove_index, [table, options_hash]] + end - def invert_remove_index(args) - table, options_or_column = *args - if (options = options_or_column).is_a?(Hash) - unless options[:column] - raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option." + def invert_remove_index(args) + table, options_or_column = *args + if (options = options_or_column).is_a?(Hash) + unless options[:column] + raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option." + end + options = options.dup + [:add_index, [table, options.delete(:column), options]] + elsif (column = options_or_column).present? + [:add_index, [table, column]] end - options = options.dup - [:add_index, [table, options.delete(:column), options]] - elsif (column = options_or_column).present? - [:add_index, [table, column]] end - end - alias :invert_add_belongs_to :invert_add_reference - alias :invert_remove_belongs_to :invert_remove_reference + alias :invert_add_belongs_to :invert_add_reference + alias :invert_remove_belongs_to :invert_remove_reference + + def invert_change_column_default(args) + table, column, options = *args - def invert_change_column_default(args) - table, column, options = *args + unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to) + raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option." + end - unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to) - raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option." + [:change_column_default, [table, column, from: options[:to], to: options[:from]]] end - [:change_column_default, [table, column, from: options[:to], to: options[:from]]] - end + def invert_change_column_null(args) + args[2] = !args[2] + [:change_column_null, args] + end - def invert_change_column_null(args) - args[2] = !args[2] - [:change_column_null, args] - end + def invert_add_foreign_key(args) + from_table, to_table, add_options = args + add_options ||= {} - def invert_add_foreign_key(args) - from_table, to_table, add_options = args - add_options ||= {} + if add_options[:name] + options = { name: add_options[:name] } + elsif add_options[:column] + options = { column: add_options[:column] } + else + options = to_table + end - if add_options[:name] - options = { name: add_options[:name] } - elsif add_options[:column] - options = { column: add_options[:column] } - else - options = to_table + [:remove_foreign_key, [from_table, options]] end - [:remove_foreign_key, [from_table, options]] - end - - def invert_remove_foreign_key(args) - from_table, to_table, remove_options = args - raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil? || to_table.is_a?(Hash) + def invert_remove_foreign_key(args) + from_table, to_table, remove_options = args + raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil? || to_table.is_a?(Hash) - reversed_args = [from_table, to_table] - reversed_args << remove_options if remove_options + reversed_args = [from_table, to_table] + reversed_args << remove_options if remove_options - [:add_foreign_key, reversed_args] - end + [:add_foreign_key, reversed_args] + end - # Forwards any missing method call to the \target. - def method_missing(method, *args, &block) - if @delegate.respond_to?(method) - @delegate.send(method, *args, &block) - else - super + # Forwards any missing method call to the \target. + def method_missing(method, *args, &block) + if @delegate.respond_to?(method) + @delegate.send(method, *args, &block) + else + super + end end - end end end end diff --git a/activerecord/lib/active_record/migration/compatibility.rb b/activerecord/lib/active_record/migration/compatibility.rb index 74833f938f..04e538baa5 100644 --- a/activerecord/lib/active_record/migration/compatibility.rb +++ b/activerecord/lib/active_record/migration/compatibility.rb @@ -5,7 +5,7 @@ module ActiveRecord version = version.to_s name = "V#{version.tr('.', '_')}" unless const_defined?(name) - versions = constants.grep(/\AV[0-9_]+\z/).map { |s| s.to_s.delete('V').tr('_', '.').inspect } + versions = constants.grep(/\AV[0-9_]+\z/).map { |s| s.to_s.delete("V").tr("_", ".").inspect } raise ArgumentError, "Unknown migration version #{version.inspect}; expected one of #{versions.sort.join(', ')}" end const_get(name) @@ -21,7 +21,7 @@ module ActiveRecord end alias :belongs_to :references - def timestamps(*, **options) + def timestamps(**options) options[:null] = true if options[:null].nil? super end @@ -59,7 +59,7 @@ module ActiveRecord end alias :add_belongs_to :add_reference - def add_timestamps(*, **options) + def add_timestamps(_, **options) options[:null] = true if options[:null].nil? super end @@ -83,23 +83,23 @@ module ActiveRecord private - def index_name_for_remove(table_name, options = {}) - index_name = index_name(table_name, options) + def index_name_for_remove(table_name, options = {}) + index_name = index_name(table_name, options) - unless index_name_exists?(table_name, index_name, true) - if options.is_a?(Hash) && options.has_key?(:name) - options_without_column = options.dup - options_without_column.delete :column - index_name_without_column = index_name(table_name, options_without_column) + unless index_name_exists?(table_name, index_name, true) + if options.is_a?(Hash) && options.has_key?(:name) + options_without_column = options.dup + options_without_column.delete :column + index_name_without_column = index_name(table_name, options_without_column) - return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false) + return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false) + end + + raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist" end - raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist" + index_name end - - index_name - end end class V5_0 < V5_1 diff --git a/activerecord/lib/active_record/migration/join_table.rb b/activerecord/lib/active_record/migration/join_table.rb index 05569fadbd..89789f00ea 100644 --- a/activerecord/lib/active_record/migration/join_table.rb +++ b/activerecord/lib/active_record/migration/join_table.rb @@ -3,13 +3,13 @@ module ActiveRecord module JoinTable #:nodoc: private - def find_join_table_name(table_1, table_2, options = {}) - options.delete(:table_name) || join_table_name(table_1, table_2) - end + def find_join_table_name(table_1, table_2, options = {}) + options.delete(:table_name) || join_table_name(table_1, table_2) + end - def join_table_name(table_1, table_2) - ModelSchema.derive_join_table_name(table_1, table_2).to_sym - end + def join_table_name(table_1, table_2) + ModelSchema.derive_join_table_name(table_1, table_2).to_sym + end end end end diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index 7996c32bbc..525f7444a5 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -2,75 +2,154 @@ module ActiveRecord module ModelSchema extend ActiveSupport::Concern + ## + # :singleton-method: primary_key_prefix_type + # :call-seq: primary_key_prefix_type + # + # The prefix type that will be prepended to every primary key column name. + # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified, + # the Product class will look for "productid" instead of "id" as the primary column. If the + # latter is specified, the Product class will look for "product_id" instead of "id". Remember + # that this is a global setting for all Active Records. + + ## + # :singleton-method: primary_key_prefix_type= + # :call-seq: primary_key_prefix_type=(prefix_type) + # + # Sets the prefix type that will be prepended to every primary key column name. + # The options are +:table_name+ and +:table_name_with_underscore+. If the first is specified, + # the Product class will look for "productid" instead of "id" as the primary column. If the + # latter is specified, the Product class will look for "product_id" instead of "id". Remember + # that this is a global setting for all Active Records. + + ## + # :singleton-method: table_name_prefix + # :call-seq: table_name_prefix + # + # The prefix string to prepend to every table name. + + ## + # :singleton-method: table_name_prefix= + # :call-seq: table_name_prefix=(prefix) + # + # Sets the prefix string to prepend to every table name. So if set to "basecamp_", all table + # names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient + # way of creating a namespace for tables in a shared database. By default, the prefix is the + # empty string. + # + # If you are organising your models within modules you can add a prefix to the models within + # a namespace by defining a singleton method in the parent module called table_name_prefix which + # returns your chosen prefix. + + ## + # :singleton-method: table_name_suffix + # :call-seq: table_name_suffix + # + # The suffix string to append to every table name. + + ## + # :singleton-method: table_name_suffix= + # :call-seq: table_name_suffix=(suffix) + # + # Works like +table_name_prefix=+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp", + # "people_basecamp"). By default, the suffix is the empty string. + # + # If you are organising your models within modules, you can add a suffix to the models within + # a namespace by defining a singleton method in the parent module called table_name_suffix which + # returns your chosen suffix. + + ## + # :singleton-method: schema_migrations_table_name + # :call-seq: schema_migrations_table_name + # + # The name of the schema migrations table. By default, the value is <tt>"schema_migrations"</tt>. + + ## + # :singleton-method: schema_migrations_table_name= + # :call-seq: schema_migrations_table_name=(table_name) + # + # Sets the name of the schema migrations table. + + ## + # :singleton-method: internal_metadata_table_name + # :call-seq: internal_metadata_table_name + # + # The name of the internal metadata table. By default, the value is <tt>"ar_internal_metadata"</tt>. + + ## + # :singleton-method: internal_metadata_table_name= + # :call-seq: internal_metadata_table_name=(table_name) + # + # Sets the name of the internal metadata table. + + ## + # :singleton-method: protected_environments + # :call-seq: protected_environments + # + # The array of names of environments where destructive actions should be prohibited. By default, + # the value is <tt>["production"]</tt>. + + ## + # :singleton-method: protected_environments= + # :call-seq: protected_environments=(environments) + # + # Sets an array of names of environments where destructive actions should be prohibited. + + ## + # :singleton-method: pluralize_table_names + # :call-seq: pluralize_table_names + # + # Indicates whether table names should be the pluralized versions of the corresponding class names. + # If true, the default table name for a Product class will be "products". If false, it would just be "product". + # See table_name for the full rules on table/class naming. This is true, by default. + + ## + # :singleton-method: pluralize_table_names= + # :call-seq: pluralize_table_names=(value) + # + # Set whether table names should be the pluralized versions of the corresponding class names. + # If true, the default table name for a Product class will be "products". If false, it would just be "product". + # See table_name for the full rules on table/class naming. This is true, by default. + + ## + # :singleton-method: ignored_columns + # :call-seq: ignored_columns + # + # The list of columns names the model should ignore. Ignored columns won't have attribute + # accessors defined, and won't be referenced in SQL queries. + + ## + # :singleton-method: ignored_columns= + # :call-seq: ignored_columns=(columns) + # + # Sets the columns names the model should ignore. Ignored columns won't have attribute + # accessors defined, and won't be referenced in SQL queries. + included do - ## - # :singleton-method: - # Accessor for the prefix type that will be prepended to every primary key column name. - # The options are :table_name and :table_name_with_underscore. If the first is specified, - # the Product class will look for "productid" instead of "id" as the primary column. If the - # latter is specified, the Product class will look for "product_id" instead of "id". Remember - # that this is a global setting for all Active Records. mattr_accessor :primary_key_prefix_type, instance_writer: false - ## - # :singleton-method: - # Accessor for the name of the prefix string to prepend to every table name. So if set - # to "basecamp_", all table names will be named like "basecamp_projects", "basecamp_people", - # etc. This is a convenient way of creating a namespace for tables in a shared database. - # By default, the prefix is the empty string. - # - # If you are organising your models within modules you can add a prefix to the models within - # a namespace by defining a singleton method in the parent module called table_name_prefix which - # returns your chosen prefix. class_attribute :table_name_prefix, instance_writer: false self.table_name_prefix = "" - ## - # :singleton-method: - # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp", - # "people_basecamp"). By default, the suffix is the empty string. - # - # If you are organising your models within modules, you can add a suffix to the models within - # a namespace by defining a singleton method in the parent module called table_name_suffix which - # returns your chosen suffix. class_attribute :table_name_suffix, instance_writer: false self.table_name_suffix = "" - ## - # :singleton-method: - # Accessor for the name of the schema migrations table. By default, the value is "schema_migrations" class_attribute :schema_migrations_table_name, instance_accessor: false self.schema_migrations_table_name = "schema_migrations" - ## - # :singleton-method: - # Accessor for the name of the internal metadata table. By default, the value is "ar_internal_metadata" class_attribute :internal_metadata_table_name, instance_accessor: false self.internal_metadata_table_name = "ar_internal_metadata" - ## - # :singleton-method: - # Accessor for an array of names of environments where destructive actions should be prohibited. By default, - # the value is ["production"] class_attribute :protected_environments, instance_accessor: false self.protected_environments = ["production"] - ## - # :singleton-method: - # Indicates whether table names should be the pluralized versions of the corresponding class names. - # If true, the default table name for a Product class will be +products+. If false, it would just be +product+. - # See table_name for the full rules on table/class naming. This is true, by default. class_attribute :pluralize_table_names, instance_writer: false self.pluralize_table_names = true - ## - # :singleton-method: - # Accessor for the list of columns names the model should ignore. Ignored columns won't have attribute - # accessors defined, and won't be referenced in SQL queries. class_attribute :ignored_columns, instance_accessor: false self.ignored_columns = [].freeze - self.inheritance_column = 'type' + self.inheritance_column = "type" delegate :type_for_attribute, to: :class end @@ -173,11 +252,11 @@ module ActiveRecord end def full_table_name_prefix #:nodoc: - (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix + (parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix end def full_table_name_suffix #:nodoc: - (parents.detect {|p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix + (parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix end # Defines the name of the table column which will store the class name on single-table @@ -249,7 +328,11 @@ module ActiveRecord end def attributes_builder # :nodoc: - @attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key) + @attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key) do |name| + unless columns_hash.key?(name) + _default_attributes[name].dup + end + end end def columns_hash # :nodoc: @@ -264,7 +347,7 @@ module ActiveRecord def attribute_types # :nodoc: load_schema - @attribute_types ||= Hash.new(Type::Value.new) + @attribute_types ||= Hash.new(Type.default_value) end def yaml_encoder # :nodoc: @@ -282,8 +365,12 @@ module ActiveRecord # # +attr_name+ The name of the attribute to retrieve the type for. Must be # a string - def type_for_attribute(attr_name) - attribute_types[attr_name] + def type_for_attribute(attr_name, &block) + if block + attribute_types.fetch(attr_name, &block) + else + attribute_types[attr_name] + end end # Returns a hash where the keys are column names and the values are @@ -305,7 +392,12 @@ module ActiveRecord # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count", # and columns used for single table inheritance have been removed. def content_columns - @content_columns ||= columns.reject { |c| c.name == primary_key || c.name =~ /(_id|_count)$/ || c.name == inheritance_column } + @content_columns ||= columns.reject do |c| + c.name == primary_key || + c.name == inheritance_column || + c.name.end_with?("_id") || + c.name.end_with?("_count") + end end # Resets all the cached information about columns, which will cause them @@ -344,92 +436,69 @@ module ActiveRecord private - def schema_loaded? - defined?(@columns_hash) && @columns_hash - end - - def load_schema - unless schema_loaded? - load_schema! + def schema_loaded? + defined?(@columns_hash) && @columns_hash end - end - def load_schema! - @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns) - @columns_hash.each do |name, column| - warn_if_deprecated_type(column) - define_attribute( - name, - connection.lookup_cast_type_from_column(column), - default: column.default, - user_provided_default: false - ) + def load_schema + unless schema_loaded? + load_schema! + end end - end - def reload_schema_from_cache - @arel_engine = nil - @arel_table = nil - @column_names = nil - @attribute_types = nil - @content_columns = nil - @default_attributes = nil - @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column - @attributes_builder = nil - @columns = nil - @columns_hash = nil - @attribute_names = nil - @yaml_encoder = nil - direct_descendants.each do |descendant| - descendant.send(:reload_schema_from_cache) + def load_schema! + @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns) + @columns_hash.each do |name, column| + define_attribute( + name, + connection.lookup_cast_type_from_column(column), + default: column.default, + user_provided_default: false + ) + end end - end - # Guesses the table name, but does not decorate it with prefix and suffix information. - def undecorated_table_name(class_name = base_class.name) - table_name = class_name.to_s.demodulize.underscore - pluralize_table_names ? table_name.pluralize : table_name - end - - # Computes and returns a table name according to default conventions. - def compute_table_name - base = base_class - if self == base - # Nested classes are prefixed with singular parent table name. - if parent < Base && !parent.abstract_class? - contained = parent.table_name - contained = contained.singularize if parent.pluralize_table_names - contained += '_' + def reload_schema_from_cache + @arel_engine = nil + @arel_table = nil + @column_names = nil + @attribute_types = nil + @content_columns = nil + @default_attributes = nil + @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column + @attributes_builder = nil + @columns = nil + @columns_hash = nil + @attribute_names = nil + @yaml_encoder = nil + direct_descendants.each do |descendant| + descendant.send(:reload_schema_from_cache) end + end - "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}" - else - # STI subclasses always use their superclass' table. - base.table_name + # Guesses the table name, but does not decorate it with prefix and suffix information. + def undecorated_table_name(class_name = base_class.name) + table_name = class_name.to_s.demodulize.underscore + pluralize_table_names ? table_name.pluralize : table_name end - end - def warn_if_deprecated_type(column) - return if attributes_to_define_after_schema_loads.key?(column.name) - if column.respond_to?(:oid) && column.sql_type.start_with?("point") - if column.array? - array_arguments = ", array: true" + # Computes and returns a table name according to default conventions. + def compute_table_name + base = base_class + if self == base + # Nested classes are prefixed with singular parent table name. + if parent < Base && !parent.abstract_class? + contained = parent.table_name + contained = contained.singularize if parent.pluralize_table_names + contained += "_" + end + + "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}" else - array_arguments = "" + # STI subclasses always use their superclass' table. + base.table_name end - ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc) - The behavior of the `:point` type will be changing in Rails 5.1 to - return a `Point` object, rather than an `Array`. If you'd like to - keep the old behavior, you can add this line to #{self.name}: - - attribute :#{column.name}, :legacy_point#{array_arguments} - - If you'd like the new behavior today, you can add this line: - - attribute :#{column.name}, :point#{array_arguments} - WARNING end - end end end end diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index fe68869143..e983026961 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/object/try' -require 'active_support/core_ext/hash/indifferent_access' +require "active_support/core_ext/hash/except" +require "active_support/core_ext/object/try" +require "active_support/core_ext/hash/indifferent_access" module ActiveRecord module NestedAttributes #:nodoc: @@ -267,7 +267,7 @@ module ActiveRecord # member.avatar_attributes = {icon: 'sad'} # member.avatar.width # => 200 module ClassMethods - REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } } + REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } } # Defines an attributes writer for the specified association(s). # @@ -317,7 +317,7 @@ module ActiveRecord # # creates avatar_attributes= and posts_attributes= # accepts_nested_attributes_for :avatar, :posts, allow_destroy: true def accepts_nested_attributes_for(*attr_names) - options = { :allow_destroy => false, :update_only => false } + options = { allow_destroy: false, update_only: false } options.update(attr_names.extract_options!) options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only) options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank @@ -341,27 +341,27 @@ module ActiveRecord private - # Generates a writer method for this association. Serves as a point for - # accessing the objects in the association. For example, this method - # could generate the following: - # - # def pirate_attributes=(attributes) - # assign_nested_attributes_for_one_to_one_association(:pirate, attributes) - # end - # - # This redirects the attempts to write objects in an association through - # the helper methods defined below. Makes it seem like the nested - # associations are just regular associations. - def generate_association_writer(association_name, type) - generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1 - if method_defined?(:#{association_name}_attributes=) - remove_method(:#{association_name}_attributes=) - end - def #{association_name}_attributes=(attributes) - assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes) - end - eoruby - end + # Generates a writer method for this association. Serves as a point for + # accessing the objects in the association. For example, this method + # could generate the following: + # + # def pirate_attributes=(attributes) + # assign_nested_attributes_for_one_to_one_association(:pirate, attributes) + # end + # + # This redirects the attempts to write objects in an association through + # the helper methods defined below. Makes it seem like the nested + # associations are just regular associations. + def generate_association_writer(association_name, type) + generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1 + if method_defined?(:#{association_name}_attributes=) + remove_method(:#{association_name}_attributes=) + end + def #{association_name}_attributes=(attributes) + assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes) + end + eoruby + end end # Returns ActiveRecord::AutosaveAssociation::marked_for_destruction? It's @@ -375,213 +375,214 @@ module ActiveRecord private - # Attribute hash keys that should not be assigned as normal attributes. - # These hash keys are nested attributes implementation details. - UNASSIGNABLE_KEYS = %w( id _destroy ) - - # Assigns the given attributes to the association. - # - # If an associated record does not yet exist, one will be instantiated. If - # an associated record already exists, the method's behavior depends on - # the value of the update_only option. If update_only is +false+ and the - # given attributes include an <tt>:id</tt> that matches the existing record's - # id, then the existing record will be modified. If no <tt>:id</tt> is provided - # it will be replaced with a new record. If update_only is +true+ the existing - # record will be modified regardless of whether an <tt>:id</tt> is provided. - # - # If the given attributes include a matching <tt>:id</tt> attribute, or - # update_only is true, and a <tt>:_destroy</tt> key set to a truthy value, - # then the existing record will be marked for destruction. - def assign_nested_attributes_for_one_to_one_association(association_name, attributes) - options = self.nested_attributes_options[association_name] - if attributes.respond_to?(:permitted?) - attributes = attributes.to_h - end - attributes = attributes.with_indifferent_access - existing_record = send(association_name) + # Attribute hash keys that should not be assigned as normal attributes. + # These hash keys are nested attributes implementation details. + UNASSIGNABLE_KEYS = %w( id _destroy ) - if (options[:update_only] || !attributes['id'].blank?) && existing_record && - (options[:update_only] || existing_record.id.to_s == attributes['id'].to_s) - assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) + # Assigns the given attributes to the association. + # + # If an associated record does not yet exist, one will be instantiated. If + # an associated record already exists, the method's behavior depends on + # the value of the update_only option. If update_only is +false+ and the + # given attributes include an <tt>:id</tt> that matches the existing record's + # id, then the existing record will be modified. If no <tt>:id</tt> is provided + # it will be replaced with a new record. If update_only is +true+ the existing + # record will be modified regardless of whether an <tt>:id</tt> is provided. + # + # If the given attributes include a matching <tt>:id</tt> attribute, or + # update_only is true, and a <tt>:_destroy</tt> key set to a truthy value, + # then the existing record will be marked for destruction. + def assign_nested_attributes_for_one_to_one_association(association_name, attributes) + options = self.nested_attributes_options[association_name] + if attributes.respond_to?(:permitted?) + attributes = attributes.to_h + end + attributes = attributes.with_indifferent_access + existing_record = send(association_name) - elsif attributes['id'].present? - raise_nested_attributes_record_not_found!(association_name, attributes['id']) + if (options[:update_only] || !attributes["id"].blank?) && existing_record && + (options[:update_only] || existing_record.id.to_s == attributes["id"].to_s) + assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) - elsif !reject_new_record?(association_name, attributes) - assignable_attributes = attributes.except(*UNASSIGNABLE_KEYS) + elsif attributes["id"].present? + raise_nested_attributes_record_not_found!(association_name, attributes["id"]) - if existing_record && existing_record.new_record? - existing_record.assign_attributes(assignable_attributes) - association(association_name).initialize_attributes(existing_record) - else - method = "build_#{association_name}" - if respond_to?(method) - send(method, assignable_attributes) + elsif !reject_new_record?(association_name, attributes) + assignable_attributes = attributes.except(*UNASSIGNABLE_KEYS) + + if existing_record && existing_record.new_record? + existing_record.assign_attributes(assignable_attributes) + association(association_name).initialize_attributes(existing_record) else - raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?" + method = "build_#{association_name}" + if respond_to?(method) + send(method, assignable_attributes) + else + raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?" + end end end end - end - # Assigns the given attributes to the collection association. - # - # Hashes with an <tt>:id</tt> value matching an existing associated record - # will update that record. Hashes without an <tt>:id</tt> value will build - # a new record for the association. Hashes with a matching <tt>:id</tt> - # value and a <tt>:_destroy</tt> key set to a truthy value will mark the - # matched record for destruction. - # - # For example: - # - # assign_nested_attributes_for_collection_association(:people, { - # '1' => { id: '1', name: 'Peter' }, - # '2' => { name: 'John' }, - # '3' => { id: '2', _destroy: true } - # }) - # - # Will update the name of the Person with ID 1, build a new associated - # person with the name 'John', and mark the associated Person with ID 2 - # for destruction. - # - # Also accepts an Array of attribute hashes: - # - # assign_nested_attributes_for_collection_association(:people, [ - # { id: '1', name: 'Peter' }, - # { name: 'John' }, - # { id: '2', _destroy: true } - # ]) - def assign_nested_attributes_for_collection_association(association_name, attributes_collection) - options = self.nested_attributes_options[association_name] - if attributes_collection.respond_to?(:permitted?) - attributes_collection = attributes_collection.to_h - end + # Assigns the given attributes to the collection association. + # + # Hashes with an <tt>:id</tt> value matching an existing associated record + # will update that record. Hashes without an <tt>:id</tt> value will build + # a new record for the association. Hashes with a matching <tt>:id</tt> + # value and a <tt>:_destroy</tt> key set to a truthy value will mark the + # matched record for destruction. + # + # For example: + # + # assign_nested_attributes_for_collection_association(:people, { + # '1' => { id: '1', name: 'Peter' }, + # '2' => { name: 'John' }, + # '3' => { id: '2', _destroy: true } + # }) + # + # Will update the name of the Person with ID 1, build a new associated + # person with the name 'John', and mark the associated Person with ID 2 + # for destruction. + # + # Also accepts an Array of attribute hashes: + # + # assign_nested_attributes_for_collection_association(:people, [ + # { id: '1', name: 'Peter' }, + # { name: 'John' }, + # { id: '2', _destroy: true } + # ]) + def assign_nested_attributes_for_collection_association(association_name, attributes_collection) + options = self.nested_attributes_options[association_name] + if attributes_collection.respond_to?(:permitted?) + attributes_collection = attributes_collection.to_h + end - unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array) - raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})" - end + unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array) + raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})" + end - check_record_limit!(options[:limit], attributes_collection) + check_record_limit!(options[:limit], attributes_collection) - if attributes_collection.is_a? Hash - keys = attributes_collection.keys - attributes_collection = if keys.include?('id') || keys.include?(:id) - [attributes_collection] - else - attributes_collection.values + if attributes_collection.is_a? Hash + keys = attributes_collection.keys + attributes_collection = if keys.include?("id") || keys.include?(:id) + [attributes_collection] + else + attributes_collection.values + end end - end - association = association(association_name) + association = association(association_name) - existing_records = if association.loaded? - association.target - else - attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact - attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids) - end - - attributes_collection.each do |attributes| - if attributes.respond_to?(:permitted?) - attributes = attributes.to_h + existing_records = if association.loaded? + association.target + else + attribute_ids = attributes_collection.map { |a| a["id"] || a[:id] }.compact + attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids) end - attributes = attributes.with_indifferent_access - if attributes['id'].blank? - unless reject_new_record?(association_name, attributes) - association.build(attributes.except(*UNASSIGNABLE_KEYS)) + attributes_collection.each do |attributes| + if attributes.respond_to?(:permitted?) + attributes = attributes.to_h end - elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s } - unless call_reject_if(association_name, attributes) - # Make sure we are operating on the actual object which is in the association's - # proxy_target array (either by finding it, or adding it if not found) - # Take into account that the proxy_target may have changed due to callbacks - target_record = association.target.detect { |record| record.id.to_s == attributes['id'].to_s } - if target_record - existing_record = target_record - else - association.add_to_target(existing_record, :skip_callbacks) - end + attributes = attributes.with_indifferent_access - assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) + if attributes["id"].blank? + unless reject_new_record?(association_name, attributes) + association.build(attributes.except(*UNASSIGNABLE_KEYS)) + end + elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s } + unless call_reject_if(association_name, attributes) + # Make sure we are operating on the actual object which is in the association's + # proxy_target array (either by finding it, or adding it if not found) + # Take into account that the proxy_target may have changed due to callbacks + target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s } + if target_record + existing_record = target_record + else + association.add_to_target(existing_record, :skip_callbacks) + end + + assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) + end + else + raise_nested_attributes_record_not_found!(association_name, attributes["id"]) end - else - raise_nested_attributes_record_not_found!(association_name, attributes['id']) end end - end - # Takes in a limit and checks if the attributes_collection has too many - # records. It accepts limit in the form of symbol, proc, or - # number-like object (anything that can be compared with an integer). - # - # Raises TooManyRecords error if the attributes_collection is - # larger than the limit. - def check_record_limit!(limit, attributes_collection) - if limit - limit = case limit - when Symbol - send(limit) - when Proc - limit.call - else - limit - end + # Takes in a limit and checks if the attributes_collection has too many + # records. It accepts limit in the form of symbol, proc, or + # number-like object (anything that can be compared with an integer). + # + # Raises TooManyRecords error if the attributes_collection is + # larger than the limit. + def check_record_limit!(limit, attributes_collection) + if limit + limit = \ + case limit + when Symbol + send(limit) + when Proc + limit.call + else + limit + end - if limit && attributes_collection.size > limit - raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead." + if limit && attributes_collection.size > limit + raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead." + end end end - end - # Updates a record with the +attributes+ or marks it for destruction if - # +allow_destroy+ is +true+ and has_destroy_flag? returns +true+. - def assign_to_or_mark_for_destruction(record, attributes, allow_destroy) - record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS)) - record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy - end + # Updates a record with the +attributes+ or marks it for destruction if + # +allow_destroy+ is +true+ and has_destroy_flag? returns +true+. + def assign_to_or_mark_for_destruction(record, attributes, allow_destroy) + record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS)) + record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy + end - # Determines if a hash contains a truthy _destroy key. - def has_destroy_flag?(hash) - Type::Boolean.new.cast(hash['_destroy']) - end + # Determines if a hash contains a truthy _destroy key. + def has_destroy_flag?(hash) + Type::Boolean.new.cast(hash["_destroy"]) + end - # Determines if a new record should be rejected by checking - # has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this - # association and evaluates to +true+. - def reject_new_record?(association_name, attributes) - will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes) - end + # Determines if a new record should be rejected by checking + # has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this + # association and evaluates to +true+. + def reject_new_record?(association_name, attributes) + will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes) + end - # Determines if a record with the particular +attributes+ should be - # rejected by calling the reject_if Symbol or Proc (if defined). - # The reject_if option is defined by +accepts_nested_attributes_for+. - # - # Returns false if there is a +destroy_flag+ on the attributes. - def call_reject_if(association_name, attributes) - return false if will_be_destroyed?(association_name, attributes) + # Determines if a record with the particular +attributes+ should be + # rejected by calling the reject_if Symbol or Proc (if defined). + # The reject_if option is defined by +accepts_nested_attributes_for+. + # + # Returns false if there is a +destroy_flag+ on the attributes. + def call_reject_if(association_name, attributes) + return false if will_be_destroyed?(association_name, attributes) - case callback = self.nested_attributes_options[association_name][:reject_if] - when Symbol - method(callback).arity == 0 ? send(callback) : send(callback, attributes) - when Proc - callback.call(attributes) + case callback = self.nested_attributes_options[association_name][:reject_if] + when Symbol + method(callback).arity == 0 ? send(callback) : send(callback, attributes) + when Proc + callback.call(attributes) + end end - end - # Only take into account the destroy flag if <tt>:allow_destroy</tt> is true - def will_be_destroyed?(association_name, attributes) - allow_destroy?(association_name) && has_destroy_flag?(attributes) - end + # Only take into account the destroy flag if <tt>:allow_destroy</tt> is true + def will_be_destroyed?(association_name, attributes) + allow_destroy?(association_name) && has_destroy_flag?(attributes) + end - def allow_destroy?(association_name) - self.nested_attributes_options[association_name][:allow_destroy] - end + def allow_destroy?(association_name) + nested_attributes_options[association_name][:allow_destroy] + end - def raise_nested_attributes_record_not_found!(association_name, record_id) - model = self.class._reflect_on_association(association_name).klass.name - raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}", - model, 'id', record_id) - end + def raise_nested_attributes_record_not_found!(association_name, record_id) + model = self.class._reflect_on_association(association_name).klass.name + raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}", + model, "id", record_id) + end end end diff --git a/activerecord/lib/active_record/no_touching.rb b/activerecord/lib/active_record/no_touching.rb index edb5066fa0..4059020e25 100644 --- a/activerecord/lib/active_record/no_touching.rb +++ b/activerecord/lib/active_record/no_touching.rb @@ -45,6 +45,10 @@ module ActiveRecord NoTouching.applied_to?(self.class) end + def touch_later(*) # :nodoc: + super unless no_touching? + end + def touch(*) # :nodoc: super unless no_touching? end diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb index 1ab4e0404f..254550c378 100644 --- a/activerecord/lib/active_record/null_relation.rb +++ b/activerecord/lib/active_record/null_relation.rb @@ -1,9 +1,5 @@ module ActiveRecord module NullRelation # :nodoc: - def exec_queries - @records = [].freeze - end - def pluck(*column_names) [] end @@ -20,10 +16,6 @@ module ActiveRecord 0 end - def size - calculate :size, nil - end - def empty? true end @@ -48,28 +40,8 @@ module ActiveRecord "" end - def count(*) - calculate :count, nil - end - - def sum(*) - calculate :sum, nil - end - - def average(*) - calculate :average, nil - end - - def minimum(*) - calculate :minimum, nil - end - - def maximum(*) - calculate :maximum, nil - end - def calculate(operation, _column_name) - if [:count, :sum, :size].include? operation + if [:count, :sum].include? operation group_values.any? ? Hash.new : 0 elsif [:average, :minimum, :maximum].include?(operation) && group_values.any? Hash.new @@ -85,5 +57,11 @@ module ActiveRecord def or(other) other.spawn end + + private + + def exec_queries + @records = [].freeze + end end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index afed5e5e85..6933f3f9b8 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -63,10 +63,10 @@ module ActiveRecord # # See <tt>ActiveRecord::Inheritance#discriminate_class_for_record</tt> to see # how this "single-table" inheritance mapping is implemented. - def instantiate(attributes, column_types = {}) + def instantiate(attributes, column_types = {}, &block) klass = discriminate_class_for_record(attributes) attributes = klass.attributes_builder.build_from_database(attributes, column_types) - klass.allocate.init_with('attributes' => attributes, 'new_record' => false) + klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block) end private @@ -107,7 +107,7 @@ module ActiveRecord # # By default, save always runs validations. If any of them fail the action # is cancelled and #save returns +false+, and the record won't be saved. However, if you supply - # validate: false, validations are bypassed altogether. See + # <tt>validate: false</tt>, validations are bypassed altogether. See # ActiveRecord::Validations for more information. # # By default, #save also sets the +updated_at+/+updated_on+ attributes to @@ -134,7 +134,7 @@ module ActiveRecord # # By default, #save! always runs validations. If any of them fail # ActiveRecord::RecordInvalid gets raised, and the record won't be saved. However, if you supply - # validate: false, validations are bypassed altogether. See + # <tt>validate: false</tt>, validations are bypassed altogether. See # ActiveRecord::Validations for more information. # # By default, #save! also sets the +updated_at+/+updated_on+ attributes to @@ -178,7 +178,7 @@ module ActiveRecord # and #destroy returns +false+. # See ActiveRecord::Callbacks for further details. def destroy - raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly? + _raise_readonly_record_error if readonly? destroy_associations self.class.connection.add_transaction_record(self) destroy_row if persisted? @@ -252,7 +252,8 @@ module ActiveRecord name = name.to_s verify_readonly_attribute(name) public_send("#{name}=", value) - save(validate: false) if changed? + + changed? ? save(validate: false) : true end # Updates the attributes of the model from the passed-in hash and saves the @@ -439,7 +440,7 @@ module ActiveRecord self.class.unscoped { self.class.find(id) } end - @attributes = fresh_object.instance_variable_get('@attributes') + @attributes = fresh_object.instance_variable_get("@attributes") @new_record = false self end @@ -479,7 +480,12 @@ module ActiveRecord # ball.touch(:updated_at) # => raises ActiveRecordError # def touch(*names, time: nil) - raise ActiveRecordError, "cannot touch on a new record object" unless persisted? + unless persisted? + raise ActiveRecordError, <<-MSG.squish + cannot touch on a new or destroyed record object. Consider using + persisted?, new_record?, or destroyed? before touching + MSG + end time ||= current_time_from_proper_timezone attributes = timestamp_attributes_for_update_in_model @@ -493,7 +499,6 @@ module ActiveRecord changes[column] = write_attribute(column, time) end - clear_attribute_changes(changes.keys) primary_key = self.class.primary_key scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key)) @@ -503,6 +508,7 @@ module ActiveRecord changes[locking_column] = increment_lock end + clear_attribute_changes(changes.keys) result = scope.update_all(changes) == 1 if !result && locking_enabled? @@ -530,7 +536,7 @@ module ActiveRecord end def create_or_update(*args) - raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly? + _raise_readonly_record_error if readonly? result = new_record? ? _create_record : _update_record(*args) result != false end @@ -572,5 +578,9 @@ module ActiveRecord def belongs_to_touch_method :touch end + + def _raise_readonly_record_error + raise ReadOnlyRecord, "#{self.class} is marked as readonly" + end end end diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index 07d863d15e..c45c8c1697 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -26,28 +26,22 @@ module ActiveRecord def self.run connection = ActiveRecord::Base.connection enabled = connection.query_cache_enabled - connection_id = ActiveRecord::Base.connection_id connection.enable_query_cache! - [enabled, connection_id] + enabled end - def self.complete(state) - enabled, connection_id = state - - ActiveRecord::Base.connection_id = connection_id + def self.complete(enabled) ActiveRecord::Base.connection.clear_query_cache ActiveRecord::Base.connection.disable_query_cache! unless enabled + + unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? + ActiveRecord::Base.clear_active_connections! + end end def self.install_executor_hooks(executor = ActiveSupport::Executor) executor.register_hook(self) - - executor.to_complete do - unless ActiveRecord::Base.connection.transaction_open? - ActiveRecord::Base.clear_active_connections! - end - end end end end diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index 53ddd95bb0..36689f6559 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -9,7 +9,7 @@ module ActiveRecord delegate :find_each, :find_in_batches, :in_batches, to: :all delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or, :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, - :having, :create_with, :uniq, :distinct, :references, :none, :unscope, to: :all + :having, :create_with, :uniq, :distinct, :references, :none, :unscope, :merge, to: :all delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all delegate :pluck, :ids, to: :all @@ -35,7 +35,7 @@ module ActiveRecord # # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date] # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }] - def find_by_sql(sql, binds = [], preparable: nil) + def find_by_sql(sql, binds = [], preparable: nil, &block) result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable) column_types = result_set.column_types.dup columns_hash.each_key { |k| column_types.delete k } @@ -46,8 +46,8 @@ module ActiveRecord class_name: name } - message_bus.instrument('instantiation.active_record', payload) do - result_set.map { |record| instantiate(record, column_types) } + message_bus.instrument("instantiation.active_record", payload) do + result_set.map { |record| instantiate(record, column_types, &block) } end end @@ -62,8 +62,7 @@ module ActiveRecord # # * +sql+ - An SQL statement which should return a count query from the database, see the example above. def count_by_sql(sql) - sql = sanitize_conditions(sql) - connection.select_value(sql, "#{name} Count").to_i + connection.select_value(sanitize_sql(sql), "#{name} Count").to_i end end end diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 98ea425d16..989d23bc37 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -3,7 +3,7 @@ require "rails" require "active_model/railtie" # For now, action_controller must always be present with -# rails, so let's make sure that it gets required before +# Rails, so let's make sure that it gets required before # here. This is needed for correctly setting up the middleware. # In the future, this might become an optional require. require "action_controller/railtie" @@ -13,17 +13,16 @@ module ActiveRecord class Railtie < Rails::Railtie # :nodoc: config.active_record = ActiveSupport::OrderedOptions.new - config.app_generators.orm :active_record, :migration => true, - :timestamps => true + config.app_generators.orm :active_record, migration: true, + timestamps: true config.action_dispatch.rescue_responses.merge!( - 'ActiveRecord::RecordNotFound' => :not_found, - 'ActiveRecord::StaleObjectError' => :conflict, - 'ActiveRecord::RecordInvalid' => :unprocessable_entity, - 'ActiveRecord::RecordNotSaved' => :unprocessable_entity + "ActiveRecord::RecordNotFound" => :not_found, + "ActiveRecord::StaleObjectError" => :conflict, + "ActiveRecord::RecordInvalid" => :unprocessable_entity, + "ActiveRecord::RecordNotSaved" => :unprocessable_entity ) - config.active_record.use_schema_cache_dump = true config.active_record.maintain_test_schema = true @@ -35,8 +34,8 @@ module ActiveRecord ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration if defined?(ENGINE_ROOT) && engine = Rails::Engine.find(ENGINE_ROOT) - if engine.paths['db/migrate'].existent - ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a + if engine.paths["db/migrate"].existent + ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths["db/migrate"].to_a end end end @@ -102,7 +101,7 @@ module ActiveRecord initializer "active_record.warn_on_records_fetched_greater_than" do if config.active_record.warn_on_records_fetched_greater_than ActiveSupport.on_load(:active_record) do - require 'active_record/relation/record_fetch_warning' + require "active_record/relation/record_fetch_warning" end end end diff --git a/activerecord/lib/active_record/railties/controller_runtime.rb b/activerecord/lib/active_record/railties/controller_runtime.rb index 8727e46cb3..adb3c6c4e6 100644 --- a/activerecord/lib/active_record/railties/controller_runtime.rb +++ b/activerecord/lib/active_record/railties/controller_runtime.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module/attr_internal' -require 'active_record/log_subscriber' +require "active_support/core_ext/module/attr_internal" +require "active_record/log_subscriber" module ActiveRecord module Railties # :nodoc: @@ -19,7 +19,7 @@ module ActiveRecord end def cleanup_view_runtime - if logger.info? && ActiveRecord::Base.connected? + if logger && logger.info? && ActiveRecord::Base.connected? db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime self.db_runtime = (db_runtime || 0) + db_rt_before_render runtime = super diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index fc1b62ee96..46235ab922 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -1,4 +1,4 @@ -require 'active_record' +require "active_record" db_namespace = namespace :db do desc "Set the environment value for the database" @@ -7,7 +7,7 @@ db_namespace = namespace :db do ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment end - task :check_protected_environments => [:environment, :load_config] do + task check_protected_environments: [:environment, :load_config] do ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! end @@ -17,24 +17,24 @@ db_namespace = namespace :db do end namespace :create do - task :all => :load_config do + task all: :load_config do ActiveRecord::Tasks::DatabaseTasks.create_all end end - desc 'Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to creating the development and test databases.' - task :create => [:load_config] do + desc "Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to creating the development and test databases." + task create: [:load_config] do ActiveRecord::Tasks::DatabaseTasks.create_current end namespace :drop do - task :all => [:load_config, :check_protected_environments] do + task all: [:load_config, :check_protected_environments] do ActiveRecord::Tasks::DatabaseTasks.drop_all end end - desc 'Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to dropping the development and test databases.' - task :drop => [:load_config, :check_protected_environments] do + desc "Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to dropping the development and test databases." + task drop: [:load_config, :check_protected_environments] do db_namespace["drop:_unsafe"].invoke end @@ -43,20 +43,20 @@ db_namespace = namespace :db do end namespace :purge do - task :all => [:load_config, :check_protected_environments] do + task all: [:load_config, :check_protected_environments] do ActiveRecord::Tasks::DatabaseTasks.purge_all end end # desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:purge:all to purge all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases." - task :purge => [:load_config, :check_protected_environments] do + task purge: [:load_config, :check_protected_environments] do ActiveRecord::Tasks::DatabaseTasks.purge_current end desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)." - task :migrate => [:environment, :load_config] do + task migrate: [:environment, :load_config] do ActiveRecord::Tasks::DatabaseTasks.migrate - db_namespace['_dump'].invoke + db_namespace["_dump"].invoke end # IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false @@ -71,44 +71,44 @@ db_namespace = namespace :db do end # Allow this task to be called as many times as required. An example is the # migrate:redo task, which calls other two internally that depend on this one. - db_namespace['_dump'].reenable + db_namespace["_dump"].reenable end namespace :migrate do # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).' - task :redo => [:environment, :load_config] do - if ENV['VERSION'] - db_namespace['migrate:down'].invoke - db_namespace['migrate:up'].invoke + task redo: [:environment, :load_config] do + if ENV["VERSION"] + db_namespace["migrate:down"].invoke + db_namespace["migrate:up"].invoke else - db_namespace['rollback'].invoke - db_namespace['migrate'].invoke + db_namespace["rollback"].invoke + db_namespace["migrate"].invoke end end # desc 'Resets your database using your migrations for the current environment' - task :reset => ['db:drop', 'db:create', 'db:migrate'] + task reset: ["db:drop", "db:create", "db:migrate"] # desc 'Runs the "up" for a given migration VERSION.' - task :up => [:environment, :load_config] do - version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil - raise 'VERSION is required' unless version + task up: [:environment, :load_config] do + version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil + raise "VERSION is required" unless version ActiveRecord::Migrator.run(:up, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version) - db_namespace['_dump'].invoke + db_namespace["_dump"].invoke end # desc 'Runs the "down" for a given migration VERSION.' - task :down => [:environment, :load_config] do - version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil - raise 'VERSION is required - To go down one migration, run db:rollback' unless version + task down: [:environment, :load_config] do + version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil + raise "VERSION is required - To go down one migration, run db:rollback" unless version ActiveRecord::Migrator.run(:down, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version) - db_namespace['_dump'].invoke + db_namespace["_dump"].invoke end - desc 'Display status of migrations' - task :status => [:environment, :load_config] do + desc "Display status of migrations" + task status: [:environment, :load_config] do unless ActiveRecord::SchemaMigration.table_exists? - abort 'Schema migrations table does not exist yet.' + abort "Schema migrations table does not exist yet." end db_list = ActiveRecord::SchemaMigration.normalized_versions @@ -119,13 +119,13 @@ db_namespace = namespace :db do version, name, scope = ActiveRecord::Migrator.parse_migration_filename(file) version = ActiveRecord::SchemaMigration.normalize_migration_number(version) - status = db_list.delete(version) ? 'up' : 'down' + status = db_list.delete(version) ? "up" : "down" [status, version, (name + scope).humanize] end.compact end db_list.map! do |version| - ['up', version, '********** NO FILE **********'] + ["up", version, "********** NO FILE **********"] end # output puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n" @@ -138,93 +138,93 @@ db_namespace = namespace :db do end end - desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).' - task :rollback => [:environment, :load_config] do - step = ENV['STEP'] ? ENV['STEP'].to_i : 1 + desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)." + task rollback: [:environment, :load_config] do + step = ENV["STEP"] ? ENV["STEP"].to_i : 1 ActiveRecord::Migrator.rollback(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step) - db_namespace['_dump'].invoke + db_namespace["_dump"].invoke end # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).' - task :forward => [:environment, :load_config] do - step = ENV['STEP'] ? ENV['STEP'].to_i : 1 + task forward: [:environment, :load_config] do + step = ENV["STEP"] ? ENV["STEP"].to_i : 1 ActiveRecord::Migrator.forward(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step) - db_namespace['_dump'].invoke + db_namespace["_dump"].invoke end # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.' - task :reset => [ 'db:drop', 'db:setup' ] + task reset: [ "db:drop", "db:setup" ] # desc "Retrieves the charset for the current environment's database" - task :charset => [:environment, :load_config] do + task charset: [:environment, :load_config] do puts ActiveRecord::Tasks::DatabaseTasks.charset_current end # desc "Retrieves the collation for the current environment's database" - task :collation => [:environment, :load_config] do + task collation: [:environment, :load_config] do begin puts ActiveRecord::Tasks::DatabaseTasks.collation_current rescue NoMethodError - $stderr.puts 'Sorry, your database adapter is not supported yet. Feel free to submit a patch.' + $stderr.puts "Sorry, your database adapter is not supported yet. Feel free to submit a patch." end end - desc 'Retrieves the current schema version number' - task :version => [:environment, :load_config] do + desc "Retrieves the current schema version number" + task version: [:environment, :load_config] do puts "Current version: #{ActiveRecord::Migrator.current_version}" end # desc "Raises an error if there are pending migrations" - task :abort_if_pending_migrations => [:environment, :load_config] do + task abort_if_pending_migrations: [:environment, :load_config] do pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Tasks::DatabaseTasks.migrations_paths).pending_migrations if pending_migrations.any? puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}" pending_migrations.each do |pending_migration| - puts ' %4d %s' % [pending_migration.version, pending_migration.name] + puts " %4d %s" % [pending_migration.version, pending_migration.name] end abort %{Run `rails db:migrate` to update your database then try again.} end end - desc 'Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)' - task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed] + desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)" + task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed] - desc 'Loads the seed data from db/seeds.rb' + desc "Loads the seed data from db/seeds.rb" task :seed do - db_namespace['abort_if_pending_migrations'].invoke + db_namespace["abort_if_pending_migrations"].invoke ActiveRecord::Tasks::DatabaseTasks.load_seed end namespace :fixtures do desc "Loads fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures." - task :load => [:environment, :load_config] do - require 'active_record/fixtures' + task load: [:environment, :load_config] do + require "active_record/fixtures" base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path - fixtures_dir = if ENV['FIXTURES_DIR'] - File.join base_dir, ENV['FIXTURES_DIR'] - else - base_dir - end + fixtures_dir = if ENV["FIXTURES_DIR"] + File.join base_dir, ENV["FIXTURES_DIR"] + else + base_dir + end - fixture_files = if ENV['FIXTURES'] - ENV['FIXTURES'].split(',') - else - # The use of String#[] here is to support namespaced fixtures - Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] } - end + fixture_files = if ENV["FIXTURES"] + ENV["FIXTURES"].split(",") + else + # The use of String#[] here is to support namespaced fixtures. + Dir["#{fixtures_dir}/**/*.yml"].map { |f| f[(fixtures_dir.size + 1)..-5] } + end ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files) end # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures." - task :identify => [:environment, :load_config] do - require 'active_record/fixtures' + task identify: [:environment, :load_config] do + require "active_record/fixtures" - label, id = ENV['LABEL'], ENV['ID'] - raise 'LABEL or ID required' if label.blank? && id.blank? + label, id = ENV["LABEL"], ENV["ID"] + raise "LABEL or ID required" if label.blank? && id.blank? puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label @@ -245,38 +245,38 @@ db_namespace = namespace :db do end namespace :schema do - desc 'Creates a db/schema.rb file that is portable against any DB supported by Active Record' - task :dump => [:environment, :load_config] do - require 'active_record/schema_dumper' - filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb') + desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record" + task dump: [:environment, :load_config] do + require "active_record/schema_dumper" + filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema.rb") File.open(filename, "w:utf-8") do |file| ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file) end - db_namespace['schema:dump'].reenable + db_namespace["schema:dump"].reenable end - desc 'Loads a schema.rb file into the database' - task :load => [:environment, :load_config, :check_protected_environments] do - ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA']) + desc "Loads a schema.rb file into the database" + task load: [:environment, :load_config, :check_protected_environments] do + ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV["SCHEMA"]) end - task :load_if_ruby => ['db:create', :environment] do + task load_if_ruby: ["db:create", :environment] do db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby end namespace :cache do - desc 'Creates a db/schema_cache.dump file.' - task :dump => [:environment, :load_config] do + desc "Creates a db/schema_cache.dump file." + task dump: [:environment, :load_config] do con = ActiveRecord::Base.connection filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump") con.schema_cache.clear! con.data_sources.each { |table| con.schema_cache.add(table) } - open(filename, 'wb') { |f| f.write(Marshal.dump(con.schema_cache)) } + open(filename, "wb") { |f| f.write(Marshal.dump(con.schema_cache)) } end - desc 'Clears a db/schema_cache.dump file.' - task :clear => [:environment, :load_config] do + desc "Clears a db/schema_cache.dump file." + task clear: [:environment, :load_config] do filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump") rm_f filename, verbose: false end @@ -285,9 +285,9 @@ db_namespace = namespace :db do end namespace :structure do - desc 'Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql' - task :dump => [:environment, :load_config] do - filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql") + desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql" + task dump: [:environment, :load_config] do + filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql") current_config = ActiveRecord::Tasks::DatabaseTasks.current_config ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename) @@ -298,15 +298,15 @@ db_namespace = namespace :db do f.print "\n" end end - db_namespace['structure:dump'].reenable + db_namespace["structure:dump"].reenable end desc "Recreates the databases from the structure.sql file" - task :load => [:environment, :load_config, :check_protected_environments] do - ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['SCHEMA']) + task load: [:environment, :load_config, :check_protected_environments] do + ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV["SCHEMA"]) end - task :load_if_sql => ['db:create', :environment] do + task load_if_sql: ["db:create", :environment] do db_namespace["structure:load"].invoke if ActiveRecord::Base.schema_format == :sql end end @@ -321,21 +321,21 @@ db_namespace = namespace :db do end # desc "Recreate the test database from the current schema" - task :load => %w(db:test:purge) do + task load: %w(db:test:purge) do case ActiveRecord::Base.schema_format - when :ruby - db_namespace["test:load_schema"].invoke - when :sql - db_namespace["test:load_structure"].invoke + when :ruby + db_namespace["test:load_schema"].invoke + when :sql + db_namespace["test:load_structure"].invoke end end # desc "Recreate the test database from an existent schema.rb file" - task :load_schema => %w(db:test:purge) do + task load_schema: %w(db:test:purge) do begin should_reconnect = ActiveRecord::Base.connection_pool.active_connection? ActiveRecord::Schema.verbose = false - ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA'] + ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :ruby, ENV["SCHEMA"] ensure if should_reconnect ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env]) @@ -344,35 +344,35 @@ db_namespace = namespace :db do end # desc "Recreate the test database from an existent structure.sql file" - task :load_structure => %w(db:test:purge) do - ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA'] + task load_structure: %w(db:test:purge) do + ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :sql, ENV["SCHEMA"] end # desc "Recreate the test database from a fresh schema" - task :clone => %w(db:test:deprecated environment) do + task clone: %w(db:test:deprecated environment) do case ActiveRecord::Base.schema_format - when :ruby - db_namespace["test:clone_schema"].invoke - when :sql - db_namespace["test:clone_structure"].invoke + when :ruby + db_namespace["test:clone_schema"].invoke + when :sql + db_namespace["test:clone_structure"].invoke end end # desc "Recreate the test database from a fresh schema.rb file" - task :clone_schema => %w(db:test:deprecated db:schema:dump db:test:load_schema) + task clone_schema: %w(db:test:deprecated db:schema:dump db:test:load_schema) # desc "Recreate the test database from a fresh structure.sql file" - task :clone_structure => %w(db:test:deprecated db:structure:dump db:test:load_structure) + task clone_structure: %w(db:test:deprecated db:structure:dump db:test:load_structure) # desc "Empty the test database" - task :purge => %w(environment load_config check_protected_environments) do - ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test'] + task purge: %w(environment load_config check_protected_environments) do + ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations["test"] end # desc 'Load the test schema' - task :prepare => %w(environment load_config) do + task prepare: %w(environment load_config) do unless ActiveRecord::Base.configurations.blank? - db_namespace['test:load'].invoke + db_namespace["test:load"].invoke end end end @@ -381,13 +381,13 @@ end namespace :railties do namespace :install do # desc "Copies missing migrations from Railties (e.g. engines). You can specify Railties to use with FROM=railtie1,railtie2" - task :migrations => :'db:load_config' do - to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map(&:strip) + task migrations: :'db:load_config' do + to_load = ENV["FROM"].blank? ? :all : ENV["FROM"].split(",").map(&:strip) railties = {} Rails.application.migration_railties.each do |railtie| next unless to_load == :all || to_load.include?(railtie.railtie_name) - if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first) + if railtie.respond_to?(:paths) && (path = railtie.paths["db/migrate"].first) railties[railtie.railtie_name] = path end end @@ -401,7 +401,7 @@ namespace :railties do end ActiveRecord::Migration.copy(ActiveRecord::Tasks::DatabaseTasks.migrations_paths.first, railties, - :on_skip => on_skip, :on_copy => on_copy) + on_skip: on_skip, on_copy: on_copy) end end end diff --git a/activerecord/lib/active_record/railties/jdbcmysql_error.rb b/activerecord/lib/active_record/railties/jdbcmysql_error.rb index 6a38211bff..d7cf4df339 100644 --- a/activerecord/lib/active_record/railties/jdbcmysql_error.rb +++ b/activerecord/lib/active_record/railties/jdbcmysql_error.rb @@ -3,7 +3,7 @@ module ArJdbcMySQL #:nodoc: class Error < StandardError #:nodoc: attr_accessor :error_number, :sql_state - def initialize msg + def initialize(msg) super @error_number = nil @sql_state = nil diff --git a/activerecord/lib/active_record/readonly_attributes.rb b/activerecord/lib/active_record/readonly_attributes.rb index ce78f1756d..8ff265bdfa 100644 --- a/activerecord/lib/active_record/readonly_attributes.rb +++ b/activerecord/lib/active_record/readonly_attributes.rb @@ -16,7 +16,7 @@ module ActiveRecord # Returns an array of all the attributes that have been specified as readonly. def readonly_attributes - self._attr_readonly + _attr_readonly end end end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 6684283f03..ce70c29093 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -1,5 +1,5 @@ -require 'thread' -require 'active_support/core_ext/string/filters' +require "thread" +require "active_support/core_ext/string/filters" module ActiveRecord # = Active Record Reflection @@ -14,18 +14,19 @@ module ActiveRecord end def self.create(macro, name, scope, options, ar) - klass = case macro - when :composed_of - AggregateReflection - when :has_many - HasManyReflection - when :has_one - HasOneReflection - when :belongs_to - BelongsToReflection - else - raise "Unsupported Macro: #{macro}" - end + klass = \ + case macro + when :composed_of + AggregateReflection + when :has_many + HasManyReflection + when :has_one + HasOneReflection + when :belongs_to + BelongsToReflection + else + raise "Unsupported Macro: #{macro}" + end reflection = klass.new(name, scope, options, ar) options[:through] ? ThroughReflection.new(reflection) : reflection @@ -281,6 +282,10 @@ module ActiveRecord end def autosave=(autosave) + # autosave and inverse_of do not get along together nowadays. They may + # for example cause double saves. Thus, we disable this flag. If in the + # future those two flags are known to work well together, this could be + # removed. @automatic_inverse_of = false @options[:autosave] = autosave parent_reflection = self.parent_reflection @@ -311,13 +316,16 @@ module ActiveRecord active_record == other_aggregation.active_record end + def scope_for(klass) + scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped + end + private def derive_class_name name.to_s.camelize end end - # Holds all the meta-data about an aggregation as it was specified in the # Active Record class. class AggregateReflection < MacroReflection #:nodoc: @@ -700,7 +708,7 @@ module ActiveRecord class ThroughReflection < AbstractReflection #:nodoc: attr_reader :delegate_reflection delegate :foreign_key, :foreign_type, :association_foreign_key, - :active_record_primary_key, :type, :to => :source_reflection + :active_record_primary_key, :type, to: :source_reflection def initialize(delegate_reflection) @delegate_reflection = delegate_reflection @@ -978,7 +986,6 @@ module ActiveRecord public_instance_methods delegate(*delegate_methods, to: :delegate_reflection) - end class PolymorphicReflection < AbstractReflection # :nodoc: diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 7a1552856b..ef629dcb3b 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -1,5 +1,3 @@ -require "arel/collectors/bind" - module ActiveRecord # = Active Record \Relation class Relation @@ -31,9 +29,7 @@ module ActiveRecord end def initialize_copy(other) - # This method is a hot spot, so for now, use Hash[] to dup the hash. - # https://bugs.ruby-lang.org/issues/7166 - @values = Hash[@values] + @values = @values.dup reset end @@ -64,8 +60,8 @@ module ActiveRecord @klass.connection.insert( im, - 'SQL', - primary_key, + "SQL", + primary_key || false, primary_key_value, nil, binds) @@ -88,7 +84,7 @@ module ActiveRecord @klass.connection.update( um, - 'SQL', + "SQL", bvs, ) end @@ -247,7 +243,6 @@ module ActiveRecord # Please see further details in the # {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain]. def explain - #TODO: Fix for binds. exec_explain(collecting_queries_for_explain { exec_queries }) end @@ -384,7 +379,7 @@ module ActiveRecord stmt.wheres = arel.constraints end - @klass.connection.update stmt, 'SQL', bound_attributes + @klass.connection.update stmt, "SQL", bound_attributes end # Updates an object (or multiple objects) and saves it to the database, if validations pass. @@ -506,15 +501,10 @@ module ActiveRecord # Post.limit(100).delete_all # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit def delete_all(conditions = nil) - invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method| - if MULTI_VALUE_METHODS.include?(method) - send("#{method}_values").any? - elsif SINGLE_VALUE_METHODS.include?(method) - send("#{method}_value") - elsif CLAUSE_METHODS.include?(method) - send("#{method}_clause").any? - end - } + invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method| + value = get_value(method) + SINGLE_VALUE_METHODS.include?(method) ? value : value.any? + end if invalid_methods.any? raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}") end @@ -535,7 +525,7 @@ module ActiveRecord stmt.wheres = arel.constraints end - affected = @klass.connection.delete(stmt, 'SQL', bound_attributes) + affected = @klass.connection.delete(stmt, "SQL", bound_attributes) reset affected @@ -571,8 +561,8 @@ module ActiveRecord # return value is the relation itself, not the records. # # Post.where(published: true).load # => #<ActiveRecord::Relation> - def load - exec_queries unless loaded? + def load(&block) + exec_queries(&block) unless loaded? self end @@ -597,19 +587,16 @@ module ActiveRecord # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar' def to_sql @to_sql ||= begin - relation = self - connection = klass.connection - visitor = connection.visitor + relation = self if eager_loading? find_with_associations { |rel| relation = rel } end - binds = relation.bound_attributes - binds = connection.prepare_binds_for_database(binds) - binds.map! { |value| connection.quote(value) } - collect = visitor.accept(relation.arel.ast, Arel::Collectors::Bind.new) - collect.substitute_binds(binds).join + conn = klass.connection + conn.unprepared_statement { + conn.to_sql(relation.arel, relation.bound_attributes) + } end end @@ -662,7 +649,7 @@ module ActiveRecord end def pretty_print(q) - q.pp(self.records) + q.pp(records) end # Returns true if relation is blank. @@ -671,12 +658,12 @@ module ActiveRecord end def values - Hash[@values] + @values.dup end def inspect entries = records.take([limit_value, 11].compact.min).map!(&:inspect) - entries[10] = '...' if entries.size == 11 + entries[10] = "..." if entries.size == 11 "#<#{self.class.name} [#{entries.join(', ')}]>" end @@ -690,48 +677,48 @@ module ActiveRecord private - def exec_queries - @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze + def exec_queries(&block) + @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze - preload = preload_values - preload += includes_values unless eager_loading? - preloader = build_preloader - preload.each do |associations| - preloader.preload @records, associations - end + preload = preload_values + preload += includes_values unless eager_loading? + preloader = build_preloader + preload.each do |associations| + preloader.preload @records, associations + end - @records.each(&:readonly!) if readonly_value + @records.each(&:readonly!) if readonly_value - @loaded = true - @records - end + @loaded = true + @records + end - def build_preloader - ActiveRecord::Associations::Preloader.new - end + def build_preloader + ActiveRecord::Associations::Preloader.new + end - def references_eager_loaded_tables? - joined_tables = arel.join_sources.map do |join| - if join.is_a?(Arel::Nodes::StringJoin) - tables_in_string(join.left) - else - [join.left.table_name, join.left.table_alias] + def references_eager_loaded_tables? + joined_tables = arel.join_sources.map do |join| + if join.is_a?(Arel::Nodes::StringJoin) + tables_in_string(join.left) + else + [join.left.table_name, join.left.table_alias] + end end - end - joined_tables += [table.name, table.table_alias] + joined_tables += [table.name, table.table_alias] - # always convert table names to downcase as in Oracle quoted table names are in uppercase - joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq + # always convert table names to downcase as in Oracle quoted table names are in uppercase + joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq - (references_values - joined_tables).any? - end + (references_values - joined_tables).any? + end - def tables_in_string(string) - return [] if string.blank? - # always convert table names to downcase as in Oracle quoted table names are in uppercase - # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries - string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ['raw_sql_'] - end + def tables_in_string(string) + return [] if string.blank? + # always convert table names to downcase as in Oracle quoted table names are in uppercase + # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries + string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"] + end end end diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index 3639625722..4b2987ac6d 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -2,7 +2,7 @@ require "active_record/relation/batches/batch_enumerator" module ActiveRecord module Batches - ORDER_OR_LIMIT_IGNORED_MESSAGE = "Scoped order and limit are ignored, it's forced to be batch order and batch size." + ORDER_IGNORE_MESSAGE = "Scoped order is ignored, it's forced to be batch order." # Looping through a collection of records from the database # (using the Scoping::Named::ClassMethods.all method, for example) @@ -34,15 +34,19 @@ module ActiveRecord # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value. # * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value. # * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when - # the order and limit have to be ignored due to batching. + # an order is present in the relation. # - # This is especially useful if you want multiple workers dealing with - # the same processing queue. You can make worker 1 handle all the records - # between id 0 and 10,000 and worker 2 handle from 10,000 and beyond - # (by setting the +:start+ and +:finish+ option on each worker). + # Limits are honored, and if present there is no requirement for the batch + # size, it can be less than, equal, or greater than the limit. # - # # Let's process for a batch of 2000 records, skipping the first 2000 rows - # Person.find_each(start: 2000, batch_size: 2000) do |person| + # The options +start+ and +finish+ are especially useful if you want + # multiple workers dealing with the same processing queue. You can make + # worker 1 handle all the records between id 1 and 9999 and worker 2 + # handle from 10000 and beyond by setting the +:start+ and +:finish+ + # option on each worker. + # + # # Let's process from record 10_000 on. + # Person.find_each(start: 10_000) do |person| # person.party_all_night! # end # @@ -51,8 +55,8 @@ module ActiveRecord # work. This also means that this method only works when the primary key is # orderable (e.g. an integer or string). # - # NOTE: You can't set the limit either, that's used to control - # the batch sizes. + # NOTE: By its nature, batch processing is subject to race conditions if + # other processes are modifying the database. def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil) if block_given? find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do |records| @@ -89,15 +93,19 @@ module ActiveRecord # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value. # * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value. # * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when - # the order and limit have to be ignored due to batching. + # an order is present in the relation. + # + # Limits are honored, and if present there is no requirement for the batch + # size, it can be less than, equal, or greater than the limit. # - # This is especially useful if you want multiple workers dealing with - # the same processing queue. You can make worker 1 handle all the records - # between id 0 and 10,000 and worker 2 handle from 10,000 and beyond - # (by setting the +:start+ and +:finish+ option on each worker). + # The options +start+ and +finish+ are especially useful if you want + # multiple workers dealing with the same processing queue. You can make + # worker 1 handle all the records between id 1 and 9999 and worker 2 + # handle from 10000 and beyond by setting the +:start+ and +:finish+ + # option on each worker. # - # # Let's process the next 2000 records - # Person.find_in_batches(start: 2000, batch_size: 2000) do |group| + # # Let's process from record 10_000 on. + # Person.find_in_batches(start: 10_000) do |group| # group.each { |person| person.party_all_night! } # end # @@ -106,8 +114,8 @@ module ActiveRecord # work. This also means that this method only works when the primary key is # orderable (e.g. an integer or string). # - # NOTE: You can't set the limit either, that's used to control - # the batch sizes. + # NOTE: By its nature, batch processing is subject to race conditions if + # other processes are modifying the database. def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil) relation = self unless block_given? @@ -149,17 +157,19 @@ module ActiveRecord # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value. # * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value. # * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when - # the order and limit have to be ignored due to batching. + # an order is present in the relation. # - # This is especially useful if you want to work with the - # ActiveRecord::Relation object instead of the array of records, or if - # you want multiple workers dealing with the same processing queue. You can - # make worker 1 handle all the records between id 0 and 10,000 and worker 2 - # handle from 10,000 and beyond (by setting the +:start+ and +:finish+ - # option on each worker). + # Limits are honored, and if present there is no requirement for the batch + # size, it can be less than, equal, or greater than the limit. # - # # Let's process the next 2000 records - # Person.in_batches(of: 2000, start: 2000).update_all(awesome: true) + # The options +start+ and +finish+ are especially useful if you want + # multiple workers dealing with the same processing queue. You can make + # worker 1 handle all the records between id 1 and 9999 and worker 2 + # handle from 10000 and beyond by setting the +:start+ and +:finish+ + # option on each worker. + # + # # Let's process from record 10_000 on. + # Person.in_batches(start: 10_000).update_all(awesome: true) # # An example of calling where query method on the relation: # @@ -179,19 +189,25 @@ module ActiveRecord # consistent. Therefore the primary key must be orderable, e.g an integer # or a string. # - # NOTE: You can't set the limit either, that's used to control the batch - # sizes. + # NOTE: By its nature, batch processing is subject to race conditions if + # other processes are modifying the database. def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil) relation = self unless block_given? return BatchEnumerator.new(of: of, start: start, finish: finish, relation: self) end - if arel.orders.present? || arel.taken.present? - act_on_order_or_limit_ignored(error_on_ignore) + if arel.orders.present? + act_on_ignored_order(error_on_ignore) + end + + batch_limit = of + if limit_value + remaining = limit_value + batch_limit = remaining if remaining < batch_limit end - relation = relation.reorder(batch_order).limit(of) + relation = relation.reorder(batch_order).limit(batch_limit) relation = apply_limits(relation, start, finish) batch_relation = relation @@ -199,11 +215,11 @@ module ActiveRecord if load records = batch_relation.records ids = records.map(&:id) - yielded_relation = self.where(primary_key => ids) + yielded_relation = where(primary_key => ids) yielded_relation.load_records(records) else ids = batch_relation.pluck(primary_key) - yielded_relation = self.where(primary_key => ids) + yielded_relation = where(primary_key => ids) end break if ids.empty? @@ -213,31 +229,44 @@ module ActiveRecord yield yielded_relation - break if ids.length < of + break if ids.length < batch_limit + + if limit_value + remaining -= ids.length + + if remaining == 0 + # Saves a useless iteration when the limit is a multiple of the + # batch size. + break + elsif remaining < batch_limit + relation = relation.limit(remaining) + end + end + batch_relation = relation.where(arel_attribute(primary_key).gt(primary_key_offset)) end end private - def apply_limits(relation, start, finish) - relation = relation.where(arel_attribute(primary_key).gteq(start)) if start - relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish - relation - end + def apply_limits(relation, start, finish) + relation = relation.where(arel_attribute(primary_key).gteq(start)) if start + relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish + relation + end - def batch_order - "#{quoted_table_name}.#{quoted_primary_key} ASC" - end + def batch_order + "#{quoted_table_name}.#{quoted_primary_key} ASC" + end - def act_on_order_or_limit_ignored(error_on_ignore) - raise_error = (error_on_ignore.nil? ? self.klass.error_on_ignored_order_or_limit : error_on_ignore) + def act_on_ignored_order(error_on_ignore) + raise_error = (error_on_ignore.nil? ? self.klass.error_on_ignored_order : error_on_ignore) - if raise_error - raise ArgumentError.new(ORDER_OR_LIMIT_IGNORED_MESSAGE) - elsif logger - logger.warn(ORDER_OR_LIMIT_IGNORED_MESSAGE) + if raise_error + raise ArgumentError.new(ORDER_IGNORE_MESSAGE) + elsif logger + logger.warn(ORDER_IGNORE_MESSAGE) + end end - end end end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index d6d92b8607..e4676f79a5 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -112,12 +112,11 @@ module ActiveRecord # ... # end def calculate(operation, column_name) - if column_name.is_a?(Symbol) && attribute_alias?(column_name) - column_name = attribute_alias(column_name) - end - if has_include?(column_name) - construct_relation_for_association_calculations.calculate(operation, column_name) + relation = construct_relation_for_association_calculations + relation = relation.distinct if operation.to_s.downcase == "count" + + relation.calculate(operation, column_name) else perform_calculation(operation, column_name) end @@ -160,7 +159,7 @@ module ActiveRecord # def pluck(*column_names) if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty? - return @records.pluck(*column_names) + return records.pluck(*column_names) end if has_include?(column_names.first) @@ -185,201 +184,196 @@ module ActiveRecord private - def has_include?(column_name) - eager_loading? || (includes_values.present? && column_name && column_name != :all) - end - - def perform_calculation(operation, column_name) - operation = operation.to_s.downcase + def has_include?(column_name) + eager_loading? || (includes_values.present? && column_name && column_name != :all) + end - # If #count is used with #distinct (i.e. `relation.distinct.count`) it is - # considered distinct. - distinct = self.distinct_value + def perform_calculation(operation, column_name) + operation = operation.to_s.downcase - if operation == "count" - column_name ||= select_for_count + # If #count is used with #distinct (i.e. `relation.distinct.count`) it is + # considered distinct. + distinct = self.distinct_value - unless arel.ast.grep(Arel::Nodes::OuterJoin).empty? - distinct = true + if operation == "count" + column_name ||= select_for_count + column_name = primary_key if column_name == :all && distinct + distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i end - column_name = primary_key if column_name == :all && distinct - distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i - end - - if group_values.any? - execute_grouped_calculation(operation, column_name, distinct) - else - execute_simple_calculation(operation, column_name, distinct) + if group_values.any? + execute_grouped_calculation(operation, column_name, distinct) + else + execute_simple_calculation(operation, column_name, distinct) + end end - end - def aggregate_column(column_name) - return column_name if Arel::Expressions === column_name + def aggregate_column(column_name) + return column_name if Arel::Expressions === column_name - if @klass.column_names.include?(column_name.to_s) - Arel::Attribute.new(@klass.unscoped.table, column_name) - else - Arel.sql(column_name == :all ? "*" : column_name.to_s) + if @klass.has_attribute?(column_name.to_s) || @klass.attribute_alias?(column_name.to_s) + @klass.arel_attribute(column_name) + else + Arel.sql(column_name == :all ? "*" : column_name.to_s) + end end - end - - def operation_over_aggregate_column(column, operation, distinct) - operation == 'count' ? column.count(distinct) : column.send(operation) - end - def execute_simple_calculation(operation, column_name, distinct) #:nodoc: - # PostgreSQL doesn't like ORDER BY when there are no GROUP BY - relation = unscope(:order) - - column_alias = column_name + def operation_over_aggregate_column(column, operation, distinct) + operation == "count" ? column.count(distinct) : column.send(operation) + end - if operation == "count" && (relation.limit_value || relation.offset_value) - # Shortcut when limit is zero. - return 0 if relation.limit_value == 0 + def execute_simple_calculation(operation, column_name, distinct) #:nodoc: + # PostgreSQL doesn't like ORDER BY when there are no GROUP BY + relation = unscope(:order) - query_builder = build_count_subquery(relation, column_name, distinct) - else - column = aggregate_column(column_name) + column_alias = column_name - select_value = operation_over_aggregate_column(column, operation, distinct) + if operation == "count" && (relation.limit_value || relation.offset_value) + # Shortcut when limit is zero. + return 0 if relation.limit_value == 0 - column_alias = select_value.alias - column_alias ||= @klass.connection.column_name_for_operation(operation, select_value) - relation.select_values = [select_value] + query_builder = build_count_subquery(relation, column_name, distinct) + else + column = aggregate_column(column_name) - query_builder = relation.arel - end + select_value = operation_over_aggregate_column(column, operation, distinct) - result = @klass.connection.select_all(query_builder, nil, bound_attributes) - row = result.first - value = row && row.values.first - column = result.column_types.fetch(column_alias) do - type_for(column_name) - end + column_alias = select_value.alias + column_alias ||= @klass.connection.column_name_for_operation(operation, select_value) + relation.select_values = [select_value] - type_cast_calculated_value(value, column, operation) - end + query_builder = relation.arel + end - def execute_grouped_calculation(operation, column_name, distinct) #:nodoc: - group_attrs = group_values + result = @klass.connection.select_all(query_builder, nil, bound_attributes) + row = result.first + value = row && row.values.first + type = result.column_types.fetch(column_alias) do + type_for(column_name) + end - if group_attrs.first.respond_to?(:to_sym) - association = @klass._reflect_on_association(group_attrs.first) - associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations - group_fields = Array(associated ? association.foreign_key : group_attrs) - else - group_fields = group_attrs + type_cast_calculated_value(value, type, operation) end - group_fields = arel_columns(group_fields) - - group_aliases = group_fields.map { |field| column_alias_for(field) } - group_columns = group_aliases.zip(group_fields) - if operation == 'count' && column_name == :all - aggregate_alias = 'count_all' - else - aggregate_alias = column_alias_for([operation, column_name].join(' ')) - end + def execute_grouped_calculation(operation, column_name, distinct) #:nodoc: + group_attrs = group_values - select_values = [ - operation_over_aggregate_column( - aggregate_column(column_name), - operation, - distinct).as(aggregate_alias) - ] - select_values += select_values unless having_clause.empty? - - select_values.concat group_columns.map { |aliaz, field| - if field.respond_to?(:as) - field.as(aliaz) + if group_attrs.first.respond_to?(:to_sym) + association = @klass._reflect_on_association(group_attrs.first) + associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations + group_fields = Array(associated ? association.foreign_key : group_attrs) else - "#{field} AS #{aliaz}" + group_fields = group_attrs end - } + group_fields = arel_columns(group_fields) - relation = except(:group) - relation.group_values = group_fields - relation.select_values = select_values + group_aliases = group_fields.map { |field| column_alias_for(field) } + group_columns = group_aliases.zip(group_fields) - calculated_data = @klass.connection.select_all(relation, nil, relation.bound_attributes) - - if association - key_ids = calculated_data.collect { |row| row[group_aliases.first] } - key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids) - key_records = Hash[key_records.map { |r| [r.id, r] }] - end + if operation == "count" && column_name == :all + aggregate_alias = "count_all" + else + aggregate_alias = column_alias_for([operation, column_name].join(" ")) + end - Hash[calculated_data.map do |row| - key = group_columns.map { |aliaz, col_name| - column = calculated_data.column_types.fetch(aliaz) do - type_for(col_name) + select_values = [ + operation_over_aggregate_column( + aggregate_column(column_name), + operation, + distinct).as(aggregate_alias) + ] + select_values += select_values unless having_clause.empty? + + select_values.concat group_columns.map { |aliaz, field| + if field.respond_to?(:as) + field.as(aliaz) + else + "#{field} AS #{aliaz}" end - type_cast_calculated_value(row[aliaz], column) } - key = key.first if key.size == 1 - key = key_records[key] if associated - column_type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) } - [key, type_cast_calculated_value(row[aggregate_alias], column_type, operation)] - end] - end + relation = except(:group) + relation.group_values = group_fields + relation.select_values = select_values - # Converts the given keys to the value that the database adapter returns as - # a usable column name: - # - # column_alias_for("users.id") # => "users_id" - # column_alias_for("sum(id)") # => "sum_id" - # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id" - # column_alias_for("count(*)") # => "count_all" - def column_alias_for(keys) - if keys.respond_to? :name - keys = "#{keys.relation.name}.#{keys.name}" + calculated_data = @klass.connection.select_all(relation, nil, relation.bound_attributes) + + if association + key_ids = calculated_data.collect { |row| row[group_aliases.first] } + key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids) + key_records = Hash[key_records.map { |r| [r.id, r] }] + end + + Hash[calculated_data.map do |row| + key = group_columns.map { |aliaz, col_name| + type = type_for(col_name) do + calculated_data.column_types.fetch(aliaz, Type.default_value) + end + type_cast_calculated_value(row[aliaz], type) + } + key = key.first if key.size == 1 + key = key_records[key] if associated + + type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) } + [key, type_cast_calculated_value(row[aggregate_alias], type, operation)] + end] end - table_name = keys.to_s.downcase - table_name.gsub!(/\*/, 'all') - table_name.gsub!(/\W+/, ' ') - table_name.strip! - table_name.gsub!(/ +/, '_') + # Converts the given keys to the value that the database adapter returns as + # a usable column name: + # + # column_alias_for("users.id") # => "users_id" + # column_alias_for("sum(id)") # => "sum_id" + # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id" + # column_alias_for("count(*)") # => "count_all" + def column_alias_for(keys) + if keys.respond_to? :name + keys = "#{keys.relation.name}.#{keys.name}" + end - @klass.connection.table_alias_for(table_name) - end + table_name = keys.to_s.downcase + table_name.gsub!(/\*/, "all") + table_name.gsub!(/\W+/, " ") + table_name.strip! + table_name.gsub!(/ +/, "_") - def type_for(field) - field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last - @klass.type_for_attribute(field_name) - end + @klass.connection.table_alias_for(table_name) + end - def type_cast_calculated_value(value, type, operation = nil) - case operation - when 'count' then value.to_i - when 'sum' then type.deserialize(value || 0) - when 'average' then value.respond_to?(:to_d) ? value.to_d : value + def type_for(field, &block) + field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last + @klass.type_for_attribute(field_name, &block) + end + + def type_cast_calculated_value(value, type, operation = nil) + case operation + when "count" then value.to_i + when "sum" then type.deserialize(value || 0) + when "average" then value.respond_to?(:to_d) ? value.to_d : value else type.deserialize(value) + end end - end - def select_for_count - if select_values.present? - return select_values.first if select_values.one? - select_values.join(", ") - else - :all + def select_for_count + if select_values.present? + return select_values.first if select_values.one? + select_values.join(", ") + else + :all + end end - end - def build_count_subquery(relation, column_name, distinct) - column_alias = Arel.sql('count_column') - subquery_alias = Arel.sql('subquery_for_count') + def build_count_subquery(relation, column_name, distinct) + column_alias = Arel.sql("count_column") + subquery_alias = Arel.sql("subquery_for_count") - aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias) - relation.select_values = [aliased_column] - subquery = relation.arel.as(subquery_alias) + aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias) + relation.select_values = [aliased_column] + subquery = relation.arel.as(subquery_alias) - sm = Arel::SelectManager.new relation.engine - select_value = operation_over_aggregate_column(column_alias, 'count', distinct) - sm.project(select_value).from(subquery) - end + sm = Arel::SelectManager.new relation.engine + select_value = operation_over_aggregate_column(column_alias, "count", distinct) + sm.project(select_value).from(subquery) + end end end diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb index 2484cb3264..d16de4b06c 100644 --- a/activerecord/lib/active_record/relation/delegation.rb +++ b/activerecord/lib/active_record/relation/delegation.rb @@ -1,4 +1,5 @@ -require 'active_support/concern' +require "active_support/concern" +require "active_support/core_ext/regexp" module ActiveRecord module Delegation # :nodoc: @@ -17,7 +18,7 @@ module ActiveRecord delegate = Class.new(klass) { include ClassSpecificRelation } - const_set klass.name.gsub('::'.freeze, '_'.freeze), delegate + const_set klass.name.gsub("::".freeze, "_".freeze), delegate cache[klass] = delegate end end @@ -37,10 +38,10 @@ module ActiveRecord delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, :[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of, - :shuffle, :split, to: :records + :shuffle, :split, :index, to: :records delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, - :connection, :columns_hash, :to => :klass + :connection, :columns_hash, to: :klass module ClassSpecificRelation # :nodoc: extend ActiveSupport::Concern @@ -58,7 +59,7 @@ module ActiveRecord @delegation_mutex.synchronize do return if method_defined?(method) - if method.to_s =~ /\A[a-zA-Z_]\w*[!?]?\z/ + if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method}(*args, &block) scoping { @klass.#{method}(*args, &block) } @@ -82,17 +83,17 @@ module ActiveRecord protected - def method_missing(method, *args, &block) - if @klass.respond_to?(method) - self.class.delegate_to_scoped_klass(method) - scoping { @klass.public_send(method, *args, &block) } - elsif arel.respond_to?(method) - self.class.delegate method, :to => :arel - arel.public_send(method, *args, &block) - else - super + def method_missing(method, *args, &block) + if @klass.respond_to?(method) + self.class.delegate_to_scoped_klass(method) + scoping { @klass.public_send(method, *args, &block) } + elsif arel.respond_to?(method) + self.class.delegate method, to: :arel + arel.public_send(method, *args, &block) + else + super + end end - end end module ClassMethods # :nodoc: @@ -102,26 +103,26 @@ module ActiveRecord private - def relation_class_for(klass) - klass.relation_delegate_class(self) - end + def relation_class_for(klass) + klass.relation_delegate_class(self) + end end - def respond_to?(method, include_private = false) + def respond_to_missing?(method, include_private = false) super || @klass.respond_to?(method, include_private) || arel.respond_to?(method, include_private) end protected - def method_missing(method, *args, &block) - if @klass.respond_to?(method) - scoping { @klass.public_send(method, *args, &block) } - elsif arel.respond_to?(method) - arel.public_send(method, *args, &block) - else - super + def method_missing(method, *args, &block) + if @klass.respond_to?(method) + scoping { @klass.public_send(method, *args, &block) } + elsif arel.respond_to?(method) + arel.public_send(method, *args, &block) + else + super + end end - end end end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index d255cad91b..97a819c5af 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -1,8 +1,8 @@ -require 'active_support/core_ext/string/filters' +require "active_support/core_ext/string/filters" module ActiveRecord module FinderMethods - ONE_AS_ONE = '1 AS one' + ONE_AS_ONE = "1 AS one" # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). # If one or more records can not be found for the requested ids, then RecordNotFound will be raised. If the primary key @@ -97,13 +97,13 @@ module ActiveRecord # Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5 # Person.where(["name LIKE '%?'", name]).take def take(limit = nil) - limit ? limit(limit).to_a : find_take + limit ? find_take_with_limit(limit) : find_take end # Same as #take but raises ActiveRecord::RecordNotFound if no record # is found. Note that #take! accepts no arguments. def take! - take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") + take || raise_record_not_found_exception! end # Find the first record (or first N records if a parameter is supplied). @@ -117,7 +117,7 @@ module ActiveRecord # def first(limit = nil) if limit - find_nth_with_limit_and_offset(0, limit, offset: offset_index) + find_nth_with_limit(0, limit) else find_nth 0 end @@ -126,7 +126,7 @@ module ActiveRecord # Same as #first but raises ActiveRecord::RecordNotFound if no record # is found. Note that #first! accepts no arguments. def first! - find_nth! 0 + first || raise_record_not_found_exception! end # Find the last record (or last N records if a parameter is supplied). @@ -165,7 +165,7 @@ module ActiveRecord # Same as #last but raises ActiveRecord::RecordNotFound if no record # is found. Note that #last! accepts no arguments. def last! - last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") + last || raise_record_not_found_exception! end # Find the second record. @@ -181,7 +181,7 @@ module ActiveRecord # Same as #second but raises ActiveRecord::RecordNotFound if no record # is found. def second! - find_nth! 1 + second || raise_record_not_found_exception! end # Find the third record. @@ -197,7 +197,7 @@ module ActiveRecord # Same as #third but raises ActiveRecord::RecordNotFound if no record # is found. def third! - find_nth! 2 + third || raise_record_not_found_exception! end # Find the fourth record. @@ -213,7 +213,7 @@ module ActiveRecord # Same as #fourth but raises ActiveRecord::RecordNotFound if no record # is found. def fourth! - find_nth! 3 + fourth || raise_record_not_found_exception! end # Find the fifth record. @@ -229,7 +229,7 @@ module ActiveRecord # Same as #fifth but raises ActiveRecord::RecordNotFound if no record # is found. def fifth! - find_nth! 4 + fifth || raise_record_not_found_exception! end # Find the forty-second record. Also known as accessing "the reddit". @@ -245,7 +245,7 @@ module ActiveRecord # Same as #forty_two but raises ActiveRecord::RecordNotFound if no record # is found. def forty_two! - find_nth! 41 + forty_two || raise_record_not_found_exception! end # Find the third-to-last record. @@ -261,7 +261,7 @@ module ActiveRecord # Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record # is found. def third_to_last! - find_nth_from_last 3 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") + third_to_last || raise_record_not_found_exception! end # Find the second-to-last record. @@ -277,7 +277,7 @@ module ActiveRecord # Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record # is found. def second_to_last! - find_nth_from_last 2 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") + second_to_last || raise_record_not_found_exception! end # Returns true if a record exists in the table that matches the +id+ or @@ -345,248 +345,237 @@ module ActiveRecord # of results obtained should be provided in the +result_size+ argument and # the expected number of results should be provided in the +expected_size+ # argument. - def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc: + def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil) # :nodoc: conditions = arel.where_sql(@klass.arel_engine) conditions = " [#{conditions}]" if conditions - - if Array(ids).size == 1 - error = "Couldn't find #{@klass.name} with '#{primary_key}'=#{ids}#{conditions}" + name = @klass.name + + if ids.nil? + error = "Couldn't find #{name}" + error << " with#{conditions}" if conditions + raise RecordNotFound.new(error, name) + elsif Array(ids).size == 1 + error = "Couldn't find #{name} with '#{primary_key}'=#{ids}#{conditions}" + raise RecordNotFound.new(error, name, primary_key, ids) else - error = "Couldn't find all #{@klass.name.pluralize} with '#{primary_key}': " + error = "Couldn't find all #{name.pluralize} with '#{primary_key}': " error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})" - end - raise RecordNotFound, error + raise RecordNotFound.new(error, name, primary_key, ids) + end end private - def offset_index - offset_value || 0 - end + def offset_index + offset_value || 0 + end - def find_with_associations - # NOTE: the JoinDependency constructed here needs to know about - # any joins already present in `self`, so pass them in - # - # failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136 - # incorrect SQL is generated. In that case, the join dependency for - # SpecialCategorizations is constructed without knowledge of the - # preexisting join in joins_values to categorizations (by way of - # the `has_many :through` for categories). - # - join_dependency = construct_join_dependency(joins_values) - - aliases = join_dependency.aliases - relation = select aliases.columns - relation = apply_join_dependency(relation, join_dependency) - - if block_given? - yield relation - else - if ActiveRecord::NullRelation === relation - [] + def find_with_associations + # NOTE: the JoinDependency constructed here needs to know about + # any joins already present in `self`, so pass them in + # + # failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136 + # incorrect SQL is generated. In that case, the join dependency for + # SpecialCategorizations is constructed without knowledge of the + # preexisting join in joins_values to categorizations (by way of + # the `has_many :through` for categories). + # + join_dependency = construct_join_dependency(joins_values) + + aliases = join_dependency.aliases + relation = select aliases.columns + relation = apply_join_dependency(relation, join_dependency) + + if block_given? + yield relation else - arel = relation.arel - rows = connection.select_all(arel, 'SQL', relation.bound_attributes) - join_dependency.instantiate(rows, aliases) + if ActiveRecord::NullRelation === relation + [] + else + arel = relation.arel + rows = connection.select_all(arel, "SQL", relation.bound_attributes) + join_dependency.instantiate(rows, aliases) + end end end - end - def construct_join_dependency(joins = [], eager_loading: true) - including = eager_load_values + includes_values - ActiveRecord::Associations::JoinDependency.new(@klass, including, joins, eager_loading: eager_loading) - end + def construct_join_dependency(joins = [], eager_loading: true) + including = eager_load_values + includes_values + ActiveRecord::Associations::JoinDependency.new(@klass, including, joins, eager_loading: eager_loading) + end - def construct_relation_for_association_calculations - apply_join_dependency(self, construct_join_dependency(joins_values)) - end + def construct_relation_for_association_calculations + apply_join_dependency(self, construct_join_dependency(joins_values)) + end - def apply_join_dependency(relation, join_dependency) - relation = relation.except(:includes, :eager_load, :preload) - relation = relation.joins join_dependency + def apply_join_dependency(relation, join_dependency) + relation = relation.except(:includes, :eager_load, :preload) + relation = relation.joins join_dependency - if using_limitable_reflections?(join_dependency.reflections) - relation - else - if relation.limit_value - limited_ids = limited_ids_for(relation) - limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids) + if using_limitable_reflections?(join_dependency.reflections) + relation + else + if relation.limit_value + limited_ids = limited_ids_for(relation) + limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids) + end + relation.except(:limit, :offset) end - relation.except(:limit, :offset) end - end - def limited_ids_for(relation) - values = @klass.connection.columns_for_distinct( - "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values) + def limited_ids_for(relation) + values = @klass.connection.columns_for_distinct( + "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values) - relation = relation.except(:select).select(values).distinct! - arel = relation.arel + relation = relation.except(:select).select(values).distinct! + arel = relation.arel - id_rows = @klass.connection.select_all(arel, 'SQL', relation.bound_attributes) - id_rows.map {|row| row[primary_key]} - end + id_rows = @klass.connection.select_all(arel, "SQL", relation.bound_attributes) + id_rows.map { |row| row[primary_key] } + end - def using_limitable_reflections?(reflections) - reflections.none?(&:collection?) - end + def using_limitable_reflections?(reflections) + reflections.none?(&:collection?) + end protected - def find_with_ids(*ids) - raise UnknownPrimaryKey.new(@klass) if primary_key.nil? + def find_with_ids(*ids) + raise UnknownPrimaryKey.new(@klass) if primary_key.nil? - expects_array = ids.first.kind_of?(Array) - return ids.first if expects_array && ids.first.empty? + expects_array = ids.first.kind_of?(Array) + return ids.first if expects_array && ids.first.empty? - ids = ids.flatten.compact.uniq + ids = ids.flatten.compact.uniq - case ids.size - when 0 - raise RecordNotFound, "Couldn't find #{@klass.name} without an ID" - when 1 - result = find_one(ids.first) - expects_array ? [ result ] : result - else - find_some(ids) + case ids.size + when 0 + raise RecordNotFound, "Couldn't find #{@klass.name} without an ID" + when 1 + result = find_one(ids.first) + expects_array ? [ result ] : result + else + find_some(ids) + end + rescue RangeError + raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID" end - rescue RangeError - raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID" - end - def find_one(id) - if ActiveRecord::Base === id - id = id.id - ActiveSupport::Deprecation.warn(<<-MSG.squish) - You are passing an instance of ActiveRecord::Base to `find`. - Please pass the id of the object by calling `.id`. - MSG - end + def find_one(id) + if ActiveRecord::Base === id + id = id.id + ActiveSupport::Deprecation.warn(<<-MSG.squish) + You are passing an instance of ActiveRecord::Base to `find`. + Please pass the id of the object by calling `.id`. + MSG + end - relation = where(primary_key => id) - record = relation.take + relation = where(primary_key => id) + record = relation.take - raise_record_not_found_exception!(id, 0, 1) unless record + raise_record_not_found_exception!(id, 0, 1) unless record - record - end + record + end - def find_some(ids) - return find_some_ordered(ids) unless order_values.present? + def find_some(ids) + return find_some_ordered(ids) unless order_values.present? - result = where(primary_key => ids).to_a + result = where(primary_key => ids).to_a - expected_size = - if limit_value && ids.size > limit_value - limit_value - else - ids.size - end + expected_size = + if limit_value && ids.size > limit_value + limit_value + else + ids.size + end - # 11 ids with limit 3, offset 9 should give 2 results. - if offset_value && (ids.size - offset_value < expected_size) - expected_size = ids.size - offset_value - end + # 11 ids with limit 3, offset 9 should give 2 results. + if offset_value && (ids.size - offset_value < expected_size) + expected_size = ids.size - offset_value + end - if result.size == expected_size - result - else - raise_record_not_found_exception!(ids, result.size, expected_size) + if result.size == expected_size + result + else + raise_record_not_found_exception!(ids, result.size, expected_size) + end end - end - def find_some_ordered(ids) - ids = ids.slice(offset_value || 0, limit_value || ids.size) || [] + def find_some_ordered(ids) + ids = ids.slice(offset_value || 0, limit_value || ids.size) || [] - result = except(:limit, :offset).where(primary_key => ids).records + result = except(:limit, :offset).where(primary_key => ids).records - if result.size == ids.size - pk_type = @klass.type_for_attribute(primary_key) + if result.size == ids.size + pk_type = @klass.type_for_attribute(primary_key) - records_by_id = result.index_by(&:id) - ids.map { |id| records_by_id.fetch(pk_type.cast(id)) } - else - raise_record_not_found_exception!(ids, result.size, ids.size) + records_by_id = result.index_by(&:id) + ids.map { |id| records_by_id.fetch(pk_type.cast(id)) } + else + raise_record_not_found_exception!(ids, result.size, ids.size) + end end - end - def find_take - if loaded? - @records.first - else - @take ||= limit(1).records.first + def find_take + if loaded? + records.first + else + @take ||= limit(1).records.first + end end - end - def find_nth(index, offset = nil) - # TODO: once the offset argument is removed we rely on offset_index - # within find_nth_with_limit, rather than pass it in via - # find_nth_with_limit_and_offset - if offset - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Passing an offset argument to find_nth is deprecated, - please use Relation#offset instead. - MSG - end - if loaded? - @records[index] - else - offset ||= offset_index - @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first + def find_take_with_limit(limit) + if loaded? + records.take(limit) + else + limit(limit).to_a + end end - end - def find_nth!(index) - find_nth(index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") - end + def find_nth(index) + @offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first + end - def find_nth_with_limit(index, limit) - # TODO: once the offset argument is removed from find_nth, - # find_nth_with_limit_and_offset can be merged into this method - relation = if order_values.empty? && primary_key - order(arel_attribute(primary_key).asc) - else - self - end - - relation = relation.offset(index) unless index.zero? - relation.limit(limit).to_a - end + def find_nth_with_limit(index, limit) + if loaded? + records[index, limit] || [] + else + relation = if order_values.empty? && primary_key + order(arel_attribute(primary_key).asc) + else + self + end + + relation = relation.offset(offset_index + index) unless index.zero? + relation.limit(limit).to_a + end + end - def find_nth_from_last(index) - if loaded? - @records[-index] - else - relation = if order_values.empty? && primary_key - order(arel_attribute(primary_key).asc) - else - self - end - - relation.to_a[-index] - # TODO: can be made more performant on large result sets by - # for instance, last(index)[-index] (which would require - # refactoring the last(n) finder method to make test suite pass), - # or by using a combination of reverse_order, limit, and offset, - # e.g., reverse_order.offset(index-1).first + def find_nth_from_last(index) + if loaded? + records[-index] + else + relation = if order_values.empty? && primary_key + order(arel_attribute(primary_key).asc) + else + self + end + + relation.to_a[-index] + # TODO: can be made more performant on large result sets by + # for instance, last(index)[-index] (which would require + # refactoring the last(n) finder method to make test suite pass), + # or by using a combination of reverse_order, limit, and offset, + # e.g., reverse_order.offset(index-1).first + end end - end private - def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc: - if loaded? - @records[index, limit] - else - index += offset - find_nth_with_limit(index, limit) + def find_last(limit) + limit ? records.last(limit) : records.last end - end - - def find_last(limit) - limit ? records.last(limit) : records.last - end end end diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index 396638d74d..5dac00724a 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/hash/keys" module ActiveRecord class Relation @@ -83,85 +83,81 @@ module ActiveRecord private - def merge_preloads - return if other.preload_values.empty? && other.includes_values.empty? + def merge_preloads + return if other.preload_values.empty? && other.includes_values.empty? - if other.klass == relation.klass - relation.preload!(*other.preload_values) unless other.preload_values.empty? - relation.includes!(other.includes_values) unless other.includes_values.empty? - else - reflection = relation.klass.reflect_on_all_associations.find do |r| - r.class_name == other.klass.name - end || return + if other.klass == relation.klass + relation.preload!(*other.preload_values) unless other.preload_values.empty? + relation.includes!(other.includes_values) unless other.includes_values.empty? + else + reflection = relation.klass.reflect_on_all_associations.find do |r| + r.class_name == other.klass.name + end || return - unless other.preload_values.empty? - relation.preload! reflection.name => other.preload_values - end + unless other.preload_values.empty? + relation.preload! reflection.name => other.preload_values + end - unless other.includes_values.empty? - relation.includes! reflection.name => other.includes_values + unless other.includes_values.empty? + relation.includes! reflection.name => other.includes_values + end end end - end - def merge_joins - return if other.joins_values.blank? + def merge_joins + return if other.joins_values.blank? - if other.klass == relation.klass - relation.joins!(*other.joins_values) - else - joins_dependency, rest = other.joins_values.partition do |join| - case join - when Hash, Symbol, Array - true - else - false + if other.klass == relation.klass + relation.joins!(*other.joins_values) + else + joins_dependency, rest = other.joins_values.partition do |join| + case join + when Hash, Symbol, Array + true + else + false + end end - end - - join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass, - joins_dependency, - []) - relation.joins! rest - @relation = relation.joins join_dependency - end - end + join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass, + joins_dependency, + []) + relation.joins! rest - def merge_multi_values - if other.reordering_value - # override any order specified in the original relation - relation.reorder! other.order_values - elsif other.order_values - # merge in order_values from relation - relation.order! other.order_values + @relation = relation.joins join_dependency + end end - relation.extend(*other.extending_values) unless other.extending_values.blank? - end + def merge_multi_values + if other.reordering_value + # override any order specified in the original relation + relation.reorder! other.order_values + elsif other.order_values + # merge in order_values from relation + relation.order! other.order_values + end - def merge_single_values - if relation.from_clause.empty? - relation.from_clause = other.from_clause + relation.extend(*other.extending_values) unless other.extending_values.blank? end - relation.lock_value ||= other.lock_value - unless other.create_with_value.blank? - relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value) - end - end + def merge_single_values + if relation.from_clause.empty? + relation.from_clause = other.from_clause + end + relation.lock_value ||= other.lock_value - CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name| - ["#{name}_clause", "#{name}_clause="] - end + unless other.create_with_value.blank? + relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value) + end + end - def merge_clauses - CLAUSE_METHOD_NAMES.each do |(reader, writer)| - clause = relation.send(reader) - other_clause = other.send(reader) - relation.send(writer, clause.merge(other_clause)) + def merge_clauses + CLAUSE_METHODS.each do |method| + clause = relation.get_value(method) + other_clause = other.get_value(method) + relation.set_value(method, clause.merge(other_clause)) + end end - end end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index ecce949370..780a1ee422 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -1,13 +1,13 @@ module ActiveRecord class PredicateBuilder # :nodoc: - require 'active_record/relation/predicate_builder/array_handler' - require 'active_record/relation/predicate_builder/association_query_handler' - require 'active_record/relation/predicate_builder/base_handler' - require 'active_record/relation/predicate_builder/basic_object_handler' - require 'active_record/relation/predicate_builder/class_handler' - require 'active_record/relation/predicate_builder/polymorphic_array_handler' - require 'active_record/relation/predicate_builder/range_handler' - require 'active_record/relation/predicate_builder/relation_handler' + require "active_record/relation/predicate_builder/array_handler" + require "active_record/relation/predicate_builder/association_query_handler" + require "active_record/relation/predicate_builder/base_handler" + require "active_record/relation/predicate_builder/basic_object_handler" + require "active_record/relation/predicate_builder/class_handler" + require "active_record/relation/predicate_builder/polymorphic_array_handler" + require "active_record/relation/predicate_builder/range_handler" + require "active_record/relation/predicate_builder/relation_handler" delegate :resolve_column_aliases, to: :table @@ -15,11 +15,11 @@ module ActiveRecord @table = table @handlers = [] - register_handler(BasicObject, BasicObjectHandler.new(self)) + register_handler(BasicObject, BasicObjectHandler.new) register_handler(Class, ClassHandler.new(self)) register_handler(Base, BaseHandler.new(self)) - register_handler(Range, RangeHandler.new(self)) - register_handler(RangeHandler::RangeWithBinds, RangeHandler.new(self)) + register_handler(Range, RangeHandler.new) + register_handler(RangeHandler::RangeWithBinds, RangeHandler.new) register_handler(Relation, RelationHandler.new) register_handler(Array, ArrayHandler.new(self)) register_handler(AssociationQueryValue, AssociationQueryHandler.new(self)) @@ -36,23 +36,13 @@ module ActiveRecord create_binds_for_hash(attributes) end - def expand(column, value) - # Find the foreign key when using queries such as: - # Post.where(author: author) - # - # For polymorphic relationships, find the foreign key and type: - # PriceEstimate.where(estimate_of: treasure) - value = AssociationQueryHandler.value_for(table, column, value) if table.associated_with?(column) - build(table.arel_attribute(column), value) - end - def self.references(attributes) attributes.map do |key, value| if value.is_a?(Hash) key else key = key.to_s - key.split('.'.freeze).first if key.include?('.'.freeze) + key.split(".".freeze).first if key.include?(".".freeze) end end.compact end @@ -78,91 +68,104 @@ module ActiveRecord protected - attr_reader :table + attr_reader :table - def expand_from_hash(attributes) - return ["1=0"] if attributes.empty? + def expand_from_hash(attributes) + return ["1=0"] if attributes.empty? - attributes.flat_map do |key, value| - if value.is_a?(Hash) - associated_predicate_builder(key).expand_from_hash(value) - else - expand(key, value) + attributes.flat_map do |key, value| + if value.is_a?(Hash) && !table.has_column?(key) + associated_predicate_builder(key).expand_from_hash(value) + else + build(table.arel_attribute(key), value) + end end end - end - - - def create_binds_for_hash(attributes) - result = attributes.dup - binds = [] - attributes.each do |column_name, value| - case value - when Hash - attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value) - result[column_name] = attrs - binds += bvs - when Relation - binds += value.bound_attributes - when Range - first = value.begin - last = value.end - unless first.respond_to?(:infinite?) && first.infinite? - binds << build_bind_param(column_name, first) - first = Arel::Nodes::BindParam.new - end - unless last.respond_to?(:infinite?) && last.infinite? - binds << build_bind_param(column_name, last) - last = Arel::Nodes::BindParam.new + def create_binds_for_hash(attributes) + result = attributes.dup + binds = [] + + attributes.each do |column_name, value| + case + when value.is_a?(Hash) && !table.has_column?(column_name) + attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value) + result[column_name] = attrs + binds += bvs + next + when value.is_a?(Relation) + binds += value.bound_attributes + when value.is_a?(Range) && !table.type(column_name).respond_to?(:subtype) + first = value.begin + last = value.end + unless first.respond_to?(:infinite?) && first.infinite? + binds << build_bind_param(column_name, first) + first = Arel::Nodes::BindParam.new + end + unless last.respond_to?(:infinite?) && last.infinite? + binds << build_bind_param(column_name, last) + last = Arel::Nodes::BindParam.new + end + + result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?) + else + if can_be_bound?(column_name, value) + result[column_name] = Arel::Nodes::BindParam.new + binds << build_bind_param(column_name, value) + end end - result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?) - else - if can_be_bound?(column_name, value) - result[column_name] = Arel::Nodes::BindParam.new - binds << build_bind_param(column_name, value) + # Find the foreign key when using queries such as: + # Post.where(author: author) + # + # For polymorphic relationships, find the foreign key and type: + # PriceEstimate.where(estimate_of: treasure) + if table.associated_with?(column_name) + result[column_name] = AssociationQueryHandler.value_for(table, column_name, value) end end - end - [result, binds] - end + [result, binds] + end private - def associated_predicate_builder(association_name) - self.class.new(table.associated_table(association_name)) - end - - def convert_dot_notation_to_hash(attributes) - dot_notation = attributes.select do |k, v| - k.include?(".".freeze) && !v.is_a?(Hash) + def associated_predicate_builder(association_name) + self.class.new(table.associated_table(association_name)) end - dot_notation.each_key do |key| - table_name, column_name = key.split(".".freeze) - value = attributes.delete(key) - attributes[table_name] ||= {} + def convert_dot_notation_to_hash(attributes) + dot_notation = attributes.select do |k, v| + k.include?(".".freeze) && !v.is_a?(Hash) + end - attributes[table_name] = attributes[table_name].merge(column_name => value) - end + dot_notation.each_key do |key| + table_name, column_name = key.split(".".freeze) + value = attributes.delete(key) + attributes[table_name] ||= {} - attributes - end + attributes[table_name] = attributes[table_name].merge(column_name => value) + end - def handler_for(object) - @handlers.detect { |klass, _| klass === object }.last - end + attributes + end - def can_be_bound?(column_name, value) - !value.nil? && - handler_for(value).is_a?(BasicObjectHandler) && - !table.associated_with?(column_name) - end + def handler_for(object) + @handlers.detect { |klass, _| klass === object }.last + end - def build_bind_param(column_name, value) - Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name)) - end + def can_be_bound?(column_name, value) + return if table.associated_with?(column_name) + case value + when Array, Range + table.type(column_name).respond_to?(:subtype) + else + !value.nil? && handler_for(value).is_a?(BasicObjectHandler) + end + end + + def build_bind_param(column_name, value) + Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name)) + end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb index 95dbd6a77f..6400caba06 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb @@ -31,13 +31,13 @@ module ActiveRecord protected - attr_reader :predicate_builder + attr_reader :predicate_builder - module NullPredicate # :nodoc: - def self.or(other) - other + module NullPredicate # :nodoc: + def self.or(other) + other + end end - end end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb index 413cb9fd84..7e20cb2c63 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb @@ -30,7 +30,7 @@ module ActiveRecord protected - attr_reader :predicate_builder + attr_reader :predicate_builder end class AssociationQueryValue # :nodoc: @@ -60,30 +60,30 @@ module ActiveRecord private - def primary_key - associated_table.association_primary_key(base_class) - end + def primary_key + associated_table.association_primary_key(base_class) + end - def polymorphic_base_class_from_value - case value - when Relation - value.klass.base_class - when Array - val = value.compact.first - val.class.base_class if val.is_a?(Base) - when Base - value.class.base_class + def polymorphic_base_class_from_value + case value + when Relation + value.klass.base_class + when Array + val = value.compact.first + val.class.base_class if val.is_a?(Base) + when Base + value.class.base_class + end end - end - def convert_to_id(value) - case value - when Base - value._read_attribute(primary_key) - else - value + def convert_to_id(value) + case value + when Base + value._read_attribute(primary_key) + else + value + end end - end end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb index 6fa5b16f73..65c5159704 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb @@ -11,7 +11,7 @@ module ActiveRecord protected - attr_reader :predicate_builder + attr_reader :predicate_builder end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/basic_object_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/basic_object_handler.rb index 6cec75dc0a..79cde00303 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/basic_object_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/basic_object_handler.rb @@ -1,17 +1,9 @@ module ActiveRecord class PredicateBuilder class BasicObjectHandler # :nodoc: - def initialize(predicate_builder) - @predicate_builder = predicate_builder - end - def call(attribute, value) attribute.eq(value) end - - protected - - attr_reader :predicate_builder end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb index ed313fc9d4..0a6574fcf1 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb @@ -12,16 +12,16 @@ module ActiveRecord protected - attr_reader :predicate_builder + attr_reader :predicate_builder private - def print_deprecation_warning - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Passing a class as a value in an Active Record query is deprecated and - will be removed. Pass a string instead. - MSG - end + def print_deprecation_warning + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Passing a class as a value in an Active Record query is deprecated and + will be removed. Pass a string instead. + MSG + end end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb index b6c6240343..0c7f92b3d0 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb @@ -23,7 +23,7 @@ module ActiveRecord protected - attr_reader :predicate_builder + attr_reader :predicate_builder end class PolymorphicArrayValue # :nodoc: @@ -41,17 +41,17 @@ module ActiveRecord private - def primary_key(value) - associated_table.association_primary_key(base_class(value)) - end + def primary_key(value) + associated_table.association_primary_key(base_class(value)) + end - def base_class(value) - value.class.base_class - end + def base_class(value) + value.class.base_class + end - def convert_to_id(value) - value._read_attribute(primary_key(value)) - end + def convert_to_id(value) + value._read_attribute(primary_key(value)) + end end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb index 306d4694ae..5db778e19c 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb @@ -3,10 +3,6 @@ module ActiveRecord class RangeHandler # :nodoc: RangeWithBinds = Struct.new(:begin, :end, :exclude_end?) - def initialize(predicate_builder) - @predicate_builder = predicate_builder - end - def call(attribute, value) if value.begin.respond_to?(:infinite?) && value.begin.infinite? if value.end.respond_to?(:infinite?) && value.end.infinite? @@ -24,10 +20,6 @@ module ActiveRecord attribute.between(value) end end - - protected - - attr_reader :predicate_builder end end end diff --git a/activerecord/lib/active_record/relation/query_attribute.rb b/activerecord/lib/active_record/relation/query_attribute.rb index 7ba964e802..a68e508fcc 100644 --- a/activerecord/lib/active_record/relation/query_attribute.rb +++ b/activerecord/lib/active_record/relation/query_attribute.rb @@ -1,4 +1,4 @@ -require 'active_record/attribute' +require "active_record/attribute" module ActiveRecord class Relation diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 8a87015e44..c6d0902e0d 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -2,8 +2,9 @@ require "active_record/relation/from_clause" require "active_record/relation/query_attribute" require "active_record/relation/where_clause" require "active_record/relation/where_clause_factory" -require 'active_model/forbidden_attributes_protection' -require 'active_support/core_ext/string/filters' +require "active_model/forbidden_attributes_protection" +require "active_support/core_ext/string/filters" +require "active_support/core_ext/regexp" module ActiveRecord module QueryMethods @@ -55,62 +56,39 @@ module ActiveRecord end FROZEN_EMPTY_ARRAY = [].freeze - Relation::MULTI_VALUE_METHODS.each do |name| - class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name}_values - @values[:#{name}] || FROZEN_EMPTY_ARRAY - end + FROZEN_EMPTY_HASH = {}.freeze - def #{name}_values=(values) - assert_mutability! - @values[:#{name}] = values + Relation::VALUE_METHODS.each do |name| + method_name = \ + case name + when *Relation::MULTI_VALUE_METHODS then "#{name}_values" + when *Relation::SINGLE_VALUE_METHODS then "#{name}_value" + when *Relation::CLAUSE_METHODS then "#{name}_clause" end - CODE - end - - (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name| class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name}_value # def readonly_value - @values[:#{name}] # @values[:readonly] + def #{method_name} # def includes_values + get_value(#{name.inspect}) # get_value(:includes) end # end - CODE - end - Relation::SINGLE_VALUE_METHODS.each do |name| - class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name}_value=(value) # def readonly_value=(value) - assert_mutability! # assert_mutability! - @values[:#{name}] = value # @values[:readonly] = value + def #{method_name}=(value) # def includes_values=(value) + set_value(#{name.inspect}, value) # set_value(:includes, value) end # end CODE end - Relation::CLAUSE_METHODS.each do |name| - class_eval <<-CODE, __FILE__, __LINE__ + 1 - def #{name}_clause # def where_clause - @values[:#{name}] || new_#{name}_clause # @values[:where] || new_where_clause - end # end - # - def #{name}_clause=(value) # def where_clause=(value) - assert_mutability! # assert_mutability! - @values[:#{name}] = value # @values[:where] = value - end # end - CODE - end - def bound_attributes if limit_value && !string_containing_comma?(limit_value) limit_bind = Attribute.with_cast_value( "LIMIT".freeze, connection.sanitize_limit(limit_value), - Type::Value.new, + Type.default_value, ) end if offset_value offset_bind = Attribute.with_cast_value( "OFFSET".freeze, offset_value.to_i, - Type::Value.new, + Type.default_value, ) end connection.combine_bind_parameters( @@ -123,11 +101,6 @@ module ActiveRecord ) end - FROZEN_EMPTY_HASH = {}.freeze - def create_with_value # :nodoc: - @values[:create_with] || FROZEN_EMPTY_HASH - end - alias extensions extending_values # Specify relationships to be included in the result set. For @@ -269,8 +242,17 @@ module ActiveRecord # Model.select(:field).first.other_field # # => ActiveModel::MissingAttributeError: missing attribute: other_field def select(*fields) - return super if block_given? - raise ArgumentError, 'Call this with at least one field' if fields.empty? + if block_given? + if fields.any? + ActiveSupport::Deprecation.warn(<<-WARNING.squish) + When select is called with a block, it ignores other arguments. This behavior is now deprecated and will result in an ArgumentError in Rails 5.1. You can safely remove the arguments to resolve the deprecation warning because they do not have any effect on the output of the call to the select method with a block. + WARNING + end + + return super() + end + + raise ArgumentError, "Call this with at least one field" if fields.empty? spawn._select!(*fields) end @@ -417,7 +399,10 @@ module ActiveRecord args.each do |scope| case scope when Symbol - symbol_unscoping(scope) + if !VALID_UNSCOPING_VALUES.include?(scope) + raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}." + end + set_value(scope, nil) when Hash scope.each do |key, target_value| if key != :where @@ -495,7 +480,6 @@ module ActiveRecord self.left_outer_joins_values += args self end - alias :left_joins! :left_outer_joins! # Returns a new relation, which is the result of filtering the current relation # according to the conditions in the arguments. @@ -949,288 +933,287 @@ module ActiveRecord @arel ||= build_arel end - private - - def assert_mutability! - raise ImmutableRelation if @loaded - raise ImmutableRelation if defined?(@arel) && @arel + # Returns a relation value with a given name + def get_value(name) # :nodoc: + @values[name] || default_value_for(name) end - def build_arel - arel = Arel::SelectManager.new(table) + # Sets the relation value with the given name + def set_value(name, value) # :nodoc: + assert_mutability! + @values[name] = value + end - build_joins(arel, joins_values.flatten) unless joins_values.empty? - build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty? + private - arel.where(where_clause.ast) unless where_clause.empty? - arel.having(having_clause.ast) unless having_clause.empty? - if limit_value - if string_containing_comma?(limit_value) - arel.take(connection.sanitize_limit(limit_value)) - else - arel.take(Arel::Nodes::BindParam.new) - end + def assert_mutability! + raise ImmutableRelation if @loaded + raise ImmutableRelation if defined?(@arel) && @arel end - arel.skip(Arel::Nodes::BindParam.new) if offset_value - arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty? - build_order(arel) + def build_arel + arel = Arel::SelectManager.new(table) - build_select(arel) + build_joins(arel, joins_values.flatten) unless joins_values.empty? + build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty? - arel.distinct(distinct_value) - arel.from(build_from) unless from_clause.empty? - arel.lock(lock_value) if lock_value + arel.where(where_clause.ast) unless where_clause.empty? + arel.having(having_clause.ast) unless having_clause.empty? + if limit_value + if string_containing_comma?(limit_value) + arel.take(connection.sanitize_limit(limit_value)) + else + arel.take(Arel::Nodes::BindParam.new) + end + end + arel.skip(Arel::Nodes::BindParam.new) if offset_value + arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty? - arel - end + build_order(arel) - def symbol_unscoping(scope) - if !VALID_UNSCOPING_VALUES.include?(scope) - raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}." - end + build_select(arel) - clause_method = Relation::CLAUSE_METHODS.include?(scope) - multi_val_method = Relation::MULTI_VALUE_METHODS.include?(scope) - if clause_method - unscope_code = "#{scope}_clause=" - else - unscope_code = "#{scope}_value#{'s' if multi_val_method}=" - end + arel.distinct(distinct_value) + arel.from(build_from) unless from_clause.empty? + arel.lock(lock_value) if lock_value - case scope - when :order - result = [] - else - result = [] if multi_val_method + arel end - self.send(unscope_code, result) - end - - def build_from - opts = from_clause.value - name = from_clause.name - case opts - when Relation - name ||= 'subquery' - opts.arel.as(name.to_s) - else - opts - end - end - - def build_left_outer_joins(manager, outer_joins) - buckets = outer_joins.group_by do |join| - case join - when Hash, Symbol, Array - :association_join + def build_from + opts = from_clause.value + name = from_clause.name + case opts + when Relation + name ||= "subquery" + opts.arel.as(name.to_s) else - raise ArgumentError, 'only Hash, Symbol and Array are allowed' + opts end end - build_join_query(manager, buckets, Arel::Nodes::OuterJoin) - end - - def build_joins(manager, joins) - buckets = joins.group_by do |join| - case join - when String - :string_join - when Hash, Symbol, Array - :association_join - when ActiveRecord::Associations::JoinDependency - :stashed_join - when Arel::Nodes::Join - :join_node - else - raise 'unknown class: %s' % join.class.name + def build_left_outer_joins(manager, outer_joins) + buckets = outer_joins.group_by do |join| + case join + when Hash, Symbol, Array + :association_join + else + raise ArgumentError, "only Hash, Symbol and Array are allowed" + end end + + build_join_query(manager, buckets, Arel::Nodes::OuterJoin) end - build_join_query(manager, buckets, Arel::Nodes::InnerJoin) - end + def build_joins(manager, joins) + buckets = joins.group_by do |join| + case join + when String + :string_join + when Hash, Symbol, Array + :association_join + when ActiveRecord::Associations::JoinDependency + :stashed_join + when Arel::Nodes::Join + :join_node + else + raise "unknown class: %s" % join.class.name + end + end - def build_join_query(manager, buckets, join_type) - buckets.default = [] + build_join_query(manager, buckets, Arel::Nodes::InnerJoin) + end - association_joins = buckets[:association_join] - stashed_association_joins = buckets[:stashed_join] - join_nodes = buckets[:join_node].uniq - string_joins = buckets[:string_join].map(&:strip).uniq + def build_join_query(manager, buckets, join_type) + buckets.default = [] - join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins) + association_joins = buckets[:association_join] + stashed_association_joins = buckets[:stashed_join] + join_nodes = buckets[:join_node].uniq + string_joins = buckets[:string_join].map(&:strip).uniq - join_dependency = ActiveRecord::Associations::JoinDependency.new( - @klass, - association_joins, - join_list - ) + join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins) - join_infos = join_dependency.join_constraints stashed_association_joins, join_type + join_dependency = ActiveRecord::Associations::JoinDependency.new( + @klass, + association_joins, + join_list + ) - join_infos.each do |info| - info.joins.each { |join| manager.from(join) } - manager.bind_values.concat info.binds - end + join_infos = join_dependency.join_constraints stashed_association_joins, join_type - manager.join_sources.concat(join_list) + join_infos.each do |info| + info.joins.each { |join| manager.from(join) } + manager.bind_values.concat info.binds + end - manager - end + manager.join_sources.concat(join_list) - def convert_join_strings_to_ast(table, joins) - joins - .flatten - .reject(&:blank?) - .map { |join| table.create_string_join(Arel.sql(join)) } - end + manager + end - def build_select(arel) - if select_values.any? - arel.project(*arel_columns(select_values.uniq)) - else - arel.project(@klass.arel_table[Arel.star]) + def convert_join_strings_to_ast(table, joins) + joins + .flatten + .reject(&:blank?) + .map { |join| table.create_string_join(Arel.sql(join)) } end - end - def arel_columns(columns) - columns.map do |field| - if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value - arel_attribute(field) - elsif Symbol === field - connection.quote_table_name(field.to_s) + def build_select(arel) + if select_values.any? + arel.project(*arel_columns(select_values.uniq)) else - field + arel.project(@klass.arel_table[Arel.star]) end end - end - def reverse_sql_order(order_query) - if order_query.empty? - return [arel_attribute(primary_key).desc] if primary_key - raise IrreversibleOrderError, - "Relation has no current order and table has no primary key to be used as default order" + def arel_columns(columns) + columns.map do |field| + if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value + arel_attribute(field) + elsif Symbol === field + connection.quote_table_name(field.to_s) + else + field + end + end end - order_query.flat_map do |o| - case o - when Arel::Attribute - o.desc - when Arel::Nodes::Ordering - o.reverse - when String - if does_not_support_reverse?(o) - raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically" - end - o.split(',').map! do |s| - s.strip! - s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') + def reverse_sql_order(order_query) + if order_query.empty? + return [arel_attribute(primary_key).desc] if primary_key + raise IrreversibleOrderError, + "Relation has no current order and table has no primary key to be used as default order" + end + + order_query.flat_map do |o| + case o + when Arel::Attribute + o.desc + when Arel::Nodes::Ordering + o.reverse + when String + if does_not_support_reverse?(o) + raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically" + end + o.split(",").map! do |s| + s.strip! + s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s.concat(" DESC") + end + else + o end - else - o end end - end - def does_not_support_reverse?(order) - #uses sql function with multiple arguments - order =~ /\([^()]*,[^()]*\)/ || - # uses "nulls first" like construction - order =~ /nulls (first|last)\Z/i - end + def does_not_support_reverse?(order) + # Uses SQL function with multiple arguments. + (order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) || + # Uses "nulls first" like construction. + /nulls (first|last)\Z/i.match?(order) + end - def build_order(arel) - orders = order_values.uniq - orders.reject!(&:blank?) + def build_order(arel) + orders = order_values.uniq + orders.reject!(&:blank?) - arel.order(*orders) unless orders.empty? - end + arel.order(*orders) unless orders.empty? + end - VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC, - 'asc', 'desc', 'ASC', 'DESC'] # :nodoc: + VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC, + "asc", "desc", "ASC", "DESC"] # :nodoc: - def validate_order_args(args) - args.each do |arg| - next unless arg.is_a?(Hash) - arg.each do |_key, value| - raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \ - "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value) + def validate_order_args(args) + args.each do |arg| + next unless arg.is_a?(Hash) + arg.each do |_key, value| + raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \ + "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value) + end end end - end - def preprocess_order_args(order_args) - order_args.map! do |arg| - klass.send(:sanitize_sql_for_order, arg) + def preprocess_order_args(order_args) + order_args.map! do |arg| + klass.send(:sanitize_sql_for_order, arg) + end + order_args.flatten! + validate_order_args(order_args) + + references = order_args.grep(String) + references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact! + references!(references) if references.any? + + # if a symbol is given we prepend the quoted table name + order_args.map! do |arg| + case arg + when Symbol + arel_attribute(arg).asc + when Hash + arg.map { |field, dir| + arel_attribute(field).send(dir.downcase) + } + else + arg + end + end.flatten! end - order_args.flatten! - validate_order_args(order_args) - - references = order_args.grep(String) - references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact! - references!(references) if references.any? - # if a symbol is given we prepend the quoted table name - order_args.map! do |arg| - case arg - when Symbol - arel_attribute(arg).asc - when Hash - arg.map { |field, dir| - arel_attribute(field).send(dir.downcase) - } - else - arg + # Checks to make sure that the arguments are not blank. Note that if some + # blank-like object were initially passed into the query method, then this + # method will not raise an error. + # + # Example: + # + # Post.references() # raises an error + # Post.references([]) # does not raise an error + # + # This particular method should be called with a method_name and the args + # passed into that method as an input. For example: + # + # def references(*args) + # check_if_method_has_arguments!("references", args) + # ... + # end + def check_if_method_has_arguments!(method_name, args) + if args.blank? + raise ArgumentError, "The method .#{method_name}() must contain arguments." end - end.flatten! - end - - # Checks to make sure that the arguments are not blank. Note that if some - # blank-like object were initially passed into the query method, then this - # method will not raise an error. - # - # Example: - # - # Post.references() # raises an error - # Post.references([]) # does not raise an error - # - # This particular method should be called with a method_name and the args - # passed into that method as an input. For example: - # - # def references(*args) - # check_if_method_has_arguments!("references", args) - # ... - # end - def check_if_method_has_arguments!(method_name, args) - if args.blank? - raise ArgumentError, "The method .#{method_name}() must contain arguments." end - end - def structurally_incompatible_values_for_or(other) - Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } + - (Relation::MULTI_VALUE_METHODS - [:extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } + - (Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") } - end - - def new_where_clause - Relation::WhereClause.empty - end - alias new_having_clause new_where_clause + STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having] + def structurally_incompatible_values_for_or(other) + STRUCTURAL_OR_METHODS.reject do |method| + get_value(method) == other.get_value(method) + end + end - def where_clause_factory - @where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder) - end - alias having_clause_factory where_clause_factory + def where_clause_factory + @where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder) + end + alias having_clause_factory where_clause_factory - def new_from_clause - Relation::FromClause.empty - end + def string_containing_comma?(value) + ::String === value && value.include?(",") + end - def string_containing_comma?(value) - ::String === value && value.include?(",") - end + def default_value_for(name) + case name + when :create_with + FROZEN_EMPTY_HASH + when :readonly + false + when :where, :having + Relation::WhereClause.empty + when :from + Relation::FromClause.empty + when *Relation::MULTI_VALUE_METHODS + FROZEN_EMPTY_ARRAY + when *Relation::SINGLE_VALUE_METHODS + nil + else + raise ArgumentError, "unknown relation value #{name.inspect}" + end + end end end diff --git a/activerecord/lib/active_record/relation/record_fetch_warning.rb b/activerecord/lib/active_record/relation/record_fetch_warning.rb index dbd08811fa..31544c730e 100644 --- a/activerecord/lib/active_record/relation/record_fetch_warning.rb +++ b/activerecord/lib/active_record/relation/record_fetch_warning.rb @@ -2,15 +2,15 @@ module ActiveRecord class Relation module RecordFetchWarning # When this module is prepended to ActiveRecord::Relation and - # `config.active_record.warn_on_records_fetched_greater_than` is + # +config.active_record.warn_on_records_fetched_greater_than+ is # set to an integer, if the number of records a query returns is - # greater than the value of `warn_on_records_fetched_greater_than`, + # greater than the value of +warn_on_records_fetched_greater_than+, # a warning is logged. This allows for the detection of queries that # return a large number of records, which could cause memory bloat. # # In most cases, fetching large number of records can be performed # efficiently using the ActiveRecord::Batches methods. - # See active_record/lib/relation/batches.rb for more information. + # See ActiveRecord::Batches for more information. def exec_queries QueryRegistry.reset diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index d5c18a2a4a..190e339ea8 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -1,10 +1,9 @@ -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/slice' -require 'active_record/relation/merger' +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" +require "active_record/relation/merger" module ActiveRecord module SpawnMethods - # This is overridden by Associations::CollectionProxy def spawn #:nodoc: clone diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb index 89396b518c..402f8acfd1 100644 --- a/activerecord/lib/active_record/relation/where_clause.rb +++ b/activerecord/lib/active_record/relation/where_clause.rb @@ -86,89 +86,89 @@ module ActiveRecord protected - attr_reader :predicates + attr_reader :predicates - def referenced_columns - @referenced_columns ||= begin - equality_nodes = predicates.select { |n| equality_node?(n) } - Set.new(equality_nodes, &:left) + def referenced_columns + @referenced_columns ||= begin + equality_nodes = predicates.select { |n| equality_node?(n) } + Set.new(equality_nodes, &:left) + end end - end private - def predicates_unreferenced_by(other) - predicates.reject do |n| - equality_node?(n) && other.referenced_columns.include?(n.left) + def predicates_unreferenced_by(other) + predicates.reject do |n| + equality_node?(n) && other.referenced_columns.include?(n.left) + end end - end - def equality_node?(node) - node.respond_to?(:operator) && node.operator == :== - end - - def non_conflicting_binds(other) - conflicts = referenced_columns & other.referenced_columns - conflicts.map! { |node| node.name.to_s } - binds.reject { |attr| conflicts.include?(attr.name) } - end + def equality_node?(node) + node.respond_to?(:operator) && node.operator == :== + end - def inverted_predicates - predicates.map { |node| invert_predicate(node) } - end + def non_conflicting_binds(other) + conflicts = referenced_columns & other.referenced_columns + conflicts.map! { |node| node.name.to_s } + binds.reject { |attr| conflicts.include?(attr.name) } + end - def invert_predicate(node) - case node - when NilClass - raise ArgumentError, 'Invalid argument for .where.not(), got nil.' - when Arel::Nodes::In - Arel::Nodes::NotIn.new(node.left, node.right) - when Arel::Nodes::Equality - Arel::Nodes::NotEqual.new(node.left, node.right) - when String - Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node)) - else - Arel::Nodes::Not.new(node) + def inverted_predicates + predicates.map { |node| invert_predicate(node) } end - end - def predicates_except(columns) - predicates.reject do |node| + def invert_predicate(node) case node - when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual - subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right) - columns.include?(subrelation.name.to_s) + when NilClass + raise ArgumentError, "Invalid argument for .where.not(), got nil." + when Arel::Nodes::In + Arel::Nodes::NotIn.new(node.left, node.right) + when Arel::Nodes::Equality + Arel::Nodes::NotEqual.new(node.left, node.right) + when String + Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node)) + else + Arel::Nodes::Not.new(node) end end - end - def binds_except(columns) - binds.reject do |attr| - columns.include?(attr.name) + def predicates_except(columns) + predicates.reject do |node| + case node + when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual + subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right) + columns.include?(subrelation.name.to_s) + end + end end - end - def predicates_with_wrapped_sql_literals - non_empty_predicates.map do |node| - if Arel::Nodes::Equality === node - node - else - wrap_sql_literal(node) + def binds_except(columns) + binds.reject do |attr| + columns.include?(attr.name) end end - end - ARRAY_WITH_EMPTY_STRING = [''] - def non_empty_predicates - predicates - ARRAY_WITH_EMPTY_STRING - end + def predicates_with_wrapped_sql_literals + non_empty_predicates.map do |node| + if Arel::Nodes::Equality === node + node + else + wrap_sql_literal(node) + end + end + end - def wrap_sql_literal(node) - if ::String === node - node = Arel.sql(node) + ARRAY_WITH_EMPTY_STRING = [""] + def non_empty_predicates + predicates - ARRAY_WITH_EMPTY_STRING + end + + def wrap_sql_literal(node) + if ::String === node + node = Arel.sql(node) + end + Arel::Nodes::Grouping.new(node) end - Arel::Nodes::Grouping.new(node) - end end end end diff --git a/activerecord/lib/active_record/relation/where_clause_factory.rb b/activerecord/lib/active_record/relation/where_clause_factory.rb index dbf172a577..1e7deeffad 100644 --- a/activerecord/lib/active_record/relation/where_clause_factory.rb +++ b/activerecord/lib/active_record/relation/where_clause_factory.rb @@ -7,8 +7,6 @@ module ActiveRecord end def build(opts, other) - binds = [] - case opts when String, Array parts = [klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))] @@ -22,17 +20,16 @@ module ActiveRecord parts = predicate_builder.build_from_hash(attributes) when Arel::Nodes::Node parts = [opts] - binds = other else raise ArgumentError, "Unsupported argument type: #{opts} (#{opts.class})" end - WhereClause.new(parts, binds) + WhereClause.new(parts, binds || []) end protected - attr_reader :klass, :predicate_builder + attr_reader :klass, :predicate_builder end end end diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb index 8e6cd6c82f..9ed70a9c2b 100644 --- a/activerecord/lib/active_record/result.rb +++ b/activerecord/lib/active_record/result.rb @@ -32,8 +32,6 @@ module ActiveRecord class Result include Enumerable - IDENTITY_TYPE = Type::Value.new # :nodoc: - attr_reader :columns, :rows, :column_types def initialize(columns, rows, column_types = {}) @@ -75,8 +73,14 @@ module ActiveRecord hash_rows[idx] end + def first + return nil if @rows.empty? + Hash[@columns.zip(@rows.first)] + end + def last - hash_rows.last + return nil if @rows.empty? + Hash[@columns.zip(@rows.last)] end def cast_values(type_overrides = {}) # :nodoc: @@ -97,36 +101,36 @@ module ActiveRecord private - def column_type(name, type_overrides = {}) - type_overrides.fetch(name) do - column_types.fetch(name, IDENTITY_TYPE) + def column_type(name, type_overrides = {}) + type_overrides.fetch(name) do + column_types.fetch(name, Type.default_value) + end end - end - def hash_rows - @hash_rows ||= - begin - # We freeze the strings to prevent them getting duped when - # used as keys in ActiveRecord::Base's @attributes hash - columns = @columns.map { |c| c.dup.freeze } - @rows.map { |row| - # In the past we used Hash[columns.zip(row)] - # though elegant, the verbose way is much more efficient - # both time and memory wise cause it avoids a big array allocation - # this method is called a lot and needs to be micro optimised - hash = {} - - index = 0 - length = columns.length - - while index < length - hash[columns[index]] = row[index] - index += 1 - end - - hash - } - end - end + def hash_rows + @hash_rows ||= + begin + # We freeze the strings to prevent them getting duped when + # used as keys in ActiveRecord::Base's @attributes hash + columns = @columns.map { |c| c.dup.freeze } + @rows.map { |row| + # In the past we used Hash[columns.zip(row)] + # though elegant, the verbose way is much more efficient + # both time and memory wise cause it avoids a big array allocation + # this method is called a lot and needs to be micro optimised + hash = {} + + index = 0 + length = columns.length + + while index < length + hash[columns[index]] = row[index] + index += 1 + end + + hash + } + end + end end end diff --git a/activerecord/lib/active_record/runtime_registry.rb b/activerecord/lib/active_record/runtime_registry.rb index 56e88bc661..b79eb2263f 100644 --- a/activerecord/lib/active_record/runtime_registry.rb +++ b/activerecord/lib/active_record/runtime_registry.rb @@ -1,4 +1,4 @@ -require 'active_support/per_thread_registry' +require "active_support/per_thread_registry" module ActiveRecord # This is a thread locals registry for Active Record. For example: @@ -12,9 +12,9 @@ module ActiveRecord class RuntimeRegistry # :nodoc: extend ActiveSupport::PerThreadRegistry - attr_accessor :connection_handler, :sql_runtime, :connection_id + attr_accessor :connection_handler, :sql_runtime - [:connection_handler, :sql_runtime, :connection_id].each do |val| + [:connection_handler, :sql_runtime].each do |val| class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__ class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__ end diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index a9e1fd0dad..e7c0936984 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -1,220 +1,216 @@ +require "active_support/core_ext/regexp" + module ActiveRecord module Sanitization extend ActiveSupport::Concern module ClassMethods - # Used to sanitize objects before they're used in an SQL SELECT statement. - # Delegates to {connection.quote}[rdoc-ref:ConnectionAdapters::Quoting#quote]. - def sanitize(object) # :nodoc: - connection.quote(object) - end - alias_method :quote_value, :sanitize - protected - # Accepts an array or string of SQL conditions and sanitizes - # them into a valid SQL fragment for a WHERE clause. - # - # sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4]) - # # => "name='foo''bar' and group_id=4" - # - # sanitize_sql_for_conditions(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4]) - # # => "name='foo''bar' and group_id='4'" - # - # sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4]) - # # => "name='foo''bar' and group_id='4'" - # - # sanitize_sql_for_conditions("name='foo''bar' and group_id='4'") - # # => "name='foo''bar' and group_id='4'" - def sanitize_sql_for_conditions(condition) - return nil if condition.blank? - - case condition - when Array; sanitize_sql_array(condition) - else condition + # Accepts an array or string of SQL conditions and sanitizes + # them into a valid SQL fragment for a WHERE clause. + # + # sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4]) + # # => "name='foo''bar' and group_id=4" + # + # sanitize_sql_for_conditions(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4]) + # # => "name='foo''bar' and group_id='4'" + # + # sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4]) + # # => "name='foo''bar' and group_id='4'" + # + # sanitize_sql_for_conditions("name='foo''bar' and group_id='4'") + # # => "name='foo''bar' and group_id='4'" + def sanitize_sql_for_conditions(condition) + return nil if condition.blank? + + case condition + when Array; sanitize_sql_array(condition) + else condition + end end - end - alias_method :sanitize_sql, :sanitize_sql_for_conditions - alias_method :sanitize_conditions, :sanitize_sql - - # Accepts an array, hash, or string of SQL conditions and sanitizes - # them into a valid SQL fragment for a SET clause. - # - # sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4]) - # # => "name=NULL and group_id=4" - # - # sanitize_sql_for_assignment(["name=:name and group_id=:group_id", name: nil, group_id: 4]) - # # => "name=NULL and group_id=4" - # - # Post.send(:sanitize_sql_for_assignment, { name: nil, group_id: 4 }) - # # => "`posts`.`name` = NULL, `posts`.`group_id` = 4" - # - # sanitize_sql_for_assignment("name=NULL and group_id='4'") - # # => "name=NULL and group_id='4'" - def sanitize_sql_for_assignment(assignments, default_table_name = self.table_name) - case assignments - when Array; sanitize_sql_array(assignments) - when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name) - else assignments + alias :sanitize_sql :sanitize_sql_for_conditions + alias :sanitize_conditions :sanitize_sql + deprecate sanitize_conditions: :sanitize_sql + + # Accepts an array, hash, or string of SQL conditions and sanitizes + # them into a valid SQL fragment for a SET clause. + # + # sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4]) + # # => "name=NULL and group_id=4" + # + # sanitize_sql_for_assignment(["name=:name and group_id=:group_id", name: nil, group_id: 4]) + # # => "name=NULL and group_id=4" + # + # Post.send(:sanitize_sql_for_assignment, { name: nil, group_id: 4 }) + # # => "`posts`.`name` = NULL, `posts`.`group_id` = 4" + # + # sanitize_sql_for_assignment("name=NULL and group_id='4'") + # # => "name=NULL and group_id='4'" + def sanitize_sql_for_assignment(assignments, default_table_name = self.table_name) + case assignments + when Array; sanitize_sql_array(assignments) + when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name) + else assignments + end end - end - - # Accepts an array, or string of SQL conditions and sanitizes - # them into a valid SQL fragment for an ORDER clause. - # - # sanitize_sql_for_order(["field(id, ?)", [1,3,2]]) - # # => "field(id, 1,3,2)" - # - # sanitize_sql_for_order("id ASC") - # # => "id ASC" - def sanitize_sql_for_order(condition) - if condition.is_a?(Array) && condition.first.to_s.include?('?') - sanitize_sql_array(condition) - else - condition + + # Accepts an array, or string of SQL conditions and sanitizes + # them into a valid SQL fragment for an ORDER clause. + # + # sanitize_sql_for_order(["field(id, ?)", [1,3,2]]) + # # => "field(id, 1,3,2)" + # + # sanitize_sql_for_order("id ASC") + # # => "id ASC" + def sanitize_sql_for_order(condition) + if condition.is_a?(Array) && condition.first.to_s.include?("?") + sanitize_sql_array(condition) + else + condition + end end - end - - # Accepts a hash of SQL conditions and replaces those attributes - # that correspond to a {#composed_of}[rdoc-ref:Aggregations::ClassMethods#composed_of] - # relationship with their expanded aggregate attribute values. - # - # Given: - # - # class Person < ActiveRecord::Base - # composed_of :address, class_name: "Address", - # mapping: [%w(address_street street), %w(address_city city)] - # end - # - # Then: - # - # { address: Address.new("813 abc st.", "chicago") } - # # => { address_street: "813 abc st.", address_city: "chicago" } - def expand_hash_conditions_for_aggregates(attrs) - expanded_attrs = {} - attrs.each do |attr, value| - if aggregation = reflect_on_aggregation(attr.to_sym) - mapping = aggregation.mapping - mapping.each do |field_attr, aggregate_attr| - if mapping.size == 1 && !value.respond_to?(aggregate_attr) - expanded_attrs[field_attr] = value - else - expanded_attrs[field_attr] = value.send(aggregate_attr) + + # Accepts a hash of SQL conditions and replaces those attributes + # that correspond to a {#composed_of}[rdoc-ref:Aggregations::ClassMethods#composed_of] + # relationship with their expanded aggregate attribute values. + # + # Given: + # + # class Person < ActiveRecord::Base + # composed_of :address, class_name: "Address", + # mapping: [%w(address_street street), %w(address_city city)] + # end + # + # Then: + # + # { address: Address.new("813 abc st.", "chicago") } + # # => { address_street: "813 abc st.", address_city: "chicago" } + def expand_hash_conditions_for_aggregates(attrs) + expanded_attrs = {} + attrs.each do |attr, value| + if aggregation = reflect_on_aggregation(attr.to_sym) + mapping = aggregation.mapping + mapping.each do |field_attr, aggregate_attr| + if mapping.size == 1 && !value.respond_to?(aggregate_attr) + expanded_attrs[field_attr] = value + else + expanded_attrs[field_attr] = value.send(aggregate_attr) + end end + else + expanded_attrs[attr] = value end - else - expanded_attrs[attr] = value end + expanded_attrs end - expanded_attrs - end - - # Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause. - # - # sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts") - # # => "`posts`.`status` = NULL, `posts`.`group_id` = 1" - def sanitize_sql_hash_for_assignment(attrs, table) - c = connection - attrs.map do |attr, value| - value = type_for_attribute(attr.to_s).serialize(value) - "#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}" - end.join(', ') - end - - # Sanitizes a +string+ so that it is safe to use within an SQL - # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%". - # - # sanitize_sql_like("100%") - # # => "100\\%" - # - # sanitize_sql_like("snake_cased_string") - # # => "snake\\_cased\\_string" - # - # sanitize_sql_like("100%", "!") - # # => "100!%" - # - # sanitize_sql_like("snake_cased_string", "!") - # # => "snake!_cased!_string" - def sanitize_sql_like(string, escape_character = "\\") - pattern = Regexp.union(escape_character, "%", "_") - string.gsub(pattern) { |x| [escape_character, x].join } - end - - # Accepts an array of conditions. The array has each value - # sanitized and interpolated into the SQL statement. - # - # sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4]) - # # => "name='foo''bar' and group_id=4" - # - # sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4]) - # # => "name='foo''bar' and group_id=4" - # - # sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4]) - # # => "name='foo''bar' and group_id='4'" - def sanitize_sql_array(ary) - statement, *values = ary - if values.first.is_a?(Hash) && statement =~ /:\w+/ - replace_named_bind_variables(statement, values.first) - elsif statement.include?('?') - replace_bind_variables(statement, values) - elsif statement.blank? - statement - else - statement % values.collect { |value| connection.quote_string(value.to_s) } + + # Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause. + # + # sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts") + # # => "`posts`.`status` = NULL, `posts`.`group_id` = 1" + def sanitize_sql_hash_for_assignment(attrs, table) + c = connection + attrs.map do |attr, value| + value = type_for_attribute(attr.to_s).serialize(value) + "#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}" + end.join(", ") end - end - - def replace_bind_variables(statement, values) # :nodoc: - raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size) - bound = values.dup - c = connection - statement.gsub(/\?/) do - replace_bind_variable(bound.shift, c) + + # Sanitizes a +string+ so that it is safe to use within an SQL + # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%". + # + # sanitize_sql_like("100%") + # # => "100\\%" + # + # sanitize_sql_like("snake_cased_string") + # # => "snake\\_cased\\_string" + # + # sanitize_sql_like("100%", "!") + # # => "100!%" + # + # sanitize_sql_like("snake_cased_string", "!") + # # => "snake!_cased!_string" + def sanitize_sql_like(string, escape_character = "\\") + pattern = Regexp.union(escape_character, "%", "_") + string.gsub(pattern) { |x| [escape_character, x].join } end - end - def replace_bind_variable(value, c = connection) # :nodoc: - if ActiveRecord::Relation === value - value.to_sql - else - quote_bound_value(value, c) + # Accepts an array of conditions. The array has each value + # sanitized and interpolated into the SQL statement. + # + # sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4]) + # # => "name='foo''bar' and group_id=4" + # + # sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4]) + # # => "name='foo''bar' and group_id=4" + # + # sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4]) + # # => "name='foo''bar' and group_id='4'" + def sanitize_sql_array(ary) + statement, *values = ary + if values.first.is_a?(Hash) && /:\w+/.match?(statement) + replace_named_bind_variables(statement, values.first) + elsif statement.include?("?") + replace_bind_variables(statement, values) + elsif statement.blank? + statement + else + statement % values.collect { |value| connection.quote_string(value.to_s) } + end + end + + def replace_bind_variables(statement, values) # :nodoc: + raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size) + bound = values.dup + c = connection + statement.gsub(/\?/) do + replace_bind_variable(bound.shift, c) + end end - end - - def replace_named_bind_variables(statement, bind_vars) # :nodoc: - statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match| - if $1 == ':' # skip postgresql casts - match # return the whole match - elsif bind_vars.include?(match = $2.to_sym) - replace_bind_variable(bind_vars[match]) + + def replace_bind_variable(value, c = connection) # :nodoc: + if ActiveRecord::Relation === value + value.to_sql else - raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}" + quote_bound_value(value, c) end end - end - def quote_bound_value(value, c = connection) # :nodoc: - if value.respond_to?(:map) && !value.acts_like?(:string) - if value.respond_to?(:empty?) && value.empty? - c.quote(nil) + def replace_named_bind_variables(statement, bind_vars) # :nodoc: + statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match| + if $1 == ":" # skip postgresql casts + match # return the whole match + elsif bind_vars.include?(match = $2.to_sym) + replace_bind_variable(bind_vars[match]) + else + raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}" + end + end + end + + def quote_bound_value(value, c = connection) # :nodoc: + if value.respond_to?(:map) && !value.acts_like?(:string) + if value.respond_to?(:empty?) && value.empty? + c.quote(nil) + else + value.map { |v| c.quote(v) }.join(",") + end else - value.map { |v| c.quote(v) }.join(',') + c.quote(value) end - else - c.quote(value) end - end - def raise_if_bind_arity_mismatch(statement, expected, provided) # :nodoc: - unless expected == provided - raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}" + def raise_if_bind_arity_mismatch(statement, expected, provided) # :nodoc: + unless expected == provided + raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}" + end end - end end # TODO: Deprecate this def quoted_id # :nodoc: - self.class.quote_value(@attributes[self.class.primary_key].value_for_database) + self.class.connection.quote(@attributes[self.class.primary_key].value_for_database) end end end diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index d769376d1a..c1c6519cfa 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -1,4 +1,4 @@ -require 'stringio' +require "stringio" module ActiveRecord # = Active Record Schema Dumper @@ -105,24 +105,17 @@ HEADER tbl = StringIO.new # first dump primary key column - if @connection.respond_to?(:primary_keys) - pk = @connection.primary_keys(table) - pk = pk.first unless pk.size > 1 - else - pk = @connection.primary_key(table) - end + pk = @connection.primary_key(table) tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}" case pk when String - tbl.print ", primary_key: #{pk.inspect}" unless pk == 'id' + tbl.print ", primary_key: #{pk.inspect}" unless pk == "id" pkcol = columns.detect { |c| c.name == pk } pkcolspec = @connection.column_spec_for_primary_key(pkcol) if pkcolspec.present? - pkcolspec.each do |key, value| - tbl.print ", #{key}: #{value}" - end + tbl.print ", #{format_colspec(pkcolspec)}" end when Array tbl.print ", primary_key: #{pk.inspect}" @@ -132,46 +125,19 @@ HEADER tbl.print ", force: :cascade" table_options = @connection.table_options(table) - tbl.print ", options: #{table_options.inspect}" unless table_options.blank? - - if comment = @connection.table_comment(table).presence - tbl.print ", comment: #{comment.inspect}" + if table_options.present? + tbl.print ", #{format_options(table_options)}" end tbl.puts " do |t|" # then dump all non-primary key columns - column_specs = columns.map do |column| + columns.each do |column| raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type) next if column.name == pk - @connection.column_spec(column) - end.compact - - # find all migration keys used in this table - keys = @connection.migration_keys - - # figure out the lengths for each column based on above keys - lengths = keys.map { |key| - column_specs.map { |spec| - spec[key] ? spec[key].length + 2 : 0 - }.max - } - - # the string we're going to sprintf our values against, with standardized column widths - format_string = lengths.map{ |len| "%-#{len}s" } - - # find the max length for the 'type' column, which is special - type_length = column_specs.map{ |column| column[:type].length }.max - - # add column type definition to our format string - format_string.unshift " t.%-#{type_length}s " - - format_string *= '' - - column_specs.each do |colspec| - values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len } - values.unshift colspec[:type] - tbl.print((format_string % values).gsub(/,\s*$/, '')) + type, colspec = @connection.column_spec(column) + tbl.print " t.#{type} #{column.name.inspect}" + tbl.print ", #{format_colspec(colspec)}" if colspec.present? tbl.puts end @@ -218,13 +184,9 @@ HEADER index.columns.inspect, "name: #{index.name.inspect}", ] - index_parts << 'unique: true' if index.unique - - index_lengths = (index.lengths || []).compact - index_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any? - - index_orders = index.orders || {} - index_parts << "order: #{index.orders.inspect}" if index_orders.any? + index_parts << "unique: true" if index.unique + index_parts << "length: { #{format_options(index.lengths)} }" if index.lengths.present? + index_parts << "order: { #{format_options(index.orders)} }" if index.orders.present? index_parts << "where: #{index.where.inspect}" if index.where index_parts << "using: #{index.using.inspect}" if index.using index_parts << "type: #{index.type.inspect}" if index.type @@ -262,6 +224,14 @@ HEADER end end + def format_colspec(colspec) + colspec.map { |key, value| "#{key}: #{value}" }.join(", ") + end + + def format_options(options) + options.map { |key, value| "#{key}: #{value.inspect}" }.join(", ") + end + def remove_prefix_and_suffix(table) table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2") end diff --git a/activerecord/lib/active_record/schema_migration.rb b/activerecord/lib/active_record/schema_migration.rb index b6cb233e03..99b23e5593 100644 --- a/activerecord/lib/active_record/schema_migration.rb +++ b/activerecord/lib/active_record/schema_migration.rb @@ -1,5 +1,5 @@ -require 'active_record/scoping/default' -require 'active_record/scoping/named' +require "active_record/scoping/default" +require "active_record/scoping/named" module ActiveRecord # This class is used to create a table that keeps track of which migrations diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb index 7794af8ca4..d1bd1cd89a 100644 --- a/activerecord/lib/active_record/scoping.rb +++ b/activerecord/lib/active_record/scoping.rb @@ -1,4 +1,4 @@ -require 'active_support/per_thread_registry' +require "active_support/per_thread_registry" module ActiveRecord module Scoping @@ -94,11 +94,11 @@ module ActiveRecord private - def raise_invalid_scope_type!(scope_type) - if !VALID_SCOPE_TYPES.include?(scope_type) - raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES" + def raise_invalid_scope_type!(scope_type) + if !VALID_SCOPE_TYPES.include?(scope_type) + raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES" + end end - end end end end diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb index 9eab59ac78..9d8253faa3 100644 --- a/activerecord/lib/active_record/scoping/default.rb +++ b/activerecord/lib/active_record/scoping/default.rb @@ -46,103 +46,103 @@ module ActiveRecord protected - # Use this macro in your model to set a default scope for all operations on - # the model. - # - # class Article < ActiveRecord::Base - # default_scope { where(published: true) } - # end - # - # Article.all # => SELECT * FROM articles WHERE published = true - # - # The #default_scope is also applied while creating/building a record. - # It is not applied while updating a record. - # - # Article.new.published # => true - # Article.create.published # => true - # - # (You can also pass any object which responds to +call+ to the - # +default_scope+ macro, and it will be called when building the - # default scope.) - # - # If you use multiple #default_scope declarations in your model then - # they will be merged together: - # - # class Article < ActiveRecord::Base - # default_scope { where(published: true) } - # default_scope { where(rating: 'G') } - # end - # - # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G' - # - # This is also the case with inheritance and module includes where the - # parent or module defines a #default_scope and the child or including - # class defines a second one. - # - # If you need to do more complex things with a default scope, you can - # alternatively define it as a class method: - # - # class Article < ActiveRecord::Base - # def self.default_scope - # # Should return a scope, you can call 'super' here etc. - # end - # end - def default_scope(scope = nil) - scope = Proc.new if block_given? - - if scope.is_a?(Relation) || !scope.respond_to?(:call) - raise ArgumentError, - "Support for calling #default_scope without a block is removed. For example instead " \ - "of `default_scope where(color: 'red')`, please use " \ - "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \ - "self.default_scope.)" - end + # Use this macro in your model to set a default scope for all operations on + # the model. + # + # class Article < ActiveRecord::Base + # default_scope { where(published: true) } + # end + # + # Article.all # => SELECT * FROM articles WHERE published = true + # + # The #default_scope is also applied while creating/building a record. + # It is not applied while updating a record. + # + # Article.new.published # => true + # Article.create.published # => true + # + # (You can also pass any object which responds to +call+ to the + # +default_scope+ macro, and it will be called when building the + # default scope.) + # + # If you use multiple #default_scope declarations in your model then + # they will be merged together: + # + # class Article < ActiveRecord::Base + # default_scope { where(published: true) } + # default_scope { where(rating: 'G') } + # end + # + # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G' + # + # This is also the case with inheritance and module includes where the + # parent or module defines a #default_scope and the child or including + # class defines a second one. + # + # If you need to do more complex things with a default scope, you can + # alternatively define it as a class method: + # + # class Article < ActiveRecord::Base + # def self.default_scope + # # Should return a scope, you can call 'super' here etc. + # end + # end + def default_scope(scope = nil) + scope = Proc.new if block_given? + + if scope.is_a?(Relation) || !scope.respond_to?(:call) + raise ArgumentError, + "Support for calling #default_scope without a block is removed. For example instead " \ + "of `default_scope where(color: 'red')`, please use " \ + "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \ + "self.default_scope.)" + end - self.default_scopes += [scope] - end + self.default_scopes += [scope] + end - def build_default_scope(base_rel = nil) # :nodoc: - return if abstract_class? + def build_default_scope(base_rel = nil) # :nodoc: + return if abstract_class? - if self.default_scope_override.nil? - self.default_scope_override = !Base.is_a?(method(:default_scope).owner) - end + if default_scope_override.nil? + self.default_scope_override = !Base.is_a?(method(:default_scope).owner) + end - if self.default_scope_override - # The user has defined their own default scope method, so call that - evaluate_default_scope { default_scope } - elsif default_scopes.any? - base_rel ||= relation - evaluate_default_scope do - default_scopes.inject(base_rel) do |default_scope, scope| - scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call) - default_scope.merge(base_rel.instance_exec(&scope)) + if default_scope_override + # The user has defined their own default scope method, so call that + evaluate_default_scope { default_scope } + elsif default_scopes.any? + base_rel ||= relation + evaluate_default_scope do + default_scopes.inject(base_rel) do |default_scope, scope| + scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call) + default_scope.merge(base_rel.instance_exec(&scope)) + end end end end - end - def ignore_default_scope? # :nodoc: - ScopeRegistry.value_for(:ignore_default_scope, base_class) - end + def ignore_default_scope? # :nodoc: + ScopeRegistry.value_for(:ignore_default_scope, base_class) + end - def ignore_default_scope=(ignore) # :nodoc: - ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore) - end + def ignore_default_scope=(ignore) # :nodoc: + ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore) + end - # The ignore_default_scope flag is used to prevent an infinite recursion - # situation where a default scope references a scope which has a default - # scope which references a scope... - def evaluate_default_scope # :nodoc: - return if ignore_default_scope? - - begin - self.ignore_default_scope = true - yield - ensure - self.ignore_default_scope = false + # The ignore_default_scope flag is used to prevent an infinite recursion + # situation where a default scope references a scope which has a default + # scope which references a scope... + def evaluate_default_scope # :nodoc: + return if ignore_default_scope? + + begin + self.ignore_default_scope = true + yield + ensure + self.ignore_default_scope = false + end end - end end end end diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb index 5395bd6076..094c0e9c6f 100644 --- a/activerecord/lib/active_record/scoping/named.rb +++ b/activerecord/lib/active_record/scoping/named.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/array' -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/kernel/singleton_class' +require "active_support/core_ext/array" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/kernel/singleton_class" module ActiveRecord # = Active Record \Named \Scopes @@ -142,7 +142,7 @@ module ActiveRecord # Article.featured.titles def scope(name, body, &block) unless body.respond_to?(:call) - raise ArgumentError, 'The scope body needs to be callable.' + raise ArgumentError, "The scope body needs to be callable." end if dangerous_class_method?(name) @@ -174,7 +174,7 @@ module ActiveRecord protected def valid_scope_name?(name) - if respond_to?(name, true) + if respond_to?(name, true) && logger logger.warn "Creating scope :#{name}. " \ "Overwriting existing method #{self.name}.#{name}." end diff --git a/activerecord/lib/active_record/secure_token.rb b/activerecord/lib/active_record/secure_token.rb index 8abda2ac49..7606961e2e 100644 --- a/activerecord/lib/active_record/secure_token.rb +++ b/activerecord/lib/active_record/secure_token.rb @@ -25,9 +25,9 @@ module ActiveRecord # You're encouraged to add a unique index in the database to deal with this even more unlikely scenario. def has_secure_token(attribute = :token) # Load securerandom only when has_secure_token is used. - require 'active_support/core_ext/securerandom' + require "active_support/core_ext/securerandom" define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token } - before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token) unless self.send("#{attribute}?")} + before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token) unless self.send("#{attribute}?") } end def generate_unique_secure_token diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb index 6c896ccea6..691940ab70 100644 --- a/activerecord/lib/active_record/statement_cache.rb +++ b/activerecord/lib/active_record/statement_cache.rb @@ -1,5 +1,4 @@ module ActiveRecord - # Statement cache is used to cache a single statement in order to avoid creating the AST again. # Initializing the cache is done by passing the statement in the create block: # @@ -8,12 +7,12 @@ module ActiveRecord # end # # The cached statement is executed by using the - # [connection.execute]{rdoc-ref:ConnectionAdapters::DatabaseStatements#execute} method: + # {connection.execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute] method: # # cache.execute([], Book, Book.connection) # # The relation returned by the block is cached, and for each - # [execute]{rdoc-ref:ConnectionAdapters::DatabaseStatements#execute} + # {execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute] # call the cached relation gets duped. Database is queried when +to_a+ is called on the relation. # # If you want to cache the statement without the values you can use the +bind+ method of the @@ -40,7 +39,7 @@ module ActiveRecord end class PartialQuery < Query # :nodoc: - def initialize values + def initialize(values) @values = values @indexes = values.each_with_index.find_all { |thing,i| Arel::Nodes::BindParam === thing @@ -49,19 +48,18 @@ module ActiveRecord def sql_for(binds, connection) val = @values.dup - binds = connection.prepare_binds_for_database(binds) - @indexes.each { |i| val[i] = connection.quote(binds.shift) } + casted_binds = binds.map(&:value_for_database) + @indexes.each { |i| val[i] = connection.quote(casted_binds.shift) } val.join end end - def self.query(visitor, ast) - Query.new visitor.accept(ast, Arel::Collectors::SQLString.new).value + def self.query(sql) + Query.new(sql) end - def self.partial_query(visitor, ast, collector) - collected = visitor.accept(ast, collector).value - PartialQuery.new collected + def self.partial_query(values) + PartialQuery.new(values) end class Params # :nodoc: @@ -92,7 +90,7 @@ module ActiveRecord def self.create(connection, block = Proc.new) relation = block.call Params.new bind_map = BindMap.new relation.bound_attributes - query_builder = connection.cacheable_query relation.arel + query_builder = connection.cacheable_query(self, relation.arel) new query_builder, bind_map end @@ -101,12 +99,12 @@ module ActiveRecord @bind_map = bind_map end - def execute(params, klass, connection) + def execute(params, klass, connection, &block) bind_values = bind_map.bind params sql = query_builder.sql_for bind_values, connection - klass.find_by_sql(sql, bind_values, preparable: true) + klass.find_by_sql(sql, bind_values, preparable: true, &block) end alias :call :execute end diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb index 1b407f7702..066573192e 100644 --- a/activerecord/lib/active_record/store.rb +++ b/activerecord/lib/active_record/store.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/indifferent_access' +require "active_support/core_ext/hash/indifferent_access" module ActiveRecord # Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column. @@ -114,8 +114,8 @@ module ActiveRecord def stored_attributes parent = superclass.respond_to?(:stored_attributes) ? superclass.stored_attributes : {} - if self.local_stored_attributes - parent.merge!(self.local_stored_attributes) { |k, a, b| a | b } + if local_stored_attributes + parent.merge!(local_stored_attributes) { |k, a, b| a | b } end parent end @@ -177,34 +177,34 @@ module ActiveRecord end end - class IndifferentCoder # :nodoc: - def initialize(coder_or_class_name) - @coder = - if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump) - coder_or_class_name - else - ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object) - end - end + class IndifferentCoder # :nodoc: + def initialize(coder_or_class_name) + @coder = + if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump) + coder_or_class_name + else + ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object) + end + end - def dump(obj) - @coder.dump self.class.as_indifferent_hash(obj) - end + def dump(obj) + @coder.dump self.class.as_indifferent_hash(obj) + end - def load(yaml) - self.class.as_indifferent_hash(@coder.load(yaml || '')) - end + def load(yaml) + self.class.as_indifferent_hash(@coder.load(yaml || "")) + end - def self.as_indifferent_hash(obj) - case obj - when ActiveSupport::HashWithIndifferentAccess - obj - when Hash - obj.with_indifferent_access - else - ActiveSupport::HashWithIndifferentAccess.new + def self.as_indifferent_hash(obj) + case obj + when ActiveSupport::HashWithIndifferentAccess + obj + when Hash + obj.with_indifferent_access + else + ActiveSupport::HashWithIndifferentAccess.new + end end end - end end end diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb index a1326aa359..58184f3872 100644 --- a/activerecord/lib/active_record/table_metadata.rb +++ b/activerecord/lib/active_record/table_metadata.rb @@ -10,9 +10,7 @@ module ActiveRecord end def resolve_column_aliases(hash) - # This method is a hot spot, so for now, use Hash[] to dup the hash. - # https://bugs.ruby-lang.org/issues/7166 - new_hash = Hash[hash] + new_hash = hash.dup hash.each do |key, _| if (key.is_a?(Symbol)) && klass.attribute_alias?(key) new_hash[klass.attribute_alias(key)] = new_hash.delete(key) @@ -33,20 +31,24 @@ module ActiveRecord if klass klass.type_for_attribute(column_name.to_s) else - Type::Value.new + Type.default_value end end + def has_column?(column_name) + klass && klass.columns_hash.key?(column_name.to_s) + end + def associated_with?(association_name) klass && klass._reflect_on_association(association_name) end def associated_table(table_name) - return self if table_name == arel_table.name - association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.singularize) - if association && !association.polymorphic? + if !association && table_name == arel_table.name + return self + elsif association && !association.polymorphic? association_klass = association.klass arel_table = association_klass.arel_table.alias(table_name) else @@ -64,6 +66,6 @@ module ActiveRecord protected - attr_reader :klass, :arel_table, :association + attr_reader :klass, :arel_table, :association end end diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index e3e665e149..a19913f2a8 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/filters' +require "active_support/core_ext/string/filters" module ActiveRecord module Tasks # :nodoc: @@ -40,10 +40,10 @@ module ActiveRecord attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader attr_accessor :database_configuration - LOCAL_HOSTS = ['127.0.0.1', 'localhost'] + LOCAL_HOSTS = ["127.0.0.1", "localhost"] def check_protected_environments! - unless ENV['DISABLE_DATABASE_ENVIRONMENT_CHECK'] + unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"] current = ActiveRecord::Migrator.current_environment stored = ActiveRecord::Migrator.last_stored_environment @@ -72,15 +72,15 @@ module ActiveRecord end def migrations_paths - @migrations_paths ||= Rails.application.paths['db/migrate'].to_a + @migrations_paths ||= Rails.application.paths["db/migrate"].to_a end def fixtures_path - @fixtures_path ||= if ENV['FIXTURES_PATH'] - File.join(root, ENV['FIXTURES_PATH']) - else - File.join(root, 'test', 'fixtures') - end + @fixtures_path ||= if ENV["FIXTURES_PATH"] + File.join(root, ENV["FIXTURES_PATH"]) + else + File.join(root, "test", "fixtures") + end end def root @@ -96,7 +96,7 @@ module ActiveRecord end def current_config(options = {}) - options.reverse_merge! :env => env + options.reverse_merge! env: env if options.has_key?(:config) @current_config = options[:config] else @@ -106,7 +106,7 @@ module ActiveRecord def create(*arguments) configuration = arguments.first - class_for_adapter(configuration['adapter']).new(*arguments).create + class_for_adapter(configuration["adapter"]).new(*arguments).create $stdout.puts "Created database '#{configuration['database']}'" rescue DatabaseAlreadyExists $stderr.puts "Database '#{configuration['database']}' already exists" @@ -133,7 +133,7 @@ module ActiveRecord def drop(*arguments) configuration = arguments.first - class_for_adapter(configuration['adapter']).new(*arguments).drop + class_for_adapter(configuration["adapter"]).new(*arguments).drop $stdout.puts "Dropped database '#{configuration['database']}'" rescue ActiveRecord::NoDatabaseError $stderr.puts "Database '#{configuration['database']}' does not exist" @@ -156,7 +156,7 @@ module ActiveRecord def migrate verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil - scope = ENV['SCOPE'] + scope = ENV["SCOPE"] verbose_was, Migration.verbose = Migration.verbose, verbose Migrator.migrate(migrations_paths, version) do |migration| scope.blank? || scope == migration.scope @@ -172,7 +172,7 @@ module ActiveRecord def charset(*arguments) configuration = arguments.first - class_for_adapter(configuration['adapter']).new(*arguments).charset + class_for_adapter(configuration["adapter"]).new(*arguments).charset end def collation_current(environment = env) @@ -181,11 +181,11 @@ module ActiveRecord def collation(*arguments) configuration = arguments.first - class_for_adapter(configuration['adapter']).new(*arguments).collation + class_for_adapter(configuration["adapter"]).new(*arguments).collation end def purge(configuration) - class_for_adapter(configuration['adapter']).new(configuration).purge + class_for_adapter(configuration["adapter"]).new(configuration).purge end def purge_all @@ -204,13 +204,13 @@ module ActiveRecord def structure_dump(*arguments) configuration = arguments.first filename = arguments.delete_at 1 - class_for_adapter(configuration['adapter']).new(*arguments).structure_dump(filename) + class_for_adapter(configuration["adapter"]).new(*arguments).structure_dump(filename) end def structure_load(*arguments) configuration = arguments.first filename = arguments.delete_at 1 - class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename) + class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename) end def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc: @@ -275,39 +275,39 @@ module ActiveRecord private - def class_for_adapter(adapter) - key = @tasks.keys.detect { |pattern| adapter[pattern] } - unless key - raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter" + def class_for_adapter(adapter) + key = @tasks.keys.detect { |pattern| adapter[pattern] } + unless key + raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter" + end + @tasks[key] end - @tasks[key] - end - def each_current_configuration(environment) - environments = [environment] - environments << 'test' if environment == 'development' + def each_current_configuration(environment) + environments = [environment] + environments << "test" if environment == "development" - configurations = ActiveRecord::Base.configurations.values_at(*environments) - configurations.compact.each do |configuration| - yield configuration unless configuration['database'].blank? + configurations = ActiveRecord::Base.configurations.values_at(*environments) + configurations.compact.each do |configuration| + yield configuration unless configuration["database"].blank? + end end - end - def each_local_configuration - ActiveRecord::Base.configurations.each_value do |configuration| - next unless configuration['database'] + def each_local_configuration + ActiveRecord::Base.configurations.each_value do |configuration| + next unless configuration["database"] - if local_database?(configuration) - yield configuration - else - $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host." + if local_database?(configuration) + yield configuration + else + $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host." + end end end - end - def local_database?(configuration) - configuration['host'].blank? || LOCAL_HOSTS.include?(configuration['host']) - end + def local_database?(configuration) + configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"]) + end end end end diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index b1a0ad0115..3a5e0b8dfe 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -11,7 +11,7 @@ module ActiveRecord def create establish_connection configuration_without_database - connection.create_database configuration['database'], creation_options + connection.create_database configuration["database"], creation_options establish_connection configuration rescue ActiveRecord::StatementInvalid => error if /database exists/ === error.message @@ -23,26 +23,26 @@ module ActiveRecord if error.respond_to?(:errno) && error.errno == ACCESS_DENIED_ERROR $stdout.print error.message establish_connection root_configuration_without_database - connection.create_database configuration['database'], creation_options - if configuration['username'] != 'root' - connection.execute grant_statement.gsub(/\s+/, ' ').strip + connection.create_database configuration["database"], creation_options + if configuration["username"] != "root" + connection.execute grant_statement.gsub(/\s+/, " ").strip end establish_connection configuration else $stderr.puts error.inspect $stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}" - $stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['encoding'] + $stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration["encoding"] end end def drop establish_connection configuration - connection.drop_database configuration['database'] + connection.drop_database configuration["database"] end def purge establish_connection configuration - connection.recreate_database configuration['database'], creation_options + connection.recreate_database configuration["database"], creation_options end def charset @@ -61,92 +61,92 @@ module ActiveRecord args.concat(["--skip-comments"]) args.concat(["#{configuration['database']}"]) - run_cmd('mysqldump', args, 'dumping') + run_cmd("mysqldump", args, "dumping") end def structure_load(filename) args = prepare_command_options - args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}]) + args.concat(["--execute", %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}]) args.concat(["--database", "#{configuration['database']}"]) - run_cmd('mysql', args, 'loading') + run_cmd("mysql", args, "loading") end private - def configuration - @configuration - end + def configuration + @configuration + end - def configuration_without_database - configuration.merge('database' => nil) - end + def configuration_without_database + configuration.merge("database" => nil) + end - def creation_options - Hash.new.tap do |options| - options[:charset] = configuration['encoding'] if configuration.include? 'encoding' - options[:collation] = configuration['collation'] if configuration.include? 'collation' + def creation_options + Hash.new.tap do |options| + options[:charset] = configuration["encoding"] if configuration.include? "encoding" + options[:collation] = configuration["collation"] if configuration.include? "collation" + end end - end - def error_class - if configuration['adapter'] =~ /jdbc/ - require 'active_record/railties/jdbcmysql_error' - ArJdbcMySQL::Error - elsif defined?(Mysql2) - Mysql2::Error - else - StandardError + def error_class + if configuration["adapter"].include?("jdbc") + require "active_record/railties/jdbcmysql_error" + ArJdbcMySQL::Error + elsif defined?(Mysql2) + Mysql2::Error + else + StandardError + end end - end - def grant_statement - <<-SQL + def grant_statement + <<-SQL GRANT ALL PRIVILEGES ON #{configuration['database']}.* TO '#{configuration['username']}'@'localhost' IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION; - SQL - end + SQL + end - def root_configuration_without_database - configuration_without_database.merge( - 'username' => 'root', - 'password' => root_password - ) - end + def root_configuration_without_database + configuration_without_database.merge( + "username" => "root", + "password" => root_password + ) + end - def root_password - $stdout.print "Please provide the root password for your MySQL installation\n>" - $stdin.gets.strip - end + def root_password + $stdout.print "Please provide the root password for your MySQL installation\n>" + $stdin.gets.strip + end - def prepare_command_options - args = { - 'host' => '--host', - 'port' => '--port', - 'socket' => '--socket', - 'username' => '--user', - 'password' => '--password', - 'encoding' => '--default-character-set', - 'sslca' => '--ssl-ca', - 'sslcert' => '--ssl-cert', - 'sslcapath' => '--ssl-capath', - 'sslcipher' => '--ssl-cipher', - 'sslkey' => '--ssl-key' - }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact - - args - end + def prepare_command_options + args = { + "host" => "--host", + "port" => "--port", + "socket" => "--socket", + "username" => "--user", + "password" => "--password", + "encoding" => "--default-character-set", + "sslca" => "--ssl-ca", + "sslcert" => "--ssl-cert", + "sslcapath" => "--ssl-capath", + "sslcipher" => "--ssl-cipher", + "sslkey" => "--ssl-key" + }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact + + args + end - def run_cmd(cmd, args, action) - fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args) - end + def run_cmd(cmd, args, action) + fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args) + end - def run_cmd_error(cmd, args, action) - msg = "failed to execute: `#{cmd}`\n" - msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" - msg - end + def run_cmd_error(cmd, args, action) + msg = "failed to execute: `#{cmd}`\n" + msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" + msg + end end end end diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb index b19ab57ee4..a3a9430c03 100644 --- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb @@ -1,8 +1,8 @@ module ActiveRecord module Tasks # :nodoc: class PostgreSQLDatabaseTasks # :nodoc: - DEFAULT_ENCODING = ENV['CHARSET'] || 'utf8' - ON_ERROR_STOP_1 = 'ON_ERROR_STOP=1'.freeze + DEFAULT_ENCODING = ENV["CHARSET"] || "utf8" + ON_ERROR_STOP_1 = "ON_ERROR_STOP=1".freeze delegate :connection, :establish_connection, :clear_active_connections!, to: ActiveRecord::Base @@ -13,8 +13,8 @@ module ActiveRecord def create(master_established = false) establish_master_connection unless master_established - connection.create_database configuration['database'], - configuration.merge('encoding' => encoding) + connection.create_database configuration["database"], + configuration.merge("encoding" => encoding) establish_connection configuration rescue ActiveRecord::StatementInvalid => error if /database .* already exists/ === error.message @@ -26,7 +26,7 @@ module ActiveRecord def drop establish_master_connection - connection.drop_database configuration['database'] + connection.drop_database configuration["database"] end def charset @@ -46,66 +46,67 @@ module ActiveRecord def structure_dump(filename) set_psql_env - search_path = case ActiveRecord::Base.dump_schemas - when :schema_search_path - configuration['schema_search_path'] - when :all - nil - when String - ActiveRecord::Base.dump_schemas - end + search_path = \ + case ActiveRecord::Base.dump_schemas + when :schema_search_path + configuration["schema_search_path"] + when :all + nil + when String + ActiveRecord::Base.dump_schemas + end - args = ['-s', '-x', '-O', '-f', filename] + args = ["-s", "-x", "-O", "-f", filename] unless search_path.blank? - args += search_path.split(',').map do |part| + args += search_path.split(",").map do |part| "--schema=#{part.strip}" end end - args << configuration['database'] - run_cmd('pg_dump', args, 'dumping') + args << configuration["database"] + run_cmd("pg_dump", args, "dumping") File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" } end def structure_load(filename) set_psql_env - args = [ '-v', ON_ERROR_STOP_1, '-q', '-f', filename, configuration['database'] ] - run_cmd('psql', args, 'loading' ) + args = [ "-v", ON_ERROR_STOP_1, "-q", "-f", filename, configuration["database"] ] + run_cmd("psql", args, "loading" ) end private - def configuration - @configuration - end + def configuration + @configuration + end - def encoding - configuration['encoding'] || DEFAULT_ENCODING - end + def encoding + configuration["encoding"] || DEFAULT_ENCODING + end - def establish_master_connection - establish_connection configuration.merge( - 'database' => 'postgres', - 'schema_search_path' => 'public' - ) - end + def establish_master_connection + establish_connection configuration.merge( + "database" => "postgres", + "schema_search_path" => "public" + ) + end - def set_psql_env - ENV['PGHOST'] = configuration['host'] if configuration['host'] - ENV['PGPORT'] = configuration['port'].to_s if configuration['port'] - ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password'] - ENV['PGUSER'] = configuration['username'].to_s if configuration['username'] - end + def set_psql_env + ENV["PGHOST"] = configuration["host"] if configuration["host"] + ENV["PGPORT"] = configuration["port"].to_s if configuration["port"] + ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"] + ENV["PGUSER"] = configuration["username"].to_s if configuration["username"] + end - def run_cmd(cmd, args, action) - fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args) - end + def run_cmd(cmd, args, action) + fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args) + end - def run_cmd_error(cmd, args, action) - msg = "failed to execute:\n" - msg << "#{cmd} #{args.join(' ')}\n\n" - msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" - msg - end + def run_cmd_error(cmd, args, action) + msg = "failed to execute:\n" + msg << "#{cmd} #{args.join(' ')}\n\n" + msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" + msg + end end end end diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb index 9ec3c8a94a..31f1b7efd4 100644 --- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb @@ -8,15 +8,15 @@ module ActiveRecord end def create - raise DatabaseAlreadyExists if File.exist?(configuration['database']) + raise DatabaseAlreadyExists if File.exist?(configuration["database"]) establish_connection configuration connection end def drop - require 'pathname' - path = Pathname.new configuration['database'] + require "pathname" + path = Pathname.new configuration["database"] file = path.absolute? ? path.to_s : File.join(root, path) FileUtils.rm(file) @@ -36,24 +36,24 @@ module ActiveRecord end def structure_dump(filename) - dbfile = configuration['database'] + dbfile = configuration["database"] `sqlite3 #{dbfile} .schema > #{filename}` end def structure_load(filename) - dbfile = configuration['database'] + dbfile = configuration["database"] `sqlite3 #{dbfile} < "#{filename}"` end private - def configuration - @configuration - end + def configuration + @configuration + end - def root - @root - end + def root + @root + end end end end diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index d9c18a5e38..6641ab5df1 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -54,7 +54,7 @@ module ActiveRecord private def _create_record - if self.record_timestamps + if record_timestamps current_time = current_time_from_proper_timezone all_timestamp_attributes.each do |column| @@ -82,7 +82,7 @@ module ActiveRecord end def should_record_timestamps? - self.record_timestamps && (!partial_writes? || changed?) + record_timestamps && (!partial_writes? || changed?) end def timestamp_attributes_for_create_in_model diff --git a/activerecord/lib/active_record/touch_later.rb b/activerecord/lib/active_record/touch_later.rb index 9a80a63e28..c337a7532f 100644 --- a/activerecord/lib/active_record/touch_later.rb +++ b/activerecord/lib/active_record/touch_later.rb @@ -8,7 +8,12 @@ module ActiveRecord end def touch_later(*names) # :nodoc: - raise ActiveRecordError, "cannot touch on a new record object" unless persisted? + unless persisted? + raise ActiveRecordError, <<-MSG.squish + cannot touch on a new or destroyed record object. Consider using + persisted?, new_record?, or destroyed? before touching + MSG + end @_defer_touch_attrs ||= timestamp_attributes_for_update_in_model @_defer_touch_attrs |= names @@ -53,6 +58,5 @@ module ActiveRecord def belongs_to_touch_method :touch_later end - end end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 77c2845d88..af3fc88282 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -189,8 +189,8 @@ module ActiveRecord # # === Caveats # - # If you're on MySQL, then do not use DDL operations in nested transactions - # blocks that are emulated with savepoints. That is, do not execute statements + # If you're on MySQL, then do not use Data Definition Language(DDL) operations in nested + # transactions blocks that are emulated with savepoints. That is, do not execute statements # like 'CREATE TABLE' inside such blocks. This is because MySQL automatically # releases all savepoints upon executing a DDL operation. When +transaction+ # is finished and tries to release the savepoint it created earlier, a @@ -275,34 +275,34 @@ module ActiveRecord end def raise_in_transactional_callbacks - ActiveSupport::Deprecation.warn('ActiveRecord::Base.raise_in_transactional_callbacks is deprecated and will be removed without replacement.') + ActiveSupport::Deprecation.warn("ActiveRecord::Base.raise_in_transactional_callbacks is deprecated and will be removed without replacement.") true end def raise_in_transactional_callbacks=(value) - ActiveSupport::Deprecation.warn('ActiveRecord::Base.raise_in_transactional_callbacks= is deprecated, has no effect and will be removed without replacement.') + ActiveSupport::Deprecation.warn("ActiveRecord::Base.raise_in_transactional_callbacks= is deprecated, has no effect and will be removed without replacement.") value end private - def set_options_for_callbacks!(args, enforced_options = {}) - options = args.extract_options!.merge!(enforced_options) - args << options + def set_options_for_callbacks!(args, enforced_options = {}) + options = args.extract_options!.merge!(enforced_options) + args << options - if options[:on] - fire_on = Array(options[:on]) - assert_valid_transaction_action(fire_on) - options[:if] = Array(options[:if]) - options[:if] << "transaction_include_any_action?(#{fire_on})" + if options[:on] + fire_on = Array(options[:on]) + assert_valid_transaction_action(fire_on) + options[:if] = Array(options[:if]) + options[:if] << "transaction_include_any_action?(#{fire_on})" + end end - end - def assert_valid_transaction_action(actions) - if (actions - ACTIONS).any? - raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}" + def assert_valid_transaction_action(actions) + if (actions - ACTIONS).any? + raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}" + end end - end end # See ActiveRecord::Transactions::ClassMethods for detailed documentation. @@ -409,101 +409,101 @@ module ActiveRecord protected - # Save the new record state and id of a record so it can be restored later if a transaction fails. - def remember_transaction_record_state #:nodoc: - @_start_transaction_state[:id] = id - @_start_transaction_state.reverse_merge!( - new_record: @new_record, - destroyed: @destroyed, - frozen?: frozen?, - ) - @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1 - end + # Save the new record state and id of a record so it can be restored later if a transaction fails. + def remember_transaction_record_state #:nodoc: + @_start_transaction_state[:id] = id + @_start_transaction_state.reverse_merge!( + new_record: @new_record, + destroyed: @destroyed, + frozen?: frozen?, + ) + @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1 + end - # Clear the new record state and id of a record. - def clear_transaction_record_state #:nodoc: - @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1 - force_clear_transaction_record_state if @_start_transaction_state[:level] < 1 - end + # Clear the new record state and id of a record. + def clear_transaction_record_state #:nodoc: + @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1 + force_clear_transaction_record_state if @_start_transaction_state[:level] < 1 + end - # Force to clear the transaction record state. - def force_clear_transaction_record_state #:nodoc: - @_start_transaction_state.clear - end + # Force to clear the transaction record state. + def force_clear_transaction_record_state #:nodoc: + @_start_transaction_state.clear + end - # Restore the new record state and id of a record that was previously saved by a call to save_record_state. - def restore_transaction_record_state(force = false) #:nodoc: - unless @_start_transaction_state.empty? - transaction_level = (@_start_transaction_state[:level] || 0) - 1 - if transaction_level < 1 || force - restore_state = @_start_transaction_state - thaw - @new_record = restore_state[:new_record] - @destroyed = restore_state[:destroyed] - pk = self.class.primary_key - if pk && read_attribute(pk) != restore_state[:id] - write_attribute(pk, restore_state[:id]) + # Restore the new record state and id of a record that was previously saved by a call to save_record_state. + def restore_transaction_record_state(force = false) #:nodoc: + unless @_start_transaction_state.empty? + transaction_level = (@_start_transaction_state[:level] || 0) - 1 + if transaction_level < 1 || force + restore_state = @_start_transaction_state + thaw + @new_record = restore_state[:new_record] + @destroyed = restore_state[:destroyed] + pk = self.class.primary_key + if pk && read_attribute(pk) != restore_state[:id] + write_attribute(pk, restore_state[:id]) + end + freeze if restore_state[:frozen?] end - freeze if restore_state[:frozen?] end end - end - # Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed. - def transaction_record_state(state) #:nodoc: - @_start_transaction_state[state] - end + # Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed. + def transaction_record_state(state) #:nodoc: + @_start_transaction_state[state] + end - # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks. - def transaction_include_any_action?(actions) #:nodoc: - actions.any? do |action| - case action - when :create - transaction_record_state(:new_record) - when :destroy - destroyed? - when :update - !(transaction_record_state(:new_record) || destroyed?) + # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks. + def transaction_include_any_action?(actions) #:nodoc: + actions.any? do |action| + case action + when :create + transaction_record_state(:new_record) + when :destroy + destroyed? + when :update + !(transaction_record_state(:new_record) || destroyed?) + end end end - end private - def set_transaction_state(state) # :nodoc: - @transaction_state = state - end + def set_transaction_state(state) # :nodoc: + @transaction_state = state + end - def has_transactional_callbacks? # :nodoc: - !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty? - end + def has_transactional_callbacks? # :nodoc: + !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty? + end - # Updates the attributes on this particular Active Record object so that - # if it's associated with a transaction, then the state of the Active Record - # object will be updated to reflect the current state of the transaction - # - # The +@transaction_state+ variable stores the states of the associated - # transaction. This relies on the fact that a transaction can only be in - # one rollback or commit (otherwise a list of states would be required) - # Each Active Record object inside of a transaction carries that transaction's - # TransactionState. - # - # This method checks to see if the ActiveRecord object's state reflects - # the TransactionState, and rolls back or commits the Active Record object - # as appropriate. - # - # Since Active Record objects can be inside multiple transactions, this - # method recursively goes through the parent of the TransactionState and - # checks if the Active Record object reflects the state of the object. - def sync_with_transaction_state - update_attributes_from_transaction_state(@transaction_state) - end + # Updates the attributes on this particular Active Record object so that + # if it's associated with a transaction, then the state of the Active Record + # object will be updated to reflect the current state of the transaction. + # + # The +@transaction_state+ variable stores the states of the associated + # transaction. This relies on the fact that a transaction can only be in + # one rollback or commit (otherwise a list of states would be required). + # Each Active Record object inside of a transaction carries that transaction's + # TransactionState. + # + # This method checks to see if the ActiveRecord object's state reflects + # the TransactionState, and rolls back or commits the Active Record object + # as appropriate. + # + # Since Active Record objects can be inside multiple transactions, this + # method recursively goes through the parent of the TransactionState and + # checks if the Active Record object reflects the state of the object. + def sync_with_transaction_state + update_attributes_from_transaction_state(@transaction_state) + end - def update_attributes_from_transaction_state(transaction_state) - if transaction_state && transaction_state.finalized? - restore_transaction_record_state if transaction_state.rolledback? - clear_transaction_record_state + def update_attributes_from_transaction_state(transaction_state) + if transaction_state && transaction_state.finalized? + restore_transaction_record_state if transaction_state.rolledback? + clear_transaction_record_state + end end - end end end diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb index 4911d93dd9..0b48d2186a 100644 --- a/activerecord/lib/active_record/type.rb +++ b/activerecord/lib/active_record/type.rb @@ -1,17 +1,17 @@ -require 'active_model/type' +require "active_model/type" -require 'active_record/type/internal/abstract_json' -require 'active_record/type/internal/timezone' +require "active_record/type/internal/abstract_json" +require "active_record/type/internal/timezone" -require 'active_record/type/date' -require 'active_record/type/date_time' -require 'active_record/type/time' +require "active_record/type/date" +require "active_record/type/date_time" +require "active_record/type/time" -require 'active_record/type/serialized' -require 'active_record/type/adapter_specific_registry' +require "active_record/type/serialized" +require "active_record/type/adapter_specific_registry" -require 'active_record/type/type_map' -require 'active_record/type/hash_lookup_type_map' +require "active_record/type/type_map" +require "active_record/type/hash_lookup_type_map" module ActiveRecord module Type @@ -37,6 +37,10 @@ module ActiveRecord registry.lookup(*args, adapter: adapter, **kwargs) end + def default_value # :nodoc: + @default_value ||= Value.new + end + private def current_adapter_name diff --git a/activerecord/lib/active_record/type/adapter_specific_registry.rb b/activerecord/lib/active_record/type/adapter_specific_registry.rb index d440eac619..d0f9581576 100644 --- a/activerecord/lib/active_record/type/adapter_specific_registry.rb +++ b/activerecord/lib/active_record/type/adapter_specific_registry.rb @@ -1,4 +1,4 @@ -require 'active_model/type/registry' +require "active_model/type/registry" module ActiveRecord # :stopdoc: @@ -10,15 +10,15 @@ module ActiveRecord private - def registration_klass - Registration - end + def registration_klass + Registration + end - def find_registration(symbol, *args) - registrations - .select { |registration| registration.matches?(symbol, *args) } - .max - end + def find_registration(symbol, *args) + registrations + .select { |registration| registration.matches?(symbol, *args) } + .max + end end class Registration @@ -52,42 +52,42 @@ module ActiveRecord protected - attr_reader :name, :block, :adapter, :override - - def priority - result = 0 - if adapter - result |= 1 - end - if override - result |= 2 + attr_reader :name, :block, :adapter, :override + + def priority + result = 0 + if adapter + result |= 1 + end + if override + result |= 2 + end + result end - result - end - def priority_except_adapter - priority & 0b111111100 - end + def priority_except_adapter + priority & 0b111111100 + end private - def matches_adapter?(adapter: nil, **) - (self.adapter.nil? || adapter == self.adapter) - end + def matches_adapter?(adapter: nil, **) + (self.adapter.nil? || adapter == self.adapter) + end - def conflicts_with?(other) - same_priority_except_adapter?(other) && - has_adapter_conflict?(other) - end + def conflicts_with?(other) + same_priority_except_adapter?(other) && + has_adapter_conflict?(other) + end - def same_priority_except_adapter?(other) - priority_except_adapter == other.priority_except_adapter - end + def same_priority_except_adapter?(other) + priority_except_adapter == other.priority_except_adapter + end - def has_adapter_conflict?(other) - (override.nil? && other.adapter) || - (adapter && other.override.nil?) - end + def has_adapter_conflict?(other) + (override.nil? && other.adapter) || + (adapter && other.override.nil?) + end end class DecorationRegistration < Registration @@ -112,15 +112,15 @@ module ActiveRecord protected - attr_reader :options, :klass + attr_reader :options, :klass private - def matches_options?(**kwargs) - options.all? do |key, value| - kwargs[key] == value + def matches_options?(**kwargs) + options.all? do |key, value| + kwargs[key] == value + end end - end end end diff --git a/activerecord/lib/active_record/type/hash_lookup_type_map.rb b/activerecord/lib/active_record/type/hash_lookup_type_map.rb index 3b01e3f8ca..0145d5d6c1 100644 --- a/activerecord/lib/active_record/type/hash_lookup_type_map.rb +++ b/activerecord/lib/active_record/type/hash_lookup_type_map.rb @@ -15,9 +15,9 @@ module ActiveRecord private - def perform_fetch(type, *args, &block) - @mapping.fetch(type, block).call(type, *args) - end + def perform_fetch(type, *args, &block) + @mapping.fetch(type, block).call(type, *args) + end end end end diff --git a/activerecord/lib/active_record/type/internal/abstract_json.rb b/activerecord/lib/active_record/type/internal/abstract_json.rb index 513c938088..e19c5a14da 100644 --- a/activerecord/lib/active_record/type/internal/abstract_json.rb +++ b/activerecord/lib/active_record/type/internal/abstract_json.rb @@ -17,7 +17,11 @@ module ActiveRecord end def serialize(value) - ::ActiveSupport::JSON.encode(value) + if value.nil? + nil + else + ::ActiveSupport::JSON.encode(value) + end end def accessor diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb index a3a5241780..ac9134bfcb 100644 --- a/activerecord/lib/active_record/type/serialized.rb +++ b/activerecord/lib/active_record/type/serialized.rb @@ -49,15 +49,15 @@ module ActiveRecord private - def default_value?(value) - value == coder.load(nil) - end + def default_value?(value) + value == coder.load(nil) + end - def encoded(value) - unless default_value?(value) - coder.dump(value) + def encoded(value) + unless default_value?(value) + coder.dump(value) + end end - end end end end diff --git a/activerecord/lib/active_record/type/time.rb b/activerecord/lib/active_record/type/time.rb index 7da49e43c7..b9bac87c67 100644 --- a/activerecord/lib/active_record/type/time.rb +++ b/activerecord/lib/active_record/type/time.rb @@ -17,4 +17,3 @@ module ActiveRecord end end end - diff --git a/activerecord/lib/active_record/type/type_map.rb b/activerecord/lib/active_record/type/type_map.rb index 850a7a4e09..7bce82a1ff 100644 --- a/activerecord/lib/active_record/type/type_map.rb +++ b/activerecord/lib/active_record/type/type_map.rb @@ -1,4 +1,4 @@ -require 'concurrent/map' +require "concurrent/map" module ActiveRecord module Type @@ -11,7 +11,7 @@ module ActiveRecord end def lookup(lookup_key, *args) - fetch(lookup_key, *args) { default_value } + fetch(lookup_key, *args) { Type.default_value } end def fetch(lookup_key, *args, &block) @@ -44,21 +44,17 @@ module ActiveRecord private - def perform_fetch(lookup_key, *args) - matching_pair = @mapping.reverse_each.detect do |key, _| - key === lookup_key - end + def perform_fetch(lookup_key, *args) + matching_pair = @mapping.reverse_each.detect do |key, _| + key === lookup_key + end - if matching_pair - matching_pair.last.call(lookup_key, *args) - else - yield lookup_key, *args + if matching_pair + matching_pair.last.call(lookup_key, *args) + else + yield lookup_key, *args + end end - end - - def default_value - @default_value ||= ActiveModel::Type::Value.new - end end end end diff --git a/activerecord/lib/active_record/type_caster.rb b/activerecord/lib/active_record/type_caster.rb index accc339d00..f1686e4913 100644 --- a/activerecord/lib/active_record/type_caster.rb +++ b/activerecord/lib/active_record/type_caster.rb @@ -1,5 +1,5 @@ -require 'active_record/type_caster/map' -require 'active_record/type_caster/connection' +require "active_record/type_caster/map" +require "active_record/type_caster/connection" module ActiveRecord module TypeCaster # :nodoc: diff --git a/activerecord/lib/active_record/type_caster/connection.rb b/activerecord/lib/active_record/type_caster/connection.rb index 7ed8dcc313..6c54792e26 100644 --- a/activerecord/lib/active_record/type_caster/connection.rb +++ b/activerecord/lib/active_record/type_caster/connection.rb @@ -14,16 +14,16 @@ module ActiveRecord protected - attr_reader :table_name - delegate :connection, to: :@klass + attr_reader :table_name + delegate :connection, to: :@klass private - def column_for(attribute_name) - if connection.schema_cache.data_source_exists?(table_name) - connection.schema_cache.columns_hash(table_name)[attribute_name.to_s] + def column_for(attribute_name) + if connection.schema_cache.data_source_exists?(table_name) + connection.schema_cache.columns_hash(table_name)[attribute_name.to_s] + end end - end end end end diff --git a/activerecord/lib/active_record/type_caster/map.rb b/activerecord/lib/active_record/type_caster/map.rb index 3a367b3999..52529a6b42 100644 --- a/activerecord/lib/active_record/type_caster/map.rb +++ b/activerecord/lib/active_record/type_caster/map.rb @@ -13,7 +13,7 @@ module ActiveRecord protected - attr_reader :types + attr_reader :types end end end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index ec9f498c40..8c4930a81d 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -12,10 +12,9 @@ module ActiveRecord def validate_each(record, attribute, value) finder_class = find_finder_class_for(record) - table = finder_class.arel_table value = map_enum_attribute(finder_class, attribute, value) - relation = build_relation(finder_class, table, attribute, value) + relation = build_relation(finder_class, attribute, value) if record.persisted? if finder_class.primary_key relation = relation.where.not(finder_class.primary_key => record.id_was || record.id) @@ -23,7 +22,7 @@ module ActiveRecord raise UnknownPrimaryKey.new(finder_class, "Can not validate uniqueness for persisted record without primary key.") end end - relation = scope_relation(record, table, relation) + relation = scope_relation(record, relation) relation = relation.merge(options[:conditions]) if options[:conditions] if relation.exists? @@ -50,12 +49,16 @@ module ActiveRecord class_hierarchy.detect { |klass| !klass.abstract_class? } end - def build_relation(klass, table, attribute, value) #:nodoc: + def build_relation(klass, attribute, value) # :nodoc: if reflection = klass._reflect_on_association(attribute) attribute = reflection.foreign_key value = value.attributes[reflection.klass.primary_key] unless value.nil? end + if value.nil? + return klass.unscoped.where!(attribute => value) + end + # the attribute may be an aliased attribute if klass.attribute_alias?(attribute) attribute = klass.attribute_alias(attribute) @@ -63,24 +66,24 @@ module ActiveRecord attribute_name = attribute.to_s + table = klass.arel_table column = klass.columns_hash[attribute_name] cast_type = klass.type_for_attribute(attribute_name) - comparison = if !options[:case_sensitive] && !value.nil? + comparison = if !options[:case_sensitive] # will use SQL LOWER function before comparison, unless it detects a case insensitive collation klass.connection.case_insensitive_comparison(table, attribute, column, value) else klass.connection.case_sensitive_comparison(table, attribute, column, value) end - if value.nil? - klass.unscoped.where(comparison) - else - bind = Relation::QueryAttribute.new(attribute_name, value, cast_type) - klass.unscoped.where(comparison, bind) + klass.unscoped.tap do |scope| + parts = [comparison] + binds = [Relation::QueryAttribute.new(attribute_name, value, cast_type)] + scope.where_clause += Relation::WhereClause.new(parts, binds) end end - def scope_relation(record, table, relation) + def scope_relation(record, relation) Array(options[:scope]).each do |scope_item| if reflection = record.class._reflect_on_association(scope_item) scope_value = record.send(reflection.foreign_key) diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index cf76a13b44..146cfacc18 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActiveRecord # Returns the version of the currently loaded ActiveRecord as a <tt>Gem::Version</tt> diff --git a/activerecord/lib/rails/generators/active_record.rb b/activerecord/lib/rails/generators/active_record.rb index dc29213235..68fca44e3b 100644 --- a/activerecord/lib/rails/generators/active_record.rb +++ b/activerecord/lib/rails/generators/active_record.rb @@ -1,7 +1,7 @@ -require 'rails/generators/named_base' -require 'rails/generators/active_model' -require 'rails/generators/active_record/migration' -require 'active_record' +require "rails/generators/named_base" +require "rails/generators/active_model" +require "rails/generators/active_record/migration" +require "active_record" module ActiveRecord module Generators # :nodoc: diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb index c2b2209638..4263c11ffc 100644 --- a/activerecord/lib/rails/generators/active_record/migration.rb +++ b/activerecord/lib/rails/generators/active_record/migration.rb @@ -1,4 +1,4 @@ -require 'rails/generators/migration' +require "rails/generators/migration" module ActiveRecord module Generators # :nodoc: diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb index 4e5872b585..76ed25ea75 100644 --- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb +++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb @@ -1,9 +1,10 @@ -require 'rails/generators/active_record' +require "rails/generators/active_record" +require "active_support/core_ext/regexp" module ActiveRecord module Generators # :nodoc: class MigrationGenerator < Base # :nodoc: - argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" + argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]" class_option :primary_key_type, type: :string, desc: "The type for primary key" @@ -14,43 +15,43 @@ module ActiveRecord end protected - attr_reader :migration_action, :join_tables + attr_reader :migration_action, :join_tables - # Sets the default migration template that is being used for the generation of the migration. - # Depending on command line arguments, the migration template and the table name instance - # variables are set up. - def set_local_assigns! - @migration_template = "migration.rb" - case file_name - when /^(add|remove)_.*_(?:to|from)_(.*)/ - @migration_action = $1 - @table_name = normalize_table_name($2) - when /join_table/ - if attributes.length == 2 - @migration_action = 'join' - @join_tables = pluralize_table_names? ? attributes.map(&:plural_name) : attributes.map(&:singular_name) + # Sets the default migration template that is being used for the generation of the migration. + # Depending on command line arguments, the migration template and the table name instance + # variables are set up. + def set_local_assigns! + @migration_template = "migration.rb" + case file_name + when /^(add|remove)_.*_(?:to|from)_(.*)/ + @migration_action = $1 + @table_name = normalize_table_name($2) + when /join_table/ + if attributes.length == 2 + @migration_action = "join" + @join_tables = pluralize_table_names? ? attributes.map(&:plural_name) : attributes.map(&:singular_name) - set_index_names + set_index_names + end + when /^create_(.+)/ + @table_name = normalize_table_name($1) + @migration_template = "create_table_migration.rb" end - when /^create_(.+)/ - @table_name = normalize_table_name($1) - @migration_template = "create_table_migration.rb" end - end - def set_index_names - attributes.each_with_index do |attr, i| - attr.index_name = [attr, attributes[i - 1]].map{ |a| index_name_for(a) } + def set_index_names + attributes.each_with_index do |attr, i| + attr.index_name = [attr, attributes[i - 1]].map { |a| index_name_for(a) } + end end - end - def index_name_for(attribute) - if attribute.foreign_key? - attribute.name - else - attribute.name.singularize.foreign_key - end.to_sym - end + def index_name_for(attribute) + if attribute.foreign_key? + attribute.name + else + attribute.name.singularize.foreign_key + end.to_sym + end private def attributes_with_index @@ -60,7 +61,7 @@ module ActiveRecord # A migration file name can only contain underscores (_), lowercase characters, # and numbers 0-9. Any other file name will raise an IllegalMigrationNameError. def validate_file_name! - unless file_name =~ /^[_a-z0-9]+$/ + unless /^[_a-z0-9]+$/.match?(file_name) raise IllegalMigrationNameError.new(file_name) end end diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb index 0d72913258..f1ddc61688 100644 --- a/activerecord/lib/rails/generators/active_record/model/model_generator.rb +++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb @@ -1,9 +1,9 @@ -require 'rails/generators/active_record' +require "rails/generators/active_record" module ActiveRecord module Generators # :nodoc: class ModelGenerator < Base # :nodoc: - argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]" + argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]" check_class_collision @@ -22,13 +22,13 @@ module ActiveRecord def create_model_file generate_application_record - template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb") + template "model.rb", File.join("app/models", class_path, "#{file_name}.rb") end def create_module_file return if regular_class_path.empty? generate_application_record - template 'module.rb', File.join('app/models', "#{class_path.join('/')}.rb") if behavior == :invoke + template "module.rb", File.join("app/models", "#{class_path.join('/')}.rb") if behavior == :invoke end hook_for :test_framework @@ -42,13 +42,13 @@ module ActiveRecord # FIXME: Change this file to a symlink once RubyGems 2.5.0 is required. def generate_application_record if self.behavior == :invoke && !application_record_exist? - template 'application_record.rb', application_record_file_name + template "application_record.rb", application_record_file_name end end # Used by the migration template to determine the parent name of the model def parent_class_name - options[:parent] || 'ApplicationRecord' + options[:parent] || "ApplicationRecord" end def application_record_exist? @@ -61,7 +61,7 @@ module ActiveRecord @application_record_file_name ||= if mountable_engine? "app/models/#{namespaced_path}/application_record.rb" else - 'app/models/application_record.rb' + "app/models/application_record.rb" end end end diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 34e3bc9d66..cfbc8ab942 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -33,17 +33,19 @@ module ActiveRecord def test_tables tables = nil ActiveSupport::Deprecation.silence { tables = @connection.tables } - assert tables.include?("accounts") - assert tables.include?("authors") - assert tables.include?("tasks") - assert tables.include?("topics") + assert_includes tables, "accounts" + assert_includes tables, "authors" + assert_includes tables, "tasks" + assert_includes tables, "topics" end def test_table_exists? ActiveSupport::Deprecation.silence do assert @connection.table_exists?("accounts") - assert !@connection.table_exists?("nonexistingtable") - assert !@connection.table_exists?(nil) + assert @connection.table_exists?(:accounts) + assert_not @connection.table_exists?("nonexistingtable") + assert_not @connection.table_exists?("'") + assert_not @connection.table_exists?(nil) end end @@ -53,16 +55,17 @@ module ActiveRecord def test_data_sources data_sources = @connection.data_sources - assert data_sources.include?("accounts") - assert data_sources.include?("authors") - assert data_sources.include?("tasks") - assert data_sources.include?("topics") + assert_includes data_sources, "accounts" + assert_includes data_sources, "authors" + assert_includes data_sources, "tasks" + assert_includes data_sources, "topics" end def test_data_source_exists? assert @connection.data_source_exists?("accounts") assert @connection.data_source_exists?(:accounts) assert_not @connection.data_source_exists?("nonexistingtable") + assert_not @connection.data_source_exists?("'") assert_not @connection.data_source_exists?(nil) end @@ -73,7 +76,7 @@ module ActiveRecord indexes = @connection.indexes("accounts") assert indexes.empty? - @connection.add_index :accounts, :firm_id, :name => idx_name + @connection.add_index :accounts, :firm_id, name: idx_name indexes = @connection.indexes("accounts") assert_equal "accounts", indexes.first.table assert_equal idx_name, indexes.first.name @@ -84,47 +87,47 @@ module ActiveRecord end ensure - @connection.remove_index(:accounts, :name => idx_name) rescue nil + @connection.remove_index(:accounts, name: idx_name) rescue nil end def test_remove_index_when_name_and_wrong_column_name_specified index_name = "accounts_idx" - @connection.add_index :accounts, :firm_id, :name => index_name + @connection.add_index :accounts, :firm_id, name: index_name assert_raises ArgumentError do - @connection.remove_index :accounts, :name => index_name, :column => :wrong_column_name + @connection.remove_index :accounts, name: index_name, column: :wrong_column_name end ensure - @connection.remove_index(:accounts, :name => index_name) + @connection.remove_index(:accounts, name: index_name) end def test_current_database if @connection.respond_to?(:current_database) - assert_equal ARTest.connection_config['arunit']['database'], @connection.current_database + assert_equal ARTest.connection_config["arunit"]["database"], @connection.current_database end end if current_adapter?(:Mysql2Adapter) def test_charset assert_not_nil @connection.charset - assert_not_equal 'character_set_database', @connection.charset - assert_equal @connection.show_variable('character_set_database'), @connection.charset + assert_not_equal "character_set_database", @connection.charset + assert_equal @connection.show_variable("character_set_database"), @connection.charset end def test_collation assert_not_nil @connection.collation - assert_not_equal 'collation_database', @connection.collation - assert_equal @connection.show_variable('collation_database'), @connection.collation + assert_not_equal "collation_database", @connection.collation + assert_equal @connection.show_variable("collation_database"), @connection.collation end def test_show_nonexistent_variable_returns_nil - assert_nil @connection.show_variable('foo_bar_baz') + assert_nil @connection.show_variable("foo_bar_baz") end def test_not_specifying_database_name_for_cross_database_selects begin assert_nothing_raised do - ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database)) + ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["arunit"].except(:database)) config = ARTest.connection_config ActiveRecord::Base.connection.execute( @@ -145,9 +148,9 @@ module ActiveRecord alias_method :table_alias_length, :test_table_alias_length end - assert_equal 'posts', @connection.table_alias_for('posts') - assert_equal 'posts_comm', @connection.table_alias_for('posts_comments') - assert_equal 'dbo_posts', @connection.table_alias_for('dbo.posts') + assert_equal "posts", @connection.table_alias_for("posts") + assert_equal "posts_comm", @connection.table_alias_for("posts_comments") + assert_equal "dbo_posts", @connection.table_alias_for("dbo.posts") class << @connection remove_method :table_alias_length @@ -157,20 +160,20 @@ module ActiveRecord # test resetting sequences in odd tables in PostgreSQL if ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!) - require 'models/movie' - require 'models/subscriber' + require "models/movie" + require "models/subscriber" def test_reset_empty_table_with_custom_pk Movie.delete_all - Movie.connection.reset_pk_sequence! 'movies' - assert_equal 1, Movie.create(:name => 'fight club').id + Movie.connection.reset_pk_sequence! "movies" + assert_equal 1, Movie.create(name: "fight club").id end def test_reset_table_with_non_integer_pk Subscriber.delete_all - Subscriber.connection.reset_pk_sequence! 'subscribers' - sub = Subscriber.new(:name => 'robert drake') - sub.id = 'bob drake' + Subscriber.connection.reset_pk_sequence! "subscribers" + sub = Subscriber.new(name: "robert drake") + sub.id = "bob drake" assert_nothing_raised { sub.save! } end end @@ -201,7 +204,7 @@ module ActiveRecord def test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false klass_has_fk = Class.new(ActiveRecord::Base) do - self.table_name = 'fk_test_has_fk' + self.table_name = "fk_test_has_fk" end error = assert_raises(ActiveRecord::InvalidForeignKey) do @@ -215,7 +218,7 @@ module ActiveRecord def test_value_limit_violations_are_translated_to_specific_exception error = assert_raises(ActiveRecord::ValueTooLong) do - Event.create(title: 'abcdefgh') + Event.create(title: "abcdefgh") end assert_not_nil error.cause @@ -245,21 +248,21 @@ module ActiveRecord end def test_select_methods_passing_a_association_relation - author = Author.create!(name: 'john') - Post.create!(author: author, title: 'foo', body: 'bar') - query = author.posts.where(title: 'foo').select(:title) - assert_equal({"title" => "foo"}, @connection.select_one(query.arel, nil, query.bound_attributes)) - assert_equal({"title" => "foo"}, @connection.select_one(query)) + author = Author.create!(name: "john") + Post.create!(author: author, title: "foo", body: "bar") + query = author.posts.where(title: "foo").select(:title) + assert_equal({ "title" => "foo" }, @connection.select_one(query.arel, nil, query.bound_attributes)) + assert_equal({ "title" => "foo" }, @connection.select_one(query)) assert @connection.select_all(query).is_a?(ActiveRecord::Result) assert_equal "foo", @connection.select_value(query) assert_equal ["foo"], @connection.select_values(query) end def test_select_methods_passing_a_relation - Post.create!(title: 'foo', body: 'bar') - query = Post.where(title: 'foo').select(:title) - assert_equal({"title" => "foo"}, @connection.select_one(query.arel, nil, query.bound_attributes)) - assert_equal({"title" => "foo"}, @connection.select_one(query)) + Post.create!(title: "foo", body: "bar") + query = Post.where(title: "foo").select(:title) + assert_equal({ "title" => "foo" }, @connection.select_one(query.arel, nil, query.bound_attributes)) + assert_equal({ "title" => "foo" }, @connection.select_one(query)) assert @connection.select_all(query).is_a?(ActiveRecord::Result) assert_equal "foo", @connection.select_value(query) assert_equal ["foo"], @connection.select_values(query) @@ -273,7 +276,7 @@ module ActiveRecord def test_log_invalid_encoding error = assert_raise ActiveRecord::StatementInvalid do @connection.send :log, "SELECT 'ы' FROM DUAL" do - raise 'ы'.force_encoding(Encoding::ASCII_8BIT) + raise "ы".force_encoding(Encoding::ASCII_8BIT) end end diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 95d1f6b8a3..a70eb5a094 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase include ConnectionHelper @@ -21,42 +21,42 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase def (ActiveRecord::Base.connection).index_name_exists?(*); false; end expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) " - assert_equal expected, add_index(:people, :last_name, :length => nil) + assert_equal expected, add_index(:people, :last_name, length: nil) expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10)) " - assert_equal expected, add_index(:people, :last_name, :length => 10) + assert_equal expected, add_index(:people, :last_name, length: 10) expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15)) " - assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15) + assert_equal expected, add_index(:people, [:last_name, :first_name], length: 15) expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`) " - assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15}) + assert_equal expected, add_index(:people, [:last_name, :first_name], length: { last_name: 15 }) expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10)) " - assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10}) + assert_equal expected, add_index(:people, [:last_name, :first_name], length: { last_name: 15, first_name: 10 }) %w(SPATIAL FULLTEXT UNIQUE).each do |type| expected = "CREATE #{type} INDEX `index_people_on_last_name` ON `people` (`last_name`) " - assert_equal expected, add_index(:people, :last_name, :type => type) + assert_equal expected, add_index(:people, :last_name, type: type) end %w(btree hash).each do |using| expected = "CREATE INDEX `index_people_on_last_name` USING #{using} ON `people` (`last_name`) " - assert_equal expected, add_index(:people, :last_name, :using => using) + assert_equal expected, add_index(:people, :last_name, using: using) end expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) " - assert_equal expected, add_index(:people, :last_name, :length => 10, :using => :btree) + assert_equal expected, add_index(:people, :last_name, length: 10, using: :btree) expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) ALGORITHM = COPY" - assert_equal expected, add_index(:people, :last_name, :length => 10, using: :btree, algorithm: :copy) + assert_equal expected, add_index(:people, :last_name, length: 10, using: :btree, algorithm: :copy) assert_raise ArgumentError do add_index(:people, :last_name, algorithm: :coyp) end expected = "CREATE INDEX `index_people_on_last_name_and_first_name` USING btree ON `people` (`last_name`(15), `first_name`(15)) " - assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15, :using => :btree) + assert_equal expected, add_index(:people, [:last_name, :first_name], length: 15, using: :btree) end def test_index_in_create @@ -102,13 +102,13 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase def test_create_mysql_database_with_encoding assert_equal "CREATE DATABASE `matt` DEFAULT CHARACTER SET `utf8`", create_database(:matt) - assert_equal "CREATE DATABASE `aimonetti` DEFAULT CHARACTER SET `latin1`", create_database(:aimonetti, {:charset => 'latin1'}) - assert_equal "CREATE DATABASE `matt_aimonetti` DEFAULT CHARACTER SET `big5` COLLATE `big5_chinese_ci`", create_database(:matt_aimonetti, {:charset => :big5, :collation => :big5_chinese_ci}) + assert_equal "CREATE DATABASE `aimonetti` DEFAULT CHARACTER SET `latin1`", create_database(:aimonetti, charset: "latin1") + assert_equal "CREATE DATABASE `matt_aimonetti` DEFAULT CHARACTER SET `big5` COLLATE `big5_chinese_ci`", create_database(:matt_aimonetti, charset: :big5, collation: :big5_chinese_ci) end def test_recreate_mysql_database_with_encoding - create_database(:luca, {:charset => 'latin1'}) - assert_equal "CREATE DATABASE `luca` DEFAULT CHARACTER SET `latin1`", recreate_database(:luca, {:charset => 'latin1'}) + create_database(:luca, charset: "latin1") + assert_equal "CREATE DATABASE `luca` DEFAULT CHARACTER SET `latin1`", recreate_database(:luca, charset: "latin1") end def test_add_column @@ -116,11 +116,11 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase end def test_add_column_with_limit - assert_equal "ALTER TABLE `people` ADD `key` varchar(32)", add_column(:people, :key, :string, :limit => 32) + assert_equal "ALTER TABLE `people` ADD `key` varchar(32)", add_column(:people, :key, :string, limit: 32) end def test_drop_table_with_specific_database - assert_equal "DROP TABLE `otherdb`.`people`", drop_table('otherdb.people') + assert_equal "DROP TABLE `otherdb`.`people`", drop_table("otherdb.people") end def test_add_timestamps @@ -128,8 +128,8 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase begin ActiveRecord::Base.connection.create_table :delete_me ActiveRecord::Base.connection.add_timestamps :delete_me, null: true - assert column_present?('delete_me', 'updated_at', 'datetime') - assert column_present?('delete_me', 'created_at', 'datetime') + assert column_present?("delete_me", "updated_at", "datetime") + assert column_present?("delete_me", "created_at", "datetime") ensure ActiveRecord::Base.connection.drop_table :delete_me rescue nil end @@ -142,9 +142,9 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase ActiveRecord::Base.connection.create_table :delete_me do |t| t.timestamps null: true end - ActiveRecord::Base.connection.remove_timestamps :delete_me, { null: true } - assert !column_present?('delete_me', 'updated_at', 'datetime') - assert !column_present?('delete_me', 'created_at', 'datetime') + ActiveRecord::Base.connection.remove_timestamps :delete_me, null: true + assert !column_present?("delete_me", "updated_at", "datetime") + assert !column_present?("delete_me", "created_at", "datetime") ensure ActiveRecord::Base.connection.drop_table :delete_me rescue nil end @@ -185,6 +185,6 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase def column_present?(table_name, column_name, type) results = ActiveRecord::Base.connection.select_all("SHOW FIELDS FROM #{table_name} LIKE '#{column_name}'") - results.first && results.first['Type'] == type + results.first && results.first["Type"] == type end end diff --git a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb index abdf3dbf5b..8f7c803a21 100644 --- a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'models/topic' +require "models/topic" module ActiveRecord module ConnectionAdapters @@ -20,7 +20,7 @@ module ActiveRecord def test_create_question_marks str = "foo?bar" - x = Topic.create!(:title => str, :content => str) + x = Topic.create!(title: str, content: str) x.reload assert_equal str, x.title assert_equal str, x.content @@ -39,7 +39,7 @@ module ActiveRecord def test_create_null_bytes str = "foo\0bar" - x = Topic.create!(:title => str, :content => str) + x = Topic.create!(title: str, content: str) x.reload assert_equal str, x.title assert_equal str, x.content diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb index 739bb275ce..2fa39282fb 100644 --- a/activerecord/test/cases/adapters/mysql2/boolean_test.rb +++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb @@ -86,11 +86,11 @@ class Mysql2BooleanTest < ActiveRecord::Mysql2TestCase end def boolean_column - BooleanType.columns.find { |c| c.name == 'archived' } + BooleanType.columns.find { |c| c.name == "archived" } end def string_column - BooleanType.columns.find { |c| c.name == 'published' } + BooleanType.columns.find { |c| c.name == "published" } end def emulate_booleans(value) diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb index 9cb05119a2..50ba9ab831 100644 --- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb +++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb @@ -7,46 +7,46 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase repair_validations(CollationTest) def test_columns_include_collation_different_from_table - assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation - assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation + assert_equal "utf8_bin", CollationTest.columns_hash["string_cs_column"].collation + assert_equal "utf8_general_ci", CollationTest.columns_hash["string_ci_column"].collation end def test_case_sensitive - assert !CollationTest.columns_hash['string_ci_column'].case_sensitive? - assert CollationTest.columns_hash['string_cs_column'].case_sensitive? + assert !CollationTest.columns_hash["string_ci_column"].case_sensitive? + assert CollationTest.columns_hash["string_cs_column"].case_sensitive? end def test_case_insensitive_comparison_for_ci_column - CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => false) - CollationTest.create!(:string_ci_column => 'A') - invalid = CollationTest.new(:string_ci_column => 'a') + CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: false) + CollationTest.create!(string_ci_column: "A") + invalid = CollationTest.new(string_ci_column: "a") queries = assert_sql { invalid.save } ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) } assert_no_match(/lower/i, ci_uniqueness_query) end def test_case_insensitive_comparison_for_cs_column - CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => false) - CollationTest.create!(:string_cs_column => 'A') - invalid = CollationTest.new(:string_cs_column => 'a') + CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: false) + CollationTest.create!(string_cs_column: "A") + invalid = CollationTest.new(string_cs_column: "a") queries = assert_sql { invalid.save } - cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/)} + cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) } assert_match(/lower/i, cs_uniqueness_query) end def test_case_sensitive_comparison_for_ci_column - CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => true) - CollationTest.create!(:string_ci_column => 'A') - invalid = CollationTest.new(:string_ci_column => 'A') + CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: true) + CollationTest.create!(string_ci_column: "A") + invalid = CollationTest.new(string_ci_column: "A") queries = assert_sql { invalid.save } ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) } assert_match(/binary/i, ci_uniqueness_query) end def test_case_sensitive_comparison_for_cs_column - CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => true) - CollationTest.create!(:string_cs_column => 'A') - invalid = CollationTest.new(:string_cs_column => 'A') + CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: true) + CollationTest.create!(string_cs_column: "A") + invalid = CollationTest.new(string_cs_column: "A") queries = assert_sql { invalid.save } cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) } assert_no_match(/binary/i, cs_uniqueness_query) @@ -54,8 +54,8 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase def test_case_sensitive_comparison_for_binary_column CollationTest.validates_uniqueness_of(:binary_column, case_sensitive: true) - CollationTest.create!(binary_column: 'A') - invalid = CollationTest.new(binary_column: 'A') + CollationTest.create!(binary_column: "A") + invalid = CollationTest.new(binary_column: "A") queries = assert_sql { invalid.save } bin_uniqueness_query = queries.detect { |q| q.match(/binary_column/) } assert_no_match(/\bBINARY\b/, bin_uniqueness_query) diff --git a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb index c8028b6b36..8826ad7fd1 100644 --- a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb +++ b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase include SchemaDumpingHelper @@ -8,8 +8,8 @@ class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase setup do @connection = ActiveRecord::Base.connection @connection.create_table :charset_collations, force: true do |t| - t.string :string_ascii_bin, charset: 'ascii', collation: 'ascii_bin' - t.text :text_ucs2_unicode_ci, charset: 'ucs2', collation: 'ucs2_unicode_ci' + t.string :string_ascii_bin, charset: "ascii", collation: "ascii_bin" + t.text :text_ucs2_unicode_ci, charset: "ucs2", collation: "ucs2_unicode_ci" end end @@ -18,32 +18,32 @@ class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase end test "string column with charset and collation" do - column = @connection.columns(:charset_collations).find { |c| c.name == 'string_ascii_bin' } + column = @connection.columns(:charset_collations).find { |c| c.name == "string_ascii_bin" } assert_equal :string, column.type - assert_equal 'ascii_bin', column.collation + assert_equal "ascii_bin", column.collation end test "text column with charset and collation" do - column = @connection.columns(:charset_collations).find { |c| c.name == 'text_ucs2_unicode_ci' } + column = @connection.columns(:charset_collations).find { |c| c.name == "text_ucs2_unicode_ci" } assert_equal :text, column.type - assert_equal 'ucs2_unicode_ci', column.collation + assert_equal "ucs2_unicode_ci", column.collation end test "add column with charset and collation" do - @connection.add_column :charset_collations, :title, :string, charset: 'utf8', collation: 'utf8_bin' + @connection.add_column :charset_collations, :title, :string, charset: "utf8", collation: "utf8_bin" - column = @connection.columns(:charset_collations).find { |c| c.name == 'title' } + column = @connection.columns(:charset_collations).find { |c| c.name == "title" } assert_equal :string, column.type - assert_equal 'utf8_bin', column.collation + assert_equal "utf8_bin", column.collation end test "change column with charset and collation" do - @connection.add_column :charset_collations, :description, :string, charset: 'utf8', collation: 'utf8_unicode_ci' - @connection.change_column :charset_collations, :description, :text, charset: 'utf8', collation: 'utf8_general_ci' + @connection.add_column :charset_collations, :description, :string, charset: "utf8", collation: "utf8_unicode_ci" + @connection.change_column :charset_collations, :description, :text, charset: "utf8", collation: "utf8_general_ci" - column = @connection.columns(:charset_collations).find { |c| c.name == 'description' } + column = @connection.columns(:charset_collations).find { |c| c.name == "description" } assert_equal :text, column.type - assert_equal 'utf8_general_ci', column.collation + assert_equal "utf8_general_ci", column.collation end test "schema dump includes collation" do diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index fe610ae951..ff012efc5f 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase include ConnectionHelper @@ -9,7 +9,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def setup super @subscriber = SQLSubscriber.new - @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + @subscription = ActiveSupport::Notifications.subscribe("sql.active_record", @subscriber) @connection = ActiveRecord::Base.connection end @@ -20,9 +20,9 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_bad_connection assert_raise ActiveRecord::NoDatabaseError do - configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'inexistent_activerecord_unittest') + configuration = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest") connection = ActiveRecord::Base.mysql2_connection(configuration) - connection.drop_table 'ex', if_exists: true + connection.drop_table "ex", if_exists: true end end @@ -39,7 +39,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_no_automatic_reconnection_after_timeout assert @connection.active? - @connection.update('set @@wait_timeout=1') + @connection.update("set @@wait_timeout=1") sleep 2 assert !@connection.active? @@ -49,7 +49,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_successful_reconnection_after_timeout_with_manual_reconnect assert @connection.active? - @connection.update('set @@wait_timeout=1') + @connection.update("set @@wait_timeout=1") sleep 2 @connection.reconnect! assert @connection.active? @@ -57,15 +57,36 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_successful_reconnection_after_timeout_with_verify assert @connection.active? - @connection.update('set @@wait_timeout=1') + @connection.update("set @@wait_timeout=1") sleep 2 @connection.verify! assert @connection.active? end + def test_execute_after_disconnect + @connection.disconnect! + + assert_raise(ActiveRecord::StatementInvalid) do + @connection.execute("SELECT 1") + end + end + + def test_quote_after_disconnect + @connection.disconnect! + + assert_raise(Mysql2::Error) do + @connection.quote("string") + end + end + + def test_active_after_disconnect + @connection.disconnect! + assert_equal false, @connection.active? + end + def test_mysql_connection_collation_is_configured - assert_equal 'utf8_unicode_ci', @connection.show_variable('collation_connection') - assert_equal 'utf8_general_ci', ARUnit2Model.connection.show_variable('collation_connection') + assert_equal "utf8_unicode_ci", @connection.show_variable("collation_connection") + assert_equal "utf8_general_ci", ARUnit2Model.connection.show_variable("collation_connection") end def test_mysql_default_in_strict_mode @@ -92,29 +113,29 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_mysql_sql_mode_variable_overrides_strict_mode run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { 'sql_mode' => 'ansi' })) - result = ActiveRecord::Base.connection.select_value('SELECT @@SESSION.sql_mode') + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { "sql_mode" => "ansi" })) + result = ActiveRecord::Base.connection.select_value("SELECT @@SESSION.sql_mode") assert_no_match %r(STRICT_ALL_TABLES), result end end def test_passing_arbitary_flags_to_adapter run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.merge({flags: Mysql2::Client::COMPRESS})) + ActiveRecord::Base.establish_connection(orig_connection.merge(flags: Mysql2::Client::COMPRESS)) assert_equal (Mysql2::Client::COMPRESS | Mysql2::Client::FOUND_ROWS), ActiveRecord::Base.connection.raw_connection.query_options[:flags] end end def test_passing_flags_by_array_to_adapter run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.merge({flags: ['COMPRESS'] })) + ActiveRecord::Base.establish_connection(orig_connection.merge(flags: ["COMPRESS"])) assert_equal ["COMPRESS", "FOUND_ROWS"], ActiveRecord::Base.connection.raw_connection.query_options[:flags] end end def test_mysql_set_session_variable run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:default_week_format => 3}})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { default_week_format: 3 })) session_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.DEFAULT_WEEK_FORMAT" assert_equal 3, session_mode.rows.first.first.to_i end @@ -122,7 +143,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase def test_mysql_set_session_variable_to_default run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:default_week_format => :default}})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { default_week_format: :default })) global_mode = ActiveRecord::Base.connection.exec_query "SELECT @@GLOBAL.DEFAULT_WEEK_FORMAT" session_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.DEFAULT_WEEK_FORMAT" assert_equal global_mode.rows, session_mode.rows @@ -130,14 +151,14 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase end def test_logs_name_show_variable - @connection.show_variable 'foo' + @connection.show_variable "foo" assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_logs_name_rename_column_sql @connection.execute "CREATE TABLE `bar_baz` (`foo` varchar(255))" @subscriber.logged.clear - @connection.send(:rename_column_sql, 'bar_baz', 'foo', 'foo2') + @connection.send(:rename_column_sql, "bar_baz", "foo", "foo2") assert_equal "SCHEMA", @subscriber.logged[0][1] ensure @connection.execute "DROP TABLE `bar_baz`" @@ -155,19 +176,19 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase released_lock = @connection.release_advisory_lock(lock_name) assert released_lock, "expected release_advisory_lock to return true but it didn't" - assert test_lock_free(lock_name), 'expected the test lock to be available after releasing' + assert test_lock_free(lock_name), "expected the test lock to be available after releasing" end def test_release_non_existent_advisory_lock lock_name = "fake lock'n'name" released_non_existent_lock = @connection.release_advisory_lock(lock_name) assert_equal released_non_existent_lock, false, - 'expected release_advisory_lock to return false when there was no lock to release' + "expected release_advisory_lock to return false when there was no lock to release" end protected - def test_lock_free(lock_name) - @connection.select_value("SELECT IS_FREE_LOCK(#{@connection.quote(lock_name)})") == 1 - end + def test_lock_free(lock_name) + @connection.select_value("SELECT IS_FREE_LOCK(#{@connection.quote(lock_name)})") == 1 + end end diff --git a/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb index e349c67c93..135789a57d 100644 --- a/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +++ b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb @@ -5,23 +5,23 @@ class Mysql2DatetimePrecisionQuotingTest < ActiveRecord::Mysql2TestCase @connection = ActiveRecord::Base.connection end - test 'microsecond precision for MySQL gte 5.6.4' do - stub_version '5.6.4' + test "microsecond precision for MySQL gte 5.6.4" do + stub_version "5.6.4" assert_microsecond_precision end - test 'no microsecond precision for MySQL lt 5.6.4' do - stub_version '5.6.3' + test "no microsecond precision for MySQL lt 5.6.4" do + stub_version "5.6.3" assert_no_microsecond_precision end - test 'microsecond precision for MariaDB gte 5.3.0' do - stub_version '5.5.5-10.1.8-MariaDB-log' + test "microsecond precision for MariaDB gte 5.3.0" do + stub_version "5.5.5-10.1.8-MariaDB-log" assert_microsecond_precision end - test 'no microsecond precision for MariaDB lt 5.3.0' do - stub_version '5.2.9-MariaDB' + test "no microsecond precision for MariaDB lt 5.3.0" do + stub_version "5.2.9-MariaDB" assert_no_microsecond_precision end diff --git a/activerecord/test/cases/adapters/mysql2/enum_test.rb b/activerecord/test/cases/adapters/mysql2/enum_test.rb index 35dbc76d1b..7ad3e3ca2d 100644 --- a/activerecord/test/cases/adapters/mysql2/enum_test.rb +++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb @@ -5,22 +5,17 @@ class Mysql2EnumTest < ActiveRecord::Mysql2TestCase end def test_enum_limit - column = EnumTest.columns_hash['enum_column'] + column = EnumTest.columns_hash["enum_column"] assert_equal 8, column.limit end - def test_should_not_be_blob_or_text_column - column = EnumTest.columns_hash['enum_column'] - assert_not column.blob_or_text_column? - end - def test_should_not_be_unsigned - column = EnumTest.columns_hash['enum_column'] + column = EnumTest.columns_hash["enum_column"] assert_not column.unsigned? end def test_should_not_be_bigint - column = EnumTest.columns_hash['enum_column'] + column = EnumTest.columns_hash["enum_column"] assert_not column.bigint? end end diff --git a/activerecord/test/cases/adapters/mysql2/explain_test.rb b/activerecord/test/cases/adapters/mysql2/explain_test.rb index b783b5fcd9..7916921e5a 100644 --- a/activerecord/test/cases/adapters/mysql2/explain_test.rb +++ b/activerecord/test/cases/adapters/mysql2/explain_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'models/developer' -require 'models/computer' +require "models/developer" +require "models/computer" class Mysql2ExplainTest < ActiveRecord::Mysql2TestCase fixtures :developers diff --git a/activerecord/test/cases/adapters/mysql2/json_test.rb b/activerecord/test/cases/adapters/mysql2/json_test.rb index 9c3fef1b59..630cdb36a4 100644 --- a/activerecord/test/cases/adapters/mysql2/json_test.rb +++ b/activerecord/test/cases/adapters/mysql2/json_test.rb @@ -1,179 +1,195 @@ -require 'cases/helper' -require 'support/schema_dumping_helper' +require "cases/helper" +require "support/schema_dumping_helper" if ActiveRecord::Base.connection.supports_json? -class Mysql2JSONTest < ActiveRecord::Mysql2TestCase - include SchemaDumpingHelper - self.use_transactional_tests = false + class Mysql2JSONTest < ActiveRecord::Mysql2TestCase + include SchemaDumpingHelper + self.use_transactional_tests = false - class JsonDataType < ActiveRecord::Base - self.table_name = 'json_data_type' + class JsonDataType < ActiveRecord::Base + self.table_name = "json_data_type" - store_accessor :settings, :resolution - end + store_accessor :settings, :resolution + end - def setup - @connection = ActiveRecord::Base.connection - begin - @connection.create_table('json_data_type') do |t| - t.json 'payload' - t.json 'settings' + def setup + @connection = ActiveRecord::Base.connection + begin + @connection.create_table("json_data_type") do |t| + t.json "payload" + t.json "settings" + end end end - end - def teardown - @connection.drop_table :json_data_type, if_exists: true - JsonDataType.reset_column_information - end + def teardown + @connection.drop_table :json_data_type, if_exists: true + JsonDataType.reset_column_information + end - def test_column - column = JsonDataType.columns_hash["payload"] - assert_equal :json, column.type - assert_equal 'json', column.sql_type + def test_column + column = JsonDataType.columns_hash["payload"] + assert_equal :json, column.type + assert_equal "json", column.sql_type - type = JsonDataType.type_for_attribute("payload") - assert_not type.binary? - end + type = JsonDataType.type_for_attribute("payload") + assert_not type.binary? + end - def test_change_table_supports_json - @connection.change_table('json_data_type') do |t| - t.json 'users' + def test_change_table_supports_json + @connection.change_table("json_data_type") do |t| + t.json "users" + end + JsonDataType.reset_column_information + column = JsonDataType.columns_hash["users"] + assert_equal :json, column.type end - JsonDataType.reset_column_information - column = JsonDataType.columns_hash['users'] - assert_equal :json, column.type - end - def test_schema_dumping - output = dump_table_schema("json_data_type") - assert_match(/t\.json\s+"settings"/, output) - end + def test_schema_dumping + output = dump_table_schema("json_data_type") + assert_match(/t\.json\s+"settings"/, output) + end - def test_cast_value_on_write - x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar} - assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast) - assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload) - x.save - assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload) - end + def test_cast_value_on_write + x = JsonDataType.new payload: { "string" => "foo", :symbol => :bar } + assert_equal({ "string" => "foo", :symbol => :bar }, x.payload_before_type_cast) + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.payload) + x.save + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.reload.payload) + end - def test_type_cast_json - type = JsonDataType.type_for_attribute("payload") + def test_type_cast_json + type = JsonDataType.type_for_attribute("payload") - data = "{\"a_key\":\"a_value\"}" - hash = type.deserialize(data) - assert_equal({'a_key' => 'a_value'}, hash) - assert_equal({'a_key' => 'a_value'}, type.deserialize(data)) + data = "{\"a_key\":\"a_value\"}" + hash = type.deserialize(data) + assert_equal({ "a_key" => "a_value" }, hash) + assert_equal({ "a_key" => "a_value" }, type.deserialize(data)) - assert_equal({}, type.deserialize("{}")) - assert_equal({'key'=>nil}, type.deserialize('{"key": null}')) - assert_equal({'c'=>'}','"a"'=>'b "a b'}, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) - end + assert_equal({}, type.deserialize("{}")) + assert_equal({ "key"=>nil }, type.deserialize('{"key": null}')) + assert_equal({ "c"=>"}",'"a"'=>'b "a b' }, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) + end - def test_rewrite - @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" - x = JsonDataType.first - x.payload = { '"a\'' => 'b' } - assert x.save! - end + def test_rewrite + @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" + x = JsonDataType.first + x.payload = { '"a\'' => "b" } + assert x.save! + end - def test_select - @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" - x = JsonDataType.first - assert_equal({'k' => 'v'}, x.payload) - end + def test_select + @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" + x = JsonDataType.first + assert_equal({ "k" => "v" }, x.payload) + end - def test_select_multikey - @connection.execute %q|insert into json_data_type (payload) VALUES ('{"k1":"v1", "k2":"v2", "k3":[1,2,3]}')| - x = JsonDataType.first - assert_equal({'k1' => 'v1', 'k2' => 'v2', 'k3' => [1,2,3]}, x.payload) - end + def test_select_multikey + @connection.execute %q|insert into json_data_type (payload) VALUES ('{"k1":"v1", "k2":"v2", "k3":[1,2,3]}')| + x = JsonDataType.first + assert_equal({ "k1" => "v1", "k2" => "v2", "k3" => [1,2,3] }, x.payload) + end - def test_null_json - @connection.execute %q|insert into json_data_type (payload) VALUES(null)| - x = JsonDataType.first - assert_equal(nil, x.payload) - end + def test_null_json + @connection.execute "insert into json_data_type (payload) VALUES(null)" + x = JsonDataType.first + assert_equal(nil, x.payload) + end - def test_select_array_json_value - @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| - x = JsonDataType.first - assert_equal(['v0', {'k1' => 'v1'}], x.payload) - end + def test_select_array_json_value + @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| + x = JsonDataType.first + assert_equal(["v0", { "k1" => "v1" }], x.payload) + end - def test_rewrite_array_json_value - @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| - x = JsonDataType.first - x.payload = ['v1', {'k2' => 'v2'}, 'v3'] - assert x.save! - end + def test_select_nil_json_after_create + json = JsonDataType.create(payload: nil) + x = JsonDataType.where(payload:nil).first + assert_equal(json, x) + end - def test_with_store_accessors - x = JsonDataType.new(resolution: "320×480") - assert_equal "320×480", x.resolution + def test_select_nil_json_after_update + json = JsonDataType.create(payload: "foo") + x = JsonDataType.where(payload:nil).first + assert_equal(nil, x) - x.save! - x = JsonDataType.first - assert_equal "320×480", x.resolution + json.update_attributes payload: nil + x = JsonDataType.where(payload:nil).first + assert_equal(json.reload, x) + end - x.resolution = "640×1136" - x.save! + def test_rewrite_array_json_value + @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| + x = JsonDataType.first + x.payload = ["v1", { "k2" => "v2" }, "v3"] + assert x.save! + end - x = JsonDataType.first - assert_equal "640×1136", x.resolution - end + def test_with_store_accessors + x = JsonDataType.new(resolution: "320×480") + assert_equal "320×480", x.resolution - def test_duplication_with_store_accessors - x = JsonDataType.new(resolution: "320×480") - assert_equal "320×480", x.resolution + x.save! + x = JsonDataType.first + assert_equal "320×480", x.resolution - y = x.dup - assert_equal "320×480", y.resolution - end + x.resolution = "640×1136" + x.save! - def test_yaml_round_trip_with_store_accessors - x = JsonDataType.new(resolution: "320×480") - assert_equal "320×480", x.resolution + x = JsonDataType.first + assert_equal "640×1136", x.resolution + end - y = YAML.load(YAML.dump(x)) - assert_equal "320×480", y.resolution - end + def test_duplication_with_store_accessors + x = JsonDataType.new(resolution: "320×480") + assert_equal "320×480", x.resolution - def test_changes_in_place - json = JsonDataType.new - assert_not json.changed? + y = x.dup + assert_equal "320×480", y.resolution + end - json.payload = { 'one' => 'two' } - assert json.changed? - assert json.payload_changed? + def test_yaml_round_trip_with_store_accessors + x = JsonDataType.new(resolution: "320×480") + assert_equal "320×480", x.resolution - json.save! - assert_not json.changed? + y = YAML.load(YAML.dump(x)) + assert_equal "320×480", y.resolution + end - json.payload['three'] = 'four' - assert json.payload_changed? + def test_changes_in_place + json = JsonDataType.new + assert_not json.changed? - json.save! - json.reload + json.payload = { "one" => "two" } + assert json.changed? + assert json.payload_changed? - assert_equal({ 'one' => 'two', 'three' => 'four' }, json.payload) - assert_not json.changed? - end + json.save! + assert_not json.changed? - def test_assigning_string_literal - json = JsonDataType.create(payload: "foo") - assert_equal "foo", json.payload - end + json.payload["three"] = "four" + assert json.payload_changed? - def test_assigning_number - json = JsonDataType.create(payload: 1.234) - assert_equal 1.234, json.payload - end + json.save! + json.reload - def test_assigning_boolean - json = JsonDataType.create(payload: true) - assert_equal true, json.payload + assert_equal({ "one" => "two", "three" => "four" }, json.payload) + assert_not json.changed? + end + + def test_assigning_string_literal + json = JsonDataType.create(payload: "foo") + assert_equal "foo", json.payload + end + + def test_assigning_number + json = JsonDataType.create(payload: 1.234) + assert_equal 1.234, json.payload + end + + def test_assigning_boolean + json = JsonDataType.create(payload: true) + assert_equal true, json.payload + end end end -end diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb index 61dd0828d0..69336eb906 100644 --- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb @@ -11,15 +11,15 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_exec_query_nothing_raises_with_no_result_queries assert_nothing_raised do with_example_table do - @conn.exec_query('INSERT INTO ex (number) VALUES (1)') - @conn.exec_query('DELETE FROM ex WHERE number = 1') + @conn.exec_query("INSERT INTO ex (number) VALUES (1)") + @conn.exec_query("DELETE FROM ex WHERE number = 1") end end end def test_valid_column with_example_table do - column = @conn.columns('ex').find { |col| col.name == 'id' } + column = @conn.columns("ex").find { |col| col.name == "id" } assert @conn.valid_type?(column.type) end end @@ -45,8 +45,8 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_columns_for_distinct_with_case assert_equal( - 'posts.id, CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0', - @conn.columns_for_distinct('posts.id', + "posts.id, CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0", + @conn.columns_for_distinct("posts.id", ["CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END"]) ) end @@ -67,7 +67,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase private - def with_example_table(definition = 'id int auto_increment primary key, number int, data varchar(255)', &block) - super(@conn, 'ex', definition, &block) - end + def with_example_table(definition = "id int auto_increment primary key, number int, data varchar(255)", &block) + super(@conn, "ex", definition, &block) + end end diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb index ffb4e2c5cf..776549eb7a 100644 --- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb +++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb @@ -4,24 +4,24 @@ require "cases/helper" # reserved word names (ie: group, order, values, etc...) class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase class Group < ActiveRecord::Base - Group.table_name = 'group' + Group.table_name = "group" belongs_to :select has_one :values end class Select < ActiveRecord::Base - Select.table_name = 'select' + Select.table_name = "select" has_many :groups end class Values < ActiveRecord::Base - Values.table_name = 'values' + Values.table_name = "values" end class Distinct < ActiveRecord::Base - Distinct.table_name = 'distinct' + Distinct.table_name = "distinct" has_and_belongs_to_many :selects - has_many :values, :through => :groups + has_many :values, through: :groups end def setup @@ -30,15 +30,15 @@ class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase # we call execute directly here (and do similar below) because ActiveRecord::Base#create_table() # will fail with these table names if these test cases fail - create_tables_directly 'group'=>'id int auto_increment primary key, `order` varchar(255), select_id int', - 'select'=>'id int auto_increment primary key', - 'values'=>'id int auto_increment primary key, group_id int', - 'distinct'=>'id int auto_increment primary key', - 'distinct_select'=>'distinct_id int, select_id int' + create_tables_directly "group"=>"id int auto_increment primary key, `order` varchar(255), select_id int", + "select"=>"id int auto_increment primary key", + "values"=>"id int auto_increment primary key, group_id int", + "distinct"=>"id int auto_increment primary key", + "distinct_select"=>"distinct_id int, select_id int" end teardown do - drop_tables_directly ['group', 'select', 'values', 'distinct', 'distinct_select', 'order'] + drop_tables_directly ["group", "select", "values", "distinct", "distinct_select", "order"] end # create tables with reserved-word names and columns @@ -57,9 +57,9 @@ class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase # alter column with a reserved-word name in a table with a reserved-word name def test_change_columns - assert_nothing_raised { @connection.change_column_default(:group, :order, 'whatever') } + assert_nothing_raised { @connection.change_column_default(:group, :order, "whatever") } #the quoting here will reveal any double quoting issues in change_column's interaction with the column method in the adapter - assert_nothing_raised { @connection.change_column('group', 'order', :Int, :default => 0) } + assert_nothing_raised { @connection.change_column("group", "order", :Int, default: 0) } assert_nothing_raised { @connection.rename_column(:group, :order, :values) } end @@ -78,11 +78,11 @@ class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase create_test_fixtures :select, :distinct, :group, :values, :distinct_select x = nil assert_nothing_raised { x = Group.new } - x.order = 'x' + x.order = "x" assert_nothing_raised { x.save } - x.order = 'y' + x.order = "y" assert_nothing_raised { x.save } - assert_nothing_raised { Group.find_by_order('y') } + assert_nothing_raised { Group.find_by_order("y") } assert_nothing_raised { Group.find(1) } end @@ -124,29 +124,28 @@ class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase end def test_associations_work_with_reserved_words - assert_nothing_raised { Select.all.merge!(:includes => [:groups]).to_a } + assert_nothing_raised { Select.all.merge!(includes: [:groups]).to_a } end #the following functions were added to DRY test cases private - # custom fixture loader, uses FixtureSet#create_fixtures and appends base_path to the current file's path - def create_test_fixtures(*fixture_names) - ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT + "/reserved_words", fixture_names) - end - - # custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name - def drop_tables_directly(table_names, connection = @connection) - table_names.each do |name| - connection.drop_table name, if_exists: true + # custom fixture loader, uses FixtureSet#create_fixtures and appends base_path to the current file's path + def create_test_fixtures(*fixture_names) + ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT + "/reserved_words", fixture_names) end - end - # custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns - def create_tables_directly (tables, connection = @connection) - tables.each do |table_name, column_properties| - connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )") + # custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name + def drop_tables_directly(table_names, connection = @connection) + table_names.each do |name| + connection.drop_table name, if_exists: true + end end - end + # custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns + def create_tables_directly (tables, connection = @connection) + tables.each do |table_name, column_properties| + connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )") + end + end end diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb index 7c89fda582..fa54aac6b3 100644 --- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb +++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb @@ -18,7 +18,7 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase connection.initialize_schema_migrations_table - assert connection.column_exists?(table_name, :version, :string, collation: 'utf8_general_ci') + assert connection.column_exists?(table_name, :version, :string, collation: "utf8_general_ci") end end @@ -29,31 +29,31 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase connection.initialize_internal_metadata_table - assert connection.column_exists?(table_name, :key, :string, collation: 'utf8_general_ci') + assert connection.column_exists?(table_name, :key, :string, collation: "utf8_general_ci") end end private - def with_encoding_utf8mb4 - database_name = connection.current_database - database_info = connection.select_one("SELECT * FROM information_schema.schemata WHERE schema_name = '#{database_name}'") + def with_encoding_utf8mb4 + database_name = connection.current_database + database_info = connection.select_one("SELECT * FROM information_schema.schemata WHERE schema_name = '#{database_name}'") - original_charset = database_info["DEFAULT_CHARACTER_SET_NAME"] - original_collation = database_info["DEFAULT_COLLATION_NAME"] + original_charset = database_info["DEFAULT_CHARACTER_SET_NAME"] + original_collation = database_info["DEFAULT_COLLATION_NAME"] - execute("ALTER DATABASE #{database_name} DEFAULT CHARACTER SET utf8mb4") + execute("ALTER DATABASE #{database_name} DEFAULT CHARACTER SET utf8mb4") - yield - ensure - execute("ALTER DATABASE #{database_name} DEFAULT CHARACTER SET #{original_charset} COLLATE #{original_collation}") - end + yield + ensure + execute("ALTER DATABASE #{database_name} DEFAULT CHARACTER SET #{original_charset} COLLATE #{original_collation}") + end - def connection - @connection ||= ActiveRecord::Base.connection - end + def connection + @connection ||= ActiveRecord::Base.connection + end - def execute(sql) - connection.execute(sql) - end + def execute(sql) + connection.execute(sql) + end end diff --git a/activerecord/test/cases/adapters/mysql2/schema_test.rb b/activerecord/test/cases/adapters/mysql2/schema_test.rb index 43957791b1..aea930cfe6 100644 --- a/activerecord/test/cases/adapters/mysql2/schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/schema_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'models/post' -require 'models/comment' +require "models/post" +require "models/comment" module ActiveRecord module ConnectionAdapters @@ -16,7 +16,7 @@ module ActiveRecord @omgpost = Class.new(ActiveRecord::Base) do self.inheritance_column = :disabled self.table_name = "#{db}.#{table}" - def self.name; 'Post'; end + def self.name; "Post"; end end end @@ -31,13 +31,13 @@ module ActiveRecord t.float :float_25, limit: 25 end - column_no_limit = @connection.columns(:mysql_doubles).find { |c| c.name == 'float_no_limit' } - column_short = @connection.columns(:mysql_doubles).find { |c| c.name == 'float_short' } - column_long = @connection.columns(:mysql_doubles).find { |c| c.name == 'float_long' } + column_no_limit = @connection.columns(:mysql_doubles).find { |c| c.name == "float_no_limit" } + column_short = @connection.columns(:mysql_doubles).find { |c| c.name == "float_short" } + column_long = @connection.columns(:mysql_doubles).find { |c| c.name == "float_long" } - column_23 = @connection.columns(:mysql_doubles).find { |c| c.name == 'float_23' } - column_24 = @connection.columns(:mysql_doubles).find { |c| c.name == 'float_24' } - column_25 = @connection.columns(:mysql_doubles).find { |c| c.name == 'float_25' } + column_23 = @connection.columns(:mysql_doubles).find { |c| c.name == "float_23" } + column_24 = @connection.columns(:mysql_doubles).find { |c| c.name == "float_24" } + column_25 = @connection.columns(:mysql_doubles).find { |c| c.name == "float_25" } # Mysql floats are precision 0..24, Mysql doubles are precision 25..53 assert_equal 24, column_no_limit.limit @@ -56,7 +56,7 @@ module ActiveRecord end def test_primary_key - assert_equal 'id', @omgpost.primary_key + assert_equal "id", @omgpost.primary_key end def test_data_source_exists? @@ -69,18 +69,18 @@ module ActiveRecord end def test_dump_indexes - index_a_name = 'index_key_tests_on_snack' - index_b_name = 'index_key_tests_on_pizza' - index_c_name = 'index_key_tests_on_awesome' + index_a_name = "index_key_tests_on_snack" + index_b_name = "index_key_tests_on_pizza" + index_c_name = "index_key_tests_on_awesome" - table = 'key_tests' + table = "key_tests" indexes = @connection.indexes(table).sort_by(&:name) assert_equal 3,indexes.size - index_a = indexes.select{|i| i.name == index_a_name}[0] - index_b = indexes.select{|i| i.name == index_b_name}[0] - index_c = indexes.select{|i| i.name == index_c_name}[0] + index_a = indexes.select { |i| i.name == index_a_name }[0] + index_b = indexes.select { |i| i.name == index_b_name }[0] + index_c = indexes.select { |i| i.name == index_c_name }[0] assert_equal :btree, index_a.using assert_nil index_a.type assert_equal :btree, index_b.using @@ -103,3 +103,24 @@ module ActiveRecord end end end + +class Mysql2AnsiQuotesTest < ActiveRecord::Mysql2TestCase + def setup + @connection = ActiveRecord::Base.connection + @connection.execute("SET SESSION sql_mode='ANSI_QUOTES'") + end + + def teardown + @connection.reconnect! + end + + def test_primary_key_method_with_ansi_quotes + assert_equal "id", @connection.primary_key("topics") + end + + def test_foreign_keys_method_with_ansi_quotes + fks = @connection.foreign_keys("lessons_students") + assert_equal([["lessons_students", "students", :cascade]], + fks.map { |fk| [fk.from_table, fk.to_table, fk.on_delete] }) + end +end diff --git a/activerecord/test/cases/adapters/mysql2/sp_test.rb b/activerecord/test/cases/adapters/mysql2/sp_test.rb index 4197ba45f1..4182532535 100644 --- a/activerecord/test/cases/adapters/mysql2/sp_test.rb +++ b/activerecord/test/cases/adapters/mysql2/sp_test.rb @@ -1,13 +1,13 @@ require "cases/helper" -require 'models/topic' -require 'models/reply' +require "models/topic" +require "models/reply" class Mysql2StoredProcedureTest < ActiveRecord::Mysql2TestCase fixtures :topics def setup @connection = ActiveRecord::Base.connection - unless ActiveRecord::Base.connection.version >= '5.6.0' + unless ActiveRecord::Base.connection.version >= "5.6.0" skip("no stored procedure support") end end @@ -17,19 +17,19 @@ class Mysql2StoredProcedureTest < ActiveRecord::Mysql2TestCase # In MySQL 5.6, CLIENT_MULTI_RESULTS is enabled by default. # http://dev.mysql.com/doc/refman/5.6/en/call.html def test_multi_results - rows = @connection.select_rows('CALL ten();') + rows = @connection.select_rows("CALL ten();") assert_equal 10, rows[0][0].to_i, "ten() did not return 10 as expected: #{rows.inspect}" assert @connection.active?, "Bad connection use by 'Mysql2Adapter.select_rows'" end def test_multi_results_from_select_one - row = @connection.select_one('CALL topics(1);') - assert_equal 'David', row['author_name'] + row = @connection.select_one("CALL topics(1);") + assert_equal "David", row["author_name"] assert @connection.active?, "Bad connection use by 'Mysql2Adapter.select_one'" end def test_multi_results_from_find_by_sql - topics = Topic.find_by_sql 'CALL topics(3);' + topics = Topic.find_by_sql "CALL topics(3);" assert_equal 3, topics.size assert @connection.active?, "Bad connection use by 'Mysql2Adapter.select'" end diff --git a/activerecord/test/cases/adapters/mysql2/sql_types_test.rb b/activerecord/test/cases/adapters/mysql2/sql_types_test.rb index 4926bc2267..bee42d48f1 100644 --- a/activerecord/test/cases/adapters/mysql2/sql_types_test.rb +++ b/activerecord/test/cases/adapters/mysql2/sql_types_test.rb @@ -2,10 +2,10 @@ require "cases/helper" class Mysql2SqlTypesTest < ActiveRecord::Mysql2TestCase def test_binary_types - assert_equal 'varbinary(64)', type_to_sql(:binary, 64) - assert_equal 'varbinary(4095)', type_to_sql(:binary, 4095) - assert_equal 'blob', type_to_sql(:binary, 4096) - assert_equal 'blob', type_to_sql(:binary) + assert_equal "varbinary(64)", type_to_sql(:binary, 64) + assert_equal "varbinary(4095)", type_to_sql(:binary, 4095) + assert_equal "blob", type_to_sql(:binary, 4096) + assert_equal "blob", type_to_sql(:binary) end def type_to_sql(*args) diff --git a/activerecord/test/cases/adapters/mysql2/table_options_test.rb b/activerecord/test/cases/adapters/mysql2/table_options_test.rb index af121ee7d9..61a8ce9bc0 100644 --- a/activerecord/test/cases/adapters/mysql2/table_options_test.rb +++ b/activerecord/test/cases/adapters/mysql2/table_options_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class Mysql2TableOptionsTest < ActiveRecord::Mysql2TestCase include SchemaDumpingHelper diff --git a/activerecord/test/cases/adapters/mysql2/transaction_test.rb b/activerecord/test/cases/adapters/mysql2/transaction_test.rb index 0e37c70e5c..edd5353ee3 100644 --- a/activerecord/test/cases/adapters/mysql2/transaction_test.rb +++ b/activerecord/test/cases/adapters/mysql2/transaction_test.rb @@ -1,12 +1,12 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" module ActiveRecord class Mysql2TransactionTest < ActiveRecord::Mysql2TestCase self.use_transactional_tests = false class Sample < ActiveRecord::Base - self.table_name = 'samples' + self.table_name = "samples" end setup do @@ -14,9 +14,9 @@ module ActiveRecord @connection.clear_cache! @connection.transaction do - @connection.drop_table 'samples', if_exists: true - @connection.create_table('samples') do |t| - t.integer 'value' + @connection.drop_table "samples", if_exists: true + @connection.create_table("samples") do |t| + t.integer "value" end end @@ -24,35 +24,28 @@ module ActiveRecord end teardown do - @connection.drop_table 'samples', if_exists: true + @connection.drop_table "samples", if_exists: true end - test "raises error when a serialization failure occurs" do - assert_raises(ActiveRecord::TransactionSerializationError) do - thread = Thread.new do - Sample.transaction isolation: :serializable do - Sample.delete_all - - 10.times do |i| - sleep 0.1 + test "raises Deadlocked when a deadlock is encountered" do + assert_raises(ActiveRecord::Deadlocked) do + s1 = Sample.create value: 1 + s2 = Sample.create value: 2 - Sample.create value: i - end + thread = Thread.new do + Sample.transaction do + s1.lock! + sleep 1 + s2.update_attributes value: 1 end end - sleep 0.1 - - Sample.transaction isolation: :serializable do - Sample.delete_all - - 10.times do |i| - sleep 0.1 - - Sample.create value: i - end + sleep 0.5 + Sample.transaction do + s2.lock! sleep 1 + s1.update_attributes value: 2 end thread.join diff --git a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb index 439e2ce6f7..d3c65f3d94 100644 --- a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase def setup @@ -15,12 +15,12 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase def test_create_database_with_encoding assert_equal %(CREATE DATABASE "matt" ENCODING = 'utf8'), create_database(:matt) - assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1) - assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, 'encoding' => :latin1) + assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, encoding: :latin1) + assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, "encoding" => :latin1) end def test_create_database_with_collation_and_ctype - assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'UTF8' LC_COLLATE = 'ja_JP.UTF8' LC_CTYPE = 'ja_JP.UTF8'), create_database(:aimonetti, :encoding => :"UTF8", :collation => :"ja_JP.UTF8", :ctype => :"ja_JP.UTF8") + assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'UTF8' LC_COLLATE = 'ja_JP.UTF8' LC_CTYPE = 'ja_JP.UTF8'), create_database(:aimonetti, encoding: :"UTF8", collation: :"ja_JP.UTF8", ctype: :"ja_JP.UTF8") end def test_add_index @@ -31,10 +31,10 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase assert_equal expected, add_index(:people, :last_name, unique: true, where: "state = 'active'") expected = %(CREATE UNIQUE INDEX "index_people_on_lower_last_name" ON "people" (lower(last_name))) - assert_equal expected, add_index(:people, 'lower(last_name)', unique: true) + assert_equal expected, add_index(:people, "lower(last_name)", unique: true) expected = %(CREATE UNIQUE INDEX "index_people_on_last_name_varchar_pattern_ops" ON "people" (last_name varchar_pattern_ops)) - assert_equal expected, add_index(:people, 'last_name varchar_pattern_ops', unique: true) + assert_equal expected, add_index(:people, "last_name varchar_pattern_ops", unique: true) expected = %(CREATE INDEX CONCURRENTLY "index_people_on_last_name" ON "people" ("last_name")) assert_equal expected, add_index(:people, :last_name, algorithm: :concurrently) @@ -50,7 +50,7 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase assert_equal expected, add_index(:people, :last_name, using: type, unique: true, where: "state = 'active'") expected = %(CREATE UNIQUE INDEX "index_people_on_lower_last_name" ON "people" USING #{type} (lower(last_name))) - assert_equal expected, add_index(:people, 'lower(last_name)', using: type, unique: true) + assert_equal expected, add_index(:people, "lower(last_name)", using: type, unique: true) end assert_raise ArgumentError do @@ -63,7 +63,7 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase def test_remove_index # remove_index calls index_name_for_remove which can't work since execute is stubbed ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:define_method, :index_name_for_remove) do |*| - 'index_people_on_last_name' + "index_people_on_last_name" end expected = %(DROP INDEX CONCURRENTLY "index_people_on_last_name") @@ -81,6 +81,12 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase assert_equal expected, remove_index(:people, name: "index_people_on_last_name", algorithm: :concurrently) end + def test_remove_index_with_wrong_option + assert_raises ArgumentError do + remove_index(:people, coulmn: :last_name) + end + end + private def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index 380a90d765..97960b6c51 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -1,35 +1,35 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper include InTimeZone class PgArray < ActiveRecord::Base - self.table_name = 'pg_arrays' + self.table_name = "pg_arrays" end def setup @connection = ActiveRecord::Base.connection - enable_extension!('hstore', @connection) + enable_extension!("hstore", @connection) @connection.transaction do - @connection.create_table('pg_arrays') do |t| - t.string 'tags', array: true - t.integer 'ratings', array: true + @connection.create_table("pg_arrays") do |t| + t.string "tags", array: true + t.integer "ratings", array: true t.datetime :datetimes, array: true t.hstore :hstores, array: true end end PgArray.reset_column_information - @column = PgArray.columns_hash['tags'] + @column = PgArray.columns_hash["tags"] @type = PgArray.type_for_attribute("tags") end teardown do - @connection.drop_table 'pg_arrays', if_exists: true - disable_extension!('hstore', @connection) + @connection.drop_table "pg_arrays", if_exists: true + disable_extension!("hstore", @connection) end def test_column @@ -38,26 +38,26 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase assert @column.array? assert_not @type.binary? - ratings_column = PgArray.columns_hash['ratings'] + ratings_column = PgArray.columns_hash["ratings"] assert_equal :integer, ratings_column.type assert ratings_column.array? end def test_default - @connection.add_column 'pg_arrays', 'score', :integer, array: true, default: [4, 4, 2] + @connection.add_column "pg_arrays", "score", :integer, array: true, default: [4, 4, 2] PgArray.reset_column_information - assert_equal([4, 4, 2], PgArray.column_defaults['score']) + assert_equal([4, 4, 2], PgArray.column_defaults["score"]) assert_equal([4, 4, 2], PgArray.new.score) ensure PgArray.reset_column_information end def test_default_strings - @connection.add_column 'pg_arrays', 'names', :string, array: true, default: ["foo", "bar"] + @connection.add_column "pg_arrays", "names", :string, array: true, default: ["foo", "bar"] PgArray.reset_column_information - assert_equal(["foo", "bar"], PgArray.column_defaults['names']) + assert_equal(["foo", "bar"], PgArray.column_defaults["names"]) assert_equal(["foo", "bar"], PgArray.new.names) ensure PgArray.reset_column_information @@ -68,10 +68,10 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase @connection.change_column :pg_arrays, :snippets, :text, array: true, default: [] PgArray.reset_column_information - column = PgArray.columns_hash['snippets'] + column = PgArray.columns_hash["snippets"] assert_equal :text, column.type - assert_equal [], PgArray.column_defaults['snippets'] + assert_equal [], PgArray.column_defaults["snippets"] assert column.array? end @@ -88,17 +88,17 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase @connection.change_column_default :pg_arrays, :tags, [] PgArray.reset_column_information - assert_equal [], PgArray.column_defaults['tags'] + assert_equal [], PgArray.column_defaults["tags"] end def test_type_cast_array - assert_equal(['1', '2', '3'], @type.deserialize('{1,2,3}')) - assert_equal([], @type.deserialize('{}')) - assert_equal([nil], @type.deserialize('{NULL}')) + assert_equal(["1", "2", "3"], @type.deserialize("{1,2,3}")) + assert_equal([], @type.deserialize("{}")) + assert_equal([nil], @type.deserialize("{NULL}")) end def test_type_cast_integers - x = PgArray.new(ratings: ['1', '2']) + x = PgArray.new(ratings: ["1", "2"]) assert_equal([1, 2], x.ratings) @@ -117,15 +117,15 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase def test_select_with_strings @connection.execute "insert into pg_arrays (tags) VALUES ('{1,2,3}')" x = PgArray.first - assert_equal(['1','2','3'], x.tags) + assert_equal(["1","2","3"], x.tags) end def test_rewrite_with_strings @connection.execute "insert into pg_arrays (tags) VALUES ('{1,2,3}')" x = PgArray.first - x.tags = ['1','2','3','4'] + x.tags = ["1","2","3","4"] x.save! - assert_equal ['1','2','3','4'], x.reload.tags + assert_equal ["1","2","3","4"], x.reload.tags end def test_select_with_integers @@ -137,25 +137,25 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase def test_rewrite_with_integers @connection.execute "insert into pg_arrays (ratings) VALUES ('{1,2,3}')" x = PgArray.first - x.ratings = [2, '3', 4] + x.ratings = [2, "3", 4] x.save! assert_equal [2, 3, 4], x.reload.ratings end def test_multi_dimensional_with_strings - assert_cycle(:tags, [[['1'], ['2']], [['2'], ['3']]]) + assert_cycle(:tags, [[["1"], ["2"]], [["2"], ["3"]]]) end def test_with_empty_strings - assert_cycle(:tags, [ '1', '2', '', '4', '', '5' ]) + assert_cycle(:tags, [ "1", "2", "", "4", "", "5" ]) end def test_with_multi_dimensional_empty_strings - assert_cycle(:tags, [[['1', '2'], ['', '4'], ['', '5']]]) + assert_cycle(:tags, [[["1", "2"], ["", "4"], ["", "5"]]]) end def test_with_arbitrary_whitespace - assert_cycle(:tags, [[['1', '2'], [' ', '4'], [' ', '5']]]) + assert_cycle(:tags, [[["1", "2"], [" ", "4"], [" ", "5"]]]) end def test_multi_dimensional_with_integers @@ -163,34 +163,39 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase end def test_strings_with_quotes - assert_cycle(:tags, ['this has','some "s that need to be escaped"']) + assert_cycle(:tags, ["this has",'some "s that need to be escaped"']) end def test_strings_with_commas - assert_cycle(:tags, ['this,has','many,values']) + assert_cycle(:tags, ["this,has","many,values"]) end def test_strings_with_array_delimiters - assert_cycle(:tags, ['{','}']) + assert_cycle(:tags, ["{","}"]) end def test_strings_with_null_strings - assert_cycle(:tags, ['NULL','NULL']) + assert_cycle(:tags, ["NULL","NULL"]) end def test_contains_nils - assert_cycle(:tags, ['1',nil,nil]) + assert_cycle(:tags, ["1",nil,nil]) end def test_insert_fixture tag_values = ["val1", "val2", "val3_with_'_multiple_quote_'_chars"] - @connection.insert_fixture({"tags" => tag_values}, "pg_arrays" ) + @connection.insert_fixture({ "tags" => tag_values }, "pg_arrays" ) assert_equal(PgArray.last.tags, tag_values) end def test_attribute_for_inspect_for_array_field + record = PgArray.new { |a| a.ratings = (1..10).to_a } + assert_equal("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", record.attribute_for_inspect(:ratings)) + end + + def test_attribute_for_inspect_for_array_field_for_large_array record = PgArray.new { |a| a.ratings = (1..11).to_a } - assert_equal("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]", record.attribute_for_inspect(:ratings)) + assert_equal("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]", record.attribute_for_inspect(:ratings)) end def test_escaping @@ -206,14 +211,14 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase x = PgArray.create!(tags: tags) x.reload - assert_equal x.tags_before_type_cast, PgArray.type_for_attribute('tags').serialize(tags) + assert_equal x.tags_before_type_cast, PgArray.type_for_attribute("tags").serialize(tags) end def test_quoting_non_standard_delimiters strings = ["hello,", "world;"] oid = ActiveRecord::ConnectionAdapters::PostgreSQL::OID - comma_delim = oid::Array.new(ActiveRecord::Type::String.new, ',') - semicolon_delim = oid::Array.new(ActiveRecord::Type::String.new, ';') + comma_delim = oid::Array.new(ActiveRecord::Type::String.new, ",") + semicolon_delim = oid::Array.new(ActiveRecord::Type::String.new, ";") assert_equal %({"hello,",world;}), comma_delim.serialize(strings) assert_equal %({hello,;"world;"}), semicolon_delim.serialize(strings) @@ -231,13 +236,13 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase end def test_mutate_value_in_array - x = PgArray.create!(hstores: [{ a: 'a' }, { b: 'b' }]) + x = PgArray.create!(hstores: [{ a: "a" }, { b: "b" }]) - x.hstores.first['a'] = 'c' + x.hstores.first["a"] = "c" x.save! x.reload - assert_equal [{ 'a' => 'c' }, { 'b' => 'b' }], x.hstores + assert_equal [{ "a" => "c" }, { "b" => "b" }], x.hstores assert_not x.changed? end @@ -285,6 +290,12 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase assert_equal record.tags, record.reload.tags end + def test_where_by_attribute_with_array + tags = ["black", "blue"] + record = PgArray.create!(tags: tags) + assert_equal record, PgArray.where(tags: tags).take + end + def test_uniqueness_validation klass = Class.new(PgArray) do validates_uniqueness_of :tags @@ -300,18 +311,24 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase assert_equal ["has already been taken"], e2.errors[:tags], "Should have uniqueness message for tags" end - private - def assert_cycle field, array - # test creation - x = PgArray.create!(field => array) - x.reload - assert_equal(array, x.public_send(field)) - - # test updating - x = PgArray.create!(field => []) - x.public_send("#{field}=", array) - x.save! - x.reload - assert_equal(array, x.public_send(field)) + def test_encoding_arrays_of_utf8_strings + string_with_utf8 = "nový" + assert_equal [string_with_utf8], @type.deserialize(@type.serialize([string_with_utf8])) + assert_equal [[string_with_utf8]], @type.deserialize(@type.serialize([[string_with_utf8]])) end + + private + def assert_cycle(field, array) + # test creation + x = PgArray.create!(field => array) + x.reload + assert_equal(array, x.public_send(field)) + + # test updating + x = PgArray.create!(field => []) + x.public_send("#{field}=", array) + x.save! + x.reload + assert_equal(array, x.public_send(field)) + end end diff --git a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb index cec6081aec..7712e809a2 100644 --- a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'support/connection_helper' -require 'support/schema_dumping_helper' +require "support/connection_helper" +require "support/schema_dumping_helper" class PostgresqlBitStringTest < ActiveRecord::PostgreSQLTestCase include ConnectionHelper @@ -10,7 +10,7 @@ class PostgresqlBitStringTest < ActiveRecord::PostgreSQLTestCase def setup @connection = ActiveRecord::Base.connection - @connection.create_table('postgresql_bit_strings', :force => true) do |t| + @connection.create_table("postgresql_bit_strings", force: true) do |t| t.bit :a_bit, default: "00000011", limit: 8 t.bit_varying :a_bit_varying, default: "0011", limit: 4 t.bit :another_bit @@ -20,7 +20,7 @@ class PostgresqlBitStringTest < ActiveRecord::PostgreSQLTestCase def teardown return unless @connection - @connection.drop_table 'postgresql_bit_strings', if_exists: true + @connection.drop_table "postgresql_bit_strings", if_exists: true end def test_bit_string_column @@ -44,10 +44,10 @@ class PostgresqlBitStringTest < ActiveRecord::PostgreSQLTestCase end def test_default - assert_equal "00000011", PostgresqlBitString.column_defaults['a_bit'] + assert_equal "00000011", PostgresqlBitString.column_defaults["a_bit"] assert_equal "00000011", PostgresqlBitString.new.a_bit - assert_equal "0011", PostgresqlBitString.column_defaults['a_bit_varying'] + assert_equal "0011", PostgresqlBitString.column_defaults["a_bit_varying"] assert_equal "0011", PostgresqlBitString.new.a_bit_varying end @@ -65,10 +65,11 @@ class PostgresqlBitStringTest < ActiveRecord::PostgreSQLTestCase end def test_roundtrip - PostgresqlBitString.create! a_bit: "00001010", a_bit_varying: "0101" - record = PostgresqlBitString.first + record = PostgresqlBitString.create!(a_bit: "00001010", a_bit_varying: "0101") assert_equal "00001010", record.a_bit assert_equal "0101", record.a_bit_varying + assert_nil record.another_bit + assert_nil record.another_bit_varying record.a_bit = "11111111" record.a_bit_varying = "0xF" diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb index 7adc070430..dc0df8715a 100644 --- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -1,29 +1,29 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper class ByteaDataType < ActiveRecord::Base - self.table_name = 'bytea_data_type' + self.table_name = "bytea_data_type" end def setup @connection = ActiveRecord::Base.connection begin @connection.transaction do - @connection.create_table('bytea_data_type') do |t| - t.binary 'payload' - t.binary 'serialized' + @connection.create_table("bytea_data_type") do |t| + t.binary "payload" + t.binary "serialized" end end end - @column = ByteaDataType.columns_hash['payload'] + @column = ByteaDataType.columns_hash["payload"] @type = ByteaDataType.type_for_attribute("payload") end teardown do - @connection.drop_table 'bytea_data_type', if_exists: true + @connection.drop_table "bytea_data_type", if_exists: true end def test_column @@ -32,7 +32,7 @@ class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase end def test_binary_columns_are_limitless_the_upper_limit_is_one_GB - assert_equal 'bytea', @connection.type_to_sql(:binary, 100_000) + assert_equal "bytea", @connection.type_to_sql(:binary, 100_000) assert_raise ActiveRecord::ActiveRecordError do @connection.type_to_sql :binary, 4294967295 end @@ -42,8 +42,8 @@ class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase assert @column data = "\u001F\x8B" - assert_equal('UTF-8', data.encoding.name) - assert_equal('ASCII-8BIT', @type.deserialize(data).encoding.name) + assert_equal("UTF-8", data.encoding.name) + assert_equal("ASCII-8BIT", @type.deserialize(data).encoding.name) end def test_type_cast_binary_value @@ -88,14 +88,14 @@ class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase def test_via_to_sql_with_complicating_connection Thread.new do other_conn = ActiveRecord::Base.connection - other_conn.execute('SET standard_conforming_strings = off') + other_conn.execute("SET standard_conforming_strings = off") end.join test_via_to_sql end def test_write_binary - data = File.read(File.join(File.dirname(__FILE__), '..', '..', '..', 'assets', 'example.log')) + data = File.read(File.join(File.dirname(__FILE__), "..", "..", "..", "assets", "example.log")) assert(data.size > 1) record = ByteaDataType.create(payload: data) assert_not record.new_record? diff --git a/activerecord/test/cases/adapters/postgresql/case_insensitive_test.rb b/activerecord/test/cases/adapters/postgresql/case_insensitive_test.rb new file mode 100644 index 0000000000..03b44feab6 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/case_insensitive_test.rb @@ -0,0 +1,26 @@ +require "cases/helper" + +class PostgresqlCaseInsensitiveTest < ActiveRecord::PostgreSQLTestCase + class Default < ActiveRecord::Base; end + + def test_case_insensitiveness + connection = ActiveRecord::Base.connection + table = Default.arel_table + + column = Default.columns_hash["char1"] + comparison = connection.case_insensitive_comparison table, :char1, column, nil + assert_match(/lower/i, comparison.to_sql) + + column = Default.columns_hash["char2"] + comparison = connection.case_insensitive_comparison table, :char2, column, nil + assert_match(/lower/i, comparison.to_sql) + + column = Default.columns_hash["char3"] + comparison = connection.case_insensitive_comparison table, :char3, column, nil + assert_match(/lower/i, comparison.to_sql) + + column = Default.columns_hash["multiline_default"] + comparison = connection.case_insensitive_comparison table, :multiline_default, column, nil + assert_match(/lower/i, comparison.to_sql) + end +end diff --git a/activerecord/test/cases/adapters/postgresql/change_schema_test.rb b/activerecord/test/cases/adapters/postgresql/change_schema_test.rb index bc12df668d..ea642069d2 100644 --- a/activerecord/test/cases/adapters/postgresql/change_schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/change_schema_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration @@ -19,17 +19,17 @@ module ActiveRecord def test_change_string_to_date connection.change_column :strings, :somedate, :timestamp, using: 'CAST("somedate" AS timestamp)' - assert_equal :datetime, connection.columns(:strings).find { |c| c.name == 'somedate' }.type + assert_equal :datetime, connection.columns(:strings).find { |c| c.name == "somedate" }.type end def test_change_type_with_symbol connection.change_column :strings, :somedate, :timestamp, cast_as: :timestamp - assert_equal :datetime, connection.columns(:strings).find { |c| c.name == 'somedate' }.type + assert_equal :datetime, connection.columns(:strings).find { |c| c.name == "somedate" }.type end def test_change_type_with_array connection.change_column :strings, :somedate, :timestamp, array: true, cast_as: :timestamp - column = connection.columns(:strings).find { |c| c.name == 'somedate' } + column = connection.columns(:strings).find { |c| c.name == "somedate" } assert_equal :datetime, column.type assert column.array? end diff --git a/activerecord/test/cases/adapters/postgresql/citext_test.rb b/activerecord/test/cases/adapters/postgresql/citext_test.rb index bd62041e79..ca95e4b626 100644 --- a/activerecord/test/cases/adapters/postgresql/citext_test.rb +++ b/activerecord/test/cases/adapters/postgresql/citext_test.rb @@ -1,49 +1,49 @@ -require 'cases/helper' -require 'support/schema_dumping_helper' +require "cases/helper" +require "support/schema_dumping_helper" if ActiveRecord::Base.connection.supports_extensions? class PostgresqlCitextTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper class Citext < ActiveRecord::Base - self.table_name = 'citexts' + self.table_name = "citexts" end def setup @connection = ActiveRecord::Base.connection - enable_extension!('citext', @connection) + enable_extension!("citext", @connection) - @connection.create_table('citexts') do |t| - t.citext 'cival' + @connection.create_table("citexts") do |t| + t.citext "cival" end end teardown do - @connection.drop_table 'citexts', if_exists: true - disable_extension!('citext', @connection) + @connection.drop_table "citexts", if_exists: true + disable_extension!("citext", @connection) end def test_citext_enabled - assert @connection.extension_enabled?('citext') + assert @connection.extension_enabled?("citext") end def test_column - column = Citext.columns_hash['cival'] + column = Citext.columns_hash["cival"] assert_equal :citext, column.type - assert_equal 'citext', column.sql_type + assert_equal "citext", column.sql_type assert_not column.array? - type = Citext.type_for_attribute('cival') + type = Citext.type_for_attribute("cival") assert_not type.binary? end def test_change_table_supports_json @connection.transaction do - @connection.change_table('citexts') do |t| - t.citext 'username' + @connection.change_table("citexts") do |t| + t.citext "username" end Citext.reset_column_information - column = Citext.columns_hash['username'] + column = Citext.columns_hash["username"] assert_equal :citext, column.type raise ActiveRecord::Rollback # reset the schema change @@ -53,7 +53,7 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_write - x = Citext.new(cival: 'Some CI Text') + x = Citext.new(cival: "Some CI Text") x.save! citext = Citext.first assert_equal "Some CI Text", citext.cival @@ -66,8 +66,8 @@ if ActiveRecord::Base.connection.supports_extensions? def test_select_case_insensitive @connection.execute "insert into citexts (cival) values('Cased Text')" - x = Citext.where(cival: 'cased text').first - assert_equal 'Cased Text', x.cival + x = Citext.where(cival: "cased text").first + assert_equal "Cased Text", x.cival end def test_schema_dump_with_shorthand diff --git a/activerecord/test/cases/adapters/postgresql/collation_test.rb b/activerecord/test/cases/adapters/postgresql/collation_test.rb index 8470329c35..b39e298a5d 100644 --- a/activerecord/test/cases/adapters/postgresql/collation_test.rb +++ b/activerecord/test/cases/adapters/postgresql/collation_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlCollationTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper @@ -7,8 +7,8 @@ class PostgresqlCollationTest < ActiveRecord::PostgreSQLTestCase def setup @connection = ActiveRecord::Base.connection @connection.create_table :postgresql_collations, force: true do |t| - t.string :string_c, collation: 'C' - t.text :text_posix, collation: 'POSIX' + t.string :string_c, collation: "C" + t.text :text_posix, collation: "POSIX" end end @@ -17,32 +17,32 @@ class PostgresqlCollationTest < ActiveRecord::PostgreSQLTestCase end test "string column with collation" do - column = @connection.columns(:postgresql_collations).find { |c| c.name == 'string_c' } + column = @connection.columns(:postgresql_collations).find { |c| c.name == "string_c" } assert_equal :string, column.type - assert_equal 'C', column.collation + assert_equal "C", column.collation end test "text column with collation" do - column = @connection.columns(:postgresql_collations).find { |c| c.name == 'text_posix' } + column = @connection.columns(:postgresql_collations).find { |c| c.name == "text_posix" } assert_equal :text, column.type - assert_equal 'POSIX', column.collation + assert_equal "POSIX", column.collation end test "add column with collation" do - @connection.add_column :postgresql_collations, :title, :string, collation: 'C' + @connection.add_column :postgresql_collations, :title, :string, collation: "C" - column = @connection.columns(:postgresql_collations).find { |c| c.name == 'title' } + column = @connection.columns(:postgresql_collations).find { |c| c.name == "title" } assert_equal :string, column.type - assert_equal 'C', column.collation + assert_equal "C", column.collation end test "change column with collation" do @connection.add_column :postgresql_collations, :description, :string - @connection.change_column :postgresql_collations, :description, :text, collation: 'POSIX' + @connection.change_column :postgresql_collations, :description, :text, collation: "POSIX" - column = @connection.columns(:postgresql_collations).find { |c| c.name == 'description' } + column = @connection.columns(:postgresql_collations).find { |c| c.name == "description" } assert_equal :text, column.type - assert_equal 'POSIX', column.collation + assert_equal "POSIX", column.collation end test "schema dump includes collation" do diff --git a/activerecord/test/cases/adapters/postgresql/composite_test.rb b/activerecord/test/cases/adapters/postgresql/composite_test.rb index 1de87e5f01..1da2a9e2ac 100644 --- a/activerecord/test/cases/adapters/postgresql/composite_test.rb +++ b/activerecord/test/cases/adapters/postgresql/composite_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" module PostgresqlCompositeBehavior include ConnectionHelper @@ -20,7 +20,7 @@ module PostgresqlCompositeBehavior street VARCHAR(90) ); SQL - @connection.create_table('postgresql_composites') do |t| + @connection.create_table("postgresql_composites") do |t| t.column :address, :full_address end end @@ -29,8 +29,8 @@ module PostgresqlCompositeBehavior def teardown super - @connection.drop_table 'postgresql_composites', if_exists: true - @connection.execute 'DROP TYPE IF EXISTS full_address' + @connection.drop_table "postgresql_composites", if_exists: true + @connection.execute "DROP TYPE IF EXISTS full_address" reset_connection PostgresqlComposite.reset_column_information end @@ -69,12 +69,12 @@ class PostgresqlCompositeTest < ActiveRecord::PostgreSQLTestCase end private - def ensure_warning_is_issued - warning = capture(:stderr) do - PostgresqlComposite.columns_hash + def ensure_warning_is_issued + warning = capture(:stderr) do + PostgresqlComposite.columns_hash + end + assert_match(/unknown OID \d+: failed to recognize type of 'address'\. It will be treated as String\./, warning) end - assert_match(/unknown OID \d+: failed to recognize type of 'address'\. It will be treated as String\./, warning) - end end class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::PostgreSQLTestCase @@ -126,7 +126,7 @@ class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::PostgreSQLTestCase composite.address = FullAddress.new("Paris", "Rue Basse") composite.save! - assert_equal 'Paris', composite.reload.address.city - assert_equal 'Rue Basse', composite.reload.address.street + assert_equal "Paris", composite.reload.address.city + assert_equal "Rue Basse", composite.reload.address.street end end diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index f8403bfe1a..48c82cb7b9 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" module ActiveRecord class PostgresqlConnectionTest < ActiveRecord::PostgreSQLTestCase @@ -13,7 +13,7 @@ module ActiveRecord def setup super @subscriber = SQLSubscriber.new - @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + @subscription = ActiveSupport::Notifications.subscribe("sql.active_record", @subscriber) @connection = ActiveRecord::Base.connection end @@ -23,10 +23,10 @@ module ActiveRecord end def test_truncate - count = ActiveRecord::Base.connection.execute("select count(*) from comments").first['count'].to_i + count = ActiveRecord::Base.connection.execute("select count(*) from comments").first["count"].to_i assert_operator count, :>, 0 ActiveRecord::Base.connection.truncate("comments") - count = ActiveRecord::Base.connection.execute("select count(*) from comments").first['count'].to_i + count = ActiveRecord::Base.connection.execute("select count(*) from comments").first["count"].to_i assert_equal 0, count end @@ -54,85 +54,85 @@ module ActiveRecord NonExistentTable.establish_connection(params) # Verify the connection param has been applied. - expect = NonExistentTable.connection.query('show geqo').first.first - assert_equal 'off', expect + expect = NonExistentTable.connection.query("show geqo").first.first + assert_equal "off", expect end def test_reset - @connection.query('ROLLBACK') - @connection.query('SET geqo TO off') + @connection.query("ROLLBACK") + @connection.query("SET geqo TO off") # Verify the setting has been applied. - expect = @connection.query('show geqo').first.first - assert_equal 'off', expect + expect = @connection.query("show geqo").first.first + assert_equal "off", expect @connection.reset! # Verify the setting has been cleared. - expect = @connection.query('show geqo').first.first - assert_equal 'on', expect + expect = @connection.query("show geqo").first.first + assert_equal "on", expect end def test_reset_with_transaction - @connection.query('ROLLBACK') - @connection.query('SET geqo TO off') + @connection.query("ROLLBACK") + @connection.query("SET geqo TO off") # Verify the setting has been applied. - expect = @connection.query('show geqo').first.first - assert_equal 'off', expect + expect = @connection.query("show geqo").first.first + assert_equal "off", expect - @connection.query('BEGIN') + @connection.query("BEGIN") @connection.reset! # Verify the setting has been cleared. - expect = @connection.query('show geqo').first.first - assert_equal 'on', expect + expect = @connection.query("show geqo").first.first + assert_equal "on", expect end def test_tables_logs_name - ActiveSupport::Deprecation.silence { @connection.tables('hello') } - assert_equal 'SCHEMA', @subscriber.logged[0][1] + ActiveSupport::Deprecation.silence { @connection.tables("hello") } + assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_indexes_logs_name - @connection.indexes('items', 'hello') - assert_equal 'SCHEMA', @subscriber.logged[0][1] + @connection.indexes("items", "hello") + assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_table_exists_logs_name - ActiveSupport::Deprecation.silence { @connection.table_exists?('items') } - assert_equal 'SCHEMA', @subscriber.logged[0][1] + ActiveSupport::Deprecation.silence { @connection.table_exists?("items") } + assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_table_alias_length_logs_name @connection.instance_variable_set("@table_alias_length", nil) @connection.table_alias_length - assert_equal 'SCHEMA', @subscriber.logged[0][1] + assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_current_database_logs_name @connection.current_database - assert_equal 'SCHEMA', @subscriber.logged[0][1] + assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_encoding_logs_name @connection.encoding - assert_equal 'SCHEMA', @subscriber.logged[0][1] + assert_equal "SCHEMA", @subscriber.logged[0][1] end def test_schema_names_logs_name @connection.schema_names - assert_equal 'SCHEMA', @subscriber.logged[0][1] + assert_equal "SCHEMA", @subscriber.logged[0][1] end if ActiveRecord::Base.connection.prepared_statements def test_statement_key_is_logged bind = Relation::QueryAttribute.new(nil, 1, Type::Value.new) - @connection.exec_query('SELECT $1::integer', 'SQL', [bind], prepare: true) + @connection.exec_query("SELECT $1::integer", "SQL", [bind], prepare: true) name = @subscriber.payloads.last[:statement_name] assert name res = @connection.exec_query("EXPLAIN (FORMAT JSON) EXECUTE #{name}(1)") - plan = res.column_types['QUERY PLAN'].deserialize res.rows.first.first + plan = res.column_types["QUERY PLAN"].deserialize res.rows.first.first assert_operator plan.length, :>, 0 end end @@ -146,7 +146,7 @@ module ActiveRecord # To restart PostgreSQL 9.1 on OS X, installed via MacPorts, ... # sudo su postgres -c "pg_ctl restart -D /opt/local/var/db/postgresql91/defaultdb/ -m fast" def test_reconnection_after_actual_disconnection_with_verify - original_connection_pid = @connection.query('select pg_backend_pid()') + original_connection_pid = @connection.query("select pg_backend_pid()") # Sanity check. assert @connection.active? @@ -155,8 +155,8 @@ module ActiveRecord secondary_connection = ActiveRecord::Base.connection_pool.checkout secondary_connection.query("select pg_terminate_backend(#{original_connection_pid.first.first})") ActiveRecord::Base.connection_pool.checkin(secondary_connection) - elsif ARTest.config['with_manual_interventions'] - puts 'Kill the connection now (e.g. by restarting the PostgreSQL ' + + elsif ARTest.config["with_manual_interventions"] + puts "Kill the connection now (e.g. by restarting the PostgreSQL " + 'server with the "-m fast" option) and then press enter.' $stdin.gets else @@ -172,7 +172,7 @@ module ActiveRecord # If we get no exception here, then either we re-connected successfully, or # we never actually got disconnected. - new_connection_pid = @connection.query('select pg_backend_pid()') + new_connection_pid = @connection.query("select pg_backend_pid()") assert_not_equal original_connection_pid, new_connection_pid, "umm -- looks like you didn't break the connection, because we're still " + @@ -184,7 +184,7 @@ module ActiveRecord def test_set_session_variable_true run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:debug_print_plan => true}})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: true })) set_true = ActiveRecord::Base.connection.exec_query "SHOW DEBUG_PRINT_PLAN" assert_equal set_true.rows, [["on"]] end @@ -192,7 +192,7 @@ module ActiveRecord def test_set_session_variable_false run_without_connection do |orig_connection| - ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:debug_print_plan => false}})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: false })) set_false = ActiveRecord::Base.connection.exec_query "SHOW DEBUG_PRINT_PLAN" assert_equal set_false.rows, [["off"]] end @@ -201,14 +201,14 @@ module ActiveRecord def test_set_session_variable_nil run_without_connection do |orig_connection| # This should be a no-op that does not raise an error - ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:debug_print_plan => nil}})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: nil })) end end def test_set_session_variable_default run_without_connection do |orig_connection| # This should execute a query that does not raise an error - ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:debug_print_plan => :default}})) + ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { debug_print_plan: :default })) end end @@ -224,14 +224,14 @@ module ActiveRecord got_lock = @connection.get_advisory_lock(lock_id) assert got_lock, "get_advisory_lock should have returned true but it didn't" - advisory_lock = @connection.query(list_advisory_locks).find {|l| l[1] == lock_id} + advisory_lock = @connection.query(list_advisory_locks).find { |l| l[1] == lock_id } assert advisory_lock, "expected to find an advisory lock with lock_id #{lock_id} but there wasn't one" released_lock = @connection.release_advisory_lock(lock_id) assert released_lock, "expected release_advisory_lock to return true but it didn't" - advisory_locks = @connection.query(list_advisory_locks).select {|l| l[1] == lock_id} + advisory_locks = @connection.query(list_advisory_locks).select { |l| l[1] == lock_id } assert_empty advisory_locks, "expected to have released advisory lock with lock_id #{lock_id} but it was still held" end @@ -241,17 +241,17 @@ module ActiveRecord with_warning_suppression do released_non_existent_lock = @connection.release_advisory_lock(fake_lock_id) assert_equal released_non_existent_lock, false, - 'expected release_advisory_lock to return false when there was no lock to release' + "expected release_advisory_lock to return false when there was no lock to release" end end protected - def with_warning_suppression - log_level = @connection.client_min_messages - @connection.client_min_messages = 'error' - yield - @connection.client_min_messages = log_level - end + def with_warning_suppression + log_level = @connection.client_min_messages + @connection.client_min_messages = "error" + yield + @connection.client_min_messages = log_level + end end end diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb index 232c25cb3b..0ac8b7339b 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -1,6 +1,5 @@ require "cases/helper" -require 'support/ddl_helper' - +require "support/ddl_helper" class PostgresqlTime < ActiveRecord::Base end @@ -38,8 +37,8 @@ class PostgresqlDataTypeTest < ActiveRecord::PostgreSQLTestCase end def test_time_values - assert_equal '-1 years -2 days', @first_time.time_interval - assert_equal '-21 days', @first_time.scaled_time_interval + assert_equal "-1 years -2 days", @first_time.time_interval + assert_equal "-21 days", @first_time.scaled_time_interval end def test_oid_values @@ -47,10 +46,10 @@ class PostgresqlDataTypeTest < ActiveRecord::PostgreSQLTestCase end def test_update_time - @first_time.time_interval = '2 years 3 minutes' + @first_time.time_interval = "2 years 3 minutes" assert @first_time.save assert @first_time.reload - assert_equal '2 years 00:03:00', @first_time.time_interval + assert_equal "2 years 00:03:00", @first_time.time_interval end def test_update_oid @@ -62,7 +61,7 @@ class PostgresqlDataTypeTest < ActiveRecord::PostgreSQLTestCase end def test_text_columns_are_limitless_the_upper_limit_is_one_GB - assert_equal 'text', @connection.type_to_sql(:text, 100_000) + assert_equal "text", @connection.type_to_sql(:text, 100_000) assert_raise ActiveRecord::ActiveRecordError do @connection.type_to_sql :text, 4294967295 end @@ -77,15 +76,15 @@ class PostgresqlInternalDataTypeTest < ActiveRecord::PostgreSQLTestCase end def test_name_column_type - with_example_table @connection, 'ex', 'data name' do - column = @connection.columns('ex').find { |col| col.name == 'data' } + with_example_table @connection, "ex", "data name" do + column = @connection.columns("ex").find { |col| col.name == "data" } assert_equal :string, column.type end end def test_char_column_type - with_example_table @connection, 'ex', 'data "char"' do - column = @connection.columns('ex').find { |col| col.name == 'data' } + with_example_table @connection, "ex", 'data "char"' do + column = @connection.columns("ex").find { |col| col.name == "data" } assert_equal :string, column.type end end diff --git a/activerecord/test/cases/adapters/postgresql/domain_test.rb b/activerecord/test/cases/adapters/postgresql/domain_test.rb index 6102ddacd1..f1eb8adb15 100644 --- a/activerecord/test/cases/adapters/postgresql/domain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/domain_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" class PostgresqlDomainTest < ActiveRecord::PostgreSQLTestCase include ConnectionHelper @@ -12,15 +12,15 @@ class PostgresqlDomainTest < ActiveRecord::PostgreSQLTestCase @connection = ActiveRecord::Base.connection @connection.transaction do @connection.execute "CREATE DOMAIN custom_money as numeric(8,2)" - @connection.create_table('postgresql_domains') do |t| + @connection.create_table("postgresql_domains") do |t| t.column :price, :custom_money end end end teardown do - @connection.drop_table 'postgresql_domains', if_exists: true - @connection.execute 'DROP DOMAIN IF EXISTS custom_money' + @connection.drop_table "postgresql_domains", if_exists: true + @connection.execute "DROP DOMAIN IF EXISTS custom_money" reset_connection end diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb index 6816a6514b..5e5a3158ba 100644 --- a/activerecord/test/cases/adapters/postgresql/enum_test.rb +++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" class PostgresqlEnumTest < ActiveRecord::PostgreSQLTestCase include ConnectionHelper @@ -14,15 +14,15 @@ class PostgresqlEnumTest < ActiveRecord::PostgreSQLTestCase @connection.execute <<-SQL CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy'); SQL - @connection.create_table('postgresql_enums') do |t| + @connection.create_table("postgresql_enums") do |t| t.column :current_mood, :mood end end end teardown do - @connection.drop_table 'postgresql_enums', if_exists: true - @connection.execute 'DROP TYPE IF EXISTS mood' + @connection.drop_table "postgresql_enums", if_exists: true + @connection.execute "DROP TYPE IF EXISTS mood" reset_connection end @@ -37,10 +37,10 @@ class PostgresqlEnumTest < ActiveRecord::PostgreSQLTestCase end def test_enum_defaults - @connection.add_column 'postgresql_enums', 'good_mood', :mood, default: 'happy' + @connection.add_column "postgresql_enums", "good_mood", :mood, default: "happy" PostgresqlEnum.reset_column_information - assert_equal "happy", PostgresqlEnum.column_defaults['good_mood'] + assert_equal "happy", PostgresqlEnum.column_defaults["good_mood"] assert_equal "happy", PostgresqlEnum.new.good_mood ensure PostgresqlEnum.reset_column_information diff --git a/activerecord/test/cases/adapters/postgresql/explain_test.rb b/activerecord/test/cases/adapters/postgresql/explain_test.rb index 29bf2c15ea..7493bce4fb 100644 --- a/activerecord/test/cases/adapters/postgresql/explain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/explain_test.rb @@ -1,20 +1,20 @@ require "cases/helper" -require 'models/developer' -require 'models/computer' +require "models/developer" +require "models/computer" class PostgreSQLExplainTest < ActiveRecord::PostgreSQLTestCase fixtures :developers def test_explain_for_one_query explain = Developer.where(id: 1).explain - assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = \$?1), explain + assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\$1 \[\["id", 1\]\]|1)), explain assert_match %(QUERY PLAN), explain end def test_explain_with_eager_loading explain = Developer.where(id: 1).includes(:audit_logs).explain assert_match %(QUERY PLAN), explain - assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = \$?1), explain + assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\$1 \[\["id", 1\]\]|1)), explain assert_match %(EXPLAIN for: SELECT "audit_logs".* FROM "audit_logs" WHERE "audit_logs"."developer_id" = 1), explain end end diff --git a/activerecord/test/cases/adapters/postgresql/full_text_test.rb b/activerecord/test/cases/adapters/postgresql/full_text_test.rb index bde7513339..5ddfe32007 100644 --- a/activerecord/test/cases/adapters/postgresql/full_text_test.rb +++ b/activerecord/test/cases/adapters/postgresql/full_text_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlFullTextTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper @@ -7,13 +7,13 @@ class PostgresqlFullTextTest < ActiveRecord::PostgreSQLTestCase setup do @connection = ActiveRecord::Base.connection - @connection.create_table('tsvectors') do |t| - t.tsvector 'text_vector' + @connection.create_table("tsvectors") do |t| + t.tsvector "text_vector" end end teardown do - @connection.drop_table 'tsvectors', if_exists: true + @connection.drop_table "tsvectors", if_exists: true end def test_tsvector_column diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb index 66f0a70394..a65d4d1ad9 100644 --- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb +++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'support/connection_helper' -require 'support/schema_dumping_helper' +require "support/connection_helper" +require "support/schema_dumping_helper" class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase include ConnectionHelper @@ -18,7 +18,7 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase def setup @connection = ActiveRecord::Base.connection - @connection.create_table('postgresql_points') do |t| + @connection.create_table("postgresql_points") do |t| t.point :x t.point :y, default: [12.2, 13.3] t.point :z, default: "(14.4,15.5)" @@ -27,22 +27,10 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase t.point :legacy_y, default: [12.2, 13.3] t.point :legacy_z, default: "(14.4,15.5)" end - @connection.create_table('deprecated_points') do |t| - t.point :x - end end teardown do - @connection.drop_table 'postgresql_points', if_exists: true - @connection.drop_table 'deprecated_points', if_exists: true - end - - class DeprecatedPoint < ActiveRecord::Base; end - - def test_deprecated_legacy_type - assert_deprecated do - DeprecatedPoint.new - end + @connection.drop_table "postgresql_points", if_exists: true end def test_column @@ -56,10 +44,10 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase end def test_default - assert_equal ActiveRecord::Point.new(12.2, 13.3), PostgresqlPoint.column_defaults['y'] + assert_equal ActiveRecord::Point.new(12.2, 13.3), PostgresqlPoint.column_defaults["y"] assert_equal ActiveRecord::Point.new(12.2, 13.3), PostgresqlPoint.new.y - assert_equal ActiveRecord::Point.new(14.4, 15.5), PostgresqlPoint.column_defaults['z'] + assert_equal ActiveRecord::Point.new(14.4, 15.5), PostgresqlPoint.column_defaults["z"] assert_equal ActiveRecord::Point.new(14.4, 15.5), PostgresqlPoint.new.z end @@ -136,10 +124,10 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase end def test_legacy_default - assert_equal [12.2, 13.3], PostgresqlPoint.column_defaults['legacy_y'] + assert_equal [12.2, 13.3], PostgresqlPoint.column_defaults["legacy_y"] assert_equal [12.2, 13.3], PostgresqlPoint.new.legacy_y - assert_equal [14.4, 15.5], PostgresqlPoint.column_defaults['legacy_z'] + assert_equal [14.4, 15.5], PostgresqlPoint.column_defaults["legacy_z"] assert_equal [14.4, 15.5], PostgresqlPoint.new.legacy_z end @@ -190,51 +178,51 @@ class PostgresqlGeometricTest < ActiveRecord::PostgreSQLTestCase end teardown do - @connection.drop_table 'postgresql_geometrics', if_exists: true + @connection.drop_table "postgresql_geometrics", if_exists: true end def test_geometric_types g = PostgresqlGeometric.new( - :a_line_segment => '(2.0, 3), (5.5, 7.0)', - :a_box => '2.0, 3, 5.5, 7.0', - :a_path => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]', - :a_polygon => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', - :a_circle => '<(5.3, 10.4), 2>' + a_line_segment: "(2.0, 3), (5.5, 7.0)", + a_box: "2.0, 3, 5.5, 7.0", + a_path: "[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]", + a_polygon: "((2.0, 3), (5.5, 7.0), (8.5, 11.0))", + a_circle: "<(5.3, 10.4), 2>" ) g.save! h = PostgresqlGeometric.find(g.id) - assert_equal '[(2,3),(5.5,7)]', h.a_line_segment - assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner - assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path - assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon - assert_equal '<(5.3,10.4),2>', h.a_circle + assert_equal "[(2,3),(5.5,7)]", h.a_line_segment + assert_equal "(5.5,7),(2,3)", h.a_box # reordered to store upper right corner then bottom left corner + assert_equal "[(2,3),(5.5,7),(8.5,11)]", h.a_path + assert_equal "((2,3),(5.5,7),(8.5,11))", h.a_polygon + assert_equal "<(5.3,10.4),2>", h.a_circle end def test_alternative_format g = PostgresqlGeometric.new( - :a_line_segment => '((2.0, 3), (5.5, 7.0))', - :a_box => '(2.0, 3), (5.5, 7.0)', - :a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', - :a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0', - :a_circle => '((5.3, 10.4), 2)' + a_line_segment: "((2.0, 3), (5.5, 7.0))", + a_box: "(2.0, 3), (5.5, 7.0)", + a_path: "((2.0, 3), (5.5, 7.0), (8.5, 11.0))", + a_polygon: "2.0, 3, 5.5, 7.0, 8.5, 11.0", + a_circle: "((5.3, 10.4), 2)" ) g.save! h = PostgresqlGeometric.find(g.id) - assert_equal '[(2,3),(5.5,7)]', h.a_line_segment - assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner - assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path - assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon - assert_equal '<(5.3,10.4),2>', h.a_circle + assert_equal "[(2,3),(5.5,7)]", h.a_line_segment + assert_equal "(5.5,7),(2,3)", h.a_box # reordered to store upper right corner then bottom left corner + assert_equal "((2,3),(5.5,7),(8.5,11))", h.a_path + assert_equal "((2,3),(5.5,7),(8.5,11))", h.a_polygon + assert_equal "<(5.3,10.4),2>", h.a_circle end def test_geometric_function - PostgresqlGeometric.create! a_path: '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]' # [ ] is an open path - PostgresqlGeometric.create! a_path: '((2.0, 3), (5.5, 7.0), (8.5, 11.0))' # ( ) is a closed path + PostgresqlGeometric.create! a_path: "[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]" # [ ] is an open path + PostgresqlGeometric.create! a_path: "((2.0, 3), (5.5, 7.0), (8.5, 11.0))" # ( ) is a closed path objs = PostgresqlGeometric.find_by_sql "SELECT isopen(a_path) FROM postgresql_geometrics ORDER BY id ASC" assert_equal [true, false], objs.map(&:isopen) @@ -270,28 +258,28 @@ class PostgreSQLGeometricLineTest < ActiveRecord::PostgreSQLTestCase teardown do if defined?(@connection) - @connection.drop_table 'postgresql_lines', if_exists: true + @connection.drop_table "postgresql_lines", if_exists: true end end def test_geometric_line_type g = PostgresqlLine.new( - a_line: '{2.0, 3, 5.5}' + a_line: "{2.0, 3, 5.5}" ) g.save! h = PostgresqlLine.find(g.id) - assert_equal '{2,3,5.5}', h.a_line + assert_equal "{2,3,5.5}", h.a_line end def test_alternative_format_line_type g = PostgresqlLine.new( - a_line: '(2.0, 3), (4.0, 6.0)' + a_line: "(2.0, 3), (4.0, 6.0)" ) g.save! h = PostgresqlLine.find(g.id) - assert_equal '{1.5,-1,0}', h.a_line + assert_equal "{1.5,-1,0}", h.a_line end def test_schema_dumping_for_line_type @@ -374,12 +362,12 @@ class PostgreSQLGeometricTypesTest < ActiveRecord::PostgreSQLTestCase private - def assert_column_exists(column_name) - assert connection.column_exists?(table_name, column_name) - end + def assert_column_exists(column_name) + assert connection.column_exists?(table_name, column_name) + end - def assert_type_correct(column_name, type) - column = connection.columns(table_name).find { |c| c.name == column_name.to_s } - assert_equal type, column.type - end + def assert_type_correct(column_name, type) + column = connection.columns(table_name).find { |c| c.name == column_name.to_s } + assert_equal type, column.type + end end diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 27cc65a643..9236a67b11 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -1,11 +1,11 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" if ActiveRecord::Base.connection.supports_extensions? class PostgresqlHstoreTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper class Hstore < ActiveRecord::Base - self.table_name = 'hstores' + self.table_name = "hstores" store_accessor :settings, :language, :timezone end @@ -13,40 +13,40 @@ if ActiveRecord::Base.connection.supports_extensions? def setup @connection = ActiveRecord::Base.connection - unless @connection.extension_enabled?('hstore') - @connection.enable_extension 'hstore' + unless @connection.extension_enabled?("hstore") + @connection.enable_extension "hstore" @connection.commit_db_transaction end @connection.reconnect! @connection.transaction do - @connection.create_table('hstores') do |t| - t.hstore 'tags', :default => '' - t.hstore 'payload', array: true - t.hstore 'settings' + @connection.create_table("hstores") do |t| + t.hstore "tags", default: "" + t.hstore "payload", array: true + t.hstore "settings" end end Hstore.reset_column_information - @column = Hstore.columns_hash['tags'] + @column = Hstore.columns_hash["tags"] @type = Hstore.type_for_attribute("tags") end teardown do - @connection.drop_table 'hstores', if_exists: true + @connection.drop_table "hstores", if_exists: true end def test_hstore_included_in_extensions assert @connection.respond_to?(:extensions), "connection should have a list of extensions" - assert @connection.extensions.include?('hstore'), "extension list should include hstore" + assert_includes @connection.extensions, "hstore", "extension list should include hstore" end def test_disable_enable_hstore - assert @connection.extension_enabled?('hstore') - @connection.disable_extension 'hstore' - assert_not @connection.extension_enabled?('hstore') - @connection.enable_extension 'hstore' - assert @connection.extension_enabled?('hstore') + assert @connection.extension_enabled?("hstore") + @connection.disable_extension "hstore" + assert_not @connection.extension_enabled?("hstore") + @connection.enable_extension "hstore" + assert @connection.extension_enabled?("hstore") ensure # Restore column(s) dropped by `drop extension hstore cascade;` load_schema @@ -61,22 +61,22 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_default - @connection.add_column 'hstores', 'permissions', :hstore, default: '"users"=>"read", "articles"=>"write"' + @connection.add_column "hstores", "permissions", :hstore, default: '"users"=>"read", "articles"=>"write"' Hstore.reset_column_information - assert_equal({"users"=>"read", "articles"=>"write"}, Hstore.column_defaults['permissions']) - assert_equal({"users"=>"read", "articles"=>"write"}, Hstore.new.permissions) + assert_equal({ "users"=>"read", "articles"=>"write" }, Hstore.column_defaults["permissions"]) + assert_equal({ "users"=>"read", "articles"=>"write" }, Hstore.new.permissions) ensure Hstore.reset_column_information end def test_change_table_supports_hstore @connection.transaction do - @connection.change_table('hstores') do |t| - t.hstore 'users', default: '' + @connection.change_table("hstores") do |t| + t.hstore "users", default: "" end Hstore.reset_column_information - column = Hstore.columns_hash['users'] + column = Hstore.columns_hash["users"] assert_equal :hstore, column.type raise ActiveRecord::Rollback # reset the schema change @@ -103,18 +103,18 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_cast_value_on_write - x = Hstore.new tags: {"bool" => true, "number" => 5} - assert_equal({"bool" => true, "number" => 5}, x.tags_before_type_cast) - assert_equal({"bool" => "true", "number" => "5"}, x.tags) + x = Hstore.new tags: { "bool" => true, "number" => 5 } + assert_equal({ "bool" => true, "number" => 5 }, x.tags_before_type_cast) + assert_equal({ "bool" => "true", "number" => "5" }, x.tags) x.save - assert_equal({"bool" => "true", "number" => "5"}, x.reload.tags) + assert_equal({ "bool" => "true", "number" => "5" }, x.reload.tags) end def test_type_cast_hstore - assert_equal({'1' => '2'}, @type.deserialize("\"1\"=>\"2\"")) + assert_equal({ "1" => "2" }, @type.deserialize("\"1\"=>\"2\"")) assert_equal({}, @type.deserialize("")) - assert_equal({'key'=>nil}, @type.deserialize('key => NULL')) - assert_equal({'c'=>'}','"a"'=>'b "a b'}, @type.deserialize(%q(c=>"}", "\"a\""=>"b \"a b"))) + assert_equal({ "key"=>nil }, @type.deserialize("key => NULL")) + assert_equal({ "c"=>"}",'"a"'=>'b "a b' }, @type.deserialize(%q(c=>"}", "\"a\""=>"b \"a b"))) end def test_with_store_accessors @@ -156,132 +156,132 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_changes_in_place - hstore = Hstore.create!(settings: { 'one' => 'two' }) - hstore.settings['three'] = 'four' + hstore = Hstore.create!(settings: { "one" => "two" }) + hstore.settings["three"] = "four" hstore.save! hstore.reload - assert_equal 'four', hstore.settings['three'] + assert_equal "four", hstore.settings["three"] assert_not hstore.changed? end def test_gen1 - assert_equal(%q(" "=>""), @type.serialize({' '=>''})) + assert_equal('" "=>""', @type.serialize(" "=>"")) end def test_gen2 - assert_equal(%q(","=>""), @type.serialize({','=>''})) + assert_equal('","=>""', @type.serialize(","=>"")) end def test_gen3 - assert_equal(%q("="=>""), @type.serialize({'='=>''})) + assert_equal('"="=>""', @type.serialize("="=>"")) end def test_gen4 - assert_equal(%q(">"=>""), @type.serialize({'>'=>''})) + assert_equal('">"=>""', @type.serialize(">"=>"")) end def test_parse1 - assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @type.deserialize('a=>null,b=>NuLl,c=>"NuLl",null=>c')) + assert_equal({ "a"=>nil,"b"=>nil,"c"=>"NuLl","null"=>"c" }, @type.deserialize('a=>null,b=>NuLl,c=>"NuLl",null=>c')) end def test_parse2 - assert_equal({" " => " "}, @type.deserialize("\\ =>\\ ")) + assert_equal({ " " => " " }, @type.deserialize("\\ =>\\ ")) end def test_parse3 - assert_equal({"=" => ">"}, @type.deserialize("==>>")) + assert_equal({ "=" => ">" }, @type.deserialize("==>>")) end def test_parse4 - assert_equal({"=a"=>"q=w"}, @type.deserialize('\=a=>q=w')) + assert_equal({ "=a"=>"q=w" }, @type.deserialize('\=a=>q=w')) end def test_parse5 - assert_equal({"=a"=>"q=w"}, @type.deserialize('"=a"=>q\=w')) + assert_equal({ "=a"=>"q=w" }, @type.deserialize('"=a"=>q\=w')) end def test_parse6 - assert_equal({"\"a"=>"q>w"}, @type.deserialize('"\"a"=>q>w')) + assert_equal({ "\"a"=>"q>w" }, @type.deserialize('"\"a"=>q>w')) end def test_parse7 - assert_equal({"\"a"=>"q\"w"}, @type.deserialize('\"a=>q"w')) + assert_equal({ "\"a"=>"q\"w" }, @type.deserialize('\"a=>q"w')) end def test_rewrite @connection.execute "insert into hstores (tags) VALUES ('1=>2')" x = Hstore.first - x.tags = { '"a\'' => 'b' } + x.tags = { '"a\'' => "b" } assert x.save! end def test_select @connection.execute "insert into hstores (tags) VALUES ('1=>2')" x = Hstore.first - assert_equal({'1' => '2'}, x.tags) + assert_equal({ "1" => "2" }, x.tags) end def test_array_cycle - assert_array_cycle([{"AA" => "BB", "CC" => "DD"}, {"AA" => nil}]) + assert_array_cycle([{ "AA" => "BB", "CC" => "DD" }, { "AA" => nil }]) end def test_array_strings_with_quotes - assert_array_cycle([{'this has' => 'some "s that need to be escaped"'}]) + assert_array_cycle([{ "this has" => 'some "s that need to be escaped"' }]) end def test_array_strings_with_commas - assert_array_cycle([{'this,has' => 'many,values'}]) + assert_array_cycle([{ "this,has" => "many,values" }]) end def test_array_strings_with_array_delimiters - assert_array_cycle(['{' => '}']) + assert_array_cycle(["{" => "}"]) end def test_array_strings_with_null_strings - assert_array_cycle([{'NULL' => 'NULL'}]) + assert_array_cycle([{ "NULL" => "NULL" }]) end def test_contains_nils - assert_array_cycle([{'NULL' => nil}]) + assert_array_cycle([{ "NULL" => nil }]) end def test_select_multikey @connection.execute "insert into hstores (tags) VALUES ('1=>2,2=>3')" x = Hstore.first - assert_equal({'1' => '2', '2' => '3'}, x.tags) + assert_equal({ "1" => "2", "2" => "3" }, x.tags) end def test_create - assert_cycle('a' => 'b', '1' => '2') + assert_cycle("a" => "b", "1" => "2") end def test_nil - assert_cycle('a' => nil) + assert_cycle("a" => nil) end def test_quotes - assert_cycle('a' => 'b"ar', '1"foo' => '2') + assert_cycle("a" => 'b"ar', '1"foo' => "2") end def test_whitespace - assert_cycle('a b' => 'b ar', '1"foo' => '2') + assert_cycle("a b" => "b ar", '1"foo' => "2") end def test_backslash - assert_cycle('a\\b' => 'b\\ar', '1"foo' => '2') + assert_cycle('a\\b' => 'b\\ar', '1"foo' => "2") end def test_comma - assert_cycle('a, b' => 'bar', '1"foo' => '2') + assert_cycle("a, b" => "bar", '1"foo' => "2") end def test_arrow - assert_cycle('a=>b' => 'bar', '1"foo' => '2') + assert_cycle("a=>b" => "bar", '1"foo' => "2") end def test_quoting_special_characters - assert_cycle('ca' => 'cà ', 'ac' => 'à c') + assert_cycle("ca" => "cà ", "ac" => "à c") end def test_multiline @@ -300,20 +300,20 @@ if ActiveRecord::Base.connection.supports_extensions? end def test_hstore_with_serialized_attributes - HstoreWithSerialize.create! tags: TagCollection.new({"one" => "two"}) + HstoreWithSerialize.create! tags: TagCollection.new("one" => "two") record = HstoreWithSerialize.first assert_instance_of TagCollection, record.tags - assert_equal({"one" => "two"}, record.tags.to_hash) + assert_equal({ "one" => "two" }, record.tags.to_hash) record.tags = TagCollection.new("three" => "four") record.save! - assert_equal({"three" => "four"}, HstoreWithSerialize.first.tags.to_hash) + assert_equal({ "three" => "four" }, HstoreWithSerialize.first.tags.to_hash) end def test_clone_hstore_with_serialized_attributes - HstoreWithSerialize.create! tags: TagCollection.new({"one" => "two"}) + HstoreWithSerialize.create! tags: TagCollection.new("one" => "two") record = HstoreWithSerialize.first dupe = record.dup - assert_equal({"one" => "two"}, dupe.tags.to_hash) + assert_equal({ "one" => "two" }, dupe.tags.to_hash) end def test_schema_dump_with_shorthand @@ -322,32 +322,32 @@ if ActiveRecord::Base.connection.supports_extensions? end private - def assert_array_cycle(array) - # test creation - x = Hstore.create!(payload: array) - x.reload - assert_equal(array, x.payload) - - # test updating - x = Hstore.create!(payload: []) - x.payload = array - x.save! - x.reload - assert_equal(array, x.payload) - end - - def assert_cycle(hash) - # test creation - x = Hstore.create!(:tags => hash) - x.reload - assert_equal(hash, x.tags) + def assert_array_cycle(array) + # test creation + x = Hstore.create!(payload: array) + x.reload + assert_equal(array, x.payload) + + # test updating + x = Hstore.create!(payload: []) + x.payload = array + x.save! + x.reload + assert_equal(array, x.payload) + end - # test updating - x = Hstore.create!(:tags => {}) - x.tags = hash - x.save! - x.reload - assert_equal(hash, x.tags) - end + def assert_cycle(hash) + # test creation + x = Hstore.create!(tags: hash) + x.reload + assert_equal(hash, x.tags) + + # test updating + x = Hstore.create!(tags: {}) + x.tags = hash + x.save! + x.reload + assert_equal(hash, x.tags) + end end end diff --git a/activerecord/test/cases/adapters/postgresql/infinity_test.rb b/activerecord/test/cases/adapters/postgresql/infinity_test.rb index bfda933fa4..19b00258b6 100644 --- a/activerecord/test/cases/adapters/postgresql/infinity_test.rb +++ b/activerecord/test/cases/adapters/postgresql/infinity_test.rb @@ -15,7 +15,7 @@ class PostgresqlInfinityTest < ActiveRecord::PostgreSQLTestCase end teardown do - @connection.drop_table 'postgresql_infinities', if_exists: true + @connection.drop_table "postgresql_infinities", if_exists: true end test "type casting infinity on a float column" do @@ -25,11 +25,11 @@ class PostgresqlInfinityTest < ActiveRecord::PostgreSQLTestCase end test "type casting string on a float column" do - record = PostgresqlInfinity.new(float: 'Infinity') + record = PostgresqlInfinity.new(float: "Infinity") assert_equal Float::INFINITY, record.float - record = PostgresqlInfinity.new(float: '-Infinity') + record = PostgresqlInfinity.new(float: "-Infinity") assert_equal(-Float::INFINITY, record.float) - record = PostgresqlInfinity.new(float: 'NaN') + record = PostgresqlInfinity.new(float: "NaN") assert_send [record.float, :nan?] end diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb index 663de680b5..273b2c1c7b 100644 --- a/activerecord/test/cases/adapters/postgresql/json_test.rb +++ b/activerecord/test/cases/adapters/postgresql/json_test.rb @@ -1,11 +1,11 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" module PostgresqlJSONSharedTestCases include SchemaDumpingHelper class JsonDataType < ActiveRecord::Base - self.table_name = 'json_data_type' + self.table_name = "json_data_type" store_accessor :settings, :resolution end @@ -13,9 +13,9 @@ module PostgresqlJSONSharedTestCases def setup @connection = ActiveRecord::Base.connection begin - @connection.create_table('json_data_type') do |t| - t.public_send column_type, 'payload', default: {} # t.json 'payload', default: {} - t.public_send column_type, 'settings' # t.json 'settings' + @connection.create_table("json_data_type") do |t| + t.public_send column_type, "payload", default: {} # t.json 'payload', default: {} + t.public_send column_type, "settings" # t.json 'settings' end rescue ActiveRecord::StatementInvalid skip "do not test on PostgreSQL without #{column_type} type." @@ -38,22 +38,22 @@ module PostgresqlJSONSharedTestCases end def test_default - @connection.add_column 'json_data_type', 'permissions', column_type, default: {"users": "read", "posts": ["read", "write"]} + @connection.add_column "json_data_type", "permissions", column_type, default: { "users": "read", "posts": ["read", "write"] } JsonDataType.reset_column_information - assert_equal({"users"=>"read", "posts"=>["read", "write"]}, JsonDataType.column_defaults['permissions']) - assert_equal({"users"=>"read", "posts"=>["read", "write"]}, JsonDataType.new.permissions) + assert_equal({ "users"=>"read", "posts"=>["read", "write"] }, JsonDataType.column_defaults["permissions"]) + assert_equal({ "users"=>"read", "posts"=>["read", "write"] }, JsonDataType.new.permissions) ensure JsonDataType.reset_column_information end def test_change_table_supports_json @connection.transaction do - @connection.change_table('json_data_type') do |t| - t.public_send column_type, 'users', default: '{}' # t.json 'users', default: '{}' + @connection.change_table("json_data_type") do |t| + t.public_send column_type, "users", default: "{}" # t.json 'users', default: '{}' end JsonDataType.reset_column_information - column = JsonDataType.columns_hash['users'] + column = JsonDataType.columns_hash["users"] assert_equal column_type, column.type raise ActiveRecord::Rollback # reset the schema change @@ -68,11 +68,11 @@ module PostgresqlJSONSharedTestCases end def test_cast_value_on_write - x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar} - assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast) - assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload) + x = JsonDataType.new payload: { "string" => "foo", :symbol => :bar } + assert_equal({ "string" => "foo", :symbol => :bar }, x.payload_before_type_cast) + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.payload) x.save - assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload) + assert_equal({ "string" => "foo", "symbol" => "bar" }, x.reload.payload) end def test_type_cast_json @@ -80,49 +80,65 @@ module PostgresqlJSONSharedTestCases data = "{\"a_key\":\"a_value\"}" hash = type.deserialize(data) - assert_equal({'a_key' => 'a_value'}, hash) - assert_equal({'a_key' => 'a_value'}, type.deserialize(data)) + assert_equal({ "a_key" => "a_value" }, hash) + assert_equal({ "a_key" => "a_value" }, type.deserialize(data)) assert_equal({}, type.deserialize("{}")) - assert_equal({'key'=>nil}, type.deserialize('{"key": null}')) - assert_equal({'c'=>'}','"a"'=>'b "a b'}, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) + assert_equal({ "key"=>nil }, type.deserialize('{"key": null}')) + assert_equal({ "c"=>"}",'"a"'=>'b "a b' }, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"}))) end def test_rewrite @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" x = JsonDataType.first - x.payload = { '"a\'' => 'b' } + x.payload = { '"a\'' => "b" } assert x.save! end def test_select @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')" x = JsonDataType.first - assert_equal({'k' => 'v'}, x.payload) + assert_equal({ "k" => "v" }, x.payload) end def test_select_multikey @connection.execute %q|insert into json_data_type (payload) VALUES ('{"k1":"v1", "k2":"v2", "k3":[1,2,3]}')| x = JsonDataType.first - assert_equal({'k1' => 'v1', 'k2' => 'v2', 'k3' => [1,2,3]}, x.payload) + assert_equal({ "k1" => "v1", "k2" => "v2", "k3" => [1,2,3] }, x.payload) end def test_null_json - @connection.execute %q|insert into json_data_type (payload) VALUES(null)| + @connection.execute "insert into json_data_type (payload) VALUES(null)" x = JsonDataType.first assert_equal(nil, x.payload) end + def test_select_nil_json_after_create + json = JsonDataType.create(payload: nil) + x = JsonDataType.where(payload:nil).first + assert_equal(json, x) + end + + def test_select_nil_json_after_update + json = JsonDataType.create(payload: "foo") + x = JsonDataType.where(payload:nil).first + assert_equal(nil, x) + + json.update_attributes payload: nil + x = JsonDataType.where(payload:nil).first + assert_equal(json.reload, x) + end + def test_select_array_json_value @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| x = JsonDataType.first - assert_equal(['v0', {'k1' => 'v1'}], x.payload) + assert_equal(["v0", { "k1" => "v1" }], x.payload) end def test_rewrite_array_json_value @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')| x = JsonDataType.first - x.payload = ['v1', {'k2' => 'v2'}, 'v3'] + x.payload = ["v1", { "k2" => "v2" }, "v3"] assert x.save! end @@ -161,20 +177,20 @@ module PostgresqlJSONSharedTestCases json = JsonDataType.new assert_not json.changed? - json.payload = { 'one' => 'two' } + json.payload = { "one" => "two" } assert json.changed? assert json.payload_changed? json.save! assert_not json.changed? - json.payload['three'] = 'four' + json.payload["three"] = "four" assert json.payload_changed? json.save! json.reload - assert_equal({ 'one' => 'two', 'three' => 'four' }, json.payload) + assert_equal({ "one" => "two", "three" => "four" }, json.payload) assert_not json.changed? end diff --git a/activerecord/test/cases/adapters/postgresql/ltree_test.rb b/activerecord/test/cases/adapters/postgresql/ltree_test.rb index 56516c82b4..2b5ac1cac6 100644 --- a/activerecord/test/cases/adapters/postgresql/ltree_test.rb +++ b/activerecord/test/cases/adapters/postgresql/ltree_test.rb @@ -1,20 +1,20 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlLtreeTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper class Ltree < ActiveRecord::Base - self.table_name = 'ltrees' + self.table_name = "ltrees" end def setup @connection = ActiveRecord::Base.connection - enable_extension!('ltree', @connection) + enable_extension!("ltree", @connection) @connection.transaction do - @connection.create_table('ltrees') do |t| - t.ltree 'path' + @connection.create_table("ltrees") do |t| + t.ltree "path" end end rescue ActiveRecord::StatementInvalid @@ -22,28 +22,28 @@ class PostgresqlLtreeTest < ActiveRecord::PostgreSQLTestCase end teardown do - @connection.drop_table 'ltrees', if_exists: true + @connection.drop_table "ltrees", if_exists: true end def test_column - column = Ltree.columns_hash['path'] + column = Ltree.columns_hash["path"] assert_equal :ltree, column.type assert_equal "ltree", column.sql_type assert_not column.array? - type = Ltree.type_for_attribute('path') + type = Ltree.type_for_attribute("path") assert_not type.binary? end def test_write - ltree = Ltree.new(path: '1.2.3.4') + ltree = Ltree.new(path: "1.2.3.4") assert ltree.save! end def test_select @connection.execute "insert into ltrees (path) VALUES ('1.2.3')" ltree = Ltree.first - assert_equal '1.2.3', ltree.path + assert_equal "1.2.3", ltree.path end def test_schema_dump_with_shorthand diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb index c031178479..1b5d8362af 100644 --- a/activerecord/test/cases/adapters/postgresql/money_test.rb +++ b/activerecord/test/cases/adapters/postgresql/money_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper @@ -9,14 +9,14 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase setup do @connection = ActiveRecord::Base.connection @connection.execute("set lc_monetary = 'C'") - @connection.create_table('postgresql_moneys', force: true) do |t| + @connection.create_table("postgresql_moneys", force: true) do |t| t.money "wealth" t.money "depth", default: "150.55" end end teardown do - @connection.drop_table 'postgresql_moneys', if_exists: true + @connection.drop_table "postgresql_moneys", if_exists: true end def test_column @@ -31,7 +31,7 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase end def test_default - assert_equal BigDecimal.new("150.55"), PostgresqlMoney.column_defaults['depth'] + assert_equal BigDecimal.new("150.55"), PostgresqlMoney.column_defaults["depth"] assert_equal BigDecimal.new("150.55"), PostgresqlMoney.new.depth end @@ -46,7 +46,7 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase end def test_money_type_cast - type = PostgresqlMoney.type_for_attribute('wealth') + type = PostgresqlMoney.type_for_attribute("wealth") assert_equal(12345678.12, type.cast("$12,345,678.12")) assert_equal(12345678.12, type.cast("$12.345.678,12")) assert_equal(-1.15, type.cast("-$1.15")) @@ -63,7 +63,7 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase money = PostgresqlMoney.create(wealth: "987.65") assert_equal 987.65, money.wealth - new_value = BigDecimal.new('123.45') + new_value = BigDecimal.new("123.45") money.wealth = new_value money.save! money.reload @@ -80,7 +80,7 @@ class PostgresqlMoneyTest < ActiveRecord::PostgreSQLTestCase def test_update_all_with_money_big_decimal money = PostgresqlMoney.create! - PostgresqlMoney.update_all(wealth: '123.45'.to_d) + PostgresqlMoney.update_all(wealth: "123.45".to_d) money.reload assert_equal 123.45, money.wealth diff --git a/activerecord/test/cases/adapters/postgresql/network_test.rb b/activerecord/test/cases/adapters/postgresql/network_test.rb index fe6ee4e2d9..a33b0ef8a7 100644 --- a/activerecord/test/cases/adapters/postgresql/network_test.rb +++ b/activerecord/test/cases/adapters/postgresql/network_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlNetworkTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper @@ -7,15 +7,15 @@ class PostgresqlNetworkTest < ActiveRecord::PostgreSQLTestCase setup do @connection = ActiveRecord::Base.connection - @connection.create_table('postgresql_network_addresses', force: true) do |t| - t.inet 'inet_address', default: "192.168.1.1" - t.cidr 'cidr_address', default: "192.168.1.0/24" - t.macaddr 'mac_address', default: "ff:ff:ff:ff:ff:ff" + @connection.create_table("postgresql_network_addresses", force: true) do |t| + t.inet "inet_address", default: "192.168.1.1" + t.cidr "cidr_address", default: "192.168.1.0/24" + t.macaddr "mac_address", default: "ff:ff:ff:ff:ff:ff" end end teardown do - @connection.drop_table 'postgresql_network_addresses', if_exists: true + @connection.drop_table "postgresql_network_addresses", if_exists: true end def test_cidr_column @@ -49,33 +49,33 @@ class PostgresqlNetworkTest < ActiveRecord::PostgreSQLTestCase end def test_network_types - PostgresqlNetworkAddress.create(cidr_address: '192.168.0.0/24', - inet_address: '172.16.1.254/32', - mac_address: '01:23:45:67:89:0a') + PostgresqlNetworkAddress.create(cidr_address: "192.168.0.0/24", + inet_address: "172.16.1.254/32", + mac_address: "01:23:45:67:89:0a") address = PostgresqlNetworkAddress.first - assert_equal IPAddr.new('192.168.0.0/24'), address.cidr_address - assert_equal IPAddr.new('172.16.1.254'), address.inet_address - assert_equal '01:23:45:67:89:0a', address.mac_address + assert_equal IPAddr.new("192.168.0.0/24"), address.cidr_address + assert_equal IPAddr.new("172.16.1.254"), address.inet_address + assert_equal "01:23:45:67:89:0a", address.mac_address - address.cidr_address = '10.1.2.3/32' - address.inet_address = '10.0.0.0/8' - address.mac_address = 'bc:de:f0:12:34:56' + address.cidr_address = "10.1.2.3/32" + address.inet_address = "10.0.0.0/8" + address.mac_address = "bc:de:f0:12:34:56" address.save! assert address.reload - assert_equal IPAddr.new('10.1.2.3/32'), address.cidr_address - assert_equal IPAddr.new('10.0.0.0/8'), address.inet_address - assert_equal 'bc:de:f0:12:34:56', address.mac_address + assert_equal IPAddr.new("10.1.2.3/32"), address.cidr_address + assert_equal IPAddr.new("10.0.0.0/8"), address.inet_address + assert_equal "bc:de:f0:12:34:56", address.mac_address end def test_invalid_network_address - invalid_address = PostgresqlNetworkAddress.new(cidr_address: 'invalid addr', - inet_address: 'invalid addr') + invalid_address = PostgresqlNetworkAddress.new(cidr_address: "invalid addr", + inet_address: "invalid addr") assert_nil invalid_address.cidr_address assert_nil invalid_address.inet_address - assert_equal 'invalid addr', invalid_address.cidr_address_before_type_cast - assert_equal 'invalid addr', invalid_address.inet_address_before_type_cast + assert_equal "invalid addr", invalid_address.cidr_address_before_type_cast + assert_equal "invalid addr", invalid_address.inet_address_before_type_cast assert invalid_address.save invalid_address.reload diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb index ba7e7dc9a3..834354dcc9 100644 --- a/activerecord/test/cases/adapters/postgresql/numbers_test.rb +++ b/activerecord/test/cases/adapters/postgresql/numbers_test.rb @@ -5,14 +5,14 @@ class PostgresqlNumberTest < ActiveRecord::PostgreSQLTestCase setup do @connection = ActiveRecord::Base.connection - @connection.create_table('postgresql_numbers', force: true) do |t| - t.column 'single', 'REAL' - t.column 'double', 'DOUBLE PRECISION' + @connection.create_table("postgresql_numbers", force: true) do |t| + t.column "single", "REAL" + t.column "double", "DOUBLE PRECISION" end end teardown do - @connection.drop_table 'postgresql_numbers', if_exists: true + @connection.drop_table "postgresql_numbers", if_exists: true end def test_data_type diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 9832df7839..e6af93a53e 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'support/ddl_helper' -require 'support/connection_helper' +require "support/ddl_helper" +require "support/connection_helper" module ActiveRecord module ConnectionAdapters @@ -15,15 +15,15 @@ module ActiveRecord def test_bad_connection assert_raise ActiveRecord::NoDatabaseError do - configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'should_not_exist-cinco-dog-db') + configuration = ActiveRecord::Base.configurations["arunit"].merge(database: "should_not_exist-cinco-dog-db") connection = ActiveRecord::Base.postgresql_connection(configuration) - connection.exec_query('SELECT 1') + connection.exec_query("SELECT 1") end end def test_valid_column with_example_table do - column = @connection.columns('ex').find { |col| col.name == 'id' } + column = @connection.columns("ex").find { |col| col.name == "id" } assert @connection.valid_type?(column.type) end end @@ -34,144 +34,138 @@ module ActiveRecord def test_primary_key with_example_table do - assert_equal 'id', @connection.primary_key('ex') + assert_equal "id", @connection.primary_key("ex") end end def test_primary_key_works_tables_containing_capital_letters - assert_equal 'id', @connection.primary_key('CamelCase') + assert_equal "id", @connection.primary_key("CamelCase") end def test_non_standard_primary_key - with_example_table 'data character varying(255) primary key' do - assert_equal 'data', @connection.primary_key('ex') + with_example_table "data character varying(255) primary key" do + assert_equal "data", @connection.primary_key("ex") end end def test_primary_key_returns_nil_for_no_pk - with_example_table 'id integer' do - assert_nil @connection.primary_key('ex') + with_example_table "id integer" do + assert_nil @connection.primary_key("ex") end end def test_primary_key_raises_error_if_table_not_found assert_raises(ActiveRecord::StatementInvalid) do - @connection.primary_key('unobtainium') + @connection.primary_key("unobtainium") end end def test_exec_insert_with_returning_disabled connection = connection_without_insert_returning - result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id', 'postgresql_partitioned_table_parent_id_seq') - expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first + result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], "id", "postgresql_partitioned_table_parent_id_seq") + expect = connection.query("select max(id) from postgresql_partitioned_table_parent").first.first assert_equal expect.to_i, result.rows.first.first end def test_exec_insert_with_returning_disabled_and_no_sequence_name_given connection = connection_without_insert_returning - result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], 'id') - expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first + result = connection.exec_insert("insert into postgresql_partitioned_table_parent (number) VALUES (1)", nil, [], "id") + expect = connection.query("select max(id) from postgresql_partitioned_table_parent").first.first assert_equal expect.to_i, result.rows.first.first end def test_exec_insert_default_values_with_returning_disabled_and_no_sequence_name_given connection = connection_without_insert_returning - result = connection.exec_insert("insert into postgresql_partitioned_table_parent DEFAULT VALUES", nil, [], 'id') - expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first + result = connection.exec_insert("insert into postgresql_partitioned_table_parent DEFAULT VALUES", nil, [], "id") + expect = connection.query("select max(id) from postgresql_partitioned_table_parent").first.first assert_equal expect.to_i, result.rows.first.first end def test_exec_insert_default_values_quoted_schema_with_returning_disabled_and_no_sequence_name_given connection = connection_without_insert_returning - result = connection.exec_insert('insert into "public"."postgresql_partitioned_table_parent" DEFAULT VALUES', nil, [], 'id') - expect = connection.query('select max(id) from postgresql_partitioned_table_parent').first.first + result = connection.exec_insert('insert into "public"."postgresql_partitioned_table_parent" DEFAULT VALUES', nil, [], "id") + expect = connection.query("select max(id) from postgresql_partitioned_table_parent").first.first assert_equal expect.to_i, result.rows.first.first end - def test_sql_for_insert_with_returning_disabled - connection = connection_without_insert_returning - sql, binds = connection.sql_for_insert('sql', nil, nil, nil, 'binds') - assert_equal ['sql', 'binds'], [sql, binds] - end - def test_serial_sequence - assert_equal 'public.accounts_id_seq', - @connection.serial_sequence('accounts', 'id') + assert_equal "public.accounts_id_seq", + @connection.serial_sequence("accounts", "id") assert_raises(ActiveRecord::StatementInvalid) do - @connection.serial_sequence('zomg', 'id') + @connection.serial_sequence("zomg", "id") end end def test_default_sequence_name - assert_equal 'public.accounts_id_seq', - @connection.default_sequence_name('accounts', 'id') + assert_equal "public.accounts_id_seq", + @connection.default_sequence_name("accounts", "id") - assert_equal 'public.accounts_id_seq', - @connection.default_sequence_name('accounts') + assert_equal "public.accounts_id_seq", + @connection.default_sequence_name("accounts") end def test_default_sequence_name_bad_table - assert_equal 'zomg_id_seq', - @connection.default_sequence_name('zomg', 'id') + assert_equal "zomg_id_seq", + @connection.default_sequence_name("zomg", "id") - assert_equal 'zomg_id_seq', - @connection.default_sequence_name('zomg') + assert_equal "zomg_id_seq", + @connection.default_sequence_name("zomg") end def test_pk_and_sequence_for with_example_table do - pk, seq = @connection.pk_and_sequence_for('ex') - assert_equal 'id', pk - assert_equal @connection.default_sequence_name('ex', 'id'), seq.to_s + pk, seq = @connection.pk_and_sequence_for("ex") + assert_equal "id", pk + assert_equal @connection.default_sequence_name("ex", "id"), seq.to_s end end def test_pk_and_sequence_for_with_non_standard_primary_key - with_example_table 'code serial primary key' do - pk, seq = @connection.pk_and_sequence_for('ex') - assert_equal 'code', pk - assert_equal @connection.default_sequence_name('ex', 'code'), seq.to_s + with_example_table "code serial primary key" do + pk, seq = @connection.pk_and_sequence_for("ex") + assert_equal "code", pk + assert_equal @connection.default_sequence_name("ex", "code"), seq.to_s end end def test_pk_and_sequence_for_returns_nil_if_no_seq - with_example_table 'id integer primary key' do - assert_nil @connection.pk_and_sequence_for('ex') + with_example_table "id integer primary key" do + assert_nil @connection.pk_and_sequence_for("ex") end end def test_pk_and_sequence_for_returns_nil_if_no_pk - with_example_table 'id integer' do - assert_nil @connection.pk_and_sequence_for('ex') + with_example_table "id integer" do + assert_nil @connection.pk_and_sequence_for("ex") end end def test_pk_and_sequence_for_returns_nil_if_table_not_found - assert_nil @connection.pk_and_sequence_for('unobtainium') + assert_nil @connection.pk_and_sequence_for("unobtainium") end def test_pk_and_sequence_for_with_collision_pg_class_oid - @connection.exec_query('create table ex(id serial primary key)') - @connection.exec_query('create table ex2(id serial primary key)') + @connection.exec_query("create table ex(id serial primary key)") + @connection.exec_query("create table ex2(id serial primary key)") correct_depend_record = [ "'pg_class'::regclass", "'ex_id_seq'::regclass", - '0', + "0", "'pg_class'::regclass", "'ex'::regclass", - '1', + "1", "'a'" ] collision_depend_record = [ "'pg_attrdef'::regclass", "'ex2_id_seq'::regclass", - '0', + "0", "'pg_class'::regclass", "'ex'::regclass", - '1', + "1", "'a'" ] @@ -185,15 +179,15 @@ module ActiveRecord "INSERT INTO pg_depend VALUES(#{correct_depend_record.join(',')})" ) - seq = @connection.pk_and_sequence_for('ex').last + seq = @connection.pk_and_sequence_for("ex").last assert_equal PostgreSQL::Name.new("public", "ex_id_seq"), seq @connection.exec_query( "DELETE FROM pg_depend WHERE objid = 'ex2_id_seq'::regclass AND refobjid = 'ex'::regclass AND deptype = 'a'" ) ensure - @connection.drop_table 'ex', if_exists: true - @connection.drop_table 'ex2', if_exists: true + @connection.drop_table "ex", if_exists: true + @connection.drop_table "ex2", if_exists: true end def test_table_alias_length @@ -204,74 +198,74 @@ module ActiveRecord def test_exec_no_binds with_example_table do - result = @connection.exec_query('SELECT id, data FROM ex') + result = @connection.exec_query("SELECT id, data FROM ex") assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns - string = @connection.quote('foo') + string = @connection.quote("foo") @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") - result = @connection.exec_query('SELECT id, data FROM ex') + result = @connection.exec_query("SELECT id, data FROM ex") assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, "foo"]], result.rows end end if ActiveRecord::Base.connection.prepared_statements def test_exec_with_binds with_example_table do - string = @connection.quote('foo') + string = @connection.quote("foo") @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") bind = Relation::QueryAttribute.new("id", 1, Type::Value.new) - result = @connection.exec_query('SELECT id, data FROM ex WHERE id = $1', nil, [bind]) + result = @connection.exec_query("SELECT id, data FROM ex WHERE id = $1", nil, [bind]) assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, "foo"]], result.rows end end def test_exec_typecasts_bind_vals with_example_table do - string = @connection.quote('foo') + string = @connection.quote("foo") @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") bind = Relation::QueryAttribute.new("id", "1-fuu", Type::Integer.new) - result = @connection.exec_query('SELECT id, data FROM ex WHERE id = $1', nil, [bind]) + result = @connection.exec_query("SELECT id, data FROM ex WHERE id = $1", nil, [bind]) assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, "foo"]], result.rows end end end def test_partial_index with_example_table do - @connection.add_index 'ex', %w{ id number }, :name => 'partial', :where => "number > 100" - index = @connection.indexes('ex').find { |idx| idx.name == 'partial' } + @connection.add_index "ex", %w{ id number }, name: "partial", where: "number > 100" + index = @connection.indexes("ex").find { |idx| idx.name == "partial" } assert_equal "(number > 100)", index.where end end def test_expression_index with_example_table do - @connection.add_index 'ex', 'mod(id, 10), abs(number)', name: 'expression' - index = @connection.indexes('ex').find { |idx| idx.name == 'expression' } - assert_equal 'mod(id, 10), abs(number)', index.columns + @connection.add_index "ex", "mod(id, 10), abs(number)", name: "expression" + index = @connection.indexes("ex").find { |idx| idx.name == "expression" } + assert_equal "mod(id, 10), abs(number)", index.columns end end def test_index_with_opclass with_example_table do - @connection.add_index 'ex', 'data varchar_pattern_ops', name: 'with_opclass' - index = @connection.indexes('ex').find { |idx| idx.name == 'with_opclass' } - assert_equal 'data varchar_pattern_ops', index.columns + @connection.add_index "ex", "data varchar_pattern_ops", name: "with_opclass" + index = @connection.indexes("ex").find { |idx| idx.name == "with_opclass" } + assert_equal "data varchar_pattern_ops", index.columns end end @@ -292,8 +286,8 @@ module ActiveRecord def test_columns_for_distinct_with_case assert_equal( - 'posts.id, CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0', - @connection.columns_for_distinct('posts.id', + "posts.id, CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0", + @connection.columns_for_distinct("posts.id", ["CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END"]) ) end @@ -374,7 +368,7 @@ module ActiveRecord def test_unparsed_defaults_are_at_least_set_when_saving with_example_table "id SERIAL PRIMARY KEY, number INTEGER NOT NULL DEFAULT (4 + 4) * 2 / 4" do number_klass = Class.new(ActiveRecord::Base) do - self.table_name = 'ex' + self.table_name = "ex" end column = number_klass.columns_hash["number"] assert_nil column.default @@ -390,13 +384,13 @@ module ActiveRecord private - def with_example_table(definition = 'id serial primary key, number integer, data character varying(255)', &block) - super(@connection, 'ex', definition, &block) - end + def with_example_table(definition = "id serial primary key, number integer, data character varying(255)", &block) + super(@connection, "ex", definition, &block) + end - def connection_without_insert_returning - ActiveRecord::Base.postgresql_connection(ActiveRecord::Base.configurations['arunit'].merge(:insert_returning => false)) - end + def connection_without_insert_returning + ActiveRecord::Base.postgresql_connection(ActiveRecord::Base.configurations["arunit"].merge(insert_returning: false)) + end end end end diff --git a/activerecord/test/cases/adapters/postgresql/prepared_statements_test.rb b/activerecord/test/cases/adapters/postgresql/prepared_statements_test.rb index f1519db48b..b898929f8a 100644 --- a/activerecord/test/cases/adapters/postgresql/prepared_statements_test.rb +++ b/activerecord/test/cases/adapters/postgresql/prepared_statements_test.rb @@ -18,5 +18,4 @@ class PreparedStatementsTest < ActiveRecord::PostgreSQLTestCase Developer.where(id: 1) end end - end diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index 5e6f4dbbb8..865a3a5098 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'ipaddr' +require "ipaddr" module ActiveRecord module ConnectionAdapters @@ -10,11 +10,11 @@ module ActiveRecord end def test_type_cast_true - assert_equal 't', @conn.type_cast(true) + assert_equal "t", @conn.type_cast(true) end def test_type_cast_false - assert_equal 'f', @conn.type_cast(false) + assert_equal "f", @conn.type_cast(false) end def test_quote_float_nan diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb index 0edfa4ed9d..f411884dfd 100644 --- a/activerecord/test/cases/adapters/postgresql/range_test.rb +++ b/activerecord/test/cases/adapters/postgresql/range_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" if ActiveRecord::Base.connection.respond_to?(:supports_ranges?) && ActiveRecord::Base.connection.supports_ranges? class PostgresqlRange < ActiveRecord::Base @@ -23,7 +23,7 @@ if ActiveRecord::Base.connection.respond_to?(:supports_ranges?) && ActiveRecord: ); _SQL - @connection.create_table('postgresql_ranges') do |t| + @connection.create_table("postgresql_ranges") do |t| t.daterange :date_range t.numrange :num_range t.tsrange :ts_range @@ -32,7 +32,7 @@ _SQL t.int8range :int8_range end - @connection.add_column 'postgresql_ranges', 'float_range', 'floatrange' + @connection.add_column "postgresql_ranges", "float_range", "floatrange" end PostgresqlRange.reset_column_information rescue ActiveRecord::StatementInvalid @@ -93,8 +93,8 @@ _SQL end teardown do - @connection.drop_table 'postgresql_ranges', if_exists: true - @connection.execute 'DROP TYPE IF EXISTS floatrange' + @connection.drop_table "postgresql_ranges", if_exists: true + @connection.execute "DROP TYPE IF EXISTS floatrange" reset_connection end @@ -132,10 +132,10 @@ _SQL end def test_numrange_values - assert_equal BigDecimal.new('0.1')..BigDecimal.new('0.2'), @first_range.num_range - assert_equal BigDecimal.new('0.1')...BigDecimal.new('0.2'), @second_range.num_range - assert_equal BigDecimal.new('0.1')...BigDecimal.new('Infinity'), @third_range.num_range - assert_equal BigDecimal.new('-Infinity')...BigDecimal.new('Infinity'), @fourth_range.num_range + assert_equal BigDecimal.new("0.1")..BigDecimal.new("0.2"), @first_range.num_range + assert_equal BigDecimal.new("0.1")...BigDecimal.new("0.2"), @second_range.num_range + assert_equal BigDecimal.new("0.1")...BigDecimal.new("Infinity"), @third_range.num_range + assert_equal BigDecimal.new("-Infinity")...BigDecimal.new("Infinity"), @fourth_range.num_range assert_nil @empty_range.num_range end @@ -148,8 +148,8 @@ _SQL end def test_tstzrange_values - assert_equal Time.parse('2010-01-01 09:30:00 UTC')..Time.parse('2011-01-01 17:30:00 UTC'), @first_range.tstz_range - assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Time.parse('2011-01-01 17:30:00 UTC'), @second_range.tstz_range + assert_equal Time.parse("2010-01-01 09:30:00 UTC")..Time.parse("2011-01-01 17:30:00 UTC"), @first_range.tstz_range + assert_equal Time.parse("2010-01-01 09:30:00 UTC")...Time.parse("2011-01-01 17:30:00 UTC"), @second_range.tstz_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.tstz_range) assert_nil @empty_range.tstz_range end @@ -183,17 +183,17 @@ _SQL end def test_create_tstzrange - tstzrange = Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2011-02-02 14:30:00 CDT') + tstzrange = Time.parse("2010-01-01 14:30:00 +0100")...Time.parse("2011-02-02 14:30:00 CDT") round_trip(@new_range, :tstz_range, tstzrange) assert_equal @new_range.tstz_range, tstzrange - assert_equal @new_range.tstz_range, Time.parse('2010-01-01 13:30:00 UTC')...Time.parse('2011-02-02 19:30:00 UTC') + assert_equal @new_range.tstz_range, Time.parse("2010-01-01 13:30:00 UTC")...Time.parse("2011-02-02 19:30:00 UTC") end def test_update_tstzrange assert_equal_round_trip(@first_range, :tstz_range, - Time.parse('2010-01-01 14:30:00 CDT')...Time.parse('2011-02-02 14:30:00 CET')) + Time.parse("2010-01-01 14:30:00 CDT")...Time.parse("2011-02-02 14:30:00 CET")) assert_nil_round_trip(@first_range, :tstz_range, - Time.parse('2010-01-01 14:30:00 +0100')...Time.parse('2010-01-01 13:30:00 +0000')) + Time.parse("2010-01-01 14:30:00 +0100")...Time.parse("2010-01-01 13:30:00 +0000")) end def test_create_tsrange @@ -232,14 +232,14 @@ _SQL def test_create_numrange assert_equal_round_trip(@new_range, :num_range, - BigDecimal.new('0.5')...BigDecimal.new('1')) + BigDecimal.new("0.5")...BigDecimal.new("1")) end def test_update_numrange assert_equal_round_trip(@first_range, :num_range, - BigDecimal.new('0.5')...BigDecimal.new('1')) + BigDecimal.new("0.5")...BigDecimal.new("1")) assert_nil_round_trip(@first_range, :num_range, - BigDecimal.new('0.5')...BigDecimal.new('0.5')) + BigDecimal.new("0.5")...BigDecimal.new("0.5")) end def test_create_daterange @@ -282,6 +282,12 @@ _SQL assert_raises(ArgumentError) { PostgresqlRange.create!(tstz_range: "(''2010-01-01 14:30:00+05'', ''2011-01-01 14:30:00-03'']") } end + def test_where_by_attribute_with_range + range = 1..100 + record = PostgresqlRange.create!(int4_range: range) + assert_equal record, PostgresqlRange.where(int4_range: range).take + end + def test_update_all_with_ranges PostgresqlRange.create! diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb index c895ab9db5..0ff04bfa27 100644 --- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb +++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'support/connection_helper' +require "cases/helper" +require "support/connection_helper" class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase self.use_transactional_tests = false @@ -14,7 +14,7 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase def execute(sql) if IS_REFERENTIAL_INTEGRITY_SQL.call(sql) super "BROKEN;" rescue nil # put transaction in broken state - raise ActiveRecord::StatementInvalid, 'PG::InsufficientPrivilege' + raise ActiveRecord::StatementInvalid, "PG::InsufficientPrivilege" else super end @@ -24,7 +24,7 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase module ProgrammerMistake def execute(sql) if IS_REFERENTIAL_INTEGRITY_SQL.call(sql) - raise ArgumentError, 'something is not right.' + raise ArgumentError, "something is not right." else super end @@ -48,10 +48,10 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase warning = capture(:stderr) do e = assert_raises(ActiveRecord::InvalidForeignKey) do @connection.disable_referential_integrity do - raise ActiveRecord::InvalidForeignKey, 'Should be re-raised' + raise ActiveRecord::InvalidForeignKey, "Should be re-raised" end end - assert_equal 'Should be re-raised', e.message + assert_equal "Should be re-raised", e.message end assert_match (/WARNING: Rails was not able to disable referential integrity/), warning assert_match (/cause: PG::InsufficientPrivilege/), warning @@ -63,10 +63,10 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase warning = capture(:stderr) do e = assert_raises(ActiveRecord::StatementInvalid) do @connection.disable_referential_integrity do - raise ActiveRecord::StatementInvalid, 'Should be re-raised' + raise ActiveRecord::StatementInvalid, "Should be re-raised" end end - assert_equal 'Should be re-raised', e.message + assert_equal "Should be re-raised", e.message end assert warning.blank?, "expected no warnings but got:\n#{warning}" end @@ -105,7 +105,7 @@ class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase private - def assert_transaction_is_not_broken - assert_equal 1, @connection.select_value("SELECT 1") - end + def assert_transaction_is_not_broken + assert_equal 1, @connection.select_value("SELECT 1") + end end diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb index bd64bae308..e9e7f717ac 100644 --- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb +++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb @@ -24,11 +24,11 @@ class PostgresqlRenameTableTest < ActiveRecord::PostgreSQLTestCase private - def num_indices_named(name) - @connection.execute(<<-SQL).values.length - SELECT 1 FROM "pg_index" - JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid" - WHERE "pg_class"."relname" = '#{name}' - SQL - end + def num_indices_named(name) + @connection.execute(<<-SQL).values.length + SELECT 1 FROM "pg_index" + JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid" + WHERE "pg_class"."relname" = '#{name}' + SQL + end end diff --git a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb index 285a92f60e..7193f23880 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb @@ -6,12 +6,12 @@ end class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase self.use_transactional_tests = false - TABLE_NAME = 'schema_things' + TABLE_NAME = "schema_things" COLUMNS = [ - 'id serial primary key', - 'name character varying(50)' + "id serial primary key", + "name character varying(50)" ] - USERS = ['rails_pg_schema_user1', 'rails_pg_schema_user2'] + USERS = ["rails_pg_schema_user1", "rails_pg_schema_user2"] def setup @connection = ActiveRecord::Base.connection @@ -45,7 +45,7 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase def test_session_auth= assert_raise(ActiveRecord::StatementInvalid) do - @connection.session_auth = 'DEFAULT' + @connection.session_auth = "DEFAULT" @connection.execute "SELECT * FROM #{TABLE_NAME}" end end @@ -68,7 +68,7 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase USERS.each do |u| @connection.clear_cache! set_session_auth u - assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [bind_param(1)]) + assert_equal u, @connection.select_value("SELECT name FROM #{TABLE_NAME} WHERE id = $1", "SQL", [bind_param(1)]) set_session_auth end end @@ -90,9 +90,9 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase assert_nothing_raised do USERS.each do |u| set_session_auth u - st = SchemaThing.new :name => 'TEST1' + st = SchemaThing.new name: "TEST1" st.save! - st = SchemaThing.new :id => 5, :name => 'TEST2' + st = SchemaThing.new id: 5, name: "TEST2" st.save! set_session_auth end @@ -100,17 +100,17 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase end def test_tables_in_current_schemas - assert !@connection.tables.include?(TABLE_NAME) + assert_not_includes @connection.tables, TABLE_NAME USERS.each do |u| set_session_auth u - assert @connection.tables.include?(TABLE_NAME) + assert_includes @connection.tables, TABLE_NAME set_session_auth end end private - def set_session_auth auth = nil - @connection.session_auth = auth || 'default' + def set_session_auth(auth = nil) + @connection.session_auth = auth || "default" end def bind_param(value) diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 52ef07f654..51a2306c59 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'models/default' -require 'support/schema_dumping_helper' +require "models/default" +require "support/schema_dumping_helper" module PGSchemaHelper def with_schema_search_path(schema_search_path) @@ -17,32 +17,32 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase include PGSchemaHelper self.use_transactional_tests = false - SCHEMA_NAME = 'test_schema' - SCHEMA2_NAME = 'test_schema2' - TABLE_NAME = 'things' - CAPITALIZED_TABLE_NAME = 'Things' - INDEX_A_NAME = 'a_index_things_on_name' - INDEX_B_NAME = 'b_index_things_on_different_columns_in_each_schema' - INDEX_C_NAME = 'c_index_full_text_search' - INDEX_D_NAME = 'd_index_things_on_description_desc' - INDEX_E_NAME = 'e_index_things_on_name_vector' - INDEX_A_COLUMN = 'name' - INDEX_B_COLUMN_S1 = 'email' - INDEX_B_COLUMN_S2 = 'moment' - INDEX_C_COLUMN = %q{(to_tsvector('english', coalesce(things.name, '')))} - INDEX_D_COLUMN = 'description' - INDEX_E_COLUMN = 'name_vector' + SCHEMA_NAME = "test_schema" + SCHEMA2_NAME = "test_schema2" + TABLE_NAME = "things" + CAPITALIZED_TABLE_NAME = "Things" + INDEX_A_NAME = "a_index_things_on_name" + INDEX_B_NAME = "b_index_things_on_different_columns_in_each_schema" + INDEX_C_NAME = "c_index_full_text_search" + INDEX_D_NAME = "d_index_things_on_description_desc" + INDEX_E_NAME = "e_index_things_on_name_vector" + INDEX_A_COLUMN = "name" + INDEX_B_COLUMN_S1 = "email" + INDEX_B_COLUMN_S2 = "moment" + INDEX_C_COLUMN = "(to_tsvector('english', coalesce(things.name, '')))" + INDEX_D_COLUMN = "description" + INDEX_E_COLUMN = "name_vector" COLUMNS = [ - 'id integer', - 'name character varying(50)', - 'email character varying(50)', - 'description character varying(100)', - 'name_vector tsvector', - 'moment timestamp without time zone default now()' + "id integer", + "name character varying(50)", + "email character varying(50)", + "description character varying(100)", + "name_vector tsvector", + "moment timestamp without time zone default now()" ] - PK_TABLE_NAME = 'table_with_pk' - UNMATCHED_SEQUENCE_NAME = 'unmatched_primary_key_default_value_seq' - UNMATCHED_PK_TABLE_NAME = 'table_with_unmatched_sequence_for_pk' + PK_TABLE_NAME = "table_with_pk" + UNMATCHED_SEQUENCE_NAME = "unmatched_primary_key_default_value_seq" + UNMATCHED_PK_TABLE_NAME = "table_with_unmatched_sequence_for_pk" class Thing1 < ActiveRecord::Base self.table_name = "test_schema.things" @@ -61,7 +61,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase end class Thing5 < ActiveRecord::Base - self.table_name = 'things' + self.table_name = "things" end class Song < ActiveRecord::Base @@ -130,7 +130,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase ensure @connection.drop_schema "test_schema3" end - assert !@connection.schema_names.include?("test_schema3") + assert_not_includes @connection.schema_names, "test_schema3" end def test_drop_schema_if_exists @@ -168,21 +168,21 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase def test_raise_wrapped_exception_on_bad_prepare assert_raises(ActiveRecord::StatementInvalid) do - @connection.exec_query "select * from developers where id = ?", 'sql', [bind_param(1)] + @connection.exec_query "select * from developers where id = ?", "sql", [bind_param(1)] end end if ActiveRecord::Base.connection.prepared_statements def test_schema_change_with_prepared_stmt altered = false - @connection.exec_query "select * from developers where id = $1", 'sql', [bind_param(1)] - @connection.exec_query "alter table developers add column zomg int", 'sql', [] + @connection.exec_query "select * from developers where id = $1", "sql", [bind_param(1)] + @connection.exec_query "alter table developers add column zomg int", "sql", [] altered = true - @connection.exec_query "select * from developers where id = $1", 'sql', [bind_param(1)] + @connection.exec_query "select * from developers where id = $1", "sql", [bind_param(1)] ensure # We are not using DROP COLUMN IF EXISTS because that syntax is only # supported by pg 9.X - @connection.exec_query("alter table developers drop column zomg", 'sql', []) if altered + @connection.exec_query("alter table developers drop column zomg", "sql", []) if altered end end @@ -200,7 +200,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase end def test_data_source_exists_when_not_on_schema_search_path - with_schema_search_path('PUBLIC') do + with_schema_search_path("PUBLIC") do assert(!@connection.data_source_exists?(TABLE_NAME), "data_source exists but should not be found") end end @@ -246,9 +246,9 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase end def test_proper_encoding_of_table_name - assert_equal '"table_name"', @connection.quote_table_name('table_name') + assert_equal '"table_name"', @connection.quote_table_name("table_name") assert_equal '"table.name"', @connection.quote_table_name('"table.name"') - assert_equal '"schema_name"."table_name"', @connection.quote_table_name('schema_name.table_name') + assert_equal '"schema_name"."table_name"', @connection.quote_table_name("schema_name.table_name") assert_equal '"schema_name"."table.name"', @connection.quote_table_name('schema_name."table.name"') assert_equal '"schema.name"."table_name"', @connection.quote_table_name('"schema.name".table_name') assert_equal '"schema.name"."table.name"', @connection.quote_table_name('"schema.name"."table.name"') @@ -260,25 +260,25 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase assert_equal 0, Thing3.count assert_equal 0, Thing4.count - Thing1.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + Thing1.create(id: 1, name: "thing1", email: "thing1@localhost", moment: Time.now) assert_equal 1, Thing1.count assert_equal 0, Thing2.count assert_equal 0, Thing3.count assert_equal 0, Thing4.count - Thing2.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + Thing2.create(id: 1, name: "thing1", email: "thing1@localhost", moment: Time.now) assert_equal 1, Thing1.count assert_equal 1, Thing2.count assert_equal 0, Thing3.count assert_equal 0, Thing4.count - Thing3.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + Thing3.create(id: 1, name: "thing1", email: "thing1@localhost", moment: Time.now) assert_equal 1, Thing1.count assert_equal 1, Thing2.count assert_equal 1, Thing3.count assert_equal 0, Thing4.count - Thing4.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now) + Thing4.create(id: 1, name: "thing1", email: "thing1@localhost", moment: Time.now) assert_equal 1, Thing1.count assert_equal 1, Thing2.count assert_equal 1, Thing3.count @@ -287,7 +287,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase def test_raise_on_unquoted_schema_name assert_raises(ActiveRecord::StatementInvalid) do - with_schema_search_path '$user,public' + with_schema_search_path "$user,public" end end @@ -307,7 +307,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase assert @connection.index_name_exists?(TABLE_NAME, INDEX_D_NAME, true) assert @connection.index_name_exists?(TABLE_NAME, INDEX_E_NAME, true) assert @connection.index_name_exists?(TABLE_NAME, INDEX_E_NAME, true) - assert_not @connection.index_name_exists?(TABLE_NAME, 'missing_index', true) + assert_not @connection.index_name_exists?(TABLE_NAME, "missing_index", true) end end @@ -332,7 +332,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase @connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" with_schema_search_path SCHEMA_NAME do - assert_nothing_raised { @connection.remove_index "things", name: "things_Index"} + assert_nothing_raised { @connection.remove_index "things", name: "things_Index" } end end @@ -356,13 +356,13 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase %(#{SCHEMA_NAME}."#{PK_TABLE_NAME}"), %(#{SCHEMA_NAME}.#{PK_TABLE_NAME}) ].each do |given| - assert_equal 'id', @connection.primary_key(given), "primary key should be found when table referenced as #{given}" + assert_equal "id", @connection.primary_key(given), "primary key should be found when table referenced as #{given}" end end def test_primary_key_assuming_schema_search_path with_schema_search_path(SCHEMA_NAME) do - assert_equal 'id', @connection.primary_key(PK_TABLE_NAME), "primary key should be found" + assert_equal "id", @connection.primary_key(PK_TABLE_NAME), "primary key should be found" end end @@ -381,7 +381,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}") ].each do |given| pk, seq = @connection.pk_and_sequence_for(given) - assert_equal 'id', pk, "primary key should be found when table referenced as #{given}" + assert_equal "id", pk, "primary key should be found when table referenced as #{given}" assert_equal pg_name.new(SCHEMA_NAME, "#{PK_TABLE_NAME}_id_seq"), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}") assert_equal pg_name.new(SCHEMA_NAME, UNMATCHED_SEQUENCE_NAME), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}") end @@ -389,10 +389,10 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase def test_current_schema { - %('$user',public) => 'public', + %('$user',public) => "public", SCHEMA_NAME => SCHEMA_NAME, %(#{SCHEMA2_NAME},#{SCHEMA_NAME},public) => SCHEMA2_NAME, - %(public,#{SCHEMA2_NAME},#{SCHEMA_NAME}) => 'public' + %(public,#{SCHEMA2_NAME},#{SCHEMA_NAME}) => "public" }.each do |given,expect| with_schema_search_path(given) { assert_equal expect, @connection.current_schema } end @@ -401,7 +401,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase def test_prepared_statements_with_multiple_schemas [SCHEMA_NAME, SCHEMA2_NAME].each do |schema_name| with_schema_search_path schema_name do - Thing5.create(:id => 1, :name => "thing inside #{SCHEMA_NAME}", :email => "thing1@localhost", :moment => Time.now) + Thing5.create(id: 1, name: "thing inside #{SCHEMA_NAME}", email: "thing1@localhost", moment: Time.now) end end @@ -414,10 +414,10 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase def test_schema_exists? { - 'public' => true, + "public" => true, SCHEMA_NAME => true, SCHEMA2_NAME => true, - 'darkside' => false + "darkside" => false }.each do |given,expect| assert_equal expect, @connection.schema_exists?(given) end @@ -442,7 +442,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase private def columns(table_name) @connection.send(:column_definitions, table_name).map do |name, type, default| - "#{name} #{type}" + (default ? " default #{default}" : '') + "#{name} #{type}" + (default ? " default #{default}" : "") end end diff --git a/activerecord/test/cases/adapters/postgresql/serial_test.rb b/activerecord/test/cases/adapters/postgresql/serial_test.rb index 8abe064bf1..d711b3b729 100644 --- a/activerecord/test/cases/adapters/postgresql/serial_test.rb +++ b/activerecord/test/cases/adapters/postgresql/serial_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class PostgresqlSerialTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper diff --git a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb index 5aab246c99..eb9978a898 100644 --- a/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb +++ b/activerecord/test/cases/adapters/postgresql/statement_pool_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord module ConnectionAdapters @@ -17,22 +17,22 @@ module ActiveRecord if Process.respond_to?(:fork) def test_cache_is_per_pid cache = StatementPool.new nil, 10 - cache['foo'] = 'bar' - assert_equal 'bar', cache['foo'] + cache["foo"] = "bar" + assert_equal "bar", cache["foo"] pid = fork { - lookup = cache['foo']; + lookup = cache["foo"]; exit!(!lookup) } Process.waitpid pid - assert $?.success?, 'process should exit successfully' + assert $?.success?, "process should exit successfully" end end def test_dealloc_does_not_raise_on_inactive_connection cache = StatementPool.new InactivePGconn.new, 10 - cache['foo'] = 'bar' + cache["foo"] = "bar" assert_nothing_raised { cache.clear } end end diff --git a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb index 4c4866b46b..e7c1d97d16 100644 --- a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb +++ b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/developer' -require 'models/topic' +require "cases/helper" +require "models/developer" +require "models/topic" class PostgresqlTimestampTest < ActiveRecord::PostgreSQLTestCase class PostgresqlTimestampWithZone < ActiveRecord::Base; end @@ -32,7 +32,7 @@ class PostgresqlTimestampTest < ActiveRecord::PostgreSQLTestCase with_timezone_config default: :local, aware_attributes: false do @connection.reconnect! # make sure to use a non-UTC time zone - @connection.execute("SET time zone 'America/Jamaica'", 'SCHEMA') + @connection.execute("SET time zone 'America/Jamaica'", "SCHEMA") timestamp = PostgresqlTimestampWithZone.find(1) assert_equal Time.utc(2010,1,1, 11,0,0), timestamp.time @@ -54,37 +54,37 @@ class PostgresqlTimestampFixtureTest < ActiveRecord::PostgreSQLTestCase def test_load_infinity_and_beyond d = Developer.find_by_sql("select 'infinity'::timestamp as updated_at") - assert d.first.updated_at.infinite?, 'timestamp should be infinite' + assert d.first.updated_at.infinite?, "timestamp should be infinite" d = Developer.find_by_sql("select '-infinity'::timestamp as updated_at") time = d.first.updated_at - assert time.infinite?, 'timestamp should be infinite' + assert time.infinite?, "timestamp should be infinite" assert_operator time, :<, 0 end def test_save_infinity_and_beyond - d = Developer.create!(:name => 'aaron', :updated_at => 1.0 / 0.0) + d = Developer.create!(name: "aaron", updated_at: 1.0 / 0.0) assert_equal(1.0 / 0.0, d.updated_at) - d = Developer.create!(:name => 'aaron', :updated_at => -1.0 / 0.0) + d = Developer.create!(name: "aaron", updated_at: -1.0 / 0.0) assert_equal(-1.0 / 0.0, d.updated_at) end def test_bc_timestamp date = Date.new(0) - 1.week - Developer.create!(:name => "aaron", :updated_at => date) + Developer.create!(name: "aaron", updated_at: date) assert_equal date, Developer.find_by_name("aaron").updated_at end def test_bc_timestamp_leap_year date = Time.utc(-4, 2, 29) - Developer.create!(:name => "taihou", :updated_at => date) + Developer.create!(name: "taihou", updated_at: date) assert_equal date, Developer.find_by_name("taihou").updated_at end def test_bc_timestamp_year_zero date = Time.utc(0, 4, 7) - Developer.create!(:name => "yahagi", :updated_at => date) + Developer.create!(name: "yahagi", updated_at: date) assert_equal date, Developer.find_by_name("yahagi").updated_at end end diff --git a/activerecord/test/cases/adapters/postgresql/transaction_test.rb b/activerecord/test/cases/adapters/postgresql/transaction_test.rb index e76705a802..c450524de8 100644 --- a/activerecord/test/cases/adapters/postgresql/transaction_test.rb +++ b/activerecord/test/cases/adapters/postgresql/transaction_test.rb @@ -1,21 +1,22 @@ require "cases/helper" -require 'support/connection_helper' +require "support/connection_helper" +require "concurrent/atomic/cyclic_barrier" module ActiveRecord class PostgresqlTransactionTest < ActiveRecord::PostgreSQLTestCase self.use_transactional_tests = false class Sample < ActiveRecord::Base - self.table_name = 'samples' + self.table_name = "samples" end setup do @connection = ActiveRecord::Base.connection @connection.transaction do - @connection.drop_table 'samples', if_exists: true - @connection.create_table('samples') do |t| - t.integer 'value' + @connection.drop_table "samples", if_exists: true + @connection.create_table("samples") do |t| + t.integer "value" end end @@ -23,50 +24,75 @@ module ActiveRecord end teardown do - @connection.drop_table 'samples', if_exists: true + @connection.drop_table "samples", if_exists: true end - test "raises error when a serialization failure occurs" do - with_warning_suppression do - assert_raises(ActiveRecord::TransactionSerializationError) do - thread = Thread.new do - Sample.transaction isolation: :serializable do - Sample.delete_all + test "raises SerializationFailure when a serialization failure occurs" do + assert_raises(ActiveRecord::SerializationFailure) do + before = Concurrent::CyclicBarrier.new(2) + after = Concurrent::CyclicBarrier.new(2) - 10.times do |i| - sleep 0.1 - - Sample.create value: i - end + thread = Thread.new do + with_warning_suppression do + Sample.transaction isolation: :serializable do + before.wait + Sample.create value: Sample.sum(:value) + after.wait end end + end - sleep 0.1 + begin + with_warning_suppression do + Sample.transaction isolation: :serializable do + before.wait + Sample.create value: Sample.sum(:value) + after.wait + end + end + ensure + thread.join + end + end + end - Sample.transaction isolation: :serializable do - Sample.delete_all + test "raises Deadlocked when a deadlock is encountered" do + with_warning_suppression do + assert_raises(ActiveRecord::Deadlocked) do + barrier = Concurrent::CyclicBarrier.new(2) - 10.times do |i| - sleep 0.1 + s1 = Sample.create value: 1 + s2 = Sample.create value: 2 - Sample.create value: i + thread = Thread.new do + Sample.transaction do + s1.lock! + barrier.wait + s2.update_attributes value: 1 end - - sleep 1 end - thread.join + begin + Sample.transaction do + s2.lock! + barrier.wait + s1.update_attributes value: 2 + end + ensure + thread.join + end end end end protected - def with_warning_suppression - log_level = @connection.client_min_messages - @connection.client_min_messages = 'error' - yield - @connection.client_min_messages = log_level - end + def with_warning_suppression + log_level = ActiveRecord::Base.connection.client_min_messages + ActiveRecord::Base.connection.client_min_messages = "error" + yield + ensure + ActiveRecord::Base.connection.client_min_messages = log_level + end end end diff --git a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb index ea0f0b8fa5..bd45a9daa0 100644 --- a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb +++ b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" class PostgresqlTypeLookupTest < ActiveRecord::PostgreSQLTestCase setup do @@ -9,8 +9,8 @@ class PostgresqlTypeLookupTest < ActiveRecord::PostgreSQLTestCase box_array = @connection.type_map.lookup(1020) int_array = @connection.type_map.lookup(1007) - assert_equal ';', box_array.delimiter - assert_equal ',', int_array.delimiter + assert_equal ";", box_array.delimiter + assert_equal ",", int_array.delimiter end test "array types correctly respect registration of subtypes" do diff --git a/activerecord/test/cases/adapters/postgresql/utils_test.rb b/activerecord/test/cases/adapters/postgresql/utils_test.rb index 095c1826e5..01c597beae 100644 --- a/activerecord/test/cases/adapters/postgresql/utils_test.rb +++ b/activerecord/test/cases/adapters/postgresql/utils_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'active_record/connection_adapters/postgresql/utils' +require "cases/helper" +require "active_record/connection_adapters/postgresql/utils" class PostgreSQLUtilsTest < ActiveRecord::PostgreSQLTestCase Name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name @@ -7,14 +7,14 @@ class PostgreSQLUtilsTest < ActiveRecord::PostgreSQLTestCase def test_extract_schema_qualified_name { - %(table_name) => [nil,'table_name'], - %("table.name") => [nil,'table.name'], + %(table_name) => [nil,"table_name"], + %("table.name") => [nil,"table.name"], %(schema.table_name) => %w{schema table_name}, %("schema".table_name) => %w{schema table_name}, %(schema."table_name") => %w{schema table_name}, %("schema"."table_name") => %w{schema table_name}, - %("even spaces".table) => ['even spaces','table'], - %(schema."table.name") => ['schema', 'table.name'] + %("even spaces".table) => ["even spaces","table"], + %(schema."table.name") => ["schema", "table.name"] }.each do |given, expect| assert_equal Name.new(*expect), extract_schema_qualified_name(given) end @@ -54,7 +54,7 @@ class PostgreSQLNameTest < ActiveRecord::PostgreSQLTestCase end test "can be used as hash key" do - hash = {Name.new("schema", "article_seq") => "success"} + hash = { Name.new("schema", "article_seq") => "success" } assert_equal "success", hash[Name.new("schema", "article_seq")] assert_equal nil, hash[Name.new("schema", "articles")] assert_equal nil, hash[Name.new("public", "article_seq")] diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index 7628075ad2..9a59691737 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" module PostgresqlUUIDHelper def connection @@ -20,10 +20,10 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase end setup do - enable_extension!('uuid-ossp', connection) + enable_extension!("uuid-ossp", connection) connection.create_table "uuid_data_type" do |t| - t.uuid 'guid' + t.uuid "guid" end end @@ -34,13 +34,13 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase def test_change_column_default @connection.add_column :uuid_data_type, :thingy, :uuid, null: false, default: "uuid_generate_v1()" UUIDType.reset_column_information - column = UUIDType.columns_hash['thingy'] + column = UUIDType.columns_hash["thingy"] assert_equal "uuid_generate_v1()", column.default_function @connection.change_column :uuid_data_type, :thingy, :uuid, null: false, default: "uuid_generate_v4()" UUIDType.reset_column_information - column = UUIDType.columns_hash['thingy'] + column = UUIDType.columns_hash["thingy"] assert_equal "uuid_generate_v4()", column.default_function ensure UUIDType.reset_column_information @@ -57,46 +57,46 @@ class PostgresqlUUIDTest < ActiveRecord::PostgreSQLTestCase end def test_treat_blank_uuid_as_nil - UUIDType.create! guid: '' + UUIDType.create! guid: "" assert_equal(nil, UUIDType.last.guid) end def test_treat_invalid_uuid_as_nil - uuid = UUIDType.create! guid: 'foobar' + uuid = UUIDType.create! guid: "foobar" assert_equal(nil, uuid.guid) end def test_invalid_uuid_dont_modify_before_type_cast - uuid = UUIDType.new guid: 'foobar' - assert_equal 'foobar', uuid.guid_before_type_cast + uuid = UUIDType.new guid: "foobar" + assert_equal "foobar", uuid.guid_before_type_cast end def test_acceptable_uuid_regex # Valid uuids - ['A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11', - '{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}', - 'a0eebc999c0b4ef8bb6d6bb9bd380a11', - 'a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11', - '{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}', + ["A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11", + "{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}", + "a0eebc999c0b4ef8bb6d6bb9bd380a11", + "a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11", + "{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}", # The following is not a valid RFC 4122 UUID, but PG doesn't seem to care, # so we shouldn't block it either. (Pay attention to "fb6d" – the "f" here # is invalid – it must be one of 8, 9, A, B, a, b according to the spec.) - '{a0eebc99-9c0b-4ef8-fb6d-6bb9bd380a11}', + "{a0eebc99-9c0b-4ef8-fb6d-6bb9bd380a11}", ].each do |valid_uuid| uuid = UUIDType.new guid: valid_uuid assert_not_nil uuid.guid end # Invalid uuids - [['A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'], + [["A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11"], Hash.new, 0, 0.0, true, - 'Z0000C99-9C0B-4EF8-BB6D-6BB9BD380A11', - 'a0eebc999r0b4ef8ab6d6bb9bd380a11', - 'a0ee-bc99------4ef8-bb6d-6bb9-bd38-0a11', - '{a0eebc99-bb6d6bb9-bd380a11}'].each do |invalid_uuid| + "Z0000C99-9C0B-4EF8-BB6D-6BB9BD380A11", + "a0eebc999r0b4ef8ab6d6bb9bd380a11", + "a0ee-bc99------4ef8-bb6d-6bb9-bd38-0a11", + "{a0eebc99-bb6d6bb9-bd380a11}"].each do |invalid_uuid| uuid = UUIDType.new guid: invalid_uuid assert_nil uuid.guid end @@ -142,13 +142,13 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper class UUID < ActiveRecord::Base - self.table_name = 'pg_uuids' + self.table_name = "pg_uuids" end setup do - connection.create_table('pg_uuids', id: :uuid, default: 'uuid_generate_v1()') do |t| - t.string 'name' - t.uuid 'other_uuid', default: 'uuid_generate_v4()' + connection.create_table("pg_uuids", id: :uuid, default: "uuid_generate_v1()") do |t| + t.string "name" + t.uuid "other_uuid", default: "uuid_generate_v4()" end # Create custom PostgreSQL function to generate UUIDs @@ -160,21 +160,21 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase SQL # Create such a table with custom function as default value generator - connection.create_table('pg_uuids_2', id: :uuid, default: 'my_uuid_generator()') do |t| - t.string 'name' - t.uuid 'other_uuid_2', default: 'my_uuid_generator()' + connection.create_table("pg_uuids_2", id: :uuid, default: "my_uuid_generator()") do |t| + t.string "name" + t.uuid "other_uuid_2", default: "my_uuid_generator()" end end teardown do drop_table "pg_uuids" - drop_table 'pg_uuids_2' - connection.execute 'DROP FUNCTION IF EXISTS my_uuid_generator();' + drop_table "pg_uuids_2" + connection.execute "DROP FUNCTION IF EXISTS my_uuid_generator();" end if ActiveRecord::Base.connection.supports_extensions? def test_id_is_uuid - assert_equal :uuid, UUID.columns_hash['id'].type + assert_equal :uuid, UUID.columns_hash["id"].type assert UUID.primary_key end @@ -190,21 +190,21 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::PostgreSQLTestCase end def test_pk_and_sequence_for_uuid_primary_key - pk, seq = connection.pk_and_sequence_for('pg_uuids') - assert_equal 'id', pk + pk, seq = connection.pk_and_sequence_for("pg_uuids") + assert_equal "id", pk assert_equal nil, seq end def test_schema_dumper_for_uuid_primary_key schema = dump_table_schema "pg_uuids" assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: -> { "uuid_generate_v1\(\)" }/, schema) - assert_match(/t\.uuid "other_uuid", default: -> { "uuid_generate_v4\(\)" }/, schema) + assert_match(/t\.uuid "other_uuid", default: -> { "uuid_generate_v4\(\)" }/, schema) end def test_schema_dumper_for_uuid_primary_key_with_custom_default schema = dump_table_schema "pg_uuids_2" assert_match(/\bcreate_table "pg_uuids_2", id: :uuid, default: -> { "my_uuid_generator\(\)" }/, schema) - assert_match(/t\.uuid "other_uuid_2", default: -> { "my_uuid_generator\(\)" }/, schema) + assert_match(/t\.uuid "other_uuid_2", default: -> { "my_uuid_generator\(\)" }/, schema) end end end @@ -214,9 +214,9 @@ class PostgresqlUUIDTestNilDefault < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper setup do - connection.create_table('pg_uuids', id: false) do |t| + connection.create_table("pg_uuids", id: false) do |t| t.primary_key :id, :uuid, default: nil - t.string 'name' + t.string "name" end end @@ -244,30 +244,30 @@ class PostgresqlUUIDTestInverseOf < ActiveRecord::PostgreSQLTestCase include PostgresqlUUIDHelper class UuidPost < ActiveRecord::Base - self.table_name = 'pg_uuid_posts' + self.table_name = "pg_uuid_posts" has_many :uuid_comments, inverse_of: :uuid_post end class UuidComment < ActiveRecord::Base - self.table_name = 'pg_uuid_comments' + self.table_name = "pg_uuid_comments" belongs_to :uuid_post end setup do connection.transaction do - connection.create_table('pg_uuid_posts', id: :uuid) do |t| - t.string 'title' + connection.create_table("pg_uuid_posts", id: :uuid) do |t| + t.string "title" end - connection.create_table('pg_uuid_comments', id: :uuid) do |t| + connection.create_table("pg_uuid_comments", id: :uuid) do |t| t.references :uuid_post, type: :uuid - t.string 'content' + t.string "content" end end end teardown do - drop_table "pg_uuid_comments" - drop_table "pg_uuid_posts" + drop_table "pg_uuid_comments" + drop_table "pg_uuid_posts" end if ActiveRecord::Base.connection.supports_extensions? @@ -290,5 +290,4 @@ class PostgresqlUUIDTestInverseOf < ActiveRecord::PostgreSQLTestCase assert_nil UuidPost.find_by(id: 789) end end - end diff --git a/activerecord/test/cases/adapters/postgresql/xml_test.rb b/activerecord/test/cases/adapters/postgresql/xml_test.rb index add32699fa..826b384fb3 100644 --- a/activerecord/test/cases/adapters/postgresql/xml_test.rb +++ b/activerecord/test/cases/adapters/postgresql/xml_test.rb @@ -1,28 +1,28 @@ -require 'cases/helper' -require 'support/schema_dumping_helper' +require "cases/helper" +require "support/schema_dumping_helper" class PostgresqlXMLTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper class XmlDataType < ActiveRecord::Base - self.table_name = 'xml_data_type' + self.table_name = "xml_data_type" end def setup @connection = ActiveRecord::Base.connection begin @connection.transaction do - @connection.create_table('xml_data_type') do |t| - t.xml 'payload' + @connection.create_table("xml_data_type") do |t| + t.xml "payload" end end rescue ActiveRecord::StatementInvalid skip "do not test on PG without xml" end - @column = XmlDataType.columns_hash['payload'] + @column = XmlDataType.columns_hash["payload"] end teardown do - @connection.drop_table 'xml_data_type', if_exists: true + @connection.drop_table "xml_data_type", if_exists: true end def test_column @@ -30,7 +30,7 @@ class PostgresqlXMLTest < ActiveRecord::PostgreSQLTestCase end def test_null_xml - @connection.execute %q|insert into xml_data_type (payload) VALUES(null)| + @connection.execute "insert into xml_data_type (payload) VALUES(null)" assert_nil XmlDataType.first.payload end diff --git a/activerecord/test/cases/adapters/sqlite3/collation_test.rb b/activerecord/test/cases/adapters/sqlite3/collation_test.rb index 58a9469ce5..28e8f12c18 100644 --- a/activerecord/test/cases/adapters/sqlite3/collation_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/collation_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class SQLite3CollationTest < ActiveRecord::SQLite3TestCase include SchemaDumpingHelper @@ -7,8 +7,8 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase def setup @connection = ActiveRecord::Base.connection @connection.create_table :collation_table_sqlite3, force: true do |t| - t.string :string_nocase, collation: 'NOCASE' - t.text :text_rtrim, collation: 'RTRIM' + t.string :string_nocase, collation: "NOCASE" + t.text :text_rtrim, collation: "RTRIM" end end @@ -17,32 +17,32 @@ class SQLite3CollationTest < ActiveRecord::SQLite3TestCase end test "string column with collation" do - column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == 'string_nocase' } + column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "string_nocase" } assert_equal :string, column.type - assert_equal 'NOCASE', column.collation + assert_equal "NOCASE", column.collation end test "text column with collation" do - column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == 'text_rtrim' } + column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "text_rtrim" } assert_equal :text, column.type - assert_equal 'RTRIM', column.collation + assert_equal "RTRIM", column.collation end test "add column with collation" do - @connection.add_column :collation_table_sqlite3, :title, :string, collation: 'RTRIM' + @connection.add_column :collation_table_sqlite3, :title, :string, collation: "RTRIM" - column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == 'title' } + column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "title" } assert_equal :string, column.type - assert_equal 'RTRIM', column.collation + assert_equal "RTRIM", column.collation end test "change column with collation" do @connection.add_column :collation_table_sqlite3, :description, :string - @connection.change_column :collation_table_sqlite3, :description, :text, collation: 'RTRIM' + @connection.change_column :collation_table_sqlite3, :description, :text, collation: "RTRIM" - column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == 'description' } + column = @connection.columns(:collation_table_sqlite3).find { |c| c.name == "description" } assert_equal :text, column.type - assert_equal 'RTRIM', column.collation + assert_equal "RTRIM", column.collation end test "schema dump includes collation" do diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb index 34e3b2e023..8342b05870 100644 --- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb @@ -10,8 +10,8 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase end end - def test_copy_table(from = 'customers', to = 'customers2', options = {}) - assert_nothing_raised {copy_table(from, to, options)} + def test_copy_table(from = "customers", to = "customers2", options = {}) + assert_nothing_raised { copy_table(from, to, options) } assert_equal row_count(from), row_count(to) if block_given? @@ -24,39 +24,39 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase end def test_copy_table_renaming_column - test_copy_table('customers', 'customers2', - :rename => {'name' => 'person_name'}) do |from, to, options| - expected = column_values(from, 'name') - assert_equal expected, column_values(to, 'person_name') + test_copy_table("customers", "customers2", + rename: { "name" => "person_name" }) do |from, to, options| + expected = column_values(from, "name") + assert_equal expected, column_values(to, "person_name") assert expected.any?, "No values in table: #{expected.inspect}" end end def test_copy_table_allows_to_pass_options_to_create_table - @connection.create_table('blocker_table') - test_copy_table('customers', 'blocker_table', force: true) + @connection.create_table("blocker_table") + test_copy_table("customers", "blocker_table", force: true) end def test_copy_table_with_index - test_copy_table('comments', 'comments_with_index') do - @connection.add_index('comments_with_index', ['post_id', 'type']) - test_copy_table('comments_with_index', 'comments_with_index2') do - assert_equal table_indexes_without_name('comments_with_index'), - table_indexes_without_name('comments_with_index2') + test_copy_table("comments", "comments_with_index") do + @connection.add_index("comments_with_index", ["post_id", "type"]) + test_copy_table("comments_with_index", "comments_with_index2") do + assert_equal table_indexes_without_name("comments_with_index"), + table_indexes_without_name("comments_with_index2") end end end def test_copy_table_without_primary_key - test_copy_table('developers_projects', 'programmers_projects') do - assert_nil @connection.primary_key('programmers_projects') + test_copy_table("developers_projects", "programmers_projects") do + assert_nil @connection.primary_key("programmers_projects") end end def test_copy_table_with_id_col_that_is_not_primary_key - test_copy_table('goofy_string_id', 'goofy_string_id2') do - original_id = @connection.columns('goofy_string_id').detect{|col| col.name == 'id' } - copied_id = @connection.columns('goofy_string_id2').detect{|col| col.name == 'id' } + test_copy_table("goofy_string_id", "goofy_string_id2") do + original_id = @connection.columns("goofy_string_id").detect { |col| col.name == "id" } + copied_id = @connection.columns("goofy_string_id2").detect { |col| col.name == "id" } assert_equal original_id.type, copied_id.type assert_equal original_id.sql_type, copied_id.sql_type assert_equal original_id.limit, copied_id.limit @@ -64,28 +64,28 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase end def test_copy_table_with_unconventional_primary_key - test_copy_table('owners', 'owners_unconventional') do - original_pk = @connection.primary_key('owners') - copied_pk = @connection.primary_key('owners_unconventional') + test_copy_table("owners", "owners_unconventional") do + original_pk = @connection.primary_key("owners") + copied_pk = @connection.primary_key("owners_unconventional") assert_equal original_pk, copied_pk end end def test_copy_table_with_binary_column - test_copy_table 'binaries', 'binaries2' + test_copy_table "binaries", "binaries2" end protected def copy_table(from, to, options = {}) - @connection.copy_table(from, to, {:temporary => true}.merge(options)) + @connection.copy_table(from, to, { temporary: true }.merge(options)) end def column_names(table) - @connection.table_structure(table).map {|column| column['name']} + @connection.table_structure(table).map { |column| column["name"] } end def column_values(table, column) - @connection.select_all("SELECT #{column} FROM #{table} ORDER BY id").map {|row| row[column]} + @connection.select_all("SELECT #{column} FROM #{table} ORDER BY id").map { |row| row[column] } end def table_indexes_without_name(table) @@ -93,6 +93,6 @@ protected end def row_count(table) - @connection.select_one("SELECT COUNT(*) AS count FROM #{table}")['count'] + @connection.select_one("SELECT COUNT(*) AS count FROM #{table}")["count"] end end diff --git a/activerecord/test/cases/adapters/sqlite3/explain_test.rb b/activerecord/test/cases/adapters/sqlite3/explain_test.rb index a1a6e5f16a..128acb79cf 100644 --- a/activerecord/test/cases/adapters/sqlite3/explain_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/explain_test.rb @@ -1,19 +1,19 @@ require "cases/helper" -require 'models/developer' -require 'models/computer' +require "models/developer" +require "models/computer" class SQLite3ExplainTest < ActiveRecord::SQLite3TestCase fixtures :developers def test_explain_for_one_query explain = Developer.where(id: 1).explain - assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\?|1)), explain + assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\? \[\["id", 1\]\]|1)), explain assert_match(/(SEARCH )?TABLE developers USING (INTEGER )?PRIMARY KEY/, explain) end def test_explain_with_eager_loading explain = Developer.where(id: 1).includes(:audit_logs).explain - assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\?|1)), explain + assert_match %r(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = (?:\? \[\["id", 1\]\]|1)), explain assert_match(/(SEARCH )?TABLE developers USING (INTEGER )?PRIMARY KEY/, explain) assert_match %(EXPLAIN for: SELECT "audit_logs".* FROM "audit_logs" WHERE "audit_logs"."developer_id" = 1), explain assert_match(/(SCAN )?TABLE audit_logs/, explain) diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb index fe2425b845..80a37e83ff 100644 --- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb @@ -1,7 +1,7 @@ require "cases/helper" -require 'bigdecimal' -require 'yaml' -require 'securerandom' +require "bigdecimal" +require "yaml" +require "securerandom" class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase def setup @@ -16,7 +16,7 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase end def test_type_cast_symbol - assert_equal 'foo', @conn.type_cast(:foo) + assert_equal "foo", @conn.type_cast(:foo) end def test_type_cast_date @@ -41,15 +41,15 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase end def test_type_cast_true - assert_equal 't', @conn.type_cast(true) + assert_equal "t", @conn.type_cast(true) end def test_type_cast_false - assert_equal 'f', @conn.type_cast(false) + assert_equal "f", @conn.type_cast(false) end def test_type_cast_bigdecimal - bd = BigDecimal.new '10.0' + bd = BigDecimal.new "10.0" assert_equal bd.to_f, @conn.type_cast(bd) end @@ -79,7 +79,7 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase end def test_quoting_binary_strings - value = "hello".encode('ascii-8bit') + value = "hello".encode("ascii-8bit") type = ActiveRecord::Type::String.new assert_equal "'hello'", @conn.quote(type.serialize(value)) diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index bbc9f978bf..66f9349111 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -1,7 +1,7 @@ require "cases/helper" -require 'models/owner' -require 'tempfile' -require 'support/ddl_helper' +require "models/owner" +require "tempfile" +require "support/ddl_helper" module ActiveRecord module ConnectionAdapters @@ -14,22 +14,22 @@ module ActiveRecord end def setup - @conn = Base.sqlite3_connection database: ':memory:', - adapter: 'sqlite3', + @conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", timeout: 100 end def test_bad_connection assert_raise ActiveRecord::NoDatabaseError do connection = ActiveRecord::Base.sqlite3_connection(adapter: "sqlite3", database: "/tmp/should/_not/_exist/-cinco-dog.db") - connection.drop_table 'ex', if_exists: true + connection.drop_table "ex", if_exists: true end end unless in_memory_db? def test_connect_with_url original_connection = ActiveRecord::Base.remove_connection - tf = Tempfile.open 'whatever' + tf = Tempfile.open "whatever" url = "sqlite3:#{tf.path}" ActiveRecord::Base.establish_connection(url) assert ActiveRecord::Base.connection @@ -51,7 +51,7 @@ module ActiveRecord def test_valid_column with_example_table do - column = @conn.columns('ex').find { |col| col.name == 'id' } + column = @conn.columns("ex").find { |col| col.name == "id" } assert @conn.valid_type?(column.type) end end @@ -66,9 +66,9 @@ module ActiveRecord end def test_column_types - owner = Owner.create!(name: "hello".encode('ascii-8bit')) + owner = Owner.create!(name: "hello".encode("ascii-8bit")) owner.reload - select = Owner.columns.map { |c| "typeof(#{c.name})" }.join ', ' + select = Owner.columns.map { |c| "typeof(#{c.name})" }.join ", " result = Owner.connection.exec_query <<-esql SELECT #{select} FROM #{Owner.table_name} @@ -83,10 +83,10 @@ module ActiveRecord def test_exec_insert with_example_table do vals = [Relation::QueryAttribute.new("number", 10, Type::Value.new)] - @conn.exec_insert('insert into ex (number) VALUES (?)', 'SQL', vals) + @conn.exec_insert("insert into ex (number) VALUES (?)", "SQL", vals) result = @conn.exec_query( - 'select number from ex where number = ?', 'SQL', vals) + "select number from ex where number = ?", "SQL", vals) assert_equal 1, result.rows.length assert_equal 10, result.rows.first.first @@ -94,8 +94,8 @@ module ActiveRecord end def test_primary_key_returns_nil_for_no_pk - with_example_table 'id int, data string' do - assert_nil @conn.primary_key('ex') + with_example_table "id int, data string" do + assert_nil @conn.primary_key("ex") end end @@ -107,69 +107,69 @@ module ActiveRecord def test_bad_timeout assert_raises(TypeError) do - Base.sqlite3_connection database: ':memory:', - adapter: 'sqlite3', - timeout: 'usa' + Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", + timeout: "usa" end end # connection is OK with a nil timeout def test_nil_timeout - conn = Base.sqlite3_connection database: ':memory:', - adapter: 'sqlite3', + conn = Base.sqlite3_connection database: ":memory:", + adapter: "sqlite3", timeout: nil - assert conn, 'made a connection' + assert conn, "made a connection" end def test_connect - assert @conn, 'should have connection' + assert @conn, "should have connection" end # sqlite3 defaults to UTF-8 encoding def test_encoding - assert_equal 'UTF-8', @conn.encoding + assert_equal "UTF-8", @conn.encoding end def test_exec_no_binds - with_example_table 'id int, data string' do - result = @conn.exec_query('SELECT id, data FROM ex') + with_example_table "id int, data string" do + result = @conn.exec_query("SELECT id, data FROM ex") assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @conn.exec_query('SELECT id, data FROM ex') + result = @conn.exec_query("SELECT id, data FROM ex") assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, "foo"]], result.rows end end def test_exec_query_with_binds - with_example_table 'id int, data string' do + with_example_table "id int, data string" do @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') result = @conn.exec_query( - 'SELECT id, data FROM ex WHERE id = ?', nil, [Relation::QueryAttribute.new(nil, 1, Type::Value.new)]) + "SELECT id, data FROM ex WHERE id = ?", nil, [Relation::QueryAttribute.new(nil, 1, Type::Value.new)]) assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, "foo"]], result.rows end end def test_exec_query_typecasts_bind_vals - with_example_table 'id int, data string' do + with_example_table "id int, data string" do @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') result = @conn.exec_query( - 'SELECT id, data FROM ex WHERE id = ?', nil, [Relation::QueryAttribute.new("id", "1-fuu", Type::Integer.new)]) + "SELECT id, data FROM ex WHERE id = ?", nil, [Relation::QueryAttribute.new("id", "1-fuu", Type::Integer.new)]) assert_equal 1, result.rows.length assert_equal 2, result.columns.length - assert_equal [[1, 'foo']], result.rows + assert_equal [[1, "foo"]], result.rows end end @@ -182,15 +182,15 @@ module ActiveRecord ) eosql str = "\x80".force_encoding("ASCII-8BIT") - binary = DualEncoding.new name: 'ã„ãŸã ãã¾ã™ï¼', data: str + binary = DualEncoding.new name: "ã„ãŸã ãã¾ã™ï¼", data: str binary.save! assert_equal str, binary.data ensure - DualEncoding.connection.drop_table 'dual_encodings', if_exists: true + DualEncoding.connection.drop_table "dual_encodings", if_exists: true end def test_type_cast_should_not_mutate_encoding - name = 'hello'.force_encoding(Encoding::ASCII_8BIT) + name = "hello".force_encoding(Encoding::ASCII_8BIT) Owner.create(name: name) assert_equal Encoding::ASCII_8BIT, name.encoding ensure @@ -204,8 +204,8 @@ module ActiveRecord assert_equal 1, records.length record = records.first - assert_equal 10, record['number'] - assert_equal 1, record['id'] + assert_equal 10, record["number"] + assert_equal 1, record["id"] end end @@ -226,7 +226,7 @@ module ActiveRecord def test_insert_id_value_returned with_example_table do sql = "INSERT INTO ex (number) VALUES (10)" - idval = 'vuvuzela' + idval = "vuvuzela" id = @conn.insert(sql, nil, nil, idval) assert_equal idval, id end @@ -237,7 +237,7 @@ module ActiveRecord 2.times do |i| @conn.create "INSERT INTO ex (number) VALUES (#{i})" end - rows = @conn.select_rows 'select number, id from ex' + rows = @conn.select_rows "select number, id from ex" assert_equal [[0, 1], [1, 2]], rows end end @@ -254,7 +254,7 @@ module ActiveRecord def test_transaction with_example_table do - count_sql = 'select count(*) from ex' + count_sql = "select count(*) from ex" @conn.begin_db_transaction @conn.create "INSERT INTO ex (number) VALUES (10)" @@ -268,7 +268,7 @@ module ActiveRecord def test_tables with_example_table do ActiveSupport::Deprecation.silence { assert_equal %w{ ex }, @conn.tables } - with_example_table 'id integer PRIMARY KEY AUTOINCREMENT, number integer', 'people' do + with_example_table "id integer PRIMARY KEY AUTOINCREMENT, number integer", "people" do ActiveSupport::Deprecation.silence { assert_equal %w{ ex people }.sort, @conn.tables.sort } end end @@ -279,17 +279,17 @@ module ActiveRecord SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence' SQL - assert_logged [[sql.squish, 'SCHEMA', []]] do + assert_logged [[sql.squish, "SCHEMA", []]] do ActiveSupport::Deprecation.silence do - @conn.tables('hello') + @conn.tables("hello") end end end def test_indexes_logs_name with_example_table do - assert_logged [["PRAGMA index_list(\"ex\")", 'SCHEMA', []]] do - @conn.indexes('ex', 'hello') + assert_logged [["PRAGMA index_list(\"ex\")", "SCHEMA", []]] do + @conn.indexes("ex", "hello") end end end @@ -300,9 +300,9 @@ module ActiveRecord SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence' AND name = 'ex' SQL - assert_logged [[sql.squish, 'SCHEMA', []]] do + assert_logged [[sql.squish, "SCHEMA", []]] do ActiveSupport::Deprecation.silence do - assert @conn.table_exists?('ex') + assert @conn.table_exists?("ex") end end end @@ -310,7 +310,7 @@ module ActiveRecord def test_columns with_example_table do - columns = @conn.columns('ex').sort_by(&:name) + columns = @conn.columns("ex").sort_by(&:name) assert_equal 2, columns.length assert_equal %w{ id number }.sort, columns.map(&:name) assert_equal [nil, nil], columns.map(&:default) @@ -319,17 +319,17 @@ module ActiveRecord end def test_columns_with_default - with_example_table 'id integer PRIMARY KEY AUTOINCREMENT, number integer default 10' do - column = @conn.columns('ex').find { |x| - x.name == 'number' + with_example_table "id integer PRIMARY KEY AUTOINCREMENT, number integer default 10" do + column = @conn.columns("ex").find { |x| + x.name == "number" } - assert_equal '10', column.default + assert_equal "10", column.default end end def test_columns_with_not_null - with_example_table 'id integer PRIMARY KEY AUTOINCREMENT, number integer not null' do - column = @conn.columns('ex').find { |x| x.name == 'number' } + with_example_table "id integer PRIMARY KEY AUTOINCREMENT, number integer not null" do + column = @conn.columns("ex").find { |x| x.name == "number" } assert_not column.null, "column should not be null" end end @@ -337,59 +337,59 @@ module ActiveRecord def test_indexes_logs with_example_table do assert_logged [["PRAGMA index_list(\"ex\")", "SCHEMA", []]] do - @conn.indexes('ex') + @conn.indexes("ex") end end end def test_no_indexes - assert_equal [], @conn.indexes('items') + assert_equal [], @conn.indexes("items") end def test_index with_example_table do - @conn.add_index 'ex', 'id', unique: true, name: 'fun' - index = @conn.indexes('ex').find { |idx| idx.name == 'fun' } + @conn.add_index "ex", "id", unique: true, name: "fun" + index = @conn.indexes("ex").find { |idx| idx.name == "fun" } - assert_equal 'ex', index.table - assert index.unique, 'index is unique' - assert_equal ['id'], index.columns + assert_equal "ex", index.table + assert index.unique, "index is unique" + assert_equal ["id"], index.columns end end def test_non_unique_index with_example_table do - @conn.add_index 'ex', 'id', name: 'fun' - index = @conn.indexes('ex').find { |idx| idx.name == 'fun' } - assert_not index.unique, 'index is not unique' + @conn.add_index "ex", "id", name: "fun" + index = @conn.indexes("ex").find { |idx| idx.name == "fun" } + assert_not index.unique, "index is not unique" end end def test_compound_index with_example_table do - @conn.add_index 'ex', %w{ id number }, name: 'fun' - index = @conn.indexes('ex').find { |idx| idx.name == 'fun' } + @conn.add_index "ex", %w{ id number }, name: "fun" + index = @conn.indexes("ex").find { |idx| idx.name == "fun" } assert_equal %w{ id number }.sort, index.columns.sort end end def test_primary_key with_example_table do - assert_equal 'id', @conn.primary_key('ex') - with_example_table 'internet integer PRIMARY KEY AUTOINCREMENT, number integer not null', 'foos' do - assert_equal 'internet', @conn.primary_key('foos') + assert_equal "id", @conn.primary_key("ex") + with_example_table "internet integer PRIMARY KEY AUTOINCREMENT, number integer not null", "foos" do + assert_equal "internet", @conn.primary_key("foos") end end end def test_no_primary_key - with_example_table 'number integer not null' do - assert_nil @conn.primary_key('ex') + with_example_table "number integer not null" do + assert_nil @conn.primary_key("ex") end end def test_supports_extensions - assert_not @conn.supports_extensions?, 'does not support extensions' + assert_not @conn.supports_extensions?, "does not support extensions" end def test_respond_to_enable_extension @@ -402,15 +402,15 @@ module ActiveRecord def test_statement_closed db = ::SQLite3::Database.new(ActiveRecord::Base. - configurations['arunit']['database']) + configurations["arunit"]["database"]) statement = ::SQLite3::Statement.new(db, - 'CREATE TABLE statement_test (number integer not null)') - statement.stub(:step, ->{ raise ::SQLite3::BusyException.new('busy') }) do + "CREATE TABLE statement_test (number integer not null)") + statement.stub(:step, -> { raise ::SQLite3::BusyException.new("busy") }) do assert_called(statement, :columns, returns: []) do assert_called(statement, :close) do ::SQLite3::Statement.stub(:new, statement) do assert_raises ActiveRecord::StatementInvalid do - @conn.exec_query 'select * from statement_test' + @conn.exec_query "select * from statement_test" end end end @@ -420,22 +420,22 @@ module ActiveRecord private - def assert_logged logs - subscriber = SQLSubscriber.new - subscription = ActiveSupport::Notifications.subscribe('sql.active_record', subscriber) - yield - assert_equal logs, subscriber.logged - ensure - ActiveSupport::Notifications.unsubscribe(subscription) - end + def assert_logged(logs) + subscriber = SQLSubscriber.new + subscription = ActiveSupport::Notifications.subscribe("sql.active_record", subscriber) + yield + assert_equal logs, subscriber.logged + ensure + ActiveSupport::Notifications.unsubscribe(subscription) + end - def with_example_table(definition = nil, table_name = 'ex', &block) - definition ||= <<-SQL - id integer PRIMARY KEY AUTOINCREMENT, - number integer - SQL - super(@conn, table_name, definition, &block) - end + def with_example_table(definition = nil, table_name = "ex", &block) + definition ||= <<-SQL + id integer PRIMARY KEY AUTOINCREMENT, + number integer + SQL + super(@conn, table_name, definition, &block) + end end end end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb index 9b675b804b..b1b4463bf1 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'models/owner' +require "models/owner" module ActiveRecord module ConnectionAdapters @@ -8,12 +8,12 @@ module ActiveRecord Dir.mktmpdir do |dir| begin dir = Pathname.new(dir) - @conn = Base.sqlite3_connection :database => dir.join("db/foo.sqlite3"), - :adapter => 'sqlite3', - :timeout => 100 + @conn = Base.sqlite3_connection database: dir.join("db/foo.sqlite3"), + adapter: "sqlite3", + timeout: 100 - assert Dir.exist? dir.join('db') - assert File.exist? dir.join('db/foo.sqlite3') + assert Dir.exist? dir.join("db") + assert File.exist? dir.join("db/foo.sqlite3") ensure @conn.disconnect! if @conn end diff --git a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb index 24cc6875ab..aebcce3691 100644 --- a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb @@ -1,20 +1,20 @@ -require 'cases/helper' +require "cases/helper" class SQLite3StatementPoolTest < ActiveRecord::SQLite3TestCase if Process.respond_to?(:fork) def test_cache_is_per_pid cache = ActiveRecord::ConnectionAdapters::SQLite3Adapter::StatementPool.new(10) - cache['foo'] = 'bar' - assert_equal 'bar', cache['foo'] + cache["foo"] = "bar" + assert_equal "bar", cache["foo"] pid = fork { - lookup = cache['foo']; + lookup = cache["foo"]; exit!(!lookup) } Process.waitpid pid - assert $?.success?, 'process should exit successfully' + assert $?.success?, "process should exit successfully" end end end diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb index 8a728902a8..f8136fde72 100644 --- a/activerecord/test/cases/aggregations_test.rb +++ b/activerecord/test/cases/aggregations_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'models/customer' +require "models/customer" class AggregationsTest < ActiveRecord::TestCase fixtures :customers @@ -51,17 +51,17 @@ class AggregationsTest < ActiveRecord::TestCase Customer.update_all("gps_location = '24x113'") customers(:david).reload - assert_equal '24x113', customers(:david)['gps_location'] + assert_equal "24x113", customers(:david)["gps_location"] - assert_equal GpsLocation.new('24x113'), customers(:david).gps_location + assert_equal GpsLocation.new("24x113"), customers(:david).gps_location end def test_gps_equality - assert_equal GpsLocation.new('39x110'), GpsLocation.new('39x110') + assert_equal GpsLocation.new("39x110"), GpsLocation.new("39x110") end def test_gps_inequality - assert_not_equal GpsLocation.new('39x110'), GpsLocation.new('39x111') + assert_not_equal GpsLocation.new("39x110"), GpsLocation.new("39x111") end def test_allow_nil_gps_is_nil @@ -102,7 +102,7 @@ class AggregationsTest < ActiveRecord::TestCase end def test_nil_assignment_results_in_nil - customers(:david).gps_location = GpsLocation.new('39x111') + customers(:david).gps_location = GpsLocation.new("39x111") assert_not_nil customers(:david).gps_location customers(:david).gps_location = nil assert_nil customers(:david).gps_location @@ -129,13 +129,13 @@ class AggregationsTest < ActiveRecord::TestCase end def test_custom_constructor - assert_equal 'Barney GUMBLE', customers(:barney).fullname.to_s + assert_equal "Barney GUMBLE", customers(:barney).fullname.to_s assert_kind_of Fullname, customers(:barney).fullname end def test_custom_converter - customers(:barney).fullname = 'Barnoit Gumbleau' - assert_equal 'Barnoit GUMBLEAU', customers(:barney).fullname.to_s + customers(:barney).fullname = "Barnoit Gumbleau" + assert_equal "Barnoit GUMBLEAU", customers(:barney).fullname.to_s assert_kind_of Fullname, customers(:barney).fullname end @@ -143,17 +143,22 @@ class AggregationsTest < ActiveRecord::TestCase customers(:barney).fullname = { first: "Barney", last: "Stinson" } assert_equal "Barney STINSON", customers(:barney).name end + + def test_assigning_hash_without_custom_converter + customers(:barney).fullname_no_converter = { first: "Barney", last: "Stinson" } + assert_equal({ first: "Barney", last: "Stinson" }.to_s, customers(:barney).name) + end end class OverridingAggregationsTest < ActiveRecord::TestCase class DifferentName; end class Person < ActiveRecord::Base - composed_of :composed_of, :mapping => %w(person_first_name first_name) + composed_of :composed_of, mapping: %w(person_first_name first_name) end class DifferentPerson < Person - composed_of :composed_of, :class_name => 'DifferentName', :mapping => %w(different_person_first_name first_name) + composed_of :composed_of, class_name: "DifferentName", mapping: %w(different_person_first_name first_name) end def test_composed_of_aggregation_redefinition_reflections_should_differ_and_not_inherited diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb index 9c99689c1e..e3eccad71f 100644 --- a/activerecord/test/cases/ar_schema_test.rb +++ b/activerecord/test/cases/ar_schema_test.rb @@ -17,6 +17,7 @@ if ActiveRecord::Base.connection.supports_migrations? @connection.drop_table :nep_fruits rescue nil @connection.drop_table :nep_schema_migrations rescue nil @connection.drop_table :has_timestamps rescue nil + @connection.drop_table :multiple_indexes rescue nil ActiveRecord::SchemaMigration.delete_all rescue nil ActiveRecord::Migration.verbose = @original_verbose end @@ -36,7 +37,7 @@ if ActiveRecord::Base.connection.supports_migrations? end def test_schema_define - ActiveRecord::Schema.define(:version => 7) do + ActiveRecord::Schema.define(version: 7) do create_table :fruits do |t| t.column :color, :string t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle @@ -55,7 +56,7 @@ if ActiveRecord::Base.connection.supports_migrations? old_table_name_prefix = ActiveRecord::Base.table_name_prefix ActiveRecord::Base.table_name_prefix = "nep_" ActiveRecord::SchemaMigration.table_name = "nep_#{table_name}" - ActiveRecord::Schema.define(:version => 7) do + ActiveRecord::Schema.define(version: 7) do create_table :fruits do |t| t.column :color, :string t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle @@ -71,7 +72,7 @@ if ActiveRecord::Base.connection.supports_migrations? def test_schema_raises_an_error_for_invalid_column_type assert_raise NoMethodError do - ActiveRecord::Schema.define(:version => 8) do + ActiveRecord::Schema.define(version: 8) do create_table :vegetables do |t| t.unknown :color end @@ -80,7 +81,7 @@ if ActiveRecord::Base.connection.supports_migrations? end def test_schema_subclass - Class.new(ActiveRecord::Schema).define(:version => 9) do + Class.new(ActiveRecord::Schema).define(version: 9) do create_table :fruits end assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" } @@ -93,6 +94,21 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "20131219224947", ActiveRecord::SchemaMigration.normalize_migration_number("20131219224947") end + def test_schema_load_with_multiple_indexes_for_column_of_different_names + ActiveRecord::Schema.define do + create_table :multiple_indexes do |t| + t.string "foo" + t.index ["foo"], name: "multiple_indexes_foo_1" + t.index ["foo"], name: "multiple_indexes_foo_2" + end + end + + indexes = @connection.indexes("multiple_indexes") + + assert_equal 2, indexes.length + assert_equal ["multiple_indexes_foo_1", "multiple_indexes_foo_2"], indexes.collect(&:name).sort + end + def test_timestamps_without_null_set_null_to_false_on_create_table ActiveRecord::Schema.define do create_table :has_timestamps do |t| @@ -100,8 +116,8 @@ if ActiveRecord::Base.connection.supports_migrations? end end - assert !@connection.columns(:has_timestamps).find { |c| c.name == 'created_at' }.null - assert !@connection.columns(:has_timestamps).find { |c| c.name == 'updated_at' }.null + assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null + assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null end def test_timestamps_without_null_set_null_to_false_on_change_table @@ -113,8 +129,8 @@ if ActiveRecord::Base.connection.supports_migrations? end end - assert !@connection.columns(:has_timestamps).find { |c| c.name == 'created_at' }.null - assert !@connection.columns(:has_timestamps).find { |c| c.name == 'updated_at' }.null + assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null + assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null end def test_timestamps_without_null_set_null_to_false_on_add_timestamps @@ -123,8 +139,8 @@ if ActiveRecord::Base.connection.supports_migrations? add_timestamps :has_timestamps, default: Time.now end - assert !@connection.columns(:has_timestamps).find { |c| c.name == 'created_at' }.null - assert !@connection.columns(:has_timestamps).find { |c| c.name == 'updated_at' }.null + assert !@connection.columns(:has_timestamps).find { |c| c.name == "created_at" }.null + assert !@connection.columns(:has_timestamps).find { |c| c.name == "updated_at" }.null end end end diff --git a/activerecord/test/cases/associations/association_scope_test.rb b/activerecord/test/cases/associations/association_scope_test.rb index 472e270f8c..c322333f6d 100644 --- a/activerecord/test/cases/associations/association_scope_test.rb +++ b/activerecord/test/cases/associations/association_scope_test.rb @@ -1,11 +1,11 @@ -require 'cases/helper' -require 'models/post' -require 'models/author' +require "cases/helper" +require "models/post" +require "models/author" module ActiveRecord module Associations class AssociationScopeTest < ActiveRecord::TestCase - test 'does not duplicate conditions' do + test "does not duplicate conditions" do scope = AssociationScope.scope(Author.new.association(:welcome_posts), Author.connection) binds = scope.where_clause.binds.map(&:value) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 9dadd114a1..2418346d1b 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -1,28 +1,28 @@ -require 'cases/helper' -require 'models/developer' -require 'models/project' -require 'models/company' -require 'models/topic' -require 'models/reply' -require 'models/computer' -require 'models/post' -require 'models/author' -require 'models/tag' -require 'models/tagging' -require 'models/comment' -require 'models/sponsor' -require 'models/member' -require 'models/essay' -require 'models/toy' -require 'models/invoice' -require 'models/line_item' -require 'models/column' -require 'models/record' -require 'models/admin' -require 'models/admin/user' -require 'models/ship' -require 'models/treasure' -require 'models/parrot' +require "cases/helper" +require "models/developer" +require "models/project" +require "models/company" +require "models/topic" +require "models/reply" +require "models/computer" +require "models/post" +require "models/author" +require "models/tag" +require "models/tagging" +require "models/comment" +require "models/sponsor" +require "models/member" +require "models/essay" +require "models/toy" +require "models/invoice" +require "models/line_item" +require "models/column" +require "models/record" +require "models/admin" +require "models/admin/user" +require "models/ship" +require "models/treasure" +require "models/parrot" class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -43,11 +43,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase ActiveRecord::SQLCounter.clear_log Client.find(3).firm ensure - assert ActiveRecord::SQLCounter.log_all.all? { |sql| /order by/i !~ sql }, 'ORDER BY was used in the query' + assert ActiveRecord::SQLCounter.log_all.all? { |sql| /order by/i !~ sql }, "ORDER BY was used in the query" end def test_belongs_to_with_primary_key - client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name) + client = Client.create(name: "Primary key client", firm_name: companies(:first_firm).name) assert_equal companies(:first_firm).name, client.firm_with_primary_key.name end @@ -94,7 +94,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase account = model.new assert_not account.valid? - assert_equal [{error: :blank}], account.errors.details[:company] + assert_equal [{ error: :blank }], account.errors.details[:company] ensure ActiveRecord::Base.belongs_to_required_by_default = original_value end @@ -111,7 +111,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase account = model.new assert_not account.valid? - assert_equal [{error: :blank}], account.errors.details[:company] + assert_equal [{ error: :blank }], account.errors.details[:company] ensure ActiveRecord::Base.belongs_to_required_by_default = original_value end @@ -120,21 +120,21 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase counter = 0 comments = Class.new(ActiveRecord::Base) { - self.table_name = 'comments' - self.inheritance_column = 'not_there' + self.table_name = "comments" + self.inheritance_column = "not_there" posts = Class.new(ActiveRecord::Base) { - self.table_name = 'posts' - self.inheritance_column = 'not_there' + self.table_name = "posts" + self.inheritance_column = "not_there" default_scope -> { counter += 1 - where("id = :inc", :inc => counter) + where("id = :inc", inc: counter) } - has_many :comments, :anonymous_class => comments + has_many :comments, anonymous_class: comments } - belongs_to :post, :anonymous_class => posts, :inverse_of => false + belongs_to :post, anonymous_class: posts, inverse_of: false } assert_equal 0, counter @@ -166,7 +166,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase Admin.const_set "Region", Class.new(ActiveRecord::Base) e = assert_raise(ActiveRecord::AssociationTypeMismatch) { - Admin::RegionalUser.new(region: 'wrong value') + Admin::RegionalUser.new(region: "wrong value") } assert_match(/^Region\([^)]+\) expected, got "wrong value" which is an instance of String\([^)]+\)$/, e.message) ensure @@ -203,14 +203,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_eager_loading_with_primary_key Firm.create("name" => "Apple") Client.create("name" => "Citibank", :firm_name => "Apple") - citibank_result = Client.all.merge!(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key).first + citibank_result = Client.all.merge!(where: { name: "Citibank" }, includes: :firm_with_primary_key).first assert citibank_result.association(:firm_with_primary_key).loaded? end def test_eager_loading_with_primary_key_as_symbol Firm.create("name" => "Apple") Client.create("name" => "Citibank", :firm_name => "Apple") - citibank_result = Client.all.merge!(:where => {:name => "Citibank"}, :includes => :firm_with_primary_key_symbols).first + citibank_result = Client.all.merge!(where: { name: "Citibank" }, includes: :firm_with_primary_key_symbols).first assert citibank_result.association(:firm_with_primary_key_symbols).loaded? end @@ -224,7 +224,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_creating_the_belonging_object_with_primary_key - client = Client.create(:name => "Primary key client") + client = Client.create(name: "Primary key client") apple = client.create_firm_with_primary_key("name" => "Apple") assert_equal apple, client.firm_with_primary_key client.save @@ -247,36 +247,36 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_building_the_belonging_object_with_explicit_sti_base_class account = Account.new - company = account.build_firm(:type => "Company") + company = account.build_firm(type: "Company") assert_kind_of Company, company, "Expected #{company.class} to be a Company" end def test_building_the_belonging_object_with_sti_subclass account = Account.new - company = account.build_firm(:type => "Firm") + company = account.build_firm(type: "Firm") assert_kind_of Firm, company, "Expected #{company.class} to be a Firm" end def test_building_the_belonging_object_with_an_invalid_type account = Account.new - assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(:type => "InvalidType") } + assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(type: "InvalidType") } end def test_building_the_belonging_object_with_an_unrelated_type account = Account.new - assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(:type => "Account") } + assert_raise(ActiveRecord::SubclassNotFound) { account.build_firm(type: "Account") } end def test_building_the_belonging_object_with_primary_key - client = Client.create(:name => "Primary key client") + client = Client.create(name: "Primary key client") apple = client.build_firm_with_primary_key("name" => "Apple") client.save assert_equal apple.name, client.firm_name end def test_create! - client = Client.create!(:name => "Jimmy") - account = client.create_account!(:credit_limit => 10) + client = Client.create!(name: "Jimmy") + account = client.create_account!(credit_limit: 10) assert_equal account, client.account assert account.persisted? client.save @@ -285,7 +285,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_failing_create! - client = Client.create!(:name => "Jimmy") + client = Client.create!(name: "Jimmy") assert_raise(ActiveRecord::RecordInvalid) { client.create_account! } assert_not_nil client.account assert client.account.new_record? @@ -301,7 +301,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_natural_assignment_to_nil_with_primary_key - client = Client.create(:name => "Primary key client", :firm_name => companies(:first_firm).name) + client = Client.create(name: "Primary key client", firm_name: companies(:first_firm).name) client.firm_with_primary_key = nil client.save client.association(:firm_with_primary_key).reload @@ -325,19 +325,19 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase sponsor.association(:sponsorable).reload assert_nil sponsor.sponsorable - sponsor.sponsorable_type = '' # the column doesn't have to be declared NOT NULL + sponsor.sponsorable_type = "" # the column doesn't have to be declared NOT NULL assert_nil sponsor.association(:sponsorable).send(:klass) sponsor.association(:sponsorable).reload assert_nil sponsor.sponsorable - sponsor.sponsorable = Member.new :name => "Bert" + sponsor.sponsorable = Member.new name: "Bert" assert_equal Member, sponsor.association(:sponsorable).send(:klass) assert_equal "members", sponsor.association(:sponsorable).aliased_table_name end def test_with_polymorphic_and_condition sponsor = Sponsor.create - member = Member.create :name => "Bert" + member = Member.create name: "Bert" sponsor.sponsorable = member assert_equal member, sponsor.sponsorable @@ -346,16 +346,16 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_with_select assert_equal 1, Company.find(2).firm_with_select.attributes.size - assert_equal 1, Company.all.merge!(:includes => :firm_with_select ).find(2).firm_with_select.attributes.size + assert_equal 1, Company.all.merge!(includes: :firm_with_select ).find(2).firm_with_select.attributes.size end def test_belongs_to_without_counter_cache_option # Ship has a conventionally named `treasures_count` column, but the counter_cache # option is not given on the association. - ship = Ship.create(name: 'Countless') + ship = Ship.create(name: "Countless") assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed unless counter_cache is given on the relation" do - treasure = Treasure.new(name: 'Gold', ship: ship) + treasure = Treasure.new(name: "Gold", ship: ship) treasure.save end @@ -461,8 +461,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_belongs_to_counter_after_save - topic = Topic.create!(:title => "monday night") - topic.replies.create!(:title => "re: monday night", :content => "football") + topic = Topic.create!(title: "monday night") + topic.replies.create!(title: "re: monday night", content: "football") assert_equal 1, Topic.find(topic.id)[:replies_count] topic.save! @@ -564,8 +564,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_belongs_to_counter_when_update_columns - topic = Topic.create!(:title => "37s") - topic.replies.create!(:title => "re: 37s", :content => "rails") + topic = Topic.create!(title: "37s") + topic.replies.create!(title: "re: 37s", content: "rails") assert_equal 1, Topic.find(topic.id)[:replies_count] topic.update_columns(content: "rails is wonderful") @@ -601,7 +601,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_new_record_with_foreign_key_but_no_object client = Client.new("firm_id" => 1) # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first - assert_equal Firm.all.merge!(:order => "id").first, client.firm_with_basic_id + assert_equal Firm.all.merge!(order: "id").first, client.firm_with_basic_id end def test_setting_foreign_key_after_nil_target_loaded @@ -626,16 +626,22 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_queries(0) { tagging.super_tag } end + def test_dont_find_target_when_saving_foreign_key_after_stale_association_loaded + client = Client.create!(name: "Test client", firm_with_basic_id: Firm.find(1)) + client.firm_id = Firm.create!(name: "Test firm").id + assert_queries(1) { client.save! } + end + def test_field_name_same_as_foreign_key computer = Computer.find(1) assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # ' end def test_counter_cache - topic = Topic.create :title => "Zoom-zoom-zoom" + topic = Topic.create title: "Zoom-zoom-zoom" assert_equal 0, topic[:replies_count] - reply = Reply.create(:title => "re: zoom", :content => "speedy quick!") + reply = Reply.create(title: "re: zoom", content: "speedy quick!") reply.topic = topic assert_equal 1, topic.reload[:replies_count] @@ -646,10 +652,10 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_counter_cache_double_destroy - topic = Topic.create :title => "Zoom-zoom-zoom" + topic = Topic.create title: "Zoom-zoom-zoom" 5.times do - topic.replies.create(:title => "re: zoom", :content => "speedy quick!") + topic.replies.create(title: "re: zoom", content: "speedy quick!") end assert_equal 5, topic.reload[:replies_count] @@ -666,10 +672,10 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_concurrent_counter_cache_double_destroy - topic = Topic.create :title => "Zoom-zoom-zoom" + topic = Topic.create title: "Zoom-zoom-zoom" 5.times do - topic.replies.create(:title => "re: zoom", :content => "speedy quick!") + topic.replies.create(title: "re: zoom", content: "speedy quick!") end assert_equal 5, topic.reload[:replies_count] @@ -687,10 +693,10 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_custom_counter_cache - reply = Reply.create(:title => "re: zoom", :content => "speedy quick!") + reply = Reply.create(title: "re: zoom", content: "speedy quick!") assert_equal 0, reply[:replies_count] - silly = SillyReply.create(:title => "gaga", :content => "boo-boo") + silly = SillyReply.create(title: "gaga", content: "boo-boo") silly.reply = reply assert_equal 1, reply.reload[:replies_count] @@ -714,7 +720,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_association_assignment_sticks post = Post.first - author1, author2 = Author.all.merge!(:limit => 2).to_a + author1, author2 = Author.all.merge!(limit: 2).to_a assert_not_nil author1 assert_not_nil author2 @@ -767,7 +773,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_polymorphic_assignment_with_primary_key_foreign_type_field_updating # should update when assigning a saved record essay = Essay.new - writer = Author.create(:name => "David") + writer = Author.create(name: "David") essay.writer = writer assert_equal "Author", essay.writer_type @@ -792,7 +798,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_assignment_updates_foreign_id_field_for_new_and_saved_records client = Client.new - saved_firm = Firm.create :name => "Saved" + saved_firm = Firm.create name: "Saved" new_firm = Firm.new client.firm = saved_firm @@ -804,7 +810,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records essay = Essay.new - saved_writer = Author.create(:name => "David") + saved_writer = Author.create(name: "David") new_writer = Author.new essay.writer = saved_writer @@ -820,7 +826,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_nil essay.writer_type essay.writer_id = 1 - essay.writer_type = 'Author' + essay.writer_type = "Author" essay.writer = nil assert_nil essay.writer_id @@ -842,14 +848,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_nothing_raised do Account.find(@account.id).save! - Account.all.merge!(:includes => :firm).find(@account.id).save! + Account.all.merge!(includes: :firm).find(@account.id).save! end @account.firm.delete assert_nothing_raised do Account.find(@account.id).save! - Account.all.merge!(:includes => :firm).find(@account.id).save! + Account.all.merge!(includes: :firm).find(@account.id).save! end end @@ -870,18 +876,18 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_belongs_to_invalid_dependent_option_raises_exception error = assert_raise ArgumentError do - Class.new(Author).belongs_to :special_author_address, :dependent => :nullify + Class.new(Author).belongs_to :special_author_address, dependent: :nullify end - assert_equal error.message, 'The :dependent option must be one of [:destroy, :delete], but is :nullify' + assert_equal error.message, "The :dependent option must be one of [:destroy, :delete], but is :nullify" end def test_attributes_are_being_set_when_initialized_from_belongs_to_association_with_where_clause - new_firm = accounts(:signals37).build_firm(:name => 'Apple') + new_firm = accounts(:signals37).build_firm(name: "Apple") assert_equal new_firm.name, "Apple" end def test_attributes_are_set_without_error_when_initialized_from_belongs_to_association_with_array_in_where_clause - new_account = Account.where(:credit_limit => [ 50, 60 ]).new + new_account = Account.where(credit_limit: [ 50, 60 ]).new assert_nil new_account.credit_limit end @@ -930,7 +936,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert !proxy.stale_target? assert_equal members(:groucho), sponsor.sponsorable - sponsor.sponsorable_type = 'Firm' + sponsor.sponsorable_type = "Firm" assert proxy.stale_target? assert_equal companies(:first_firm), sponsor.sponsorable @@ -955,7 +961,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase comment = comments(:greetings) assert_difference lambda { post.reload.tags_count }, -1 do - assert_difference 'comment.reload.tags_count', +1 do + assert_difference "comment.reload.tags_count", +1 do tagging.taggable = comment end end @@ -1002,42 +1008,42 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_build_with_block - client = Client.create(:name => 'Client Company') + client = Client.create(name: "Client Company") - firm = client.build_firm{ |f| f.name = 'Agency Company' } - assert_equal 'Agency Company', firm.name + firm = client.build_firm { |f| f.name = "Agency Company" } + assert_equal "Agency Company", firm.name end def test_create_with_block - client = Client.create(:name => 'Client Company') + client = Client.create(name: "Client Company") - firm = client.create_firm{ |f| f.name = 'Agency Company' } - assert_equal 'Agency Company', firm.name + firm = client.create_firm { |f| f.name = "Agency Company" } + assert_equal "Agency Company", firm.name end def test_create_bang_with_block - client = Client.create(:name => 'Client Company') + client = Client.create(name: "Client Company") - firm = client.create_firm!{ |f| f.name = 'Agency Company' } - assert_equal 'Agency Company', firm.name + firm = client.create_firm! { |f| f.name = "Agency Company" } + assert_equal "Agency Company", firm.name end def test_should_set_foreign_key_on_create_association - client = Client.create! :name => "fuu" + client = Client.create! name: "fuu" - firm = client.create_firm :name => "baa" + firm = client.create_firm name: "baa" assert_equal firm.id, client.client_of end def test_should_set_foreign_key_on_create_association! - client = Client.create! :name => "fuu" + client = Client.create! name: "fuu" - firm = client.create_firm! :name => "baa" + firm = client.create_firm! name: "baa" assert_equal firm.id, client.client_of end def test_self_referential_belongs_to_with_counter_cache_assigning_nil - comment = Comment.create! :post => posts(:thinking), :body => "fuu" + comment = Comment.create! post: posts(:thinking), body: "fuu" comment.parent = nil comment.save! @@ -1058,7 +1064,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_polymorphic_with_custom_primary_key toy = Toy.create! - sponsor = Sponsor.create!(:sponsorable => toy) + sponsor = Sponsor.create!(sponsorable: toy) assert_equal toy, sponsor.reload.sponsorable end @@ -1077,7 +1083,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_reflect_the_most_recent_change author1, author2 = Author.limit(2) - post = Post.new(:title => "foo", :body=> "bar") + post = Post.new(title: "foo", body: "bar") post.author = author1 post.author_id = author2.id @@ -1086,8 +1092,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal post.author_id, author2.id end - test 'dangerous association name raises ArgumentError' do - [:errors, 'errors', :save, 'save'].each do |name| + test "dangerous association name raises ArgumentError" do + [:errors, "errors", :save, "save"].each do |name| assert_raises(ArgumentError, "Association #{name} should not be allowed") do Class.new(ActiveRecord::Base) do belongs_to name @@ -1096,7 +1102,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end end - test 'belongs_to works with model called Record' do + test "belongs_to works with model called Record" do record = Record.create! Column.create! record: record assert_equal 1, Column.count diff --git a/activerecord/test/cases/associations/bidirectional_destroy_dependencies_test.rb b/activerecord/test/cases/associations/bidirectional_destroy_dependencies_test.rb index 2b867965ba..8a0e041864 100644 --- a/activerecord/test/cases/associations/bidirectional_destroy_dependencies_test.rb +++ b/activerecord/test/cases/associations/bidirectional_destroy_dependencies_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'models/content' +require "cases/helper" +require "models/content" class BidirectionalDestroyDependenciesTest < ActiveRecord::TestCase fixtures :content, :content_positions diff --git a/activerecord/test/cases/associations/callbacks_test.rb b/activerecord/test/cases/associations/callbacks_test.rb index a4298a25a6..2f62d0367e 100644 --- a/activerecord/test/cases/associations/callbacks_test.rb +++ b/activerecord/test/cases/associations/callbacks_test.rb @@ -1,10 +1,10 @@ require "cases/helper" -require 'models/post' -require 'models/author' -require 'models/project' -require 'models/developer' -require 'models/computer' -require 'models/company' +require "models/post" +require "models/author" +require "models/project" +require "models/developer" +require "models/computer" +require "models/company" class AssociationCallbacksTest < ActiveRecord::TestCase fixtures :posts, :authors, :projects, :developers @@ -61,20 +61,20 @@ class AssociationCallbacksTest < ActiveRecord::TestCase end def test_has_many_callbacks_with_create - morten = Author.create :name => "Morten" - post = morten.posts_with_proc_callbacks.create! :title => "Hello", :body => "How are you doing?" + morten = Author.create name: "Morten" + post = morten.posts_with_proc_callbacks.create! title: "Hello", body: "How are you doing?" assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log end def test_has_many_callbacks_with_create! - morten = Author.create! :name => "Morten" - post = morten.posts_with_proc_callbacks.create :title => "Hello", :body => "How are you doing?" + morten = Author.create! name: "Morten" + post = morten.posts_with_proc_callbacks.create title: "Hello", body: "How are you doing?" assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log end def test_has_many_callbacks_for_save_on_parent - jack = Author.new :name => "Jack" - jack.posts_with_callbacks.build :title => "Call me back!", :body => "Before you wake up and after you sleep" + jack = Author.new name: "Jack" + jack.posts_with_callbacks.build title: "Call me back!", body: "Before you wake up and after you sleep" callback_log = ["before_adding<new>", "after_adding#{jack.posts_with_callbacks.first.id}"] assert_equal callback_log, jack.post_log @@ -84,8 +84,8 @@ class AssociationCallbacksTest < ActiveRecord::TestCase end def test_has_many_callbacks_for_destroy_on_parent - firm = Firm.create! :name => "Firm" - client = firm.clients.create! :name => "Client" + firm = Firm.create! name: "Firm" + client = firm.clients.create! name: "Client" firm.destroy assert_equal ["before_remove#{client.id}", "after_remove#{client.id}"], firm.log @@ -108,14 +108,14 @@ class AssociationCallbacksTest < ActiveRecord::TestCase klass = Class.new(Project) do def self.name; Project.name; end has_and_belongs_to_many :developers_with_callbacks, - :class_name => "Developer", - :before_add => lambda { |o,r| + class_name: "Developer", + before_add: lambda { |o,r| dev = r new_dev = r.new_record? } end rec = klass.create! - alice = Developer.new(:name => 'alice') + alice = Developer.new(name: "alice") rec.developers_with_callbacks << alice assert_equal alice, dev assert_not_nil new_dev @@ -126,18 +126,17 @@ class AssociationCallbacksTest < ActiveRecord::TestCase def test_has_and_belongs_to_many_after_add_called_after_save ar = projects(:active_record) assert ar.developers_log.empty? - alice = Developer.new(:name => 'alice') + alice = Developer.new(name: "alice") ar.developers_with_callbacks << alice assert_equal"after_adding#{alice.id}", ar.developers_log.last - bob = ar.developers_with_callbacks.create(:name => 'bob') + bob = ar.developers_with_callbacks.create(name: "bob") assert_equal "after_adding#{bob.id}", ar.developers_log.last - ar.developers_with_callbacks.build(:name => 'charlie') + ar.developers_with_callbacks.build(name: "charlie") assert_equal "after_adding<new>", ar.developers_log.last end - def test_has_and_belongs_to_many_remove_callback david = developers(:david) jamis = developers(:jamis) @@ -160,14 +159,14 @@ class AssociationCallbacksTest < ActiveRecord::TestCase activerecord.reload assert activerecord.developers_with_callbacks.size == 2 end - activerecord.developers_with_callbacks.flat_map {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.sort + activerecord.developers_with_callbacks.flat_map { |d| ["before_removing#{d.id}","after_removing#{d.id}"] }.sort assert activerecord.developers_with_callbacks.clear assert_predicate activerecord.developers_log, :empty? end def test_has_many_and_belongs_to_many_callbacks_for_save_on_parent - project = Project.new :name => "Callbacks" - project.developers_with_callbacks.build :name => "Jack", :salary => 95000 + project = Project.new name: "Callbacks" + project.developers_with_callbacks.build name: "Jack", salary: 95000 callback_log = ["before_adding<new>", "after_adding<new>"] assert_equal callback_log, project.developers_log @@ -177,14 +176,14 @@ class AssociationCallbacksTest < ActiveRecord::TestCase end def test_dont_add_if_before_callback_raises_exception - assert !@david.unchangeable_posts.include?(@authorless) + assert_not_includes @david.unchangeable_posts, @authorless begin @david.unchangeable_posts << @authorless rescue Exception end assert @david.post_log.empty? - assert !@david.unchangeable_posts.include?(@authorless) + assert_not_includes @david.unchangeable_posts, @authorless @david.reload - assert !@david.unchangeable_posts.include?(@authorless) + assert_not_includes @david.unchangeable_posts, @authorless end end diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 51d8e0523e..e87431bf32 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -1,56 +1,56 @@ require "cases/helper" -require 'models/post' -require 'models/comment' -require 'models/author' -require 'models/categorization' -require 'models/category' -require 'models/company' -require 'models/topic' -require 'models/reply' -require 'models/person' -require 'models/vertex' -require 'models/edge' +require "models/post" +require "models/comment" +require "models/author" +require "models/categorization" +require "models/category" +require "models/company" +require "models/topic" +require "models/reply" +require "models/person" +require "models/vertex" +require "models/edge" class CascadedEagerLoadingTest < ActiveRecord::TestCase fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments, :categorizations, :people, :categories, :edges, :vertices def test_eager_association_loading_with_cascaded_two_levels - authors = Author.all.merge!(:includes=>{:posts=>:comments}, :order=>"authors.id").to_a + authors = Author.all.merge!(includes: { posts: :comments }, order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 3, authors[1].posts.size - assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + assert_equal 10, authors[0].posts.collect { |post| post.comments.size }.inject(0) { |sum,i| sum+i } end def test_eager_association_loading_with_cascaded_two_levels_and_one_level - authors = Author.all.merge!(:includes=>[{:posts=>:comments}, :categorizations], :order=>"authors.id").to_a + authors = Author.all.merge!(includes: [{ posts: :comments }, :categorizations], order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 3, authors[1].posts.size - assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + assert_equal 10, authors[0].posts.collect { |post| post.comments.size }.inject(0) { |sum,i| sum+i } assert_equal 1, authors[0].categorizations.size assert_equal 2, authors[1].categorizations.size end def test_eager_association_loading_with_hmt_does_not_table_name_collide_when_joining_associations assert_nothing_raised do - Author.joins(:posts).eager_load(:comments).where(:posts => {:tags_count => 1}).to_a + Author.joins(:posts).eager_load(:comments).where(posts: { tags_count: 1 }).to_a end - authors = Author.joins(:posts).eager_load(:comments).where(:posts => {:tags_count => 1}).to_a + authors = Author.joins(:posts).eager_load(:comments).where(posts: { tags_count: 1 }).to_a assert_equal 1, assert_no_queries { authors.size } assert_equal 10, assert_no_queries { authors[0].comments.size } end def test_eager_association_loading_grafts_stashed_associations_to_correct_parent assert_nothing_raised do - Person.eager_load(:primary_contact => :primary_contact).where('primary_contacts_people_2.first_name = ?', 'Susan').order('people.id').to_a + Person.eager_load(primary_contact: :primary_contact).where("primary_contacts_people_2.first_name = ?", "Susan").order("people.id").to_a end - assert_equal people(:michael), Person.eager_load(:primary_contact => :primary_contact).where('primary_contacts_people_2.first_name = ?', 'Susan').order('people.id').first + assert_equal people(:michael), Person.eager_load(primary_contact: :primary_contact).where("primary_contacts_people_2.first_name = ?", "Susan").order("people.id").first end def test_cascaded_eager_association_loading_with_join_for_count - categories = Category.joins(:categorizations).includes([{:posts=>:comments}, :authors]) + categories = Category.joins(:categorizations).includes([{ posts: :comments }, :authors]) assert_equal 4, categories.count assert_equal 4, categories.to_a.count @@ -59,7 +59,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_cascaded_eager_association_loading_with_duplicated_includes - categories = Category.includes(:categorizations).includes(:categorizations => :author).where("categorizations.id is not null").references(:categorizations) + categories = Category.includes(:categorizations).includes(categorizations: :author).where("categorizations.id is not null").references(:categorizations) assert_nothing_raised do assert_equal 3, categories.count assert_equal 3, categories.to_a.size @@ -67,7 +67,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_cascaded_eager_association_loading_with_twice_includes_edge_cases - categories = Category.includes(:categorizations => :author).includes(:categorizations => :post).where("posts.id is not null").references(:posts) + categories = Category.includes(categorizations: :author).includes(categorizations: :post).where("posts.id is not null").references(:posts) assert_nothing_raised do assert_equal 3, categories.count assert_equal 3, categories.to_a.size @@ -82,29 +82,29 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations - authors = Author.all.merge!(:includes=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id").to_a + authors = Author.all.merge!(includes: { posts: [:comments, :categorizations] }, order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal 3, authors[1].posts.size - assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} + assert_equal 10, authors[0].posts.collect { |post| post.comments.size }.inject(0) { |sum,i| sum+i } end def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference - authors = Author.all.merge!(:includes=>{:posts=>[:comments, :author]}, :order=>"authors.id").to_a + authors = Author.all.merge!(includes: { posts: [:comments, :author] }, order: "authors.id").to_a assert_equal 3, authors.size assert_equal 5, authors[0].posts.size assert_equal authors(:david).name, authors[0].name - assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq + assert_equal [authors(:david).name], authors[0].posts.collect { |post| post.author.name }.uniq end def test_eager_association_loading_with_cascaded_two_levels_with_condition - authors = Author.all.merge!(:includes=>{:posts=>:comments}, :where=>"authors.id=1", :order=>"authors.id").to_a + authors = Author.all.merge!(includes: { posts: :comments }, where: "authors.id=1", order: "authors.id").to_a assert_equal 1, authors.size assert_equal 5, authors[0].posts.size end def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong - firms = Firm.all.merge!(:includes=>{:account=>{:firm=>:account}}, :order=>"companies.id").to_a + firms = Firm.all.merge!(includes: { account: { firm: :account } }, order: "companies.id").to_a assert_equal 2, firms.size assert_equal firms.first.account, firms.first.account.firm.account assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account } @@ -112,7 +112,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_has_many_sti - topics = Topic.all.merge!(:includes => :replies, :order => 'topics.id').to_a + topics = Topic.all.merge!(includes: :replies, order: "topics.id").to_a first, second, = topics(:first).replies.size, topics(:second).replies.size assert_no_queries do assert_equal first, topics[0].replies.size @@ -121,11 +121,11 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_has_many_sti_and_subclasses - silly = SillyReply.new(:title => "gaga", :content => "boo-boo", :parent_id => 1) + silly = SillyReply.new(title: "gaga", content: "boo-boo", parent_id: 1) silly.parent_id = 1 assert silly.save - topics = Topic.all.merge!(:includes => :replies, :order => ['topics.id', 'replies_topics.id']).to_a + topics = Topic.all.merge!(includes: :replies, order: ["topics.id", "replies_topics.id"]).to_a assert_no_queries do assert_equal 2, topics[0].replies.size assert_equal 0, topics[1].replies.size @@ -133,14 +133,14 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_belongs_to_sti - replies = Reply.all.merge!(:includes => :topic, :order => 'topics.id').to_a - assert replies.include?(topics(:second)) - assert !replies.include?(topics(:first)) + replies = Reply.all.merge!(includes: :topic, order: "topics.id").to_a + assert_includes replies, topics(:second) + assert_not_includes replies, topics(:first) assert_equal topics(:first), assert_no_queries { replies.first.topic } end def test_eager_association_loading_with_multiple_stis_and_order - author = Author.all.merge!(:includes => { :posts => [ :special_comments , :very_special_comment ] }, :order => ['authors.name', 'comments.body', 'very_special_comments_posts.body'], :where => 'posts.id = 4').first + author = Author.all.merge!(includes: { posts: [ :special_comments , :very_special_comment ] }, order: ["authors.name", "comments.body", "very_special_comments_posts.body"], where: "posts.id = 4").first assert_equal authors(:david), author assert_no_queries do author.posts.first.special_comments @@ -149,7 +149,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_of_stis_with_multiple_references - authors = Author.all.merge!(:includes => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :where => 'posts.id = 4').to_a + authors = Author.all.merge!(includes: { posts: { special_comments: { post: [ :special_comments, :very_special_comment ] } } }, order: "comments.body, very_special_comments_posts.body", where: "posts.id = 4").to_a assert_equal [authors(:david)], authors assert_no_queries do authors.first.posts.first.special_comments.first.post.special_comments @@ -158,7 +158,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_where_first_level_returns_nil - authors = Author.all.merge!(:includes => {:post_about_thinking => :comments}, :order => 'authors.id DESC').to_a + authors = Author.all.merge!(includes: { post_about_thinking: :comments }, order: "authors.id DESC").to_a assert_equal [authors(:bob), authors(:mary), authors(:david)], authors assert_no_queries do authors[2].post_about_thinking.comments.first @@ -166,12 +166,12 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through - source = Vertex.all.merge!(:includes=>{:sinks=>{:sinks=>{:sinks=>:sinks}}}, :order => 'vertices.id').first + source = Vertex.all.merge!(includes: { sinks: { sinks: { sinks: :sinks } } }, order: "vertices.id").first assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first } end def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many - sink = Vertex.all.merge!(:includes=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC').first + sink = Vertex.all.merge!(includes: { sources: { sources: { sources: :sources } } }, order: "vertices.id DESC").first assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first } end diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb index 75a6295350..aa82b9dd2a 100644 --- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb +++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb @@ -1,34 +1,33 @@ -require 'cases/helper' -require 'models/post' -require 'models/tagging' +require "cases/helper" +require "models/post" +require "models/tagging" module Namespaced class Post < ActiveRecord::Base - self.table_name = 'posts' - has_one :tagging, :as => :taggable, :class_name => 'Tagging' + self.table_name = "posts" + has_one :tagging, as: :taggable, class_name: "Tagging" end end class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase - def setup generate_test_objects end def generate_test_objects - post = Namespaced::Post.create( :title => 'Great stuff', :body => 'This is not', :author_id => 1 ) - Tagging.create( :taggable => post ) + post = Namespaced::Post.create( title: "Great stuff", body: "This is not", author_id: 1 ) + Tagging.create( taggable: post ) end def test_class_names old = ActiveRecord::Base.store_full_sti_class ActiveRecord::Base.store_full_sti_class = false - post = Namespaced::Post.includes(:tagging).find_by_title('Great stuff') + post = Namespaced::Post.includes(:tagging).find_by_title("Great stuff") assert_nil post.tagging ActiveRecord::Base.store_full_sti_class = true - post = Namespaced::Post.includes(:tagging).find_by_title('Great stuff') + post = Namespaced::Post.includes(:tagging).find_by_title("Great stuff") assert_instance_of Tagging, post.tagging ensure ActiveRecord::Base.store_full_sti_class = old diff --git a/activerecord/test/cases/associations/eager_load_nested_include_test.rb b/activerecord/test/cases/associations/eager_load_nested_include_test.rb index f571198079..a7a8c6a783 100644 --- a/activerecord/test/cases/associations/eager_load_nested_include_test.rb +++ b/activerecord/test/cases/associations/eager_load_nested_include_test.rb @@ -1,11 +1,11 @@ -require 'cases/helper' -require 'models/post' -require 'models/tag' -require 'models/author' -require 'models/comment' -require 'models/category' -require 'models/categorization' -require 'models/tagging' +require "cases/helper" +require "models/post" +require "models/tag" +require "models/author" +require "models/comment" +require "models/category" +require "models/categorization" +require "models/tagging" module Remembered extend ActiveSupport::Concern @@ -23,30 +23,30 @@ module Remembered end class ShapeExpression < ActiveRecord::Base - belongs_to :shape, :polymorphic => true - belongs_to :paint, :polymorphic => true + belongs_to :shape, polymorphic: true + belongs_to :paint, polymorphic: true end class Circle < ActiveRecord::Base - has_many :shape_expressions, :as => :shape + has_many :shape_expressions, as: :shape include Remembered end class Square < ActiveRecord::Base - has_many :shape_expressions, :as => :shape + has_many :shape_expressions, as: :shape include Remembered end class Triangle < ActiveRecord::Base - has_many :shape_expressions, :as => :shape + has_many :shape_expressions, as: :shape include Remembered end class PaintColor < ActiveRecord::Base - has_many :shape_expressions, :as => :paint - belongs_to :non_poly, :foreign_key => "non_poly_one_id", :class_name => "NonPolyOne" + has_many :shape_expressions, as: :paint + belongs_to :non_poly, foreign_key: "non_poly_one_id", class_name: "NonPolyOne" include Remembered end class PaintTexture < ActiveRecord::Base - has_many :shape_expressions, :as => :paint - belongs_to :non_poly, :foreign_key => "non_poly_two_id", :class_name => "NonPolyTwo" + has_many :shape_expressions, as: :paint + belongs_to :non_poly, foreign_key: "non_poly_two_id", class_name: "NonPolyTwo" include Remembered end class NonPolyOne < ActiveRecord::Base @@ -58,8 +58,6 @@ class NonPolyTwo < ActiveRecord::Base include Remembered end - - class EagerLoadPolyAssocsTest < ActiveRecord::TestCase NUM_SIMPLE_OBJS = 50 NUM_SHAPE_EXPRESSIONS = 100 @@ -78,19 +76,19 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase [Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!) end 1.upto(NUM_SIMPLE_OBJS) do - PaintColor.create!(:non_poly_one_id => NonPolyOne.sample.id) - PaintTexture.create!(:non_poly_two_id => NonPolyTwo.sample.id) + PaintColor.create!(non_poly_one_id: NonPolyOne.sample.id) + PaintTexture.create!(non_poly_two_id: NonPolyTwo.sample.id) end 1.upto(NUM_SHAPE_EXPRESSIONS) do shape_type = [Circle, Square, Triangle].sample paint_type = [PaintColor, PaintTexture].sample - ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.sample.id, - :paint_type => paint_type.to_s, :paint_id => paint_type.sample.id) + ShapeExpression.create!(shape_type: shape_type.to_s, shape_id: shape_type.sample.id, + paint_type: paint_type.to_s, paint_id: paint_type.sample.id) end end def test_include_query - res = ShapeExpression.all.merge!(:includes => [ :shape, { :paint => :non_poly } ]).to_a + res = ShapeExpression.all.merge!(includes: [ :shape, { paint: :non_poly } ]).to_a assert_equal NUM_SHAPE_EXPRESSIONS, res.size assert_queries(0) do res.each do |se| @@ -103,10 +101,10 @@ end class EagerLoadNestedIncludeWithMissingDataTest < ActiveRecord::TestCase def setup - @davey_mcdave = Author.create(:name => 'Davey McDave') - @first_post = @davey_mcdave.posts.create(:title => 'Davey Speaks', :body => 'Expressive wordage') - @first_comment = @first_post.comments.create(:body => 'Inflamatory doublespeak') - @first_categorization = @davey_mcdave.categorizations.create(:category => Category.first, :post => @first_post) + @davey_mcdave = Author.create(name: "Davey McDave") + @first_post = @davey_mcdave.posts.create(title: "Davey Speaks", body: "Expressive wordage") + @first_comment = @first_post.comments.create(body: "Inflamatory doublespeak") + @first_categorization = @davey_mcdave.categorizations.create(category: Category.first, post: @first_post) end teardown do @@ -119,8 +117,8 @@ class EagerLoadNestedIncludeWithMissingDataTest < ActiveRecord::TestCase def test_missing_data_in_a_nested_include_should_not_cause_errors_when_constructing_objects assert_nothing_raised do # @davey_mcdave doesn't have any author_favorites - includes = {:posts => :comments, :categorizations => :category, :author_favorites => :favorite_author } - Author.all.merge!(:includes => includes, :where => {:authors => {:name => @davey_mcdave.name}}, :order => 'categories.name').to_a + includes = { posts: :comments, categorizations: :category, author_favorites: :favorite_author } + Author.all.merge!(includes: includes, where: { authors: { name: @davey_mcdave.name } }, order: "categories.name").to_a end end end diff --git a/activerecord/test/cases/associations/eager_singularization_test.rb b/activerecord/test/cases/associations/eager_singularization_test.rb index a61a070331..5d1c1c4b9b 100644 --- a/activerecord/test/cases/associations/eager_singularization_test.rb +++ b/activerecord/test/cases/associations/eager_singularization_test.rb @@ -1,148 +1,147 @@ require "cases/helper" - if ActiveRecord::Base.connection.supports_migrations? -class EagerSingularizationTest < ActiveRecord::TestCase - class Virus < ActiveRecord::Base - belongs_to :octopus - end - - class Octopus < ActiveRecord::Base - has_one :virus - end - - class Pass < ActiveRecord::Base - belongs_to :bus - end - - class Bus < ActiveRecord::Base - has_many :passes - end - - class Mess < ActiveRecord::Base - has_and_belongs_to_many :crises - end - - class Crisis < ActiveRecord::Base - has_and_belongs_to_many :messes - has_many :analyses, :dependent => :destroy - has_many :successes, :through => :analyses - has_many :dresses, :dependent => :destroy - has_many :compresses, :through => :dresses - end - - class Analysis < ActiveRecord::Base - belongs_to :crisis - belongs_to :success - end - - class Success < ActiveRecord::Base - has_many :analyses, :dependent => :destroy - has_many :crises, :through => :analyses - end + class EagerSingularizationTest < ActiveRecord::TestCase + class Virus < ActiveRecord::Base + belongs_to :octopus + end + + class Octopus < ActiveRecord::Base + has_one :virus + end + + class Pass < ActiveRecord::Base + belongs_to :bus + end - class Dress < ActiveRecord::Base - belongs_to :crisis - has_many :compresses - end + class Bus < ActiveRecord::Base + has_many :passes + end - class Compress < ActiveRecord::Base - belongs_to :dress - end - - def setup - connection.create_table :viri do |t| - t.column :octopus_id, :integer - t.column :species, :string - end - connection.create_table :octopi do |t| - t.column :species, :string + class Mess < ActiveRecord::Base + has_and_belongs_to_many :crises end - connection.create_table :passes do |t| - t.column :bus_id, :integer - t.column :rides, :integer - end - connection.create_table :buses do |t| - t.column :name, :string - end - connection.create_table :crises_messes, :id => false do |t| - t.column :crisis_id, :integer - t.column :mess_id, :integer - end - connection.create_table :messes do |t| - t.column :name, :string - end - connection.create_table :crises do |t| - t.column :name, :string - end - connection.create_table :successes do |t| - t.column :name, :string - end - connection.create_table :analyses do |t| - t.column :crisis_id, :integer - t.column :success_id, :integer - end - connection.create_table :dresses do |t| - t.column :crisis_id, :integer + + class Crisis < ActiveRecord::Base + has_and_belongs_to_many :messes + has_many :analyses, dependent: :destroy + has_many :successes, through: :analyses + has_many :dresses, dependent: :destroy + has_many :compresses, through: :dresses end - connection.create_table :compresses do |t| - t.column :dress_id, :integer + + class Analysis < ActiveRecord::Base + belongs_to :crisis + belongs_to :success end - end - teardown do - connection.drop_table :viri - connection.drop_table :octopi - connection.drop_table :passes - connection.drop_table :buses - connection.drop_table :crises_messes - connection.drop_table :messes - connection.drop_table :crises - connection.drop_table :successes - connection.drop_table :analyses - connection.drop_table :dresses - connection.drop_table :compresses - end + class Success < ActiveRecord::Base + has_many :analyses, dependent: :destroy + has_many :crises, through: :analyses + end - def connection - ActiveRecord::Base.connection - end + class Dress < ActiveRecord::Base + belongs_to :crisis + has_many :compresses + end - def test_eager_no_extra_singularization_belongs_to - assert_nothing_raised do - Virus.all.merge!(:includes => :octopus).to_a + class Compress < ActiveRecord::Base + belongs_to :dress end - end - def test_eager_no_extra_singularization_has_one - assert_nothing_raised do - Octopus.all.merge!(:includes => :virus).to_a + def setup + connection.create_table :viri do |t| + t.column :octopus_id, :integer + t.column :species, :string + end + connection.create_table :octopi do |t| + t.column :species, :string + end + connection.create_table :passes do |t| + t.column :bus_id, :integer + t.column :rides, :integer + end + connection.create_table :buses do |t| + t.column :name, :string + end + connection.create_table :crises_messes, id: false do |t| + t.column :crisis_id, :integer + t.column :mess_id, :integer + end + connection.create_table :messes do |t| + t.column :name, :string + end + connection.create_table :crises do |t| + t.column :name, :string + end + connection.create_table :successes do |t| + t.column :name, :string + end + connection.create_table :analyses do |t| + t.column :crisis_id, :integer + t.column :success_id, :integer + end + connection.create_table :dresses do |t| + t.column :crisis_id, :integer + end + connection.create_table :compresses do |t| + t.column :dress_id, :integer + end end - end - def test_eager_no_extra_singularization_has_many - assert_nothing_raised do - Bus.all.merge!(:includes => :passes).to_a + teardown do + connection.drop_table :viri + connection.drop_table :octopi + connection.drop_table :passes + connection.drop_table :buses + connection.drop_table :crises_messes + connection.drop_table :messes + connection.drop_table :crises + connection.drop_table :successes + connection.drop_table :analyses + connection.drop_table :dresses + connection.drop_table :compresses end - end - def test_eager_no_extra_singularization_has_and_belongs_to_many - assert_nothing_raised do - Crisis.all.merge!(:includes => :messes).to_a - Mess.all.merge!(:includes => :crises).to_a + def connection + ActiveRecord::Base.connection end - end - def test_eager_no_extra_singularization_has_many_through_belongs_to - assert_nothing_raised do - Crisis.all.merge!(:includes => :successes).to_a + def test_eager_no_extra_singularization_belongs_to + assert_nothing_raised do + Virus.all.merge!(includes: :octopus).to_a + end end - end - def test_eager_no_extra_singularization_has_many_through_has_many - assert_nothing_raised do - Crisis.all.merge!(:includes => :compresses).to_a + def test_eager_no_extra_singularization_has_one + assert_nothing_raised do + Octopus.all.merge!(includes: :virus).to_a + end + end + + def test_eager_no_extra_singularization_has_many + assert_nothing_raised do + Bus.all.merge!(includes: :passes).to_a + end + end + + def test_eager_no_extra_singularization_has_and_belongs_to_many + assert_nothing_raised do + Crisis.all.merge!(includes: :messes).to_a + Mess.all.merge!(includes: :crises).to_a + end + end + + def test_eager_no_extra_singularization_has_many_through_belongs_to + assert_nothing_raised do + Crisis.all.merge!(includes: :successes).to_a + end + end + + def test_eager_no_extra_singularization_has_many_through_has_many + assert_nothing_raised do + Crisis.all.merge!(includes: :compresses).to_a + end end end end -end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 80d9a6083b..d1c4c1cef8 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -1,31 +1,31 @@ require "cases/helper" -require 'models/post' -require 'models/tagging' -require 'models/tag' -require 'models/comment' -require 'models/author' -require 'models/essay' -require 'models/category' -require 'models/company' -require 'models/person' -require 'models/reader' -require 'models/owner' -require 'models/pet' -require 'models/reference' -require 'models/job' -require 'models/subscriber' -require 'models/subscription' -require 'models/book' -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/member' -require 'models/membership' -require 'models/club' -require 'models/categorization' -require 'models/sponsor' -require 'models/mentor' -require 'models/contract' +require "models/post" +require "models/tagging" +require "models/tag" +require "models/comment" +require "models/author" +require "models/essay" +require "models/category" +require "models/company" +require "models/person" +require "models/reader" +require "models/owner" +require "models/pet" +require "models/reference" +require "models/job" +require "models/subscriber" +require "models/subscription" +require "models/book" +require "models/developer" +require "models/computer" +require "models/project" +require "models/member" +require "models/membership" +require "models/club" +require "models/categorization" +require "models/sponsor" +require "models/mentor" +require "models/contract" class EagerAssociationTest < ActiveRecord::TestCase fixtures :posts, :comments, :authors, :essays, :author_addresses, :categories, :categories_posts, @@ -34,42 +34,42 @@ class EagerAssociationTest < ActiveRecord::TestCase :developers, :projects, :developers_projects, :members, :memberships, :clubs, :sponsors def test_eager_with_has_one_through_join_model_with_conditions_on_the_through - member = Member.all.merge!(:includes => :favourite_club).find(members(:some_other_guy).id) + member = Member.all.merge!(includes: :favourite_club).find(members(:some_other_guy).id) assert_nil member.favourite_club end def test_loading_with_one_association - posts = Post.all.merge!(:includes => :comments).to_a + posts = Post.all.merge!(includes: :comments).to_a post = posts.find { |p| p.id == 1 } assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) - post = Post.all.merge!(:includes => :comments, :where => "posts.title = 'Welcome to the weblog'").first + post = Post.all.merge!(includes: :comments, where: "posts.title = 'Welcome to the weblog'").first assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) - posts = Post.all.merge!(:includes => :last_comment).to_a + posts = Post.all.merge!(includes: :last_comment).to_a post = posts.find { |p| p.id == 1 } assert_equal Post.find(1).last_comment, post.last_comment end def test_loading_with_one_association_with_non_preload - posts = Post.all.merge!(:includes => :last_comment, :order => 'comments.id DESC').to_a + posts = Post.all.merge!(includes: :last_comment, order: "comments.id DESC").to_a post = posts.find { |p| p.id == 1 } assert_equal Post.find(1).last_comment, post.last_comment end def test_loading_conditions_with_or posts = authors(:david).posts.references(:comments).merge( - :includes => :comments, - :where => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'" + includes: :comments, + where: "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'" ).to_a assert_nil posts.detect { |p| p.author_id != authors(:david).id }, "expected to find only david's posts" end def test_with_ordering - list = Post.all.merge!(:includes => :comments, :order => "posts.id DESC").to_a + list = Post.all.merge!(includes: :comments, order: "posts.id DESC").to_a [:other_by_mary, :other_by_bob, :misc_by_mary, :misc_by_bob, :eager_other, :sti_habtm, :sti_post_and_comments, :sti_comments, :authorless, :thinking, :welcome ].each_with_index do |post, index| @@ -100,43 +100,43 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_loading_with_multiple_associations - posts = Post.all.merge!(:includes => [ :comments, :author, :categories ], :order => "posts.id").to_a + posts = Post.all.merge!(includes: [ :comments, :author, :categories ], order: "posts.id").to_a assert_equal 2, posts.first.comments.size assert_equal 2, posts.first.categories.size - assert posts.first.comments.include?(comments(:greetings)) + assert_includes posts.first.comments, comments(:greetings) end def test_duplicate_middle_objects - comments = Comment.all.merge!(:where => 'post_id = 1', :includes => [:post => :author]).to_a + comments = Comment.all.merge!(where: "post_id = 1", includes: [post: :author]).to_a assert_no_queries do - comments.each {|comment| comment.post.author.name} + comments.each { |comment| comment.post.author.name } end end def test_preloading_has_many_in_multiple_queries_with_more_ids_than_database_can_handle assert_called(Comment.connection, :in_clause_length, returns: 5) do - posts = Post.all.merge!(:includes=>:comments).to_a + posts = Post.all.merge!(includes: :comments).to_a assert_equal 11, posts.size end end def test_preloading_has_many_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle assert_called(Comment.connection, :in_clause_length, returns: nil) do - posts = Post.all.merge!(:includes=>:comments).to_a + posts = Post.all.merge!(includes: :comments).to_a assert_equal 11, posts.size end end def test_preloading_habtm_in_multiple_queries_with_more_ids_than_database_can_handle assert_called(Comment.connection, :in_clause_length, times: 2, returns: 5) do - posts = Post.all.merge!(:includes=>:categories).to_a + posts = Post.all.merge!(includes: :categories).to_a assert_equal 11, posts.size end end def test_preloading_habtm_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle assert_called(Comment.connection, :in_clause_length, times: 2, returns: nil) do - posts = Post.all.merge!(:includes=>:categories).to_a + posts = Post.all.merge!(includes: :categories).to_a assert_equal 11, posts.size end end @@ -145,7 +145,7 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_called(Comment.connection, :in_clause_length, returns: nil) do post = posts(:welcome) assert_queries(2) do - Post.includes(:comments).where(:id => post.id).to_a + Post.includes(:comments).where(id: post.id).to_a end end end @@ -154,7 +154,7 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_called(Comment.connection, :in_clause_length, returns: 1) do post1, post2 = posts(:welcome), posts(:thinking) assert_queries(3) do - Post.includes(:comments).where(:id => [post1.id, post2.id]).to_a + Post.includes(:comments).where(id: [post1.id, post2.id]).to_a end end end @@ -163,50 +163,50 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_called(Comment.connection, :in_clause_length, returns: 3) do post = posts(:welcome) assert_queries(2) do - Post.includes(:comments).where(:id => post.id).to_a + Post.includes(:comments).where(id: post.id).to_a end end end def test_including_duplicate_objects_from_belongs_to - popular_post = Post.create!(:title => 'foo', :body => "I like cars!") - comment = popular_post.comments.create!(:body => "lol") - popular_post.readers.create!(:person => people(:michael)) - popular_post.readers.create!(:person => people(:david)) + popular_post = Post.create!(title: "foo", body: "I like cars!") + comment = popular_post.comments.create!(body: "lol") + popular_post.readers.create!(person: people(:michael)) + popular_post.readers.create!(person: people(:david)) - readers = Reader.all.merge!(:where => ["post_id = ?", popular_post.id], - :includes => {:post => :comments}).to_a + readers = Reader.all.merge!(where: ["post_id = ?", popular_post.id], + includes: { post: :comments }).to_a readers.each do |reader| assert_equal [comment], reader.post.comments end end def test_including_duplicate_objects_from_has_many - car_post = Post.create!(:title => 'foo', :body => "I like cars!") + car_post = Post.create!(title: "foo", body: "I like cars!") car_post.categories << categories(:general) car_post.categories << categories(:technology) - comment = car_post.comments.create!(:body => "hmm") - categories = Category.all.merge!(:where => { 'posts.id' => car_post.id }, - :includes => {:posts => :comments}).to_a + comment = car_post.comments.create!(body: "hmm") + categories = Category.all.merge!(where: { "posts.id" => car_post.id }, + includes: { posts: :comments }).to_a categories.each do |category| assert_equal [comment], category.posts[0].comments end end def test_associations_loaded_for_all_records - post = Post.create!(:title => 'foo', :body => "I like cars!") - SpecialComment.create!(:body => 'Come on!', :post => post) - first_category = Category.create! :name => 'First!', :posts => [post] - second_category = Category.create! :name => 'Second!', :posts => [post] + post = Post.create!(title: "foo", body: "I like cars!") + SpecialComment.create!(body: "Come on!", post: post) + first_category = Category.create! name: "First!", posts: [post] + second_category = Category.create! name: "Second!", posts: [post] - categories = Category.where(:id => [first_category.id, second_category.id]).includes(:posts => :special_comments) + categories = Category.where(id: [first_category.id, second_category.id]).includes(posts: :special_comments) assert_equal categories.map { |category| category.posts.first.special_comments.loaded? }, [true, true] end def test_finding_with_includes_on_has_many_association_with_same_include_includes_only_once author_id = authors(:david).id - author = assert_queries(3) { Author.all.merge!(:includes => {:posts_with_comments => :comments}).find(author_id) } # find the author, then find the posts, then find the comments + author = assert_queries(3) { Author.all.merge!(includes: { posts_with_comments: :comments }).find(author_id) } # find the author, then find the posts, then find the comments author.posts_with_comments.each do |post_with_comments| assert_equal post_with_comments.comments.length, post_with_comments.comments.count assert_nil post_with_comments.comments.to_a.uniq! @@ -217,7 +217,7 @@ class EagerAssociationTest < ActiveRecord::TestCase author = authors(:david) post = author.post_about_thinking_with_last_comment last_comment = post.last_comment - author = assert_queries(3) { Author.all.merge!(:includes => {:post_about_thinking_with_last_comment => :last_comment}).find(author.id)} # find the author, then find the posts, then find the comments + author = assert_queries(3) { Author.all.merge!(includes: { post_about_thinking_with_last_comment: :last_comment }).find(author.id) } # find the author, then find the posts, then find the comments assert_no_queries do assert_equal post, author.post_about_thinking_with_last_comment assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment @@ -228,7 +228,7 @@ class EagerAssociationTest < ActiveRecord::TestCase post = posts(:welcome) author = post.author author_address = author.author_address - post = assert_queries(3) { Post.all.merge!(:includes => {:author_with_address => :author_address}).find(post.id) } # find the post, then find the author, then find the address + post = assert_queries(3) { Post.all.merge!(includes: { author_with_address: :author_address }).find(post.id) } # find the post, then find the author, then find the address assert_no_queries do assert_equal author, post.author_with_address assert_equal author_address, post.author_with_address.author_address @@ -238,7 +238,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_finding_with_includes_on_null_belongs_to_association_with_same_include_includes_only_once post = posts(:welcome) post.update!(author: nil) - post = assert_queries(1) { Post.all.merge!(includes: {author_with_address: :author_address}).find(post.id) } + post = assert_queries(1) { Post.all.merge!(includes: { author_with_address: :author_address }).find(post.id) } # find the post, then find the author which is null so no query for the author or address assert_no_queries do assert_equal nil, post.author_with_address @@ -248,7 +248,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_finding_with_includes_on_null_belongs_to_polymorphic_association sponsor = sponsors(:moustache_club_sponsor_for_groucho) sponsor.update!(sponsorable: nil) - sponsor = assert_queries(1) { Sponsor.all.merge!(:includes => :sponsorable).find(sponsor.id) } + sponsor = assert_queries(1) { Sponsor.all.merge!(includes: :sponsorable).find(sponsor.id) } assert_no_queries do assert_equal nil, sponsor.sponsorable end @@ -256,9 +256,9 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_finding_with_includes_on_empty_polymorphic_type_column sponsor = sponsors(:moustache_club_sponsor_for_groucho) - sponsor.update!(sponsorable_type: '', sponsorable_id: nil) # sponsorable_type column might be declared NOT NULL + sponsor.update!(sponsorable_type: "", sponsorable_id: nil) # sponsorable_type column might be declared NOT NULL sponsor = assert_queries(1) do - assert_nothing_raised { Sponsor.all.merge!(:includes => :sponsorable).find(sponsor.id) } + assert_nothing_raised { Sponsor.all.merge!(includes: :sponsorable).find(sponsor.id) } end assert_no_queries do assert_equal nil, sponsor.sponsorable @@ -266,25 +266,25 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_loading_from_an_association - posts = authors(:david).posts.merge(:includes => :comments, :order => "posts.id").to_a + posts = authors(:david).posts.merge(includes: :comments, order: "posts.id").to_a assert_equal 2, posts.first.comments.size end def test_loading_from_an_association_that_has_a_hash_of_conditions assert_nothing_raised do - Author.all.merge!(:includes => :hello_posts_with_hash_conditions).to_a + Author.all.merge!(includes: :hello_posts_with_hash_conditions).to_a end - assert !Author.all.merge!(:includes => :hello_posts_with_hash_conditions).find(authors(:david).id).hello_posts.empty? + assert !Author.all.merge!(includes: :hello_posts_with_hash_conditions).find(authors(:david).id).hello_posts.empty? end def test_loading_with_no_associations - assert_nil Post.all.merge!(:includes => :author).find(posts(:authorless).id).author + assert_nil Post.all.merge!(includes: :author).find(posts(:authorless).id).author end # Regression test for 21c75e5 def test_nested_loading_does_not_raise_exception_when_association_does_not_exist assert_nothing_raised do - Post.all.merge!(:includes => {:author => :author_addresss}).find(posts(:authorless).id) + Post.all.merge!(includes: { author: :author_addresss }).find(posts(:authorless).id) end end @@ -292,107 +292,107 @@ class EagerAssociationTest < ActiveRecord::TestCase post_id = Comment.where(author_id: nil).where.not(post_id: nil).first.post_id assert_nothing_raised do - Post.preload(:comments => [{:author => :essays}]).find(post_id) + Post.preload(comments: [{ author: :essays }]).find(post_id) end end def test_nested_loading_through_has_one_association - aa = AuthorAddress.all.merge!(:includes => {:author => :posts}).find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }).find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_order - aa = AuthorAddress.all.merge!(:includes => {:author => :posts}, :order => 'author_addresses.id').find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "author_addresses.id").find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_order_on_association - aa = AuthorAddress.all.merge!(:includes => {:author => :posts}, :order => 'authors.id').find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "authors.id").find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_order_on_nested_association - aa = AuthorAddress.all.merge!(:includes => {:author => :posts}, :order => 'posts.id').find(author_addresses(:david_address).id) + aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "posts.id").find(author_addresses(:david_address).id) assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_conditions aa = AuthorAddress.references(:author_addresses).merge( - :includes => {:author => :posts}, - :where => "author_addresses.id > 0" + includes: { author: :posts }, + where: "author_addresses.id > 0" ).find author_addresses(:david_address).id assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_conditions_on_association aa = AuthorAddress.references(:authors).merge( - :includes => {:author => :posts}, - :where => "authors.id > 0" + includes: { author: :posts }, + where: "authors.id > 0" ).find author_addresses(:david_address).id assert_equal aa.author.posts.count, aa.author.posts.length end def test_nested_loading_through_has_one_association_with_conditions_on_nested_association aa = AuthorAddress.references(:posts).merge( - :includes => {:author => :posts}, - :where => "posts.id > 0" + includes: { author: :posts }, + where: "posts.id > 0" ).find author_addresses(:david_address).id assert_equal aa.author.posts.count, aa.author.posts.length end def test_eager_association_loading_with_belongs_to_and_foreign_keys - pets = Pet.all.merge!(:includes => :owner).to_a + pets = Pet.all.merge!(includes: :owner).to_a assert_equal 4, pets.length end def test_eager_association_loading_with_belongs_to - comments = Comment.all.merge!(:includes => :post).to_a + comments = Comment.all.merge!(includes: :post).to_a assert_equal 11, comments.length titles = comments.map { |c| c.post.title } - assert titles.include?(posts(:welcome).title) - assert titles.include?(posts(:sti_post_and_comments).title) + assert_includes titles, posts(:welcome).title + assert_includes titles, posts(:sti_post_and_comments).title end def test_eager_association_loading_with_belongs_to_and_limit - comments = Comment.all.merge!(:includes => :post, :limit => 5, :order => 'comments.id').to_a + comments = Comment.all.merge!(includes: :post, limit: 5, order: "comments.id").to_a assert_equal 5, comments.length assert_equal [1,2,3,5,6], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_conditions - comments = Comment.all.merge!(:includes => :post, :where => 'post_id = 4', :limit => 3, :order => 'comments.id').to_a + comments = Comment.all.merge!(includes: :post, where: "post_id = 4", limit: 3, order: "comments.id").to_a assert_equal 3, comments.length assert_equal [5,6,7], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_offset - comments = Comment.all.merge!(:includes => :post, :limit => 3, :offset => 2, :order => 'comments.id').to_a + comments = Comment.all.merge!(includes: :post, limit: 3, offset: 2, order: "comments.id").to_a assert_equal 3, comments.length assert_equal [3,5,6], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions - comments = Comment.all.merge!(:includes => :post, :where => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id').to_a + comments = Comment.all.merge!(includes: :post, where: "post_id = 4", limit: 3, offset: 1, order: "comments.id").to_a assert_equal 3, comments.length assert_equal [6,7,8], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array - comments = Comment.all.merge!(:includes => :post, :where => ['post_id = ?',4], :limit => 3, :offset => 1, :order => 'comments.id').to_a + comments = Comment.all.merge!(includes: :post, where: ["post_id = ?",4], limit: 3, offset: 1, order: "comments.id").to_a assert_equal 3, comments.length assert_equal [6,7,8], comments.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_conditions_string_with_unquoted_table_name assert_nothing_raised do - Comment.includes(:post).references(:posts).where('posts.id = ?', 4) + Comment.includes(:post).references(:posts).where("posts.id = ?", 4) end end def test_eager_association_loading_with_belongs_to_and_conditions_hash comments = [] assert_nothing_raised do - comments = Comment.all.merge!(:includes => :post, :where => {:posts => {:id => 4}}, :limit => 3, :order => 'comments.id').to_a + comments = Comment.all.merge!(includes: :post, where: { posts: { id: 4 } }, limit: 3, order: "comments.id").to_a end assert_equal 3, comments.length assert_equal [5,6,7], comments.collect(&:id) @@ -402,7 +402,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_association_loading_with_belongs_to_and_conditions_string_with_quoted_table_name - quoted_posts_id= Comment.connection.quote_table_name('posts') + '.' + Comment.connection.quote_column_name('id') + quoted_posts_id= Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id") assert_nothing_raised do Comment.includes(:post).references(:posts).where("#{quoted_posts_id} = ?", 4) end @@ -410,61 +410,61 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_association_loading_with_belongs_to_and_order_string_with_unquoted_table_name assert_nothing_raised do - Comment.all.merge!(:includes => :post, :order => 'posts.id').to_a + Comment.all.merge!(includes: :post, order: "posts.id").to_a end end def test_eager_association_loading_with_belongs_to_and_order_string_with_quoted_table_name - quoted_posts_id= Comment.connection.quote_table_name('posts') + '.' + Comment.connection.quote_column_name('id') + quoted_posts_id= Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id") assert_nothing_raised do Comment.includes(:post).references(:posts).order(quoted_posts_id) end end def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations - posts = Post.all.merge!(:includes => [:author, :very_special_comment], :limit => 1, :order => 'posts.id').to_a + posts = Post.all.merge!(includes: [:author, :very_special_comment], limit: 1, order: "posts.id").to_a assert_equal 1, posts.length assert_equal [1], posts.collect(&:id) end def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations - posts = Post.all.merge!(:includes => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id').to_a + posts = Post.all.merge!(includes: [:author, :very_special_comment], limit: 1, offset: 1, order: "posts.id").to_a assert_equal 1, posts.length assert_equal [2], posts.collect(&:id) end def test_eager_association_loading_with_belongs_to_inferred_foreign_key_from_association_name - author_favorite = AuthorFavorite.all.merge!(:includes => :favorite_author).first + author_favorite = AuthorFavorite.all.merge!(includes: :favorite_author).first assert_equal authors(:mary), assert_no_queries { author_favorite.favorite_author } end def test_eager_load_belongs_to_quotes_table_and_column_names job = Job.includes(:ideal_reference).find jobs(:unicyclist).id references(:michael_unicyclist) - assert_no_queries{ assert_equal references(:michael_unicyclist), job.ideal_reference} + assert_no_queries { assert_equal references(:michael_unicyclist), job.ideal_reference } end def test_eager_load_has_one_quotes_table_and_column_names - michael = Person.all.merge!(:includes => :favourite_reference).find(people(:michael).id) + michael = Person.all.merge!(includes: :favourite_reference).find(people(:michael).id) references(:michael_unicyclist) - assert_no_queries{ assert_equal references(:michael_unicyclist), michael.favourite_reference} + assert_no_queries { assert_equal references(:michael_unicyclist), michael.favourite_reference } end def test_eager_load_has_many_quotes_table_and_column_names - michael = Person.all.merge!(:includes => :references).find(people(:michael).id) + michael = Person.all.merge!(includes: :references).find(people(:michael).id) references(:michael_magician,:michael_unicyclist) - assert_no_queries{ assert_equal references(:michael_magician,:michael_unicyclist), michael.references.sort_by(&:id) } + assert_no_queries { assert_equal references(:michael_magician,:michael_unicyclist), michael.references.sort_by(&:id) } end def test_eager_load_has_many_through_quotes_table_and_column_names - michael = Person.all.merge!(:includes => :jobs).find(people(:michael).id) + michael = Person.all.merge!(includes: :jobs).find(people(:michael).id) jobs(:magician, :unicyclist) - assert_no_queries{ assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) } + assert_no_queries { assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) } end def test_eager_load_has_many_with_string_keys subscriptions = subscriptions(:webster_awdr, :webster_rfr) - subscriber =Subscriber.all.merge!(:includes => :subscriptions).find(subscribers(:second).id) + subscriber =Subscriber.all.merge!(includes: :subscriptions).find(subscribers(:second).id) assert_equal subscriptions, subscriber.subscriptions.sort_by(&:id) end @@ -475,32 +475,32 @@ class EagerAssociationTest < ActiveRecord::TestCase b = Book.create! - Subscription.create!(:subscriber_id => "PL", :book_id => b.id) + Subscription.create!(subscriber_id: "PL", book_id: b.id) s.reload s.book_ids = s.book_ids end def test_eager_load_has_many_through_with_string_keys books = books(:awdr, :rfr) - subscriber = Subscriber.all.merge!(:includes => :books).find(subscribers(:second).id) + subscriber = Subscriber.all.merge!(includes: :books).find(subscribers(:second).id) assert_equal books, subscriber.books.sort_by(&:id) end def test_eager_load_belongs_to_with_string_keys subscriber = subscribers(:second) - subscription = Subscription.all.merge!(:includes => :subscriber).find(subscriptions(:webster_awdr).id) + subscription = Subscription.all.merge!(includes: :subscriber).find(subscriptions(:webster_awdr).id) assert_equal subscriber, subscription.subscriber end def test_eager_association_loading_with_explicit_join - posts = Post.all.merge!(:includes => :comments, :joins => "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", :limit => 1, :order => 'author_id').to_a + posts = Post.all.merge!(includes: :comments, joins: "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", limit: 1, order: "author_id").to_a assert_equal 1, posts.length end def test_eager_with_has_many_through - posts_with_comments = people(:michael).posts.merge(:includes => :comments, :order => 'posts.id').to_a - posts_with_author = people(:michael).posts.merge(:includes => :author, :order => 'posts.id').to_a - posts_with_comments_and_author = people(:michael).posts.merge(:includes => [ :comments, :author ], :order => 'posts.id').to_a + posts_with_comments = people(:michael).posts.merge(includes: :comments, order: "posts.id").to_a + posts_with_author = people(:michael).posts.merge(includes: :author, order: "posts.id").to_a + posts_with_comments_and_author = people(:michael).posts.merge(includes: [ :comments, :author ], order: "posts.id").to_a assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum + post.comments.size } assert_equal authors(:david), assert_no_queries { posts_with_author.first.author } assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author } @@ -508,35 +508,35 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_has_many_through_a_belongs_to_association author = authors(:mary) - Post.create!(:author => author, :title => "TITLE", :body => "BODY") - author.author_favorites.create(:favorite_author_id => 1) - author.author_favorites.create(:favorite_author_id => 2) - posts_with_author_favorites = author.posts.merge(:includes => :author_favorites).to_a + Post.create!(author: author, title: "TITLE", body: "BODY") + author.author_favorites.create(favorite_author_id: 1) + author.author_favorites.create(favorite_author_id: 2) + posts_with_author_favorites = author.posts.merge(includes: :author_favorites).to_a assert_no_queries { posts_with_author_favorites.first.author_favorites.first.author_id } end def test_eager_with_has_many_through_an_sti_join_model - author = Author.all.merge!(:includes => :special_post_comments, :order => 'authors.id').first + author = Author.all.merge!(includes: :special_post_comments, order: "authors.id").first assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments } end def test_eager_with_has_many_through_an_sti_join_model_with_conditions_on_both - author = Author.all.merge!(:includes => :special_nonexistent_post_comments, :order => 'authors.id').first + author = Author.all.merge!(includes: :special_nonexistent_post_comments, order: "authors.id").first assert_equal [], author.special_nonexistent_post_comments end def test_eager_with_has_many_through_join_model_with_conditions - assert_equal Author.all.merge!(:includes => :hello_post_comments, - :order => 'authors.id').first.hello_post_comments.sort_by(&:id), - Author.all.merge!(:order => 'authors.id').first.hello_post_comments.sort_by(&:id) + assert_equal Author.all.merge!(includes: :hello_post_comments, + order: "authors.id").first.hello_post_comments.sort_by(&:id), + Author.all.merge!(order: "authors.id").first.hello_post_comments.sort_by(&:id) end def test_eager_with_has_many_through_join_model_with_conditions_on_top_level - assert_equal comments(:more_greetings), Author.all.merge!(:includes => :comments_with_order_and_conditions).find(authors(:david).id).comments_with_order_and_conditions.first + assert_equal comments(:more_greetings), Author.all.merge!(includes: :comments_with_order_and_conditions).find(authors(:david).id).comments_with_order_and_conditions.first end def test_eager_with_has_many_through_join_model_with_include - author_comments = Author.all.merge!(:includes => :comments_with_include).find(authors(:david).id).comments_with_include.to_a + author_comments = Author.all.merge!(includes: :comments_with_include).find(authors(:david).id).comments_with_include.to_a assert_no_queries do author_comments.first.post.title end @@ -544,7 +544,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_has_many_through_with_conditions_join_model_with_include post_tags = Post.find(posts(:welcome).id).misc_tags - eager_post_tags = Post.all.merge!(:includes => :misc_tags).find(1).misc_tags + eager_post_tags = Post.all.merge!(includes: :misc_tags).find(1).misc_tags assert_equal post_tags, eager_post_tags end @@ -555,67 +555,67 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_has_many_and_limit - posts = Post.all.merge!(:order => 'posts.id asc', :includes => [ :author, :comments ], :limit => 2).to_a + posts = Post.all.merge!(order: "posts.id asc", includes: [ :author, :comments ], limit: 2).to_a assert_equal 2, posts.size assert_equal 3, posts.inject(0) { |sum, post| sum + post.comments.size } end def test_eager_with_has_many_and_limit_and_conditions - posts = Post.all.merge!(:includes => [ :author, :comments ], :limit => 2, :where => "posts.body = 'hello'", :order => "posts.id").to_a + posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: "posts.body = 'hello'", order: "posts.id").to_a assert_equal 2, posts.size assert_equal [4,5], posts.collect(&:id) end def test_eager_with_has_many_and_limit_and_conditions_array - posts = Post.all.merge!(:includes => [ :author, :comments ], :limit => 2, :where => [ "posts.body = ?", 'hello' ], :order => "posts.id").to_a + posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: [ "posts.body = ?", "hello" ], order: "posts.id").to_a assert_equal 2, posts.size assert_equal [4,5], posts.collect(&:id) end def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers - posts = Post.includes(:author, :comments).limit(2).references(:author).where("authors.name = ?", 'David') + posts = Post.includes(:author, :comments).limit(2).references(:author).where("authors.name = ?", "David") assert_equal 2, posts.size - count = Post.includes(:author, :comments).limit(2).references(:author).where("authors.name = ?", 'David').count + count = Post.includes(:author, :comments).limit(2).references(:author).where("authors.name = ?", "David").count assert_equal posts.size, count end def test_eager_with_has_many_and_limit_and_high_offset - posts = Post.all.merge!(:includes => [ :author, :comments ], :limit => 2, :offset => 10, :where => { 'authors.name' => 'David' }).to_a + posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, offset: 10, where: { "authors.name" => "David" }).to_a assert_equal 0, posts.size end def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_array_conditions assert_queries(1) do posts = Post.references(:authors, :comments). - merge(:includes => [ :author, :comments ], :limit => 2, :offset => 10, - :where => [ "authors.name = ? and comments.body = ?", 'David', 'go crazy' ]).to_a + merge(includes: [ :author, :comments ], limit: 2, offset: 10, + where: [ "authors.name = ? and comments.body = ?", "David", "go crazy" ]).to_a assert_equal 0, posts.size end end def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_hash_conditions assert_queries(1) do - posts = Post.all.merge!(:includes => [ :author, :comments ], :limit => 2, :offset => 10, - :where => { 'authors.name' => 'David', 'comments.body' => 'go crazy' }).to_a + posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, offset: 10, + where: { "authors.name" => "David", "comments.body" => "go crazy" }).to_a assert_equal 0, posts.size end end def test_count_eager_with_has_many_and_limit_and_high_offset - posts = Post.all.merge!(:includes => [ :author, :comments ], :limit => 2, :offset => 10, :where => { 'authors.name' => 'David' }).count(:all) + posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, offset: 10, where: { "authors.name" => "David" }).count(:all) assert_equal 0, posts end def test_eager_with_has_many_and_limit_with_no_results - posts = Post.all.merge!(:includes => [ :author, :comments ], :limit => 2, :where => "posts.title = 'magic forest'").to_a + posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: "posts.title = 'magic forest'").to_a assert_equal 0, posts.size end def test_eager_count_performed_on_a_has_many_association_with_multi_table_conditional author = authors(:david) author_posts_without_comments = author.posts.select { |post| post.comments.blank? } - assert_equal author_posts_without_comments.size, author.posts.includes(:comments).where('comments.id is null').references(:comments).count + assert_equal author_posts_without_comments.size, author.posts.includes(:comments).where("comments.id is null").references(:comments).count end def test_eager_count_performed_on_a_has_many_through_association_with_multi_table_conditional @@ -625,13 +625,13 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_has_and_belongs_to_many_and_limit - posts = Post.all.merge!(:includes => :categories, :order => "posts.id", :limit => 3).to_a + posts = Post.all.merge!(includes: :categories, order: "posts.id", limit: 3).to_a assert_equal 3, posts.size assert_equal 2, posts[0].categories.size assert_equal 1, posts[1].categories.size assert_equal 0, posts[2].categories.size - assert posts[0].categories.include?(categories(:technology)) - assert posts[1].categories.include?(categories(:general)) + assert_includes posts[0].categories, categories(:technology) + assert_includes posts[1].categories, categories(:general) end # Since the preloader for habtm gets raw row hashes from the database and then @@ -691,32 +691,32 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_association_loading_with_habtm - posts = Post.all.merge!(:includes => :categories, :order => "posts.id").to_a + posts = Post.all.merge!(includes: :categories, order: "posts.id").to_a assert_equal 2, posts[0].categories.size assert_equal 1, posts[1].categories.size assert_equal 0, posts[2].categories.size - assert posts[0].categories.include?(categories(:technology)) - assert posts[1].categories.include?(categories(:general)) + assert_includes posts[0].categories, categories(:technology) + assert_includes posts[1].categories, categories(:general) end def test_eager_with_inheritance - SpecialPost.all.merge!(:includes => [ :comments ]).to_a + SpecialPost.all.merge!(includes: [ :comments ]).to_a end def test_eager_has_one_with_association_inheritance - post = Post.all.merge!(:includes => [ :very_special_comment ]).find(4) + post = Post.all.merge!(includes: [ :very_special_comment ]).find(4) assert_equal "VerySpecialComment", post.very_special_comment.class.to_s end def test_eager_has_many_with_association_inheritance - post = Post.all.merge!(:includes => [ :special_comments ]).find(4) + post = Post.all.merge!(includes: [ :special_comments ]).find(4) post.special_comments.each do |special_comment| assert special_comment.is_a?(SpecialComment) end end def test_eager_habtm_with_association_inheritance - post = Post.all.merge!(:includes => [ :special_categories ]).find(6) + post = Post.all.merge!(includes: [ :special_categories ]).find(6) assert_equal 1, post.special_categories.size post.special_categories.each do |special_category| assert_equal "SpecialCategory", special_category.class.to_s @@ -725,8 +725,8 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_has_one_dependent_does_not_destroy_dependent assert_not_nil companies(:first_firm).account - f = Firm.all.merge!(:includes => :account, - :where => ["companies.name = ?", "37signals"]).first + f = Firm.all.merge!(includes: :account, + where: ["companies.name = ?", "37signals"]).first assert_not_nil f.account assert_equal companies(:first_firm, :reload).account, f.account end @@ -740,37 +740,37 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_invalid_association_reference assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { - Post.all.merge!(:includes=> :monkeys ).find(6) + Post.all.merge!(includes: :monkeys ).find(6) } assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { - Post.all.merge!(:includes=>[ :monkeys ]).find(6) + Post.all.merge!(includes: [ :monkeys ]).find(6) } assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { - Post.all.merge!(:includes=>[ 'monkeys' ]).find(6) + Post.all.merge!(includes: [ "monkeys" ]).find(6) } assert_raise(ActiveRecord::AssociationNotFoundError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") { - Post.all.merge!(:includes=>[ :monkeys, :elephants ]).find(6) + Post.all.merge!(includes: [ :monkeys, :elephants ]).find(6) } end def test_eager_has_many_through_with_order - tag = OrderedTag.create(name: 'Foo') - post1 = Post.create!(title: 'Beaches', body: "I like beaches!") - post2 = Post.create!(title: 'Pools', body: "I like pools!") + tag = OrderedTag.create(name: "Foo") + post1 = Post.create!(title: "Beaches", body: "I like beaches!") + post2 = Post.create!(title: "Pools", body: "I like pools!") - Tagging.create!(taggable_type: 'Post', taggable_id: post1.id, tag: tag) - Tagging.create!(taggable_type: 'Post', taggable_id: post2.id, tag: tag) + Tagging.create!(taggable_type: "Post", taggable_id: post1.id, tag: tag) + Tagging.create!(taggable_type: "Post", taggable_id: post2.id, tag: tag) tag_with_includes = OrderedTag.includes(:tagged_posts).find(tag.id) assert_equal(tag_with_includes.taggings.map(&:taggable).map(&:title), tag_with_includes.tagged_posts.map(&:title)) end def test_eager_has_many_through_multiple_with_order - tag1 = OrderedTag.create!(name: 'Bar') - tag2 = OrderedTag.create!(name: 'Foo') + tag1 = OrderedTag.create!(name: "Bar") + tag2 = OrderedTag.create!(name: "Foo") - post1 = Post.create!(title: 'Beaches', body: "I like beaches!") - post2 = Post.create!(title: 'Pools', body: "I like pools!") + post1 = Post.create!(title: "Beaches", body: "I like beaches!") + post2 = Post.create!(title: "Pools", body: "I like pools!") Tagging.create!(taggable: post1, tag: tag1) Tagging.create!(taggable: post2, tag: tag1) @@ -786,7 +786,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_default_scope - developer = EagerDeveloperWithDefaultScope.where(:name => 'David').first + developer = EagerDeveloperWithDefaultScope.where(name: "David").first projects = Project.order(:id).to_a assert_no_queries do assert_equal(projects, developer.projects) @@ -794,7 +794,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_default_scope_as_class_method - developer = EagerDeveloperWithClassMethodDefaultScope.where(:name => 'David').first + developer = EagerDeveloperWithClassMethodDefaultScope.where(name: "David").first projects = Project.order(:id).to_a assert_no_queries do assert_equal(projects, developer.projects) @@ -811,7 +811,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_default_scope_as_class_method_using_find_by_method - developer = EagerDeveloperWithClassMethodDefaultScope.find_by(name: 'David') + developer = EagerDeveloperWithClassMethodDefaultScope.find_by(name: "David") projects = Project.order(:id).to_a assert_no_queries do assert_equal(projects, developer.projects) @@ -819,7 +819,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_default_scope_as_lambda - developer = EagerDeveloperWithLambdaDefaultScope.where(:name => 'David').first + developer = EagerDeveloperWithLambdaDefaultScope.where(name: "David").first projects = Project.order(:id).to_a assert_no_queries do assert_equal(projects, developer.projects) @@ -828,8 +828,8 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_with_default_scope_as_block # warm up the habtm cache - EagerDeveloperWithBlockDefaultScope.where(:name => 'David').first.projects - developer = EagerDeveloperWithBlockDefaultScope.where(:name => 'David').first + EagerDeveloperWithBlockDefaultScope.where(name: "David").first.projects + developer = EagerDeveloperWithBlockDefaultScope.where(name: "David").first projects = Project.order(:id).to_a assert_no_queries do assert_equal(projects, developer.projects) @@ -837,7 +837,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_eager_with_default_scope_as_callable - developer = EagerDeveloperWithCallableDefaultScope.where(:name => 'David').first + developer = EagerDeveloperWithCallableDefaultScope.where(name: "David").first projects = Project.order(:id).to_a assert_no_queries do assert_equal(projects, developer.projects) @@ -845,22 +845,22 @@ class EagerAssociationTest < ActiveRecord::TestCase end def find_all_ordered(className, include=nil) - className.all.merge!(:order=>"#{className.table_name}.#{className.primary_key}", :includes=>include).to_a + className.all.merge!(order: "#{className.table_name}.#{className.primary_key}", includes: include).to_a end def test_limited_eager_with_order assert_equal( posts(:thinking, :sti_comments), Post.all.merge!( - :includes => [:author, :comments], :where => { 'authors.name' => 'David' }, - :order => 'UPPER(posts.title)', :limit => 2, :offset => 1 + includes: [:author, :comments], where: { "authors.name" => "David" }, + order: "UPPER(posts.title)", limit: 2, offset: 1 ).to_a ) assert_equal( posts(:sti_post_and_comments, :sti_comments), Post.all.merge!( - :includes => [:author, :comments], :where => { 'authors.name' => 'David' }, - :order => 'UPPER(posts.title) DESC', :limit => 2, :offset => 1 + includes: [:author, :comments], where: { "authors.name" => "David" }, + order: "UPPER(posts.title) DESC", limit: 2, offset: 1 ).to_a ) end @@ -869,15 +869,15 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal( posts(:thinking, :sti_comments), Post.all.merge!( - :includes => [:author, :comments], :where => { 'authors.name' => 'David' }, - :order => ['UPPER(posts.title)', 'posts.id'], :limit => 2, :offset => 1 + includes: [:author, :comments], where: { "authors.name" => "David" }, + order: ["UPPER(posts.title)", "posts.id"], limit: 2, offset: 1 ).to_a ) assert_equal( posts(:sti_post_and_comments, :sti_comments), Post.all.merge!( - :includes => [:author, :comments], :where => { 'authors.name' => 'David' }, - :order => ['UPPER(posts.title) DESC', 'posts.id'], :limit => 2, :offset => 1 + includes: [:author, :comments], where: { "authors.name" => "David" }, + order: ["UPPER(posts.title) DESC", "posts.id"], limit: 2, offset: 1 ).to_a ) end @@ -886,25 +886,25 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_equal( people(:david, :susan), Person.references(:number1_fans_people).merge( - :includes => [:readers, :primary_contact, :number1_fan], - :where => "number1_fans_people.first_name like 'M%'", - :order => 'people.id', :limit => 2, :offset => 0 + includes: [:readers, :primary_contact, :number1_fan], + where: "number1_fans_people.first_name like 'M%'", + order: "people.id", limit: 2, offset: 0 ).to_a ) end def test_polymorphic_type_condition - post = Post.all.merge!(:includes => :taggings).find(posts(:thinking).id) - assert post.taggings.include?(taggings(:thinking_general)) - post = SpecialPost.all.merge!(:includes => :taggings).find(posts(:thinking).id) - assert post.taggings.include?(taggings(:thinking_general)) + post = Post.all.merge!(includes: :taggings).find(posts(:thinking).id) + assert_includes post.taggings, taggings(:thinking_general) + post = SpecialPost.all.merge!(includes: :taggings).find(posts(:thinking).id) + assert_includes post.taggings, taggings(:thinking_general) end def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm # Eager includes of has many and habtm associations aren't necessarily sorted in the same way def assert_equal_after_sort(item1, item2, item3 = nil) - assert_equal(item1.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) - assert_equal(item3.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) if item3 + assert_equal(item1.sort { |a,b| a.id <=> b.id }, item2.sort { |a,b| a.id <=> b.id }) + assert_equal(item3.sort { |a,b| a.id <=> b.id }, item2.sort { |a,b| a.id <=> b.id }) if item3 end # Test regular association, association with conditions, association with # STI, and association with conditions assured not to be true @@ -947,24 +947,24 @@ class EagerAssociationTest < ActiveRecord::TestCase end end def test_eager_with_valid_association_as_string_not_symbol - assert_nothing_raised { Post.all.merge!(:includes => 'comments').to_a } + assert_nothing_raised { Post.all.merge!(includes: "comments").to_a } end def test_eager_with_floating_point_numbers assert_queries(2) do # Before changes, the floating point numbers will be interpreted as table names and will cause this to run in one query - Comment.all.merge!(:where => "123.456 = 123.456", :includes => :post).to_a + Comment.all.merge!(where: "123.456 = 123.456", includes: :post).to_a end end def test_preconfigured_includes_with_belongs_to author = posts(:welcome).author_with_posts - assert_no_queries {assert_equal 5, author.posts.size} + assert_no_queries { assert_equal 5, author.posts.size } end def test_preconfigured_includes_with_has_one comment = posts(:sti_comments).very_special_comment_with_post - assert_no_queries {assert_equal posts(:sti_comments), comment.post} + assert_no_queries { assert_equal posts(:sti_comments), comment.post } end def test_eager_association_with_scope_with_joins @@ -1006,13 +1006,13 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_association_loading_notification - notifications = messages_for('instantiation.active_record') do - Developer.all.merge!(:includes => 'projects', :where => { 'developers_projects.access_level' => 1 }, :limit => 5).to_a.size + notifications = messages_for("instantiation.active_record") do + Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a.size end message = notifications.first payload = message.last - count = Developer.all.merge!(:includes => 'projects', :where => { 'developers_projects.access_level' => 1 }, :limit => 5).to_a.size + count = Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a.size # eagerloaded row count should be greater than just developer count assert_operator payload[:record_count], :>, count @@ -1020,7 +1020,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_base_messages - notifications = messages_for('instantiation.active_record') do + notifications = messages_for("instantiation.active_record") do Developer.all.to_a end message = notifications.first @@ -1048,55 +1048,55 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_conditions_on_join_table_with_include_and_limit - assert_equal 3, Developer.all.merge!(:includes => 'projects', :where => { 'developers_projects.access_level' => 1 }, :limit => 5).to_a.size + assert_equal 3, Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a.size end def test_dont_create_temporary_active_record_instances Developer.instance_count = 0 - developers = Developer.all.merge!(:includes => 'projects', :where => { 'developers_projects.access_level' => 1 }, :limit => 5).to_a + developers = Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a assert_equal developers.count, Developer.instance_count end def test_order_on_join_table_with_include_and_limit - assert_equal 5, Developer.all.merge!(:includes => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).to_a.size + assert_equal 5, Developer.all.merge!(includes: "projects", order: "developers_projects.joined_on DESC", limit: 5).to_a.size end def test_eager_loading_with_order_on_joined_table_preloads posts = assert_queries(2) do - Post.all.merge!(:joins => :comments, :includes => :author, :order => 'comments.id DESC').to_a + Post.all.merge!(joins: :comments, includes: :author, order: "comments.id DESC").to_a end assert_equal posts(:eager_other), posts[1] - assert_equal authors(:mary), assert_no_queries { posts[1].author} + assert_equal authors(:mary), assert_no_queries { posts[1].author } end def test_eager_loading_with_conditions_on_joined_table_preloads posts = assert_queries(2) do - Post.all.merge!(:select => 'distinct posts.*', :includes => :author, :joins => [:comments], :where => "comments.body like 'Thank you%'", :order => 'posts.id').to_a + Post.all.merge!(select: "distinct posts.*", includes: :author, joins: [:comments], where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } posts = assert_queries(2) do - Post.all.merge!(:select => 'distinct posts.*', :includes => :author, :joins => [:comments], :where => "comments.body like 'Thank you%'", :order => 'posts.id').to_a + Post.all.merge!(select: "distinct posts.*", includes: :author, joins: [:comments], where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } posts = assert_queries(2) do - Post.all.merge!(:includes => :author, :joins => {:taggings => :tag}, :where => "tags.name = 'General'", :order => 'posts.id').to_a + Post.all.merge!(includes: :author, joins: { taggings: :tag }, where: "tags.name = 'General'", order: "posts.id").to_a end assert_equal posts(:welcome, :thinking), posts posts = assert_queries(2) do - Post.all.merge!(:includes => :author, :joins => {:taggings => {:tag => :taggings}}, :where => "taggings_tags.super_tag_id=2", :order => 'posts.id').to_a + Post.all.merge!(includes: :author, joins: { taggings: { tag: :taggings } }, where: "taggings_tags.super_tag_id=2", order: "posts.id").to_a end assert_equal posts(:welcome, :thinking), posts end def test_preload_has_many_with_association_condition_and_default_scope - post = Post.create!(:title => 'Beaches', :body => "I like beaches!") - Reader.create! :person => people(:david), :post => post - LazyReader.create! :person => people(:susan), :post => post + post = Post.create!(title: "Beaches", body: "I like beaches!") + Reader.create! person: people(:david), post: post + LazyReader.create! person: people(:susan), post: post assert_equal 1, post.lazy_readers.to_a.size assert_equal 2, post.lazy_readers_skimmers_or_not.to_a.size @@ -1107,39 +1107,39 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_eager_loading_with_conditions_on_string_joined_table_preloads posts = assert_queries(2) do - Post.all.merge!(:select => 'distinct posts.*', :includes => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :where => "comments.body like 'Thank you%'", :order => 'posts.id').to_a + Post.all.merge!(select: "distinct posts.*", includes: :author, joins: "INNER JOIN comments on comments.post_id = posts.id", where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } posts = assert_queries(2) do - Post.all.merge!(:select => 'distinct posts.*', :includes => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :where => "comments.body like 'Thank you%'", :order => 'posts.id').to_a + Post.all.merge!(select: "distinct posts.*", includes: :author, joins: ["INNER JOIN comments on comments.post_id = posts.id"], where: "comments.body like 'Thank you%'", order: "posts.id").to_a end assert_equal [posts(:welcome)], posts - assert_equal authors(:david), assert_no_queries { posts[0].author} + assert_equal authors(:david), assert_no_queries { posts[0].author } end def test_eager_loading_with_select_on_joined_table_preloads posts = assert_queries(2) do - Post.all.merge!(:select => 'posts.*, authors.name as author_name', :includes => :comments, :joins => :author, :order => 'posts.id').to_a + Post.all.merge!(select: "posts.*, authors.name as author_name", includes: :comments, joins: :author, order: "posts.id").to_a end - assert_equal 'David', posts[0].author_name - assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments} + assert_equal "David", posts[0].author_name + assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments } end def test_eager_loading_with_conditions_on_join_model_preloads authors = assert_queries(2) do - Author.all.merge!(:includes => :author_address, :joins => :comments, :where => "posts.title like 'Welcome%'").to_a + Author.all.merge!(includes: :author_address, joins: :comments, where: "posts.title like 'Welcome%'").to_a end assert_equal authors(:david), authors[0] assert_equal author_addresses(:david_address), authors[0].author_address end def test_preload_belongs_to_uses_exclusive_scope - people = Person.males.merge(:includes => :primary_contact).to_a + people = Person.males.merge(includes: :primary_contact).to_a assert_not_equal people.length, 0 people.each do |person| - assert_no_queries {assert_not_nil person.primary_contact} + assert_no_queries { assert_not_nil person.primary_contact } assert_equal Person.find(person.id).primary_contact, person.primary_contact end end @@ -1163,9 +1163,9 @@ class EagerAssociationTest < ActiveRecord::TestCase expected = Firm.find(1).clients_using_primary_key.sort_by(&:name) # Oracle adapter truncates alias to 30 characters if current_adapter?(:OracleAdapter) - firm = Firm.all.merge!(:includes => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies'[0,30]+'.name').find(1) + firm = Firm.all.merge!(includes: :clients_using_primary_key, order: "clients_using_primary_keys_companies"[0,30]+".name").find(1) else - firm = Firm.all.merge!(:includes => :clients_using_primary_key, :order => 'clients_using_primary_keys_companies.name').find(1) + firm = Firm.all.merge!(includes: :clients_using_primary_key, order: "clients_using_primary_keys_companies.name").find(1) end assert_no_queries do assert_equal expected, firm.clients_using_primary_key @@ -1174,7 +1174,7 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_preload_has_one_using_primary_key expected = accounts(:signals37) - firm = Firm.all.merge!(:includes => :account_using_primary_key, :order => 'companies.id').first + firm = Firm.all.merge!(includes: :account_using_primary_key, order: "companies.id").first assert_no_queries do assert_equal expected, firm.account_using_primary_key end @@ -1182,35 +1182,35 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_include_has_one_using_primary_key expected = accounts(:signals37) - firm = Firm.all.merge!(:includes => :account_using_primary_key, :order => 'accounts.id').to_a.detect {|f| f.id == 1} + firm = Firm.all.merge!(includes: :account_using_primary_key, order: "accounts.id").to_a.detect { |f| f.id == 1 } assert_no_queries do assert_equal expected, firm.account_using_primary_key end end def test_preloading_empty_belongs_to - c = Client.create!(:name => 'Foo', :client_of => Company.maximum(:id) + 1) + c = Client.create!(name: "Foo", client_of: Company.maximum(:id) + 1) client = assert_queries(2) { Client.preload(:firm).find(c.id) } assert_no_queries { assert_nil client.firm } end def test_preloading_empty_belongs_to_polymorphic - t = Tagging.create!(:taggable_type => 'Post', :taggable_id => Post.maximum(:id) + 1, :tag => tags(:general)) + t = Tagging.create!(taggable_type: "Post", taggable_id: Post.maximum(:id) + 1, tag: tags(:general)) tagging = assert_queries(2) { Tagging.preload(:taggable).find(t.id) } assert_no_queries { assert_nil tagging.taggable } end def test_preloading_through_empty_belongs_to - c = Client.create!(:name => 'Foo', :client_of => Company.maximum(:id) + 1) + c = Client.create!(name: "Foo", client_of: Company.maximum(:id) + 1) client = assert_queries(2) { Client.preload(:accounts).find(c.id) } assert_no_queries { assert client.accounts.empty? } end def test_preloading_has_many_through_with_distinct - mary = Author.includes(:unique_categorized_posts).where(:id => authors(:mary).id).first + mary = Author.includes(:unique_categorized_posts).where(id: authors(:mary).id).first assert_equal 1, mary.unique_categorized_posts.length assert_equal 1, mary.unique_categorized_post_ids.length end @@ -1238,13 +1238,13 @@ class EagerAssociationTest < ActiveRecord::TestCase groucho = members(:groucho) sponsor = assert_queries(2) { - Sponsor.includes(:thing).where(:id => sponsor.id).first + Sponsor.includes(:thing).where(id: sponsor.id).first } assert_no_queries { assert_equal groucho, sponsor.thing } end def test_joins_with_includes_should_preload_via_joins - post = assert_queries(1) { Post.includes(:comments).joins(:comments).order('posts.id desc').to_a.first } + post = assert_queries(1) { Post.includes(:comments).joins(:comments).order("posts.id desc").to_a.first } assert_queries(0) do assert_not_equal 0, post.comments.to_a.count @@ -1253,16 +1253,16 @@ class EagerAssociationTest < ActiveRecord::TestCase def test_join_eager_with_empty_order_should_generate_valid_sql assert_nothing_raised do - Post.includes(:comments).order("").where(:comments => {:body => "Thank you for the welcome"}).first + Post.includes(:comments).order("").where(comments: { body: "Thank you for the welcome" }).first end end def test_deep_including_through_habtm # warm up habtm cache - posts = Post.all.merge!(:includes => {:categories => :categorizations}, :order => "posts.id").to_a + posts = Post.all.merge!(includes: { categories: :categorizations }, order: "posts.id").to_a posts[0].categories[0].categorizations.length - posts = Post.all.merge!(:includes => {:categories => :categorizations}, :order => "posts.id").to_a + posts = Post.all.merge!(includes: { categories: :categorizations }, order: "posts.id").to_a assert_no_queries { assert_equal 2, posts[0].categories[0].categorizations.length } assert_no_queries { assert_equal 1, posts[0].categories[1].categorizations.length } assert_no_queries { assert_equal 2, posts[1].categories[0].categorizations.length } @@ -1279,19 +1279,19 @@ class EagerAssociationTest < ActiveRecord::TestCase end test "scoping with a circular preload" do - assert_equal Comment.find(1), Comment.preload(:post => :comments).scoping { Comment.find(1) } + assert_equal Comment.find(1), Comment.preload(post: :comments).scoping { Comment.find(1) } end test "circular preload does not modify unscoped" do expected = FirstPost.unscoped.find(2) - FirstPost.preload(:comments => :first_post).find(1) + FirstPost.preload(comments: :first_post).find(1) assert_equal expected, FirstPost.unscoped.find(2) end test "preload ignores the scoping" do assert_equal( Comment.find(1).post, - Post.where('1 = 0').scoping { Comment.preload(:post).find(1).post } + Post.where("1 = 0").scoping { Comment.preload(:post).find(1).post } ) end @@ -1316,10 +1316,10 @@ class EagerAssociationTest < ActiveRecord::TestCase end test "works in combination with order(:symbol) and reorder(:symbol)" do - author = Author.includes(:posts).references(:posts).order(:name).find_by('posts.title IS NOT NULL') + author = Author.includes(:posts).references(:posts).order(:name).find_by("posts.title IS NOT NULL") assert_equal authors(:bob), author - author = Author.includes(:posts).references(:posts).reorder(:name).find_by('posts.title IS NOT NULL') + author = Author.includes(:posts).references(:posts).reorder(:name).find_by("posts.title IS NOT NULL") assert_equal authors(:bob), author end @@ -1360,7 +1360,7 @@ class EagerAssociationTest < ActiveRecord::TestCase test "including associations with where.not adds implicit references" do author = assert_queries(2) { - Author.includes(:posts).where.not(posts: { title: 'Welcome to the weblog'} ).last + Author.includes(:posts).where.not(posts: { title: "Welcome to the weblog" } ).last } assert_no_queries { @@ -1394,7 +1394,7 @@ class EagerAssociationTest < ActiveRecord::TestCase exception = assert_raises(ArgumentError) do Author.preload(10).to_a end - assert_equal('10 was not recognized for preload', exception.message) + assert_equal("10 was not recognized for preload", exception.message) end test "associations with extensions are not instance dependent" do @@ -1424,6 +1424,24 @@ class EagerAssociationTest < ActiveRecord::TestCase assert david.readonly_comments.first.readonly? end + test "eager-loading non-readonly association" do + # has_one + firm = Firm.where(id: "1").eager_load(:account).first! + assert_not firm.account.readonly? + + # has_and_belongs_to_many + project = Project.where(id: "2").eager_load(:developers).first! + assert_not project.developers.first.readonly? + + # has_many :through + david = Author.where(id: "1").eager_load(:comments).first! + assert_not david.comments.first.readonly? + + # belongs_to + post = Post.where(id: "1").eager_load(:author).first! + assert_not post.author.readonly? + end + test "eager-loading readonly association" do # has-one firm = Firm.where(id: "1").eager_load(:readonly_account).first! @@ -1438,17 +1456,17 @@ class EagerAssociationTest < ActiveRecord::TestCase assert david.readonly_comments.first.readonly? # belongs_to - post = Post.where(id: "1").eager_load(:author).first! - assert post.author.readonly? + post = Post.where(id: "1").eager_load(:readonly_author).first! + assert post.readonly_author.readonly? end test "preloading a polymorphic association with references to the associated table" do - post = Post.includes(:tags).references(:tags).where('tags.name = ?', 'General').first + post = Post.includes(:tags).references(:tags).where("tags.name = ?", "General").first assert_equal posts(:welcome), post end test "eager-loading a polymorphic association with references to the associated table" do - post = Post.eager_load(:tags).where('tags.name = ?', 'General').first + post = Post.eager_load(:tags).where("tags.name = ?", "General").first assert_equal posts(:welcome), post end diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index b161cde335..cc86e1a16d 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -1,10 +1,10 @@ require "cases/helper" -require 'models/post' -require 'models/comment' -require 'models/project' -require 'models/developer' -require 'models/computer' -require 'models/company_in_module' +require "models/post" +require "models/comment" +require "models/project" +require "models/developer" +require "models/computer" +require "models/company_in_module" class AssociationsExtensionsTest < ActiveRecord::TestCase fixtures :projects, :developers, :developers_projects, :comments, :posts @@ -63,19 +63,19 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase extend!(Developer) extend!(MyApplication::Business::Developer) - assert Object.const_get 'DeveloperAssociationNameAssociationExtension' - assert MyApplication::Business.const_get 'DeveloperAssociationNameAssociationExtension' + assert Object.const_get "DeveloperAssociationNameAssociationExtension" + assert MyApplication::Business.const_get "DeveloperAssociationNameAssociationExtension" end def test_proxy_association_after_scoped post = posts(:welcome) assert_equal post.association(:comments), post.comments.the_association - assert_equal post.association(:comments), post.comments.where('1=1').the_association + assert_equal post.association(:comments), post.comments.where("1=1").the_association end private def extend!(model) - ActiveRecord::Associations::Builder::HasMany.define_extensions(model, :association_name) { } + ActiveRecord::Associations::Builder::HasMany.define_extensions(model, :association_name) {} end end diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 1bbca84bb2..06fc7a4388 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -1,84 +1,85 @@ require "cases/helper" -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/company' -require 'models/course' -require 'models/customer' -require 'models/order' -require 'models/categorization' -require 'models/category' -require 'models/post' -require 'models/author' -require 'models/tag' -require 'models/tagging' -require 'models/parrot' -require 'models/person' -require 'models/pirate' -require 'models/professor' -require 'models/treasure' -require 'models/price_estimate' -require 'models/club' -require 'models/member' -require 'models/membership' -require 'models/sponsor' -require 'models/country' -require 'models/treaty' -require 'models/vertex' -require 'models/publisher' -require 'models/publisher/article' -require 'models/publisher/magazine' -require 'active_support/core_ext/string/conversions' +require "models/developer" +require "models/computer" +require "models/project" +require "models/company" +require "models/course" +require "models/customer" +require "models/order" +require "models/categorization" +require "models/category" +require "models/post" +require "models/author" +require "models/tag" +require "models/tagging" +require "models/parrot" +require "models/person" +require "models/pirate" +require "models/professor" +require "models/treasure" +require "models/price_estimate" +require "models/club" +require "models/user" +require "models/member" +require "models/membership" +require "models/sponsor" +require "models/country" +require "models/treaty" +require "models/vertex" +require "models/publisher" +require "models/publisher/article" +require "models/publisher/magazine" +require "active_support/core_ext/string/conversions" class ProjectWithAfterCreateHook < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" has_and_belongs_to_many :developers, - :class_name => "DeveloperForProjectWithAfterCreateHook", - :join_table => "developers_projects", - :foreign_key => "project_id", - :association_foreign_key => "developer_id" + class_name: "DeveloperForProjectWithAfterCreateHook", + join_table: "developers_projects", + foreign_key: "project_id", + association_foreign_key: "developer_id" after_create :add_david def add_david - david = DeveloperForProjectWithAfterCreateHook.find_by_name('David') + david = DeveloperForProjectWithAfterCreateHook.find_by_name("David") david.projects << self end end class DeveloperForProjectWithAfterCreateHook < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" has_and_belongs_to_many :projects, - :class_name => "ProjectWithAfterCreateHook", - :join_table => "developers_projects", - :association_foreign_key => "project_id", - :foreign_key => "developer_id" + class_name: "ProjectWithAfterCreateHook", + join_table: "developers_projects", + association_foreign_key: "project_id", + foreign_key: "developer_id" end class ProjectWithSymbolsForKeys < ActiveRecord::Base - self.table_name = 'projects' + self.table_name = "projects" has_and_belongs_to_many :developers, - :class_name => "DeveloperWithSymbolsForKeys", - :join_table => :developers_projects, - :foreign_key => :project_id, - :association_foreign_key => "developer_id" + class_name: "DeveloperWithSymbolsForKeys", + join_table: :developers_projects, + foreign_key: :project_id, + association_foreign_key: "developer_id" end class DeveloperWithSymbolsForKeys < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" has_and_belongs_to_many :projects, - :class_name => "ProjectWithSymbolsForKeys", - :join_table => :developers_projects, - :association_foreign_key => :project_id, - :foreign_key => "developer_id" + class_name: "ProjectWithSymbolsForKeys", + join_table: :developers_projects, + association_foreign_key: :project_id, + foreign_key: "developer_id" end class SubDeveloper < Developer - self.table_name = 'developers' + self.table_name = "developers" has_and_belongs_to_many :special_projects, - :join_table => 'developers_projects', - :foreign_key => "project_id", - :association_foreign_key => "developer_id" + join_table: "developers_projects", + foreign_key: "project_id", + association_foreign_key: "developer_id" end class DeveloperWithSymbolClassName < Developer @@ -88,7 +89,7 @@ end class DeveloperWithExtendOption < Developer module NamedExtension def category - 'sns' + "sns" end end @@ -96,8 +97,8 @@ class DeveloperWithExtendOption < Developer end class ProjectUnscopingDavidDefaultScope < ActiveRecord::Base - self.table_name = 'projects' - has_and_belongs_to_many :developers, -> { unscope(where: 'name') }, + self.table_name = "projects" + has_and_belongs_to_many :developers, -> { unscope(where: "name") }, class_name: "LazyBlockDeveloperCalledDavid", join_table: "developers_projects", foreign_key: "project_id", @@ -109,14 +110,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings, :computers def setup_data_for_habtm_case - ActiveRecord::Base.connection.execute('delete from countries_treaties') + ActiveRecord::Base.connection.execute("delete from countries_treaties") - country = Country.new(:name => 'India') - country.country_id = 'c1' + country = Country.new(name: "India") + country.country_id = "c1" country.save! - treaty = Treaty.new(:name => 'peace') - treaty.treaty_id = 't1' + treaty = Treaty.new(name: "peace") + treaty.treaty_id = "t1" country.treaties << treaty end @@ -130,33 +131,33 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase setup_data_for_habtm_case con = ActiveRecord::Base.connection - sql = 'select * from countries_treaties' + sql = "select * from countries_treaties" record = con.select_rows(sql).last - assert_equal 'c1', record[0] - assert_equal 't1', record[1] + assert_equal "c1", record[0] + assert_equal "t1", record[1] end def test_proper_usage_of_primary_keys_and_join_table setup_data_for_habtm_case - assert_equal 'country_id', Country.primary_key - assert_equal 'treaty_id', Treaty.primary_key + assert_equal "country_id", Country.primary_key + assert_equal "treaty_id", Treaty.primary_key country = Country.first assert_equal 1, country.treaties.count end def test_join_table_composite_primary_key_should_not_warn - country = Country.new(:name => 'India') - country.country_id = 'c1' + country = Country.new(name: "India") + country.country_id = "c1" country.save! - treaty = Treaty.new(:name => 'peace') - treaty.treaty_id = 't1' + treaty = Treaty.new(name: "peace") + treaty.treaty_id = "t1" warning = capture(:stderr) do country.treaties << treaty end - assert_no_match(/WARNING: Rails does not support composite primary key\./, warning) + assert_no_match(/WARNING: Active Record does not support composite primary key\./, warning) end def test_has_and_belongs_to_many @@ -168,7 +169,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase active_record = Project.find(1) assert !active_record.developers.empty? assert_equal 3, active_record.developers.size - assert active_record.developers.include?(david) + assert_includes active_record.developers, david end def test_adding_single @@ -257,7 +258,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_habtm_saving_multiple_relationships new_project = Project.new("name" => "Grimetime") amount_of_developers = 4 - developers = (0...amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }.reverse + developers = (0...amount_of_developers).collect { |i| Developer.create(name: "JME #{i}") }.reverse new_project.developer_ids = [developers[0].id, developers[1].id] new_project.developers_with_callback_ids = [developers[2].id, developers[3].id] @@ -282,11 +283,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_habtm_collection_size_from_params - devel = Developer.new({ + devel = Developer.new( projects_attributes: { - '0' => {} - } - }) + "0" => {} + }) assert_equal 1, devel.projects.size end @@ -322,9 +322,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_build_by_new_record - devel = Developer.new(:name => "Marcel", :salary => 75000) - devel.projects.build(:name => "Make bed") - proj2 = devel.projects.build(:name => "Lie in it") + devel = Developer.new(name: "Marcel", salary: 75000) + devel.projects.build(name: "Make bed") + proj2 = devel.projects.build(name: "Lie in it") assert_equal devel.projects.last, proj2 assert !proj2.persisted? devel.save @@ -347,9 +347,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_create_by_new_record - devel = Developer.new(:name => "Marcel", :salary => 75000) - devel.projects.build(:name => "Make bed") - proj2 = devel.projects.build(:name => "Lie in it") + devel = Developer.new(name: "Marcel", salary: 75000) + devel.projects.build(name: "Make bed") + proj2 = devel.projects.build(name: "Lie in it") assert_equal devel.projects.last, proj2 assert !proj2.persisted? devel.save @@ -361,16 +361,16 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_creation_respects_hash_condition # in Oracle '' is saved as null therefore need to save ' ' in not null column - post = categories(:general).post_with_conditions.build(:body => ' ') + post = categories(:general).post_with_conditions.build(body: " ") assert post.save - assert_equal 'Yet Another Testing Title', post.title + assert_equal "Yet Another Testing Title", post.title # in Oracle '' is saved as null therefore need to save ' ' in not null column - another_post = categories(:general).post_with_conditions.create(:body => ' ') + another_post = categories(:general).post_with_conditions.create(body: " ") assert another_post.persisted? - assert_equal 'Yet Another Testing Title', another_post.title + assert_equal "Yet Another Testing Title", another_post.title end def test_distinct_after_the_fact @@ -544,7 +544,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_no_queries(ignore_none: false) do assert project.developers.loaded? - assert project.developers.include?(developer) + assert_includes project.developers, developer end end @@ -555,14 +555,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase project.reload assert ! project.developers.loaded? assert_queries(1) do - assert project.developers.include?(developer) + assert_includes project.developers, developer end assert ! project.developers.loaded? end def test_include_returns_false_for_non_matching_record_to_verify_scoping project = projects(:active_record) - developer = Developer.create :name => "Bryan", :salary => 50_000 + developer = Developer.create name: "Bryan", salary: 50_000 assert ! project.developers.loaded? assert ! project.developers.include?(developer) @@ -576,32 +576,32 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_dynamic_find_should_respect_association_order # Developers are ordered 'name DESC, id DESC' - high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis') + high_id_jamis = projects(:active_record).developers.create(name: "Jamis") - assert_equal high_id_jamis, projects(:active_record).developers.merge(:where => "name = 'Jamis'").first - assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis') + assert_equal high_id_jamis, projects(:active_record).developers.merge(where: "name = 'Jamis'").first + assert_equal high_id_jamis, projects(:active_record).developers.find_by_name("Jamis") end def test_find_should_append_to_association_order - ordered_developers = projects(:active_record).developers.order('projects.id') - assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values + ordered_developers = projects(:active_record).developers.order("projects.id") + assert_equal ["developers.name desc, developers.id desc", "projects.id"], ordered_developers.order_values end def test_dynamic_find_all_should_respect_readonly_access - projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid?} + projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid? } projects(:active_record).readonly_developers.each(&:readonly?) end def test_new_with_values_in_collection - jamis = DeveloperForProjectWithAfterCreateHook.find_by_name('Jamis') - david = DeveloperForProjectWithAfterCreateHook.find_by_name('David') - project = ProjectWithAfterCreateHook.new(:name => "Cooking with Bertie") + jamis = DeveloperForProjectWithAfterCreateHook.find_by_name("Jamis") + david = DeveloperForProjectWithAfterCreateHook.find_by_name("David") + project = ProjectWithAfterCreateHook.new(name: "Cooking with Bertie") project.developers << jamis project.save! project.reload - assert project.developers.include?(jamis) - assert project.developers.include?(david) + assert_includes project.developers, jamis + assert_includes project.developers, david end def test_find_in_association_with_options @@ -612,8 +612,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_association_with_extend_option - eponine = DeveloperWithExtendOption.create(name: 'Eponine') - assert_equal 'sns', eponine.projects.category + eponine = DeveloperWithExtendOption.create(name: "Eponine") + assert_equal "sns", eponine.projects.category end def test_replace_with_less @@ -628,7 +628,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase david.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")] david.save assert_equal 2, david.projects.length - assert !david.projects.include?(projects(:active_record)) + assert_not_includes david.projects, projects(:active_record) end def test_replace_on_new_object @@ -646,9 +646,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase developer.special_projects << special_project developer.reload - assert developer.projects.include?(special_project) - assert developer.special_projects.include?(special_project) - assert !developer.special_projects.include?(other_project) + assert_includes developer.projects, special_project + assert_includes developer.special_projects, special_project + assert_not_includes developer.special_projects, other_project end def test_symbol_join_table @@ -689,7 +689,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_habtm_respects_select_query_method - assert_equal ['id'], developers(:david).projects.select(:id).first.attributes.keys + assert_equal ["id"], developers(:david).projects.select(:id).first.attributes.keys end def test_join_table_alias @@ -700,8 +700,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal( 3, Developer.references(:developers_projects_join).merge( - :includes => {:projects => :developers}, - :where => 'projects_developers_projects_join.joined_on IS NOT NULL' + includes: { projects: :developers }, + where: "projects_developers_projects_join.joined_on IS NOT NULL" ).to_a.size ) end @@ -720,15 +720,15 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal( 3, Developer.references(:developers_projects_join).merge( - :includes => {:projects => :developers}, :where => 'projects_developers_projects_join.joined_on IS NOT NULL', - :group => group.join(",") + includes: { projects: :developers }, where: "projects_developers_projects_join.joined_on IS NOT NULL", + group: group.join(",") ).to_a.size ) end def test_find_grouped - all_posts_from_category1 = Post.all.merge!(:where => "category_id = 1", :joins => :categories).to_a - grouped_posts_of_category1 = Post.all.merge!(:where => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories).to_a + all_posts_from_category1 = Post.all.merge!(where: "category_id = 1", joins: :categories).to_a + grouped_posts_of_category1 = Post.all.merge!(where: "category_id = 1", group: "author_id", select: "count(posts.id) as posts_count", joins: :categories).to_a assert_equal 5, all_posts_from_category1.size assert_equal 2, grouped_posts_of_category1.size end @@ -775,7 +775,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_assign_ids_ignoring_blanks developer = Developer.new("name" => "Joe") - developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, ''] + developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, ""] developer.save developer.reload assert_equal 2, developer.projects.length @@ -795,8 +795,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_symbols_as_keys - developer = DeveloperWithSymbolsForKeys.new(:name => 'David') - project = ProjectWithSymbolsForKeys.new(:name => 'Rails Testing') + developer = DeveloperWithSymbolsForKeys.new(name: "David") + project = ProjectWithSymbolsForKeys.new(name: "Rails Testing") project.developers << developer project.save! @@ -809,7 +809,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_dynamic_find_should_respect_association_include # SQL error in sort clause if :include is not included # due to Unknown column 'authors.id' - assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog') + assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title("Welcome to the weblog") end def test_count @@ -841,12 +841,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase end def test_attributes_are_being_set_when_initialized_from_habtm_association_with_where_clause - new_developer = projects(:action_controller).developers.where(:name => "Marcelo").build + new_developer = projects(:action_controller).developers.where(name: "Marcelo").build assert_equal new_developer.name, "Marcelo" end def test_attributes_are_being_set_when_initialized_from_habtm_association_with_multiple_where_clauses - new_developer = projects(:action_controller).developers.where(:name => "Marcelo").where(:salary => 90_000).build + new_developer = projects(:action_controller).developers.where(name: "Marcelo").where(salary: 90_000).build assert_equal new_developer.name, "Marcelo" assert_equal new_developer.salary, 90_000 end @@ -854,7 +854,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_include_method_in_has_and_belongs_to_many_association_should_return_true_for_instance_added_with_build project = Project.new developer = project.developers.build - assert project.developers.include?(developer) + assert_includes project.developers, developer end def test_destruction_does_not_error_without_primary_key @@ -871,7 +871,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase projects = Developer.new.projects assert_no_queries(ignore_none: false) do assert_equal [], projects - assert_equal [], projects.where(title: 'omg') + assert_equal [], projects.where(title: "omg") assert_equal [], projects.pluck(:title) assert_equal 0, projects.count end @@ -885,7 +885,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase treasure.valid? assert_equal 1, treasure.rich_people.size - assert_nil rich_person.first_name, 'should not run associated person validation on create when validate: false' + assert_nil rich_person.first_name, "should not run associated person validation on create when validate: false" end def test_association_with_validate_false_does_not_run_associated_validation_callbacks_on_update @@ -898,11 +898,11 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase treasure.valid? assert_equal 1, treasure.rich_people.size - assert_equal person_first_name, rich_person.first_name, 'should not run associated person validation on update when validate: false' + assert_equal person_first_name, rich_person.first_name, "should not run associated person validation on update when validate: false" end def test_custom_join_table - assert_equal 'edges', Vertex.reflect_on_association(:sources).join_table + assert_equal "edges", Vertex.reflect_on_association(:sources).join_table end def test_has_and_belongs_to_many_in_a_namespaced_model_pointing_to_a_namespaced_model @@ -926,11 +926,11 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_redefine_habtm child = SubDeveloper.new("name" => "Aredridel") child.special_projects << SpecialProject.new("name" => "Special Project") - assert child.save, 'child object should be saved' + assert child.save, "child object should be saved" end def test_habtm_with_reflection_using_class_name_and_fixtures - assert_not_nil Developer._reflections['shared_computers'] + assert_not_nil Developer._reflections["shared_computers"] # Checking the fixture for named association is important here, because it's the only way # we've been able to reproduce this bug assert_not_nil File.read(File.expand_path("../../../fixtures/developers.yml", __FILE__)).index("shared_computers") @@ -995,4 +995,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase Project.first.developers_required_by_default.create!(name: "Sean", salary: 50000) end end + + def test_association_name_is_the_same_as_join_table_name + user = User.create! + assert_nothing_raised { user.jobs_pool.clear } + end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 7ec0dfce7a..c1e04714fb 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1,43 +1,43 @@ require "cases/helper" -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/company' -require 'models/contract' -require 'models/topic' -require 'models/reply' -require 'models/category' -require 'models/image' -require 'models/post' -require 'models/author' -require 'models/essay' -require 'models/comment' -require 'models/person' -require 'models/reader' -require 'models/tagging' -require 'models/tag' -require 'models/invoice' -require 'models/line_item' -require 'models/car' -require 'models/bulb' -require 'models/engine' -require 'models/categorization' -require 'models/minivan' -require 'models/speedometer' -require 'models/reference' -require 'models/job' -require 'models/college' -require 'models/student' -require 'models/pirate' -require 'models/ship' -require 'models/ship_part' -require 'models/treasure' -require 'models/parrot' -require 'models/tyre' -require 'models/subscriber' -require 'models/subscription' -require 'models/zine' -require 'models/interest' +require "models/developer" +require "models/computer" +require "models/project" +require "models/company" +require "models/contract" +require "models/topic" +require "models/reply" +require "models/category" +require "models/image" +require "models/post" +require "models/author" +require "models/essay" +require "models/comment" +require "models/person" +require "models/reader" +require "models/tagging" +require "models/tag" +require "models/invoice" +require "models/line_item" +require "models/car" +require "models/bulb" +require "models/engine" +require "models/categorization" +require "models/minivan" +require "models/speedometer" +require "models/reference" +require "models/job" +require "models/college" +require "models/student" +require "models/pirate" +require "models/ship" +require "models/ship_part" +require "models/treasure" +require "models/parrot" +require "models/tyre" +require "models/subscriber" +require "models/subscription" +require "models/zine" +require "models/interest" class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase fixtures :authors, :posts, :comments @@ -46,7 +46,7 @@ class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCa author = authors(:david) # this can fail on adapters which require ORDER BY expressions to be included in the SELECT expression # if the reorder clauses are not correctly handled - assert author.posts_with_comments_sorted_by_comment_id.where('comments.id > 0').reorder('posts.comments_count DESC', 'posts.tags_count DESC').last + assert author.posts_with_comments_sorted_by_comment_id.where("comments.id > 0").reorder("posts.comments_count DESC", "posts.tags_count DESC").last end end @@ -54,18 +54,18 @@ class HasManyAssociationsTestPrimaryKeys < ActiveRecord::TestCase fixtures :authors, :essays, :subscribers, :subscriptions, :people def test_custom_primary_key_on_new_record_should_fetch_with_query - subscriber = Subscriber.new(nick: 'webster132') + subscriber = Subscriber.new(nick: "webster132") assert !subscriber.subscriptions.loaded? assert_queries 1 do assert_equal 2, subscriber.subscriptions.size end - assert_equal subscriber.subscriptions, Subscription.where(subscriber_id: 'webster132') + assert_equal subscriber.subscriptions, Subscription.where(subscriber_id: "webster132") end def test_association_primary_key_on_new_record_should_fetch_with_query - author = Author.new(:name => "David") + author = Author.new(name: "David") assert !author.essays.loaded? assert_queries 1 do @@ -116,14 +116,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_anonymous_has_many developer = Class.new(ActiveRecord::Base) { - self.table_name = 'developers' + self.table_name = "developers" dev = self developer_project = Class.new(ActiveRecord::Base) { - self.table_name = 'developers_projects' - belongs_to :developer, :anonymous_class => dev + self.table_name = "developers_projects" + belongs_to :developer, anonymous_class: dev } - has_many :developer_projects, :anonymous_class => developer_project, :foreign_key => 'developer_id' + has_many :developer_projects, anonymous_class: developer_project, foreign_key: "developer_id" } dev = developer.first named = Developer.find(dev.id) @@ -135,20 +135,20 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_default_scope_on_relations_is_not_cached counter = 0 posts = Class.new(ActiveRecord::Base) { - self.table_name = 'posts' - self.inheritance_column = 'not_there' + self.table_name = "posts" + self.inheritance_column = "not_there" post = self comments = Class.new(ActiveRecord::Base) { - self.table_name = 'comments' - self.inheritance_column = 'not_there' - belongs_to :post, :anonymous_class => post + self.table_name = "comments" + self.inheritance_column = "not_there" + belongs_to :post, anonymous_class: post default_scope -> { counter += 1 - where("id = :inc", :inc => counter) + where("id = :inc", inc: counter) } } - has_many :comments, :anonymous_class => comments, :foreign_key => 'post_id' + has_many :comments, anonymous_class: comments, foreign_key: "post_id" } assert_equal 0, counter post = posts.first @@ -159,15 +159,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_has_many_build_with_options - college = College.create(name: 'UFMT') - Student.create(active: true, college_id: college.id, name: 'Sarah') + college = College.create(name: "UFMT") + Student.create(active: true, college_id: college.id, name: "Sarah") assert_equal college.students, Student.where(active: true, college_id: college.id) end def test_add_record_to_collection_should_change_its_updated_at - ship = Ship.create(name: 'dauntless') - part = ShipPart.create(name: 'cockpit') + ship = Ship.create(name: "dauntless") + part = ShipPart.create(name: "cockpit") updated_at = part.updated_at travel(1.second) do @@ -181,8 +181,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_clear_collection_should_not_change_updated_at # GH#17161: .clear calls delete_all (and returns the association), # which is intended to not touch associated objects's updated_at field - ship = Ship.create(name: 'dauntless') - part = ShipPart.create(name: 'cockpit', ship_id: ship.id) + ship = Ship.create(name: "dauntless") + part = ShipPart.create(name: "cockpit", ship_id: ship.id) ship.parts.clear part.reload @@ -192,27 +192,27 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_create_from_association_should_respect_default_scope - car = Car.create(:name => 'honda') - assert_equal 'honda', car.name + car = Car.create(name: "honda") + assert_equal "honda", car.name bulb = Bulb.create - assert_equal 'defaulty', bulb.name + assert_equal "defaulty", bulb.name bulb = car.bulbs.build - assert_equal 'defaulty', bulb.name + assert_equal "defaulty", bulb.name bulb = car.bulbs.create - assert_equal 'defaulty', bulb.name + assert_equal "defaulty", bulb.name end def test_build_and_create_from_association_should_respect_passed_attributes_over_default_scope - car = Car.create(name: 'honda') + car = Car.create(name: "honda") - bulb = car.bulbs.build(name: 'exotic') - assert_equal 'exotic', bulb.name + bulb = car.bulbs.build(name: "exotic") + assert_equal "exotic", bulb.name - bulb = car.bulbs.create(name: 'exotic') - assert_equal 'exotic', bulb.name + bulb = car.bulbs.create(name: "exotic") + assert_equal "exotic", bulb.name bulb = car.awesome_bulbs.build(frickinawesome: false) assert_equal false, bulb.frickinawesome @@ -225,36 +225,37 @@ class HasManyAssociationsTest < ActiveRecord::TestCase author = Author.new post = author.thinking_posts.build - assert_equal 'So I was thinking', post.title + assert_equal "So I was thinking", post.title end def test_create_from_association_with_nil_values_should_work - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") bulb = car.bulbs.new(nil) - assert_equal 'defaulty', bulb.name + assert_equal "defaulty", bulb.name bulb = car.bulbs.build(nil) - assert_equal 'defaulty', bulb.name + assert_equal "defaulty", bulb.name bulb = car.bulbs.create(nil) - assert_equal 'defaulty', bulb.name + assert_equal "defaulty", bulb.name end def test_do_not_call_callbacks_for_delete_all - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") car.funky_bulbs.create! + assert_equal 1, car.funky_bulbs.count assert_nothing_raised { car.reload.funky_bulbs.delete_all } - assert_equal 0, Bulb.count, "bulbs should have been deleted using :delete_all strategy" + assert_equal 0, car.funky_bulbs.count, "bulbs should have been deleted using :delete_all strategy" end def test_delete_all_on_association_is_the_same_as_not_loaded author = authors :david - author.thinking_posts.create!(:body => "test") + author.thinking_posts.create!(body: "test") author.reload expected_sql = capture_sql { author.thinking_posts.delete_all } - author.thinking_posts.create!(:body => "test") + author.thinking_posts.create!(body: "test") author.reload author.thinking_posts.inspect loaded_sql = capture_sql { author.thinking_posts.delete_all } @@ -263,11 +264,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_delete_all_on_association_with_nil_dependency_is_the_same_as_not_loaded author = authors :david - author.posts.create!(:title => "test", :body => "body") + author.posts.create!(title: "test", body: "body") author.reload expected_sql = capture_sql { author.posts.delete_all } - author.posts.create!(:title => "test", :body => "body") + author.posts.create!(title: "test", body: "body") author.reload author.posts.to_a loaded_sql = capture_sql { author.posts.delete_all } @@ -282,29 +283,29 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_building_the_associated_object_with_explicit_sti_base_class firm = DependentFirm.new - company = firm.companies.build(:type => "Company") + company = firm.companies.build(type: "Company") assert_kind_of Company, company, "Expected #{company.class} to be a Company" end def test_building_the_associated_object_with_sti_subclass firm = DependentFirm.new - company = firm.companies.build(:type => "Client") + company = firm.companies.build(type: "Client") assert_kind_of Client, company, "Expected #{company.class} to be a Client" end def test_building_the_associated_object_with_an_invalid_type firm = DependentFirm.new - assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Invalid") } + assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(type: "Invalid") } end def test_building_the_associated_object_with_an_unrelated_type firm = DependentFirm.new - assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(:type => "Account") } + assert_raise(ActiveRecord::SubclassNotFound) { firm.companies.build(type: "Account") } end test "building the association with an array" do speedometer = Speedometer.new(speedometer_id: "a") - data = [{name: "first"}, {name: "second"}] + data = [{ name: "first" }, { name: "second" }] speedometer.minivans.build(data) assert_equal 2, speedometer.minivans.size @@ -313,24 +314,24 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_association_keys_bypass_attribute_protection - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") bulb = car.bulbs.new assert_equal car.id, bulb.car_id - bulb = car.bulbs.new :car_id => car.id + 1 + bulb = car.bulbs.new car_id: car.id + 1 assert_equal car.id, bulb.car_id bulb = car.bulbs.build assert_equal car.id, bulb.car_id - bulb = car.bulbs.build :car_id => car.id + 1 + bulb = car.bulbs.build car_id: car.id + 1 assert_equal car.id, bulb.car_id bulb = car.bulbs.create assert_equal car.id, bulb.car_id - bulb = car.bulbs.create :car_id => car.id + 1 + bulb = car.bulbs.create car_id: car.id + 1 assert_equal car.id, bulb.car_id end @@ -340,19 +341,19 @@ class HasManyAssociationsTest < ActiveRecord::TestCase line_item = invoice.line_items.new assert_equal invoice.id, line_item.invoice_id - line_item = invoice.line_items.new :invoice_id => invoice.id + 1 + line_item = invoice.line_items.new invoice_id: invoice.id + 1 assert_equal invoice.id, line_item.invoice_id line_item = invoice.line_items.build assert_equal invoice.id, line_item.invoice_id - line_item = invoice.line_items.build :invoice_id => invoice.id + 1 + line_item = invoice.line_items.build invoice_id: invoice.id + 1 assert_equal invoice.id, line_item.invoice_id line_item = invoice.line_items.create assert_equal invoice.id, line_item.invoice_id - line_item = invoice.line_items.create :invoice_id => invoice.id + 1 + line_item = invoice.line_items.create invoice_id: invoice.id + 1 assert_equal invoice.id, line_item.invoice_id end @@ -373,64 +374,95 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_no_sql_should_be_fired_if_association_already_loaded - Car.create(:name => 'honda') + Car.create(name: "honda") bulbs = Car.first.bulbs bulbs.to_a # to load all instances of bulbs assert_no_queries do bulbs.first() - bulbs.first({}) end assert_no_queries do bulbs.second() - bulbs.second({}) end assert_no_queries do bulbs.third() - bulbs.third({}) end assert_no_queries do bulbs.fourth() - bulbs.fourth({}) end assert_no_queries do bulbs.fifth() - bulbs.fifth({}) end assert_no_queries do bulbs.forty_two() - bulbs.forty_two({}) end assert_no_queries do bulbs.third_to_last() - bulbs.third_to_last({}) end assert_no_queries do bulbs.second_to_last() - bulbs.second_to_last({}) end assert_no_queries do bulbs.last() - bulbs.last({}) + end + end + + def test_finder_method_with_dirty_target + company = companies(:first_firm) + new_clients = [] + assert_no_queries(ignore_none: false) do + new_clients << company.clients_of_firm.build(name: "Another Client") + new_clients << company.clients_of_firm.build(name: "Another Client II") + new_clients << company.clients_of_firm.build(name: "Another Client III") + end + + assert_not company.clients_of_firm.loaded? + assert_queries(1) do + assert_same new_clients[0], company.clients_of_firm.third + assert_same new_clients[1], company.clients_of_firm.fourth + assert_same new_clients[2], company.clients_of_firm.fifth + assert_same new_clients[0], company.clients_of_firm.third_to_last + assert_same new_clients[1], company.clients_of_firm.second_to_last + assert_same new_clients[2], company.clients_of_firm.last + end + end + + def test_finder_bang_method_with_dirty_target + company = companies(:first_firm) + new_clients = [] + assert_no_queries(ignore_none: false) do + new_clients << company.clients_of_firm.build(name: "Another Client") + new_clients << company.clients_of_firm.build(name: "Another Client II") + new_clients << company.clients_of_firm.build(name: "Another Client III") + end + + assert_not company.clients_of_firm.loaded? + assert_queries(1) do + assert_same new_clients[0], company.clients_of_firm.third! + assert_same new_clients[1], company.clients_of_firm.fourth! + assert_same new_clients[2], company.clients_of_firm.fifth! + assert_same new_clients[0], company.clients_of_firm.third_to_last! + assert_same new_clients[1], company.clients_of_firm.second_to_last! + assert_same new_clients[2], company.clients_of_firm.last! end end def test_create_resets_cached_counters - person = Person.create!(:first_name => 'tenderlove') + person = Person.create!(first_name: "tenderlove") post = Post.first assert_equal [], person.readers assert_nil person.readers.find_by_post_id(post.id) - person.readers.create(:post_id => post.id) + person.readers.create(post_id: post.id) assert_equal 1, person.readers.count assert_equal 1, person.readers.length @@ -438,25 +470,41 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal person, person.readers.first.person end - def force_signal37_to_load_all_clients_of_firm - companies(:first_firm).clients_of_firm.each {|f| } + def test_update_all_respects_association_scope + person = Person.new + person.first_name = "Naruto" + person.references << Reference.new + person.id = 10 + person.references + person.save! + assert_equal 1, person.references.update_all(favourite: true) + end + + def test_exists_respects_association_scope + person = Person.new + person.first_name = "Sasuke" + person.references << Reference.new + person.id = 10 + person.references + person.save! + assert_predicate person.references, :exists? end # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first def test_counting_with_counter_sql - assert_equal 3, Firm.all.merge!(:order => "id").first.clients.count + assert_equal 3, Firm.all.merge!(order: "id").first.clients.count end def test_counting - assert_equal 3, Firm.all.merge!(:order => "id").first.plain_clients.count + assert_equal 3, Firm.all.merge!(order: "id").first.plain_clients.count end def test_counting_with_single_hash - assert_equal 1, Firm.all.merge!(:order => "id").first.plain_clients.where(:name => "Microsoft").count + assert_equal 1, Firm.all.merge!(order: "id").first.plain_clients.where(name: "Microsoft").count end def test_counting_with_column_name_and_hash - assert_equal 3, Firm.all.merge!(:order => "id").first.plain_clients.count(:name) + assert_equal 3, Firm.all.merge!(order: "id").first.plain_clients.count(:name) end def test_counting_with_association_limit @@ -466,11 +514,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_finding - assert_equal 3, Firm.all.merge!(:order => "id").first.clients.length + assert_equal 3, Firm.all.merge!(order: "id").first.clients.length end def test_finding_array_compatibility - assert_equal 3, Firm.order(:id).find{|f| f.id > 0}.clients.length + assert_equal 3, Firm.order(:id).find { |f| f.id > 0 }.clients.length end def test_find_many_with_merged_options @@ -480,13 +528,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_find_should_append_to_association_order - ordered_clients = companies(:first_firm).clients_sorted_desc.order('companies.id') - assert_equal ['id DESC', 'companies.id'], ordered_clients.order_values + ordered_clients = companies(:first_firm).clients_sorted_desc.order("companies.id") + assert_equal ["id DESC", "companies.id"], ordered_clients.order_values end def test_dynamic_find_should_respect_association_order assert_equal companies(:another_first_firm_client), companies(:first_firm).clients_sorted_desc.where("type = 'Client'").first - assert_equal companies(:another_first_firm_client), companies(:first_firm).clients_sorted_desc.find_by_type('Client') + assert_equal companies(:another_first_firm_client), companies(:first_firm).clients_sorted_desc.find_by_type("Client") end def test_taking @@ -508,14 +556,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_taking_with_a_number # taking from unloaded Relation bob = Author.find(authors(:bob).id) + new_post = bob.posts.build + assert_not bob.posts.loaded? assert_equal [posts(:misc_by_bob)], bob.posts.take(1) - bob = Author.find(authors(:bob).id) assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], bob.posts.take(2) + assert_equal [posts(:misc_by_bob), posts(:other_by_bob), new_post], bob.posts.take(3) # taking from loaded Relation - bob.posts.to_a - assert_equal [posts(:misc_by_bob)], authors(:bob).posts.take(1) - assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], authors(:bob).posts.take(2) + bob.posts.load + assert bob.posts.loaded? + assert_equal [posts(:misc_by_bob)], bob.posts.take(1) + assert_equal [posts(:misc_by_bob), posts(:other_by_bob)], bob.posts.take(2) + assert_equal [posts(:misc_by_bob), posts(:other_by_bob), new_post], bob.posts.take(3) end def test_taking_with_inverse_of @@ -534,45 +586,45 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_finding_default_orders - assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients.first.name + assert_equal "Summit", Firm.all.merge!(order: "id").first.clients.first.name end def test_finding_with_different_class_name_and_order - assert_equal "Apex", Firm.all.merge!(:order => "id").first.clients_sorted_desc.first.name + assert_equal "Apex", Firm.all.merge!(order: "id").first.clients_sorted_desc.first.name end def test_finding_with_foreign_key - assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_of_firm.first.name + assert_equal "Microsoft", Firm.all.merge!(order: "id").first.clients_of_firm.first.name end def test_finding_with_condition - assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_like_ms.first.name + assert_equal "Microsoft", Firm.all.merge!(order: "id").first.clients_like_ms.first.name end def test_finding_with_condition_hash - assert_equal "Microsoft", Firm.all.merge!(:order => "id").first.clients_like_ms_with_hash_conditions.first.name + assert_equal "Microsoft", Firm.all.merge!(order: "id").first.clients_like_ms_with_hash_conditions.first.name end def test_finding_using_primary_key - assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients_using_primary_key.first.name + assert_equal "Summit", Firm.all.merge!(order: "id").first.clients_using_primary_key.first.name end def test_update_all_on_association_accessed_before_save - firm = Firm.new(name: 'Firm') + firm = Firm.new(name: "Firm") clients_proxy_id = firm.clients.object_id firm.clients << Client.first firm.save! - assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!') + assert_equal firm.clients.count, firm.clients.update_all(description: "Great!") assert_not_equal clients_proxy_id, firm.clients.object_id end def test_update_all_on_association_accessed_before_save_with_explicit_foreign_key # We can use the same cached proxy object because the id is available for the scope - firm = Firm.new(name: 'Firm', id: 100) + firm = Firm.new(name: "Firm", id: 100) clients_proxy_id = firm.clients.object_id firm.clients << Client.first firm.save! - assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!') + assert_equal firm.clients.count, firm.clients.update_all(description: "Great!") assert_equal clients_proxy_id, firm.clients.object_id end @@ -582,7 +634,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_find_ids - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find } @@ -601,9 +653,23 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(2, 99) } end + def test_find_one_message_on_primary_key + firm = Firm.all.merge!(order: "id").first + + e = assert_raises(ActiveRecord::RecordNotFound) do + firm.clients.find(0) + end + assert_equal 0, e.id + assert_equal "id", e.primary_key + assert_equal "Client", e.model + assert_match (/\ACouldn't find Client with 'id'=0/), e.message + end + def test_find_ids_and_inverse_of force_signal37_to_load_all_clients_of_firm + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + firm = companies(:first_firm) client = firm.clients_of_firm.find(3) assert_kind_of Client, client @@ -614,7 +680,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_find_all - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first assert_equal 3, firm.clients.where("#{QUOTED_TYPE} = 'Client'").to_a.length assert_equal 1, firm.clients.where("name = 'Summit'").to_a.length end @@ -625,7 +691,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert ! firm.clients.loaded? assert_queries(4) do - firm.clients.find_each(:batch_size => 1) {|c| assert_equal firm.id, c.firm_id } + firm.clients.find_each(batch_size: 1) { |c| assert_equal firm.id, c.firm_id } end assert ! firm.clients.loaded? @@ -635,7 +701,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm = companies(:first_firm) assert_queries(2) do - firm.clients.where(name: 'Microsoft').find_each(batch_size: 1) do |c| + firm.clients.where(name: "Microsoft").find_each(batch_size: 1) do |c| assert_equal firm.id, c.firm_id assert_equal "Microsoft", c.name end @@ -650,8 +716,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert ! firm.clients.loaded? assert_queries(2) do - firm.clients.find_in_batches(:batch_size => 2) do |clients| - clients.each {|c| assert_equal firm.id, c.firm_id } + firm.clients.find_in_batches(batch_size: 2) do |clients| + clients.each { |c| assert_equal firm.id, c.firm_id } end end @@ -660,29 +726,29 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_find_all_sanitized # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first summit = firm.clients.where("name = 'Summit'").to_a assert_equal summit, firm.clients.where("name = ?", "Summit").to_a - assert_equal summit, firm.clients.where("name = :name", { :name => "Summit" }).to_a + assert_equal summit, firm.clients.where("name = :name", name: "Summit").to_a end def test_find_first - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first client2 = Client.find(2) assert_equal firm.clients.first, firm.clients.order("id").first assert_equal client2, firm.clients.where("#{QUOTED_TYPE} = 'Client'").order("id").first end def test_find_first_sanitized - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first client2 = Client.find(2) - assert_equal client2, firm.clients.merge!(:where => ["#{QUOTED_TYPE} = ?", 'Client'], :order => "id").first - assert_equal client2, firm.clients.merge!(:where => ["#{QUOTED_TYPE} = :type", { :type => 'Client' }], :order => "id").first + assert_equal client2, firm.clients.merge!(where: ["#{QUOTED_TYPE} = ?", "Client"], order: "id").first + assert_equal client2, firm.clients.merge!(where: ["#{QUOTED_TYPE} = :type", { type: "Client" }], order: "id").first end def test_find_all_with_include_and_conditions assert_nothing_raised do - Developer.all.merge!(:joins => :audit_logs, :where => {'audit_logs.message' => nil, :name => 'Smith'}).to_a + Developer.all.merge!(joins: :audit_logs, where: { "audit_logs.message" => nil, :name => "Smith" }).to_a end end @@ -692,8 +758,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_find_grouped - all_clients_of_firm1 = Client.all.merge!(:where => "firm_id = 1").to_a - grouped_clients_of_firm1 = Client.all.merge!(:where => "firm_id = 1", :group => "firm_id", :select => 'firm_id, count(id) as clients_count').to_a + all_clients_of_firm1 = Client.all.merge!(where: "firm_id = 1").to_a + grouped_clients_of_firm1 = Client.all.merge!(where: "firm_id = 1", group: "firm_id", select: "firm_id, count(id) as clients_count").to_a assert_equal 3, all_clients_of_firm1.size assert_equal 1, grouped_clients_of_firm1.size end @@ -715,19 +781,29 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_select_query_method - assert_equal ['id', 'body'], posts(:welcome).comments.select(:id, :body).first.attributes.keys + assert_equal ["id", "body"], posts(:welcome).comments.select(:id, :body).first.attributes.keys end def test_select_with_block assert_equal [1], posts(:welcome).comments.select { |c| c.id == 1 }.map(&:id) end + def test_select_with_block_and_specific_attributes + assert_deprecated do + comments = posts(:welcome).comments.select(:id, :body) { |c| c.id == 1 } + assert_equal [1], comments.map(&:id) + end + end + def test_select_without_foreign_key assert_equal companies(:first_firm).accounts.first.credit_limit, companies(:first_firm).accounts.select(:credit_limit).first.credit_limit end def test_adding force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + natural = Client.new("name" => "Natural Company") companies(:first_firm).clients_of_firm << natural assert_equal 3, companies(:first_firm).clients_of_firm.size # checking via the collection @@ -738,7 +814,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_adding_using_create first_firm = companies(:first_firm) assert_equal 3, first_firm.plain_clients.size - first_firm.plain_clients.create(:name => "Natural Company") + first_firm.plain_clients.create(name: "Natural Company") assert_equal 4, first_firm.plain_clients.length assert_equal 4, first_firm.plain_clients.size end @@ -746,7 +822,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_create_with_bang_on_has_many_when_parent_is_new_raises error = assert_raise(ActiveRecord::RecordNotSaved) do firm = Firm.new - firm.plain_clients.create! :name=>"Whoever" + firm.plain_clients.create! name: "Whoever" end assert_equal "You cannot call create unless the parent is saved", error.message @@ -755,7 +831,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_regular_create_on_has_many_when_parent_is_new_raises error = assert_raise(ActiveRecord::RecordNotSaved) do firm = Firm.new - firm.plain_clients.create :name=>"Whoever" + firm.plain_clients.create name: "Whoever" end assert_equal "You cannot call create unless the parent is saved", error.message @@ -763,7 +839,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_create_with_bang_on_has_many_raises_when_record_not_saved assert_raise(ActiveRecord::RecordInvalid) do - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first firm.plain_clients.create! end end @@ -784,21 +860,24 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_adding_a_collection force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + companies(:first_firm).clients_of_firm.concat([Client.new("name" => "Natural Company"), Client.new("name" => "Apple")]) assert_equal 4, companies(:first_firm).clients_of_firm.size assert_equal 4, companies(:first_firm).clients_of_firm.reload.size end def test_transactions_when_adding_to_persisted - good = Client.new(:name => "Good") - bad = Client.new(:name => "Bad", :raise_on_save => true) + good = Client.new(name: "Good") + bad = Client.new(name: "Bad", raise_on_save: true) begin companies(:first_firm).clients_of_firm.concat(good, bad) rescue Client::RaisedOnSave end - assert !companies(:first_firm).clients_of_firm.reload.include?(good) + assert_not_includes companies(:first_firm).clients_of_firm.reload, good end def test_transactions_when_adding_to_new_record @@ -863,7 +942,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many company = companies(:first_firm) - new_clients = assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } + new_clients = assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) } assert_equal 2, new_clients.size end @@ -880,7 +959,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, first_topic.replies.length assert_no_queries do - first_topic.replies.build(:title => "Not saved", :content => "Superstars") + first_topic.replies.build(title: "Not saved", content: "Superstars") assert_equal 2, first_topic.replies.size end @@ -889,7 +968,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_via_block company = companies(:first_firm) - new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build { |client| client.name = "Another Client" } } assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name @@ -900,7 +979,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many_via_block company = companies(:first_firm) new_clients = assert_no_queries(ignore_none: false) do - company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| + company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) do |client| client.name = "changed" end end @@ -919,7 +998,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase first_firm.clients_of_firm.reset assert_queries(1) do - first_firm.clients_of_firm.create(:name => "Superstars") + first_firm.clients_of_firm.create(name: "Superstars") end assert_equal 3, first_firm.clients_of_firm.size @@ -927,6 +1006,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_create force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client") assert new_client.persisted? assert_equal new_client, companies(:first_firm).clients_of_firm.last @@ -934,7 +1016,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_create_many - companies(:first_firm).clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}]) + companies(:first_firm).clients_of_firm.create([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) assert_equal 4, companies(:first_firm).clients_of_firm.reload.size end @@ -946,6 +1028,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_deleting force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + companies(:first_firm).clients_of_firm.delete(companies(:first_firm).clients_of_firm.first) assert_equal 1, companies(:first_firm).clients_of_firm.size assert_equal 1, companies(:first_firm).clients_of_firm.reload.size @@ -962,7 +1047,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_has_many_without_counter_cache_option # Ship has a conventionally named `treasures_count` column, but the counter_cache # option is not given on the association. - ship = Ship.create(name: 'Countless', treasures_count: 10) + ship = Ship.create(name: "Countless", treasures_count: 10) assert_not Ship.reflect_on_association(:treasures).has_cached_counter? @@ -970,7 +1055,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal ship.treasures.size, 0 assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed" do - ship.treasures.create(name: 'Gold') + ship.treasures.create(name: "Gold") end assert_no_difference lambda { ship.reload.treasures_count }, "treasures_count should not be changed" do @@ -1073,10 +1158,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal original_count, topic.replies_count first_reply = topic.replies.first - first_reply.update_attributes(:parent_id => nil) + first_reply.update_attributes(parent_id: nil) assert_equal original_count - 1, topic.reload.replies_count - first_reply.update_attributes(:parent_id => topic.id) + first_reply.update_attributes(parent_id: topic.id) assert_equal original_count, topic.reload.replies_count end @@ -1089,17 +1174,20 @@ class HasManyAssociationsTest < ActiveRecord::TestCase reply1 = topic1.replies.first reply2 = topic2.replies.first - reply1.update_attributes(:parent_id => topic2.id) + reply1.update_attributes(parent_id: topic2.id) assert_equal original_count1 - 1, topic1.reload.replies_count assert_equal original_count2 + 1, topic2.reload.replies_count - reply2.update_attributes(:parent_id => topic1.id) + reply2.update_attributes(parent_id: topic1.id) assert_equal original_count1, topic1.reload.replies_count assert_equal original_count2, topic2.reload.replies_count end def test_deleting_a_collection force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + companies(:first_firm).clients_of_firm.create("name" => "Another Client") assert_equal 3, companies(:first_firm).clients_of_firm.size companies(:first_firm).clients_of_firm.delete([companies(:first_firm).clients_of_firm[0], companies(:first_firm).clients_of_firm[1], companies(:first_firm).clients_of_firm[2]]) @@ -1109,6 +1197,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_delete_all force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + companies(:first_firm).dependent_clients_of_firm.create("name" => "Another Client") clients = companies(:first_firm).dependent_clients_of_firm.to_a assert_equal 3, clients.count @@ -1120,6 +1211,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_delete_all_with_not_yet_loaded_association_collection force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + companies(:first_firm).clients_of_firm.create("name" => "Another Client") assert_equal 3, companies(:first_firm).clients_of_firm.size companies(:first_firm).clients_of_firm.reset @@ -1129,8 +1223,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_transaction_when_deleting_persisted - good = Client.new(:name => "Good") - bad = Client.new(:name => "Bad", :raise_on_destroy => true) + good = Client.new(name: "Good") + bad = Client.new(name: "Bad", raise_on_destroy: true) companies(:first_firm).clients_of_firm = [good, bad] @@ -1171,7 +1265,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_clearing_updates_counter_cache topic = Topic.first - assert_difference 'topic.reload.replies_count', -1 do + assert_difference "topic.reload.replies_count", -1 do topic.replies.clear end end @@ -1180,7 +1274,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase car = Car.first car.engines.create! - assert_difference 'car.reload.engines_count', -1 do + assert_difference "car.reload.engines_count", -1 do car.engines.clear end end @@ -1238,8 +1332,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_dependent_association_respects_optional_conditions_on_delete firm = companies(:odegy) - Client.create(:client_of => firm.id, :name => "BigShot Inc.") - Client.create(:client_of => firm.id, :name => "SmallTime Inc.") + Client.create(client_of: firm.id, name: "BigShot Inc.") + Client.create(client_of: firm.id, name: "SmallTime Inc.") # only one of two clients is included in the association due to the :conditions key assert_equal 2, Client.where(client_of: firm.id).size assert_equal 1, firm.dependent_conditional_clients_of_firm.size @@ -1250,8 +1344,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_dependent_association_respects_optional_sanitized_conditions_on_delete firm = companies(:odegy) - Client.create(:client_of => firm.id, :name => "BigShot Inc.") - Client.create(:client_of => firm.id, :name => "SmallTime Inc.") + Client.create(client_of: firm.id, name: "BigShot Inc.") + Client.create(client_of: firm.id, name: "SmallTime Inc.") # only one of two clients is included in the association due to the :conditions key assert_equal 2, Client.where(client_of: firm.id).size assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size @@ -1262,8 +1356,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_dependent_association_respects_optional_hash_conditions_on_delete firm = companies(:odegy) - Client.create(:client_of => firm.id, :name => "BigShot Inc.") - Client.create(:client_of => firm.id, :name => "SmallTime Inc.") + Client.create(client_of: firm.id, name: "BigShot Inc.") + Client.create(client_of: firm.id, name: "SmallTime Inc.") # only one of two clients is included in the association due to the :conditions key assert_equal 2, Client.where(client_of: firm.id).size assert_equal 1, firm.dependent_sanitized_conditional_clients_of_firm.size @@ -1289,12 +1383,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.build assert ms_client.save - assert_equal 'Microsoft', ms_client.name + assert_equal "Microsoft", ms_client.name another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create assert another_ms_client.persisted? - assert_equal 'Microsoft', another_ms_client.name + assert_equal "Microsoft", another_ms_client.name end def test_clearing_without_initial_access @@ -1308,7 +1402,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_deleting_a_item_which_is_not_in_the_collection force_signal37_to_load_all_clients_of_firm - summit = Client.find_by_name('Summit') + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + + summit = Client.find_by_name("Summit") companies(:first_firm).clients_of_firm.delete(summit) assert_equal 2, companies(:first_firm).clients_of_firm.size assert_equal 2, companies(:first_firm).clients_of_firm.reload.size @@ -1318,7 +1415,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_deleting_by_integer_id david = Developer.find(1) - assert_difference 'david.projects.count', -1 do + assert_difference "david.projects.count", -1 do assert_equal 1, david.projects.delete(1).size end @@ -1328,8 +1425,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_deleting_by_string_id david = Developer.find(1) - assert_difference 'david.projects.count', -1 do - assert_equal 1, david.projects.delete('1').size + assert_difference "david.projects.count", -1 do + assert_equal 1, david.projects.delete("1").size end assert_equal 1, david.projects.size @@ -1344,6 +1441,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_destroying force_signal37_to_load_all_clients_of_firm + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + assert_difference "Client.count", -1 do companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first) end @@ -1355,6 +1454,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_destroying_by_integer_id force_signal37_to_load_all_clients_of_firm + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + assert_difference "Client.count", -1 do companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id) end @@ -1366,6 +1467,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_destroying_by_string_id force_signal37_to_load_all_clients_of_firm + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + assert_difference "Client.count", -1 do companies(:first_firm).clients_of_firm.destroy(companies(:first_firm).clients_of_firm.first.id.to_s) end @@ -1376,6 +1479,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_destroying_a_collection force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + companies(:first_firm).clients_of_firm.create("name" => "Another Client") assert_equal 3, companies(:first_firm).clients_of_firm.size @@ -1389,6 +1495,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_destroy_all force_signal37_to_load_all_clients_of_firm + + assert_predicate companies(:first_firm).clients_of_firm, :loaded? + clients = companies(:first_firm).clients_of_firm.to_a assert !clients.empty?, "37signals has clients after load" destroyed = companies(:first_firm).clients_of_firm.destroy_all @@ -1402,17 +1511,17 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm = companies(:first_firm) assert_equal 3, firm.clients.size firm.destroy - assert Client.all.merge!(:where => "firm_id=#{firm.id}").to_a.empty? + assert Client.all.merge!(where: "firm_id=#{firm.id}").to_a.empty? end def test_dependence_for_associations_with_hash_condition david = authors(:david) - assert_difference('Post.count', -1) { assert david.destroy } + assert_difference("Post.count", -1) { assert david.destroy } end def test_destroy_dependent_when_deleted_from_association # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first assert_equal 3, firm.clients.size client = firm.clients.first @@ -1439,7 +1548,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm.destroy rescue "do nothing" - assert_equal 3, Client.all.merge!(:where => "firm_id=#{firm.id}").to_a.size + assert_equal 3, Client.all.merge!(where: "firm_id=#{firm.id}").to_a.size end def test_dependence_on_account @@ -1463,21 +1572,21 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_restrict_with_exception - firm = RestrictedWithExceptionFirm.create!(:name => 'restrict') - firm.companies.create(:name => 'child') + firm = RestrictedWithExceptionFirm.create!(name: "restrict") + firm.companies.create(name: "child") assert !firm.companies.empty? assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } - assert RestrictedWithExceptionFirm.exists?(:name => 'restrict') - assert firm.companies.exists?(:name => 'child') + assert RestrictedWithExceptionFirm.exists?(name: "restrict") + assert firm.companies.exists?(name: "child") end def test_restrict_with_error_is_deprecated_using_key_many I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { many: 'message for deprecated key' } } } } + I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { many: "message for deprecated key" } } } } - firm = RestrictedWithErrorFirm.create!(name: 'restrict') - firm.companies.create(name: 'child') + firm = RestrictedWithErrorFirm.create!(name: "restrict") + firm.companies.create(name: "child") assert !firm.companies.empty? @@ -1485,16 +1594,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !firm.errors.empty? - assert_equal 'message for deprecated key', firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(name: 'restrict') - assert firm.companies.exists?(name: 'child') + assert_equal "message for deprecated key", firm.errors[:base].first + assert RestrictedWithErrorFirm.exists?(name: "restrict") + assert firm.companies.exists?(name: "child") ensure I18n.backend.reload! end def test_restrict_with_error - firm = RestrictedWithErrorFirm.create!(:name => 'restrict') - firm.companies.create(:name => 'child') + firm = RestrictedWithErrorFirm.create!(name: "restrict") + firm.companies.create(name: "child") assert !firm.companies.empty? @@ -1503,15 +1612,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !firm.errors.empty? assert_equal "Cannot delete record because dependent companies exist", firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(:name => 'restrict') - assert firm.companies.exists?(:name => 'child') + assert RestrictedWithErrorFirm.exists?(name: "restrict") + assert firm.companies.exists?(name: "child") end def test_restrict_with_error_with_locale I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations 'en', activerecord: {attributes: {restricted_with_error_firm: {companies: 'client companies'}}} - firm = RestrictedWithErrorFirm.create!(name: 'restrict') - firm.companies.create(name: 'child') + I18n.backend.store_translations "en", activerecord: { attributes: { restricted_with_error_firm: { companies: "client companies" } } } + firm = RestrictedWithErrorFirm.create!(name: "restrict") + firm.companies.create(name: "child") assert !firm.companies.empty? @@ -1520,8 +1629,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !firm.errors.empty? assert_equal "Cannot delete record because dependent client companies exist", firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(name: 'restrict') - assert firm.companies.exists?(name: 'child') + assert RestrictedWithErrorFirm.exists?(name: "restrict") + assert firm.companies.exists?(name: "child") ensure I18n.backend.reload! end @@ -1531,10 +1640,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_included_in_collection_for_new_records - client = Client.create(:name => 'Persisted') + client = Client.create(name: "Persisted") assert_nil client.client_of assert_equal false, Firm.new.clients_of_firm.include?(client), - 'includes a client that does not belong to any firm' + "includes a client that does not belong to any firm" end def test_adding_array_and_collection @@ -1542,7 +1651,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_replace_with_less - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first firm.clients = [companies(:first_client)] assert firm.save, "Could not save firm" firm.reload @@ -1556,7 +1665,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_replace_with_new - firm = Firm.all.merge!(:order => "id").first + firm = Firm.all.merge!(order: "id").first firm.clients = [companies(:second_client), Client.new("name" => "New Client")] firm.save firm.reload @@ -1589,12 +1698,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm.clients = [] end - assert_equal [], firm.send('clients=', []) + assert_equal [], firm.send("clients=", []) end def test_transactions_when_replacing_on_persisted - good = Client.new(:name => "Good") - bad = Client.new(:name => "Bad", :raise_on_save => true) + good = Client.new(name: "Good") + bad = Client.new(name: "Bad", raise_on_save: true) companies(:first_firm).clients_of_firm = [good] @@ -1657,7 +1766,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase contract_a = Contract.create! contract_b = Contract.create! Contract.create! # another contract - company = Company.new(:name => "Some Company") + company = Company.new(name: "Some Company") company.contract_ids = [contract_a.id, contract_b.id] assert_equal [contract_a.id, contract_b.id], company.contract_ids @@ -1669,8 +1778,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_assign_ids_ignoring_blanks - firm = Firm.create!(:name => 'Apple') - firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, ''] + firm = Firm.create!(name: "Apple") + firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, ""] firm.save! assert_equal 2, firm.clients.reload.size @@ -1685,14 +1794,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase [ lambda { authors(:mary).comment_ids = [comments(:greetings).id, comments(:more_greetings).id] }, lambda { authors(:mary).comments = [comments(:greetings), comments(:more_greetings)] }, - lambda { authors(:mary).comments << Comment.create!(:body => "Yay", :post_id => 424242) }, + lambda { authors(:mary).comments << Comment.create!(body: "Yay", post_id: 424242) }, lambda { authors(:mary).comments.delete(authors(:mary).comments.first) }, - ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } + ].each { |block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } end def test_dynamic_find_should_respect_association_order_for_through assert_equal Comment.find(10), authors(:david).comments_desc.where("comments.type = 'SpecialComment'").first - assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type('SpecialComment') + assert_equal Comment.find(10), authors(:david).comments_desc.find_by_type("SpecialComment") end def test_has_many_through_respects_hash_conditions @@ -1726,7 +1835,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_include_returns_false_for_non_matching_record_to_verify_scoping firm = companies(:first_firm) - client = Client.create!(:name => 'Not Associated') + client = Client.create!(name: "Not Associated") assert ! firm.clients.loaded? assert_equal false, firm.clients.include?(client) @@ -1755,7 +1864,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_calling_first_or_last_on_existing_record_with_build_should_load_association firm = companies(:first_firm) - firm.clients.build(:name => 'Foo') + firm.clients.build(name: "Foo") assert !firm.clients.loaded? assert_queries 1 do @@ -1769,7 +1878,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_calling_first_nth_or_last_on_existing_record_with_create_should_not_load_association firm = companies(:first_firm) - firm.clients.create(:name => 'Foo') + firm.clients.create(name: "Foo") assert !firm.clients.loaded? assert_queries 3 do @@ -1793,7 +1902,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_calling_first_or_last_with_integer_on_association_should_not_load_association firm = companies(:first_firm) - firm.clients.create(:name => 'Foo') + firm.clients.create(name: "Foo") assert !firm.clients.loaded? assert_queries 2 do @@ -1923,13 +2032,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase old = ActiveRecord::Base.store_full_sti_class ActiveRecord::Base.store_full_sti_class = true - firm = Namespaced::Firm.create({ :name => 'Some Company' }) - firm.clients.create({ :name => 'Some Client' }) + firm = Namespaced::Firm.create(name: "Some Company") + firm.clients.create(name: "Some Client") stats = Namespaced::Firm.all.merge!( - :select => "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients", - :joins => :clients, - :group => "#{Namespaced::Firm.table_name}.id" + select: "#{Namespaced::Firm.table_name}.id, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients", + joins: :clients, + group: "#{Namespaced::Firm.table_name}.id" ).find firm.id assert_equal 1, stats.num_clients.to_i ensure @@ -1955,8 +2064,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_creating_using_primary_key - firm = Firm.all.merge!(:order => "id").first - client = firm.clients_using_primary_key.create!(:name => 'test') + firm = Firm.all.merge!(order: "id").first + client = firm.clients_using_primary_key.create!(name: "test") assert_equal firm.name, client.firm_name end @@ -1979,12 +2088,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_attributes_are_being_set_when_initialized_from_has_many_association_with_where_clause - new_comment = posts(:welcome).comments.where(:body => "Some content").build + new_comment = posts(:welcome).comments.where(body: "Some content").build assert_equal new_comment.body, "Some content" end def test_attributes_are_being_set_when_initialized_from_has_many_association_with_multiple_where_clauses - new_comment = posts(:welcome).comments.where(:body => "Some content").where(:type => 'SpecialComment').build + new_comment = posts(:welcome).comments.where(body: "Some content").where(type: "SpecialComment").build assert_equal new_comment.body, "Some content" assert_equal new_comment.type, "SpecialComment" assert_equal new_comment.post_id, posts(:welcome).id @@ -1998,7 +2107,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_load_target_respects_protected_attributes topic = Topic.create! - reply = topic.replies.create(:title => "reply 1") + reply = topic.replies.create(title: "reply 1") reply.approved = false reply.save! @@ -2025,7 +2134,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_merging_with_custom_attribute_writer - bulb = Bulb.new(:color => "red") + bulb = Bulb.new(color: "red") assert_equal "RED!", bulb.color car = Car.create! @@ -2035,13 +2144,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_abstract_class_with_polymorphic_has_many - post = SubStiPost.create! :title => "fooo", :body => "baa" - tagging = Tagging.create! :taggable => post + post = SubStiPost.create! title: "fooo", body: "baa" + tagging = Tagging.create! taggable: post assert_equal [tagging], post.taggings end def test_with_polymorphic_has_many_with_custom_columns_name - post = Post.create! :title => 'foo', :body => 'bar' + post = Post.create! title: "foo", body: "bar" image = Image.create! post.images << image @@ -2051,10 +2160,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_with_polymorphic_has_many_does_not_allow_to_override_type_and_id welcome = posts(:welcome) - tagging = welcome.taggings.build(:taggable_id => 99, :taggable_type => 'ShouldNotChange') + tagging = welcome.taggings.build(taggable_id: 99, taggable_type: "ShouldNotChange") assert_equal welcome.id, tagging.taggable_id - assert_equal 'Post', tagging.taggable_type + assert_equal "Post", tagging.taggable_type end def test_dont_call_save_callbacks_twice_on_has_many @@ -2066,30 +2175,30 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_association_attributes_are_available_to_after_initialize - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") bulb = car.bulbs.build - assert_equal car.id, bulb.attributes_after_initialize['car_id'] + assert_equal car.id, bulb.attributes_after_initialize["car_id"] end def test_attributes_are_set_when_initialized_from_has_many_null_relationship - car = Car.new name: 'honda' - bulb = car.bulbs.where(name: 'headlight').first_or_initialize - assert_equal 'headlight', bulb.name + car = Car.new name: "honda" + bulb = car.bulbs.where(name: "headlight").first_or_initialize + assert_equal "headlight", bulb.name end def test_attributes_are_set_when_initialized_from_polymorphic_has_many_null_relationship - post = Post.new title: 'title', body: 'bar' - tag = Tag.create!(name: 'foo') + post = Post.new title: "title", body: "bar" + tag = Tag.create!(name: "foo") tagging = post.taggings.where(tag: tag).first_or_initialize assert_equal tag.id, tagging.tag_id - assert_equal 'Post', tagging.taggable_type + assert_equal "Post", tagging.taggable_type end def test_replace - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") bulb1 = car.bulbs.create bulb2 = Bulb.create @@ -2100,7 +2209,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_replace_returns_target - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") bulb1 = car.bulbs.create bulb2 = car.bulbs.create bulb3 = Bulb.create @@ -2117,15 +2226,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end test "first_or_initialize adds the record to the association" do - firm = Firm.create! name: 'omg' + firm = Firm.create! name: "omg" client = firm.clients_of_firm.first_or_initialize assert_equal [client], firm.clients_of_firm end test "first_or_create adds the record to the association" do - firm = Firm.create! name: 'omg' + firm = Firm.create! name: "omg" firm.clients_of_firm.load_target - client = firm.clients_of_firm.first_or_create name: 'lol' + client = firm.clients_of_firm.first_or_create name: "lol" assert_equal [client], firm.clients_of_firm assert_equal [client], firm.reload.clients_of_firm end @@ -2147,7 +2256,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_no_queries(ignore_none: false) do assert_equal [], post.comments - assert_equal [], post.comments.where(body: 'omg') + assert_equal [], post.comments.where(body: "omg") assert_equal [], post.comments.pluck(:body) assert_equal 0, post.comments.sum(:id) assert_equal 0, post.comments.count @@ -2175,7 +2284,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase david = authors(:david) post = david.posts.first - post.type = 'PostWithSpecialCategorization' + post.type = "PostWithSpecialCategorization" post.save categorization = post.categorizations.first @@ -2188,8 +2297,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end test "does not duplicate associations when used with natural primary keys" do - speedometer = Speedometer.create!(id: '4') - speedometer.minivans.create!(minivan_id: 'a-van-red' ,name: 'a van', color: 'red') + speedometer = Speedometer.create!(id: "4") + speedometer.minivans.create!(minivan_id: "a-van-red" ,name: "a van", color: "red") assert_equal 1, speedometer.minivans.to_a.size, "Only one association should be present:\n#{speedometer.minivans.to_a}" assert_equal 1, speedometer.reload.minivans.to_a.size @@ -2205,7 +2314,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end test "can unscope and where the default scope of the associated model" do - Car.has_many :other_bulbs, -> { unscope(where: [:name]).where(name: 'other') }, class_name: "Bulb" + Car.has_many :other_bulbs, -> { unscope(where: [:name]).where(name: "other") }, class_name: "Bulb" car = Car.create! bulb1 = Bulb.create! name: "defaulty", car: car bulb2 = Bulb.create! name: "other", car: car @@ -2215,7 +2324,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end test "can rewhere the default scope of the associated model" do - Car.has_many :old_bulbs, -> { rewhere(name: 'old') }, class_name: "Bulb" + Car.has_many :old_bulbs, -> { rewhere(name: "old") }, class_name: "Bulb" car = Car.create! bulb1 = Bulb.create! name: "defaulty", car: car bulb2 = Bulb.create! name: "old", car: car @@ -2224,7 +2333,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [bulb2], car.old_bulbs end - test 'unscopes the default scope of associated model when used with include' do + test "unscopes the default scope of associated model when used with include" do car = Car.create! bulb = Bulb.create! name: "other", car: car @@ -2244,7 +2353,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal "Failed to destroy the record", error.message end - test 'updates counter cache when default scope is given' do + test "updates counter cache when default scope is given" do topic = DefaultRejectedTopic.create approved: true assert_difference "topic.reload.replies_count", 1 do @@ -2252,8 +2361,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end end - test 'dangerous association name raises ArgumentError' do - [:errors, 'errors', :save, 'save'].each do |name| + test "dangerous association name raises ArgumentError" do + [:errors, "errors", :save, "save"].each do |name| assert_raises(ArgumentError, "Association #{name} should not be allowed") do Class.new(ActiveRecord::Base) do has_many name @@ -2262,7 +2371,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end end - test 'passes custom context validation to validate children' do + test "passes custom context validation to validate children" do pirate = FamousPirate.new pirate.famous_ships << ship = FamousShip.new @@ -2271,7 +2380,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal "can't be blank", ship.errors[:name].first end - test 'association with instance dependent scope' do + test "association with instance dependent scope" do bob = authors(:bob) Post.create!(title: "signed post by bob", body: "stuff", author: authors(:bob)) Post.create!(title: "anonymous post", body: "more stuff", author: authors(:bob)) @@ -2281,7 +2390,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [], authors(:david).posts_with_signature.map(&:title) end - test 'associations autosaves when object is already persisted' do + test "associations autosaves when object is already persisted" do bulb = Bulb.create! tyre = Tyre.create! @@ -2294,7 +2403,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, car.tyres.count end - test 'associations replace in memory when records have the same id' do + test "associations replace in memory when records have the same id" do bulb = Bulb.create! car = Car.create!(bulbs: [bulb]) @@ -2305,7 +2414,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal "foo", car.bulbs.first.name end - test 'in memory replacement executes no queries' do + test "in memory replacement executes no queries" do bulb = Bulb.create! car = Car.create!(bulbs: [bulb]) @@ -2316,7 +2425,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end end - test 'in memory replacements do not execute callbacks' do + test "in memory replacements do not execute callbacks" do raise_after_add = false klass = Class.new(ActiveRecord::Base) do self.table_name = :cars @@ -2337,7 +2446,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end end - test 'in memory replacements sets inverse instance' do + test "in memory replacements sets inverse instance" do bulb = Bulb.create! car = Car.create!(bulbs: [bulb]) @@ -2347,7 +2456,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_same car, new_bulb.car end - test 'in memory replacement maintains order' do + test "in memory replacement maintains order" do first_bulb = Bulb.create! second_bulb = Bulb.create! car = Car.create!(bulbs: [first_bulb, second_bulb]) @@ -2358,10 +2467,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [first_bulb, second_bulb], car.bulbs end - test 'double insertion of new object to association when same association used in the after create callback of a new object' do - car = Car.create! - car.bulbs << TrickyBulb.new - assert_equal 1, car.bulbs.size + test "double insertion of new object to association when same association used in the after create callback of a new object" do + reset_callbacks(:save, Bulb) do + Bulb.after_save { |record| record.car.bulbs.to_a } + car = Car.create! + car.bulbs << Bulb.new + assert_equal 1, car.bulbs.size + end end def test_association_force_reload_with_only_true_is_deprecated @@ -2401,10 +2513,41 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_ids_reader_memoization - car = Car.create!(name: 'TofaÅŸ') + car = Car.create!(name: "TofaÅŸ") bulb = Bulb.create!(car: car) assert_equal [bulb.id], car.bulb_ids assert_no_queries { car.bulb_ids } end + + def test_loading_association_in_validate_callback_doesnt_affect_persistence + reset_callbacks(:validation, Bulb) do + Bulb.after_validation { |m| m.car.bulbs.load } + + car = Car.create!(name: "Car") + bulb = car.bulbs.create! + + assert_equal [bulb], car.bulbs + end + end + + private + + def force_signal37_to_load_all_clients_of_firm + companies(:first_firm).clients_of_firm.load_target + end + + def reset_callbacks(kind, klass) + old_callbacks = {} + old_callbacks[klass] = klass.send("_#{kind}_callbacks").dup + klass.subclasses.each do |subclass| + old_callbacks[subclass] = subclass.send("_#{kind}_callbacks").dup + end + yield + ensure + klass.send("_#{kind}_callbacks=", old_callbacks[klass]) + klass.subclasses.each do |subclass| + subclass.send("_#{kind}_callbacks=", old_callbacks[subclass]) + end + end end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index aa35844a03..9f716d7820 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -1,33 +1,33 @@ require "cases/helper" -require 'models/post' -require 'models/person' -require 'models/reference' -require 'models/job' -require 'models/reader' -require 'models/comment' -require 'models/rating' -require 'models/tag' -require 'models/tagging' -require 'models/author' -require 'models/owner' -require 'models/pet' -require 'models/pet_treasure' -require 'models/toy' -require 'models/treasure' -require 'models/contract' -require 'models/company' -require 'models/developer' -require 'models/computer' -require 'models/subscriber' -require 'models/book' -require 'models/subscription' -require 'models/essay' -require 'models/category' -require 'models/categorization' -require 'models/member' -require 'models/membership' -require 'models/club' -require 'models/organization' +require "models/post" +require "models/person" +require "models/reference" +require "models/job" +require "models/reader" +require "models/comment" +require "models/rating" +require "models/tag" +require "models/tagging" +require "models/author" +require "models/owner" +require "models/pet" +require "models/pet_treasure" +require "models/toy" +require "models/treasure" +require "models/contract" +require "models/company" +require "models/developer" +require "models/computer" +require "models/subscriber" +require "models/book" +require "models/subscription" +require "models/essay" +require "models/category" +require "models/categorization" +require "models/member" +require "models/membership" +require "models/club" +require "models/organization" class HasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :posts, :readers, :people, :comments, :authors, :categories, :taggings, :tags, @@ -37,8 +37,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # Dummies to force column loads so query counts are clean. def setup - Person.create :first_name => 'gummy' - Reader.create :person_id => 0, :post_id => 0 + Person.create first_name: "gummy" + Reader.create person_id: 0, post_id: 0 end def test_preload_sti_rhs_class @@ -49,9 +49,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_preload_sti_middle_relation - club = Club.create!(name: 'Aaron cool banana club') - member1 = Member.create!(name: 'Aaron') - member2 = Member.create!(name: 'Cat') + club = Club.create!(name: "Aaron cool banana club") + member1 = Member.create!(name: "Aaron") + member2 = Member.create!(name: "Cat") SuperMembership.create! club: club, member: member1 CurrentMembership.create! club: club, member: member2 @@ -67,10 +67,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_ordered_has_many_through person_prime = Class.new(ActiveRecord::Base) do - def self.name; 'Person'; end + def self.name; "Person"; end has_many :readers - has_many :posts, -> { order('posts.id DESC') }, :through => :readers + has_many :posts, -> { order("posts.id DESC") }, through: :readers end posts = person_prime.includes(:posts).first.posts @@ -85,7 +85,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase subscription = make_model "Subscription" subscriber = make_model "Subscriber" - subscriber.primary_key = 'nick' + subscriber.primary_key = "nick" subscription.belongs_to :book, anonymous_class: book subscription.belongs_to :subscriber, anonymous_class: subscriber @@ -106,8 +106,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_no_pk_join_table_append lesson, _, student = make_no_pk_hm_t - sicp = lesson.new(:name => "SICP") - ben = student.new(:name => "Ben Bitdiddle") + sicp = lesson.new(name: "SICP") + ben = student.new(name: "Ben Bitdiddle") sicp.students << ben assert sicp.save! end @@ -115,17 +115,17 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_no_pk_join_table_delete lesson, lesson_student, student = make_no_pk_hm_t - sicp = lesson.new(:name => "SICP") - ben = student.new(:name => "Ben Bitdiddle") - louis = student.new(:name => "Louis Reasoner") + sicp = lesson.new(name: "SICP") + ben = student.new(name: "Ben Bitdiddle") + louis = student.new(name: "Louis Reasoner") sicp.students << ben sicp.students << louis assert sicp.save! sicp.students.reload assert_operator lesson_student.count, :>=, 2 - assert_no_difference('student.count') do - assert_difference('lesson_student.count', -2) do + assert_no_difference("student.count") do + assert_difference("lesson_student.count", -2) do sicp.students.destroy(*student.all.to_a) end end @@ -139,8 +139,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase after_destroy_called = true end - sicp = lesson.new(:name => "SICP") - ben = student.new(:name => "Ben Bitdiddle") + sicp = lesson.new(name: "SICP") + ben = student.new(name: "Ben Bitdiddle") sicp.students << ben assert sicp.save! @@ -150,16 +150,16 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def make_no_pk_hm_t - lesson = make_model 'Lesson' - student = make_model 'Student' + lesson = make_model "Lesson" + student = make_model "Student" - lesson_student = make_model 'LessonStudent' - lesson_student.table_name = 'lessons_students' + lesson_student = make_model "LessonStudent" + lesson_student.table_name = "lessons_students" - lesson_student.belongs_to :lesson, :anonymous_class => lesson - lesson_student.belongs_to :student, :anonymous_class => student - lesson.has_many :lesson_students, :anonymous_class => lesson_student - lesson.has_many :students, :through => :lesson_students, :anonymous_class => student + lesson_student.belongs_to :lesson, anonymous_class: lesson + lesson_student.belongs_to :student, anonymous_class: student + lesson.has_many :lesson_students, anonymous_class: lesson_student + lesson.has_many :students, through: :lesson_students, anonymous_class: student [lesson, lesson_student, student] end @@ -175,7 +175,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person = Person.new post = Post.new person.posts << post - assert person.posts.include?(post) + assert_includes person.posts, post end def test_associate_existing @@ -187,18 +187,18 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end assert_queries(1) do - assert post.people.include?(person) + assert_includes post.people, person end - assert post.reload.people.reload.include?(person) + assert_includes post.reload.people.reload, person end def test_delete_all_for_with_dependent_option_destroy person = people(:david) assert_equal 1, person.jobs_with_dependent_destroy.count - assert_no_difference 'Job.count' do - assert_difference 'Reference.count', -1 do + assert_no_difference "Job.count" do + assert_difference "Reference.count", -1 do person.reload.jobs_with_dependent_destroy.delete_all end end @@ -208,8 +208,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person = people(:david) assert_equal 1, person.jobs_with_dependent_nullify.count - assert_no_difference 'Job.count' do - assert_no_difference 'Reference.count' do + assert_no_difference "Job.count" do + assert_no_difference "Reference.count" do person.reload.jobs_with_dependent_nullify.delete_all end end @@ -219,8 +219,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person = people(:david) assert_equal 1, person.jobs_with_dependent_delete_all.count - assert_no_difference 'Job.count' do - assert_difference 'Reference.count', -1 do + assert_no_difference "Job.count" do + assert_difference "Reference.count", -1 do person.reload.jobs_with_dependent_delete_all.delete_all end end @@ -238,7 +238,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase post = posts(:thinking) person = people(:david) - assert_difference 'post.people.to_a.count', 2 do + assert_difference "post.people.to_a.count", 2 do post.people << person post.people << person end @@ -248,7 +248,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase post = posts(:thinking) person = people(:david) - assert_difference 'post.people.count', 2 do + assert_difference "post.people.count", 2 do post.people << person post.people << person end @@ -261,12 +261,12 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase post.people << person post.people << person - counts = ['post.people.count', 'post.people.to_a.count', 'post.readers.count', 'post.readers.to_a.count'] + counts = ["post.people.count", "post.people.to_a.count", "post.readers.count", "post.readers.to_a.count"] assert_difference counts, -2 do post.people.delete(person) end - assert !post.people.reload.include?(person) + assert_not_includes post.people.reload, person end def test_associating_new @@ -274,7 +274,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase new_person = nil # so block binding catches it assert_queries(0) do - new_person = Person.new :first_name => 'bob' + new_person = Person.new first_name: "bob" end # Associating new records always saves them @@ -284,59 +284,59 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end assert_queries(1) do - assert posts(:thinking).people.include?(new_person) + assert_includes posts(:thinking).people, new_person end - assert posts(:thinking).reload.people.reload.include?(new_person) + assert_includes posts(:thinking).reload.people.reload, new_person end def test_associate_new_by_building assert_queries(1) { posts(:thinking) } assert_queries(0) do - posts(:thinking).people.build(:first_name => "Bob") - posts(:thinking).people.new(:first_name => "Ted") + posts(:thinking).people.build(first_name: "Bob") + posts(:thinking).people.new(first_name: "Ted") end # Should only need to load the association once assert_queries(1) do - assert posts(:thinking).people.collect(&:first_name).include?("Bob") - assert posts(:thinking).people.collect(&:first_name).include?("Ted") + assert_includes posts(:thinking).people.collect(&:first_name), "Bob" + assert_includes posts(:thinking).people.collect(&:first_name), "Ted" end # 2 queries for each new record (1 to save the record itself, 1 for the join model) # * 2 new records = 4 # + 1 query to save the actual post = 5 assert_queries(5) do - posts(:thinking).body += '-changed' + posts(:thinking).body += "-changed" posts(:thinking).save end - assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Bob") - assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Ted") + assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Bob" + assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Ted" end def test_build_then_save_with_has_many_inverse post = posts(:thinking) - person = post.people.build(:first_name => "Bob") + person = post.people.build(first_name: "Bob") person.save post.reload - assert post.people.include?(person) + assert_includes post.people, person end def test_build_then_save_with_has_one_inverse post = posts(:thinking) - person = post.single_people.build(:first_name => "Bob") + person = post.single_people.build(first_name: "Bob") person.save post.reload - assert post.single_people.include?(person) + assert_includes post.single_people, person end def test_both_parent_ids_set_when_saving_new - post = Post.new(title: 'Hello', body: 'world') - person = Person.new(first_name: 'Sean') + post = Post.new(title: "Hello", body: "world") + person = Person.new(first_name: "Sean") post.people = [person] post.save @@ -348,7 +348,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_delete_association - assert_queries(2){posts(:welcome);people(:michael); } + assert_queries(2) { posts(:welcome);people(:michael); } assert_queries(1) do posts(:welcome).people.delete(people(:michael)) @@ -394,10 +394,10 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person = people(:michael) job = jobs(:magician) - reference = Reference.where(:job_id => job.id, :person_id => person.id).first + reference = Reference.where(job_id: job.id, person_id: person.id).first - assert_no_difference ['Job.count', 'Reference.count'] do - assert_difference 'person.jobs.count', -1 do + assert_no_difference ["Job.count", "Reference.count"] do + assert_difference "person.jobs.count", -1 do person.jobs_with_dependent_nullify.delete(job) end end @@ -416,8 +416,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # Make sure we're not deleting everything assert person.jobs.count >= 2 - assert_no_difference 'Job.count' do - assert_difference ['person.jobs.count', 'Reference.count'], -1 do + assert_no_difference "Job.count" do + assert_difference ["person.jobs.count", "Reference.count"], -1 do person.jobs_with_dependent_delete_all.delete(job) end end @@ -437,8 +437,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # Make sure we're not deleting everything assert person.jobs.count >= 2 - assert_no_difference 'Job.count' do - assert_difference ['person.jobs.count', 'Reference.count'], -1 do + assert_no_difference "Job.count" do + assert_difference ["person.jobs.count", "Reference.count"], -1 do person.jobs_with_dependent_destroy.delete(job) end end @@ -455,8 +455,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # Create a reference which is not linked to a job. This should not be destroyed. person.references.create! - assert_no_difference 'Job.count' do - assert_difference 'Reference.count', -person.jobs.count do + assert_no_difference "Job.count" do + assert_difference "Reference.count", -person.jobs.count do person.destroy end end @@ -468,8 +468,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # Create a reference which is not linked to a job. This should not be destroyed. person.references.create! - assert_no_difference 'Job.count' do - assert_difference 'Reference.count', -person.jobs.count do + assert_no_difference "Job.count" do + assert_difference "Reference.count", -person.jobs.count do person.destroy end end @@ -480,7 +480,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase references = person.references.to_a - assert_no_difference ['Reference.count', 'Job.count'] do + assert_no_difference ["Reference.count", "Job.count"] do person.destroy end @@ -491,30 +491,30 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_update_counter_caches_on_delete post = posts(:welcome) - tag = post.tags.create!(:name => 'doomed') + tag = post.tags.create!(name: "doomed") - assert_difference ['post.reload.tags_count'], -1 do + assert_difference ["post.reload.tags_count"], -1 do posts(:welcome).tags.delete(tag) end end def test_update_counter_caches_on_delete_with_dependent_destroy post = posts(:welcome) - tag = post.tags.create!(:name => 'doomed') + tag = post.tags.create!(name: "doomed") post.update_columns(tags_with_destroy_count: post.tags.count) - assert_difference ['post.reload.tags_with_destroy_count'], -1 do + assert_difference ["post.reload.tags_with_destroy_count"], -1 do posts(:welcome).tags_with_destroy.delete(tag) end end def test_update_counter_caches_on_delete_with_dependent_nullify post = posts(:welcome) - tag = post.tags.create!(:name => 'doomed') + tag = post.tags.create!(name: "doomed") post.update_columns(tags_with_nullify_count: post.tags.count) - assert_no_difference 'post.reload.tags_count' do - assert_difference 'post.reload.tags_with_nullify_count', -1 do + assert_no_difference "post.reload.tags_count" do + assert_difference "post.reload.tags_with_nullify_count", -1 do posts(:welcome).tags_with_nullify.delete(tag) end end @@ -522,7 +522,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_update_counter_caches_on_replace_association post = posts(:welcome) - tag = post.tags.create!(:name => 'doomed') + tag = post.tags.create!(name: "doomed") tag.tagged_posts << posts(:thinking) tag.tagged_posts = [] @@ -533,15 +533,15 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_update_counter_caches_on_destroy post = posts(:welcome) - tag = post.tags.create!(name: 'doomed') + tag = post.tags.create!(name: "doomed") - assert_difference 'post.reload.tags_count', -1 do + assert_difference "post.reload.tags_count", -1 do tag.tagged_posts.destroy(post) end end def test_replace_association - assert_queries(4){posts(:welcome);people(:david);people(:michael); posts(:welcome).people.reload} + assert_queries(4) { posts(:welcome);people(:david);people(:michael); posts(:welcome).people.reload } # 1 query to delete the existing reader (michael) # 1 query to associate the new reader (david) @@ -549,35 +549,35 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase posts(:welcome).people = [people(:david)] end - assert_queries(0){ - assert posts(:welcome).people.include?(people(:david)) - assert !posts(:welcome).people.include?(people(:michael)) + assert_queries(0) { + assert_includes posts(:welcome).people, people(:david) + assert_not_includes posts(:welcome).people, people(:michael) } - assert posts(:welcome).reload.people.reload.include?(people(:david)) - assert !posts(:welcome).reload.people.reload.include?(people(:michael)) + assert_includes posts(:welcome).reload.people.reload, people(:david) + assert_not_includes posts(:welcome).reload.people.reload, people(:michael) end def test_replace_order_is_preserved posts(:welcome).people.clear posts(:welcome).people = [people(:david), people(:michael)] - assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id) + assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id) # Test the inverse order in case the first success was a coincidence posts(:welcome).people.clear posts(:welcome).people = [people(:michael), people(:david)] - assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id) + assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id) end def test_replace_by_id_order_is_preserved posts(:welcome).people.clear posts(:welcome).person_ids = [people(:david).id, people(:michael).id] - assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order('id').map(&:person_id) + assert_equal [people(:david).id, people(:michael).id], posts(:welcome).readers.order("id").map(&:person_id) # Test the inverse order in case the first success was a coincidence posts(:welcome).people.clear posts(:welcome).person_ids = [people(:michael).id, people(:david).id] - assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order('id').map(&:person_id) + assert_equal [people(:michael).id, people(:david).id], posts(:welcome).readers.order("id").map(&:person_id) end def test_associate_with_create @@ -586,15 +586,15 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # 1 query for the new record, 1 for the join table record # No need to update the actual collection yet! assert_queries(2) do - posts(:thinking).people.create(:first_name=>"Jeb") + posts(:thinking).people.create(first_name: "Jeb") end # *Now* we actually need the collection so it's loaded assert_queries(1) do - assert posts(:thinking).people.collect(&:first_name).include?("Jeb") + assert_includes posts(:thinking).people.collect(&:first_name), "Jeb" end - assert posts(:thinking).reload.people.reload.collect(&:first_name).include?("Jeb") + assert_includes posts(:thinking).reload.people.reload.collect(&:first_name), "Jeb" end def test_through_record_is_built_when_created_with_where @@ -605,66 +605,66 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_associate_with_create_and_no_options peeps = posts(:thinking).people.count - posts(:thinking).people.create(:first_name => 'foo') + posts(:thinking).people.create(first_name: "foo") assert_equal peeps + 1, posts(:thinking).people.count end def test_associate_with_create_with_through_having_conditions impatient_people = posts(:thinking).impatient_people.count - posts(:thinking).impatient_people.create!(:first_name => 'foo') + posts(:thinking).impatient_people.create!(first_name: "foo") assert_equal impatient_people + 1, posts(:thinking).impatient_people.count end def test_associate_with_create_exclamation_and_no_options peeps = posts(:thinking).people.count - posts(:thinking).people.create!(:first_name => 'foo') + posts(:thinking).people.create!(first_name: "foo") assert_equal peeps + 1, posts(:thinking).people.count end def test_create_on_new_record p = Post.new - error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(:first_name => "mew") } + error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create(first_name: "mew") } assert_equal "You cannot call create unless the parent is saved", error.message - error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(:first_name => "snow") } + error = assert_raises(ActiveRecord::RecordNotSaved) { p.people.create!(first_name: "snow") } assert_equal "You cannot call create unless the parent is saved", error.message end def test_associate_with_create_and_invalid_options firm = companies(:first_firm) - assert_no_difference('firm.developers.count') { assert_nothing_raised { firm.developers.create(:name => '0') } } + assert_no_difference("firm.developers.count") { assert_nothing_raised { firm.developers.create(name: "0") } } end def test_associate_with_create_and_valid_options firm = companies(:first_firm) - assert_difference('firm.developers.count', 1) { firm.developers.create(:name => 'developer') } + assert_difference("firm.developers.count", 1) { firm.developers.create(name: "developer") } end def test_associate_with_create_bang_and_invalid_options firm = companies(:first_firm) - assert_no_difference('firm.developers.count') { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(:name => '0') } } + assert_no_difference("firm.developers.count") { assert_raises(ActiveRecord::RecordInvalid) { firm.developers.create!(name: "0") } } end def test_associate_with_create_bang_and_valid_options firm = companies(:first_firm) - assert_difference('firm.developers.count', 1) { firm.developers.create!(:name => 'developer') } + assert_difference("firm.developers.count", 1) { firm.developers.create!(name: "developer") } end def test_push_with_invalid_record firm = companies(:first_firm) - assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(:name => '0') } + assert_raises(ActiveRecord::RecordInvalid) { firm.developers << Developer.new(name: "0") } end def test_push_with_invalid_join_record repair_validations(Contract) do - Contract.validate {|r| r.errors[:base] << 'Invalid Contract' } + Contract.validate { |r| r.errors[:base] << "Invalid Contract" } firm = companies(:first_firm) - lifo = Developer.new(:name => 'lifo') + lifo = Developer.new(name: "lifo") assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo } - lifo = Developer.create!(:name => 'lifo') + lifo = Developer.create!(name: "lifo") assert_raises(ActiveRecord::RecordInvalid) { firm.developers << lifo } end end @@ -694,7 +694,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase [:added, :after, "Michael"] ], log.last(2) - post.people_with_callbacks.push(people(:david), Person.create!(:first_name => "Bob"), Person.new(:first_name => "Lary")) + post.people_with_callbacks.push(people(:david), Person.create!(first_name: "Bob"), Person.new(first_name: "Lary")) assert_equal [ [:added, :before, "David"], [:added, :after, "David"], @@ -704,19 +704,19 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase [:added, :after, "Lary"] ],log.last(6) - post.people_with_callbacks.build(:first_name => "Ted") + post.people_with_callbacks.build(first_name: "Ted") assert_equal [ [:added, :before, "Ted"], [:added, :after, "Ted"] ], log.last(2) - post.people_with_callbacks.create(:first_name => "Sam") + post.people_with_callbacks.create(first_name: "Sam") assert_equal [ [:added, :before, "Sam"], [:added, :after, "Sam"] ], log.last(2) - post.people_with_callbacks = [people(:michael),people(:david), Person.new(:first_name => "Julian"), Person.create!(:first_name => "Roger")] + post.people_with_callbacks = [people(:michael),people(:david), Person.new(first_name: "Julian"), Person.create!(first_name: "Roger")] assert_equal((%w(Ted Bob Sam Lary) * 2).sort, log[-12..-5].collect(&:last).sort) assert_equal [ [:added, :before, "Julian"], @@ -729,7 +729,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_dynamic_find_should_respect_association_include # SQL error in sort clause if :include is not included # due to Unknown column 'comments.id' - assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title('Welcome to the weblog') + assert Person.find(1).posts_with_comments_sorted_by_comment_id.find_by_title("Welcome to the weblog") end def test_count_with_include_should_alias_join_table @@ -745,7 +745,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_get_ids_for_has_many_through_with_conditions_should_not_preload - Tagging.create!(:taggable_type => 'Post', :taggable_id => posts(:welcome).id, :tag => tags(:misc)) + Tagging.create!(taggable_type: "Post", taggable_id: posts(:welcome).id, tag: tags(:misc)) assert_not_called(ActiveRecord::Associations::Preloader, :new) do posts(:welcome).misc_tag_ids end @@ -776,16 +776,16 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist - post = Post.create!(:title => "TITLE", :body => "BODY") + post = Post.create!(title: "TITLE", body: "BODY") assert_equal [], post.author_favorites end def test_has_many_association_through_a_belongs_to_association author = authors(:mary) - post = Post.create!(:author => author, :title => "TITLE", :body => "BODY") - author.author_favorites.create(:favorite_author_id => 1) - author.author_favorites.create(:favorite_author_id => 2) - author.author_favorites.create(:favorite_author_id => 3) + post = Post.create!(author: author, title: "TITLE", body: "BODY") + author.author_favorites.create(favorite_author_id: 1) + author.author_favorites.create(favorite_author_id: 2) + author.author_favorites.create(favorite_author_id: 3) assert_equal post.author.author_favorites, post.author_favorites end @@ -809,37 +809,37 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_modifying_has_many_through_has_one_reflection_should_raise [ - lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(:body => "Gorp!", :post_id => 1011), VerySpecialComment.create!(:body => "Eep!", :post_id => 1012)] }, - lambda { authors(:david).very_special_comments << VerySpecialComment.create!(:body => "Hoohah!", :post_id => 1013) }, + lambda { authors(:david).very_special_comments = [VerySpecialComment.create!(body: "Gorp!", post_id: 1011), VerySpecialComment.create!(body: "Eep!", post_id: 1012)] }, + lambda { authors(:david).very_special_comments << VerySpecialComment.create!(body: "Hoohah!", post_id: 1013) }, lambda { authors(:david).very_special_comments.delete(authors(:david).very_special_comments.first) }, - ].each {|block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } + ].each { |block| assert_raise(ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection, &block) } end def test_has_many_association_through_a_has_many_association_to_self - sarah = Person.create!(:first_name => 'Sarah', :primary_contact_id => people(:susan).id, :gender => 'F', :number1_fan_id => 1) - john = Person.create!(:first_name => 'John', :primary_contact_id => sarah.id, :gender => 'M', :number1_fan_id => 1) + sarah = Person.create!(first_name: "Sarah", primary_contact_id: people(:susan).id, gender: "F", number1_fan_id: 1) + john = Person.create!(first_name: "John", primary_contact_id: sarah.id, gender: "M", number1_fan_id: 1) assert_equal sarah.agents, [john] assert_equal people(:susan).agents.flat_map(&:agents), people(:susan).agents_of_agents end def test_associate_existing_with_nonstandard_primary_key_on_belongs_to - Categorization.create(:author => authors(:mary), :named_category_name => categories(:general).name) + Categorization.create(author: authors(:mary), named_category_name: categories(:general).name) assert_equal categories(:general), authors(:mary).named_categories.first end def test_collection_build_with_nonstandard_primary_key_on_belongs_to author = authors(:mary) - category = author.named_categories.build(:name => "Primary") + category = author.named_categories.build(name: "Primary") author.save - assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name) - assert author.named_categories.reload.include?(category) + assert Categorization.exists?(author_id: author.id, named_category_name: category.name) + assert_includes author.named_categories.reload, category end def test_collection_create_with_nonstandard_primary_key_on_belongs_to author = authors(:mary) - category = author.named_categories.create(:name => "Primary") - assert Categorization.exists?(:author_id => author.id, :named_category_name => category.name) - assert author.named_categories.reload.include?(category) + category = author.named_categories.create(name: "Primary") + assert Categorization.exists?(author_id: author.id, named_category_name: category.name) + assert_includes author.named_categories.reload, category end def test_collection_exists @@ -851,9 +851,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_collection_delete_with_nonstandard_primary_key_on_belongs_to author = authors(:mary) - category = author.named_categories.create(:name => "Primary") + category = author.named_categories.create(name: "Primary") author.named_categories.delete(category) - assert !Categorization.exists?(:author_id => author.id, :named_category_name => category.name) + assert !Categorization.exists?(author_id: author.id, named_category_name: category.name) assert author.named_categories.reload.empty? end @@ -886,20 +886,20 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set company = companies(:rails_core) ids = [Developer.first.id, -9999] - assert_raises(ActiveRecord::AssociationTypeMismatch) {company.developer_ids= ids} + assert_raises(ActiveRecord::AssociationTypeMismatch) { company.developer_ids= ids } end def test_build_a_model_from_hm_through_association_with_where_clause - assert_nothing_raised { books(:awdr).subscribers.where(:nick => "marklazz").build } + assert_nothing_raised { books(:awdr).subscribers.where(nick: "marklazz").build } end def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_where_clause - new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").build + new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").build assert_equal new_subscriber.nick, "marklazz" end def test_attributes_are_being_set_when_initialized_from_hm_through_association_with_multiple_where_clauses - new_subscriber = books(:awdr).subscribers.where(:nick => "marklazz").where(:name => 'Marcelo Giorgi').build + new_subscriber = books(:awdr).subscribers.where(nick: "marklazz").where(name: "Marcelo Giorgi").build assert_equal new_subscriber.nick, "marklazz" assert_equal new_subscriber.name, "Marcelo Giorgi" end @@ -908,14 +908,14 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase person = Person.new reference = person.references.build job = reference.build_job - assert person.jobs.include?(job) + assert_includes person.jobs, job end def test_include_method_in_association_through_should_return_true_for_instance_added_with_nested_builds author = Author.new post = author.posts.build comment = post.comments.build - assert author.comments.include?(comment) + assert_includes author.comments, comment end def test_through_association_readonly_should_be_false @@ -932,7 +932,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_polymorphic_with_primary_key_option assert_equal [categories(:general)], authors(:david).essay_categories - authors = Author.joins(:essay_categories).where('categories.id' => categories(:general).id) + authors = Author.joins(:essay_categories).where("categories.id" => categories(:general).id) assert_equal authors(:david), authors.first assert_equal [owners(:blackbeard)], authors(:david).essay_owners @@ -944,7 +944,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_with_primary_key_option assert_equal [categories(:general)], authors(:david).essay_categories_2 - authors = Author.joins(:essay_categories_2).where('categories.id' => categories(:general).id) + authors = Author.joins(:essay_categories_2).where("categories.id" => categories(:general).id) assert_equal authors(:david), authors.first end @@ -956,30 +956,30 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_through_with_default_scope_on_join_model - assert_equal posts(:welcome).comments.order('id').to_a, authors(:david).comments_on_first_posts + assert_equal posts(:welcome).comments.order("id").to_a, authors(:david).comments_on_first_posts end def test_create_has_many_through_with_default_scope_on_join_model - category = authors(:david).special_categories.create(:name => "Foo") - assert_equal 1, category.categorizations.where(:special => true).count + category = authors(:david).special_categories.create(name: "Foo") + assert_equal 1, category.categorizations.where(special: true).count end def test_joining_has_many_through_with_distinct - mary = Author.joins(:unique_categorized_posts).where(:id => authors(:mary).id).first + mary = Author.joins(:unique_categorized_posts).where(id: authors(:mary).id).first assert_equal 1, mary.unique_categorized_posts.length assert_equal 1, mary.unique_categorized_post_ids.length end def test_joining_has_many_through_belongs_to - posts = Post.joins(:author_categorizations).order('posts.id'). - where('categorizations.id' => categorizations(:mary_thinking_sti).id) + posts = Post.joins(:author_categorizations).order("posts.id"). + where("categorizations.id" => categorizations(:mary_thinking_sti).id) assert_equal [posts(:eager_other), posts(:misc_by_mary), posts(:other_by_mary)], posts end def test_select_chosen_fields_only author = authors(:david) - assert_equal ['body', 'id'].sort, author.comments.select('comments.body').first.attributes.keys.sort + assert_equal ["body", "id"].sort, author.comments.select("comments.body").first.attributes.keys.sort end def test_get_has_many_through_belongs_to_ids_with_conditions @@ -1022,7 +1022,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase post = posts(:welcome) address = author_addresses(:david_address) - assert post.author_addresses.include?(address) + assert_includes post.author_addresses, address post.author_addresses.delete(address) assert post[:author_count].nil? end @@ -1030,7 +1030,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_primary_key_option_on_source post = posts(:welcome) category = categories(:general) - Categorization.create!(:post_id => post.id, :named_category_name => category.name) + Categorization.create!(post_id: post.id, named_category_name: category.name) assert_equal [category], post.named_categories assert_equal [category.name], post.named_category_ids # checks when target loaded @@ -1039,29 +1039,29 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_create_should_not_raise_exception_when_join_record_has_errors repair_validations(Categorization) do - Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } - Category.create(:name => 'Fishing', :authors => [Author.first]) + Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" } + Category.create(name: "Fishing", authors: [Author.first]) end end def test_assign_array_to_new_record_builds_join_records - c = Category.new(:name => 'Fishing', :authors => [Author.first]) + c = Category.new(name: "Fishing", authors: [Author.first]) assert_equal 1, c.categorizations.size end def test_create_bang_should_raise_exception_when_join_record_has_errors repair_validations(Categorization) do - Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } + Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" } assert_raises(ActiveRecord::RecordInvalid) do - Category.create!(:name => 'Fishing', :authors => [Author.first]) + Category.create!(name: "Fishing", authors: [Author.first]) end end end def test_save_bang_should_raise_exception_when_join_record_has_errors repair_validations(Categorization) do - Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } - c = Category.new(:name => 'Fishing', :authors => [Author.first]) + Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" } + c = Category.new(name: "Fishing", authors: [Author.first]) assert_raises(ActiveRecord::RecordInvalid) do c.save! end @@ -1070,17 +1070,17 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_save_returns_falsy_when_join_record_has_errors repair_validations(Categorization) do - Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } - c = Category.new(:name => 'Fishing', :authors => [Author.first]) + Categorization.validate { |r| r.errors[:base] << "Invalid Categorization" } + c = Category.new(name: "Fishing", authors: [Author.first]) assert_not c.save end end def test_preloading_empty_through_association_via_joins - person = Person.create!(:first_name => "Gaga") - person = Person.where(:id => person.id).where('readers.id = 1 or 1=1').references(:readers).includes(:posts).to_a.first + person = Person.create!(first_name: "Gaga") + person = Person.where(id: person.id).where("readers.id = 1 or 1=1").references(:readers).includes(:posts).to_a.first - assert person.posts.loaded?, 'person.posts should be loaded' + assert person.posts.loaded?, "person.posts should be loaded" assert_equal [], person.posts end @@ -1101,13 +1101,13 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_through_with_polymorphic_source - post = tags(:general).tagged_posts.create! :title => "foo", :body => "bar" + post = tags(:general).tagged_posts.create! title: "foo", body: "bar" assert_equal [tags(:general)], post.reload.tags end def test_has_many_through_obeys_order_on_through_association owner = owners(:blackbeard) - assert owner.toys.to_sql.include?("pets.name desc") + assert_includes owner.toys.to_sql, "pets.name desc" assert_equal ["parrot", "bulbul"], owner.toys.map { |r| r.pet.name } end @@ -1116,7 +1116,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_no_queries(ignore_none: false) do assert_equal [], person.posts - assert_equal [], person.posts.where(body: 'omg') + assert_equal [], person.posts.where(body: "omg") assert_equal [], person.posts.pluck(:body) assert_equal 0, person.posts.sum(:tags_count) assert_equal 0, person.posts.count @@ -1148,9 +1148,9 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_through_unscope_default_scope - post = Post.create!(:title => 'Beaches', :body => "I like beaches!") - Reader.create! :person => people(:david), :post => post - LazyReader.create! :person => people(:susan), :post => post + post = Post.create!(title: "Beaches", body: "I like beaches!") + Reader.create! person: people(:david), post: post + LazyReader.create! person: people(:susan), post: post assert_equal 2, post.people.to_a.size assert_equal 1, post.lazy_people.to_a.size @@ -1160,8 +1160,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_through_add_with_sti_middle_relation - club = SuperClub.create!(name: 'Fight Club') - member = Member.create!(name: 'Tyler Durden') + club = SuperClub.create!(name: "Fight Club") + member = Member.create!(name: "Tyler Durden") club.members << member assert_equal 1, SuperMembership.where(member_id: member.id, club_id: club.id).count diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 1574f373c2..1a0e6d2f8e 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -1,15 +1,15 @@ require "cases/helper" -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/company' -require 'models/ship' -require 'models/pirate' -require 'models/car' -require 'models/bulb' -require 'models/author' -require 'models/image' -require 'models/post' +require "models/developer" +require "models/computer" +require "models/project" +require "models/company" +require "models/ship" +require "models/pirate" +require "models/car" +require "models/bulb" +require "models/author" +require "models/image" +require "models/post" class HasOneAssociationsTest < ActiveRecord::TestCase self.use_transactional_tests = false unless supports_savepoints? @@ -28,7 +28,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase ActiveRecord::SQLCounter.clear_log companies(:first_firm).account ensure - assert ActiveRecord::SQLCounter.log_all.all? { |sql| /order by/i !~ sql }, 'ORDER BY was used in the query' + assert ActiveRecord::SQLCounter.log_all.all? { |sql| /order by/i !~ sql }, "ORDER BY was used in the query" end def test_has_one_cache_nils @@ -36,13 +36,13 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_queries(1) { assert_nil firm.account } assert_queries(0) { assert_nil firm.account } - firms = Firm.all.merge!(:includes => :account).to_a + firms = Firm.all.merge!(includes: :account).to_a assert_queries(0) { firms.each(&:account) } end def test_with_select assert_equal Firm.find(1).account_with_select.attributes.size, 2 - assert_equal Firm.all.merge!(:includes => :account_with_select).find(1).account_with_select.attributes.size, 2 + assert_equal Firm.all.merge!(includes: :account_with_select).find(1).account_with_select.attributes.size, 2 end def test_finding_using_primary_key @@ -102,7 +102,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_nullification_on_association_change firm = companies(:rails_core) old_account_id = firm.account.id - firm.account = Account.new(:credit_limit => 5) + firm.account = Account.new(credit_limit: 5) # account is dependent with nullify, therefore its firm_id should be nil assert_nil Account.find(old_account_id).firm_id end @@ -125,12 +125,12 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_association_change_calls_delete - companies(:first_firm).deletable_account = Account.new(:credit_limit => 5) + companies(:first_firm).deletable_account = Account.new(credit_limit: 5) assert_equal [], Account.destroyed_account_ids[companies(:first_firm).id] end def test_association_change_calls_destroy - companies(:first_firm).account = Account.new(:credit_limit => 5) + companies(:first_firm).account = Account.new(credit_limit: 5) assert_equal [companies(:first_firm).id], Account.destroyed_account_ids[companies(:first_firm).id] end @@ -170,27 +170,27 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_dependence_with_nil_associate - firm = DependentFirm.new(:name => 'nullify') + firm = DependentFirm.new(name: "nullify") firm.save! assert_nothing_raised { firm.destroy } end def test_restrict_with_exception - firm = RestrictedWithExceptionFirm.create!(:name => 'restrict') - firm.create_account(:credit_limit => 10) + firm = RestrictedWithExceptionFirm.create!(name: "restrict") + firm.create_account(credit_limit: 10) assert_not_nil firm.account assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } - assert RestrictedWithExceptionFirm.exists?(:name => 'restrict') + assert RestrictedWithExceptionFirm.exists?(name: "restrict") assert firm.account.present? end def test_restrict_with_error_is_deprecated_using_key_one I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { one: 'message for deprecated key' } } } } + I18n.backend.store_translations :en, activerecord: { errors: { messages: { restrict_dependent_destroy: { one: "message for deprecated key" } } } } - firm = RestrictedWithErrorFirm.create!(name: 'restrict') + firm = RestrictedWithErrorFirm.create!(name: "restrict") firm.create_account(credit_limit: 10) assert_not_nil firm.account @@ -198,16 +198,16 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_deprecated { firm.destroy } assert !firm.errors.empty? - assert_equal 'message for deprecated key', firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(name: 'restrict') + assert_equal "message for deprecated key", firm.errors[:base].first + assert RestrictedWithErrorFirm.exists?(name: "restrict") assert firm.account.present? ensure I18n.backend.reload! end def test_restrict_with_error - firm = RestrictedWithErrorFirm.create!(:name => 'restrict') - firm.create_account(:credit_limit => 10) + firm = RestrictedWithErrorFirm.create!(name: "restrict") + firm.create_account(credit_limit: 10) assert_not_nil firm.account @@ -215,14 +215,14 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert !firm.errors.empty? assert_equal "Cannot delete record because a dependent account exists", firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(:name => 'restrict') + assert RestrictedWithErrorFirm.exists?(name: "restrict") assert firm.account.present? end def test_restrict_with_error_with_locale I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations 'en', activerecord: {attributes: {restricted_with_error_firm: {account: 'firm account'}}} - firm = RestrictedWithErrorFirm.create!(name: 'restrict') + I18n.backend.store_translations "en", activerecord: { attributes: { restricted_with_error_firm: { account: "firm account" } } } + firm = RestrictedWithErrorFirm.create!(name: "restrict") firm.create_account(credit_limit: 10) assert_not_nil firm.account @@ -231,7 +231,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert !firm.errors.empty? assert_equal "Cannot delete record because a dependent firm account exists", firm.errors[:base].first - assert RestrictedWithErrorFirm.exists?(name: 'restrict') + assert RestrictedWithErrorFirm.exists?(name: "restrict") assert firm.account.present? ensure I18n.backend.reload! @@ -260,24 +260,24 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_building_the_associated_object_with_explicit_sti_base_class firm = DependentFirm.new - company = firm.build_company(:type => "Company") + company = firm.build_company(type: "Company") assert_kind_of Company, company, "Expected #{company.class} to be a Company" end def test_building_the_associated_object_with_sti_subclass firm = DependentFirm.new - company = firm.build_company(:type => "Client") + company = firm.build_company(type: "Client") assert_kind_of Client, company, "Expected #{company.class} to be a Client" end def test_building_the_associated_object_with_an_invalid_type firm = DependentFirm.new - assert_raise(ActiveRecord::SubclassNotFound) { firm.build_company(:type => "Invalid") } + assert_raise(ActiveRecord::SubclassNotFound) { firm.build_company(type: "Invalid") } end def test_building_the_associated_object_with_an_unrelated_type firm = DependentFirm.new - assert_raise(ActiveRecord::SubclassNotFound) { firm.build_company(:type => "Account") } + assert_raise(ActiveRecord::SubclassNotFound) { firm.build_company(type: "Account") } end def test_build_and_create_should_not_happen_within_scope @@ -295,19 +295,19 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_create_association - firm = Firm.create(:name => "GlobalMegaCorp") - account = firm.create_account(:credit_limit => 1000) + firm = Firm.create(name: "GlobalMegaCorp") + account = firm.create_account(credit_limit: 1000) assert_equal account, firm.reload.account end def test_create_association_with_bang - firm = Firm.create(:name => "GlobalMegaCorp") - account = firm.create_account!(:credit_limit => 1000) + firm = Firm.create(name: "GlobalMegaCorp") + account = firm.create_account!(credit_limit: 1000) assert_equal account, firm.reload.account end def test_create_association_with_bang_failing - firm = Firm.create(:name => "GlobalMegaCorp") + firm = Firm.create(name: "GlobalMegaCorp") assert_raise ActiveRecord::RecordInvalid do firm.create_account! end @@ -319,7 +319,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_create_with_inexistent_foreign_key_failing - firm = Firm.create(name: 'GlobalMegaCorp') + firm = Firm.create(name: "GlobalMegaCorp") assert_raises(ActiveRecord::UnknownAttributeError) do firm.create_account_with_inexistent_foreign_key @@ -365,7 +365,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_finding_with_interpolated_condition firm = Firm.first - superior = firm.clients.create(:name => 'SuperiorCo') + superior = firm.clients.create(name: "SuperiorCo") superior.rating = 10 superior.save assert_equal 10, firm.clients_with_interpolated_conditions.first.rating @@ -382,7 +382,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_save_still_works_after_accessing_nil_has_one - jp = Company.new :name => 'Jaded Pixel' + jp = Company.new name: "Jaded Pixel" jp.dummy_account.nil? assert_nothing_raised do @@ -411,14 +411,14 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_nothing_raised do Firm.find(@firm.id).save! - Firm.all.merge!(:includes => :account).find(@firm.id).save! + Firm.all.merge!(includes: :account).find(@firm.id).save! end @firm.account.destroy assert_nothing_raised do Firm.find(@firm.id).save! - Firm.all.merge!(:includes => :account).find(@firm.id).save! + Firm.all.merge!(includes: :account).find(@firm.id).save! end end @@ -435,7 +435,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_attributes_are_being_set_when_initialized_from_has_one_association_with_where_clause - new_account = companies(:first_firm).build_account(:firm_name => 'Account') + new_account = companies(:first_firm).build_account(firm_name: "Account") assert_equal new_account.firm_name, "Account" end @@ -505,63 +505,63 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_association_keys_bypass_attribute_protection - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") bulb = car.build_bulb assert_equal car.id, bulb.car_id - bulb = car.build_bulb :car_id => car.id + 1 + bulb = car.build_bulb car_id: car.id + 1 assert_equal car.id, bulb.car_id bulb = car.create_bulb assert_equal car.id, bulb.car_id - bulb = car.create_bulb :car_id => car.id + 1 + bulb = car.create_bulb car_id: car.id + 1 assert_equal car.id, bulb.car_id end def test_association_protect_foreign_key - pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") + pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") ship = pirate.build_ship assert_equal pirate.id, ship.pirate_id - ship = pirate.build_ship :pirate_id => pirate.id + 1 + ship = pirate.build_ship pirate_id: pirate.id + 1 assert_equal pirate.id, ship.pirate_id ship = pirate.create_ship assert_equal pirate.id, ship.pirate_id - ship = pirate.create_ship :pirate_id => pirate.id + 1 + ship = pirate.create_ship pirate_id: pirate.id + 1 assert_equal pirate.id, ship.pirate_id end def test_build_with_block - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") - bulb = car.build_bulb{ |b| b.color = 'Red' } - assert_equal 'RED!', bulb.color + bulb = car.build_bulb { |b| b.color = "Red" } + assert_equal "RED!", bulb.color end def test_create_with_block - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") - bulb = car.create_bulb{ |b| b.color = 'Red' } - assert_equal 'RED!', bulb.color + bulb = car.create_bulb { |b| b.color = "Red" } + assert_equal "RED!", bulb.color end def test_create_bang_with_block - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") - bulb = car.create_bulb!{ |b| b.color = 'Red' } - assert_equal 'RED!', bulb.color + bulb = car.create_bulb! { |b| b.color = "Red" } + assert_equal "RED!", bulb.color end def test_association_attributes_are_available_to_after_initialize - car = Car.create(:name => 'honda') + car = Car.create(name: "honda") bulb = car.create_bulb - assert_equal car.id, bulb.attributes_after_initialize['car_id'] + assert_equal car.id, bulb.attributes_after_initialize["car_id"] end def test_has_one_transaction @@ -581,36 +581,36 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_has_one_assignment_dont_trigger_save_on_change_of_same_object pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") - ship = pirate.build_ship(name: 'old name') + ship = pirate.build_ship(name: "old name") ship.save! - ship.name = 'new name' + ship.name = "new name" assert ship.changed? assert_queries(1) do # One query for updating name, not triggering query for updating pirate_id pirate.ship = ship end - assert_equal 'new name', pirate.ship.reload.name + assert_equal "new name", pirate.ship.reload.name end def test_has_one_assignment_triggers_save_on_change_on_replacing_object pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") - ship = pirate.build_ship(name: 'old name') + ship = pirate.build_ship(name: "old name") ship.save! - new_ship = Ship.create(name: 'new name') + new_ship = Ship.create(name: "new name") assert_queries(2) do # One query for updating name and second query for updating pirate_id pirate.ship = new_ship end - assert_equal 'new name', pirate.ship.reload.name + assert_equal "new name", pirate.ship.reload.name end def test_has_one_autosave_with_primary_key_manually_set - post = Post.create(id: 1234, title: "Some title", body: 'Some content') - author = Author.new(id: 33, name: 'Hank Moody') + post = Post.create(id: 1234, title: "Some title", body: "Some content") + author = Author.new(id: 33, name: "Hank Moody") author.post = post author.save @@ -621,7 +621,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_has_one_loading_for_new_record - post = Post.create!(author_id: 42, title: 'foo', body: 'bar') + post = Post.create!(author_id: 42, title: "foo", body: "bar") author = Author.new(id: 42) assert_equal post, author.post end @@ -635,7 +635,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_with_polymorphic_has_one_with_custom_columns_name - post = Post.create! :title => 'foo', :body => 'bar' + post = Post.create! title: "foo", body: "bar" image = Image.create! post.main_image = image @@ -644,8 +644,8 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal image, post.main_image end - test 'dangerous association name raises ArgumentError' do - [:errors, 'errors', :save, 'save'].each do |name| + test "dangerous association name raises ArgumentError" do + [:errors, "errors", :save, "save"].each do |name| assert_raises(ArgumentError, "Association #{name} should not be allowed") do Class.new(ActiveRecord::Base) do has_one name @@ -661,20 +661,20 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end class SpecialBook < ActiveRecord::Base - self.table_name = 'books' - belongs_to :author, class_name: 'SpecialAuthor' + self.table_name = "books" + belongs_to :author, class_name: "SpecialAuthor" end class SpecialAuthor < ActiveRecord::Base - self.table_name = 'authors' - has_one :book, class_name: 'SpecialBook', foreign_key: 'author_id' + self.table_name = "authors" + has_one :book, class_name: "SpecialBook", foreign_key: "author_id" end def test_assocation_enum_works_properly - author = SpecialAuthor.create!(name: 'Test') - book = SpecialBook.create!(status: 'published') + author = SpecialAuthor.create!(name: "Test") + book = SpecialBook.create!(status: "published") author.book = book - refute_equal 0, SpecialAuthor.joins(:book).where(books: { status: 'published' } ).count + refute_equal 0, SpecialAuthor.joins(:book).where(books: { status: "published" } ).count end end diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb index b2b46812b9..b2f47d2daf 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -1,25 +1,25 @@ require "cases/helper" -require 'models/club' -require 'models/member_type' -require 'models/member' -require 'models/membership' -require 'models/sponsor' -require 'models/organization' -require 'models/member_detail' -require 'models/minivan' -require 'models/dashboard' -require 'models/speedometer' -require 'models/category' -require 'models/author' -require 'models/essay' -require 'models/owner' -require 'models/post' -require 'models/comment' -require 'models/categorization' -require 'models/customer' -require 'models/carrier' -require 'models/shop_account' -require 'models/customer_carrier' +require "models/club" +require "models/member_type" +require "models/member" +require "models/membership" +require "models/sponsor" +require "models/organization" +require "models/member_detail" +require "models/minivan" +require "models/dashboard" +require "models/speedometer" +require "models/category" +require "models/author" +require "models/essay" +require "models/owner" +require "models/post" +require "models/comment" +require "models/categorization" +require "models/customer" +require "models/carrier" +require "models/shop_account" +require "models/customer_carrier" class HasOneThroughAssociationsTest < ActiveRecord::TestCase fixtures :member_types, :members, :clubs, :memberships, :sponsors, :organizations, :minivans, @@ -34,14 +34,14 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_creating_association_creates_through_record - new_member = Member.create(:name => "Chris") - new_member.club = Club.create(:name => "LRUG") + new_member = Member.create(name: "Chris") + new_member.club = Club.create(name: "LRUG") assert_not_nil new_member.current_membership assert_not_nil new_member.club end def test_creating_association_builds_through_record_for_new - new_member = Member.new(:name => "Jane") + new_member = Member.new(name: "Jane") new_member.club = clubs(:moustache_club) assert new_member.current_membership assert_equal clubs(:moustache_club), new_member.current_membership.club @@ -51,8 +51,8 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_creating_association_sets_both_parent_ids_for_new - member = Member.new(name: 'Sean Griffin') - club = Club.new(name: 'Da Club') + member = Member.new(name: "Sean Griffin") + club = Club.new(name: "Da Club") member.club = club @@ -65,7 +65,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_replace_target_record - new_club = Club.create(:name => "Marx Bros") + new_club = Club.create(name: "Marx Bros") @member.club = new_club @member.reload assert_equal new_club, @member.club @@ -73,7 +73,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase def test_replacing_target_record_deletes_old_association assert_no_difference "Membership.count" do - new_club = Club.create(:name => "Bananarama") + new_club = Club.create(name: "Bananarama") @member.club = new_club @member.reload end @@ -92,30 +92,30 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase def test_has_one_through_eager_loading members = assert_queries(3) do #base table, through table, clubs table - Member.all.merge!(:includes => :club, :where => ["name = ?", "Groucho Marx"]).to_a + Member.all.merge!(includes: :club, where: ["name = ?", "Groucho Marx"]).to_a end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].club} + assert_not_nil assert_no_queries { members[0].club } end def test_has_one_through_eager_loading_through_polymorphic members = assert_queries(3) do #base table, through table, clubs table - Member.all.merge!(:includes => :sponsor_club, :where => ["name = ?", "Groucho Marx"]).to_a + Member.all.merge!(includes: :sponsor_club, where: ["name = ?", "Groucho Marx"]).to_a end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].sponsor_club} + assert_not_nil assert_no_queries { members[0].sponsor_club } end def test_has_one_through_with_conditions_eager_loading # conditions on the through table - assert_equal clubs(:moustache_club), Member.all.merge!(:includes => :favourite_club).find(@member.id).favourite_club + assert_equal clubs(:moustache_club), Member.all.merge!(includes: :favourite_club).find(@member.id).favourite_club memberships(:membership_of_favourite_club).update_columns(favourite: false) - assert_equal nil, Member.all.merge!(:includes => :favourite_club).find(@member.id).reload.favourite_club + assert_equal nil, Member.all.merge!(includes: :favourite_club).find(@member.id).reload.favourite_club # conditions on the source table - assert_equal clubs(:moustache_club), Member.all.merge!(:includes => :hairy_club).find(@member.id).hairy_club + assert_equal clubs(:moustache_club), Member.all.merge!(includes: :hairy_club).find(@member.id).hairy_club clubs(:moustache_club).update_columns(name: "Association of Clean-Shaven Persons") - assert_equal nil, Member.all.merge!(:includes => :hairy_club).find(@member.id).reload.hairy_club + assert_equal nil, Member.all.merge!(includes: :hairy_club).find(@member.id).reload.hairy_club end def test_has_one_through_polymorphic_with_source_type @@ -123,31 +123,31 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_eager_has_one_through_polymorphic_with_source_type - clubs = Club.all.merge!(:includes => :sponsored_member, :where => ["name = ?","Moustache and Eyebrow Fancier Club"]).to_a + clubs = Club.all.merge!(includes: :sponsored_member, where: ["name = ?","Moustache and Eyebrow Fancier Club"]).to_a # Only the eyebrow fanciers club has a sponsored_member - assert_not_nil assert_no_queries {clubs[0].sponsored_member} + assert_not_nil assert_no_queries { clubs[0].sponsored_member } end def test_has_one_through_nonpreload_eagerloading members = assert_queries(1) do - Member.all.merge!(:includes => :club, :where => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name').to_a #force fallback + Member.all.merge!(includes: :club, where: ["members.name = ?", "Groucho Marx"], order: "clubs.name").to_a #force fallback end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].club} + assert_not_nil assert_no_queries { members[0].club } end def test_has_one_through_nonpreload_eager_loading_through_polymorphic members = assert_queries(1) do - Member.all.merge!(:includes => :sponsor_club, :where => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name').to_a #force fallback + Member.all.merge!(includes: :sponsor_club, where: ["members.name = ?", "Groucho Marx"], order: "clubs.name").to_a #force fallback end assert_equal 1, members.size - assert_not_nil assert_no_queries {members[0].sponsor_club} + assert_not_nil assert_no_queries { members[0].sponsor_club } end def test_has_one_through_nonpreload_eager_loading_through_polymorphic_with_more_than_one_through_record - Sponsor.new(:sponsor_club => clubs(:crazy_club), :sponsorable => members(:groucho)).save! + Sponsor.new(sponsor_club: clubs(:crazy_club), sponsorable: members(:groucho)).save! members = assert_queries(1) do - Member.all.merge!(:includes => :sponsor_club, :where => ["members.name = ?", "Groucho Marx"], :order => 'clubs.name DESC').to_a #force fallback + Member.all.merge!(includes: :sponsor_club, where: ["members.name = ?", "Groucho Marx"], order: "clubs.name DESC").to_a #force fallback end assert_equal 1, members.size assert_not_nil assert_no_queries { members[0].sponsor_club } @@ -159,8 +159,8 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_assigning_association_correctly_assigns_target - new_member = Member.create(:name => "Chris") - new_member.club = new_club = Club.create(:name => "LRUG") + new_member = Member.create(name: "Chris") + new_member.club = new_club = Club.create(name: "LRUG") assert_equal new_club, new_member.association(:club).target end @@ -176,37 +176,37 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase def test_assigning_to_has_one_through_preserves_decorated_join_record @organization = organizations(:nsa) - assert_difference 'MemberDetail.count', 1 do - @member_detail = MemberDetail.new(:extra_data => 'Extra') + assert_difference "MemberDetail.count", 1 do + @member_detail = MemberDetail.new(extra_data: "Extra") @member.member_detail = @member_detail @member.organization = @organization end assert_equal @organization, @member.organization - assert @organization.members.include?(@member) - assert_equal 'Extra', @member.member_detail.extra_data + assert_includes @organization.members, @member + assert_equal "Extra", @member.member_detail.extra_data end def test_reassigning_has_one_through @organization = organizations(:nsa) @new_organization = organizations(:discordians) - assert_difference 'MemberDetail.count', 1 do - @member_detail = MemberDetail.new(:extra_data => 'Extra') + assert_difference "MemberDetail.count", 1 do + @member_detail = MemberDetail.new(extra_data: "Extra") @member.member_detail = @member_detail @member.organization = @organization end assert_equal @organization, @member.organization - assert_equal 'Extra', @member.member_detail.extra_data - assert @organization.members.include?(@member) - assert !@new_organization.members.include?(@member) + assert_equal "Extra", @member.member_detail.extra_data + assert_includes @organization.members, @member + assert_not_includes @new_organization.members, @member - assert_no_difference 'MemberDetail.count' do + assert_no_difference "MemberDetail.count" do @member.organization = @new_organization end assert_equal @new_organization, @member.organization - assert_equal 'Extra', @member.member_detail.extra_data - assert !@organization.members.include?(@member) - assert @new_organization.members.include?(@member) + assert_equal "Extra", @member.member_detail.extra_data + assert_not_includes @organization.members, @member + assert_includes @new_organization.members, @member end def test_preloading_has_one_through_on_belongs_to @@ -217,7 +217,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase @member.member_detail = @member_detail @member.organization = @organization @member_details = assert_queries(3) do - MemberDetail.all.merge!(:includes => :member_type).to_a + MemberDetail.all.merge!(includes: :member_type).to_a end @new_detail = @member_details[0] assert @new_detail.send(:association, :member_type).loaded? @@ -230,19 +230,19 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase assert_nothing_raised do Club.find(@club.id).save! - Club.all.merge!(:includes => :sponsored_member).find(@club.id).save! + Club.all.merge!(includes: :sponsored_member).find(@club.id).save! end @club.sponsor.destroy assert_nothing_raised do Club.find(@club.id).save! - Club.all.merge!(:includes => :sponsored_member).find(@club.id).save! + Club.all.merge!(includes: :sponsored_member).find(@club.id).save! end end def test_through_belongs_to_after_destroy - @member_detail = MemberDetail.new(:extra_data => 'Extra') + @member_detail = MemberDetail.new(extra_data: "Extra") @member.member_detail = @member_detail @member.save! @@ -261,7 +261,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_value_is_properly_quoted - minivan = Minivan.find('m1') + minivan = Minivan.find("m1") assert_nothing_raised do minivan.dashboard end @@ -270,7 +270,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase def test_has_one_through_polymorphic_with_primary_key_option assert_equal categories(:general), authors(:david).essay_category - authors = Author.joins(:essay_category).where('categories.id' => categories(:general).id) + authors = Author.joins(:essay_category).where("categories.id" => categories(:general).id) assert_equal authors(:david), authors.first assert_equal owners(:blackbeard), authors(:david).essay_owner @@ -282,12 +282,12 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase def test_has_one_through_with_primary_key_option assert_equal categories(:general), authors(:david).essay_category_2 - authors = Author.joins(:essay_category_2).where('categories.id' => categories(:general).id) + authors = Author.joins(:essay_category_2).where("categories.id" => categories(:general).id) assert_equal authors(:david), authors.first end def test_has_one_through_with_default_scope_on_join_model - assert_equal posts(:welcome).comments.order('id').first, authors(:david).comment_on_first_post + assert_equal posts(:welcome).comments.order("id").first, authors(:david).comment_on_first_post end def test_has_one_through_many_raises_exception diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index b3fe759ad9..7414869c8f 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -1,13 +1,13 @@ require "cases/helper" -require 'models/post' -require 'models/comment' -require 'models/author' -require 'models/essay' -require 'models/category' -require 'models/categorization' -require 'models/person' -require 'models/tagging' -require 'models/tag' +require "models/post" +require "models/comment" +require "models/author" +require "models/essay" +require "models/category" +require "models/categorization" +require "models/person" +require "models/tagging" +require "models/tag" class InnerJoinAssociationTest < ActiveRecord::TestCase fixtures :authors, :essays, :posts, :comments, :categories, :categories_posts, :categorizations, @@ -20,7 +20,7 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associations assert_nothing_raised do - sql = Person.joins(:agents => {:agents => :agents}).joins(:agents => {:agents => {:primary_contact => :agents}}).to_sql + sql = Person.joins(agents: { agents: :agents }).joins(agents: { agents: { primary_contact: :agents } }).to_sql assert_match(/agents_people_4/i, sql) end end @@ -47,7 +47,7 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase end def test_join_conditions_allow_nil_associations - authors = Author.includes(:essays).where(:essays => {:id => nil}) + authors = Author.includes(:essays).where(essays: { id: nil }) assert_equal 2, authors.count end @@ -58,41 +58,41 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase end def test_find_with_implicit_inner_joins_honors_readonly_with_select - authors = Author.joins(:posts).select('authors.*').to_a + authors = Author.joins(:posts).select("authors.*").to_a assert !authors.empty?, "expected authors to be non-empty" - assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly" + assert authors.all? { |a| !a.readonly? }, "expected no authors to be readonly" end def test_find_with_implicit_inner_joins_honors_readonly_false authors = Author.joins(:posts).readonly(false).to_a assert !authors.empty?, "expected authors to be non-empty" - assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly" + assert authors.all? { |a| !a.readonly? }, "expected no authors to be readonly" end def test_find_with_implicit_inner_joins_does_not_set_associations - authors = Author.joins(:posts).select('authors.*').to_a + authors = Author.joins(:posts).select("authors.*").to_a assert !authors.empty?, "expected authors to be non-empty" assert authors.all? { |a| !a.instance_variable_defined?(:@posts) }, "expected no authors to have the @posts association loaded" end def test_count_honors_implicit_inner_joins - real_count = Author.all.to_a.sum{|a| a.posts.count } + real_count = Author.all.to_a.sum { |a| a.posts.count } assert_equal real_count, Author.joins(:posts).count, "plain inner join count should match the number of referenced posts records" end def test_calculate_honors_implicit_inner_joins - real_count = Author.all.to_a.sum{|a| a.posts.count } - assert_equal real_count, Author.joins(:posts).calculate(:count, 'authors.id'), "plain inner join count should match the number of referenced posts records" + real_count = Author.all.to_a.sum { |a| a.posts.count } + assert_equal real_count, Author.joins(:posts).calculate(:count, "authors.id"), "plain inner join count should match the number of referenced posts records" end def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions - real_count = Author.all.to_a.select {|a| a.posts.any? {|p| p.title =~ /^Welcome/} }.length - authors_with_welcoming_post_titles = Author.all.merge!(joins: :posts, where: "posts.title like 'Welcome%'").distinct.calculate(:count, 'authors.id') + real_count = Author.all.to_a.select { |a| a.posts.any? { |p| p.title.start_with?("Welcome") } }.length + authors_with_welcoming_post_titles = Author.all.merge!(joins: :posts, where: "posts.title like 'Welcome%'").distinct.calculate(:count, "authors.id") assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'" end def test_find_with_sti_join - scope = Post.joins(:special_comments).where(:id => posts(:sti_comments).id) + scope = Post.joins(:special_comments).where(id: posts(:sti_comments).id) # The join should match SpecialComment and its subclasses only assert scope.where("comments.type" => "Comment").empty? @@ -102,12 +102,12 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase def test_find_with_conditions_on_reflection assert !posts(:welcome).comments.empty? - assert Post.joins(:nonexistent_comments).where(:id => posts(:welcome).id).empty? # [sic!] + assert Post.joins(:nonexistent_comments).where(id: posts(:welcome).id).empty? # [sic!] end def test_find_with_conditions_on_through_reflection assert !posts(:welcome).tags.empty? - assert Post.joins(:misc_tags).where(:id => posts(:welcome).id).empty? + assert Post.joins(:misc_tags).where(id: posts(:welcome).id).empty? end test "the default scope of the target is applied when joining associations" do @@ -120,8 +120,8 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase test "the default scope of the target is correctly aliased when joining associations" do author = Author.create! name: "Jon" - author.categories.create! name: 'Not Special' - author.special_categories.create! name: 'Special' + author.categories.create! name: "Not Special" + author.special_categories.create! name: "Special" categories = author.categories.includes(:special_categorizations).references(:special_categorizations).to_a assert_equal 2, categories.size @@ -129,8 +129,8 @@ class InnerJoinAssociationTest < ActiveRecord::TestCase test "the correct records are loaded when including an aliased association" do author = Author.create! name: "Jon" - author.categories.create! name: 'Not Special' - author.special_categories.create! name: 'Special' + author.categories.create! name: "Not Special" + author.special_categories.create! name: "Special" categories = author.categories.eager_load(:special_categorizations).order(:name).to_a assert_equal 0, categories.first.special_categorizations.size diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index c9743e80d3..6fe6ee6783 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -1,21 +1,21 @@ require "cases/helper" -require 'models/man' -require 'models/face' -require 'models/interest' -require 'models/zine' -require 'models/club' -require 'models/sponsor' -require 'models/rating' -require 'models/comment' -require 'models/car' -require 'models/bulb' -require 'models/mixed_case_monkey' -require 'models/admin' -require 'models/admin/account' -require 'models/admin/user' -require 'models/developer' -require 'models/company' -require 'models/project' +require "models/man" +require "models/face" +require "models/interest" +require "models/zine" +require "models/club" +require "models/sponsor" +require "models/rating" +require "models/comment" +require "models/car" +require "models/bulb" +require "models/mixed_case_monkey" +require "models/admin" +require "models/admin/account" +require "models/admin/user" +require "models/developer" +require "models/company" +require "models/project" class AutomaticInverseFindingTests < ActiveRecord::TestCase fixtures :ratings, :comments, :cars @@ -131,15 +131,15 @@ end class InverseAssociationTests < ActiveRecord::TestCase def test_should_allow_for_inverse_of_options_in_associations assert_nothing_raised do - Class.new(ActiveRecord::Base).has_many(:wheels, :inverse_of => :car) + Class.new(ActiveRecord::Base).has_many(:wheels, inverse_of: :car) end assert_nothing_raised do - Class.new(ActiveRecord::Base).has_one(:engine, :inverse_of => :car) + Class.new(ActiveRecord::Base).has_one(:engine, inverse_of: :car) end assert_nothing_raised do - Class.new(ActiveRecord::Base).belongs_to(:car, :inverse_of => :driver) + Class.new(ActiveRecord::Base).belongs_to(:car, inverse_of: :driver) end end @@ -203,9 +203,9 @@ class InverseAssociationTests < ActiveRecord::TestCase end def test_this_inverse_stuff - firm = Firm.create!(name: 'Adequate Holdings') - Project.create!(name: 'Project 1', firm: firm) - Developer.create!(name: 'Gorbypuff', firm: firm) + firm = Firm.create!(name: "Adequate Holdings") + Project.create!(name: "Project 1", firm: firm) + Developer.create!(name: "Gorbypuff", firm: firm) new_project = Project.last assert Project.reflect_on_association(:lead_developer).inverse_of.present?, "Expected inverse of to be present" @@ -220,73 +220,72 @@ class InverseHasOneTests < ActiveRecord::TestCase m = men(:gordon) f = m.face assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance" - f.man.name = 'Mungo' + f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to child-owned instance" end - def test_parent_instance_should_be_shared_with_eager_loaded_child_on_find - m = Man.all.merge!(:where => {:name => 'Gordon'}, :includes => :face).first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :face).first f = m.face assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance" - f.man.name = 'Mungo' + f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to child-owned instance" - m = Man.all.merge!(:where => {:name => 'Gordon'}, :includes => :face, :order => 'faces.id').first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :face, order: "faces.id").first f = m.face assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance" - f.man.name = 'Mungo' + f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to child-owned instance" end def test_parent_instance_should_be_shared_with_newly_built_child m = Man.first - f = m.build_face(:description => 'haunted') + f = m.build_face(description: "haunted") assert_not_nil f.man assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance" - f.man.name = 'Mungo' + f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to just-built-child-owned instance" end def test_parent_instance_should_be_shared_with_newly_created_child m = Man.first - f = m.create_face(:description => 'haunted') + f = m.create_face(description: "haunted") assert_not_nil f.man assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance" - f.man.name = 'Mungo' + f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance" end def test_parent_instance_should_be_shared_with_newly_created_child_via_bang_method m = Man.first - f = m.create_face!(:description => 'haunted') + f = m.create_face!(description: "haunted") assert_not_nil f.man assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance" - f.man.name = 'Mungo' + f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to newly-created-child-owned instance" end def test_parent_instance_should_be_shared_with_replaced_via_accessor_child m = Man.first - f = Face.new(:description => 'haunted') + f = Face.new(description: "haunted") m.face = f assert_not_nil f.man assert_equal m.name, f.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to parent instance" - f.man.name = 'Mungo' + f.man.name = "Mungo" assert_equal m.name, f.man.name, "Name of man should be the same after changes to replaced-child-owned instance" end @@ -303,67 +302,67 @@ class InverseHasManyTests < ActiveRecord::TestCase is = m.interests is.each do |i| assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to child-owned instance" end end def test_parent_instance_should_be_shared_with_eager_loaded_children - m = Man.all.merge!(:where => {:name => 'Gordon'}, :includes => :interests).first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :interests).first is = m.interests is.each do |i| assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to child-owned instance" end - m = Man.all.merge!(:where => {:name => 'Gordon'}, :includes => :interests, :order => 'interests.id').first + m = Man.all.merge!(where: { name: "Gordon" }, includes: :interests, order: "interests.id").first is = m.interests is.each do |i| assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to child-owned instance" end end def test_parent_instance_should_be_shared_with_newly_block_style_built_child m = Man.first - i = m.interests.build {|ii| ii.topic = 'Industrial Revolution Re-enactment'} + i = m.interests.build { |ii| ii.topic = "Industrial Revolution Re-enactment" } assert_not_nil i.topic, "Child attributes supplied to build via blocks should be populated" assert_not_nil i.man assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to just-built-child-owned instance" end def test_parent_instance_should_be_shared_with_newly_created_via_bang_method_child m = Man.first - i = m.interests.create!(:topic => 'Industrial Revolution Re-enactment') + i = m.interests.create!(topic: "Industrial Revolution Re-enactment") assert_not_nil i.man assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance" end def test_parent_instance_should_be_shared_with_newly_block_style_created_child m = Man.first - i = m.interests.create {|ii| ii.topic = 'Industrial Revolution Re-enactment'} + i = m.interests.create { |ii| ii.topic = "Industrial Revolution Re-enactment" } assert_not_nil i.topic, "Child attributes supplied to create via blocks should be populated" assert_not_nil i.man assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance" end @@ -385,25 +384,25 @@ class InverseHasManyTests < ActiveRecord::TestCase def test_parent_instance_should_be_shared_with_poked_in_child m = men(:gordon) - i = Interest.create(:topic => 'Industrial Revolution Re-enactment') + i = Interest.create(topic: "Industrial Revolution Re-enactment") m.interests << i assert_not_nil i.man assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to newly-created-child-owned instance" end def test_parent_instance_should_be_shared_with_replaced_via_accessor_children m = Man.first - i = Interest.new(:topic => 'Industrial Revolution Re-enactment') + i = Interest.new(topic: "Industrial Revolution Re-enactment") m.interests = [i] assert_not_nil i.man assert_equal m.name, i.man.name, "Name of man should be the same before changes to parent instance" - m.name = 'Bongo' + m.name = "Bongo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to parent instance" - i.man.name = 'Mungo' + i.man.name = "Mungo" assert_equal m.name, i.man.name, "Name of man should be the same after changes to replaced-child-owned instance" end @@ -485,7 +484,7 @@ class InverseHasManyTests < ActiveRecord::TestCase def test_child_instance_should_point_to_parent_without_saving man = Man.new - i = Interest.create(:topic => 'Industrial Revolution Re-enactment') + i = Interest.create(topic: "Industrial Revolution Re-enactment") man.interests << i assert_not_nil i.man @@ -495,6 +494,33 @@ class InverseHasManyTests < ActiveRecord::TestCase assert !man.persisted? end + + def test_inverse_instance_should_be_set_before_find_callbacks_are_run + reset_callbacks(Interest, :find) do + Interest.after_find { raise unless association(:man).loaded? && man.present? } + + assert Man.first.interests.reload.any? + assert Man.includes(:interests).first.interests.any? + assert Man.joins(:interests).includes(:interests).first.interests.any? + end + end + + def test_inverse_instance_should_be_set_before_initialize_callbacks_are_run + reset_callbacks(Interest, :initialize) do + Interest.after_initialize { raise unless association(:man).loaded? && man.present? } + + assert Man.first.interests.reload.any? + assert Man.includes(:interests).first.interests.any? + assert Man.joins(:interests).includes(:interests).first.interests.any? + end + end + + def reset_callbacks(target, type) + old_callbacks = target.send(:get_callbacks, type).deep_dup + yield + ensure + target.send(:set_callbacks, type, old_callbacks) if old_callbacks + end end class InverseBelongsToTests < ActiveRecord::TestCase @@ -504,49 +530,49 @@ class InverseBelongsToTests < ActiveRecord::TestCase f = faces(:trusting) m = f.man assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance" - m.face.description = 'pleasing' + m.face.description = "pleasing" assert_equal f.description, m.face.description, "Description of face should be the same after changes to parent-owned instance" end def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find - f = Face.all.merge!(:includes => :man, :where => {:description => 'trusting'}).first + f = Face.all.merge!(includes: :man, where: { description: "trusting" }).first m = f.man assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance" - m.face.description = 'pleasing' + m.face.description = "pleasing" assert_equal f.description, m.face.description, "Description of face should be the same after changes to parent-owned instance" - f = Face.all.merge!(:includes => :man, :order => 'men.id', :where => {:description => 'trusting'}).first + f = Face.all.merge!(includes: :man, order: "men.id", where: { description: "trusting" }).first m = f.man assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance" - m.face.description = 'pleasing' + m.face.description = "pleasing" assert_equal f.description, m.face.description, "Description of face should be the same after changes to parent-owned instance" end def test_child_instance_should_be_shared_with_newly_built_parent f = faces(:trusting) - m = f.build_man(:name => 'Charles') + m = f.build_man(name: "Charles") assert_not_nil m.face assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance" - m.face.description = 'pleasing' + m.face.description = "pleasing" assert_equal f.description, m.face.description, "Description of face should be the same after changes to just-built-parent-owned instance" end def test_child_instance_should_be_shared_with_newly_created_parent f = faces(:trusting) - m = f.create_man(:name => 'Charles') + m = f.create_man(name: "Charles") assert_not_nil m.face assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance" - m.face.description = 'pleasing' + m.face.description = "pleasing" assert_equal f.description, m.face.description, "Description of face should be the same after changes to newly-created-parent-owned instance" end @@ -554,24 +580,24 @@ class InverseBelongsToTests < ActiveRecord::TestCase i = interests(:trainspotting) m = i.man assert_not_nil m.interests - iz = m.interests.detect { |_iz| _iz.id == i.id} + iz = m.interests.detect { |_iz| _iz.id == i.id } assert_not_nil iz assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child" - i.topic = 'Eating cheese with a spoon' + i.topic = "Eating cheese with a spoon" assert_not_equal i.topic, iz.topic, "Interest topics should not be the same after changes to child" - iz.topic = 'Cow tipping' + iz.topic = "Cow tipping" assert_not_equal i.topic, iz.topic, "Interest topics should not be the same after changes to parent-owned instance" end def test_child_instance_should_be_shared_with_replaced_via_accessor_parent f = Face.first - m = Man.new(:name => 'Charles') + m = Man.new(name: "Charles") f.man = m assert_not_nil m.face assert_equal f.description, m.face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.face.description, "Description of face should be the same after changes to child instance" - m.face.description = 'pleasing' + m.face.description = "pleasing" assert_equal f.description, m.face.description, "Description of face should be the same after changes to replaced-parent-owned instance" end @@ -584,30 +610,30 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase fixtures :men, :faces, :interests def test_child_instance_should_be_shared_with_parent_on_find - f = Face.all.merge!(:where => {:description => 'confused'}).first + f = Face.all.merge!(where: { description: "confused" }).first m = f.polymorphic_man assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to child instance" - m.polymorphic_face.description = 'pleasing' + m.polymorphic_face.description = "pleasing" assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance" end def test_eager_loaded_child_instance_should_be_shared_with_parent_on_find - f = Face.all.merge!(:where => {:description => 'confused'}, :includes => :man).first + f = Face.all.merge!(where: { description: "confused" }, includes: :man).first m = f.polymorphic_man assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to child instance" - m.polymorphic_face.description = 'pleasing' + m.polymorphic_face.description = "pleasing" assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance" - f = Face.all.merge!(:where => {:description => 'confused'}, :includes => :man, :order => 'men.id').first + f = Face.all.merge!(where: { description: "confused" }, includes: :man, order: "men.id").first m = f.polymorphic_man assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same before changes to child instance" - f.description = 'gormless' + f.description = "gormless" assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to child instance" - m.polymorphic_face.description = 'pleasing' + m.polymorphic_face.description = "pleasing" assert_equal f.description, m.polymorphic_face.description, "Description of face should be the same after changes to parent-owned instance" end @@ -619,9 +645,9 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase face.polymorphic_man = new_man assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same before changes to parent instance" - face.description = 'Bongo' + face.description = "Bongo" assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to parent instance" - new_man.polymorphic_face.description = 'Mungo' + new_man.polymorphic_face.description = "Mungo" assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to replaced-parent-owned instance" end @@ -633,9 +659,9 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase face.polymorphic_man = new_man assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same before changes to parent instance" - face.description = 'Bongo' + face.description = "Bongo" assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to parent instance" - new_man.polymorphic_face.description = 'Mungo' + new_man.polymorphic_face.description = "Mungo" assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to replaced-parent-owned instance" end @@ -655,12 +681,12 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase i = interests(:llama_wrangling) m = i.polymorphic_man assert_not_nil m.polymorphic_interests - iz = m.polymorphic_interests.detect { |_iz| _iz.id == i.id} + iz = m.polymorphic_interests.detect { |_iz| _iz.id == i.id } assert_not_nil iz assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child" - i.topic = 'Eating cheese with a spoon' + i.topic = "Eating cheese with a spoon" assert_not_equal i.topic, iz.topic, "Interest topics should not be the same after changes to child" - iz.topic = 'Cow tipping' + iz.topic = "Cow tipping" assert_not_equal i.topic, iz.topic, "Interest topics should not be the same after changes to parent-owned instance" end @@ -698,8 +724,8 @@ class InverseMultipleHasManyInversesForSameModel < ActiveRecord::TestCase def test_that_we_can_create_associations_that_have_the_same_reciprocal_name_from_different_models assert_nothing_raised do i = Interest.first - i.build_zine(:title => 'Get Some in Winter! 2008') - i.build_man(:name => 'Gordon') + i.build_zine(title: "Get Some in Winter! 2008") + i.build_man(name: "Gordon") i.save! end end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 3047914b70..15a7ae941a 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -1,20 +1,20 @@ require "cases/helper" -require 'models/tag' -require 'models/tagging' -require 'models/post' -require 'models/rating' -require 'models/item' -require 'models/comment' -require 'models/author' -require 'models/category' -require 'models/categorization' -require 'models/vertex' -require 'models/edge' -require 'models/book' -require 'models/citation' -require 'models/aircraft' -require 'models/engine' -require 'models/car' +require "models/tag" +require "models/tagging" +require "models/post" +require "models/rating" +require "models/item" +require "models/comment" +require "models/author" +require "models/category" +require "models/categorization" +require "models/vertex" +require "models/edge" +require "models/book" +require "models/citation" +require "models/aircraft" +require "models/engine" +require "models/car" class AssociationsJoinModelTest < ActiveRecord::TestCase self.use_transactional_tests = false unless supports_savepoints? @@ -24,15 +24,15 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase :edges def test_has_many - assert authors(:david).categories.include?(categories(:general)) + assert_includes authors(:david).categories, categories(:general) end def test_has_many_inherited - assert authors(:mary).categories.include?(categories(:sti_test)) + assert_includes authors(:mary).categories, categories(:sti_test) end def test_inherited_has_many - assert categories(:sti_test).authors.include?(authors(:mary)) + assert_includes categories(:sti_test).authors, authors(:mary) end def test_has_many_distinct_through_join_model @@ -97,10 +97,10 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class - post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body' + post = SubStiPost.create title: "SubStiPost", body: "SubStiPost body" assert_instance_of SubStiPost, post - tagging = tags(:misc).taggings.create(:taggable => post) + tagging = tags(:misc).taggings.create(taggable: post) assert_equal "SubStiPost", tagging.taggable_type end @@ -116,12 +116,12 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase post = posts(:thinking) assert_instance_of SpecialPost, post - tagging = tags(:misc).taggings.create(:taggable => post) + tagging = tags(:misc).taggings.create(taggable: post) assert_equal "Post", tagging.taggable_type end def test_polymorphic_has_one_create_model_with_inheritance - tagging = tags(:misc).create_tagging(:taggable => posts(:thinking)) + tagging = tags(:misc).create_tagging(taggable: posts(:thinking)) assert_equal "Post", tagging.taggable_type end @@ -142,7 +142,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_set_polymorphic_has_one_on_new_record tagging = tags(:misc).taggings.create - post = Post.new :title => "foo", :body => "bar" + post = Post.new title: "foo", body: "bar" post.tagging = tagging post.save! @@ -153,28 +153,28 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_create_polymorphic_has_many_with_scope old_count = posts(:welcome).taggings.count - tagging = posts(:welcome).taggings.create(:tag => tags(:misc)) + tagging = posts(:welcome).taggings.create(tag: tags(:misc)) assert_equal "Post", tagging.taggable_type assert_equal old_count+1, posts(:welcome).taggings.count end def test_create_bang_polymorphic_with_has_many_scope old_count = posts(:welcome).taggings.count - tagging = posts(:welcome).taggings.create!(:tag => tags(:misc)) + tagging = posts(:welcome).taggings.create!(tag: tags(:misc)) assert_equal "Post", tagging.taggable_type assert_equal old_count+1, posts(:welcome).taggings.count end def test_create_polymorphic_has_one_with_scope old_count = Tagging.count - tagging = posts(:welcome).create_tagging(:tag => tags(:misc)) + tagging = posts(:welcome).create_tagging(tag: tags(:misc)) assert_equal "Post", tagging.taggable_type assert_equal old_count+1, Tagging.count end def test_delete_polymorphic_has_many_with_delete_all assert_equal 1, posts(:welcome).taggings.count - posts(:welcome).taggings.first.update_columns taggable_type: 'PostWithHasManyDeleteAll' + posts(:welcome).taggings.first.update_columns taggable_type: "PostWithHasManyDeleteAll" post = find_post_with_dependency(1, :has_many, :taggings, :delete_all) old_count = Tagging.count @@ -185,7 +185,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_delete_polymorphic_has_many_with_destroy assert_equal 1, posts(:welcome).taggings.count - posts(:welcome).taggings.first.update_columns taggable_type: 'PostWithHasManyDestroy' + posts(:welcome).taggings.first.update_columns taggable_type: "PostWithHasManyDestroy" post = find_post_with_dependency(1, :has_many, :taggings, :destroy) old_count = Tagging.count @@ -196,7 +196,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_delete_polymorphic_has_many_with_nullify assert_equal 1, posts(:welcome).taggings.count - posts(:welcome).taggings.first.update_columns taggable_type: 'PostWithHasManyNullify' + posts(:welcome).taggings.first.update_columns taggable_type: "PostWithHasManyNullify" post = find_post_with_dependency(1, :has_many, :taggings, :nullify) old_count = Tagging.count @@ -207,7 +207,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_delete_polymorphic_has_one_with_destroy assert posts(:welcome).tagging - posts(:welcome).tagging.update_columns taggable_type: 'PostWithHasOneDestroy' + posts(:welcome).tagging.update_columns taggable_type: "PostWithHasOneDestroy" post = find_post_with_dependency(1, :has_one, :tagging, :destroy) old_count = Tagging.count @@ -219,7 +219,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_delete_polymorphic_has_one_with_nullify assert posts(:welcome).tagging - posts(:welcome).tagging.update_columns taggable_type: 'PostWithHasOneNullify' + posts(:welcome).tagging.update_columns taggable_type: "PostWithHasOneNullify" post = find_post_with_dependency(1, :has_one, :tagging, :nullify) old_count = Tagging.count @@ -235,15 +235,15 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_create_through_has_many_with_piggyback category = categories(:sti_test) - ernie = category.authors_with_select.create(:name => 'Ernie') + ernie = category.authors_with_select.create(name: "Ernie") assert_nothing_raised do - assert_equal ernie, category.authors_with_select.detect {|a| a.name == 'Ernie'} + assert_equal ernie, category.authors_with_select.detect { |a| a.name == "Ernie" } end end def test_include_has_many_through - posts = Post.all.merge!(:order => 'posts.id').to_a - posts_with_authors = Post.all.merge!(:includes => :authors, :order => 'posts.id').to_a + posts = Post.all.merge!(order: "posts.id").to_a + posts_with_authors = Post.all.merge!(includes: :authors, order: "posts.id").to_a assert_equal posts.length, posts_with_authors.length posts.length.times do |i| assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length } @@ -267,8 +267,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_include_polymorphic_has_many_through - posts = Post.all.merge!(:order => 'posts.id').to_a - posts_with_tags = Post.all.merge!(:includes => :tags, :order => 'posts.id').to_a + posts = Post.all.merge!(order: "posts.id").to_a + posts_with_tags = Post.all.merge!(includes: :tags, order: "posts.id").to_a assert_equal posts.length, posts_with_tags.length posts.length.times do |i| assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length } @@ -276,8 +276,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_include_polymorphic_has_many - posts = Post.all.merge!(:order => 'posts.id').to_a - posts_with_taggings = Post.all.merge!(:includes => :taggings, :order => 'posts.id').to_a + posts = Post.all.merge!(order: "posts.id").to_a + posts_with_taggings = Post.all.merge!(includes: :taggings, order: "posts.id").to_a assert_equal posts.length, posts_with_taggings.length posts.length.times do |i| assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length } @@ -302,7 +302,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_has_many_array_methods_called_by_method_missing - assert authors(:david).categories.any? { |category| category.name == 'General' } + assert authors(:david).categories.any? { |category| category.name == "General" } assert_nothing_raised { authors(:david).categories.sort } end @@ -324,12 +324,12 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_has_many_through_with_custom_primary_key_on_has_many_source - assert_equal [authors(:david), authors(:bob)], posts(:thinking).authors_using_custom_pk.order('authors.id') + assert_equal [authors(:david), authors(:bob)], posts(:thinking).authors_using_custom_pk.order("authors.id") end def test_belongs_to_polymorphic_with_counter_cache assert_equal 1, posts(:welcome)[:tags_count] - tagging = posts(:welcome).taggings.create(:tag => tags(:general)) + tagging = posts(:welcome).taggings.create(tag: tags(:general)) assert_equal 2, posts(:welcome, :reload)[:tags_count] tagging.destroy assert_equal 1, posts(:welcome, :reload)[:tags_count] @@ -354,7 +354,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end assert_raise ActiveRecord::EagerLoadPolymorphicError do - tags(:general).taggings.includes(:taggable).where('bogus_table.column = 1').references(:bogus_table).to_a + tags(:general).taggings.includes(:taggable).where("bogus_table.column = 1").references(:bogus_table).to_a end end @@ -365,13 +365,13 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_has_many_polymorphic_associations_merges_through_scope Tag.has_many :null_taggings, -> { none }, class_name: :Tagging - Tag.has_many :null_tagged_posts, :through => :null_taggings, :source => 'taggable', :source_type => 'Post' + Tag.has_many :null_tagged_posts, through: :null_taggings, source: "taggable", source_type: "Post" assert_equal [], tags(:general).null_tagged_posts refute_equal [], tags(:general).tagged_posts end def test_eager_has_many_polymorphic_with_source_type - tag_with_include = Tag.all.merge!(:includes => :tagged_posts).find(tags(:general).id) + tag_with_include = Tag.all.merge!(includes: :tagged_posts).find(tags(:general).id) desired = posts(:welcome, :thinking) assert_no_queries do # added sort by ID as otherwise test using JRuby was failing as array elements were in different order @@ -381,19 +381,19 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_has_many_through_has_many_find_all - assert_equal comments(:greetings), authors(:david).comments.order('comments.id').to_a.first + assert_equal comments(:greetings), authors(:david).comments.order("comments.id").to_a.first end def test_has_many_through_has_many_find_all_with_custom_class - assert_equal comments(:greetings), authors(:david).funky_comments.order('comments.id').to_a.first + assert_equal comments(:greetings), authors(:david).funky_comments.order("comments.id").to_a.first end def test_has_many_through_has_many_find_first - assert_equal comments(:greetings), authors(:david).comments.order('comments.id').first + assert_equal comments(:greetings), authors(:david).comments.order("comments.id").first end def test_has_many_through_has_many_find_conditions - options = { :where => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' } + options = { where: "comments.#{QUOTED_TYPE}='SpecialComment'", order: "comments.id" } assert_equal comments(:does_it_hurt), authors(:david).comments.merge(options).first end @@ -418,7 +418,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_eager_load_has_many_through_has_many - author = Author.all.merge!(:where => ['name = ?', 'David'], :includes => :comments, :order => 'comments.id').first + author = Author.all.merge!(where: ["name = ?", "David"], includes: :comments, order: "comments.id").first SpecialComment.new; VerySpecialComment.new assert_no_queries do assert_equal [1,2,3,5,6,7,8,9,10,12], author.comments.collect(&:id) @@ -426,7 +426,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_eager_load_has_many_through_has_many_with_conditions - post = Post.all.merge!(:includes => :invalid_tags).first + post = Post.all.merge!(includes: :invalid_tags).first assert_no_queries do post.invalid_tags end @@ -434,8 +434,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_eager_belongs_to_and_has_one_not_singularized assert_nothing_raised do - Author.all.merge!(:includes => :author_address).first - AuthorAddress.all.merge!(:includes => :author).first + Author.all.merge!(includes: :author_address).first + AuthorAddress.all.merge!(includes: :author).first end end @@ -445,8 +445,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_add_to_self_referential_has_many_through - new_author = Author.create(:name => "Bob") - authors(:david).author_favorites.create :favorite_author => new_author + new_author = Author.create(name: "Bob") + authors(:david).author_favorites.create favorite_author: new_author assert_equal new_author, authors(:david).reload.favorite_authors.first end @@ -462,28 +462,27 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_associating_unsaved_records_with_has_many_through saved_post = posts(:thinking) - new_tag = Tag.new(:name => "new") + new_tag = Tag.new(name: "new") saved_post.tags << new_tag assert new_tag.persisted? #consistent with habtm! assert saved_post.persisted? - assert saved_post.tags.include?(new_tag) + assert_includes saved_post.tags, new_tag assert new_tag.persisted? - assert saved_post.reload.tags.reload.include?(new_tag) + assert_includes saved_post.reload.tags.reload, new_tag - - new_post = Post.new(:title => "Association replacement works!", :body => "You best believe it.") + new_post = Post.new(title: "Association replacement works!", body: "You best believe it.") saved_tag = tags(:general) new_post.tags << saved_tag assert !new_post.persisted? assert saved_tag.persisted? - assert new_post.tags.include?(saved_tag) + assert_includes new_post.tags, saved_tag new_post.save! assert new_post.persisted? - assert new_post.reload.tags.reload.include?(saved_tag) + assert_includes new_post.reload.tags.reload, saved_tag assert !posts(:thinking).tags.build.persisted? assert !posts(:thinking).tags.new.persisted? @@ -491,7 +490,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_create_associate_when_adding_to_has_many_through count = posts(:thinking).tags.count - push = Tag.create!(:name => 'pushme') + push = Tag.create!(name: "pushme") post_thinking = posts(:thinking) assert_nothing_raised { post_thinking.tags << push } assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag }, @@ -501,7 +500,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase assert_equal(count + 1, post_thinking.reload.tags.size) assert_equal(count + 1, post_thinking.tags.reload.size) - assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo') + assert_kind_of Tag, post_thinking.tags.create!(name: "foo") assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag }, message = "Expected a Tag in tags collection, got #{wrong.class}.") assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, @@ -509,7 +508,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase assert_equal(count + 2, post_thinking.reload.tags.size) assert_equal(count + 2, post_thinking.tags.reload.size) - assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) } + assert_nothing_raised { post_thinking.tags.concat(Tag.create!(name: "abc"), Tag.create!(name: "def")) } assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag }, message = "Expected a Tag in tags collection, got #{wrong.class}.") assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging }, @@ -550,7 +549,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id count = books(:awdr).references.count references_before = books(:awdr).references - book = Book.create!(:name => 'Getting Real') + book = Book.create!(name: "Getting Real") book_awdr = books(:awdr) book_awdr.references << book assert_equal(count + 1, book_awdr.references.reload.size) @@ -564,7 +563,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_delete_associate_when_deleting_from_has_many_through count = posts(:thinking).tags.count tags_before = posts(:thinking).tags.sort - tag = Tag.create!(:name => 'doomed') + tag = Tag.create!(name: "doomed") post_thinking = posts(:thinking) post_thinking.tags << tag assert_equal(count + 1, post_thinking.taggings.reload.size) @@ -581,9 +580,9 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags count = posts(:thinking).tags.count tags_before = posts(:thinking).tags.sort - doomed = Tag.create!(:name => 'doomed') - doomed2 = Tag.create!(:name => 'doomed2') - quaked = Tag.create!(:name => 'quaked') + doomed = Tag.create!(name: "doomed") + doomed2 = Tag.create!(name: "doomed2") + quaked = Tag.create!(name: "quaked") post_thinking = posts(:thinking) post_thinking.tags << doomed << doomed2 assert_equal(count + 2, post_thinking.reload.tags.reload.size) @@ -601,7 +600,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_deleting_by_integer_id_from_has_many_through post = posts(:thinking) - assert_difference 'post.tags.count', -1 do + assert_difference "post.tags.count", -1 do assert_equal 1, post.tags.delete(1).size end @@ -611,8 +610,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_deleting_by_string_id_from_has_many_through post = posts(:thinking) - assert_difference 'post.tags.count', -1 do - assert_equal 1, post.tags.delete('1').size + assert_difference "post.tags.count", -1 do + assert_equal 1, post.tags.delete("1").size end assert_equal 0, post.tags.size @@ -642,26 +641,26 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_polymorphic_has_many expected = taggings(:welcome_general) - p = Post.all.merge!(:includes => :taggings).find(posts(:welcome).id) - assert_no_queries {assert p.taggings.include?(expected)} - assert posts(:welcome).taggings.include?(taggings(:welcome_general)) + p = Post.all.merge!(includes: :taggings).find(posts(:welcome).id) + assert_no_queries { assert_includes p.taggings, expected } + assert_includes posts(:welcome).taggings, taggings(:welcome_general) end def test_polymorphic_has_one expected = posts(:welcome) - tagging = Tagging.all.merge!(:includes => :taggable).find(taggings(:welcome_general).id) - assert_no_queries { assert_equal expected, tagging.taggable} + tagging = Tagging.all.merge!(includes: :taggable).find(taggings(:welcome_general).id) + assert_no_queries { assert_equal expected, tagging.taggable } end def test_polymorphic_belongs_to - p = Post.all.merge!(:includes => {:taggings => :taggable}).find(posts(:welcome).id) - assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable} + p = Post.all.merge!(includes: { taggings: :taggable }).find(posts(:welcome).id) + assert_no_queries { assert_equal posts(:welcome), p.taggings.first.taggable } end def test_preload_polymorphic_has_many_through - posts = Post.all.merge!(:order => 'posts.id').to_a - posts_with_tags = Post.all.merge!(:includes => :tags, :order => 'posts.id').to_a + posts = Post.all.merge!(order: "posts.id").to_a + posts_with_tags = Post.all.merge!(includes: :tags, order: "posts.id").to_a assert_equal posts.length, posts_with_tags.length posts.length.times do |i| assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length } @@ -669,26 +668,26 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_preload_polymorph_many_types - taggings = Tagging.all.merge!(:includes => :taggable, :where => ['taggable_type != ?', 'FakeModel']).to_a + taggings = Tagging.all.merge!(includes: :taggable, where: ["taggable_type != ?", "FakeModel"]).to_a assert_no_queries do taggings.first.taggable.id taggings[1].taggable.id end taggables = taggings.map(&:taggable) - assert taggables.include?(items(:dvd)) - assert taggables.include?(posts(:welcome)) + assert_includes taggables, items(:dvd) + assert_includes taggables, posts(:welcome) end def test_preload_nil_polymorphic_belongs_to assert_nothing_raised do - Tagging.all.merge!(:includes => :taggable, :where => ['taggable_type IS NULL']).to_a + Tagging.all.merge!(includes: :taggable, where: ["taggable_type IS NULL"]).to_a end end def test_preload_polymorphic_has_many - posts = Post.all.merge!(:order => 'posts.id').to_a - posts_with_taggings = Post.all.merge!(:includes => :taggings, :order => 'posts.id').to_a + posts = Post.all.merge!(order: "posts.id").to_a + posts_with_taggings = Post.all.merge!(includes: :taggings, order: "posts.id").to_a assert_equal posts.length, posts_with_taggings.length posts.length.times do |i| assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length } @@ -696,7 +695,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_belongs_to_shared_parent - comments = Comment.all.merge!(:includes => :post, :where => 'post_id = 1').to_a + comments = Comment.all.merge!(includes: :post, where: "post_id = 1").to_a assert_no_queries do assert_equal comments.first.post, comments[1].post end @@ -710,7 +709,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase assert_no_queries do assert david.categories.loaded? - assert david.categories.include?(category) + assert_includes david.categories, category end end @@ -721,45 +720,45 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase david.reload assert ! david.categories.loaded? assert_queries(1) do - assert david.categories.include?(category) + assert_includes david.categories, category end assert ! david.categories.loaded? end def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping david = authors(:david) - category = Category.create!(:name => 'Not Associated') + category = Category.create!(name: "Not Associated") assert ! david.categories.loaded? assert ! david.categories.include?(category) end def test_has_many_through_goes_through_all_sti_classes - sub_sti_post = SubStiPost.create!(:title => 'test', :body => 'test', :author_id => 1) - new_comment = sub_sti_post.comments.create(:body => 'test') + sub_sti_post = SubStiPost.create!(title: "test", body: "test", author_id: 1) + new_comment = sub_sti_post.comments.create(body: "test") assert_equal [9, 10, new_comment.id], authors(:david).sti_post_comments.map(&:id).sort end def test_has_many_with_pluralize_table_names_false - aircraft = Aircraft.create!(:name => "Airbus 380") - engine = Engine.create!(:car_id => aircraft.id) + aircraft = Aircraft.create!(name: "Airbus 380") + engine = Engine.create!(car_id: aircraft.id) assert_equal aircraft.engines, [engine] end def test_proper_error_message_for_eager_load_and_includes_association_errors includes_error = assert_raises(ActiveRecord::ConfigurationError) { - Post.includes(:nonexistent_relation).where(nonexistent_relation: {name: 'Rochester'}).find(1) + Post.includes(:nonexistent_relation).where(nonexistent_relation: { name: "Rochester" }).find(1) } assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", includes_error.message) eager_load_error = assert_raises(ActiveRecord::ConfigurationError) { - Post.eager_load(:nonexistent_relation).where(nonexistent_relation: {name: 'Rochester'}).find(1) + Post.eager_load(:nonexistent_relation).where(nonexistent_relation: { name: "Rochester" }).find(1) } assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", eager_load_error.message) includes_and_eager_load_error = assert_raises(ActiveRecord::ConfigurationError) { - Post.eager_load(:nonexistent_relation).includes(:nonexistent_relation).where(nonexistent_relation: {name: 'Rochester'}).find(1) + Post.eager_load(:nonexistent_relation).includes(:nonexistent_relation).where(nonexistent_relation: { name: "Rochester" }).find(1) } assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", includes_and_eager_load_error.message) end @@ -770,8 +769,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}" Post.find(post_id).update_columns type: class_name klass = Object.const_set(class_name, Class.new(ActiveRecord::Base)) - klass.table_name = 'posts' - klass.send(association, association_name, :as => :taggable, :dependent => dependency) + klass.table_name = "posts" + klass.send(association, association_name, as: :taggable, dependent: dependency) klass.find(post_id) end end diff --git a/activerecord/test/cases/associations/left_outer_join_association_test.rb b/activerecord/test/cases/associations/left_outer_join_association_test.rb index eee135cfb8..2cc6468827 100644 --- a/activerecord/test/cases/associations/left_outer_join_association_test.rb +++ b/activerecord/test/cases/associations/left_outer_join_association_test.rb @@ -1,10 +1,11 @@ require "cases/helper" -require 'models/post' -require 'models/comment' -require 'models/author' -require 'models/essay' -require 'models/categorization' -require 'models/person' +require "models/post" +require "models/comment" +require "models/author" +require "models/essay" +require "models/categorization" +require "models/person" +require "active_support/core_ext/regexp" class LeftOuterJoinAssociationTest < ActiveRecord::TestCase fixtures :authors, :essays, :posts, :comments, :categorizations, :people @@ -17,45 +18,54 @@ class LeftOuterJoinAssociationTest < ActiveRecord::TestCase def test_construct_finder_sql_does_not_table_name_collide_on_duplicate_associations assert_nothing_raised do queries = capture_sql do - Person.left_outer_joins(:agents => {:agents => :agents}) - .left_outer_joins(:agents => {:agents => {:primary_contact => :agents}}).to_a + Person.left_outer_joins(agents: { agents: :agents }) + .left_outer_joins(agents: { agents: { primary_contact: :agents } }).to_a end - assert queries.any? { |sql| /agents_people_4/i =~ sql } + assert queries.any? { |sql| /agents_people_4/i.match?(sql) } end end - def test_construct_finder_sql_executes_a_left_outer_join - assert_not_equal Author.count, Author.joins(:posts).count - assert_equal Author.count, Author.left_outer_joins(:posts).count + def test_left_outer_joins_count_is_same_as_size_of_loaded_results + assert_equal 17, Post.left_outer_joins(:comments).to_a.size + assert_equal 17, Post.left_outer_joins(:comments).count end - def test_left_outer_join_by_left_joins - assert_not_equal Author.count, Author.joins(:posts).count - assert_equal Author.count, Author.left_joins(:posts).count + def test_left_joins_aliases_left_outer_joins + assert_equal Post.left_outer_joins(:comments).to_sql, Post.left_joins(:comments).to_sql + end + + def test_left_outer_joins_return_has_value_for_every_comment + all_post_ids = Post.pluck(:id) + assert_equal all_post_ids, all_post_ids & Post.left_outer_joins(:comments).pluck(:id) + end + + def test_left_outer_joins_actually_does_a_left_outer_join + queries = capture_sql { Author.left_outer_joins(:posts).to_a } + assert queries.any? { |sql| /LEFT OUTER JOIN/i.match?(sql) } end def test_construct_finder_sql_ignores_empty_left_outer_joins_hash - queries = capture_sql { Author.left_outer_joins({}) } - assert queries.none? { |sql| /LEFT OUTER JOIN/i =~ sql } + queries = capture_sql { Author.left_outer_joins({}).to_a } + assert queries.none? { |sql| /LEFT OUTER JOIN/i.match?(sql) } end def test_construct_finder_sql_ignores_empty_left_outer_joins_array - queries = capture_sql { Author.left_outer_joins([]) } - assert queries.none? { |sql| /LEFT OUTER JOIN/i =~ sql } + queries = capture_sql { Author.left_outer_joins([]).to_a } + assert queries.none? { |sql| /LEFT OUTER JOIN/i.match?(sql) } end def test_left_outer_joins_forbids_to_use_string_as_argument - assert_raise(ArgumentError){ Author.left_outer_joins('LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"').to_a } + assert_raise(ArgumentError) { Author.left_outer_joins('LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"').to_a } end def test_join_conditions_added_to_join_clause queries = capture_sql { Author.left_outer_joins(:essays).to_a } - assert queries.any? { |sql| /writer_type.*?=.*?(Author|\?|\$1|\:a1)/i =~ sql } - assert queries.none? { |sql| /WHERE/i =~ sql } + assert queries.any? { |sql| /writer_type.*?=.*?(Author|\?|\$1|\:a1)/i.match?(sql) } + assert queries.none? { |sql| /WHERE/i.match?(sql) } end def test_find_with_sti_join - scope = Post.left_outer_joins(:special_comments).where(:id => posts(:sti_comments).id) + scope = Post.left_outer_joins(:special_comments).where(id: posts(:sti_comments).id) # The join should match SpecialComment and its subclasses only assert scope.where("comments.type" => "Comment").empty? diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index b040485d99..dc26f6a383 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -1,27 +1,27 @@ require "cases/helper" -require 'models/author' -require 'models/post' -require 'models/person' -require 'models/reference' -require 'models/job' -require 'models/reader' -require 'models/comment' -require 'models/tag' -require 'models/tagging' -require 'models/subscriber' -require 'models/book' -require 'models/subscription' -require 'models/rating' -require 'models/member' -require 'models/member_detail' -require 'models/member_type' -require 'models/sponsor' -require 'models/club' -require 'models/organization' -require 'models/category' -require 'models/categorization' -require 'models/membership' -require 'models/essay' +require "models/author" +require "models/post" +require "models/person" +require "models/reference" +require "models/job" +require "models/reader" +require "models/comment" +require "models/tag" +require "models/tagging" +require "models/subscriber" +require "models/book" +require "models/subscription" +require "models/rating" +require "models/member" +require "models/member_detail" +require "models/member_type" +require "models/sponsor" +require "models/club" +require "models/organization" +require "models/category" +require "models/categorization" +require "models/membership" +require "models/essay" class NestedThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, @@ -65,12 +65,12 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_many_with_has_many_through_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Author.where('tags.id' => tags(:general).id), + Author.where("tags.id" => tags(:general).id), [authors(:david)], :tags ) # This ensures that the polymorphism of taggings is being observed correctly - authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel') + authors = Author.joins(:tags).where("taggings.taggable_type" => "FakeModel") assert authors.empty? end @@ -79,7 +79,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase # Through: has_many through def test_has_many_through_has_many_through_with_has_many_source_reflection luke, david = subscribers(:first), subscribers(:second) - assert_equal [luke, david, david], authors(:david).subscribers.order('subscribers.nick') + assert_equal [luke, david, david], authors(:david).subscribers.order("subscribers.nick") end def test_has_many_through_has_many_through_with_has_many_source_reflection_preload @@ -93,7 +93,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_many_through_with_has_many_source_reflection_preload_via_joins # All authors with subscribers where one of the subscribers' nick is 'alterself' assert_includes_and_joins_equal( - Author.where('subscribers.nick' => 'alterself'), + Author.where("subscribers.nick" => "alterself"), [authors(:david)], :subscribers ) end @@ -115,7 +115,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_one_with_has_one_through_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Member.where('member_types.id' => member_types(:founding).id), + Member.where("member_types.id" => member_types(:founding).id), [members(:groucho)], :nested_member_types ) end @@ -137,7 +137,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_one_through_with_has_one_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Member.where('sponsors.id' => sponsors(:moustache_club_sponsor_for_groucho).id), + Member.where("sponsors.id" => sponsors(:moustache_club_sponsor_for_groucho).id), [members(:groucho)], :nested_sponsors ) end @@ -149,7 +149,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy) assert_equal [groucho_details, other_details], - members(:groucho).organization_member_details.order('member_details.id') + members(:groucho).organization_member_details.order("member_details.id") end def test_has_many_through_has_one_with_has_many_through_source_reflection_preload @@ -164,12 +164,12 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_one_with_has_many_through_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Member.where('member_details.id' => member_details(:groucho).id).order('member_details.id'), + Member.where("member_details.id" => member_details(:groucho).id).order("member_details.id"), [members(:groucho), members(:some_other_guy)], :organization_member_details ) members = Member.joins(:organization_member_details). - where('member_details.id' => 9) + where("member_details.id" => 9) assert members.empty? end @@ -180,7 +180,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy) assert_equal [groucho_details, other_details], - members(:groucho).organization_member_details_2.order('member_details.id') + members(:groucho).organization_member_details_2.order("member_details.id") end def test_has_many_through_has_one_through_with_has_many_source_reflection_preload @@ -196,12 +196,12 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_one_through_with_has_many_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Member.where('member_details.id' => member_details(:groucho).id).order('member_details.id'), + Member.where("member_details.id" => member_details(:groucho).id).order("member_details.id"), [members(:groucho), members(:some_other_guy)], :organization_member_details_2 ) members = Member.joins(:organization_member_details_2). - where('member_details.id' => 9) + where("member_details.id" => 9) assert members.empty? end @@ -211,7 +211,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection general, cooking = categories(:general), categories(:cooking) - assert_equal [general, cooking], authors(:bob).post_categories.order('categories.id') + assert_equal [general, cooking], authors(:bob).post_categories.order("categories.id") end def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection_preload @@ -228,7 +228,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase Author.joins(:post_categories).first assert_includes_and_joins_equal( - Author.where('categories.id' => categories(:cooking).id), + Author.where("categories.id" => categories(:cooking).id), [authors(:bob)], :post_categories ) end @@ -239,7 +239,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection greetings, more = comments(:greetings), comments(:more_greetings) - assert_equal [greetings, more], categories(:technology).post_comments.order('comments.id') + assert_equal [greetings, more], categories(:technology).post_comments.order("comments.id") end def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload @@ -257,7 +257,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase Category.joins(:post_comments).first assert_includes_and_joins_equal( - Category.where('comments.id' => comments(:more_greetings).id).order('categories.id'), + Category.where("comments.id" => comments(:more_greetings).id).order("categories.id"), [categories(:general), categories(:technology)], :post_comments ) end @@ -268,7 +268,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection greetings, more = comments(:greetings), comments(:more_greetings) - assert_equal [greetings, more], authors(:bob).category_post_comments.order('comments.id') + assert_equal [greetings, more], authors(:bob).category_post_comments.order("comments.id") end def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection_preload @@ -285,7 +285,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase Author.joins(:category_post_comments).first assert_includes_and_joins_equal( - Author.where('comments.id' => comments(:does_it_hurt).id).order('authors.id'), + Author.where("comments.id" => comments(:does_it_hurt).id).order("authors.id"), [authors(:david), authors(:mary)], :category_post_comments ) end @@ -308,7 +308,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_many_through_with_belongs_to_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Author.where('tags.id' => tags(:general).id), + Author.where("tags.id" => tags(:general).id), [authors(:david)], :tagging_tags ) end @@ -320,7 +320,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase welcome_general, thinking_general = taggings(:welcome_general), taggings(:thinking_general) assert_equal [welcome_general, thinking_general], - categorizations(:david_welcome_general).post_taggings.order('taggings.id') + categorizations(:david_welcome_general).post_taggings.order("taggings.id") end def test_has_many_through_belongs_to_with_has_many_through_source_reflection_preload @@ -334,7 +334,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_belongs_to_with_has_many_through_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Categorization.where('taggings.id' => taggings(:welcome_general).id).order('taggings.id'), + Categorization.where("taggings.id" => taggings(:welcome_general).id).order("taggings.id"), [categorizations(:david_welcome_general)], :post_taggings ) end @@ -357,7 +357,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_one_through_has_one_with_has_one_through_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Member.where('member_types.id' => member_types(:founding).id), + Member.where("member_types.id" => member_types(:founding).id), [members(:groucho)], :nested_member_type ) end @@ -391,7 +391,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_one_through_has_one_through_with_belongs_to_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Member.where('categories.id' => categories(:technology).id), + Member.where("categories.id" => categories(:technology).id), [members(:blarpy_winkup)], :club_category ) end @@ -404,7 +404,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_distinct_has_many_through_a_has_many_through_association_on_through_reflection author = authors(:david) assert_equal [subscribers(:first), subscribers(:second)], - author.distinct_subscribers.order('subscribers.nick') + author.distinct_subscribers.order("subscribers.nick") end def test_nested_has_many_through_with_a_table_referenced_multiple_times @@ -413,26 +413,26 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase author.similar_posts.sort_by(&:id) # Mary and Bob both have posts in misc, but they are the only ones. - authors = Author.joins(:similar_posts).where('posts.id' => posts(:misc_by_bob).id) + authors = Author.joins(:similar_posts).where("posts.id" => posts(:misc_by_bob).id) assert_equal [authors(:mary), authors(:bob)], authors.distinct.sort_by(&:id) # Check the polymorphism of taggings is being observed correctly (in both joins) - authors = Author.joins(:similar_posts).where('taggings.taggable_type' => 'FakeModel') + authors = Author.joins(:similar_posts).where("taggings.taggable_type" => "FakeModel") assert authors.empty? - authors = Author.joins(:similar_posts).where('taggings_authors_join.taggable_type' => 'FakeModel') + authors = Author.joins(:similar_posts).where("taggings_authors_join.taggable_type" => "FakeModel") assert authors.empty? end def test_has_many_through_with_foreign_key_option_on_through_reflection - assert_equal [posts(:welcome), posts(:authorless)], people(:david).agents_posts.order('posts.id') + assert_equal [posts(:welcome), posts(:authorless)], people(:david).agents_posts.order("posts.id") assert_equal [authors(:david)], references(:david_unicyclist).agents_posts_authors - references = Reference.joins(:agents_posts_authors).where('authors.id' => authors(:david).id) + references = Reference.joins(:agents_posts_authors).where("authors.id" => authors(:david).id) assert_equal [references(:david_unicyclist)], references end def test_has_many_through_with_foreign_key_option_on_source_reflection - assert_equal [people(:michael), people(:susan)], jobs(:unicyclist).agents.order('people.id') + assert_equal [people(:michael), people(:susan)], jobs(:unicyclist).agents.order("people.id") jobs = Job.joins(:agents) assert_equal [jobs(:unicyclist), jobs(:unicyclist)], jobs @@ -443,7 +443,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase assert_equal [ratings(:special_comment_rating), ratings(:sub_special_comment_rating)], ratings # Ensure STI is respected in the join - scope = Post.joins(:special_comments_ratings).where(:id => posts(:sti_comments).id) + scope = Post.joins(:special_comments_ratings).where(id: posts(:sti_comments).id) assert scope.where("comments.type" => "Comment").empty? assert !scope.where("comments.type" => "SpecialComment").empty? assert !scope.where("comments.type" => "SubSpecialComment").empty? @@ -453,7 +453,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase taggings = posts(:sti_comments).special_comments_ratings_taggings assert_equal [taggings(:special_comment_rating)], taggings - scope = Post.joins(:special_comments_ratings_taggings).where(:id => posts(:sti_comments).id) + scope = Post.joins(:special_comments_ratings_taggings).where(id: posts(:sti_comments).id) assert scope.where("comments.type" => "Comment").empty? assert !scope.where("comments.type" => "SpecialComment").empty? end @@ -505,7 +505,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase end def test_nested_has_many_through_with_conditions_on_through_associations_preload - assert Author.where('tags.id' => 100).joins(:misc_post_first_blue_tags).empty? + assert Author.where("tags.id" => 100).joins(:misc_post_first_blue_tags).empty? authors = assert_queries(3) { Author.includes(:misc_post_first_blue_tags).to_a.sort_by(&:id) } blue = tags(:blue) @@ -518,7 +518,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_nested_has_many_through_with_conditions_on_through_associations_preload_via_joins # Pointless condition to force single-query loading assert_includes_and_joins_equal( - Author.where('tags.id = tags.id').references(:tags), + Author.where("tags.id = tags.id").references(:tags), [authors(:bob)], :misc_post_first_blue_tags ) end @@ -539,7 +539,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_nested_has_many_through_with_conditions_on_source_associations_preload_via_joins # Pointless condition to force single-query loading assert_includes_and_joins_equal( - Author.where('tags.id = tags.id').references(:tags), + Author.where("tags.id = tags.id").references(:tags), [authors(:bob)], :misc_post_first_blue_tags_2 ) end @@ -548,13 +548,13 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase assert_equal [categories(:general)], organizations(:nsa).author_essay_categories organizations = Organization.joins(:author_essay_categories). - where('categories.id' => categories(:general).id) + where("categories.id" => categories(:general).id) assert_equal [organizations(:nsa)], organizations assert_equal categories(:general), organizations(:nsa).author_owned_essay_category organizations = Organization.joins(:author_owned_essay_category). - where('categories.id' => categories(:general).id) + where("categories.id" => categories(:general).id) assert_equal [organizations(:nsa)], organizations end diff --git a/activerecord/test/cases/associations/required_test.rb b/activerecord/test/cases/associations/required_test.rb index 3e5494e897..f8b686721e 100644 --- a/activerecord/test/cases/associations/required_test.rb +++ b/activerecord/test/cases/associations/required_test.rb @@ -18,8 +18,8 @@ class RequiredAssociationsTest < ActiveRecord::TestCase end teardown do - @connection.drop_table 'parents', if_exists: true - @connection.drop_table 'children', if_exists: true + @connection.drop_table "parents", if_exists: true + @connection.drop_table "children", if_exists: true end test "belongs_to associations are not required by default" do @@ -92,11 +92,11 @@ class RequiredAssociationsTest < ActiveRecord::TestCase private - def subclass_of(klass, &block) - subclass = Class.new(klass, &block) - def subclass.name - superclass.name + def subclass_of(klass, &block) + subclass = Class.new(klass, &block) + def subclass.name + superclass.name + end + subclass end - subclass - end end diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 01a058918a..c095b3a91c 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -1,80 +1,77 @@ require "cases/helper" -require 'models/computer' -require 'models/developer' -require 'models/project' -require 'models/company' -require 'models/categorization' -require 'models/category' -require 'models/post' -require 'models/author' -require 'models/comment' -require 'models/tag' -require 'models/tagging' -require 'models/person' -require 'models/reader' -require 'models/ship_part' -require 'models/ship' -require 'models/liquid' -require 'models/molecule' -require 'models/electron' -require 'models/man' -require 'models/interest' +require "models/computer" +require "models/developer" +require "models/project" +require "models/company" +require "models/categorization" +require "models/category" +require "models/post" +require "models/author" +require "models/comment" +require "models/tag" +require "models/tagging" +require "models/person" +require "models/reader" +require "models/ship_part" +require "models/ship" +require "models/liquid" +require "models/molecule" +require "models/electron" +require "models/man" +require "models/interest" class AssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :developers_projects, :computers, :people, :readers, :authors, :author_favorites def test_eager_loading_should_not_change_count_of_children - liquid = Liquid.create(:name => 'salty') - molecule = liquid.molecules.create(:name => 'molecule_1') - molecule.electrons.create(:name => 'electron_1') - molecule.electrons.create(:name => 'electron_2') + liquid = Liquid.create(name: "salty") + molecule = liquid.molecules.create(name: "molecule_1") + molecule.electrons.create(name: "electron_1") + molecule.electrons.create(name: "electron_2") - liquids = Liquid.includes(:molecules => :electrons).references(:molecules).where('molecules.id is not null') + liquids = Liquid.includes(molecules: :electrons).references(:molecules).where("molecules.id is not null") assert_equal 1, liquids[0].molecules.length end def test_subselect author = authors :david favs = author.author_favorites - fav2 = author.author_favorites.where(:author => Author.where(id: author.id)).to_a + fav2 = author.author_favorites.where(author: Author.where(id: author.id)).to_a assert_equal favs, fav2 end def test_loading_the_association_target_should_keep_child_records_marked_for_destruction - ship = Ship.create!(:name => "The good ship Dollypop") - part = ship.parts.create!(:name => "Mast") + ship = Ship.create!(name: "The good ship Dollypop") + part = ship.parts.create!(name: "Mast") part.mark_for_destruction - ship.parts.send(:load_target) assert ship.parts[0].marked_for_destruction? end def test_loading_the_association_target_should_load_most_recent_attributes_for_child_records_marked_for_destruction - ship = Ship.create!(:name => "The good ship Dollypop") - part = ship.parts.create!(:name => "Mast") + ship = Ship.create!(name: "The good ship Dollypop") + part = ship.parts.create!(name: "Mast") part.mark_for_destruction - ShipPart.find(part.id).update_columns(name: 'Deck') - ship.parts.send(:load_target) - assert_equal 'Deck', ship.parts[0].name + ShipPart.find(part.id).update_columns(name: "Deck") + assert_equal "Deck", ship.parts[0].name end - def test_include_with_order_works - assert_nothing_raised {Account.all.merge!(:order => 'id', :includes => :firm).first} - assert_nothing_raised {Account.all.merge!(:order => :id, :includes => :firm).first} + assert_nothing_raised { Account.all.merge!(order: "id", includes: :firm).first } + assert_nothing_raised { Account.all.merge!(order: :id, includes: :firm).first } end def test_bad_collection_keys - assert_raise(ArgumentError, 'ActiveRecord should have barked on bad collection keys') do - Class.new(ActiveRecord::Base).has_many(:wheels, :name => 'wheels') + assert_raise(ArgumentError, "ActiveRecord should have barked on bad collection keys") do + Class.new(ActiveRecord::Base).has_many(:wheels, name: "wheels") end end def test_should_construct_new_finder_sql_after_create - person = Person.new :first_name => 'clark' + person = Person.new first_name: "clark" assert_equal [], person.readers.to_a person.save! - reader = Reader.create! :person => person, :post => Post.new(:title => "foo", :body => "bar") + reader = Reader.create! person: person, post: Post.new(title: "foo", body: "bar") assert person.readers.find(reader.id) end @@ -122,9 +119,8 @@ class AssociationsTest < ActiveRecord::TestCase def test_association_with_references firm = companies(:first_firm) - assert_includes firm.association_with_references.references_values, 'foo' + assert_includes firm.association_with_references.references_values, "foo" end - end class AssociationProxyTest < ActiveRecord::TestCase @@ -133,9 +129,9 @@ class AssociationProxyTest < ActiveRecord::TestCase def test_push_does_not_load_target david = authors(:david) - david.posts << (post = Post.new(:title => "New on Edge", :body => "More cool stuff!")) + david.posts << (post = Post.new(title: "New on Edge", body: "More cool stuff!")) assert !david.posts.loaded? - assert david.posts.include?(post) + assert_includes david.posts, post end def test_push_has_many_through_does_not_load_target @@ -143,35 +139,35 @@ class AssociationProxyTest < ActiveRecord::TestCase david.categories << categories(:technology) assert !david.categories.loaded? - assert david.categories.include?(categories(:technology)) + assert_includes david.categories, categories(:technology) end def test_push_followed_by_save_does_not_load_target david = authors(:david) - david.posts << (post = Post.new(:title => "New on Edge", :body => "More cool stuff!")) + david.posts << (post = Post.new(title: "New on Edge", body: "More cool stuff!")) assert !david.posts.loaded? david.save assert !david.posts.loaded? - assert david.posts.include?(post) + assert_includes david.posts, post end def test_push_does_not_lose_additions_to_new_record - josh = Author.new(:name => "Josh") - josh.posts << Post.new(:title => "New on Edge", :body => "More cool stuff!") + josh = Author.new(name: "Josh") + josh.posts << Post.new(title: "New on Edge", body: "More cool stuff!") assert josh.posts.loaded? assert_equal 1, josh.posts.size end def test_append_behaves_like_push - josh = Author.new(:name => "Josh") - josh.posts.append Post.new(:title => "New on Edge", :body => "More cool stuff!") + josh = Author.new(name: "Josh") + josh.posts.append Post.new(title: "New on Edge", body: "More cool stuff!") assert josh.posts.loaded? assert_equal 1, josh.posts.size end def test_prepend_is_not_defined - josh = Author.new(:name => "Josh") + josh = Author.new(name: "Josh") assert_raises(NoMethodError) { josh.posts.prepend Post.new } end @@ -183,25 +179,33 @@ class AssociationProxyTest < ActiveRecord::TestCase assert !david.projects.loaded? end + def test_load_does_load_target + david = developers(:david) + + assert !david.projects.loaded? + david.projects.load + assert david.projects.loaded? + end + def test_inspect_does_not_reload_a_not_yet_loaded_target - andreas = Developer.new :name => 'Andreas', :log => 'new developer added' + andreas = Developer.new name: "Andreas", log: "new developer added" assert !andreas.audit_logs.loaded? assert_match(/message: "new developer added"/, andreas.audit_logs.inspect) end def test_save_on_parent_saves_children - developer = Developer.create :name => "Bryan", :salary => 50_000 + developer = Developer.create name: "Bryan", salary: 50_000 assert_equal 1, developer.reload.audit_logs.size end def test_create_via_association_with_block - post = authors(:david).posts.create(:title => "New on Edge") {|p| p.body = "More cool stuff!"} + post = authors(:david).posts.create(title: "New on Edge") { |p| p.body = "More cool stuff!" } assert_equal post.title, "New on Edge" assert_equal post.body, "More cool stuff!" end def test_create_with_bang_via_association_with_block - post = authors(:david).posts.create!(:title => "New on Edge") {|p| p.body = "More cool stuff!"} + post = authors(:david).posts.create!(title: "New on Edge") { |p| p.body = "More cool stuff!" } assert_equal post.title, "New on Edge" assert_equal post.body, "More cool stuff!" end @@ -219,7 +223,7 @@ class AssociationProxyTest < ActiveRecord::TestCase end def test_scoped_allows_conditions - assert developers(:david).projects.merge(where: 'foo').to_sql.include?('foo') + assert developers(:david).projects.merge(where: "foo").to_sql.include?("foo") end test "getting a scope from an association" do @@ -248,6 +252,15 @@ class AssociationProxyTest < ActiveRecord::TestCase test "first! works on loaded associations" do david = authors(:david) assert_equal david.posts.first, david.posts.reload.first! + assert david.posts.loaded? + assert_no_queries { david.posts.first! } + end + + def test_pluck_uses_loaded_target + david = authors(:david) + assert_equal david.posts.pluck(:title), david.posts.load.pluck(:title) + assert david.posts.loaded? + assert_no_queries { david.posts.pluck(:title) } end def test_reset_unloads_target @@ -264,18 +277,18 @@ class OverridingAssociationsTest < ActiveRecord::TestCase class DifferentPerson < ActiveRecord::Base; end class PeopleList < ActiveRecord::Base - has_and_belongs_to_many :has_and_belongs_to_many, :before_add => :enlist - has_many :has_many, :before_add => :enlist + has_and_belongs_to_many :has_and_belongs_to_many, before_add: :enlist + has_many :has_many, before_add: :enlist belongs_to :belongs_to has_one :has_one end class DifferentPeopleList < PeopleList # Different association with the same name, callbacks should be omitted here. - has_and_belongs_to_many :has_and_belongs_to_many, :class_name => 'DifferentPerson' - has_many :has_many, :class_name => 'DifferentPerson' - belongs_to :belongs_to, :class_name => 'DifferentPerson' - has_one :has_one, :class_name => 'DifferentPerson' + has_and_belongs_to_many :has_and_belongs_to_many, class_name: "DifferentPerson" + has_many :has_many, class_name: "DifferentPerson" + belongs_to :belongs_to, class_name: "DifferentPerson" + has_one :has_one, class_name: "DifferentPerson" end def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited diff --git a/activerecord/test/cases/attribute_decorators_test.rb b/activerecord/test/cases/attribute_decorators_test.rb index 2aeb2601c2..cfa6ed1da6 100644 --- a/activerecord/test/cases/attribute_decorators_test.rb +++ b/activerecord/test/cases/attribute_decorators_test.rb @@ -1,9 +1,9 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class AttributeDecoratorsTest < ActiveRecord::TestCase class Model < ActiveRecord::Base - self.table_name = 'attribute_decorators_model' + self.table_name = "attribute_decorators_model" end class StringDecorator < SimpleDelegator @@ -28,19 +28,19 @@ module ActiveRecord teardown do return unless @connection - @connection.drop_table 'attribute_decorators_model', if_exists: true + @connection.drop_table "attribute_decorators_model", if_exists: true Model.attribute_type_decorations.clear Model.reset_column_information end test "attributes can be decorated" do - model = Model.new(a_string: 'Hello') - assert_equal 'Hello', model.a_string + model = Model.new(a_string: "Hello") + assert_equal "Hello", model.a_string Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } - model = Model.new(a_string: 'Hello') - assert_equal 'Hello decorated!', model.a_string + model = Model.new(a_string: "Hello") + assert_equal "Hello decorated!", model.a_string end test "decoration does not eagerly load existing columns" do @@ -51,54 +51,54 @@ module ActiveRecord end test "undecorated columns are not touched" do - Model.attribute :another_string, :string, default: 'something or other' + Model.attribute :another_string, :string, default: "something or other" Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } - assert_equal 'something or other', Model.new.another_string + assert_equal "something or other", Model.new.another_string end test "decorators can be chained" do Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } Model.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) } - model = Model.new(a_string: 'Hello!') + model = Model.new(a_string: "Hello!") - assert_equal 'Hello! decorated! decorated!', model.a_string + assert_equal "Hello! decorated! decorated!", model.a_string end test "decoration of the same type multiple times is idempotent" do Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } - model = Model.new(a_string: 'Hello') - assert_equal 'Hello decorated!', model.a_string + model = Model.new(a_string: "Hello") + assert_equal "Hello decorated!", model.a_string end test "decorations occur in order of declaration" do Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } Model.decorate_attribute_type(:a_string, :other) do |type| - StringDecorator.new(type, 'decorated again!') + StringDecorator.new(type, "decorated again!") end - model = Model.new(a_string: 'Hello!') + model = Model.new(a_string: "Hello!") - assert_equal 'Hello! decorated! decorated again!', model.a_string + assert_equal "Hello! decorated! decorated again!", model.a_string end test "decorating attributes does not modify parent classes" do - Model.attribute :another_string, :string, default: 'whatever' + Model.attribute :another_string, :string, default: "whatever" Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } child_class = Class.new(Model) child_class.decorate_attribute_type(:another_string, :test) { |t| StringDecorator.new(t) } child_class.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) } - model = Model.new(a_string: 'Hello!') - child = child_class.new(a_string: 'Hello!') + model = Model.new(a_string: "Hello!") + child = child_class.new(a_string: "Hello!") - assert_equal 'Hello! decorated!', model.a_string - assert_equal 'whatever', model.another_string - assert_equal 'Hello! decorated! decorated!', child.a_string - assert_equal 'whatever decorated!', child.another_string + assert_equal "Hello! decorated!", model.a_string + assert_equal "whatever", model.another_string + assert_equal "Hello! decorated! decorated!", child.a_string + assert_equal "whatever decorated!", child.another_string end class Multiplier < SimpleDelegator @@ -116,9 +116,9 @@ module ActiveRecord Multiplier.new(type) end - model = Model.new(a_string: 'whatever', an_int: 1) + model = Model.new(a_string: "whatever", an_int: 1) - assert_equal 'whatever', model.a_string + assert_equal "whatever", model.a_string assert_equal 2, model.an_int end end diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb index 74e556211b..a8592bd179 100644 --- a/activerecord/test/cases/attribute_methods/read_test.rb +++ b/activerecord/test/cases/attribute_methods/read_test.rb @@ -1,5 +1,4 @@ require "cases/helper" -require 'thread' module ActiveRecord module AttributeMethods @@ -40,13 +39,13 @@ module ActiveRecord instance = @klass.new @klass.attribute_names.each do |name| - assert !instance.methods.map(&:to_s).include?(name) + assert_not_includes instance.methods.map(&:to_s), name end @klass.define_attribute_methods @klass.attribute_names.each do |name| - assert instance.methods.map(&:to_s).include?(name), "#{name} is not defined" + assert_includes instance.methods.map(&:to_s), name, "#{name} is not defined" end end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 1db52af59b..4c77ecab7c 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -1,15 +1,15 @@ require "cases/helper" -require 'models/minimalistic' -require 'models/developer' -require 'models/auto_id' -require 'models/boolean' -require 'models/computer' -require 'models/topic' -require 'models/company' -require 'models/category' -require 'models/reply' -require 'models/contact' -require 'models/keyboard' +require "models/minimalistic" +require "models/developer" +require "models/auto_id" +require "models/boolean" +require "models/computer" +require "models/topic" +require "models/company" +require "models/category" +require "models/reply" +require "models/contact" +require "models/keyboard" class AttributeMethodsTest < ActiveRecord::TestCase include InTimeZone @@ -19,7 +19,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase def setup @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup @target = Class.new(ActiveRecord::Base) - @target.table_name = 'topics' + @target.table_name = "topics" end teardown do @@ -27,15 +27,34 @@ class AttributeMethodsTest < ActiveRecord::TestCase ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers) end - def test_attribute_for_inspect + test "attribute_for_inspect with a string" do t = topics(:first) t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters" - assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on) assert_equal '"The First Topic Now Has A Title With\nNewlines And ..."', t.attribute_for_inspect(:title) end - def test_attribute_present + test "attribute_for_inspect with a date" do + t = topics(:first) + + assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on) + end + + test "attribute_for_inspect with an array" do + t = topics(:first) + t.content = [Object.new] + + assert_match %r(\[#<Object:0x[0-9a-f]+>\]), t.attribute_for_inspect(:content) + end + + test "attribute_for_inspect with a long array" do + t = topics(:first) + t.content = (1..11).to_a + + assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]", t.attribute_for_inspect(:content) + end + + test "attribute_present" do t = Topic.new t.title = "hello there!" t.written_on = Time.now @@ -46,7 +65,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert !t.attribute_present?("author_name") end - def test_attribute_present_with_booleans + test "attribute_present with booleans" do b1 = Boolean.new b1.value = false assert b1.attribute_present?(:value) @@ -64,44 +83,44 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert Boolean.find(b4.id).attribute_present?(:value) end - def test_caching_nil_primary_key + test "caching a nil primary key" do klass = Class.new(Minimalistic) assert_called(klass, :reset_primary_key, returns: nil) do 2.times { klass.primary_key } end end - def test_attribute_keys_on_new_instance + test "attribute keys on a new instance" do t = Topic.new assert_equal nil, t.title, "The topics table has a title column, so it should be nil" assert_raise(NoMethodError) { t.title2 } end - def test_boolean_attributes + test "boolean attributes" do assert !Topic.find(1).approved? assert Topic.find(2).approved? end - def test_set_attributes + test "set attributes" do topic = Topic.find(1) - topic.attributes = { "title" => "Budget", "author_name" => "Jason" } + topic.attributes = { title: "Budget", author_name: "Jason" } topic.save assert_equal("Budget", topic.title) assert_equal("Jason", topic.author_name) assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address) end - def test_set_attributes_without_hash + test "set attributes without a hash" do topic = Topic.new - assert_raise(ArgumentError) { topic.attributes = '' } + assert_raise(ArgumentError) { topic.attributes = "" } end - def test_integers_as_nil - test = AutoId.create('value' => '') + test "integers as nil" do + test = AutoId.create(value: "") assert_nil AutoId.find(test.id).value end - def test_set_attributes_with_block + test "set attributes with a block" do topic = Topic.new do |t| t.title = "Budget" t.author_name = "Jason" @@ -111,7 +130,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal("Jason", topic.author_name) end - def test_respond_to? + test "respond_to?" do topic = Topic.find(1) assert_respond_to topic, "title" assert_respond_to topic, "title?" @@ -125,27 +144,27 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert !topic.respond_to?(:nothingness) end - def test_respond_to_with_custom_primary_key + test "respond_to? with a custom primary key" do keyboard = Keyboard.create assert_not_nil keyboard.key_number assert_equal keyboard.key_number, keyboard.id - assert keyboard.respond_to?('key_number') - assert keyboard.respond_to?('id') + assert keyboard.respond_to?("key_number") + assert keyboard.respond_to?("id") end - def test_id_before_type_cast_with_custom_primary_key + test "id_before_type_cast with a custom primary key" do keyboard = Keyboard.create - keyboard.key_number = '10' - assert_equal '10', keyboard.id_before_type_cast - assert_equal nil, keyboard.read_attribute_before_type_cast('id') - assert_equal '10', keyboard.read_attribute_before_type_cast('key_number') - assert_equal '10', keyboard.read_attribute_before_type_cast(:key_number) + keyboard.key_number = "10" + assert_equal "10", keyboard.id_before_type_cast + assert_equal nil, keyboard.read_attribute_before_type_cast("id") + assert_equal "10", keyboard.read_attribute_before_type_cast("key_number") + assert_equal "10", keyboard.read_attribute_before_type_cast(:key_number) end - # Syck calls respond_to? before actually calling initialize - def test_respond_to_with_allocated_object + # Syck calls respond_to? before actually calling initialize. + test "respond_to? with an allocated object" do klass = Class.new(ActiveRecord::Base) do - self.table_name = 'topics' + self.table_name = "topics" end topic = klass.allocate @@ -155,31 +174,32 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_respond_to topic, :title end - # IRB inspects the return value of "MyModel.allocate". - def test_allocated_object_can_be_inspected + # IRB inspects the return value of MyModel.allocate. + test "allocated objects can be inspected" do topic = Topic.allocate assert_equal "#<Topic not initialized>", topic.inspect end - def test_array_content + test "array content" do + content = %w( one two three ) topic = Topic.new - topic.content = %w( one two three ) + topic.content = content topic.save - assert_equal(%w( one two three ), Topic.find(topic.id).content) + assert_equal content, Topic.find(topic.id).content end - def test_read_attributes_before_type_cast - category = Category.new({:name=>"Test category", :type => nil}) - category_attrs = {"name"=>"Test category", "id" => nil, "type" => nil, "categorizations_count" => nil} - assert_equal category_attrs , category.attributes_before_type_cast + test "read attributes_before_type_cast" do + category = Category.new(name: "Test category", type: nil) + category_attrs = { "name" => "Test category", "id" => nil, "type" => nil, "categorizations_count" => nil } + assert_equal category_attrs, category.attributes_before_type_cast end if current_adapter?(:Mysql2Adapter) - def test_read_attributes_before_type_cast_on_boolean - bool = Boolean.create!({ "value" => false }) - if RUBY_PLATFORM =~ /java/ - # JRuby will return the value before typecast as string + test "read attributes_before_type_cast on a boolean" do + bool = Boolean.create!("value" => false) + if RUBY_PLATFORM.include?("java") + # JRuby will return the value before typecast as string. assert_equal "0", bool.reload.attributes_before_type_cast["value"] else assert_equal 0, bool.reload.attributes_before_type_cast["value"] @@ -187,7 +207,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_read_attributes_before_type_cast_on_datetime + test "read attributes_before_type_cast on a datetime" do in_time_zone "Pacific Time (US & Canada)" do record = @target.new @@ -202,7 +222,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_read_attributes_after_type_cast_on_datetime + test "read attributes_after_type_cast on a date" do tz = "Pacific Time (US & Canada)" in_time_zone tz do @@ -223,7 +243,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_hash_content + test "hash content" do topic = Topic.new topic.content = { "one" => 1, "two" => 2 } topic.save @@ -237,7 +257,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal 3, Topic.find(topic.id).content["three"] end - def test_update_array_content + test "update array content" do topic = Topic.new topic.content = %w( one two three ) @@ -251,25 +271,25 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal(%w( one two three four five ), topic.content) end - def test_case_sensitive_attributes_hash - # DB2 is not case-sensitive + test "case-sensitive attributes hash" do + # DB2 is not case-sensitive. return true if current_adapter?(:DB2Adapter) - assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.first.attributes + assert_equal @loaded_fixtures["computers"]["workstation"].to_hash, Computer.first.attributes end - def test_attributes_without_primary_key + test "attributes without primary key" do klass = Class.new(ActiveRecord::Base) do - self.table_name = 'developers_projects' + self.table_name = "developers_projects" end assert_equal klass.column_names, klass.new.attributes.keys - assert_not klass.new.has_attribute?('id') + assert_not klass.new.has_attribute?("id") end - def test_hashes_not_mangled - new_topic = { :title => "New Topic" } - new_topic_values = { :title => "AnotherTopic" } + test "hashes are not mangled" do + new_topic = { title: "New Topic" } + new_topic_values = { title: "AnotherTopic" } topic = Topic.new(new_topic) assert_equal new_topic[:title], topic.title @@ -278,13 +298,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal new_topic_values[:title], topic.title end - def test_create_through_factory - topic = Topic.create("title" => "New Topic") + test "create through factory" do + topic = Topic.create(title: "New Topic") topicReloaded = Topic.find(topic.id) assert_equal(topic, topicReloaded) end - def test_write_attribute + test "write_attribute" do topic = Topic.new topic.send(:write_attribute, :title, "Still another topic") assert_equal "Still another topic", topic.title @@ -299,7 +319,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "Still another topic: part 4", topic.title end - def test_read_attribute + test "read_attribute" do topic = Topic.new topic.title = "Don't change the topic" assert_equal "Don't change the topic", topic.read_attribute("title") @@ -309,15 +329,15 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "Don't change the topic", topic[:title] end - def test_read_attribute_raises_missing_attribute_error_when_not_exists - computer = Computer.select('id').first + test "read_attribute raises ActiveModel::MissingAttributeError when the attribute does not exist" do + computer = Computer.select("id").first assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] } assert_raises(ActiveModel::MissingAttributeError) { computer[:extendedWarranty] } - assert_raises(ActiveModel::MissingAttributeError) { computer[:no_column_exists] = 'Hello!' } - assert_nothing_raised { computer[:developer] = 'Hello!' } + assert_raises(ActiveModel::MissingAttributeError) { computer[:no_column_exists] = "Hello!" } + assert_nothing_raised { computer[:developer] = "Hello!" } end - def test_read_attribute_when_false + test "read_attribute when false" do topic = topics(:first) topic.approved = false assert !topic.approved?, "approved should be false" @@ -325,7 +345,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert !topic.approved?, "approved should be false" end - def test_read_attribute_when_true + test "read_attribute when true" do topic = topics(:first) topic.approved = true assert topic.approved?, "approved should be true" @@ -333,7 +353,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert topic.approved?, "approved should be true" end - def test_read_write_boolean_attribute + test "boolean attributes writing and reading" do topic = Topic.new topic.approved = "false" assert !topic.approved?, "approved should be false" @@ -348,7 +368,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert topic.approved?, "approved should be true" end - def test_overridden_write_attribute + test "overridden write_attribute" do topic = Topic.new def topic.write_attribute(attr_name, value) super(attr_name, value.downcase) @@ -367,7 +387,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "yet another topic: part 4", topic.title end - def test_overridden_read_attribute + test "overridden read_attribute" do topic = Topic.new topic.title = "Stop changing the topic" def topic.read_attribute(attr_name) @@ -381,40 +401,40 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "STOP CHANGING THE TOPIC", topic[:title] end - def test_read_overridden_attribute - topic = Topic.new(:title => 'a') - def topic.title() 'b' end - assert_equal 'a', topic[:title] + test "read overridden attribute" do + topic = Topic.new(title: "a") + def topic.title() "b" end + assert_equal "a", topic[:title] end - def test_query_attribute_string + test "string attribute predicate" do [nil, "", " "].each do |value| - assert_equal false, Topic.new(:author_name => value).author_name? + assert_equal false, Topic.new(author_name: value).author_name? end - assert_equal true, Topic.new(:author_name => "Name").author_name? + assert_equal true, Topic.new(author_name: "Name").author_name? end - def test_query_attribute_number + test "number attribute predicate" do [nil, 0, "0"].each do |value| - assert_equal false, Developer.new(:salary => value).salary? + assert_equal false, Developer.new(salary: value).salary? end - assert_equal true, Developer.new(:salary => 1).salary? - assert_equal true, Developer.new(:salary => "1").salary? + assert_equal true, Developer.new(salary: 1).salary? + assert_equal true, Developer.new(salary: "1").salary? end - def test_query_attribute_boolean + test "boolean attribute predicate" do [nil, "", false, "false", "f", 0].each do |value| - assert_equal false, Topic.new(:approved => value).approved? + assert_equal false, Topic.new(approved: value).approved? end [true, "true", "1", 1].each do |value| - assert_equal true, Topic.new(:approved => value).approved? + assert_equal true, Topic.new(approved: value).approved? end end - def test_query_attribute_with_custom_fields + test "custom field attribute predicate" do object = Company.find_by_sql(<<-SQL).first SELECT c1.*, c2.type as string_value, c2.rating as int_value FROM companies c1, companies c2 @@ -435,95 +455,95 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert !object.int_value? end - def test_non_attribute_access_and_assignment + test "non-attribute read and write" do topic = Topic.new assert !topic.respond_to?("mumbo") assert_raise(NoMethodError) { topic.mumbo } assert_raise(NoMethodError) { topic.mumbo = 5 } end - def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing - topic = @target.new(:title => 'Budget') - assert topic.respond_to?('title') - assert_equal 'Budget', topic.title - assert !topic.respond_to?('title_hello_world') + test "undeclared attribute method does not affect respond_to? and method_missing" do + topic = @target.new(title: "Budget") + assert topic.respond_to?("title") + assert_equal "Budget", topic.title + assert !topic.respond_to?("title_hello_world") assert_raise(NoMethodError) { topic.title_hello_world } end - def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing - topic = @target.new(:title => 'Budget') + test "declared prefixed attribute method affects respond_to? and method_missing" do + topic = @target.new(title: "Budget") %w(default_ title_).each do |prefix| @target.class_eval "def #{prefix}attribute(*args) args end" @target.attribute_method_prefix prefix meth = "#{prefix}title" assert topic.respond_to?(meth) - assert_equal ['title'], topic.send(meth) - assert_equal ['title', 'a'], topic.send(meth, 'a') - assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3) + assert_equal ["title"], topic.send(meth) + assert_equal ["title", "a"], topic.send(meth, "a") + assert_equal ["title", 1, 2, 3], topic.send(meth, 1, 2, 3) end end - def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing + test "declared suffixed attribute method affects respond_to? and method_missing" do %w(_default _title_default _it! _candidate= able?).each do |suffix| @target.class_eval "def attribute#{suffix}(*args) args end" @target.attribute_method_suffix suffix - topic = @target.new(:title => 'Budget') + topic = @target.new(title: "Budget") meth = "title#{suffix}" assert topic.respond_to?(meth) - assert_equal ['title'], topic.send(meth) - assert_equal ['title', 'a'], topic.send(meth, 'a') - assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3) + assert_equal ["title"], topic.send(meth) + assert_equal ["title", "a"], topic.send(meth, "a") + assert_equal ["title", 1, 2, 3], topic.send(meth, 1, 2, 3) end end - def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing - [['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix| + test "declared affixed attribute method affects respond_to? and method_missing" do + [["mark_", "_for_update"], ["reset_", "!"], ["default_", "_value?"]].each do |prefix, suffix| @target.class_eval "def #{prefix}attribute#{suffix}(*args) args end" - @target.attribute_method_affix({ :prefix => prefix, :suffix => suffix }) - topic = @target.new(:title => 'Budget') + @target.attribute_method_affix(prefix: prefix, suffix: suffix) + topic = @target.new(title: "Budget") meth = "#{prefix}title#{suffix}" assert topic.respond_to?(meth) - assert_equal ['title'], topic.send(meth) - assert_equal ['title', 'a'], topic.send(meth, 'a') - assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3) + assert_equal ["title"], topic.send(meth) + assert_equal ["title", "a"], topic.send(meth, "a") + assert_equal ["title", 1, 2, 3], topic.send(meth, 1, 2, 3) end end - def test_should_unserialize_attributes_for_frozen_records - myobj = {:value1 => :value2} - topic = Topic.create("content" => myobj) + test "should unserialize attributes for frozen records" do + myobj = { value1: :value2 } + topic = Topic.create(content: myobj) topic.freeze assert_equal myobj, topic.content end - def test_typecast_attribute_from_select_to_false - Topic.create(:title => 'Budget') - # Oracle does not support boolean expressions in SELECT + test "typecast attribute from select to false" do + Topic.create(title: "Budget") + # Oracle does not support boolean expressions in SELECT. if current_adapter?(:OracleAdapter, :FbAdapter) - topic = Topic.all.merge!(:select => "topics.*, 0 as is_test").first + topic = Topic.all.merge!(select: "topics.*, 0 as is_test").first else - topic = Topic.all.merge!(:select => "topics.*, 1=2 as is_test").first + topic = Topic.all.merge!(select: "topics.*, 1=2 as is_test").first end assert !topic.is_test? end - def test_typecast_attribute_from_select_to_true - Topic.create(:title => 'Budget') - # Oracle does not support boolean expressions in SELECT + test "typecast attribute from select to true" do + Topic.create(title: "Budget") + # Oracle does not support boolean expressions in SELECT. if current_adapter?(:OracleAdapter, :FbAdapter) - topic = Topic.all.merge!(:select => "topics.*, 1 as is_test").first + topic = Topic.all.merge!(select: "topics.*, 1 as is_test").first else - topic = Topic.all.merge!(:select => "topics.*, 2=2 as is_test").first + topic = Topic.all.merge!(select: "topics.*, 2=2 as is_test").first end assert topic.is_test? end - def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model + test "raises ActiveRecord::DangerousAttributeError when defining an AR method in a model" do %w(save create_or_update).each do |method| - klass = Class.new ActiveRecord::Base + klass = Class.new(ActiveRecord::Base) klass.class_eval "def #{method}() 'defined #{method}' end" assert_raise ActiveRecord::DangerousAttributeError do klass.instance_method_already_implemented?(method) @@ -531,7 +551,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_converted_values_are_returned_after_assignment + test "converted values are returned after assignment" do developer = Developer.new(name: 1337, salary: "50000") assert_equal "50000", developer.salary_before_type_cast @@ -546,7 +566,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "1337", developer.name end - def test_write_nil_to_time_attributes + test "write nil to time attribute" do in_time_zone "Pacific Time (US & Canada)" do record = @target.new record.written_on = nil @@ -554,7 +574,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_write_time_to_date_attributes + test "write time to date attribute" do in_time_zone "Pacific Time (US & Canada)" do record = @target.new record.last_read = Time.utc(2010, 1, 1, 10) @@ -562,7 +582,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_time_attributes_are_retrieved_in_current_time_zone + test "time attributes are retrieved in the current time zone" do in_time_zone "Pacific Time (US & Canada)" do utc_time = Time.utc(2008, 1, 1) record = @target.new @@ -574,7 +594,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_setting_time_zone_aware_attribute_to_utc + test "setting a time zone-aware attribute to UTC" do in_time_zone "Pacific Time (US & Canada)" do utc_time = Time.utc(2008, 1, 1) record = @target.new @@ -585,7 +605,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_setting_time_zone_aware_attribute_in_other_time_zone + test "setting time zone-aware attribute in other time zone" do utc_time = Time.utc(2008, 1, 1) cst_time = utc_time.in_time_zone("Central Time (US & Canada)") in_time_zone "Pacific Time (US & Canada)" do @@ -597,18 +617,18 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_setting_time_zone_aware_read_attribute + test "setting time zone-aware read attribute" do utc_time = Time.utc(2008, 1, 1) cst_time = utc_time.in_time_zone("Central Time (US & Canada)") in_time_zone "Pacific Time (US & Canada)" do - record = @target.create(:written_on => cst_time).reload + record = @target.create(written_on: cst_time).reload assert_equal utc_time, record[:written_on] assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time end end - def test_setting_time_zone_aware_attribute_with_string + test "setting time zone-aware attribute with a string" do utc_time = Time.utc(2008, 1, 1) (-11..13).each do |timezone_offset| time_string = utc_time.in_time_zone(timezone_offset).to_s @@ -622,27 +642,27 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_time_zone_aware_attribute_saved + test "time zone-aware attribute saved" do in_time_zone 1 do - record = @target.create(:written_on => '2012-02-20 10:00') + record = @target.create(written_on: "2012-02-20 10:00") - record.written_on = '2012-02-20 09:00' + record.written_on = "2012-02-20 09:00" record.save assert_equal Time.zone.local(2012, 02, 20, 9), record.reload.written_on end end - def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil + test "setting a time zone-aware attribute to a blank string returns nil" do in_time_zone "Pacific Time (US & Canada)" do record = @target.new - record.written_on = ' ' + record.written_on = " " assert_nil record.written_on assert_nil record[:written_on] end end - def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone - time_string = 'Tue Jan 01 00:00:00 2008' + test "setting a time zone-aware attribute interprets time zone-unaware string in time zone" do + time_string = "Tue Jan 01 00:00:00 2008" (-11..13).each do |timezone_offset| in_time_zone timezone_offset do record = @target.new @@ -654,7 +674,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_setting_time_zone_aware_datetime_in_current_time_zone + test "setting a time zone-aware datetime in the current time zone" do utc_time = Time.utc(2008, 1, 1) in_time_zone "Pacific Time (US & Canada)" do record = @target.new @@ -665,7 +685,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_yaml_dumping_record_with_time_zone_aware_attribute + test "YAML dumping a record with time zone-aware attribute" do in_time_zone "Pacific Time (US & Canada)" do record = Topic.new(id: 1) record.written_on = "Jan 01 00:00:00 2014" @@ -673,7 +693,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_setting_time_zone_aware_time_in_current_time_zone + test "setting a time zone-aware time in the current time zone" do in_time_zone "Pacific Time (US & Canada)" do record = @target.new time_string = "10:00:00" @@ -683,12 +703,12 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal expected_time, record.bonus_time assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.bonus_time.time_zone - record.bonus_time = '' + record.bonus_time = "" assert_nil record.bonus_time end end - def test_setting_time_zone_aware_time_with_dst + test "setting a time zone-aware time with DST" do in_time_zone "Pacific Time (US & Canada)" do current_time = Time.zone.local(2014, 06, 15, 10) record = @target.new(bonus_time: current_time) @@ -702,7 +722,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_removing_time_zone_aware_types + test "removing time zone-aware types" do with_time_zone_aware_types(:datetime) do in_time_zone "Pacific Time (US & Canada)" do record = @target.new(bonus_time: "10:00:00") @@ -714,14 +734,14 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_time_zone_aware_attributes_dont_recurse_infinitely_on_invalid_values + test "time zone-aware attributes do not recurse infinitely on invalid values" do in_time_zone "Pacific Time (US & Canada)" do record = @target.new(bonus_time: []) assert_equal nil, record.bonus_time end end - def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable + test "setting a time_zone_conversion_for_attributes should write the value on a class variable" do Topic.skip_time_zone_conversion_for_attributes = [:field_a] Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b] @@ -729,44 +749,44 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes end - def test_read_attributes_respect_access_control + test "attribute readers respect access control" do privatize("title") - topic = @target.new(:title => "The pros and cons of programming naked.") + topic = @target.new(title: "The pros and cons of programming naked.") assert !topic.respond_to?(:title) exception = assert_raise(NoMethodError) { topic.title } - assert exception.message.include?("private method") + assert_includes exception.message, "private method" assert_equal "I'm private", topic.send(:title) end - def test_write_attributes_respect_access_control + test "attribute writers respect access control" do privatize("title=(value)") topic = @target.new assert !topic.respond_to?(:title=) - exception = assert_raise(NoMethodError) { topic.title = "Pants"} - assert exception.message.include?("private method") + exception = assert_raise(NoMethodError) { topic.title = "Pants" } + assert_includes exception.message, "private method" topic.send(:title=, "Very large pants") end - def test_question_attributes_respect_access_control + test "attribute predicates respect access control" do privatize("title?") - topic = @target.new(:title => "Isaac Newton's pants") + topic = @target.new(title: "Isaac Newton's pants") assert !topic.respond_to?(:title?) exception = assert_raise(NoMethodError) { topic.title? } - assert exception.message.include?("private method") + assert_includes exception.message, "private method" assert topic.send(:title?) end - def test_bulk_update_respects_access_control + test "bulk updates respect access control" do privatize("title=(value)") - assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") } - assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } } + assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(title: "Rants about pants") } + assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { title: "Ants in pants" } } end - def test_bulk_update_raise_unknown_attribute_error + test "bulk update raises ActiveRecord::UnknownAttributeError" do error = assert_raises(ActiveRecord::UnknownAttributeError) { Topic.new(hello: "world") } @@ -775,22 +795,22 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "unknown attribute 'hello' for Topic.", error.message end - def test_methods_override_in_multi_level_subclass + test "method overrides in multi-level subclasses" do klass = Class.new(Developer) do def name "dev:#{read_attribute(:name)}" end end - 2.times { klass = Class.new klass } - dev = klass.new(name: 'arthurnn') + 2.times { klass = Class.new(klass) } + dev = klass.new(name: "arthurnn") dev.save! - assert_equal 'dev:arthurnn', dev.reload.name + assert_equal "dev:arthurnn", dev.reload.name end - def test_global_methods_are_overwritten + test "global methods are overwritten" do klass = Class.new(ActiveRecord::Base) do - self.table_name = 'computers' + self.table_name = "computers" end assert !klass.instance_method_already_implemented?(:system) @@ -798,11 +818,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_nil computer.system end - def test_global_methods_are_overwritten_when_subclassing - klass = Class.new(ActiveRecord::Base) { self.abstract_class = true } + test "global methods are overwritten when subclassing" do + klass = Class.new(ActiveRecord::Base) do + self.abstract_class = true + end subklass = Class.new(klass) do - self.table_name = 'computers' + self.table_name = "computers" end assert !klass.instance_method_already_implemented?(:system) @@ -811,7 +833,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_nil computer.system end - def test_instance_method_should_be_defined_on_the_base_class + test "instance methods should be defined on the base class" do subklass = Class.new(Topic) Topic.define_attribute_methods @@ -827,14 +849,14 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert subklass.method_defined?(:id), "subklass is missing id method" end - def test_read_attribute_with_nil_should_not_asplode - assert_equal nil, Topic.new.read_attribute(nil) + test "read_attribute with nil should not asplode" do + assert_nil Topic.new.read_attribute(nil) end # If B < A, and A defines an accessor for 'foo', we don't want to override # that by defining a 'foo' method in the generated methods module for B. # (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].) - def test_inherited_custom_accessors + test "inherited custom accessors" do klass = new_topic_like_ar_class do self.abstract_class = true def title; "omg"; end @@ -850,9 +872,9 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "lol", topic.author_name end - def test_inherited_custom_accessors_with_reserved_names + test "inherited custom accessors with reserved names" do klass = Class.new(ActiveRecord::Base) do - self.table_name = 'computers' + self.table_name = "computers" self.abstract_class = true def system; "omg"; end def system=(val); self.developer = val; end @@ -868,18 +890,18 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal 99, computer.developer end - def test_on_the_fly_super_invokable_generated_attribute_methods_via_method_missing + test "on_the_fly_super_invokable_generated_attribute_methods_via_method_missing" do klass = new_topic_like_ar_class do def title - super + '!' + super + "!" end end real_topic = topics(:first) - assert_equal real_topic.title + '!', klass.find(real_topic.id).title + assert_equal real_topic.title + "!", klass.find(real_topic.id).title end - def test_on_the_fly_super_invokable_generated_predicate_attribute_methods_via_method_missing + test "on-the-fly super-invokable generated attribute predicates via method_missing" do klass = new_topic_like_ar_class do def title? !super @@ -890,7 +912,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal !real_topic.title?, klass.find(real_topic.id).title? end - def test_calling_super_when_parent_does_not_define_method_raises_error + test "calling super when the parent does not define method raises NoMethodError" do klass = new_topic_like_ar_class do def some_method_that_is_not_on_super super @@ -902,38 +924,38 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end - def test_attribute_method? + test "attribute_method?" do assert @target.attribute_method?(:title) assert @target.attribute_method?(:title=) assert_not @target.attribute_method?(:wibble) end - def test_attribute_method_returns_false_if_table_does_not_exist - @target.table_name = 'wibble' + test "attribute_method? returns false if the table does not exist" do + @target.table_name = "wibble" assert_not @target.attribute_method?(:title) end - def test_attribute_names_on_new_record + test "attribute_names on a new record" do model = @target.new assert_equal @target.column_names, model.attribute_names end - def test_attribute_names_on_queried_record + test "attribute_names on a queried record" do model = @target.last! assert_equal @target.column_names, model.attribute_names end - def test_attribute_names_with_custom_select - model = @target.select('id').last! + test "attribute_names with a custom select" do + model = @target.select("id").last! - assert_equal ['id'], model.attribute_names - # Sanity check, make sure other columns exist - assert_not_equal ['id'], @target.column_names + assert_equal ["id"], model.attribute_names + # Sanity check, make sure other columns exist. + assert_not_equal ["id"], @target.column_names end - def test_came_from_user + test "came_from_user?" do model = @target.first assert_not model.id_came_from_user? @@ -941,7 +963,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert model.id_came_from_user? end - def test_accessed_fields + test "accessed_fields" do model = @target.first assert_equal [], model.accessed_fields @@ -953,38 +975,38 @@ class AttributeMethodsTest < ActiveRecord::TestCase private - def new_topic_like_ar_class(&block) - klass = Class.new(ActiveRecord::Base) do - self.table_name = 'topics' - class_eval(&block) - end + def new_topic_like_ar_class(&block) + klass = Class.new(ActiveRecord::Base) do + self.table_name = "topics" + class_eval(&block) + end - assert_empty klass.generated_attribute_methods.instance_methods(false) - klass - end + assert_empty klass.generated_attribute_methods.instance_methods(false) + klass + end - def with_time_zone_aware_types(*types) - old_types = ActiveRecord::Base.time_zone_aware_types - ActiveRecord::Base.time_zone_aware_types = types - yield - ensure - ActiveRecord::Base.time_zone_aware_types = old_types - end + def with_time_zone_aware_types(*types) + old_types = ActiveRecord::Base.time_zone_aware_types + ActiveRecord::Base.time_zone_aware_types = types + yield + ensure + ActiveRecord::Base.time_zone_aware_types = old_types + end - def cached_columns - Topic.columns.map(&:name) - end + def cached_columns + Topic.columns.map(&:name) + end - def time_related_columns_on_topic - Topic.columns.select { |c| [:time, :date, :datetime, :timestamp].include?(c.type) } - end + def time_related_columns_on_topic + Topic.columns.select { |c| [:time, :date, :datetime, :timestamp].include?(c.type) } + end - def privatize(method_signature) - @target.class_eval(<<-private_method, __FILE__, __LINE__ + 1) - private - def #{method_signature} - "I'm private" - end - private_method - end + def privatize(method_signature) + @target.class_eval(<<-private_method, __FILE__, __LINE__ + 1) + private + def #{method_signature} + "I'm private" + end + private_method + end end diff --git a/activerecord/test/cases/attribute_set_test.rb b/activerecord/test/cases/attribute_set_test.rb index 7a24b85a36..059b5b2401 100644 --- a/activerecord/test/cases/attribute_set_test.rb +++ b/activerecord/test/cases/attribute_set_test.rb @@ -1,10 +1,10 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class AttributeSetTest < ActiveRecord::TestCase test "building a new set from raw attributes" do builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) - attributes = builder.build_from_database(foo: '1.1', bar: '2.2') + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") assert_equal 1, attributes[:foo].value assert_equal 2.2, attributes[:bar].value @@ -14,7 +14,7 @@ module ActiveRecord test "building with custom types" do builder = AttributeSet::Builder.new(foo: Type::Float.new) - attributes = builder.build_from_database({ foo: '3.3', bar: '4.4' }, { bar: Type::Integer.new }) + attributes = builder.build_from_database({ foo: "3.3", bar: "4.4" }, bar: Type::Integer.new) assert_equal 3.3, attributes[:foo].value assert_equal 4, attributes[:bar].value @@ -22,16 +22,16 @@ module ActiveRecord test "[] returns a null object" do builder = AttributeSet::Builder.new(foo: Type::Float.new) - attributes = builder.build_from_database(foo: '3.3') + attributes = builder.build_from_database(foo: "3.3") - assert_equal '3.3', attributes[:foo].value_before_type_cast + assert_equal "3.3", attributes[:foo].value_before_type_cast assert_equal nil, attributes[:bar].value_before_type_cast assert_equal :bar, attributes[:bar].name end test "duping creates a new hash, but does not dup the attributes" do builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::String.new) - attributes = builder.build_from_database(foo: 1, bar: 'foo') + attributes = builder.build_from_database(foo: 1, bar: "foo") # Ensure the type cast value is cached attributes[:foo].value @@ -39,17 +39,17 @@ module ActiveRecord duped = attributes.dup duped.write_from_database(:foo, 2) - duped[:bar].value << 'bar' + duped[:bar].value << "bar" assert_equal 1, attributes[:foo].value assert_equal 2, duped[:foo].value - assert_equal 'foobar', attributes[:bar].value - assert_equal 'foobar', duped[:bar].value + assert_equal "foobar", attributes[:bar].value + assert_equal "foobar", duped[:bar].value end test "deep_duping creates a new hash and dups each attribute" do builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::String.new) - attributes = builder.build_from_database(foo: 1, bar: 'foo') + attributes = builder.build_from_database(foo: 1, bar: "foo") # Ensure the type cast value is cached attributes[:foo].value @@ -57,12 +57,12 @@ module ActiveRecord duped = attributes.deep_dup duped.write_from_database(:foo, 2) - duped[:bar].value << 'bar' + duped[:bar].value << "bar" assert_equal 1, attributes[:foo].value assert_equal 2, duped[:foo].value - assert_equal 'foo', attributes[:bar].value - assert_equal 'foobar', duped[:bar].value + assert_equal "foo", attributes[:bar].value + assert_equal "foobar", duped[:bar].value end test "freezing cloned set does not freeze original" do @@ -77,7 +77,7 @@ module ActiveRecord test "to_hash returns a hash of the type cast values" do builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) - attributes = builder.build_from_database(foo: '1.1', bar: '2.2') + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") assert_equal({ foo: 1, bar: 2.2 }, attributes.to_hash) assert_equal({ foo: 1, bar: 2.2 }, attributes.to_h) @@ -85,7 +85,7 @@ module ActiveRecord test "to_hash maintains order" do builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) - attributes = builder.build_from_database(foo: '2.2', bar: '3.3') + attributes = builder.build_from_database(foo: "2.2", bar: "3.3") attributes[:bar] hash = attributes.to_h @@ -95,9 +95,9 @@ module ActiveRecord test "values_before_type_cast" do builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Integer.new) - attributes = builder.build_from_database(foo: '1.1', bar: '2.2') + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") - assert_equal({ foo: '1.1', bar: '2.2' }, attributes.values_before_type_cast) + assert_equal({ foo: "1.1", bar: "2.2" }, attributes.values_before_type_cast) end test "known columns are built with uninitialized attributes" do @@ -129,7 +129,7 @@ module ActiveRecord test "fetch_value returns the value for the given initialized attribute" do builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) - attributes = builder.build_from_database(foo: '1.1', bar: '2.2') + attributes = builder.build_from_database(foo: "1.1", bar: "2.2") assert_equal 1, attributes.fetch_value(:foo) assert_equal 2.2, attributes.fetch_value(:bar) @@ -150,8 +150,8 @@ module ActiveRecord test "fetch_value uses the given block for uninitialized attributes" do attributes = attributes_with_uninitialized_key - value = attributes.fetch_value(:bar) { |n| n.to_s + '!' } - assert_equal 'bar!', value + value = attributes.fetch_value(:bar) { |n| n.to_s + "!" } + assert_equal "bar!", value end test "fetch_value returns nil for uninitialized attributes if no block is given" do @@ -207,7 +207,7 @@ module ActiveRecord def attributes_with_uninitialized_key builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new) - builder.build_from_database(foo: '1.1') + builder.build_from_database(foo: "1.1") end test "freezing doesn't prevent the set from materializing" do diff --git a/activerecord/test/cases/attribute_test.rb b/activerecord/test/cases/attribute_test.rb index b1b8639696..7cf6b498c9 100644 --- a/activerecord/test/cases/attribute_test.rb +++ b/activerecord/test/cases/attribute_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class AttributeTest < ActiveRecord::TestCase @@ -11,91 +11,91 @@ module ActiveRecord end test "from_database + read type casts from database" do - @type.expect(:deserialize, 'type cast from database', ['a value']) - attribute = Attribute.from_database(nil, 'a value', @type) + @type.expect(:deserialize, "type cast from database", ["a value"]) + attribute = Attribute.from_database(nil, "a value", @type) type_cast_value = attribute.value - assert_equal 'type cast from database', type_cast_value + assert_equal "type cast from database", type_cast_value end test "from_user + read type casts from user" do - @type.expect(:cast, 'type cast from user', ['a value']) - attribute = Attribute.from_user(nil, 'a value', @type) + @type.expect(:cast, "type cast from user", ["a value"]) + attribute = Attribute.from_user(nil, "a value", @type) type_cast_value = attribute.value - assert_equal 'type cast from user', type_cast_value + assert_equal "type cast from user", type_cast_value end test "reading memoizes the value" do - @type.expect(:deserialize, 'from the database', ['whatever']) - attribute = Attribute.from_database(nil, 'whatever', @type) + @type.expect(:deserialize, "from the database", ["whatever"]) + attribute = Attribute.from_database(nil, "whatever", @type) type_cast_value = attribute.value second_read = attribute.value - assert_equal 'from the database', type_cast_value + assert_equal "from the database", type_cast_value assert_same type_cast_value, second_read end test "reading memoizes falsy values" do - @type.expect(:deserialize, false, ['whatever']) - attribute = Attribute.from_database(nil, 'whatever', @type) + @type.expect(:deserialize, false, ["whatever"]) + attribute = Attribute.from_database(nil, "whatever", @type) attribute.value attribute.value end test "read_before_typecast returns the given value" do - attribute = Attribute.from_database(nil, 'raw value', @type) + attribute = Attribute.from_database(nil, "raw value", @type) raw_value = attribute.value_before_type_cast - assert_equal 'raw value', raw_value + assert_equal "raw value", raw_value end test "from_database + read_for_database type casts to and from database" do - @type.expect(:deserialize, 'read from database', ['whatever']) - @type.expect(:serialize, 'ready for database', ['read from database']) - attribute = Attribute.from_database(nil, 'whatever', @type) + @type.expect(:deserialize, "read from database", ["whatever"]) + @type.expect(:serialize, "ready for database", ["read from database"]) + attribute = Attribute.from_database(nil, "whatever", @type) serialize = attribute.value_for_database - assert_equal 'ready for database', serialize + assert_equal "ready for database", serialize end test "from_user + read_for_database type casts from the user to the database" do - @type.expect(:cast, 'read from user', ['whatever']) - @type.expect(:serialize, 'ready for database', ['read from user']) - attribute = Attribute.from_user(nil, 'whatever', @type) + @type.expect(:cast, "read from user", ["whatever"]) + @type.expect(:serialize, "ready for database", ["read from user"]) + attribute = Attribute.from_user(nil, "whatever", @type) serialize = attribute.value_for_database - assert_equal 'ready for database', serialize + assert_equal "ready for database", serialize end test "duping dups the value" do - @type.expect(:deserialize, 'type cast', ['a value']) - attribute = Attribute.from_database(nil, 'a value', @type) + @type.expect(:deserialize, "type cast", ["a value"]) + attribute = Attribute.from_database(nil, "a value", @type) value_from_orig = attribute.value value_from_clone = attribute.dup.value - value_from_orig << ' foo' + value_from_orig << " foo" - assert_equal 'type cast foo', value_from_orig - assert_equal 'type cast', value_from_clone + assert_equal "type cast foo", value_from_orig + assert_equal "type cast", value_from_clone end test "duping does not dup the value if it is not dupable" do - @type.expect(:deserialize, false, ['a value']) - attribute = Attribute.from_database(nil, 'a value', @type) + @type.expect(:deserialize, false, ["a value"]) + attribute = Attribute.from_database(nil, "a value", @type) assert_same attribute.value, attribute.dup.value end test "duping does not eagerly type cast if we have not yet type cast" do - attribute = Attribute.from_database(nil, 'a value', @type) + attribute = Attribute.from_database(nil, "a value", @type) attribute.dup end diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb index 7bcaa53aa2..f4620ae2da 100644 --- a/activerecord/test/cases/attributes_test.rb +++ b/activerecord/test/cases/attributes_test.rb @@ -1,10 +1,10 @@ -require 'cases/helper' +require "cases/helper" class OverloadedType < ActiveRecord::Base attribute :overloaded_float, :integer attribute :overloaded_string_with_limit, :string, limit: 50 attribute :non_existent_decimal, :decimal - attribute :string_with_default, :string, default: 'the overloaded default' + attribute :string_with_default, :string, default: "the overloaded default" end class ChildOfOverloadedType < OverloadedType @@ -15,7 +15,7 @@ class GrandchildOfOverloadedType < ChildOfOverloadedType end class UnoverloadedType < ActiveRecord::Base - self.table_name = 'overloaded_types' + self.table_name = "overloaded_types" end module ActiveRecord @@ -44,14 +44,14 @@ module ActiveRecord end test "properties assigned in constructor" do - data = OverloadedType.new(overloaded_float: '3.3') + data = OverloadedType.new(overloaded_float: "3.3") assert_equal 3, data.overloaded_float end test "overloaded properties with limit" do - assert_equal 50, OverloadedType.type_for_attribute('overloaded_string_with_limit').limit - assert_equal 255, UnoverloadedType.type_for_attribute('overloaded_string_with_limit').limit + assert_equal 50, OverloadedType.type_for_attribute("overloaded_string_with_limit").limit + assert_equal 255, UnoverloadedType.type_for_attribute("overloaded_string_with_limit").limit end test "nonexistent attribute" do @@ -65,7 +65,7 @@ module ActiveRecord test "model with nonexistent attribute with default value can be saved" do klass = Class.new(OverloadedType) do - attribute :non_existent_string_with_default, :string, default: 'nonexistent' + attribute :non_existent_string_with_default, :string, default: "nonexistent" end model = klass.new @@ -76,22 +76,22 @@ module ActiveRecord data = OverloadedType.new unoverloaded_data = UnoverloadedType.new - assert_equal 'the overloaded default', data.string_with_default - assert_equal 'the original default', unoverloaded_data.string_with_default + assert_equal "the overloaded default", data.string_with_default + assert_equal "the original default", unoverloaded_data.string_with_default end test "defaults are not touched on the columns" do - assert_equal 'the original default', OverloadedType.columns_hash['string_with_default'].default + assert_equal "the original default", OverloadedType.columns_hash["string_with_default"].default end test "children inherit custom properties" do - data = ChildOfOverloadedType.new(overloaded_float: '4.4') + data = ChildOfOverloadedType.new(overloaded_float: "4.4") assert_equal 4, data.overloaded_float end test "children can override parents" do - data = GrandchildOfOverloadedType.new(overloaded_float: '4.4') + data = GrandchildOfOverloadedType.new(overloaded_float: "4.4") assert_equal 4.4, data.overloaded_float end @@ -106,13 +106,13 @@ module ActiveRecord assert_equal 6, klass.attribute_types.length assert_equal 6, klass.column_defaults.length - assert_not klass.attribute_types.include?('wibble') + assert_not klass.attribute_types.include?("wibble") klass.attribute :wibble, Type::Value.new assert_equal 7, klass.attribute_types.length assert_equal 7, klass.column_defaults.length - assert klass.attribute_types.include?('wibble') + assert_includes klass.attribute_types, "wibble" end test "the given default value is cast from user" do @@ -205,5 +205,55 @@ module ActiveRecord assert_equal(:bar, child.new(foo: :bar).foo) end + + test "attributes not backed by database columns are not dirty when unchanged" do + refute OverloadedType.new.non_existent_decimal_changed? + end + + test "attributes not backed by database columns are always initialized" do + OverloadedType.create! + model = OverloadedType.first + + assert_nil model.non_existent_decimal + model.non_existent_decimal = "123" + assert_equal 123, model.non_existent_decimal + end + + test "attributes not backed by database columns return the default on models loaded from database" do + child = Class.new(OverloadedType) do + attribute :non_existent_decimal, :decimal, default: 123 + end + child.create! + model = child.first + + assert_equal 123, model.non_existent_decimal + end + + test "attributes not backed by database columns properly interact with mutation and dirty" do + child = Class.new(ActiveRecord::Base) do + self.table_name = "topics" + attribute :foo, :string, default: "lol" + end + child.create! + model = child.first + + assert_equal "lol", model.foo + + model.foo << "asdf" + assert_equal "lolasdf", model.foo + assert model.foo_changed? + + model.reload + assert_equal "lol", model.foo + + model.foo = "lol" + refute model.changed? + end + + test "attributes not backed by database columns appear in inspect" do + inspection = OverloadedType.new.inspect + + assert_includes inspection, "non_existent_decimal" + end end end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 9e3266b7d6..c24d7b8835 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -1,55 +1,55 @@ -require 'cases/helper' -require 'models/bird' -require 'models/comment' -require 'models/company' -require 'models/customer' -require 'models/developer' -require 'models/computer' -require 'models/invoice' -require 'models/line_item' -require 'models/order' -require 'models/parrot' -require 'models/person' -require 'models/pirate' -require 'models/post' -require 'models/reader' -require 'models/ship' -require 'models/ship_part' -require 'models/tag' -require 'models/tagging' -require 'models/treasure' -require 'models/eye' -require 'models/electron' -require 'models/molecule' -require 'models/member' -require 'models/member_detail' -require 'models/organization' -require 'models/guitar' -require 'models/tuning_peg' +require "cases/helper" +require "models/bird" +require "models/post" +require "models/comment" +require "models/company" +require "models/customer" +require "models/developer" +require "models/computer" +require "models/invoice" +require "models/line_item" +require "models/order" +require "models/parrot" +require "models/person" +require "models/pirate" +require "models/reader" +require "models/ship" +require "models/ship_part" +require "models/tag" +require "models/tagging" +require "models/treasure" +require "models/eye" +require "models/electron" +require "models/molecule" +require "models/member" +require "models/member_detail" +require "models/organization" +require "models/guitar" +require "models/tuning_peg" class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase def test_autosave_validation person = Class.new(ActiveRecord::Base) { - self.table_name = 'people' - validate :should_be_cool, :on => :create - def self.name; 'Person'; end + self.table_name = "people" + validate :should_be_cool, on: :create + def self.name; "Person"; end private def should_be_cool - unless self.first_name == 'cool' + unless self.first_name == "cool" errors.add :first_name, "not cool" end end } reference = Class.new(ActiveRecord::Base) { self.table_name = "references" - def self.name; 'Reference'; end + def self.name; "Reference"; end belongs_to :person, autosave: true, anonymous_class: person } - u = person.create!(first_name: 'cool') - u.update_attributes!(first_name: 'nah') # still valid because validation only applies on 'create' + u = person.create!(first_name: "cool") + u.update_attributes!(first_name: "nah") # still valid because validation only applies on 'create' assert reference.create!(person: u).persisted? end @@ -79,25 +79,25 @@ class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase private - def assert_no_difference_when_adding_callbacks_twice_for(model, association_name) - reflection = model.reflect_on_association(association_name) - assert_no_difference "callbacks_for_model(#{model.name}).length" do - model.send(:add_autosave_association_callbacks, reflection) + def assert_no_difference_when_adding_callbacks_twice_for(model, association_name) + reflection = model.reflect_on_association(association_name) + assert_no_difference "callbacks_for_model(#{model.name}).length" do + model.send(:add_autosave_association_callbacks, reflection) + end end - end - def callbacks_for_model(model) - model.instance_variables.grep(/_callbacks$/).flat_map do |ivar| - model.instance_variable_get(ivar) + def callbacks_for_model(model) + model.instance_variables.grep(/_callbacks$/).flat_map do |ivar| + model.instance_variable_get(ivar) + end end - end end class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase fixtures :companies, :accounts def test_should_save_parent_but_not_invalid_child - firm = Firm.new(:name => 'GlobalMegaCorp') + firm = Firm.new(name: "GlobalMegaCorp") assert firm.valid? firm.build_account_using_primary_key @@ -178,8 +178,8 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas end def test_not_resaved_when_unchanged - firm = Firm.all.merge!(:includes => :account).first - firm.name += '-changed' + firm = Firm.all.merge!(includes: :account).first + firm.name += "-changed" assert_queries(1) { firm.save! } firm = Firm.first @@ -196,21 +196,21 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas end def test_callbacks_firing_order_on_create - eye = Eye.create(:iris_attributes => {:color => 'honey'}) + eye = Eye.create(iris_attributes: { color: "honey" }) assert_equal [true, false], eye.after_create_callbacks_stack end def test_callbacks_firing_order_on_update - eye = Eye.create(iris_attributes: {color: 'honey'}) - eye.update(iris_attributes: {color: 'green'}) + eye = Eye.create(iris_attributes: { color: "honey" }) + eye.update(iris_attributes: { color: "green" }) assert_equal [true, false], eye.after_update_callbacks_stack end def test_callbacks_firing_order_on_save - eye = Eye.create(iris_attributes: {color: 'honey'}) + eye = Eye.create(iris_attributes: { color: "honey" }) assert_equal [false, false], eye.after_save_callbacks_stack - eye.update(iris_attributes: {color: 'blue'}) + eye.update(iris_attributes: { color: "blue" }) assert_equal [false, false, false, false], eye.after_save_callbacks_stack end end @@ -219,7 +219,7 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test fixtures :companies, :posts, :tags, :taggings def test_should_save_parent_but_not_invalid_child - client = Client.new(:name => 'Joe (the Plumber)') + client = Client.new(name: "Joe (the Plumber)") assert client.valid? client.build_firm @@ -231,7 +231,7 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test def test_save_fails_for_invalid_belongs_to # Oracle saves empty string as NULL therefore :message changed to one space - assert log = AuditLog.create(:developer_id => 0, :message => " ") + assert log = AuditLog.create(developer_id: 0, message: " ") log.developer = Developer.new assert !log.developer.valid? @@ -242,7 +242,7 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test def test_save_succeeds_for_invalid_belongs_to_with_validate_false # Oracle saves empty string as NULL therefore :message changed to one space - assert log = AuditLog.create(:developer_id => 0, :message=> " ") + assert log = AuditLog.create(developer_id: 0, message: " ") log.unvalidated_developer = Developer.new assert !log.unvalidated_developer.valid? @@ -362,22 +362,22 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test def test_store_association_with_a_polymorphic_relationship num_tagging = Tagging.count - tags(:misc).create_tagging(:taggable => posts(:thinking)) + tags(:misc).create_tagging(taggable: posts(:thinking)) assert_equal num_tagging + 1, Tagging.count end def test_build_and_then_save_parent_should_not_reload_target client = Client.first - apple = client.build_firm(:name => "Apple") + apple = client.build_firm(name: "Apple") client.save! assert_no_queries { assert_equal apple, client.firm } end def test_validation_does_not_validate_stale_association_target - valid_developer = Developer.create!(:name => "Dude", :salary => 50_000) + valid_developer = Developer.create!(name: "Dude", salary: 50_000) invalid_developer = Developer.new() - auditlog = AuditLog.new(:message => "foo") + auditlog = AuditLog.new(message: "foo") auditlog.developer = invalid_developer auditlog.developer_id = valid_developer.id @@ -388,7 +388,7 @@ end class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttributes < ActiveRecord::TestCase def test_invalid_adding_with_nested_attributes molecule = Molecule.new - valid_electron = Electron.new(name: 'electron') + valid_electron = Electron.new(name: "electron") invalid_electron = Electron.new molecule.electrons = [valid_electron, invalid_electron] @@ -396,7 +396,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib assert_not invalid_electron.valid? assert valid_electron.valid? - assert_not molecule.persisted?, 'Molecule should not be persisted when its electrons are invalid' + assert_not molecule.persisted?, "Molecule should not be persisted when its electrons are invalid" end def test_errors_should_be_indexed_when_passed_as_array @@ -419,7 +419,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib ActiveRecord::Base.index_nested_attribute_errors = true molecule = Molecule.new - valid_electron = Electron.new(name: 'electron') + valid_electron = Electron.new(name: "electron") invalid_electron = Electron.new molecule.electrons = [valid_electron, invalid_electron] @@ -435,7 +435,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib def test_errors_details_should_be_set molecule = Molecule.new - valid_electron = Electron.new(name: 'electron') + valid_electron = Electron.new(name: "electron") invalid_electron = Electron.new molecule.electrons = [valid_electron, invalid_electron] @@ -443,7 +443,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib assert_not invalid_electron.valid? assert valid_electron.valid? assert_not molecule.valid? - assert_equal [{error: :blank}], molecule.errors.details["electrons.name"] + assert_equal [{ error: :blank }], molecule.errors.details[:"electrons.name"] end def test_errors_details_should_be_indexed_when_passed_as_array @@ -457,8 +457,8 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib assert_not tuning_peg_invalid.valid? assert tuning_peg_valid.valid? assert_not guitar.valid? - assert_equal [{error: :not_a_number, value: nil}] , guitar.errors.details["tuning_pegs[1].pitch"] - assert_equal [], guitar.errors.details["tuning_pegs.pitch"] + assert_equal [{ error: :not_a_number, value: nil }], guitar.errors.details[:"tuning_pegs[1].pitch"] + assert_equal [], guitar.errors.details[:"tuning_pegs.pitch"] end def test_errors_details_should_be_indexed_when_global_flag_is_set @@ -466,7 +466,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib ActiveRecord::Base.index_nested_attribute_errors = true molecule = Molecule.new - valid_electron = Electron.new(name: 'electron') + valid_electron = Electron.new(name: "electron") invalid_electron = Electron.new molecule.electrons = [valid_electron, invalid_electron] @@ -474,15 +474,15 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttrib assert_not invalid_electron.valid? assert valid_electron.valid? assert_not molecule.valid? - assert_equal [{error: :blank}], molecule.errors.details["electrons[1].name"] - assert_equal [], molecule.errors.details["electrons.name"] + assert_equal [{ error: :blank }], molecule.errors.details[:"electrons[1].name"] + assert_equal [], molecule.errors.details[:"electrons.name"] ensure ActiveRecord::Base.index_nested_attribute_errors = old_attribute_config end def test_valid_adding_with_nested_attributes molecule = Molecule.new - valid_electron = Electron.new(name: 'electron') + valid_electron = Electron.new(name: "electron") molecule.electrons = [valid_electron] molecule.save @@ -585,16 +585,16 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa firm.save firm.reload assert_equal 2, firm.clients.length - assert firm.clients.include?(companies(:second_client)) + assert_includes firm.clients, companies(:second_client) end def test_assign_ids_for_through_a_belongs_to - post = Post.new(:title => "Assigning IDs works!", :body => "You heard it here first, folks!") + post = Post.new(title: "Assigning IDs works!", body: "You heard it here first, folks!") post.person_ids = [people(:david).id, people(:michael).id] post.save post.reload assert_equal 2, post.people.length - assert post.people.include?(people(:david)) + assert_includes post.people, people(:david) end def test_build_before_save @@ -602,7 +602,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build("name" => "Another Client") } assert !company.clients_of_firm.loaded? - company.name += '-changed' + company.name += "-changed" assert_queries(2) { assert company.save } assert new_client.persisted? assert_equal 3, company.clients_of_firm.reload.size @@ -610,19 +610,19 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_many_before_save company = companies(:first_firm) - assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } + assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) } - company.name += '-changed' + company.name += "-changed" assert_queries(3) { assert company.save } assert_equal 4, company.clients_of_firm.reload.size end def test_build_via_block_before_save company = companies(:first_firm) - new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build { |client| client.name = "Another Client" } } assert !company.clients_of_firm.loaded? - company.name += '-changed' + company.name += "-changed" assert_queries(2) { assert company.save } assert new_client.persisted? assert_equal 3, company.clients_of_firm.reload.size @@ -631,12 +631,12 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_many_via_block_before_save company = companies(:first_firm) assert_no_queries(ignore_none: false) do - company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| + company.clients_of_firm.build([{ "name" => "Another Client" }, { "name" => "Another Client II" }]) do |client| client.name = "changed" end end - company.name += '-changed' + company.name += "-changed" assert_queries(3) { assert company.save } assert_equal 4, company.clients_of_firm.reload.size end @@ -647,7 +647,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert firm.save firm.reload assert_equal 2, firm.clients.length - assert firm.clients.include?(Client.find_by_name("New Client")) + assert_includes firm.clients, Client.find_by_name("New Client") end end @@ -715,8 +715,8 @@ class TestDefaultAutosaveAssociationOnNewRecord < ActiveRecord::TestCase end def test_autosave_new_record_with_after_create_callback - post = PostWithAfterCreateCallback.new(title: 'Captain Murphy', body: 'is back') - post.comments.build(body: 'foo') + post = PostWithAfterCreateCallback.new(title: "Captain Murphy", body: "is back") + post.comments.build(body: "foo") post.save! assert_not_nil post.author_id @@ -727,8 +727,8 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase self.use_transactional_tests = false setup do - @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @ship = @pirate.create_ship(:name => 'Nights Dirty Lightning') + @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") + @ship = @pirate.create_ship(name: "Nights Dirty Lightning") end teardown do @@ -764,12 +764,12 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_skip_validation_on_a_child_association_if_marked_for_destruction - @pirate.ship.name = '' + @pirate.ship.name = "" assert !@pirate.valid? @pirate.ship.mark_for_destruction @pirate.ship.expects(:valid?).never - assert_difference('Ship.count', -1) { @pirate.save! } + assert_difference("Ship.count", -1) { @pirate.save! } end def test_a_child_marked_for_destruction_should_not_be_destroyed_twice @@ -787,7 +787,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase def save(*args) super destroy - raise 'Oh noes!' + raise "Oh noes!" end end @@ -824,12 +824,12 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_skip_validation_on_a_parent_association_if_marked_for_destruction - @ship.pirate.catchphrase = '' + @ship.pirate.catchphrase = "" assert !@ship.valid? @ship.pirate.mark_for_destruction @ship.pirate.expects(:valid?).never - assert_difference('Pirate.count', -1) { @ship.save! } + assert_difference("Pirate.count", -1) { @ship.save! } end def test_a_parent_marked_for_destruction_should_not_be_destroyed_twice @@ -847,7 +847,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase def save(*args) super destroy - raise 'Oh noes!' + raise "Oh noes!" end end @@ -858,16 +858,16 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_save_changed_child_objects_if_parent_is_saved - @pirate = @ship.create_pirate(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @parrot = @pirate.parrots.create!(:name => 'Posideons Killer') + @pirate = @ship.create_pirate(catchphrase: "Don' botharrr talkin' like one, savvy?") + @parrot = @pirate.parrots.create!(name: "Posideons Killer") @parrot.name = "NewName" @ship.save - assert_equal 'NewName', @parrot.reload.name + assert_equal "NewName", @parrot.reload.name end def test_should_destroy_has_many_as_part_of_the_save_transaction_if_they_were_marked_for_destruction - 2.times { |i| @pirate.birds.create!(:name => "birds_#{i}") } + 2.times { |i| @pirate.birds.create!(name: "birds_#{i}") } assert !@pirate.birds.any?(&:marked_for_destruction?) @@ -891,9 +891,9 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_skip_validation_on_has_many_if_marked_for_destruction - 2.times { |i| @pirate.birds.create!(:name => "birds_#{i}") } + 2.times { |i| @pirate.birds.create!(name: "birds_#{i}") } - @pirate.birds.each { |bird| bird.name = '' } + @pirate.birds.each { |bird| bird.name = "" } assert !@pirate.valid? @pirate.birds.each do |bird| @@ -904,9 +904,9 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_skip_validation_on_has_many_if_destroyed - @pirate.birds.create!(:name => "birds_1") + @pirate.birds.create!(name: "birds_1") - @pirate.birds.each { |bird| bird.name = '' } + @pirate.birds.each { |bird| bird.name = "" } assert !@pirate.valid? @pirate.birds.each(&:destroy) @@ -914,7 +914,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_a_child_marked_for_destruction_should_not_be_destroyed_twice_while_saving_has_many - @pirate.birds.create!(:name => "birds_1") + @pirate.birds.create!(name: "birds_1") @pirate.birds.each(&:mark_for_destruction) assert @pirate.save @@ -924,14 +924,14 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_rollback_destructions_if_an_exception_occurred_while_saving_has_many - 2.times { |i| @pirate.birds.create!(:name => "birds_#{i}") } + 2.times { |i| @pirate.birds.create!(name: "birds_#{i}") } before = @pirate.birds.map { |c| c.mark_for_destruction ; c } # Stub the destroy method of the second child to raise an exception class << before.last def destroy(*args) super - raise 'Oh noes!' + raise "Oh noes!" end end @@ -940,9 +940,9 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_when_new_record_a_child_marked_for_destruction_should_not_affect_other_records_from_saving - @pirate = @ship.build_pirate(:catchphrase => "Arr' now I shall keep me eye on you matey!") # new record + @pirate = @ship.build_pirate(catchphrase: "Arr' now I shall keep me eye on you matey!") # new record - 3.times { |i| @pirate.birds.build(:name => "birds_#{i}") } + 3.times { |i| @pirate.birds.build(name: "birds_#{i}") } @pirate.birds[1].mark_for_destruction @pirate.save! @@ -968,8 +968,8 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase define_method("test_should_run_add_callback_#{callback_type}s_for_has_many") do association_name_with_callbacks = "birds_with_#{callback_type}_callbacks" - pirate = Pirate.new(:catchphrase => "Arr") - pirate.send(association_name_with_callbacks).build(:name => "Crowe the One-Eyed") + pirate = Pirate.new(catchphrase: "Arr") + pirate.send(association_name_with_callbacks).build(name: "Crowe the One-Eyed") expected = [ "before_adding_#{callback_type}_bird_<new>", @@ -982,7 +982,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase define_method("test_should_run_remove_callback_#{callback_type}s_for_has_many") do association_name_with_callbacks = "birds_with_#{callback_type}_callbacks" - @pirate.send(association_name_with_callbacks).create!(:name => "Crowe the One-Eyed") + @pirate.send(association_name_with_callbacks).create!(name: "Crowe the One-Eyed") @pirate.send(association_name_with_callbacks).each(&:mark_for_destruction) child_id = @pirate.send(association_name_with_callbacks).first.id @@ -999,7 +999,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_destroy_habtm_as_part_of_the_save_transaction_if_they_were_marked_for_destruction - 2.times { |i| @pirate.parrots.create!(:name => "parrots_#{i}") } + 2.times { |i| @pirate.parrots.create!(name: "parrots_#{i}") } assert !@pirate.parrots.any?(&:marked_for_destruction?) @pirate.parrots.each(&:mark_for_destruction) @@ -1015,9 +1015,9 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_skip_validation_on_habtm_if_marked_for_destruction - 2.times { |i| @pirate.parrots.create!(:name => "parrots_#{i}") } + 2.times { |i| @pirate.parrots.create!(name: "parrots_#{i}") } - @pirate.parrots.each { |parrot| parrot.name = '' } + @pirate.parrots.each { |parrot| parrot.name = "" } assert !@pirate.valid? @pirate.parrots.each do |parrot| @@ -1030,9 +1030,9 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_skip_validation_on_habtm_if_destroyed - @pirate.parrots.create!(:name => "parrots_1") + @pirate.parrots.create!(name: "parrots_1") - @pirate.parrots.each { |parrot| parrot.name = '' } + @pirate.parrots.each { |parrot| parrot.name = "" } assert !@pirate.valid? @pirate.parrots.each(&:destroy) @@ -1040,7 +1040,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_a_child_marked_for_destruction_should_not_be_destroyed_twice_while_saving_habtm - @pirate.parrots.create!(:name => "parrots_1") + @pirate.parrots.create!(name: "parrots_1") @pirate.parrots.each(&:mark_for_destruction) assert @pirate.save @@ -1053,13 +1053,13 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase end def test_should_rollback_destructions_if_an_exception_occurred_while_saving_habtm - 2.times { |i| @pirate.parrots.create!(:name => "parrots_#{i}") } + 2.times { |i| @pirate.parrots.create!(name: "parrots_#{i}") } before = @pirate.parrots.map { |c| c.mark_for_destruction ; c } class << @pirate.association(:parrots) def destroy(*args) super - raise 'Oh noes!' + raise "Oh noes!" end end @@ -1072,8 +1072,8 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase define_method("test_should_run_add_callback_#{callback_type}s_for_habtm") do association_name_with_callbacks = "parrots_with_#{callback_type}_callbacks" - pirate = Pirate.new(:catchphrase => "Arr") - pirate.send(association_name_with_callbacks).build(:name => "Crowe the One-Eyed") + pirate = Pirate.new(catchphrase: "Arr") + pirate.send(association_name_with_callbacks).build(name: "Crowe the One-Eyed") expected = [ "before_adding_#{callback_type}_parrot_<new>", @@ -1086,7 +1086,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase define_method("test_should_run_remove_callback_#{callback_type}s_for_habtm") do association_name_with_callbacks = "parrots_with_#{callback_type}_callbacks" - @pirate.send(association_name_with_callbacks).create!(:name => "Crowe the One-Eyed") + @pirate.send(association_name_with_callbacks).create!(name: "Crowe the One-Eyed") @pirate.send(association_name_with_callbacks).each(&:mark_for_destruction) child_id = @pirate.send(association_name_with_callbacks).first.id @@ -1108,21 +1108,21 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase def setup super - @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @ship = @pirate.create_ship(:name => 'Nights Dirty Lightning') + @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") + @ship = @pirate.create_ship(name: "Nights Dirty Lightning") end def test_should_still_work_without_an_associated_model @ship.destroy @pirate.reload.catchphrase = "Arr" @pirate.save - assert_equal 'Arr', @pirate.reload.catchphrase + assert_equal "Arr", @pirate.reload.catchphrase end def test_should_automatically_save_the_associated_model - @pirate.ship.name = 'The Vile Insanity' + @pirate.ship.name = "The Vile Insanity" @pirate.save - assert_equal 'The Vile Insanity', @pirate.reload.ship.name + assert_equal "The Vile Insanity", @pirate.reload.ship.name end def test_changed_for_autosave_should_handle_cycles @@ -1136,13 +1136,13 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_automatically_save_bang_the_associated_model - @pirate.ship.name = 'The Vile Insanity' + @pirate.ship.name = "The Vile Insanity" @pirate.save! - assert_equal 'The Vile Insanity', @pirate.reload.ship.name + assert_equal "The Vile Insanity", @pirate.reload.ship.name end def test_should_automatically_validate_the_associated_model - @pirate.ship.name = '' + @pirate.ship.name = "" assert @pirate.invalid? assert @pirate.errors[:"ship.name"].any? end @@ -1158,7 +1158,7 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase def test_should_not_ignore_different_error_messages_on_the_same_attribute old_validators = Ship._validators.deep_dup old_callbacks = Ship._validate_callbacks.deep_dup - Ship.validates_format_of :name, :with => /\w/ + Ship.validates_format_of :name, with: /\w/ @pirate.ship.name = "" @pirate.catchphrase = nil assert @pirate.invalid? @@ -1169,48 +1169,48 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_still_allow_to_bypass_validations_on_the_associated_model - @pirate.catchphrase = '' - @pirate.ship.name = '' - @pirate.save(:validate => false) + @pirate.catchphrase = "" + @pirate.ship.name = "" + @pirate.save(validate: false) # Oracle saves empty string as NULL if current_adapter?(:OracleAdapter) assert_equal [nil, nil], [@pirate.reload.catchphrase, @pirate.ship.name] else - assert_equal ['', ''], [@pirate.reload.catchphrase, @pirate.ship.name] + assert_equal ["", ""], [@pirate.reload.catchphrase, @pirate.ship.name] end end def test_should_allow_to_bypass_validations_on_associated_models_at_any_depth - 2.times { |i| @pirate.ship.parts.create!(:name => "part #{i}") } + 2.times { |i| @pirate.ship.parts.create!(name: "part #{i}") } - @pirate.catchphrase = '' - @pirate.ship.name = '' - @pirate.ship.parts.each { |part| part.name = '' } - @pirate.save(:validate => false) + @pirate.catchphrase = "" + @pirate.ship.name = "" + @pirate.ship.parts.each { |part| part.name = "" } + @pirate.save(validate: false) values = [@pirate.reload.catchphrase, @pirate.ship.name, *@pirate.ship.parts.map(&:name)] # Oracle saves empty string as NULL if current_adapter?(:OracleAdapter) assert_equal [nil, nil, nil, nil], values else - assert_equal ['', '', '', ''], values + assert_equal ["", "", "", ""], values end end def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that - @pirate.ship.name = '' + @pirate.ship.name = "" assert_raise(ActiveRecord::RecordInvalid) do @pirate.save! end end def test_should_not_save_and_return_false_if_a_callback_cancelled_saving - pirate = Pirate.new(:catchphrase => 'Arr') - ship = pirate.build_ship(:name => 'The Vile Insanity') + pirate = Pirate.new(catchphrase: "Arr") + ship = pirate.build_ship(name: "The Vile Insanity") ship.cancel_save_from_callback = true - assert_no_difference 'Pirate.count' do - assert_no_difference 'Ship.count' do + assert_no_difference "Pirate.count" do + assert_no_difference "Ship.count" do assert !pirate.save end end @@ -1219,14 +1219,14 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase def test_should_rollback_any_changes_if_an_exception_occurred_while_saving before = [@pirate.catchphrase, @pirate.ship.name] - @pirate.catchphrase = 'Arr' - @pirate.ship.name = 'The Vile Insanity' + @pirate.catchphrase = "Arr" + @pirate.ship.name = "The Vile Insanity" # Stub the save method of the @pirate.ship instance to raise an exception class << @pirate.ship def save(*args) super - raise 'Oh noes!' + raise "Oh noes!" end end @@ -1235,7 +1235,7 @@ class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_not_load_the_associated_model - assert_queries(1) { @pirate.catchphrase = 'Arr'; @pirate.save! } + assert_queries(1) { @pirate.catchphrase = "Arr"; @pirate.save! } end def test_mark_for_destruction_is_ignored_without_autosave_true @@ -1260,7 +1260,7 @@ class TestAutosaveAssociationOnAHasOneThroughAssociation < ActiveRecord::TestCas class << @member.organization def save(*args) super - raise 'Oh noes!' + raise "Oh noes!" end end assert_nothing_raised { @member.save } @@ -1272,31 +1272,31 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase def setup super - @ship = Ship.create(:name => 'Nights Dirty Lightning') - @pirate = @ship.create_pirate(:catchphrase => "Don' botharrr talkin' like one, savvy?") + @ship = Ship.create(name: "Nights Dirty Lightning") + @pirate = @ship.create_pirate(catchphrase: "Don' botharrr talkin' like one, savvy?") end def test_should_still_work_without_an_associated_model @pirate.destroy @ship.reload.name = "The Vile Insanity" @ship.save - assert_equal 'The Vile Insanity', @ship.reload.name + assert_equal "The Vile Insanity", @ship.reload.name end def test_should_automatically_save_the_associated_model - @ship.pirate.catchphrase = 'Arr' + @ship.pirate.catchphrase = "Arr" @ship.save - assert_equal 'Arr', @ship.reload.pirate.catchphrase + assert_equal "Arr", @ship.reload.pirate.catchphrase end def test_should_automatically_save_bang_the_associated_model - @ship.pirate.catchphrase = 'Arr' + @ship.pirate.catchphrase = "Arr" @ship.save! - assert_equal 'Arr', @ship.reload.pirate.catchphrase + assert_equal "Arr", @ship.reload.pirate.catchphrase end def test_should_automatically_validate_the_associated_model - @ship.pirate.catchphrase = '' + @ship.pirate.catchphrase = "" assert @ship.invalid? assert @ship.errors[:"pirate.catchphrase"].any? end @@ -1310,31 +1310,31 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase end def test_should_still_allow_to_bypass_validations_on_the_associated_model - @ship.pirate.catchphrase = '' - @ship.name = '' - @ship.save(:validate => false) + @ship.pirate.catchphrase = "" + @ship.name = "" + @ship.save(validate: false) # Oracle saves empty string as NULL if current_adapter?(:OracleAdapter) assert_equal [nil, nil], [@ship.reload.name, @ship.pirate.catchphrase] else - assert_equal ['', ''], [@ship.reload.name, @ship.pirate.catchphrase] + assert_equal ["", ""], [@ship.reload.name, @ship.pirate.catchphrase] end end def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that - @ship.pirate.catchphrase = '' + @ship.pirate.catchphrase = "" assert_raise(ActiveRecord::RecordInvalid) do @ship.save! end end def test_should_not_save_and_return_false_if_a_callback_cancelled_saving - ship = Ship.new(:name => 'The Vile Insanity') - pirate = ship.build_pirate(:catchphrase => 'Arr') + ship = Ship.new(name: "The Vile Insanity") + pirate = ship.build_pirate(catchphrase: "Arr") pirate.cancel_save_from_callback = true - assert_no_difference 'Ship.count' do - assert_no_difference 'Pirate.count' do + assert_no_difference "Ship.count" do + assert_no_difference "Pirate.count" do assert !ship.save end end @@ -1343,14 +1343,14 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase def test_should_rollback_any_changes_if_an_exception_occurred_while_saving before = [@ship.pirate.catchphrase, @ship.name] - @ship.pirate.catchphrase = 'Arr' - @ship.name = 'The Vile Insanity' + @ship.pirate.catchphrase = "Arr" + @ship.name = "The Vile Insanity" # Stub the save method of the @ship.pirate instance to raise an exception class << @ship.pirate def save(*args) super - raise 'Oh noes!' + raise "Oh noes!" end end @@ -1359,13 +1359,13 @@ class TestAutosaveAssociationOnABelongsToAssociation < ActiveRecord::TestCase end def test_should_not_load_the_associated_model - assert_queries(1) { @ship.name = 'The Vile Insanity'; @ship.save! } + assert_queries(1) { @ship.name = "The Vile Insanity"; @ship.save! } end end module AutosaveAssociationOnACollectionAssociationTests def test_should_automatically_save_the_associated_models - new_names = ['Grace OMalley', 'Privateers Greed'] + new_names = ["Grace OMalley", "Privateers Greed"] @pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] } @pirate.save @@ -1373,7 +1373,7 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_automatically_save_bang_the_associated_models - new_names = ['Grace OMalley', 'Privateers Greed'] + new_names = ["Grace OMalley", "Privateers Greed"] @pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] } @pirate.save! @@ -1391,7 +1391,7 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_automatically_validate_the_associated_models - @pirate.send(@association_name).each { |child| child.name = '' } + @pirate.send(@association_name).each { |child| child.name = "" } assert !@pirate.valid? assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"] @@ -1399,7 +1399,7 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_not_use_default_invalid_error_on_associated_models - @pirate.send(@association_name).build(:name => '') + @pirate.send(@association_name).build(name: "") assert !@pirate.valid? assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"] @@ -1407,11 +1407,11 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_default_invalid_error_from_i18n - I18n.backend.store_translations(:en, activerecord: {errors: { models: + I18n.backend.store_translations(:en, activerecord: { errors: { models: { @associated_model_name.to_s.to_sym => { blank: "cannot be blank" } } - }}) + } }) - @pirate.send(@association_name).build(name: '') + @pirate.send(@association_name).build(name: "") assert !@pirate.valid? assert_equal ["cannot be blank"], @pirate.errors["#{@association_name}.name"] @@ -1422,7 +1422,7 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it_is_not_valid - @pirate.send(@association_name).each { |child| child.name = '' } + @pirate.send(@association_name).each { |child| child.name = "" } @pirate.catchphrase = nil assert !@pirate.valid? @@ -1431,10 +1431,10 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_allow_to_bypass_validations_on_the_associated_models_on_update - @pirate.catchphrase = '' - @pirate.send(@association_name).each { |child| child.name = '' } + @pirate.catchphrase = "" + @pirate.send(@association_name).each { |child| child.name = "" } - assert @pirate.save(:validate => false) + assert @pirate.save(validate: false) # Oracle saves empty string as NULL if current_adapter?(:OracleAdapter) assert_equal [nil, nil, nil], [ @@ -1443,7 +1443,7 @@ module AutosaveAssociationOnACollectionAssociationTests @pirate.send(@association_name).last.name ] else - assert_equal ['', '', ''], [ + assert_equal ["", "", ""], [ @pirate.reload.catchphrase, @pirate.send(@association_name).first.name, @pirate.send(@association_name).last.name @@ -1461,24 +1461,24 @@ module AutosaveAssociationOnACollectionAssociationTests def test_should_allow_to_bypass_validations_on_the_associated_models_on_create assert_difference("#{ @association_name == :birds ? 'Bird' : 'Parrot' }.count", 2) do 2.times { @pirate.send(@association_name).build } - @pirate.save(:validate => false) + @pirate.save(validate: false) end end def test_should_not_save_and_return_false_if_a_callback_cancelled_saving_in_either_create_or_update - @pirate.catchphrase = 'Changed' - @child_1.name = 'Changed' + @pirate.catchphrase = "Changed" + @child_1.name = "Changed" @child_1.cancel_save_from_callback = true assert !@pirate.save assert_equal "Don' botharrr talkin' like one, savvy?", @pirate.reload.catchphrase assert_equal "Posideons Killer", @child_1.reload.name - new_pirate = Pirate.new(:catchphrase => 'Arr') - new_child = new_pirate.send(@association_name).build(:name => 'Grace OMalley') + new_pirate = Pirate.new(catchphrase: "Arr") + new_child = new_pirate.send(@association_name).build(name: "Grace OMalley") new_child.cancel_save_from_callback = true - assert_no_difference 'Pirate.count' do + assert_no_difference "Pirate.count" do assert_no_difference "#{new_child.class.name}.count" do assert !new_pirate.save end @@ -1487,16 +1487,16 @@ module AutosaveAssociationOnACollectionAssociationTests def test_should_rollback_any_changes_if_an_exception_occurred_while_saving before = [@pirate.catchphrase, *@pirate.send(@association_name).map(&:name)] - new_names = ['Grace OMalley', 'Privateers Greed'] + new_names = ["Grace OMalley", "Privateers Greed"] - @pirate.catchphrase = 'Arr' + @pirate.catchphrase = "Arr" @pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] } # Stub the save method of the first child instance to raise an exception class << @pirate.send(@association_name).first def save(*args) super - raise 'Oh noes!' + raise "Oh noes!" end end @@ -1505,20 +1505,20 @@ module AutosaveAssociationOnACollectionAssociationTests end def test_should_still_raise_an_ActiveRecordRecord_Invalid_exception_if_we_want_that - @pirate.send(@association_name).each { |child| child.name = '' } + @pirate.send(@association_name).each { |child| child.name = "" } assert_raise(ActiveRecord::RecordInvalid) do @pirate.save! end end def test_should_not_load_the_associated_models_if_they_were_not_loaded_yet - assert_queries(1) { @pirate.catchphrase = 'Arr'; @pirate.save! } + assert_queries(1) { @pirate.catchphrase = "Arr"; @pirate.save! } @pirate.send(@association_name).load_target assert_queries(3) do - @pirate.catchphrase = 'Yarr' - new_names = ['Grace OMalley', 'Privateers Greed'] + @pirate.catchphrase = "Yarr" + new_names = ["Grace OMalley", "Privateers Greed"] @pirate.send(@association_name).each_with_index { |child, i| child.name = new_names[i] } @pirate.save! end @@ -1533,9 +1533,9 @@ class TestAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCase @association_name = :birds @associated_model_name = :bird - @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @child_1 = @pirate.birds.create(:name => 'Posideons Killer') - @child_2 = @pirate.birds.create(:name => 'Killer bandita Dionne') + @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") + @child_1 = @pirate.birds.create(name: "Posideons Killer") + @child_2 = @pirate.birds.create(name: "Killer bandita Dionne") end include AutosaveAssociationOnACollectionAssociationTests @@ -1551,8 +1551,8 @@ class TestAutosaveAssociationOnAHasAndBelongsToManyAssociation < ActiveRecord::T @habtm = true @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") - @child_1 = @pirate.parrots.create(name: 'Posideons Killer') - @child_2 = @pirate.parrots.create(name: 'Killer bandita Dionne') + @child_1 = @pirate.parrots.create(name: "Posideons Killer") + @child_2 = @pirate.parrots.create(name: "Killer bandita Dionne") end include AutosaveAssociationOnACollectionAssociationTests @@ -1568,8 +1568,8 @@ class TestAutosaveAssociationOnAHasAndBelongsToManyAssociationWithAcceptsNestedA @habtm = true @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") - @child_1 = @pirate.parrots.create(name: 'Posideons Killer') - @child_2 = @pirate.parrots.create(name: 'Killer bandita Dionne') + @child_1 = @pirate.parrots.create(name: "Posideons Killer") + @child_2 = @pirate.parrots.create(name: "Killer bandita Dionne") end include AutosaveAssociationOnACollectionAssociationTests @@ -1580,13 +1580,13 @@ class TestAutosaveAssociationValidationsOnAHasManyAssociation < ActiveRecord::Te def setup super - @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @pirate.birds.create(:name => 'cookoo') + @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") + @pirate.birds.create(name: "cookoo") end test "should automatically validate associations" do assert @pirate.valid? - @pirate.birds.each { |bird| bird.name = '' } + @pirate.birds.each { |bird| bird.name = "" } assert !@pirate.valid? end @@ -1597,20 +1597,20 @@ class TestAutosaveAssociationValidationsOnAHasOneAssociation < ActiveRecord::Tes def setup super - @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @pirate.create_ship(:name => 'titanic') + @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") + @pirate.create_ship(name: "titanic") super end test "should automatically validate associations with :validate => true" do assert @pirate.valid? - @pirate.ship.name = '' + @pirate.ship.name = "" assert !@pirate.valid? end test "should not automatically add validate associations without :validate => true" do assert @pirate.valid? - @pirate.non_validated_ship.name = '' + @pirate.non_validated_ship.name = "" assert @pirate.valid? end end @@ -1620,18 +1620,18 @@ class TestAutosaveAssociationValidationsOnABelongsToAssociation < ActiveRecord:: def setup super - @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") + @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") end test "should automatically validate associations with :validate => true" do assert @pirate.valid? - @pirate.parrot = Parrot.new(:name => '') + @pirate.parrot = Parrot.new(name: "") assert !@pirate.valid? end test "should not automatically validate associations without :validate => true" do assert @pirate.valid? - @pirate.non_validated_parrot = Parrot.new(:name => '') + @pirate.non_validated_parrot = Parrot.new(name: "") assert @pirate.valid? end end @@ -1641,20 +1641,20 @@ class TestAutosaveAssociationValidationsOnAHABTMAssociation < ActiveRecord::Test def setup super - @pirate = Pirate.create(:catchphrase => "Don' botharrr talkin' like one, savvy?") + @pirate = Pirate.create(catchphrase: "Don' botharrr talkin' like one, savvy?") end test "should automatically validate associations with :validate => true" do assert @pirate.valid? - @pirate.parrots = [ Parrot.new(:name => 'popuga') ] - @pirate.parrots.each { |parrot| parrot.name = '' } + @pirate.parrots = [ Parrot.new(name: "popuga") ] + @pirate.parrots.each { |parrot| parrot.name = "" } assert !@pirate.valid? end test "should not automatically validate associations without :validate => true" do assert @pirate.valid? - @pirate.non_validated_parrots = [ Parrot.new(:name => 'popuga') ] - @pirate.non_validated_parrots.each { |parrot| parrot.name = '' } + @pirate.non_validated_parrots = [ Parrot.new(name: "popuga") ] + @pirate.non_validated_parrots.each { |parrot| parrot.name = "" } assert @pirate.valid? end end @@ -1695,6 +1695,6 @@ end class TestAutosaveAssociationWithTouch < ActiveRecord::TestCase def test_autosave_with_touch_should_not_raise_system_stack_error invoice = Invoice.create - assert_nothing_raised { invoice.line_items.create(:amount => 10) } + assert_nothing_raised { invoice.line_items.create(amount: 10) } end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 00e4e50ea1..fafa144c6f 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1,30 +1,30 @@ require "cases/helper" -require 'models/post' -require 'models/author' -require 'models/topic' -require 'models/reply' -require 'models/category' -require 'models/company' -require 'models/customer' -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/default' -require 'models/auto_id' -require 'models/boolean' -require 'models/column_name' -require 'models/subscriber' -require 'models/comment' -require 'models/minimalistic' -require 'models/warehouse_thing' -require 'models/parrot' -require 'models/person' -require 'models/edge' -require 'models/joke' -require 'models/bird' -require 'models/car' -require 'models/bulb' -require 'concurrent/atomic/count_down_latch' +require "models/post" +require "models/author" +require "models/topic" +require "models/reply" +require "models/category" +require "models/company" +require "models/customer" +require "models/developer" +require "models/computer" +require "models/project" +require "models/default" +require "models/auto_id" +require "models/boolean" +require "models/column_name" +require "models/subscriber" +require "models/comment" +require "models/minimalistic" +require "models/warehouse_thing" +require "models/parrot" +require "models/person" +require "models/edge" +require "models/joke" +require "models/bird" +require "models/car" +require "models/bulb" +require "concurrent/atomic/count_down_latch" class FirstAbstractClass < ActiveRecord::Base self.abstract_class = true @@ -73,17 +73,17 @@ class LintTest < ActiveRecord::TestCase end class BasicsTest < ActiveRecord::TestCase - fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts + fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, "warehouse-things", :authors, :categorizations, :categories, :posts def test_column_names_are_escaped conn = ActiveRecord::Base.connection classname = conn.class.name[/[^:]*$/] badchar = { - 'SQLite3Adapter' => '"', - 'Mysql2Adapter' => '`', - 'PostgreSQLAdapter' => '"', - 'OracleAdapter' => '"', - 'FbAdapter' => '"' + "SQLite3Adapter" => '"', + "Mysql2Adapter" => "`", + "PostgreSQLAdapter" => '"', + "OracleAdapter" => '"', + "FbAdapter" => '"' }.fetch(classname) { raise "need a bad char for #{classname}" } @@ -100,7 +100,7 @@ class BasicsTest < ActiveRecord::TestCase def test_columns_should_obey_set_primary_key pk = Subscriber.columns_hash[Subscriber.primary_key] - assert_equal 'nick', pk.name, 'nick should be primary key' + assert_equal "nick", pk.name, "nick should be primary key" end def test_primary_key_with_no_id @@ -115,6 +115,13 @@ class BasicsTest < ActiveRecord::TestCase end end + def test_many_mutations + car = Car.new name: "<3<3<3" + car.engines_count = 0 + 20_000.times { car.engines_count += 1 } + assert car.save + end + def test_limit_without_comma assert_equal 1, Topic.limit("1").to_a.length assert_equal 1, Topic.limit(1).to_a.length @@ -164,17 +171,17 @@ class BasicsTest < ActiveRecord::TestCase def test_previously_changed topic = Topic.first - topic.title = '<3<3<3' + topic.title = "<3<3<3" assert_equal({}, topic.previous_changes) topic.save! expected = ["The First Topic", "<3<3<3"] - assert_equal(expected, topic.previous_changes['title']) + assert_equal(expected, topic.previous_changes["title"]) end def test_previously_changed_dup topic = Topic.first - topic.title = '<3<3<3' + topic.title = "<3<3<3" topic.save! t2 = topic.dup @@ -211,7 +218,7 @@ class BasicsTest < ActiveRecord::TestCase with_env_tz eastern_time_zone do with_timezone_config default: :utc do time = Time.local(2000) - topic = Topic.create('written_on' => time) + topic = Topic.create("written_on" => time) saved_time = Topic.find(topic.id).reload.written_on assert_equal time, saved_time assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "EST"], time.to_a @@ -223,9 +230,9 @@ class BasicsTest < ActiveRecord::TestCase def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_utc with_env_tz eastern_time_zone do with_timezone_config default: :utc do - Time.use_zone 'Central Time (US & Canada)' do + Time.use_zone "Central Time (US & Canada)" do time = Time.zone.local(2000) - topic = Topic.create('written_on' => time) + topic = Topic.create("written_on" => time) saved_time = Topic.find(topic.id).reload.written_on assert_equal time, saved_time assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a @@ -239,7 +246,7 @@ class BasicsTest < ActiveRecord::TestCase with_env_tz eastern_time_zone do with_timezone_config default: :local do time = Time.utc(2000) - topic = Topic.create('written_on' => time) + topic = Topic.create("written_on" => time) saved_time = Topic.find(topic.id).reload.written_on assert_equal time, saved_time assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a @@ -251,9 +258,9 @@ class BasicsTest < ActiveRecord::TestCase def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_local with_env_tz eastern_time_zone do with_timezone_config default: :local do - Time.use_zone 'Central Time (US & Canada)' do + Time.use_zone "Central Time (US & Canada)" do time = Time.zone.local(2000) - topic = Topic.create('written_on' => time) + topic = Topic.create("written_on" => time) saved_time = Topic.find(topic.id).reload.written_on assert_equal time, saved_time assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a @@ -279,49 +286,48 @@ class BasicsTest < ActiveRecord::TestCase end def test_initialize_with_attributes - topic = Topic.new({ - "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23" - }) + topic = Topic.new( + "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23") assert_equal("initialized from attributes", topic.title) end def test_initialize_with_invalid_attribute - Topic.new({ "title" => "test", - "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"}) + Topic.new("title" => "test", + "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31") rescue ActiveRecord::MultiparameterAssignmentErrors => ex assert_equal(1, ex.errors.size) assert_equal("last_read", ex.errors[0].attribute) end def test_create_after_initialize_without_block - cb = CustomBulb.create(:name => 'Dude') - assert_equal('Dude', cb.name) + cb = CustomBulb.create(name: "Dude") + assert_equal("Dude", cb.name) assert_equal(true, cb.frickinawesome) end def test_create_after_initialize_with_block - cb = CustomBulb.create {|c| c.name = 'Dude' } - assert_equal('Dude', cb.name) + cb = CustomBulb.create { |c| c.name = "Dude" } + assert_equal("Dude", cb.name) assert_equal(true, cb.frickinawesome) end def test_create_after_initialize_with_array_param - cbs = CustomBulb.create([{ name: 'Dude' }, { name: 'Bob' }]) - assert_equal 'Dude', cbs[0].name - assert_equal 'Bob', cbs[1].name + cbs = CustomBulb.create([{ name: "Dude" }, { name: "Bob" }]) + assert_equal "Dude", cbs[0].name + assert_equal "Bob", cbs[1].name assert cbs[0].frickinawesome assert !cbs[1].frickinawesome end def test_load - topics = Topic.all.merge!(:order => 'id').to_a + topics = Topic.all.merge!(order: "id").to_a assert_equal(5, topics.size) assert_equal(topics(:first).title, topics.first.title) end def test_load_with_condition - topics = Topic.all.merge!(:where => "author_name = 'Mary'").to_a + topics = Topic.all.merge!(where: "author_name = 'Mary'").to_a assert_equal(1, topics.size) assert_equal(topics(:second).title, topics.first.title) @@ -443,7 +449,7 @@ class BasicsTest < ActiveRecord::TestCase if current_adapter?(:Mysql2Adapter) def test_update_all_with_order_and_limit - assert_equal 1, Topic.limit(1).order('id DESC').update_all(:content => 'bulk updated!') + assert_equal 1, Topic.limit(1).order("id DESC").update_all(content: "bulk updated!") end end @@ -518,16 +524,16 @@ class BasicsTest < ActiveRecord::TestCase end def test_find_by_slug - assert_equal Topic.find('1-meowmeow'), Topic.find(1) + assert_equal Topic.find("1-meowmeow"), Topic.find(1) end def test_find_by_slug_with_array - assert_equal Topic.find([1, 2]), Topic.find(['1-meowmeow', '2-hello']) - assert_equal 'The Second Topic of the day', Topic.find(['2-hello', '1-meowmeow']).first.title + assert_equal Topic.find([1, 2]), Topic.find(["1-meowmeow", "2-hello"]) + assert_equal "The Second Topic of the day", Topic.find(["2-hello", "1-meowmeow"]).first.title end def test_find_by_slug_with_range - assert_equal Topic.where(id: '1-meowmeow'..'2-hello'), Topic.where(id: 1..2) + assert_equal Topic.where(id: "1-meowmeow".."2-hello"), Topic.where(id: 1..2) end def test_equality_of_new_records @@ -536,7 +542,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_equality_of_destroyed_records - topic_1 = Topic.new(:title => 'test_1') + topic_1 = Topic.new(title: "test_1") topic_1.save topic_2 = Topic.find(topic_1.id) topic_1.destroy @@ -545,8 +551,8 @@ class BasicsTest < ActiveRecord::TestCase end def test_equality_with_blank_ids - one = Subscriber.new(:id => '') - two = Subscriber.new(:id => '') + one = Subscriber.new(id: "") + two = Subscriber.new(id: "") assert_equal one, two end @@ -555,8 +561,8 @@ class BasicsTest < ActiveRecord::TestCase car.bulbs.build car.save - assert car.bulbs == Bulb.where(car_id: car.id), 'CollectionProxy should be comparable with Relation' - assert Bulb.where(car_id: car.id) == car.bulbs, 'Relation should be comparable with CollectionProxy' + assert car.bulbs == Bulb.where(car_id: car.id), "CollectionProxy should be comparable with Relation" + assert Bulb.where(car_id: car.id) == car.bulbs, "Relation should be comparable with CollectionProxy" end def test_equality_of_relation_and_array @@ -564,7 +570,7 @@ class BasicsTest < ActiveRecord::TestCase car.bulbs.build car.save - assert Bulb.where(car_id: car.id) == car.bulbs.to_a, 'Relation should be comparable with Array' + assert Bulb.where(car_id: car.id) == car.bulbs.to_a, "Relation should be comparable with Array" end def test_equality_of_relation_and_association_relation @@ -572,8 +578,8 @@ class BasicsTest < ActiveRecord::TestCase car.bulbs.build car.save - assert_equal Bulb.where(car_id: car.id), car.bulbs.includes(:car), 'Relation should be comparable with AssociationRelation' - assert_equal car.bulbs.includes(:car), Bulb.where(car_id: car.id), 'AssociationRelation should be comparable with Relation' + assert_equal Bulb.where(car_id: car.id), car.bulbs.includes(:car), "Relation should be comparable with AssociationRelation" + assert_equal car.bulbs.includes(:car), Bulb.where(car_id: car.id), "AssociationRelation should be comparable with Relation" end def test_equality_of_collection_proxy_and_association_relation @@ -581,8 +587,8 @@ class BasicsTest < ActiveRecord::TestCase car.bulbs.build car.save - assert_equal car.bulbs, car.bulbs.includes(:car), 'CollectionProxy should be comparable with AssociationRelation' - assert_equal car.bulbs.includes(:car), car.bulbs, 'AssociationRelation should be comparable with CollectionProxy' + assert_equal car.bulbs, car.bulbs.includes(:car), "CollectionProxy should be comparable with AssociationRelation" + assert_equal car.bulbs.includes(:car), car.bulbs, "AssociationRelation should be comparable with CollectionProxy" end def test_hashing @@ -604,14 +610,14 @@ class BasicsTest < ActiveRecord::TestCase def test_create_without_prepared_statement topic = Topic.connection.unprepared_statement do - Topic.create(:title => 'foo') + Topic.create(title: "foo") end assert_equal topic, Topic.find(topic.id) end def test_destroy_without_prepared_statement - topic = Topic.create(title: 'foo') + topic = Topic.create(title: "foo") Topic.connection.unprepared_statement do Topic.find(topic.id).destroy end @@ -621,7 +627,7 @@ class BasicsTest < ActiveRecord::TestCase def test_comparison_with_different_objects topic = Topic.create - category = Category.create(:name => "comparison") + category = Category.create(name: "comparison") assert_nil topic <=> category end @@ -633,9 +639,9 @@ class BasicsTest < ActiveRecord::TestCase end def test_readonly_attributes - assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes + assert_equal Set.new([ "title" , "comments_count" ]), ReadonlyTitlePost.readonly_attributes - post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable") + post = ReadonlyTitlePost.create(title: "cannot change this", body: "changeable") post.reload assert_equal "cannot change this", post.title @@ -647,8 +653,8 @@ class BasicsTest < ActiveRecord::TestCase def test_unicode_column_name Weird.reset_column_information - weird = Weird.create(:ãªã¾ãˆ => 'ãŸã“焼ãä»®é¢') - assert_equal 'ãŸã“焼ãä»®é¢', weird.ãªã¾ãˆ + weird = Weird.create(ãªã¾ãˆ: "ãŸã“焼ãä»®é¢") + assert_equal "ãŸã“焼ãä»®é¢", weird.ãªã¾ãˆ end unless current_adapter?(:PostgreSQLAdapter) @@ -658,7 +664,7 @@ class BasicsTest < ActiveRecord::TestCase Weird.reset_column_information - assert_equal ["EUC-JP"], Weird.columns.map {|c| c.name.encoding.name }.uniq + assert_equal ["EUC-JP"], Weird.columns.map { |c| c.name.encoding.name }.uniq ensure silence_warnings { Encoding.default_internal = old_default_internal } Weird.reset_column_information @@ -666,21 +672,21 @@ class BasicsTest < ActiveRecord::TestCase end def test_non_valid_identifier_column_name - weird = Weird.create('a$b' => 'value') + weird = Weird.create("a$b" => "value") weird.reload - assert_equal 'value', weird.send('a$b') - assert_equal 'value', weird.read_attribute('a$b') + assert_equal "value", weird.send("a$b") + assert_equal "value", weird.read_attribute("a$b") - weird.update_columns('a$b' => 'value2') + weird.update_columns("a$b" => "value2") weird.reload - assert_equal 'value2', weird.send('a$b') - assert_equal 'value2', weird.read_attribute('a$b') + assert_equal "value2", weird.send("a$b") + assert_equal "value2", weird.read_attribute("a$b") end def test_group_weirds_by_from - Weird.create('a$b' => 'value', :from => 'aaron') + Weird.create("a$b" => "value", :from => "aaron") count = Weird.group(Weird.arel_table[:from]).count - assert_equal 1, count['aaron'] + assert_equal 1, count["aaron"] end def test_attributes_on_dummy_time @@ -710,11 +716,11 @@ class BasicsTest < ActiveRecord::TestCase end def test_boolean - b_nil = Boolean.create({ "value" => nil }) + b_nil = Boolean.create("value" => nil) nil_id = b_nil.id - b_false = Boolean.create({ "value" => false }) + b_false = Boolean.create("value" => false) false_id = b_false.id - b_true = Boolean.create({ "value" => true }) + b_true = Boolean.create("value" => true) true_id = b_true.id b_nil = Boolean.find(nil_id) @@ -726,7 +732,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_boolean_without_questionmark - b_true = Boolean.create({ "value" => true }) + b_true = Boolean.create("value" => true) true_id = b_true.id subclass = Class.new(Boolean).find true_id @@ -736,11 +742,11 @@ class BasicsTest < ActiveRecord::TestCase end def test_boolean_cast_from_string - b_blank = Boolean.create({ "value" => "" }) + b_blank = Boolean.create("value" => "") blank_id = b_blank.id - b_false = Boolean.create({ "value" => "0" }) + b_false = Boolean.create("value" => "0") false_id = b_false.id - b_true = Boolean.create({ "value" => "1" }) + b_true = Boolean.create("value" => "1") true_id = b_true.id b_blank = Boolean.find(blank_id) @@ -789,8 +795,8 @@ class BasicsTest < ActiveRecord::TestCase DeveloperSalary = Struct.new(:amount) def test_dup_with_aggregate_of_same_name_as_attribute developer_with_aggregate = Class.new(ActiveRecord::Base) do - self.table_name = 'developers' - composed_of :salary, :class_name => 'BasicsTest::DeveloperSalary', :mapping => [%w(salary amount)] + self.table_name = "developers" + composed_of :salary, class_name: "BasicsTest::DeveloperSalary", mapping: [%w(salary amount)] end dev = developer_with_aggregate.find(1) @@ -837,7 +843,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_clone_of_new_object_marks_attributes_as_dirty - developer = Developer.new :name => 'Bjorn', :salary => 100000 + developer = Developer.new name: "Bjorn", salary: 100000 assert developer.name_changed? assert developer.salary_changed? @@ -847,7 +853,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_clone_of_new_object_marks_as_dirty_only_changed_attributes - developer = Developer.new :name => 'Bjorn' + developer = Developer.new name: "Bjorn" assert developer.name_changed? # obviously assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed @@ -857,7 +863,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_dup_of_saved_object_marks_attributes_as_dirty - developer = Developer.create! :name => 'Bjorn', :salary => 100000 + developer = Developer.create! name: "Bjorn", salary: 100000 assert !developer.name_changed? assert !developer.salary_changed? @@ -867,7 +873,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_dup_of_saved_object_marks_as_dirty_only_changed_attributes - developer = Developer.create! :name => 'Bjorn' + developer = Developer.create! name: "Bjorn" assert !developer.name_changed? # both attributes of saved object should be treated as not changed assert !developer.salary_changed? @@ -895,15 +901,15 @@ class BasicsTest < ActiveRecord::TestCase assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time # char types - assert_equal 'Y', default.char1 - assert_equal 'a varchar field', default.char2 - assert_equal 'a text field', default.char3 + assert_equal "Y", default.char1 + assert_equal "a varchar field", default.char2 + assert_equal "a text field", default.char3 end end end class NumericData < ActiveRecord::Base - self.table_name = 'numeric_data' + self.table_name = "numeric_data" attribute :my_house_population, :integer attribute :atoms_in_universe, :integer @@ -911,10 +917,10 @@ class BasicsTest < ActiveRecord::TestCase def test_big_decimal_conditions m = NumericData.new( - :bank_balance => 1586.43, - :big_bank_balance => BigDecimal("1000234000567.95"), - :world_population => 6000000000, - :my_house_population => 3 + bank_balance: 1586.43, + big_bank_balance: BigDecimal("1000234000567.95"), + world_population: 6000000000, + my_house_population: 3 ) assert m.save assert_equal 0, NumericData.where("bank_balance > ?", 2000.0).count @@ -922,10 +928,10 @@ class BasicsTest < ActiveRecord::TestCase def test_numeric_fields m = NumericData.new( - :bank_balance => 1586.43, - :big_bank_balance => BigDecimal("1000234000567.95"), - :world_population => 6000000000, - :my_house_population => 3 + bank_balance: 1586.43, + big_bank_balance: BigDecimal("1000234000567.95"), + world_population: 6000000000, + my_house_population: 3 ) assert m.save @@ -950,10 +956,10 @@ class BasicsTest < ActiveRecord::TestCase def test_numeric_fields_with_scale m = NumericData.new( - :bank_balance => 1586.43122334, - :big_bank_balance => BigDecimal("234000567.952344"), - :world_population => 6000000000, - :my_house_population => 3 + bank_balance: 1586.43122334, + big_bank_balance: BigDecimal("234000567.952344"), + world_population: 6000000000, + my_house_population: 3 ) assert m.save @@ -999,16 +1005,16 @@ class BasicsTest < ActiveRecord::TestCase end def test_quoting_arrays - replies = Reply.all.merge!(:where => [ "id IN (?)", topics(:first).replies.collect(&:id) ]).to_a + replies = Reply.all.merge!(where: [ "id IN (?)", topics(:first).replies.collect(&:id) ]).to_a assert_equal topics(:first).replies.size, replies.size - replies = Reply.all.merge!(:where => [ "id IN (?)", [] ]).to_a + replies = Reply.all.merge!(where: [ "id IN (?)", [] ]).to_a assert_equal 0, replies.size end def test_quote author_name = "\\ \001 ' \n \\n \"" - topic = Topic.create('author_name' => author_name) + topic = Topic.create("author_name" => author_name) assert_equal author_name, Topic.find(topic.id).author_name end @@ -1032,12 +1038,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal t1.title, t2.title end - def test_reload_with_exclusive_scope - dev = DeveloperCalledDavid.first - dev.update!(name: "NotDavid" ) - assert_equal dev, dev.reload - end - def test_switching_between_table_name k = Class.new(Joke) @@ -1093,7 +1093,7 @@ class BasicsTest < ActiveRecord::TestCase def test_set_table_name_symbol_converted_to_string k = Class.new(Joke) k.table_name = :cold_jokes - assert_equal 'cold_jokes', k.table_name + assert_equal "cold_jokes", k.table_name end def test_quoted_table_name_after_set_table_name @@ -1155,17 +1155,17 @@ class BasicsTest < ActiveRecord::TestCase def test_no_limit_offset assert_nothing_raised do - Developer.all.merge!(:offset => 2).to_a + Developer.all.merge!(offset: 2).to_a end end def test_find_last last = Developer.last - assert_equal last, Developer.all.merge!(:order => 'id desc').first + assert_equal last, Developer.all.merge!(order: "id desc").first end def test_last - assert_equal Developer.all.merge!(:order => 'id desc').first, Developer.last + assert_equal Developer.all.merge!(order: "id desc").first, Developer.last end def test_all @@ -1175,37 +1175,37 @@ class BasicsTest < ActiveRecord::TestCase end def test_all_with_conditions - assert_equal Developer.all.merge!(:order => 'id desc').to_a, Developer.order('id desc').to_a + assert_equal Developer.all.merge!(order: "id desc").to_a, Developer.order("id desc").to_a end def test_find_ordered_last - last = Developer.all.merge!(:order => 'developers.salary ASC').last - assert_equal last, Developer.all.merge!(:order => 'developers.salary ASC').to_a.last + last = Developer.all.merge!(order: "developers.salary ASC").last + assert_equal last, Developer.all.merge!(order: "developers.salary ASC").to_a.last end def test_find_reverse_ordered_last - last = Developer.all.merge!(:order => 'developers.salary DESC').last - assert_equal last, Developer.all.merge!(:order => 'developers.salary DESC').to_a.last + last = Developer.all.merge!(order: "developers.salary DESC").last + assert_equal last, Developer.all.merge!(order: "developers.salary DESC").to_a.last end def test_find_multiple_ordered_last - last = Developer.all.merge!(:order => 'developers.name, developers.salary DESC').last - assert_equal last, Developer.all.merge!(:order => 'developers.name, developers.salary DESC').to_a.last + last = Developer.all.merge!(order: "developers.name, developers.salary DESC").last + assert_equal last, Developer.all.merge!(order: "developers.name, developers.salary DESC").to_a.last end def test_find_keeps_multiple_order_values - combined = Developer.all.merge!(:order => 'developers.name, developers.salary').to_a - assert_equal combined, Developer.all.merge!(:order => ['developers.name', 'developers.salary']).to_a + combined = Developer.all.merge!(order: "developers.name, developers.salary").to_a + assert_equal combined, Developer.all.merge!(order: ["developers.name", "developers.salary"]).to_a end def test_find_keeps_multiple_group_values - combined = Developer.all.merge!(:group => 'developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at, developers.created_on, developers.updated_on').to_a - assert_equal combined, Developer.all.merge!(:group => ['developers.name', 'developers.salary', 'developers.id', 'developers.created_at', 'developers.updated_at', 'developers.created_on', 'developers.updated_on']).to_a + combined = Developer.all.merge!(group: "developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at, developers.created_on, developers.updated_on").to_a + assert_equal combined, Developer.all.merge!(group: ["developers.name", "developers.salary", "developers.id", "developers.created_at", "developers.updated_at", "developers.created_on", "developers.updated_on"]).to_a end def test_find_symbol_ordered_last - last = Developer.all.merge!(:order => :salary).last - assert_equal last, Developer.all.merge!(:order => :salary).to_a.last + last = Developer.all.merge!(order: :salary).last + assert_equal last, Developer.all.merge!(order: :salary).to_a.last end def test_abstract_class_table_name @@ -1216,7 +1216,7 @@ class BasicsTest < ActiveRecord::TestCase old_class = LooseDescendant Object.send :remove_const, :LooseDescendant - descendant = old_class.create! :first_name => 'bob' + descendant = old_class.create! first_name: "bob" assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}" ensure unless Object.const_defined?(:LooseDescendant) @@ -1225,7 +1225,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_assert_queries - query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' } + query = lambda { ActiveRecord::Base.connection.execute "select count(*) from developers" } assert_queries(2) { 2.times { query.call } } assert_queries 1, &query assert_no_queries { assert true } @@ -1236,9 +1236,9 @@ class BasicsTest < ActiveRecord::TestCase log = StringIO.new ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) ActiveRecord::Base.logger.level = Logger::WARN - ActiveRecord::Base.benchmark("Debug Topic Count", :level => :debug) { Topic.count } - ActiveRecord::Base.benchmark("Warn Topic Count", :level => :warn) { Topic.count } - ActiveRecord::Base.benchmark("Error Topic Count", :level => :error) { Topic.count } + ActiveRecord::Base.benchmark("Debug Topic Count", level: :debug) { Topic.count } + ActiveRecord::Base.benchmark("Warn Topic Count", level: :warn) { Topic.count } + ActiveRecord::Base.benchmark("Error Topic Count", level: :error) { Topic.count } assert_no_match(/Debug Topic Count/, log.string) assert_match(/Warn Topic Count/, log.string) assert_match(/Error Topic Count/, log.string) @@ -1251,7 +1251,7 @@ class BasicsTest < ActiveRecord::TestCase log = StringIO.new ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) ActiveRecord::Base.logger.level = Logger::DEBUG - ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" } + ActiveRecord::Base.benchmark("Logging", level: :debug, silence: false) { ActiveRecord::Base.logger.debug "Quiet" } assert_match(/Quiet/, log.string) ensure ActiveRecord::Base.logger = original_logger @@ -1259,9 +1259,9 @@ class BasicsTest < ActiveRecord::TestCase def test_clear_cache! # preheat cache - c1 = Post.connection.schema_cache.columns('posts') + c1 = Post.connection.schema_cache.columns("posts") ActiveRecord::Base.clear_cache! - c2 = Post.connection.schema_cache.columns('posts') + c2 = Post.connection.schema_cache.columns("posts") c1.each_with_index do |v, i| assert_not_same v, c2[i] end @@ -1278,7 +1278,7 @@ class BasicsTest < ActiveRecord::TestCase ActiveSupport::Dependencies.remove_unloadable_constants! assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, klass) ensure - Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost) + Object.class_eval { remove_const :UnloadablePost } if defined?(UnloadablePost) end def test_marshal_round_trip @@ -1352,11 +1352,11 @@ class BasicsTest < ActiveRecord::TestCase end def test_has_attribute - assert Company.has_attribute?('id') - assert Company.has_attribute?('type') - assert Company.has_attribute?('name') - assert_not Company.has_attribute?('lastname') - assert_not Company.has_attribute?('age') + assert Company.has_attribute?("id") + assert Company.has_attribute?("type") + assert Company.has_attribute?("name") + assert_not Company.has_attribute?("lastname") + assert_not Company.has_attribute?("age") end def test_has_attribute_with_symbol @@ -1373,7 +1373,7 @@ class BasicsTest < ActiveRecord::TestCase end def test_touch_should_raise_error_on_a_new_object - company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals") + company = Company.new(rating: 1, name: "37signals", firm_name: "37signals") assert_raises(ActiveRecord::ActiveRecordError) do company.touch :updated_at end @@ -1395,37 +1395,37 @@ class BasicsTest < ActiveRecord::TestCase def test_column_types_typecast topic = Topic.first - assert_not_equal 't.lo', topic.author_name + assert_not_equal "t.lo", topic.author_name attrs = topic.attributes.dup - attrs.delete 'id' + attrs.delete "id" typecast = Class.new(ActiveRecord::Type::Value) { - def cast value + def cast(value) "t.lo" end } - types = { 'author_name' => typecast.new } + types = { "author_name" => typecast.new } topic = Topic.instantiate(attrs, types) - assert_equal 't.lo', topic.author_name + assert_equal "t.lo", topic.author_name end def test_typecasting_aliases - assert_equal 10, Topic.select('10 as tenderlove').first.tenderlove + assert_equal 10, Topic.select("10 as tenderlove").first.tenderlove end def test_slice - company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals") + company = Company.new(rating: 1, name: "37signals", firm_name: "37signals") hash = company.slice(:name, :rating, "arbitrary_method") assert_equal hash[:name], company.name - assert_equal hash['name'], company.name + assert_equal hash["name"], company.name assert_equal hash[:rating], company.rating - assert_equal hash['arbitrary_method'], company.arbitrary_method + assert_equal hash["arbitrary_method"], company.arbitrary_method assert_equal hash[:arbitrary_method], company.arbitrary_method assert_nil hash[:firm_name] - assert_nil hash['firm_name'] + assert_nil hash["firm_name"] end def test_default_values_are_deeply_dupped @@ -1436,7 +1436,7 @@ class BasicsTest < ActiveRecord::TestCase test "scoped can take a values hash" do klass = Class.new(ActiveRecord::Base) - assert_equal ['foo'], klass.all.merge!(select: 'foo').select_values + assert_equal ["foo"], klass.all.merge!(select: "foo").select_values end test "connection_handler can be overridden" do @@ -1518,8 +1518,8 @@ class BasicsTest < ActiveRecord::TestCase test "ignored columns are not present in columns_hash" do cache_columns = Developer.connection.schema_cache.columns_hash(Developer.table_name) - assert_includes cache_columns.keys, 'first_name' - refute_includes Developer.columns_hash.keys, 'first_name' + assert_includes cache_columns.keys, "first_name" + assert_not_includes Developer.columns_hash.keys, "first_name" end test "ignored columns have no attribute methods" do diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index db71840658..f7e21faf0f 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/post' -require 'models/subscriber' +require "cases/helper" +require "models/post" +require "models/subscriber" class EachTest < ActiveRecord::TestCase fixtures :posts, :subscribers @@ -8,12 +8,12 @@ class EachTest < ActiveRecord::TestCase def setup @posts = Post.order("id asc") @total = Post.count - Post.count('id') # preheat arel's table cache + Post.count("id") # preheat arel's table cache end def test_each_should_execute_one_query_per_batch assert_queries(@total + 1) do - Post.find_each(:batch_size => 1) do |post| + Post.find_each(batch_size: 1) do |post| assert_kind_of Post, post end end @@ -21,14 +21,14 @@ class EachTest < ActiveRecord::TestCase def test_each_should_not_return_query_chain_and_execute_only_one_query assert_queries(1) do - result = Post.find_each(:batch_size => 100000){ } + result = Post.find_each(batch_size: 100000) {} assert_nil result end end def test_each_should_return_an_enumerator_if_no_block_is_present assert_queries(1) do - Post.find_each(:batch_size => 100000).with_index do |post, index| + Post.find_each(batch_size: 100000).with_index do |post, index| assert_kind_of Post, post assert_kind_of Integer, index end @@ -45,7 +45,7 @@ class EachTest < ActiveRecord::TestCase def test_each_enumerator_should_execute_one_query_per_batch assert_queries(@total + 1) do - Post.find_each(:batch_size => 1).with_index do |post, index| + Post.find_each(batch_size: 1).with_index do |post, index| assert_kind_of Post, post assert_kind_of Integer, index end @@ -62,16 +62,32 @@ class EachTest < ActiveRecord::TestCase def test_each_should_execute_if_id_is_in_select assert_queries(6) do - Post.select("id, title, type").find_each(:batch_size => 2) do |post| + Post.select("id, title, type").find_each(batch_size: 2) do |post| assert_kind_of Post, post end end end - def test_warn_if_limit_scope_is_set - assert_called(ActiveRecord::Base.logger, :warn) do - Post.limit(1).find_each { |post| post } + test "find_each should honor limit if passed a block" do + limit = @total - 1 + total = 0 + + Post.limit(limit).find_each do |post| + total += 1 + end + + assert_equal limit, total + end + + test "find_each should honor limit if no block is passed" do + limit = @total - 1 + total = 0 + + Post.limit(limit).find_each.each do |post| + total += 1 end + + assert_equal limit, total end def test_warn_if_order_scope_is_set @@ -84,7 +100,7 @@ class EachTest < ActiveRecord::TestCase previous_logger = ActiveRecord::Base.logger ActiveRecord::Base.logger = nil assert_nothing_raised do - Post.limit(1).find_each { |post| post } + Post.order("comments_count DESC").find_each { |post| post } end ensure ActiveRecord::Base.logger = previous_logger @@ -92,7 +108,7 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_return_batches assert_queries(@total + 1) do - Post.find_in_batches(:batch_size => 1) do |batch| + Post.find_in_batches(batch_size: 1) do |batch| assert_kind_of Array, batch assert_kind_of Post, batch.first end @@ -119,18 +135,18 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_shouldnt_execute_query_unless_needed assert_queries(2) do - Post.find_in_batches(:batch_size => @total) {|batch| assert_kind_of Array, batch } + Post.find_in_batches(batch_size: @total) { |batch| assert_kind_of Array, batch } end assert_queries(1) do - Post.find_in_batches(:batch_size => @total + 1) {|batch| assert_kind_of Array, batch } + Post.find_in_batches(batch_size: @total + 1) { |batch| assert_kind_of Array, batch } end end def test_find_in_batches_should_quote_batch_order c = Post.connection assert_sql(/ORDER BY #{c.quote_table_name('posts')}.#{c.quote_column_name('id')}/) do - Post.find_in_batches(:batch_size => 1) do |batch| + Post.find_in_batches(batch_size: 1) do |batch| assert_kind_of Array, batch assert_kind_of Post, batch.first end @@ -140,9 +156,9 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_not_use_records_after_yielding_them_in_case_original_array_is_modified not_a_post = "not a post" def not_a_post.id; end - not_a_post.stub(:id, ->{ raise StandardError.new("not_a_post had #id called on it") }) do + not_a_post.stub(:id, -> { raise StandardError.new("not_a_post had #id called on it") }) do assert_nothing_raised do - Post.find_in_batches(:batch_size => 1) do |batch| + Post.find_in_batches(batch_size: 1) do |batch| assert_kind_of Array, batch assert_kind_of Post, batch.first @@ -166,37 +182,37 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_error_on_ignore_the_order assert_raise(ArgumentError) do - PostWithDefaultScope.find_in_batches(error_on_ignore: true){} + PostWithDefaultScope.find_in_batches(error_on_ignore: true) {} end end def test_find_in_batches_should_not_error_if_config_overridden # Set the config option which will be overridden - prev = ActiveRecord::Base.error_on_ignored_order_or_limit - ActiveRecord::Base.error_on_ignored_order_or_limit = true + prev = ActiveRecord::Base.error_on_ignored_order + ActiveRecord::Base.error_on_ignored_order = true assert_nothing_raised do - PostWithDefaultScope.find_in_batches(error_on_ignore: false){} + PostWithDefaultScope.find_in_batches(error_on_ignore: false) {} end ensure # Set back to default - ActiveRecord::Base.error_on_ignored_order_or_limit = prev + ActiveRecord::Base.error_on_ignored_order = prev end def test_find_in_batches_should_error_on_config_specified_to_error # Set the config option - prev = ActiveRecord::Base.error_on_ignored_order_or_limit - ActiveRecord::Base.error_on_ignored_order_or_limit = true + prev = ActiveRecord::Base.error_on_ignored_order + ActiveRecord::Base.error_on_ignored_order = true assert_raise(ArgumentError) do - PostWithDefaultScope.find_in_batches(){} + PostWithDefaultScope.find_in_batches() {} end ensure # Set back to default - ActiveRecord::Base.error_on_ignored_order_or_limit = prev + ActiveRecord::Base.error_on_ignored_order = prev end def test_find_in_batches_should_not_error_by_default assert_nothing_raised do - PostWithDefaultScope.find_in_batches(){} + PostWithDefaultScope.find_in_batches() {} end end @@ -211,12 +227,12 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_not_modify_passed_options assert_nothing_raised do - Post.find_in_batches({ batch_size: 42, start: 1 }.freeze){} + Post.find_in_batches({ batch_size: 42, start: 1 }.freeze) {} end end def test_find_in_batches_should_use_any_column_as_primary_key - nick_order_subscribers = Subscriber.order('nick asc') + nick_order_subscribers = Subscriber.order("nick asc") start_nick = nick_order_subscribers.second.nick subscribers = [] @@ -239,7 +255,7 @@ class EachTest < ActiveRecord::TestCase def test_find_in_batches_should_return_an_enumerator enum = nil assert_no_queries do - enum = Post.find_in_batches(:batch_size => 1) + enum = Post.find_in_batches(batch_size: 1) end assert_queries(4) do enum.first(4) do |batch| @@ -249,6 +265,28 @@ class EachTest < ActiveRecord::TestCase end end + test "find_in_batches should honor limit if passed a block" do + limit = @total - 1 + total = 0 + + Post.limit(limit).find_in_batches do |batch| + total += batch.size + end + + assert_equal limit, total + end + + test "find_in_batches should honor limit if no block is passed" do + limit = @total - 1 + total = 0 + + Post.limit(limit).find_in_batches.each do |batch| + total += batch.size + end + + assert_equal limit, total + end + def test_in_batches_should_not_execute_any_query assert_no_queries do assert_kind_of ActiveRecord::Batches::BatchEnumerator, Post.in_batches(of: 2) @@ -290,7 +328,7 @@ class EachTest < ActiveRecord::TestCase end def test_in_batches_each_record_should_be_ordered_by_id - ids = Post.order('id ASC').pluck(:id) + ids = Post.order("id ASC").pluck(:id) assert_queries(6) do Post.in_batches(of: 2).each_record.with_index do |post, i| assert_equal ids[i], post.id @@ -306,9 +344,9 @@ class EachTest < ActiveRecord::TestCase end def test_in_batches_delete_all_should_not_delete_records_in_other_batches - not_deleted_count = Post.where('id <= 2').count - Post.where('id > 2').in_batches(of: 2).delete_all - assert_equal 0, Post.where('id > 2').count + not_deleted_count = Post.where("id <= 2").count + Post.where("id > 2").in_batches(of: 2).delete_all + assert_equal 0, Post.where("id > 2").count assert_equal not_deleted_count, Post.count end @@ -345,7 +383,7 @@ class EachTest < ActiveRecord::TestCase end def test_in_batches_should_start_from_the_start_option - post = Post.order('id ASC').where('id >= ?', 2).first + post = Post.order("id ASC").where("id >= ?", 2).first assert_queries(2) do relation = Post.in_batches(of: 1, start: 2).first assert_equal post, relation.first @@ -353,7 +391,7 @@ class EachTest < ActiveRecord::TestCase end def test_in_batches_should_end_at_the_finish_option - post = Post.order('id DESC').where('id <= ?', 5).first + post = Post.order("id DESC").where("id <= ?", 5).first assert_queries(7) do relation = Post.in_batches(of: 1, finish: 5, load: true).reverse_each.first assert_equal post, relation.last @@ -407,12 +445,12 @@ class EachTest < ActiveRecord::TestCase def test_in_batches_should_not_modify_passed_options assert_nothing_raised do - Post.in_batches({ of: 42, start: 1 }.freeze){} + Post.in_batches({ of: 42, start: 1 }.freeze) {} end end def test_in_batches_should_use_any_column_as_primary_key - nick_order_subscribers = Subscriber.order('nick asc') + nick_order_subscribers = Subscriber.order("nick asc") start_nick = nick_order_subscribers.second.nick subscribers = [] @@ -472,18 +510,108 @@ class EachTest < ActiveRecord::TestCase person.update_attributes(author_id: 1) Post.in_batches(of: 2) do |batch| - batch.where('author_id >= 1').update_all('author_id = author_id + 1') + batch.where("author_id >= 1").update_all("author_id = author_id + 1") end assert_equal 2, person.reload.author_id # incremented only once end if Enumerator.method_defined? :size def test_find_in_batches_should_return_a_sized_enumerator - assert_equal 11, Post.find_in_batches(:batch_size => 1).size - assert_equal 6, Post.find_in_batches(:batch_size => 2).size + assert_equal 11, Post.find_in_batches(batch_size: 1).size + assert_equal 6, Post.find_in_batches(batch_size: 2).size assert_equal 4, Post.find_in_batches(batch_size: 2, start: 4).size - assert_equal 4, Post.find_in_batches(:batch_size => 3).size - assert_equal 1, Post.find_in_batches(:batch_size => 10_000).size + assert_equal 4, Post.find_in_batches(batch_size: 3).size + assert_equal 1, Post.find_in_batches(batch_size: 10_000).size + end + end + + [true, false].each do |load| + test "in_batches should return limit records when limit is less than batch size and load is #{load}" do + limit = 3 + batch_size = 5 + total = 0 + + Post.limit(limit).in_batches(of: batch_size, load: load) do |batch| + total += batch.count + end + + assert_equal limit, total + end + + test "in_batches should return limit records when limit is greater than batch size and load is #{load}" do + limit = 5 + batch_size = 3 + total = 0 + + Post.limit(limit).in_batches(of: batch_size, load: load) do |batch| + total += batch.count + end + + assert_equal limit, total + end + + test "in_batches should return limit records when limit is a multiple of the batch size and load is #{load}" do + limit = 6 + batch_size = 3 + total = 0 + + Post.limit(limit).in_batches(of: batch_size, load: load) do |batch| + total += batch.count + end + + assert_equal limit, total + end + + test "in_batches should return no records if the limit is 0 and load is #{load}" do + limit = 0 + batch_size = 1 + total = 0 + + Post.limit(limit).in_batches(of: batch_size, load: load) do |batch| + total += batch.count + end + + assert_equal limit, total + end + + test "in_batches should return all if the limit is greater than the number of records when load is #{load}" do + limit = @total + 1 + batch_size = 1 + total = 0 + + Post.limit(limit).in_batches(of: batch_size, load: load) do |batch| + total += batch.count + end + + assert_equal @total, total + end + end + + test ".error_on_ignored_order_or_limit= is deprecated" do + begin + prev = ActiveRecord::Base.error_on_ignored_order + assert_deprecated "Please use error_on_ignored_order= instead." do + ActiveRecord::Base.error_on_ignored_order_or_limit = true + end + assert ActiveRecord::Base.error_on_ignored_order + ensure + ActiveRecord::Base.error_on_ignored_order = prev + end + end + + test ".error_on_ignored_order_or_limit is deprecated" do + expected = ActiveRecord::Base.error_on_ignored_order + actual = assert_deprecated "Please use error_on_ignored_order instead." do + ActiveRecord::Base.error_on_ignored_order_or_limit + end + assert_equal expected, actual + end + + test "#error_on_ignored_order_or_limit is deprecated" do + expected = ActiveRecord::Base.error_on_ignored_order + actual = assert_deprecated "Please use error_on_ignored_order instead." do + Post.new.error_on_ignored_order_or_limit end + assert_equal expected, actual end end diff --git a/activerecord/test/cases/binary_test.rb b/activerecord/test/cases/binary_test.rb index 9eb5352150..1fc30e24d2 100644 --- a/activerecord/test/cases/binary_test.rb +++ b/activerecord/test/cases/binary_test.rb @@ -4,23 +4,23 @@ require "cases/helper" # BLOB data with DB2, because the length of a statement # is limited to 32KB. unless current_adapter?(:DB2Adapter) - require 'models/binary' + require "models/binary" class BinaryTest < ActiveRecord::TestCase FIXTURES = %w(flowers.jpg example.log test.txt) def test_mixed_encoding str = "\x80" - str.force_encoding('ASCII-8BIT') + str.force_encoding("ASCII-8BIT") - binary = Binary.new :name => 'ã„ãŸã ãã¾ã™ï¼', :data => str + binary = Binary.new name: "ã„ãŸã ãã¾ã™ï¼", data: str binary.save! binary.reload assert_equal str, binary.data name = binary.name - assert_equal 'ã„ãŸã ãã¾ã™ï¼', name + assert_equal "ã„ãŸã ãã¾ã™ï¼", name end def test_load_save @@ -28,16 +28,16 @@ unless current_adapter?(:DB2Adapter) FIXTURES.each do |filename| data = File.read(ASSETS_ROOT + "/#{filename}") - data.force_encoding('ASCII-8BIT') + data.force_encoding("ASCII-8BIT") data.freeze - bin = Binary.new(:data => data) - assert_equal data, bin.data, 'Newly assigned data differs from original' + bin = Binary.new(data: data) + assert_equal data, bin.data, "Newly assigned data differs from original" bin.save! - assert_equal data, bin.data, 'Data differs from original after save' + assert_equal data, bin.data, "Data differs from original after save" - assert_equal data, bin.reload.data, 'Reloaded data differs from original' + assert_equal data, bin.reload.data, "Reloaded data differs from original" end end end diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb index fa924fe4cb..98d202dd79 100644 --- a/activerecord/test/cases/bind_parameter_test.rb +++ b/activerecord/test/cases/bind_parameter_test.rb @@ -1,7 +1,7 @@ -require 'cases/helper' -require 'models/topic' -require 'models/author' -require 'models/post' +require "cases/helper" +require "models/topic" +require "models/author" +require "models/post" module ActiveRecord class BindParameterTest < ActiveRecord::TestCase @@ -24,7 +24,7 @@ module ActiveRecord @connection = ActiveRecord::Base.connection @subscriber = LogListener.new @pk = Topic.columns_hash[Topic.primary_key] - @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber) + @subscription = ActiveSupport::Notifications.subscribe("sql.active_record", @subscriber) end teardown do @@ -34,8 +34,8 @@ module ActiveRecord if ActiveRecord::Base.connection.supports_statement_cache? && ActiveRecord::Base.connection.prepared_statements def test_bind_from_join_in_subquery - subquery = Author.joins(:thinking_posts).where(name: 'David') - scope = Author.from(subquery, 'authors').where(id: 1) + subquery = Author.joins(:thinking_posts).where(name: "David") + scope = Author.from(subquery, "authors").where(id: 1) assert_equal 1, scope.count end @@ -44,7 +44,7 @@ module ActiveRecord binds = [Relation::QueryAttribute.new("id", 1, Type::Value.new)] sql = "select * from topics where id = #{sub.to_sql}" - @connection.exec_query(sql, 'SQL', binds) + @connection.exec_query(sql, "SQL", binds) message = @subscriber.calls.find { |args| args[4][:sql] == sql } assert_equal binds, message[4][:binds] @@ -53,17 +53,20 @@ module ActiveRecord def test_find_one_uses_binds Topic.find(1) message = @subscriber.calls.find { |args| args[4][:binds].any? { |attr| attr.value == 1 } } - assert message, 'expected a message with binds' + assert message, "expected a message with binds" end def test_logs_bind_vars_after_type_cast + binds = [Relation::QueryAttribute.new("id", "10", Type::Integer.new)] + type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } payload = { - :name => 'SQL', - :sql => 'select * from topics where id = ?', - :binds => [Relation::QueryAttribute.new("id", "10", Type::Integer.new)] + name: "SQL", + sql: "select * from topics where id = ?", + binds: binds, + type_casted_binds: type_casted_binds } event = ActiveSupport::Notifications::Event.new( - 'foo', + "foo", Time.now, Time.now, 123, @@ -76,7 +79,7 @@ module ActiveRecord @debugs = [] end - def debug str + def debug(str) @debugs << str end }.new @@ -84,6 +87,12 @@ module ActiveRecord logger.sql event assert_match([[@pk.name, 10]].inspect, logger.debugs.first) end + + private + + def type_cast(value) + ActiveRecord::Base.connection.type_cast(value) + end end end end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index cfae700159..db2871d383 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -1,23 +1,24 @@ require "cases/helper" -require 'models/club' -require 'models/company' +require "models/book" +require "models/club" +require "models/company" require "models/contract" -require 'models/edge' -require 'models/organization' -require 'models/possession' -require 'models/topic' -require 'models/reply' -require 'models/minivan' -require 'models/speedometer' -require 'models/ship_part' -require 'models/treasure' -require 'models/developer' -require 'models/comment' -require 'models/rating' -require 'models/post' +require "models/edge" +require "models/organization" +require "models/possession" +require "models/topic" +require "models/reply" +require "models/minivan" +require "models/speedometer" +require "models/ship_part" +require "models/treasure" +require "models/developer" +require "models/comment" +require "models/rating" +require "models/post" class NumericData < ActiveRecord::Base - self.table_name = 'numeric_data' + self.table_name = "numeric_data" attribute :world_population, :integer attribute :my_house_population, :integer @@ -25,7 +26,7 @@ class NumericData < ActiveRecord::Base end class CalculationsTest < ActiveRecord::TestCase - fixtures :companies, :accounts, :topics, :speedometers, :minivans + fixtures :companies, :accounts, :topics, :speedometers, :minivans, :books def test_should_sum_field assert_equal 318, Account.sum(:credit_limit) @@ -56,7 +57,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_return_integer_average_if_db_returns_such ShipPart.delete_all - ShipPart.create!(:id => 3, :name => 'foo') + ShipPart.create!(id: 3, name: "foo") value = ShipPart.average(:id) assert_equal 3, value end @@ -92,24 +93,24 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_group_by_field c = Account.group(:firm_id).sum(:credit_limit) [1,6,2].each do |firm_id| - assert c.keys.include?(firm_id), "Group #{c.inspect} does not contain firm_id #{firm_id}" + assert_includes c.keys, firm_id, "Group #{c.inspect} does not contain firm_id #{firm_id}" end end def test_should_group_by_arel_attribute c = Account.group(Account.arel_table[:firm_id]).sum(:credit_limit) [1,6,2].each do |firm_id| - assert c.keys.include?(firm_id), "Group #{c.inspect} does not contain firm_id #{firm_id}" + assert_includes c.keys, firm_id, "Group #{c.inspect} does not contain firm_id #{firm_id}" end end def test_should_group_by_multiple_fields - c = Account.group('firm_id', :credit_limit).count(:all) - [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) } + c = Account.group("firm_id", :credit_limit).count(:all) + [ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert_includes c.keys, firm_and_limit } end def test_should_group_by_multiple_fields_having_functions - c = Topic.group(:author_name, 'COALESCE(type, title)').count(:all) + c = Topic.group(:author_name, "COALESCE(type, title)").count(:all) assert_equal 1, c[["Carl", "The Third Topic of the day"]] assert_equal 1, c[["Mary", "Reply"]] assert_equal 1, c[["David", "The First Topic"]] @@ -165,14 +166,14 @@ class CalculationsTest < ActiveRecord::TestCase end def test_limit_should_apply_before_count - accounts = Account.limit(3).where('firm_id IS NOT NULL') + accounts = Account.limit(3).where("firm_id IS NOT NULL") assert_equal 3, accounts.count(:firm_id) assert_equal 3, accounts.select(:firm_id).count end def test_limit_should_apply_before_count_arel_attribute - accounts = Account.limit(3).where('firm_id IS NOT NULL') + accounts = Account.limit(3).where("firm_id IS NOT NULL") firm_id_attribute = Account.arel_table[:firm_id] assert_equal 3, accounts.count(firm_id_attribute) @@ -227,7 +228,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_group_by_summed_field_having_condition - c = Account.group(:firm_id).having('sum(credit_limit) > 50').sum(:credit_limit) + c = Account.group(:firm_id).having("sum(credit_limit) > 50").sum(:credit_limit) assert_nil c[1] assert_equal 105, c[6] assert_equal 60, c[2] @@ -248,52 +249,52 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_sum_field_with_conditions - assert_equal 105, Account.where('firm_id = 6').sum(:credit_limit) + assert_equal 105, Account.where("firm_id = 6").sum(:credit_limit) end def test_should_return_zero_if_sum_conditions_return_nothing - assert_equal 0, Account.where('1 = 2').sum(:credit_limit) - assert_equal 0, companies(:rails_core).companies.where('1 = 2').sum(:id) + assert_equal 0, Account.where("1 = 2").sum(:credit_limit) + assert_equal 0, companies(:rails_core).companies.where("1 = 2").sum(:id) end def test_sum_should_return_valid_values_for_decimals - NumericData.create(:bank_balance => 19.83) + NumericData.create(bank_balance: 19.83) assert_equal 19.83, NumericData.sum(:bank_balance) end def test_should_return_type_casted_values_with_group_and_expression - assert_equal 0.5, Account.group(:firm_name).sum('0.01 * credit_limit')['37signals'] + assert_equal 0.5, Account.group(:firm_name).sum("0.01 * credit_limit")["37signals"] end def test_should_group_by_summed_field_with_conditions - c = Account.where('firm_id > 1').group(:firm_id).sum(:credit_limit) + c = Account.where("firm_id > 1").group(:firm_id).sum(:credit_limit) assert_nil c[1] assert_equal 105, c[6] assert_equal 60, c[2] end def test_should_group_by_summed_field_with_conditions_and_having - c = Account.where('firm_id > 1').group(:firm_id). - having('sum(credit_limit) > 60').sum(:credit_limit) + c = Account.where("firm_id > 1").group(:firm_id). + having("sum(credit_limit) > 60").sum(:credit_limit) assert_nil c[1] assert_equal 105, c[6] assert_nil c[2] end def test_should_group_by_fields_with_table_alias - c = Account.group('accounts.firm_id').sum(:credit_limit) + c = Account.group("accounts.firm_id").sum(:credit_limit) assert_equal 50, c[1] assert_equal 105, c[6] assert_equal 60, c[2] end def test_should_calculate_with_invalid_field - assert_equal 6, Account.calculate(:count, '*') + assert_equal 6, Account.calculate(:count, "*") assert_equal 6, Account.calculate(:count, :all) end def test_should_calculate_grouped_with_invalid_field - c = Account.group('accounts.firm_id').count(:all) + c = Account.group("accounts.firm_id").count(:all) assert_equal 1, c[1] assert_equal 2, c[6] assert_equal 1, c[2] @@ -307,8 +308,8 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_group_by_association_with_non_numeric_foreign_key - Speedometer.create! id: 'ABC' - Minivan.create! id: 'OMG', speedometer_id: 'ABC' + Speedometer.create! id: "ABC" + Minivan.create! id: "OMG", speedometer_id: "ABC" c = Minivan.group(:speedometer).count(:all) first_key = c.keys.first @@ -317,7 +318,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_calculate_grouped_association_with_foreign_key_option - Account.belongs_to :another_firm, :class_name => 'Firm', :foreign_key => 'firm_id' + Account.belongs_to :another_firm, class_name: "Firm", foreign_key: "firm_id" c = Account.group(:another_firm).count(:all) assert_equal 1, c[companies(:first_firm)] assert_equal 2, c[companies(:rails_core)] @@ -327,17 +328,17 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_calculate_grouped_by_function c = Company.group("UPPER(#{QUOTED_TYPE})").count(:all) assert_equal 2, c[nil] - assert_equal 1, c['DEPENDENTFIRM'] - assert_equal 5, c['CLIENT'] - assert_equal 2, c['FIRM'] + assert_equal 1, c["DEPENDENTFIRM"] + assert_equal 5, c["CLIENT"] + assert_equal 2, c["FIRM"] end def test_should_calculate_grouped_by_function_with_table_alias c = Company.group("UPPER(companies.#{QUOTED_TYPE})").count(:all) assert_equal 2, c[nil] - assert_equal 1, c['DEPENDENTFIRM'] - assert_equal 5, c['CLIENT'] - assert_equal 2, c['FIRM'] + assert_equal 1, c["DEPENDENTFIRM"] + assert_equal 5, c["CLIENT"] + assert_equal 2, c["FIRM"] end def test_should_not_overshadow_enumerable_sum @@ -353,19 +354,19 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_sum_scoped_field_with_conditions - assert_equal 8, companies(:rails_core).companies.where('id > 7').sum(:id) + assert_equal 8, companies(:rails_core).companies.where("id > 7").sum(:id) end def test_should_group_by_scoped_field c = companies(:rails_core).companies.group(:name).sum(:id) - assert_equal 7, c['Leetsoft'] - assert_equal 8, c['Jadedpixel'] + assert_equal 7, c["Leetsoft"] + assert_equal 8, c["Jadedpixel"] end def test_should_group_by_summed_field_through_association_and_having - c = companies(:rails_core).companies.group(:name).having('sum(id) > 7').sum(:id) - assert_nil c['Leetsoft'] - assert_equal 8, c['Jadedpixel'] + c = companies(:rails_core).companies.group(:name).having("sum(id) > 7").sum(:id) + assert_nil c["Leetsoft"] + assert_equal 8, c["Jadedpixel"] end def test_should_count_selected_field_with_include @@ -380,7 +381,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_perform_joined_include_when_referencing_included_tables - joined_count = Account.includes(:firm).where(:companies => {:name => '37signals'}).count + joined_count = Account.includes(:firm).where(companies: { name: "37signals" }).count assert_equal 1, joined_count end @@ -391,10 +392,10 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_count_scoped_select_with_options Account.update_all("credit_limit = NULL") - Account.last.update_columns('credit_limit' => 49) - Account.first.update_columns('credit_limit' => 51) + Account.last.update_columns("credit_limit" => 49) + Account.first.update_columns("credit_limit" => 51) - assert_equal 1, Account.select("credit_limit").where('credit_limit >= 50').count + assert_equal 1, Account.select("credit_limit").where("credit_limit >= 50").count end def test_should_count_manual_select_with_include @@ -435,8 +436,8 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_count_field_in_joined_table - assert_equal 5, Account.joins(:firm).count('companies.id') - assert_equal 4, Account.joins(:firm).distinct.count('companies.id') + assert_equal 5, Account.joins(:firm).count("companies.id") + assert_equal 4, Account.joins(:firm).distinct.count("companies.id") end def test_count_arel_attribute_in_joined_table_with @@ -450,14 +451,14 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_count_field_in_joined_table_with_group_by - c = Account.group('accounts.firm_id').joins(:firm).count('companies.id') + c = Account.group("accounts.firm_id").joins(:firm).count("companies.id") - [1,6,2,9].each { |firm_id| assert c.keys.include?(firm_id) } + [1,6,2,9].each { |firm_id| assert_includes c.keys, firm_id } end def test_should_count_field_of_root_table_with_conflicting_group_by_column assert_equal({ 1 => 1 }, Firm.joins(:accounts).group(:firm_id).count) - assert_equal({ 1 => 1 }, Firm.joins(:accounts).group('accounts.firm_id').count) + assert_equal({ 1 => 1 }, Firm.joins(:accounts).group("accounts.firm_id").count) end def test_count_with_no_parameters_isnt_deprecated @@ -477,9 +478,9 @@ class CalculationsTest < ActiveRecord::TestCase end def test_count_with_where_and_order - assert_equal 1, Account.where(firm_name: '37signals').count - assert_equal 1, Account.where(firm_name: '37signals').order(:firm_name).count - assert_equal 1, Account.where(firm_name: '37signals').order(:firm_name).reverse_order.count + assert_equal 1, Account.where(firm_name: "37signals").count + assert_equal 1, Account.where(firm_name: "37signals").order(:firm_name).count + assert_equal 1, Account.where(firm_name: "37signals").order(:firm_name).reverse_order.count end def test_count_with_block @@ -496,69 +497,69 @@ class CalculationsTest < ActiveRecord::TestCase end def test_sum_expression_returns_zero_when_no_records_to_sum - assert_equal 0, Account.where('1 = 2').sum("2 * credit_limit") + assert_equal 0, Account.where("1 = 2").sum("2 * credit_limit") end def test_count_with_from_option - assert_equal Company.count(:all), Company.from('companies').count(:all) + assert_equal Company.count(:all), Company.from("companies").count(:all) assert_equal Account.where("credit_limit = 50").count(:all), - Account.from('accounts').where("credit_limit = 50").count(:all) - assert_equal Company.where(:type => "Firm").count(:type), - Company.where(:type => "Firm").from('companies').count(:type) + Account.from("accounts").where("credit_limit = 50").count(:all) + assert_equal Company.where(type: "Firm").count(:type), + Company.where(type: "Firm").from("companies").count(:type) end def test_sum_with_from_option - assert_equal Account.sum(:credit_limit), Account.from('accounts').sum(:credit_limit) + assert_equal Account.sum(:credit_limit), Account.from("accounts").sum(:credit_limit) assert_equal Account.where("credit_limit > 50").sum(:credit_limit), - Account.where("credit_limit > 50").from('accounts').sum(:credit_limit) + Account.where("credit_limit > 50").from("accounts").sum(:credit_limit) end def test_average_with_from_option - assert_equal Account.average(:credit_limit), Account.from('accounts').average(:credit_limit) + assert_equal Account.average(:credit_limit), Account.from("accounts").average(:credit_limit) assert_equal Account.where("credit_limit > 50").average(:credit_limit), - Account.where("credit_limit > 50").from('accounts').average(:credit_limit) + Account.where("credit_limit > 50").from("accounts").average(:credit_limit) end def test_minimum_with_from_option - assert_equal Account.minimum(:credit_limit), Account.from('accounts').minimum(:credit_limit) + assert_equal Account.minimum(:credit_limit), Account.from("accounts").minimum(:credit_limit) assert_equal Account.where("credit_limit > 50").minimum(:credit_limit), - Account.where("credit_limit > 50").from('accounts').minimum(:credit_limit) + Account.where("credit_limit > 50").from("accounts").minimum(:credit_limit) end def test_maximum_with_from_option - assert_equal Account.maximum(:credit_limit), Account.from('accounts').maximum(:credit_limit) + assert_equal Account.maximum(:credit_limit), Account.from("accounts").maximum(:credit_limit) assert_equal Account.where("credit_limit > 50").maximum(:credit_limit), - Account.where("credit_limit > 50").from('accounts').maximum(:credit_limit) + Account.where("credit_limit > 50").from("accounts").maximum(:credit_limit) end def test_maximum_with_not_auto_table_name_prefix_if_column_included - Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) + Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) assert_equal 7, Company.includes(:contracts).maximum(:developer_id) end def test_minimum_with_not_auto_table_name_prefix_if_column_included - Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) + Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) assert_equal 7, Company.includes(:contracts).minimum(:developer_id) end def test_sum_with_not_auto_table_name_prefix_if_column_included - Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) + Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) assert_equal 7, Company.includes(:contracts).sum(:developer_id) end if current_adapter?(:Mysql2Adapter) def test_from_option_with_specified_index - assert_equal Edge.count(:all), Edge.from('edges USE INDEX(unique_edge_index)').count(:all) - assert_equal Edge.where('sink_id < 5').count(:all), - Edge.from('edges USE INDEX(unique_edge_index)').where('sink_id < 5').count(:all) + assert_equal Edge.count(:all), Edge.from("edges USE INDEX(unique_edge_index)").count(:all) + assert_equal Edge.where("sink_id < 5").count(:all), + Edge.from("edges USE INDEX(unique_edge_index)").where("sink_id < 5").count(:all) end end def test_from_option_with_table_different_than_class - assert_equal Account.count(:all), Company.from('accounts').count(:all) + assert_equal Account.count(:all), Company.from("accounts").count(:all) end def test_distinct_is_honored_when_used_with_count_operation_after_group @@ -581,7 +582,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_type_cast topic = topics(:first) - relation = Topic.where(:id => topic.id) + relation = Topic.where(id: topic.id) assert_equal [ topic.approved ], relation.pluck(:approved) assert_equal [ topic.last_read ], relation.pluck(:last_read) assert_equal [ topic.written_on ], relation.pluck(:written_on) @@ -598,12 +599,12 @@ class CalculationsTest < ActiveRecord::TestCase end def test_pluck_on_aliased_attribute - assert_equal 'The First Topic', Topic.order(:id).pluck(:heading).first + assert_equal "The First Topic", Topic.order(:id).pluck(:heading).first end def test_pluck_with_serialization - t = Topic.create!(:content => { :foo => :bar }) - assert_equal [{:foo => :bar}], Topic.where(:id => t.id).pluck(:content) + t = Topic.create!(content: { foo: :bar }) + assert_equal [{ foo: :bar }], Topic.where(id: t.id).pluck(:content) end def test_pluck_with_qualified_column_name @@ -611,29 +612,29 @@ class CalculationsTest < ActiveRecord::TestCase end def test_pluck_auto_table_name_prefix - c = Company.create!(:name => "test", :contracts => [Contract.new]) + c = Company.create!(name: "test", contracts: [Contract.new]) assert_equal [c.id], Company.joins(:contracts).pluck(:id) end def test_pluck_if_table_included - c = Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) + c = Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) assert_equal [c.id], Company.includes(:contracts).where("contracts.id" => c.contracts.first).pluck(:id) end def test_pluck_not_auto_table_name_prefix_if_column_joined - Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) + Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) assert_equal [7], Company.joins(:contracts).pluck(:developer_id) end def test_pluck_with_selection_clause - assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT credit_limit').sort - assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT accounts.credit_limit').sort - assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT(credit_limit)').sort + assert_equal [50, 53, 55, 60], Account.pluck("DISTINCT credit_limit").sort + assert_equal [50, 53, 55, 60], Account.pluck("DISTINCT accounts.credit_limit").sort + assert_equal [50, 53, 55, 60], Account.pluck("DISTINCT(credit_limit)").sort # MySQL returns "SUM(DISTINCT(credit_limit))" as the column name unless # an alias is provided. Without the alias, the column cannot be found # and properly typecast. - assert_equal [50 + 53 + 55 + 60], Account.pluck('SUM(DISTINCT(credit_limit)) as credit_limit') + assert_equal [50 + 53 + 55 + 60], Account.pluck("SUM(DISTINCT(credit_limit)) as credit_limit") end def test_plucks_with_ids @@ -642,11 +643,11 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_with_includes_limit_and_empty_result assert_equal [], Topic.includes(:replies).limit(0).pluck(:id) - assert_equal [], Topic.includes(:replies).limit(1).where('0 = 1').pluck(:id) + assert_equal [], Topic.includes(:replies).limit(1).where("0 = 1").pluck(:id) end def test_pluck_not_auto_table_name_prefix_if_column_included - Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) + Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) ids = Company.includes(:contracts).pluck(:developer_id) assert_equal Company.count, ids.length assert_equal [7], ids.compact @@ -667,12 +668,12 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_with_multiple_columns_and_selection_clause assert_equal [[1, 50], [2, 50], [3, 50], [4, 60], [5, 55], [6, 53]], - Account.pluck('id, credit_limit') + Account.pluck("id, credit_limit") end def test_pluck_with_multiple_columns_and_includes - Company.create!(:name => "test", :contracts => [Contract.new(:developer_id => 7)]) - companies_and_developers = Company.order('companies.id').includes(:contracts).pluck(:name, :developer_id) + Company.create!(name: "test", contracts: [Contract.new(developer_id: 7)]) + companies_and_developers = Company.order("companies.id").includes(:contracts).pluck(:name, :developer_id) assert_equal Company.count, companies_and_developers.length assert_equal ["37signals", nil], companies_and_developers.first @@ -680,7 +681,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_pluck_with_reserved_words - Possession.create!(:where => "Over There") + Possession.create!(where: "Over There") assert_equal ["Over There"], Possession.pluck(:where) end @@ -694,7 +695,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_columns_with_same_name expected = [["The First Topic", "The Second Topic of the day"], ["The Third Topic of the day", "The Fourth Topic of the day"]] actual = Topic.joins(:replies) - .pluck('topics.title', 'replies_topics.title') + .pluck("topics.title", "replies_topics.title") assert_equal expected, actual end @@ -715,21 +716,21 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_loaded_relation companies = Company.order(:id).limit(3).load assert_no_queries do - assert_equal ['37signals', 'Summit', 'Microsoft'], companies.pluck(:name) + assert_equal ["37signals", "Summit", "Microsoft"], companies.pluck(:name) end end def test_pluck_loaded_relation_multiple_columns companies = Company.order(:id).limit(3).load assert_no_queries do - assert_equal [[1, '37signals'], [2, 'Summit'], [3, 'Microsoft']], companies.pluck(:id, :name) + assert_equal [[1, "37signals"], [2, "Summit"], [3, "Microsoft"]], companies.pluck(:id, :name) end end def test_pluck_loaded_relation_sql_fragment companies = Company.order(:name).limit(3).load assert_queries 1 do - assert_equal ['37signals', 'Apex', 'Ex Nihilo'], companies.pluck('DISTINCT name') + assert_equal ["37signals", "Apex", "Ex Nihilo"], companies.pluck("DISTINCT name") end end @@ -747,7 +748,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_reference_correct_aliases_while_joining_tables_of_has_many_through_association assert_nothing_raised do - developer = Developer.create!(name: 'developer') + developer = Developer.create!(name: "developer") developer.ratings.includes(comment: :post).where(posts: { id: 1 }).count end end @@ -782,7 +783,7 @@ class CalculationsTest < ActiveRecord::TestCase end end - params = protected_params.new(credit_limit: '50') + params = protected_params.new(credit_limit: "50") assert_raises(ActiveModel::ForbiddenAttributesError) do Account.group(:id).having(params) @@ -793,4 +794,8 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 50, result[1].credit_limit assert_equal 50, result[2].credit_limit end + + def test_group_by_attribute_with_custom_type + assert_equal({ "proposed" => 2, "published" => 2 }, Book.group(:status).count) + end end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index 4f70ae3a1d..4b517e9d70 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -1,9 +1,9 @@ require "cases/helper" -require 'models/developer' -require 'models/computer' +require "models/developer" +require "models/computer" class CallbackDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" class << self def callback_string(callback_method) @@ -16,7 +16,7 @@ class CallbackDeveloper < ActiveRecord::Base def define_callback_method(callback_method) define_method(callback_method) do - self.history << [callback_method, :method] + history << [callback_method, :method] end send(callback_method, :"#{callback_method}") end @@ -31,7 +31,7 @@ class CallbackDeveloper < ActiveRecord::Base end ActiveRecord::Callbacks::CALLBACKS.each do |callback_method| - next if callback_method.to_s =~ /^around_/ + next if callback_method.to_s.start_with?("around_") define_callback_method(callback_method) ActiveSupport::Deprecation.silence { send(callback_method, callback_string(callback_method)) } send(callback_method, callback_proc(callback_method)) @@ -55,19 +55,18 @@ class CallbackDeveloperWithHaltedValidation < CallbackDeveloper end class ParentDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" attr_accessor :after_save_called - before_validation {|record| record.after_save_called = true} + before_validation { |record| record.after_save_called = true } end class ChildDeveloper < ParentDeveloper - end class ImmutableDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" - validates_inclusion_of :salary, :in => 50000..200000 + validates_inclusion_of :salary, in: 50000..200000 before_save :cancel before_destroy :cancel @@ -79,7 +78,7 @@ class ImmutableDeveloper < ActiveRecord::Base end class DeveloperWithCanceledCallbacks < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" validates_inclusion_of :salary, in: 50000..200000 @@ -93,19 +92,19 @@ class DeveloperWithCanceledCallbacks < ActiveRecord::Base end class OnCallbacksDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" before_validation { history << :before_validation } - before_validation(:on => :create){ history << :before_validation_on_create } - before_validation(:on => :update){ history << :before_validation_on_update } + before_validation(on: :create) { history << :before_validation_on_create } + before_validation(on: :update) { history << :before_validation_on_update } validate do history << :validate end after_validation { history << :after_validation } - after_validation(:on => :create){ history << :after_validation_on_create } - after_validation(:on => :update){ history << :after_validation_on_update } + after_validation(on: :create) { history << :after_validation_on_create } + after_validation(on: :update) { history << :after_validation_on_update } def history @history ||= [] @@ -113,17 +112,17 @@ class OnCallbacksDeveloper < ActiveRecord::Base end class ContextualCallbacksDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" before_validation { history << :before_validation } - before_validation :before_validation_on_create_and_update, :on => [ :create, :update ] + before_validation :before_validation_on_create_and_update, on: [ :create, :update ] validate do history << :validate end after_validation { history << :after_validation } - after_validation :after_validation_on_create_and_update, :on => [ :create, :update ] + after_validation :after_validation_on_create_and_update, on: [ :create, :update ] def before_validation_on_create_and_update history << "before_validation_on_#{self.validation_context}".to_sym @@ -139,12 +138,12 @@ class ContextualCallbacksDeveloper < ActiveRecord::Base end class CallbackCancellationDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" attr_reader :after_save_called, :after_create_called, :after_update_called, :after_destroy_called attr_accessor :cancel_before_save, :cancel_before_create, :cancel_before_update, :cancel_before_destroy - before_save {defined?(@cancel_before_save) ? !@cancel_before_save : false} + before_save { defined?(@cancel_before_save) ? !@cancel_before_save : false } before_create { !@cancel_before_create } before_update { !@cancel_before_update } before_destroy { !@cancel_before_destroy } @@ -156,7 +155,7 @@ class CallbackCancellationDeveloper < ActiveRecord::Base end class CallbackHaltedDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" attr_reader :after_save_called, :after_create_called, :after_update_called, :after_destroy_called attr_accessor :cancel_before_save, :cancel_before_create, :cancel_before_update, :cancel_before_destroy @@ -252,7 +251,7 @@ class CallbacksTest < ActiveRecord::TestCase end def test_create - david = CallbackDeveloper.create('name' => 'David', 'salary' => 1000000) + david = CallbackDeveloper.create("name" => "David", "salary" => 1000000) assert_equal [ [ :after_initialize, :method ], [ :after_initialize, :string ], @@ -298,7 +297,7 @@ class CallbacksTest < ActiveRecord::TestCase end def test_validate_on_create - david = OnCallbacksDeveloper.create('name' => 'David', 'salary' => 1000000) + david = OnCallbacksDeveloper.create("name" => "David", "salary" => 1000000) assert_equal [ :before_validation, :before_validation_on_create, @@ -309,7 +308,7 @@ class CallbacksTest < ActiveRecord::TestCase end def test_validate_on_contextual_create - david = ContextualCallbacksDeveloper.create('name' => 'David', 'salary' => 1000000) + david = ContextualCallbacksDeveloper.create("name" => "David", "salary" => 1000000) assert_equal [ :before_validation, :before_validation_on_create, @@ -632,5 +631,4 @@ class CallbacksTest < ActiveRecord::TestCase child.save assert child.after_save_called end - end diff --git a/activerecord/test/cases/clone_test.rb b/activerecord/test/cases/clone_test.rb index 5e43082c33..b89294c094 100644 --- a/activerecord/test/cases/clone_test.rb +++ b/activerecord/test/cases/clone_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'models/topic' +require "models/topic" module ActiveRecord class CloneTest < ActiveRecord::TestCase @@ -8,9 +8,9 @@ module ActiveRecord def test_persisted topic = Topic.first cloned = topic.clone - assert topic.persisted?, 'topic persisted' - assert cloned.persisted?, 'topic persisted' - assert !cloned.new_record?, 'topic is not new' + assert topic.persisted?, "topic persisted" + assert cloned.persisted?, "topic persisted" + assert !cloned.new_record?, "topic is not new" end def test_stays_frozen @@ -18,16 +18,16 @@ module ActiveRecord topic.freeze cloned = topic.clone - assert cloned.persisted?, 'topic persisted' - assert !cloned.new_record?, 'topic is not new' - assert cloned.frozen?, 'topic should be frozen' + assert cloned.persisted?, "topic persisted" + assert !cloned.new_record?, "topic is not new" + assert cloned.frozen?, "topic should be frozen" end def test_shallow topic = Topic.first cloned = topic.clone - topic.author_name = 'Aaron' - assert_equal 'Aaron', cloned.author_name + topic.author_name = "Aaron" + assert_equal "Aaron", cloned.author_name end def test_freezing_a_cloned_model_does_not_freeze_clone diff --git a/activerecord/test/cases/coders/yaml_column_test.rb b/activerecord/test/cases/coders/yaml_column_test.rb index b72c54f97b..b9c6224425 100644 --- a/activerecord/test/cases/coders/yaml_column_test.rb +++ b/activerecord/test/cases/coders/yaml_column_test.rb @@ -35,7 +35,7 @@ module ActiveRecord def test_returns_string_unless_starts_with_dash coder = YAMLColumn.new - assert_equal 'foo', coder.load("foo") + assert_equal "foo", coder.load("foo") end def test_load_handles_other_classes @@ -45,7 +45,7 @@ module ActiveRecord def test_load_doesnt_swallow_yaml_exceptions coder = YAMLColumn.new - bad_yaml = '--- {' + bad_yaml = "--- {" assert_raises(Psych::SyntaxError) do coder.load(bad_yaml) end diff --git a/activerecord/test/cases/column_alias_test.rb b/activerecord/test/cases/column_alias_test.rb index 40707d9cb2..9893ba9580 100644 --- a/activerecord/test/cases/column_alias_test.rb +++ b/activerecord/test/cases/column_alias_test.rb @@ -1,17 +1,17 @@ require "cases/helper" -require 'models/topic' +require "models/topic" class TestColumnAlias < ActiveRecord::TestCase fixtures :topics - QUERY = if 'Oracle' == ActiveRecord::Base.connection.adapter_name - 'SELECT id AS pk FROM topics WHERE ROWNUM < 2' - else - 'SELECT id AS pk FROM topics' - end + QUERY = if "Oracle" == ActiveRecord::Base.connection.adapter_name + "SELECT id AS pk FROM topics WHERE ROWNUM < 2" + else + "SELECT id AS pk FROM topics" + end def test_column_alias records = Topic.connection.select_all(QUERY) - assert_equal 'pk', records[0].keys[0] + assert_equal "pk", records[0].keys[0] end end diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index 81162b7e98..a65bb89052 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -6,7 +6,7 @@ module ActiveRecord def setup @adapter = AbstractAdapter.new(nil) def @adapter.native_database_types - {:string => "varchar"} + { string: "varchar" } end @viz = @adapter.schema_creation end @@ -18,7 +18,7 @@ module ActiveRecord column_def = ColumnDefinition.new( column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) - assert_equal "title varchar(20)", @viz.accept(column_def) + assert_equal "title varchar(20)", @viz.accept(column_def) end def test_should_include_default_clause_when_default_is_present @@ -26,7 +26,7 @@ module ActiveRecord column_def = ColumnDefinition.new( column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) - assert_equal %Q{title varchar(20) DEFAULT 'Hello'}, @viz.accept(column_def) + assert_equal "title varchar(20) DEFAULT 'Hello'", @viz.accept(column_def) end def test_should_specify_not_null_if_null_option_is_false @@ -35,7 +35,7 @@ module ActiveRecord column_def = ColumnDefinition.new( column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) - assert_equal %Q{title varchar(20) DEFAULT 'Hello' NOT NULL}, @viz.accept(column_def) + assert_equal "title varchar(20) DEFAULT 'Hello' NOT NULL", @viz.accept(column_def) end if current_adapter?(:Mysql2Adapter) @@ -60,21 +60,13 @@ module ActiveRecord end def test_should_not_set_default_for_blob_and_text_data_types - assert_raise ArgumentError do - MySQL::Column.new("title", "a", SqlTypeMetadata.new(sql_type: "blob")) - end - - text_type = MySQL::TypeMetadata.new( - SqlTypeMetadata.new(type: :text)) - assert_raise ArgumentError do - MySQL::Column.new("title", "Hello", text_type) - end + text_type = MySQL::TypeMetadata.new(SqlTypeMetadata.new(type: :text)) text_column = MySQL::Column.new("title", nil, text_type) - assert_equal nil, text_column.default + assert_nil text_column.default not_null_text_column = MySQL::Column.new("title", nil, text_type, false) - assert_equal "", not_null_text_column.default + assert_nil not_null_text_column.default end def test_has_default_should_return_false_for_blob_and_text_data_types diff --git a/activerecord/test/cases/comment_test.rb b/activerecord/test/cases/comment_test.rb index 839fdbe578..262ad319be 100644 --- a/activerecord/test/cases/comment_test.rb +++ b/activerecord/test/cases/comment_test.rb @@ -1,139 +1,139 @@ -require 'cases/helper' -require 'support/schema_dumping_helper' +require "cases/helper" +require "support/schema_dumping_helper" if ActiveRecord::Base.connection.supports_comments? -class CommentTest < ActiveRecord::TestCase - include SchemaDumpingHelper + class CommentTest < ActiveRecord::TestCase + include SchemaDumpingHelper - class Commented < ActiveRecord::Base - self.table_name = 'commenteds' - end - - class BlankComment < ActiveRecord::Base - end - - setup do - @connection = ActiveRecord::Base.connection - - @connection.create_table('commenteds', comment: 'A table with comment', force: true) do |t| - t.string 'name', comment: 'Comment should help clarify the column purpose' - t.boolean 'obvious', comment: 'Question is: should you comment obviously named objects?' - t.string 'content' - t.index 'name', comment: %Q["Very important" index that powers all the performance.\nAnd it's fun!] + class Commented < ActiveRecord::Base + self.table_name = "commenteds" end - @connection.create_table('blank_comments', comment: ' ', force: true) do |t| - t.string :space_comment, comment: ' ' - t.string :empty_comment, comment: '' - t.string :nil_comment, comment: nil - t.string :absent_comment - t.index :space_comment, comment: ' ' - t.index :empty_comment, comment: '' - t.index :nil_comment, comment: nil - t.index :absent_comment + class BlankComment < ActiveRecord::Base end - Commented.reset_column_information - BlankComment.reset_column_information - end - - teardown do - @connection.drop_table 'commenteds', if_exists: true - @connection.drop_table 'blank_comments', if_exists: true - end + setup do + @connection = ActiveRecord::Base.connection + + @connection.create_table("commenteds", comment: "A table with comment", force: true) do |t| + t.string "name", comment: "Comment should help clarify the column purpose" + t.boolean "obvious", comment: "Question is: should you comment obviously named objects?" + t.string "content" + t.index "name", comment: %Q["Very important" index that powers all the performance.\nAnd it's fun!] + end + + @connection.create_table("blank_comments", comment: " ", force: true) do |t| + t.string :space_comment, comment: " " + t.string :empty_comment, comment: "" + t.string :nil_comment, comment: nil + t.string :absent_comment + t.index :space_comment, comment: " " + t.index :empty_comment, comment: "" + t.index :nil_comment, comment: nil + t.index :absent_comment + end + + Commented.reset_column_information + BlankComment.reset_column_information + end - def test_column_created_in_block - column = Commented.columns_hash['name'] - assert_equal :string, column.type - assert_equal 'Comment should help clarify the column purpose', column.comment - end + teardown do + @connection.drop_table "commenteds", if_exists: true + @connection.drop_table "blank_comments", if_exists: true + end - def test_blank_columns_created_in_block - %w[ space_comment empty_comment nil_comment absent_comment ].each do |field| - column = BlankComment.columns_hash[field] + def test_column_created_in_block + column = Commented.columns_hash["name"] assert_equal :string, column.type - assert_nil column.comment + assert_equal "Comment should help clarify the column purpose", column.comment end - end - def test_blank_indexes_created_in_block - @connection.indexes('blank_comments').each do |index| - assert_nil index.comment + def test_blank_columns_created_in_block + %w[ space_comment empty_comment nil_comment absent_comment ].each do |field| + column = BlankComment.columns_hash[field] + assert_equal :string, column.type + assert_nil column.comment + end end - end - def test_add_column_with_comment_later - @connection.add_column :commenteds, :rating, :integer, comment: 'I am running out of imagination' - Commented.reset_column_information - column = Commented.columns_hash['rating'] + def test_blank_indexes_created_in_block + @connection.indexes("blank_comments").each do |index| + assert_nil index.comment + end + end - assert_equal :integer, column.type - assert_equal 'I am running out of imagination', column.comment - end + def test_add_column_with_comment_later + @connection.add_column :commenteds, :rating, :integer, comment: "I am running out of imagination" + Commented.reset_column_information + column = Commented.columns_hash["rating"] - def test_add_index_with_comment_later - @connection.add_index :commenteds, :obvious, name: 'idx_obvious', comment: 'We need to see obvious comments' - index = @connection.indexes('commenteds').find { |idef| idef.name == 'idx_obvious' } - assert_equal 'We need to see obvious comments', index.comment - end + assert_equal :integer, column.type + assert_equal "I am running out of imagination", column.comment + end - def test_add_comment_to_column - @connection.change_column :commenteds, :content, :string, comment: 'Whoa, content describes itself!' + def test_add_index_with_comment_later + @connection.add_index :commenteds, :obvious, name: "idx_obvious", comment: "We need to see obvious comments" + index = @connection.indexes("commenteds").find { |idef| idef.name == "idx_obvious" } + assert_equal "We need to see obvious comments", index.comment + end - Commented.reset_column_information - column = Commented.columns_hash['content'] + def test_add_comment_to_column + @connection.change_column :commenteds, :content, :string, comment: "Whoa, content describes itself!" - assert_equal :string, column.type - assert_equal 'Whoa, content describes itself!', column.comment - end + Commented.reset_column_information + column = Commented.columns_hash["content"] - def test_remove_comment_from_column - @connection.change_column :commenteds, :obvious, :string, comment: nil + assert_equal :string, column.type + assert_equal "Whoa, content describes itself!", column.comment + end - Commented.reset_column_information - column = Commented.columns_hash['obvious'] + def test_remove_comment_from_column + @connection.change_column :commenteds, :obvious, :string, comment: nil - assert_equal :string, column.type - assert_nil column.comment - end + Commented.reset_column_information + column = Commented.columns_hash["obvious"] - def test_schema_dump_with_comments - # Do all the stuff from other tests - @connection.add_column :commenteds, :rating, :integer, comment: 'I am running out of imagination' - @connection.change_column :commenteds, :content, :string, comment: 'Whoa, content describes itself!' - @connection.change_column :commenteds, :obvious, :string, comment: nil - @connection.add_index :commenteds, :obvious, name: 'idx_obvious', comment: 'We need to see obvious comments' - - # And check that these changes are reflected in dump - output = dump_table_schema 'commenteds' - assert_match %r[create_table "commenteds",.+\s+comment: "A table with comment"], output - assert_match %r[t\.string\s+"name",\s+comment: "Comment should help clarify the column purpose"], output - assert_match %r[t\.string\s+"obvious"\n], output - assert_match %r[t\.string\s+"content",\s+comment: "Whoa, content describes itself!"], output - assert_match %r[t\.integer\s+"rating",\s+comment: "I am running out of imagination"], output - assert_match %r[t\.index\s+.+\s+comment: "\\\"Very important\\\" index that powers all the performance.\\nAnd it's fun!"], output - assert_match %r[t\.index\s+.+\s+name: "idx_obvious",.+\s+comment: "We need to see obvious comments"], output - end + assert_equal :string, column.type + assert_nil column.comment + end - def test_schema_dump_omits_blank_comments - output = dump_table_schema 'blank_comments' + def test_schema_dump_with_comments + # Do all the stuff from other tests + @connection.add_column :commenteds, :rating, :integer, comment: "I am running out of imagination" + @connection.change_column :commenteds, :content, :string, comment: "Whoa, content describes itself!" + @connection.change_column :commenteds, :obvious, :string, comment: nil + @connection.add_index :commenteds, :obvious, name: "idx_obvious", comment: "We need to see obvious comments" + + # And check that these changes are reflected in dump + output = dump_table_schema "commenteds" + assert_match %r[create_table "commenteds",.+\s+comment: "A table with comment"], output + assert_match %r[t\.string\s+"name",\s+comment: "Comment should help clarify the column purpose"], output + assert_match %r[t\.string\s+"obvious"\n], output + assert_match %r[t\.string\s+"content",\s+comment: "Whoa, content describes itself!"], output + assert_match %r[t\.integer\s+"rating",\s+comment: "I am running out of imagination"], output + assert_match %r[t\.index\s+.+\s+comment: "\\\"Very important\\\" index that powers all the performance.\\nAnd it's fun!"], output + assert_match %r[t\.index\s+.+\s+name: "idx_obvious",.+\s+comment: "We need to see obvious comments"], output + end - assert_match %r[create_table "blank_comments"], output - assert_no_match %r[create_table "blank_comments",.+comment:], output + def test_schema_dump_omits_blank_comments + output = dump_table_schema "blank_comments" - assert_match %r[t\.string\s+"space_comment"\n], output - assert_no_match %r[t\.string\s+"space_comment", comment:\n], output + assert_match %r[create_table "blank_comments"], output + assert_no_match %r[create_table "blank_comments",.+comment:], output - assert_match %r[t\.string\s+"empty_comment"\n], output - assert_no_match %r[t\.string\s+"empty_comment", comment:\n], output + assert_match %r[t\.string\s+"space_comment"\n], output + assert_no_match %r[t\.string\s+"space_comment", comment:\n], output - assert_match %r[t\.string\s+"nil_comment"\n], output - assert_no_match %r[t\.string\s+"nil_comment", comment:\n], output + assert_match %r[t\.string\s+"empty_comment"\n], output + assert_no_match %r[t\.string\s+"empty_comment", comment:\n], output - assert_match %r[t\.string\s+"absent_comment"\n], output - assert_no_match %r[t\.string\s+"absent_comment", comment:\n], output + assert_match %r[t\.string\s+"nil_comment"\n], output + assert_no_match %r[t\.string\s+"nil_comment", comment:\n], output + + assert_match %r[t\.string\s+"absent_comment"\n], output + assert_no_match %r[t\.string\s+"absent_comment", comment:\n], output + end end -end end diff --git a/activerecord/test/cases/connection_adapters/adapter_leasing_test.rb b/activerecord/test/cases/connection_adapters/adapter_leasing_test.rb index c7ca428ab7..64189381cb 100644 --- a/activerecord/test/cases/connection_adapters/adapter_leasing_test.rb +++ b/activerecord/test/cases/connection_adapters/adapter_leasing_test.rb @@ -17,23 +17,23 @@ module ActiveRecord end def test_in_use? - assert_not @adapter.in_use?, 'adapter is not in use' - assert @adapter.lease, 'lease adapter' - assert @adapter.in_use?, 'adapter is in use' + assert_not @adapter.in_use?, "adapter is not in use" + assert @adapter.lease, "lease adapter" + assert @adapter.in_use?, "adapter is in use" end def test_lease_twice - assert @adapter.lease, 'should lease adapter' + assert @adapter.lease, "should lease adapter" assert_raises(ActiveRecordError) do @adapter.lease end end def test_expire_mutates_in_use - assert @adapter.lease, 'lease adapter' - assert @adapter.in_use?, 'adapter is in use' + assert @adapter.lease, "lease adapter" + assert @adapter.in_use?, "adapter is in use" @adapter.expire - assert_not @adapter.in_use?, 'adapter is in use' + assert_not @adapter.in_use?, "adapter is in use" end def test_close diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb index a019cc6490..d5d16e7568 100644 --- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb @@ -6,18 +6,18 @@ module ActiveRecord def setup @handler = ConnectionHandler.new @spec_name = "primary" - @pool = @handler.establish_connection(ActiveRecord::Base.configurations['arunit']) + @pool = @handler.establish_connection(ActiveRecord::Base.configurations["arunit"]) end def test_establish_connection_uses_spec_name - config = {"readonly" => {"adapter" => 'sqlite3'}} + config = { "readonly" => { "adapter" => "sqlite3" } } resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(config) spec = resolver.spec(:readonly) @handler.establish_connection(spec.to_hash) - assert_not_nil @handler.retrieve_connection_pool('readonly') + assert_not_nil @handler.retrieve_connection_pool("readonly") ensure - @handler.remove_connection('readonly') + @handler.remove_connection("readonly") end def test_retrieve_connection @@ -68,7 +68,7 @@ module ActiveRecord def test_retrieve_connection_pool_copies_schema_cache_from_ancestor_pool @pool.schema_cache = @pool.connection.schema_cache - @pool.schema_cache.add('posts') + @pool.schema_cache.add("posts") rd, wr = IO.pipe rd.binmode @@ -90,7 +90,7 @@ module ActiveRecord end def test_a_class_using_custom_pool_and_switching_back_to_primary - klass2 = Class.new(Base) { def self.name; 'klass2'; end } + klass2 = Class.new(Base) { def self.name; "klass2"; end } assert_equal klass2.connection.object_id, ActiveRecord::Base.connection.object_id @@ -113,7 +113,7 @@ module ActiveRecord end def test_remove_connection_should_not_remove_parent - klass2 = Class.new(Base) { def self.name; 'klass2'; end } + klass2 = Class.new(Base) { def self.name; "klass2"; end } klass2.remove_connection refute_nil ActiveRecord::Base.connection.object_id assert_equal klass2.connection.object_id, ActiveRecord::Base.connection.object_id diff --git a/activerecord/test/cases/connection_adapters/connection_specification_test.rb b/activerecord/test/cases/connection_adapters/connection_specification_test.rb index d204fce59f..10a3521c79 100644 --- a/activerecord/test/cases/connection_adapters/connection_specification_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_specification_test.rb @@ -4,7 +4,7 @@ module ActiveRecord module ConnectionAdapters class ConnectionSpecificationTest < ActiveRecord::TestCase def test_dup_deep_copy_config - spec = ConnectionSpecification.new("primary", { :a => :b }, "bar") + spec = ConnectionSpecification.new("primary", { a: :b }, "bar") assert_not_equal(spec.config.object_id, spec.dup.config.object_id) end end diff --git a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb index f25b85e8a7..4bb5c4f2e2 100644 --- a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +++ b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb @@ -24,7 +24,7 @@ module ActiveRecord end def test_resolver_with_database_uri_and_current_env_symbol_key - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:default_env, config) expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost", "name"=>"default_env" } @@ -32,8 +32,8 @@ module ActiveRecord end def test_resolver_with_database_uri_and_current_env_symbol_key_and_rails_env - ENV['DATABASE_URL'] = "postgres://localhost/foo" - ENV['RAILS_ENV'] = "foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" + ENV["RAILS_ENV"] = "foo" config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:foo, config) @@ -42,8 +42,8 @@ module ActiveRecord end def test_resolver_with_database_uri_and_current_env_symbol_key_and_rack_env - ENV['DATABASE_URL'] = "postgres://localhost/foo" - ENV['RACK_ENV'] = "foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" + ENV["RACK_ENV"] = "foo" config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:foo, config) @@ -52,7 +52,7 @@ module ActiveRecord end def test_resolver_with_database_uri_and_known_key - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } } actual = resolve_spec(:production, config) expected = { "adapter"=>"not_postgres", "database"=>"not_foo", "host"=>"localhost", "name"=>"production" } @@ -60,7 +60,7 @@ module ActiveRecord end def test_resolver_with_database_uri_and_unknown_symbol_key - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } assert_raises AdapterNotSpecified do resolve_spec(:production, config) @@ -68,7 +68,7 @@ module ActiveRecord end def test_resolver_with_database_uri_and_supplied_url - ENV['DATABASE_URL'] = "not-postgres://not-localhost/not_foo" + ENV["DATABASE_URL"] = "not-postgres://not-localhost/not_foo" config = { "production" => { "adapter" => "also_not_postgres", "database" => "also_not_foo" } } actual = resolve_spec("postgres://localhost/foo", config) expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } @@ -82,7 +82,7 @@ module ActiveRecord end def test_environment_does_not_exist_in_config_url_does_exist - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" config = { "not_default_env" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_config(config) expect_prod = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } @@ -90,7 +90,7 @@ module ActiveRecord end def test_url_with_hyphenated_scheme - ENV['DATABASE_URL'] = "ibm-db://localhost/foo" + ENV["DATABASE_URL"] = "ibm-db://localhost/foo" config = { "default_env" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } } actual = resolve_spec(:default_env, config) expected = { "adapter"=>"ibm_db", "database"=>"foo", "host"=>"localhost", "name"=>"default_env" } @@ -134,7 +134,7 @@ module ActiveRecord end def test_blank_with_database_url - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" config = {} actual = resolve_config(config) @@ -152,8 +152,8 @@ module ActiveRecord end def test_blank_with_database_url_with_rails_env - ENV['RAILS_ENV'] = "not_production" - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["RAILS_ENV"] = "not_production" + ENV["DATABASE_URL"] = "postgres://localhost/foo" config = {} actual = resolve_config(config) @@ -174,8 +174,8 @@ module ActiveRecord end def test_blank_with_database_url_with_rack_env - ENV['RACK_ENV'] = "not_production" - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["RACK_ENV"] = "not_production" + ENV["DATABASE_URL"] = "postgres://localhost/foo" config = {} actual = resolve_config(config) @@ -196,7 +196,7 @@ module ActiveRecord end def test_database_url_with_ipv6_host_and_port - ENV['DATABASE_URL'] = "postgres://[::1]:5454/foo" + ENV["DATABASE_URL"] = "postgres://[::1]:5454/foo" config = {} actual = resolve_config(config) @@ -208,7 +208,7 @@ module ActiveRecord end def test_url_sub_key_with_database_url - ENV['DATABASE_URL'] = "NOT-POSTGRES://localhost/NOT_FOO" + ENV["DATABASE_URL"] = "NOT-POSTGRES://localhost/NOT_FOO" config = { "default_env" => { "url" => "postgres://localhost/foo" } } actual = resolve_config(config) @@ -222,9 +222,9 @@ module ActiveRecord end def test_merge_no_conflicts_with_database_url - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" - config = {"default_env" => { "pool" => "5" } } + config = { "default_env" => { "pool" => "5" } } actual = resolve_config(config) expected = { "default_env" => { "adapter" => "postgresql", @@ -237,9 +237,9 @@ module ActiveRecord end def test_merge_conflicts_with_database_url - ENV['DATABASE_URL'] = "postgres://localhost/foo" + ENV["DATABASE_URL"] = "postgres://localhost/foo" - config = {"default_env" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } } + config = { "default_env" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } } actual = resolve_config(config) expected = { "default_env" => { "adapter" => "postgresql", diff --git a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb index f2b1d9e4e7..3657b8340d 100644 --- a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb +++ b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb @@ -1,69 +1,69 @@ require "cases/helper" if current_adapter?(:Mysql2Adapter) -module ActiveRecord - module ConnectionAdapters - class MysqlTypeLookupTest < ActiveRecord::TestCase - setup do - @connection = ActiveRecord::Base.connection - end + module ActiveRecord + module ConnectionAdapters + class MysqlTypeLookupTest < ActiveRecord::TestCase + setup do + @connection = ActiveRecord::Base.connection + end - def test_boolean_types - emulate_booleans(true) do - assert_lookup_type :boolean, 'tinyint(1)' - assert_lookup_type :boolean, 'TINYINT(1)' + def test_boolean_types + emulate_booleans(true) do + assert_lookup_type :boolean, "tinyint(1)" + assert_lookup_type :boolean, "TINYINT(1)" + end end - end - def test_string_types - assert_lookup_type :string, "enum('one', 'two', 'three')" - assert_lookup_type :string, "ENUM('one', 'two', 'three')" - assert_lookup_type :string, "set('one', 'two', 'three')" - assert_lookup_type :string, "SET('one', 'two', 'three')" - end + def test_string_types + assert_lookup_type :string, "enum('one', 'two', 'three')" + assert_lookup_type :string, "ENUM('one', 'two', 'three')" + assert_lookup_type :string, "set('one', 'two', 'three')" + assert_lookup_type :string, "SET('one', 'two', 'three')" + end - def test_set_type_with_value_matching_other_type - assert_lookup_type :string, "SET('unicode', '8bit', 'none', 'time')" - end + def test_set_type_with_value_matching_other_type + assert_lookup_type :string, "SET('unicode', '8bit', 'none', 'time')" + end - def test_enum_type_with_value_matching_other_type - assert_lookup_type :string, "ENUM('unicode', '8bit', 'none')" - end + def test_enum_type_with_value_matching_other_type + assert_lookup_type :string, "ENUM('unicode', '8bit', 'none')" + end - def test_binary_types - assert_lookup_type :binary, 'bit' - assert_lookup_type :binary, 'BIT' - end + def test_binary_types + assert_lookup_type :binary, "bit" + assert_lookup_type :binary, "BIT" + end - def test_integer_types - emulate_booleans(false) do - assert_lookup_type :integer, 'tinyint(1)' - assert_lookup_type :integer, 'TINYINT(1)' - assert_lookup_type :integer, 'year' - assert_lookup_type :integer, 'YEAR' + def test_integer_types + emulate_booleans(false) do + assert_lookup_type :integer, "tinyint(1)" + assert_lookup_type :integer, "TINYINT(1)" + assert_lookup_type :integer, "year" + assert_lookup_type :integer, "YEAR" + end end - end - private + private - def assert_lookup_type(type, lookup) - cast_type = @connection.type_map.lookup(lookup) - assert_equal type, cast_type.type - end + def assert_lookup_type(type, lookup) + cast_type = @connection.type_map.lookup(lookup) + assert_equal type, cast_type.type + end - def emulate_booleans(value) - old_emulate_booleans = @connection.emulate_booleans - change_emulate_booleans(value) - yield - ensure - change_emulate_booleans(old_emulate_booleans) - end + def emulate_booleans(value) + old_emulate_booleans = @connection.emulate_booleans + change_emulate_booleans(value) + yield + ensure + change_emulate_booleans(old_emulate_booleans) + end - def change_emulate_booleans(value) - @connection.emulate_booleans = value - @connection.clear_cache! + def change_emulate_booleans(value) + @connection.emulate_booleans = value + @connection.clear_cache! + end end end end end -end diff --git a/activerecord/test/cases/connection_adapters/schema_cache_test.rb b/activerecord/test/cases/connection_adapters/schema_cache_test.rb index db832fe55d..d4459603af 100644 --- a/activerecord/test/cases/connection_adapters/schema_cache_test.rb +++ b/activerecord/test/cases/connection_adapters/schema_cache_test.rb @@ -9,28 +9,28 @@ module ActiveRecord end def test_primary_key - assert_equal 'id', @cache.primary_keys('posts') + assert_equal "id", @cache.primary_keys("posts") end def test_primary_key_for_non_existent_table - assert_nil @cache.primary_keys('omgponies') + assert_nil @cache.primary_keys("omgponies") end def test_caches_columns - columns = @cache.columns('posts') - assert_equal columns, @cache.columns('posts') + columns = @cache.columns("posts") + assert_equal columns, @cache.columns("posts") end def test_caches_columns_hash - columns_hash = @cache.columns_hash('posts') - assert_equal columns_hash, @cache.columns_hash('posts') + columns_hash = @cache.columns_hash("posts") + assert_equal columns_hash, @cache.columns_hash("posts") end def test_clearing - @cache.columns('posts') - @cache.columns_hash('posts') - @cache.data_sources('posts') - @cache.primary_keys('posts') + @cache.columns("posts") + @cache.columns_hash("posts") + @cache.data_sources("posts") + @cache.primary_keys("posts") @cache.clear! @@ -38,23 +38,23 @@ module ActiveRecord end def test_dump_and_load - @cache.columns('posts') - @cache.columns_hash('posts') - @cache.data_sources('posts') - @cache.primary_keys('posts') + @cache.columns("posts") + @cache.columns_hash("posts") + @cache.data_sources("posts") + @cache.primary_keys("posts") @cache = Marshal.load(Marshal.dump(@cache)) - assert_equal 11, @cache.columns('posts').size - assert_equal 11, @cache.columns_hash('posts').size - assert @cache.data_sources('posts') - assert_equal 'id', @cache.primary_keys('posts') + assert_equal 11, @cache.columns("posts").size + assert_equal 11, @cache.columns_hash("posts").size + assert @cache.data_sources("posts") + assert_equal "id", @cache.primary_keys("posts") end def test_table_methods_deprecation - assert_deprecated { assert @cache.table_exists?('posts') } - assert_deprecated { assert @cache.tables('posts') } - assert_deprecated { @cache.clear_table_cache!('posts') } + assert_deprecated { assert @cache.table_exists?("posts") } + assert_deprecated { assert @cache.tables("posts") } + assert_deprecated { @cache.clear_table_cache!("posts") } end end end diff --git a/activerecord/test/cases/connection_adapters/type_lookup_test.rb b/activerecord/test/cases/connection_adapters/type_lookup_test.rb index 3acbafbff4..e2e5445a4e 100644 --- a/activerecord/test/cases/connection_adapters/type_lookup_test.rb +++ b/activerecord/test/cases/connection_adapters/type_lookup_test.rb @@ -1,110 +1,110 @@ require "cases/helper" unless current_adapter?(:PostgreSQLAdapter) # PostgreSQL does not use type strings for lookup -module ActiveRecord - module ConnectionAdapters - class TypeLookupTest < ActiveRecord::TestCase - setup do - @connection = ActiveRecord::Base.connection - end + module ActiveRecord + module ConnectionAdapters + class TypeLookupTest < ActiveRecord::TestCase + setup do + @connection = ActiveRecord::Base.connection + end - def test_boolean_types - assert_lookup_type :boolean, 'boolean' - assert_lookup_type :boolean, 'BOOLEAN' - end + def test_boolean_types + assert_lookup_type :boolean, "boolean" + assert_lookup_type :boolean, "BOOLEAN" + end - def test_string_types - assert_lookup_type :string, 'char' - assert_lookup_type :string, 'varchar' - assert_lookup_type :string, 'VARCHAR' - assert_lookup_type :string, 'varchar(255)' - assert_lookup_type :string, 'character varying' - end + def test_string_types + assert_lookup_type :string, "char" + assert_lookup_type :string, "varchar" + assert_lookup_type :string, "VARCHAR" + assert_lookup_type :string, "varchar(255)" + assert_lookup_type :string, "character varying" + end - def test_binary_types - assert_lookup_type :binary, 'binary' - assert_lookup_type :binary, 'BINARY' - assert_lookup_type :binary, 'blob' - assert_lookup_type :binary, 'BLOB' - end + def test_binary_types + assert_lookup_type :binary, "binary" + assert_lookup_type :binary, "BINARY" + assert_lookup_type :binary, "blob" + assert_lookup_type :binary, "BLOB" + end - def test_text_types - assert_lookup_type :text, 'text' - assert_lookup_type :text, 'TEXT' - assert_lookup_type :text, 'clob' - assert_lookup_type :text, 'CLOB' - end + def test_text_types + assert_lookup_type :text, "text" + assert_lookup_type :text, "TEXT" + assert_lookup_type :text, "clob" + assert_lookup_type :text, "CLOB" + end - def test_date_types - assert_lookup_type :date, 'date' - assert_lookup_type :date, 'DATE' - end + def test_date_types + assert_lookup_type :date, "date" + assert_lookup_type :date, "DATE" + end - def test_time_types - assert_lookup_type :time, 'time' - assert_lookup_type :time, 'TIME' - end + def test_time_types + assert_lookup_type :time, "time" + assert_lookup_type :time, "TIME" + end - def test_datetime_types - assert_lookup_type :datetime, 'datetime' - assert_lookup_type :datetime, 'DATETIME' - assert_lookup_type :datetime, 'timestamp' - assert_lookup_type :datetime, 'TIMESTAMP' - end + def test_datetime_types + assert_lookup_type :datetime, "datetime" + assert_lookup_type :datetime, "DATETIME" + assert_lookup_type :datetime, "timestamp" + assert_lookup_type :datetime, "TIMESTAMP" + end - def test_decimal_types - assert_lookup_type :decimal, 'decimal' - assert_lookup_type :decimal, 'decimal(2,8)' - assert_lookup_type :decimal, 'DECIMAL' - assert_lookup_type :decimal, 'numeric' - assert_lookup_type :decimal, 'numeric(2,8)' - assert_lookup_type :decimal, 'NUMERIC' - assert_lookup_type :decimal, 'number' - assert_lookup_type :decimal, 'number(2,8)' - assert_lookup_type :decimal, 'NUMBER' - end + def test_decimal_types + assert_lookup_type :decimal, "decimal" + assert_lookup_type :decimal, "decimal(2,8)" + assert_lookup_type :decimal, "DECIMAL" + assert_lookup_type :decimal, "numeric" + assert_lookup_type :decimal, "numeric(2,8)" + assert_lookup_type :decimal, "NUMERIC" + assert_lookup_type :decimal, "number" + assert_lookup_type :decimal, "number(2,8)" + assert_lookup_type :decimal, "NUMBER" + end - def test_float_types - assert_lookup_type :float, 'float' - assert_lookup_type :float, 'FLOAT' - assert_lookup_type :float, 'double' - assert_lookup_type :float, 'DOUBLE' - end + def test_float_types + assert_lookup_type :float, "float" + assert_lookup_type :float, "FLOAT" + assert_lookup_type :float, "double" + assert_lookup_type :float, "DOUBLE" + end - def test_integer_types - assert_lookup_type :integer, 'integer' - assert_lookup_type :integer, 'INTEGER' - assert_lookup_type :integer, 'tinyint' - assert_lookup_type :integer, 'smallint' - assert_lookup_type :integer, 'bigint' - end + def test_integer_types + assert_lookup_type :integer, "integer" + assert_lookup_type :integer, "INTEGER" + assert_lookup_type :integer, "tinyint" + assert_lookup_type :integer, "smallint" + assert_lookup_type :integer, "bigint" + end - def test_bigint_limit - cast_type = @connection.type_map.lookup("bigint") - if current_adapter?(:OracleAdapter) - assert_equal 19, cast_type.limit - else - assert_equal 8, cast_type.limit + def test_bigint_limit + cast_type = @connection.type_map.lookup("bigint") + if current_adapter?(:OracleAdapter) + assert_equal 19, cast_type.limit + else + assert_equal 8, cast_type.limit + end end - end - def test_decimal_without_scale - types = %w{decimal(2) decimal(2,0) numeric(2) numeric(2,0) number(2) number(2,0)} - types.each do |type| - cast_type = @connection.type_map.lookup(type) + def test_decimal_without_scale + types = %w{decimal(2) decimal(2,0) numeric(2) numeric(2,0) number(2) number(2,0)} + types.each do |type| + cast_type = @connection.type_map.lookup(type) - assert_equal :decimal, cast_type.type - assert_equal 2, cast_type.cast(2.1) + assert_equal :decimal, cast_type.type + assert_equal 2, cast_type.cast(2.1) + end end - end - private + private - def assert_lookup_type(type, lookup) - cast_type = @connection.type_map.lookup(lookup) - assert_equal type, cast_type.type + def assert_lookup_type(type, lookup) + cast_type = @connection.type_map.lookup(lookup) + assert_equal type, cast_type.type + end end end end end -end diff --git a/activerecord/test/cases/connection_management_test.rb b/activerecord/test/cases/connection_management_test.rb index 1f9b6add7a..d1e946d401 100644 --- a/activerecord/test/cases/connection_management_test.rb +++ b/activerecord/test/cases/connection_management_test.rb @@ -14,7 +14,7 @@ module ActiveRecord def call(env) @calls << env - [200, {}, ['hi mom']] + [200, {}, ["hi mom"]] end end @@ -39,7 +39,7 @@ module ActiveRecord _, _, body = @management.call(@env) bits = [] body.each { |bit| bits << bit } - assert_equal ['hi mom'], bits + assert_equal ["hi mom"], bits end def test_connections_are_cleared_after_body_close @@ -88,10 +88,10 @@ module ActiveRecord end test "doesn't mutate the original response" do - original_response = [200, {}, 'hi'] + original_response = [200, {}, "hi"] app = lambda { |_| original_response } middleware(app).call(@env)[2] - assert_equal 'hi', original_response.last + assert_equal "hi", original_response.last end private @@ -104,7 +104,7 @@ module ActiveRecord def middleware(app) lambda do |env| a, b, c = executor.wrap { app.call(env) } - [a, b, Rack::BodyProxy.new(c) { }] + [a, b, Rack::BodyProxy.new(c) {}] end end end diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index a45ee281c7..d7ff9d6880 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'concurrent/atomic/count_down_latch' +require "concurrent/atomic/count_down_latch" module ActiveRecord module ConnectionAdapters @@ -151,7 +151,7 @@ module ActiveRecord assert_equal 1, active_connections(@pool).size ensure - @pool.connections.each(&:close) + @pool.connections.each { |conn| conn.close if conn.in_use? } end def test_remove_connection @@ -341,6 +341,18 @@ module ActiveRecord end end + def test_connection_notification_is_called + payloads = [] + subscription = ActiveSupport::Notifications.subscribe("!connection.active_record") do |name, started, finished, unique_id, payload| + payloads << payload + end + ActiveRecord::Base.establish_connection :arunit + assert_equal [:config, :connection_id, :spec_name], payloads[0].keys.sort + assert_equal "primary", payloads[0][:spec_name] + ensure + ActiveSupport::Notifications.unsubscribe(subscription) if subscription + end + def test_pool_sets_connection_schema_cache connection = pool.checkout schema_cache = SchemaCache.new connection @@ -383,8 +395,8 @@ module ActiveRecord all_threads_in_new_connection.wait end rescue Timeout::Error - flunk 'pool unable to establish connections concurrently or implementation has ' << - 'changed, this test then needs to patch a different :new_connection method' + flunk "pool unable to establish connections concurrently or implementation has " << + "changed, this test then needs to patch a different :new_connection method" ensure # clean up the threads all_go.count_down @@ -432,6 +444,9 @@ module ActiveRecord Thread.new { @pool.send(group_action_method) }.join # assert connection has been forcefully taken away from us assert_not @pool.active_connection? + + # make a new connection for with_connection to clean up + @pool.connection end end end @@ -504,7 +519,7 @@ module ActiveRecord pool.clear_reloadable_connections unless stuck_thread.join(2) - flunk 'clear_reloadable_connections must not let other connection waiting threads get stuck in queue' + flunk "clear_reloadable_connections must not let other connection waiting threads get stuck in queue" end assert_equal 0, pool.num_waiting_in_queue @@ -512,13 +527,13 @@ module ActiveRecord end private - def with_single_connection_pool - one_conn_spec = ActiveRecord::Base.connection_pool.spec.dup - one_conn_spec.config[:pool] = 1 # this is safe to do, because .dupped ConnectionSpecification also auto-dups its config - yield(pool = ConnectionPool.new(one_conn_spec)) - ensure - pool.disconnect! if pool - end + def with_single_connection_pool + one_conn_spec = ActiveRecord::Base.connection_pool.spec.dup + one_conn_spec.config[:pool] = 1 # this is safe to do, because .dupped ConnectionSpecification also auto-dups its config + yield(pool = ConnectionPool.new(one_conn_spec)) + ensure + pool.disconnect! if pool + end end end end diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb index b30a83d9ce..0f62c73f8f 100644 --- a/activerecord/test/cases/connection_specification/resolver_test.rb +++ b/activerecord/test/cases/connection_specification/resolver_test.rb @@ -14,7 +14,7 @@ module ActiveRecord def test_url_invalid_adapter error = assert_raises(LoadError) do - spec 'ridiculous://foo?encoding=utf8' + spec "ridiculous://foo?encoding=utf8" end assert_match "Could not load 'active_record/connection_adapters/ridiculous_adapter'", error.message @@ -24,36 +24,36 @@ module ActiveRecord # checks that the adapter file can be required in. def test_url_from_environment - spec = resolve :production, 'production' => 'abstract://foo?encoding=utf8' + spec = resolve :production, "production" => "abstract://foo?encoding=utf8" assert_equal({ "adapter" => "abstract", "host" => "foo", "encoding" => "utf8", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_url_sub_key - spec = resolve :production, 'production' => {"url" => 'abstract://foo?encoding=utf8'} + spec = resolve :production, "production" => { "url" => "abstract://foo?encoding=utf8" } assert_equal({ "adapter" => "abstract", "host" => "foo", "encoding" => "utf8", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_url_sub_key_merges_correctly - hash = {"url" => 'abstract://foo?encoding=utf8&', "adapter" => "sqlite3", "host" => "bar", "pool" => "3"} - spec = resolve :production, 'production' => hash + hash = { "url" => "abstract://foo?encoding=utf8&", "adapter" => "sqlite3", "host" => "bar", "pool" => "3" } + spec = resolve :production, "production" => hash assert_equal({ "adapter" => "abstract", "host" => "foo", "encoding" => "utf8", "pool" => "3", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_url_host_no_db - spec = resolve 'abstract://foo?encoding=utf8' + spec = resolve "abstract://foo?encoding=utf8" assert_equal({ "adapter" => "abstract", "host" => "foo", @@ -61,13 +61,13 @@ module ActiveRecord end def test_url_missing_scheme - spec = resolve 'foo' + spec = resolve "foo" assert_equal({ "database" => "foo" }, spec) end def test_url_host_db - spec = resolve 'abstract://foo/bar?encoding=utf8' + spec = resolve "abstract://foo/bar?encoding=utf8" assert_equal({ "adapter" => "abstract", "database" => "bar", @@ -76,7 +76,7 @@ module ActiveRecord end def test_url_port - spec = resolve 'abstract://foo:123?encoding=utf8' + spec = resolve "abstract://foo:123?encoding=utf8" assert_equal({ "adapter" => "abstract", "port" => 123, @@ -85,48 +85,48 @@ module ActiveRecord end def test_encoded_password - password = 'am@z1ng_p@ssw0rd#!' + password = "am@z1ng_p@ssw0rd#!" encoded_password = URI.encode_www_form_component(password) spec = resolve "abstract://foo:#{encoded_password}@localhost/bar" assert_equal password, spec["password"] end def test_url_with_authority_for_sqlite3 - spec = resolve 'sqlite3:///foo_test' - assert_equal('/foo_test', spec["database"]) + spec = resolve "sqlite3:///foo_test" + assert_equal("/foo_test", spec["database"]) end def test_url_absolute_path_for_sqlite3 - spec = resolve 'sqlite3:/foo_test' - assert_equal('/foo_test', spec["database"]) + spec = resolve "sqlite3:/foo_test" + assert_equal("/foo_test", spec["database"]) end def test_url_relative_path_for_sqlite3 - spec = resolve 'sqlite3:foo_test' - assert_equal('foo_test', spec["database"]) + spec = resolve "sqlite3:foo_test" + assert_equal("foo_test", spec["database"]) end def test_url_memory_db_for_sqlite3 - spec = resolve 'sqlite3::memory:' - assert_equal(':memory:', spec["database"]) + spec = resolve "sqlite3::memory:" + assert_equal(":memory:", spec["database"]) end def test_url_sub_key_for_sqlite3 - spec = resolve :production, 'production' => {"url" => 'sqlite3:foo?encoding=utf8'} + spec = resolve :production, "production" => { "url" => "sqlite3:foo?encoding=utf8" } assert_equal({ "adapter" => "sqlite3", "database" => "foo", "encoding" => "utf8", - "name" => "production"}, spec) + "name" => "production" }, spec) end def test_spec_name_on_key_lookup - spec = spec(:readonly, 'readonly' => {'adapter' => 'sqlite3'}) + spec = spec(:readonly, "readonly" => { "adapter" => "sqlite3" }) assert_equal "readonly", spec.name end def test_spec_name_with_inline_config - spec = spec({'adapter' => 'sqlite3'}) + spec = spec("adapter" => "sqlite3") assert_equal "primary", spec.name, "should default to primary id" end end diff --git a/activerecord/test/cases/core_test.rb b/activerecord/test/cases/core_test.rb index 3cb98832c5..3735572898 100644 --- a/activerecord/test/cases/core_test.rb +++ b/activerecord/test/cases/core_test.rb @@ -1,8 +1,8 @@ -require 'cases/helper' -require 'models/person' -require 'models/topic' -require 'pp' -require 'active_support/core_ext/string/strip' +require "cases/helper" +require "models/person" +require "models/topic" +require "pp" +require "active_support/core_ext/string/strip" class NonExistentTable < ActiveRecord::Base; end @@ -10,8 +10,8 @@ class CoreTest < ActiveRecord::TestCase fixtures :topics def test_inspect_class - assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect - assert_equal 'LoosePerson(abstract)', LoosePerson.inspect + assert_equal "ActiveRecord::Base", ActiveRecord::Base.inspect + assert_equal "LoosePerson(abstract)", LoosePerson.inspect assert_match(/^Topic\(id: integer, title: string/, Topic.inspect) end @@ -25,8 +25,8 @@ class CoreTest < ActiveRecord::TestCase end def test_inspect_limited_select_instance - assert_equal %(#<Topic id: 1>), Topic.all.merge!(:select => 'id', :where => 'id = 1').first.inspect - assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.all.merge!(:select => 'id, title', :where => 'id = 1').first.inspect + assert_equal %(#<Topic id: 1>), Topic.all.merge!(select: "id", where: "id = 1").first.inspect + assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.all.merge!(select: "id, title", where: "id = 1").first.inspect end def test_inspect_class_without_table @@ -35,7 +35,7 @@ class CoreTest < ActiveRecord::TestCase def test_pretty_print_new topic = Topic.new - actual = '' + actual = "" PP.pp(topic, StringIO.new(actual)) expected = <<-PRETTY.strip_heredoc #<Topic:0xXXXXXX @@ -58,13 +58,13 @@ class CoreTest < ActiveRecord::TestCase created_at: nil, updated_at: nil> PRETTY - assert actual.start_with?(expected.split('XXXXXX').first) - assert actual.end_with?(expected.split('XXXXXX').last) + assert actual.start_with?(expected.split("XXXXXX").first) + assert actual.end_with?(expected.split("XXXXXX").last) end def test_pretty_print_persisted topic = topics(:first) - actual = '' + actual = "" PP.pp(topic, StringIO.new(actual)) expected = <<-PRETTY.strip_heredoc #<Topic:0x\\w+ @@ -92,11 +92,11 @@ class CoreTest < ActiveRecord::TestCase def test_pretty_print_uninitialized topic = Topic.allocate - actual = '' + actual = "" PP.pp(topic, StringIO.new(actual)) expected = "#<Topic:XXXXXX not initialized>\n" - assert actual.start_with?(expected.split('XXXXXX').first) - assert actual.end_with?(expected.split('XXXXXX').last) + assert actual.start_with?(expected.split("XXXXXX").first) + assert actual.end_with?(expected.split("XXXXXX").last) end def test_pretty_print_overridden_by_inspect @@ -105,7 +105,7 @@ class CoreTest < ActiveRecord::TestCase "inspecting topic" end end - actual = '' + actual = "" PP.pp(subtopic.new, StringIO.new(actual)) assert_equal "inspecting topic\n", actual end diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb index 66b4c3f1ff..84f2c3a465 100644 --- a/activerecord/test/cases/counter_cache_test.rb +++ b/activerecord/test/cases/counter_cache_test.rb @@ -1,30 +1,30 @@ -require 'cases/helper' -require 'models/topic' -require 'models/car' -require 'models/aircraft' -require 'models/wheel' -require 'models/engine' -require 'models/reply' -require 'models/category' -require 'models/categorization' -require 'models/dog' -require 'models/dog_lover' -require 'models/person' -require 'models/friendship' -require 'models/subscriber' -require 'models/subscription' -require 'models/book' +require "cases/helper" +require "models/topic" +require "models/car" +require "models/aircraft" +require "models/wheel" +require "models/engine" +require "models/reply" +require "models/category" +require "models/categorization" +require "models/dog" +require "models/dog_lover" +require "models/person" +require "models/friendship" +require "models/subscriber" +require "models/subscription" +require "models/book" class CounterCacheTest < ActiveRecord::TestCase fixtures :topics, :categories, :categorizations, :cars, :dogs, :dog_lovers, :people, :friendships, :subscribers, :subscriptions, :books class ::SpecialTopic < ::Topic - has_many :special_replies, :foreign_key => 'parent_id' - has_many :lightweight_special_replies, -> { select('topics.id, topics.title') }, :foreign_key => 'parent_id', :class_name => 'SpecialReply' + has_many :special_replies, foreign_key: "parent_id" + has_many :lightweight_special_replies, -> { select("topics.id, topics.title") }, foreign_key: "parent_id", class_name: "SpecialReply" end class ::SpecialReply < ::Reply - belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count' + belongs_to :special_topic, foreign_key: "parent_id", counter_cache: "replies_count" end setup do @@ -32,13 +32,13 @@ class CounterCacheTest < ActiveRecord::TestCase end test "increment counter" do - assert_difference '@topic.reload.replies_count' do + assert_difference "@topic.reload.replies_count" do Topic.increment_counter(:replies_count, @topic.id) end end test "decrement counter" do - assert_difference '@topic.reload.replies_count', -1 do + assert_difference "@topic.reload.replies_count", -1 do Topic.decrement_counter(:replies_count, @topic.id) end end @@ -48,7 +48,7 @@ class CounterCacheTest < ActiveRecord::TestCase Topic.increment_counter(:replies_count, @topic.id) # check that it gets reset - assert_difference '@topic.reload.replies_count', -1 do + assert_difference "@topic.reload.replies_count", -1 do Topic.reset_counters(@topic.id, :replies) end end @@ -58,31 +58,31 @@ class CounterCacheTest < ActiveRecord::TestCase Topic.increment_counter(:replies_count, @topic.id) # check that it gets reset - assert_difference '@topic.reload.replies_count', -1 do + assert_difference "@topic.reload.replies_count", -1 do Topic.reset_counters(@topic.id, :replies_count) end end - test 'reset multiple counters' do + test "reset multiple counters" do Topic.update_counters @topic.id, replies_count: 1, unique_replies_count: 1 - assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], -1 do + assert_difference ["@topic.reload.replies_count", "@topic.reload.unique_replies_count"], -1 do Topic.reset_counters(@topic.id, :replies, :unique_replies) end end test "reset counters with string argument" do - Topic.increment_counter('replies_count', @topic.id) + Topic.increment_counter("replies_count", @topic.id) - assert_difference '@topic.reload.replies_count', -1 do - Topic.reset_counters(@topic.id, 'replies') + assert_difference "@topic.reload.replies_count", -1 do + Topic.reset_counters(@topic.id, "replies") end end test "reset counters with modularized and camelized classnames" do - special = SpecialTopic.create!(:title => 'Special') + special = SpecialTopic.create!(title: "Special") SpecialTopic.increment_counter(:replies_count, special.id) - assert_difference 'special.reload.replies_count', -1 do + assert_difference "special.reload.replies_count", -1 do SpecialTopic.reset_counters(special.id, :special_replies) end end @@ -103,10 +103,10 @@ class CounterCacheTest < ActiveRecord::TestCase DogLover.increment_counter(:bred_dogs_count, david.id) DogLover.increment_counter(:trained_dogs_count, david.id) - assert_difference 'david.reload.bred_dogs_count', -1 do + assert_difference "david.reload.bred_dogs_count", -1 do DogLover.reset_counters(david.id, :bred_dogs) end - assert_difference 'david.reload.trained_dogs_count', -1 do + assert_difference "david.reload.trained_dogs_count", -1 do DogLover.reset_counters(david.id, :trained_dogs) end end @@ -116,26 +116,26 @@ class CounterCacheTest < ActiveRecord::TestCase assert_equal 2, category.categorizations.count assert_nil category.categorizations_count - Category.update_counters(category.id, :categorizations_count => category.categorizations.count) + Category.update_counters(category.id, categorizations_count: category.categorizations.count) assert_equal 2, category.reload.categorizations_count end test "update counter for decrement" do - assert_difference '@topic.reload.replies_count', -3 do - Topic.update_counters(@topic.id, :replies_count => -3) + assert_difference "@topic.reload.replies_count", -3 do + Topic.update_counters(@topic.id, replies_count: -3) end end test "update counters of multiple records" do t1, t2 = topics(:first, :second) - assert_difference ['t1.reload.replies_count', 't2.reload.replies_count'], 2 do - Topic.update_counters([t1.id, t2.id], :replies_count => 2) + assert_difference ["t1.reload.replies_count", "t2.reload.replies_count"], 2 do + Topic.update_counters([t1.id, t2.id], replies_count: 2) end end - test 'update multiple counters' do - assert_difference ['@topic.reload.replies_count', '@topic.reload.unique_replies_count'], 2 do + test "update multiple counters" do + assert_difference ["@topic.reload.replies_count", "@topic.reload.unique_replies_count"], 2 do Topic.update_counters @topic.id, replies_count: 2, unique_replies_count: 2 end end @@ -144,7 +144,7 @@ class CounterCacheTest < ActiveRecord::TestCase david, joanna = dog_lovers(:david, :joanna) joanna = joanna # squelch a warning - assert_difference 'joanna.reload.dogs_count', -1 do + assert_difference "joanna.reload.dogs_count", -1 do david.destroy end end @@ -157,12 +157,12 @@ class CounterCacheTest < ActiveRecord::TestCase end test "reset counter of has_many :through association" do - subscriber = subscribers('second') - Subscriber.reset_counters(subscriber.id, 'books') - Subscriber.increment_counter('books_count', subscriber.id) + subscriber = subscribers("second") + Subscriber.reset_counters(subscriber.id, "books") + Subscriber.increment_counter("books_count", subscriber.id) - assert_difference 'subscriber.reload.books_count', -1 do - Subscriber.reset_counters(subscriber.id, 'books') + assert_difference "subscriber.reload.books_count", -1 do + Subscriber.reset_counters(subscriber.id, "books") end end @@ -174,10 +174,10 @@ class CounterCacheTest < ActiveRecord::TestCase end test "reset counter works with select declared on association" do - special = SpecialTopic.create!(:title => 'Special') + special = SpecialTopic.create!(title: "Special") SpecialTopic.increment_counter(:replies_count, special.id) - assert_difference 'special.reload.replies_count', -1 do + assert_difference "special.reload.replies_count", -1 do SpecialTopic.reset_counters(special.id, :lightweight_special_replies) end end @@ -203,11 +203,11 @@ class CounterCacheTest < ActiveRecord::TestCase test "update counters in a polymorphic relationship" do aircraft = Aircraft.create! - assert_difference 'aircraft.reload.wheels_count' do + assert_difference "aircraft.reload.wheels_count" do aircraft.wheels << Wheel.create! end - assert_difference 'aircraft.reload.wheels_count', -1 do + assert_difference "aircraft.reload.wheels_count", -1 do aircraft.wheels.first.destroy end end diff --git a/activerecord/test/cases/custom_locking_test.rb b/activerecord/test/cases/custom_locking_test.rb index 26d015bf71..15c8b684e4 100644 --- a/activerecord/test/cases/custom_locking_test.rb +++ b/activerecord/test/cases/custom_locking_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'models/person' +require "models/person" module ActiveRecord class CustomLockingTest < ActiveRecord::TestCase @@ -7,9 +7,9 @@ module ActiveRecord def test_custom_lock if current_adapter?(:Mysql2Adapter) - assert_match 'SHARE MODE', Person.lock('LOCK IN SHARE MODE').to_sql + assert_match "SHARE MODE", Person.lock("LOCK IN SHARE MODE").to_sql assert_sql(/LOCK IN SHARE MODE/) do - Person.all.merge!(:lock => 'LOCK IN SHARE MODE').find(1) + Person.all.merge!(lock: "LOCK IN SHARE MODE").find(1) end end end diff --git a/activerecord/test/cases/database_statements_test.rb b/activerecord/test/cases/database_statements_test.rb index 3169408ac0..bb16076fd2 100644 --- a/activerecord/test/cases/database_statements_test.rb +++ b/activerecord/test/cases/database_statements_test.rb @@ -5,6 +5,13 @@ class DatabaseStatementsTest < ActiveRecord::TestCase @connection = ActiveRecord::Base.connection end + unless current_adapter?(:OracleAdapter) + def test_exec_insert + result = @connection.exec_insert("INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)", nil, []) + assert_not_nil @connection.send(:last_inserted_id, result) + end + end + def test_insert_should_return_the_inserted_id assert_not_nil return_the_inserted_id(method: :insert) end @@ -21,14 +28,14 @@ class DatabaseStatementsTest < ActiveRecord::TestCase private - def return_the_inserted_id(method:) - # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method - if current_adapter?(:OracleAdapter) - sequence_name = "accounts_seq" - id_value = @connection.next_sequence_value(sequence_name) - @connection.send(method, "INSERT INTO accounts (id, firm_id,credit_limit) VALUES (accounts_seq.nextval,42,5000)", nil, :id, id_value, sequence_name) - else - @connection.send(method, "INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)") + def return_the_inserted_id(method:) + # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method + if current_adapter?(:OracleAdapter) + sequence_name = "accounts_seq" + id_value = @connection.next_sequence_value(sequence_name) + @connection.send(method, "INSERT INTO accounts (id, firm_id,credit_limit) VALUES (accounts_seq.nextval,42,5000)", nil, :id, id_value, sequence_name) + else + @connection.send(method, "INSERT INTO accounts (firm_id,credit_limit) VALUES (42,5000)") + end end - end end diff --git a/activerecord/test/cases/invalid_date_test.rb b/activerecord/test/cases/date_test.rb index 426a350379..2edc0415cd 100644 --- a/activerecord/test/cases/invalid_date_test.rb +++ b/activerecord/test/cases/date_test.rb @@ -1,7 +1,19 @@ -require 'cases/helper' -require 'models/topic' +require "cases/helper" +require "models/topic" + +class DateTest < ActiveRecord::TestCase + def test_date_with_time_value + time_value = Time.new(2016, 05, 11, 19, 0, 0) + topic = Topic.create(last_read: time_value) + assert_equal topic, Topic.find_by(last_read: time_value) + end + + def test_date_with_string_value + string_value = "2016-05-11 19:00:00" + topic = Topic.create(last_read: string_value) + assert_equal topic, Topic.find_by(last_read: string_value) + end -class InvalidDateTest < ActiveRecord::TestCase def test_assign_valid_dates valid_dates = [[2007, 11, 30], [1993, 2, 28], [2008, 2, 29]] @@ -19,7 +31,7 @@ class InvalidDateTest < ActiveRecord::TestCase invalid_dates.each do |date_src| assert_nothing_raised do - topic = Topic.new({"last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s}) + topic = Topic.new("last_read(1i)" => date_src[0].to_s, "last_read(2i)" => date_src[1].to_s, "last_read(3i)" => date_src[2].to_s) # Oracle DATE columns are datetime columns and Oracle adapter returns Time value if current_adapter?(:OracleAdapter) assert_equal(topic.last_read.to_date, Time.local(*date_src).to_date, "The date should be modified according to the behavior of the Time object") diff --git a/activerecord/test/cases/date_time_precision_test.rb b/activerecord/test/cases/date_time_precision_test.rb index f8664d83bd..a1c3c5af9c 100644 --- a/activerecord/test/cases/date_time_precision_test.rb +++ b/activerecord/test/cases/date_time_precision_test.rb @@ -1,88 +1,87 @@ -require 'cases/helper' -require 'support/schema_dumping_helper' +require "cases/helper" +require "support/schema_dumping_helper" if subsecond_precision_supported? -class DateTimePrecisionTest < ActiveRecord::TestCase - include SchemaDumpingHelper - self.use_transactional_tests = false + class DateTimePrecisionTest < ActiveRecord::TestCase + include SchemaDumpingHelper + self.use_transactional_tests = false - class Foo < ActiveRecord::Base; end + class Foo < ActiveRecord::Base; end - setup do - @connection = ActiveRecord::Base.connection - Foo.reset_column_information - end - - teardown do - @connection.drop_table :foos, if_exists: true - end + setup do + @connection = ActiveRecord::Base.connection + Foo.reset_column_information + end - def test_datetime_data_type_with_precision - @connection.create_table(:foos, force: true) - @connection.add_column :foos, :created_at, :datetime, precision: 0 - @connection.add_column :foos, :updated_at, :datetime, precision: 5 - assert_equal 0, Foo.columns_hash['created_at'].precision - assert_equal 5, Foo.columns_hash['updated_at'].precision - end + teardown do + @connection.drop_table :foos, if_exists: true + end - def test_timestamps_helper_with_custom_precision - @connection.create_table(:foos, force: true) do |t| - t.timestamps precision: 4 + def test_datetime_data_type_with_precision + @connection.create_table(:foos, force: true) + @connection.add_column :foos, :created_at, :datetime, precision: 0 + @connection.add_column :foos, :updated_at, :datetime, precision: 5 + assert_equal 0, Foo.columns_hash["created_at"].precision + assert_equal 5, Foo.columns_hash["updated_at"].precision end - assert_equal 4, Foo.columns_hash['created_at'].precision - assert_equal 4, Foo.columns_hash['updated_at'].precision - end - def test_passing_precision_to_datetime_does_not_set_limit - @connection.create_table(:foos, force: true) do |t| - t.timestamps precision: 4 + def test_timestamps_helper_with_custom_precision + @connection.create_table(:foos, force: true) do |t| + t.timestamps precision: 4 + end + assert_equal 4, Foo.columns_hash["created_at"].precision + assert_equal 4, Foo.columns_hash["updated_at"].precision end - assert_nil Foo.columns_hash['created_at'].limit - assert_nil Foo.columns_hash['updated_at'].limit - end - def test_invalid_datetime_precision_raises_error - assert_raises ActiveRecord::ActiveRecordError do + def test_passing_precision_to_datetime_does_not_set_limit @connection.create_table(:foos, force: true) do |t| - t.timestamps precision: 7 + t.timestamps precision: 4 end + assert_nil Foo.columns_hash["created_at"].limit + assert_nil Foo.columns_hash["updated_at"].limit end - end - def test_formatting_datetime_according_to_precision - @connection.create_table(:foos, force: true) do |t| - t.datetime :created_at, precision: 0 - t.datetime :updated_at, precision: 4 + def test_invalid_datetime_precision_raises_error + assert_raises ActiveRecord::ActiveRecordError do + @connection.create_table(:foos, force: true) do |t| + t.timestamps precision: 7 + end + end end - date = ::Time.utc(2014, 8, 17, 12, 30, 0, 999999) - Foo.create!(created_at: date, updated_at: date) - assert foo = Foo.find_by(created_at: date) - assert_equal 1, Foo.where(updated_at: date).count - assert_equal date.to_s, foo.created_at.to_s - assert_equal date.to_s, foo.updated_at.to_s - assert_equal 000000, foo.created_at.usec - assert_equal 999900, foo.updated_at.usec - end - def test_schema_dump_includes_datetime_precision - @connection.create_table(:foos, force: true) do |t| - t.timestamps precision: 6 + def test_formatting_datetime_according_to_precision + @connection.create_table(:foos, force: true) do |t| + t.datetime :created_at, precision: 0 + t.datetime :updated_at, precision: 4 + end + date = ::Time.utc(2014, 8, 17, 12, 30, 0, 999999) + Foo.create!(created_at: date, updated_at: date) + assert foo = Foo.find_by(created_at: date) + assert_equal 1, Foo.where(updated_at: date).count + assert_equal date.to_s, foo.created_at.to_s + assert_equal date.to_s, foo.updated_at.to_s + assert_equal 000000, foo.created_at.usec + assert_equal 999900, foo.updated_at.usec end - output = dump_table_schema("foos") - assert_match %r{t\.datetime\s+"created_at",\s+precision: 6,\s+null: false$}, output - assert_match %r{t\.datetime\s+"updated_at",\s+precision: 6,\s+null: false$}, output - end - if current_adapter?(:PostgreSQLAdapter) - def test_datetime_precision_with_zero_should_be_dumped + def test_schema_dump_includes_datetime_precision @connection.create_table(:foos, force: true) do |t| - t.timestamps precision: 0 + t.timestamps precision: 6 end output = dump_table_schema("foos") - assert_match %r{t\.datetime\s+"created_at",\s+precision: 0,\s+null: false$}, output - assert_match %r{t\.datetime\s+"updated_at",\s+precision: 0,\s+null: false$}, output + assert_match %r{t\.datetime\s+"created_at",\s+precision: 6,\s+null: false$}, output + assert_match %r{t\.datetime\s+"updated_at",\s+precision: 6,\s+null: false$}, output end - end -end + if current_adapter?(:PostgreSQLAdapter) + def test_datetime_precision_with_zero_should_be_dumped + @connection.create_table(:foos, force: true) do |t| + t.timestamps precision: 0 + end + output = dump_table_schema("foos") + assert_match %r{t\.datetime\s+"created_at",\s+precision: 0,\s+null: false$}, output + assert_match %r{t\.datetime\s+"updated_at",\s+precision: 0,\s+null: false$}, output + end + end + end end diff --git a/activerecord/test/cases/date_time_test.rb b/activerecord/test/cases/date_time_test.rb index 4cbff564aa..3bc08f80ec 100644 --- a/activerecord/test/cases/date_time_test.rb +++ b/activerecord/test/cases/date_time_test.rb @@ -1,12 +1,12 @@ require "cases/helper" -require 'models/topic' -require 'models/task' +require "models/topic" +require "models/task" class DateTimeTest < ActiveRecord::TestCase include InTimeZone def test_saves_both_date_and_time - with_env_tz 'America/New_York' do + with_env_tz "America/New_York" do with_timezone_config default: :utc do time_values = [1807, 2, 10, 15, 30, 45] # create DateTime value with local time zone offset @@ -25,7 +25,7 @@ class DateTimeTest < ActiveRecord::TestCase def test_assign_empty_date_time task = Task.new - task.starting = '' + task.starting = "" task.ending = nil assert_nil task.starting assert_nil task.ending @@ -34,20 +34,20 @@ class DateTimeTest < ActiveRecord::TestCase def test_assign_bad_date_time_with_timezone in_time_zone "Pacific Time (US & Canada)" do task = Task.new - task.starting = '2014-07-01T24:59:59GMT' + task.starting = "2014-07-01T24:59:59GMT" assert_nil task.starting end end def test_assign_empty_date topic = Topic.new - topic.last_read = '' + topic.last_read = "" assert_nil topic.last_read end def test_assign_empty_time topic = Topic.new - topic.bonus_time = '' + topic.bonus_time = "" assert_nil topic.bonus_time end diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index 067513e24c..fcaff38f82 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -1,7 +1,7 @@ require "cases/helper" -require 'support/schema_dumping_helper' -require 'models/default' -require 'models/entrant' +require "support/schema_dumping_helper" +require "models/default" +require "models/entrant" class DefaultTest < ActiveRecord::TestCase def test_nil_defaults_for_not_null_columns @@ -99,7 +99,7 @@ if current_adapter?(:Mysql2Adapter) class MysqlDefaultExpressionTest < ActiveRecord::TestCase include SchemaDumpingHelper - if ActiveRecord::Base.connection.version >= '5.6.0' + if ActiveRecord::Base.connection.version >= "5.6.0" test "schema dump includes default expression" do output = dump_table_schema("datetime_defaults") assert_match %r/t\.datetime\s+"modified_datetime",\s+default: -> { "CURRENT_TIMESTAMP" }/, output @@ -127,92 +127,66 @@ if current_adapter?(:Mysql2Adapter) ActiveRecord::Base.establish_connection connection end - # MySQL cannot have defaults on text/blob columns. It reports the - # default value as null. + # Strict mode controls how MySQL handles invalid or missing values + # in data-change statements such as INSERT or UPDATE. A value can be + # invalid for several reasons. For example, it might have the wrong + # data type for the column, or it might be out of range. A value is + # missing when a new row to be inserted does not contain a value for + # a non-NULL column that has no explicit DEFAULT clause in its definition. + # (For a NULL column, NULL is inserted if the value is missing.) # - # Despite this, in non-strict mode, MySQL will use an empty string - # as the default value of the field, if no other value is - # specified. + # If strict mode is not in effect, MySQL inserts adjusted values for + # invalid or missing values and produces warnings. In strict mode, + # you can produce this behavior by using INSERT IGNORE or UPDATE IGNORE. # - # Therefore, in non-strict mode, we want column.default to report - # an empty string as its default, to be consistent with that. - # - # In strict mode, column.default should be nil. - def test_mysql_text_not_null_defaults_non_strict + # https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-strict + def test_mysql_not_null_defaults_non_strict using_strict(false) do - with_text_blob_not_null_table do |klass| + with_mysql_not_null_table do |klass| record = klass.new - assert_equal '', record.non_null_blob - assert_equal '', record.non_null_text - - assert_nil record.null_blob - assert_nil record.null_text + assert_nil record.non_null_integer + assert_nil record.non_null_string + assert_nil record.non_null_text + assert_nil record.non_null_blob record.save! record.reload - assert_equal '', record.non_null_text - assert_equal '', record.non_null_blob - - assert_nil record.null_text - assert_nil record.null_blob + assert_equal 0, record.non_null_integer + assert_equal "", record.non_null_string + assert_equal "", record.non_null_text + assert_equal "", record.non_null_blob end end end - def test_mysql_text_not_null_defaults_strict + def test_mysql_not_null_defaults_strict using_strict(true) do - with_text_blob_not_null_table do |klass| + with_mysql_not_null_table do |klass| record = klass.new - assert_nil record.non_null_blob + assert_nil record.non_null_integer + assert_nil record.non_null_string assert_nil record.non_null_text - assert_nil record.null_blob - assert_nil record.null_text + assert_nil record.non_null_blob assert_raises(ActiveRecord::StatementInvalid) { klass.create } end end end - def with_text_blob_not_null_table + def with_mysql_not_null_table klass = Class.new(ActiveRecord::Base) - klass.table_name = 'test_mysql_text_not_null_defaults' + klass.table_name = "test_mysql_not_null_defaults" klass.connection.create_table klass.table_name do |t| - t.column :non_null_text, :text, :null => false - t.column :non_null_blob, :blob, :null => false - t.column :null_text, :text, :null => true - t.column :null_blob, :blob, :null => true + t.integer :non_null_integer, null: false + t.string :non_null_string, null: false + t.text :non_null_text, null: false + t.blob :non_null_blob, null: false end yield klass ensure klass.connection.drop_table(klass.table_name) rescue nil end - - # MySQL uses an implicit default 0 rather than NULL unless in strict mode. - # We use an implicit NULL so schema.rb is compatible with other databases. - def test_mysql_integer_not_null_defaults - klass = Class.new(ActiveRecord::Base) - klass.table_name = 'test_integer_not_null_default_zero' - klass.connection.create_table klass.table_name do |t| - t.column :zero, :integer, :null => false, :default => 0 - t.column :omit, :integer, :null => false - end - - assert_equal '0', klass.columns_hash['zero'].default - assert !klass.columns_hash['zero'].null - assert_equal nil, klass.columns_hash['omit'].default - assert !klass.columns_hash['omit'].null - - assert_raise(ActiveRecord::StatementInvalid) { klass.create! } - - assert_nothing_raised do - instance = klass.create!(:omit => 1) - assert_equal 0, instance.zero - assert_equal 1, instance.omit - end - ensure - klass.connection.drop_table(klass.table_name) rescue nil - end end end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index f9794518c7..3bd8475bb0 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -1,12 +1,12 @@ -require 'cases/helper' -require 'models/topic' # For booleans -require 'models/pirate' # For timestamps -require 'models/parrot' -require 'models/person' # For optimistic locking -require 'models/aircraft' +require "cases/helper" +require "models/topic" # For booleans +require "models/pirate" # For timestamps +require "models/parrot" +require "models/person" # For optimistic locking +require "models/aircraft" class NumericData < ActiveRecord::Base - self.table_name = 'numeric_data' + self.table_name = "numeric_data" end class DirtyTest < ActiveRecord::TestCase @@ -14,7 +14,7 @@ class DirtyTest < ActiveRecord::TestCase # Dummy to force column loads so query counts are clean. def setup - Person.create :first_name => 'foo' + Person.create first_name: "foo" end def test_attribute_changes @@ -24,10 +24,10 @@ class DirtyTest < ActiveRecord::TestCase assert_equal false, pirate.non_validated_parrot_id_changed? # Change catchphrase. - pirate.catchphrase = 'arrr' + pirate.catchphrase = "arrr" assert pirate.catchphrase_changed? assert_nil pirate.catchphrase_was - assert_equal [nil, 'arrr'], pirate.catchphrase_change + assert_equal [nil, "arrr"], pirate.catchphrase_change # Saved - no changes. pirate.save! @@ -35,15 +35,15 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.catchphrase_change # Same value - no changes. - pirate.catchphrase = 'arrr' + pirate.catchphrase = "arrr" assert !pirate.catchphrase_changed? assert_nil pirate.catchphrase_change end def test_time_attributes_changes_with_time_zone - in_time_zone 'Paris' do + in_time_zone "Paris" do target = Class.new(ActiveRecord::Base) - target.table_name = 'pirates' + target.table_name = "pirates" # New record - no changes. pirate = target.new @@ -51,7 +51,7 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.created_on_change # Saved - no changes. - pirate.catchphrase = 'arrrr, time zone!!' + pirate.catchphrase = "arrrr, time zone!!" pirate.save! assert !pirate.created_on_changed? assert_nil pirate.created_on_change @@ -68,9 +68,9 @@ class DirtyTest < ActiveRecord::TestCase end def test_setting_time_attributes_with_time_zone_field_to_itself_should_not_be_marked_as_a_change - in_time_zone 'Paris' do + in_time_zone "Paris" do target = Class.new(ActiveRecord::Base) - target.table_name = 'pirates' + target.table_name = "pirates" pirate = target.create! pirate.created_on = pirate.created_on @@ -79,9 +79,9 @@ class DirtyTest < ActiveRecord::TestCase end def test_time_attributes_changes_without_time_zone_by_skip - in_time_zone 'Paris' do + in_time_zone "Paris" do target = Class.new(ActiveRecord::Base) - target.table_name = 'pirates' + target.table_name = "pirates" target.skip_time_zone_conversion_for_attributes = [:created_on] @@ -91,7 +91,7 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.created_on_change # Saved - no changes. - pirate.catchphrase = 'arrrr, time zone!!' + pirate.catchphrase = "arrrr, time zone!!" pirate.save! assert !pirate.created_on_changed? assert_nil pirate.created_on_change @@ -110,7 +110,7 @@ class DirtyTest < ActiveRecord::TestCase def test_time_attributes_changes_without_time_zone with_timezone_config aware_attributes: false do target = Class.new(ActiveRecord::Base) - target.table_name = 'pirates' + target.table_name = "pirates" # New record - no changes. pirate = target.new @@ -118,7 +118,7 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.created_on_change # Saved - no changes. - pirate.catchphrase = 'arrrr, time zone!!' + pirate.catchphrase = "arrrr, time zone!!" pirate.save! assert !pirate.created_on_changed? assert_nil pirate.created_on_change @@ -134,7 +134,6 @@ class DirtyTest < ActiveRecord::TestCase end end - def test_aliased_attribute_changes # the actual attribute here is name, title is an # alias setup via alias_attribute @@ -142,15 +141,15 @@ class DirtyTest < ActiveRecord::TestCase assert !parrot.title_changed? assert_nil parrot.title_change - parrot.name = 'Sam' + parrot.name = "Sam" assert parrot.title_changed? assert_nil parrot.title_was assert_equal parrot.name_change, parrot.title_change end def test_restore_attribute! - pirate = Pirate.create!(:catchphrase => 'Yar!') - pirate.catchphrase = 'Ahoy!' + pirate = Pirate.create!(catchphrase: "Yar!") + pirate.catchphrase = "Ahoy!" pirate.restore_catchphrase! assert_equal "Yar!", pirate.catchphrase @@ -189,9 +188,9 @@ class DirtyTest < ActiveRecord::TestCase end def test_nullable_datetime_not_marked_as_changed_if_new_value_is_blank - in_time_zone 'Edinburgh' do + in_time_zone "Edinburgh" do target = Class.new(ActiveRecord::Base) - target.table_name = 'topics' + target.table_name = "topics" topic = target.create assert_nil topic.written_on @@ -207,19 +206,19 @@ class DirtyTest < ActiveRecord::TestCase def test_integer_zero_to_string_zero_not_marked_as_changed pirate = Pirate.new pirate.parrot_id = 0 - pirate.catchphrase = 'arrr' + pirate.catchphrase = "arrr" assert pirate.save! assert !pirate.changed? - pirate.parrot_id = '0' + pirate.parrot_id = "0" assert !pirate.changed? end def test_integer_zero_to_integer_zero_not_marked_as_changed pirate = Pirate.new pirate.parrot_id = 0 - pirate.catchphrase = 'arrr' + pirate.catchphrase = "arrr" assert pirate.save! assert !pirate.changed? @@ -229,18 +228,18 @@ class DirtyTest < ActiveRecord::TestCase end def test_float_zero_to_string_zero_not_marked_as_changed - data = NumericData.new :temperature => 0.0 + data = NumericData.new temperature: 0.0 data.save! assert_not data.changed? - data.temperature = '0' + data.temperature = "0" assert_empty data.changes - data.temperature = '0.0' + data.temperature = "0.0" assert_empty data.changes - data.temperature = '0.00' + data.temperature = "0.00" assert_empty data.changes end @@ -252,7 +251,7 @@ class DirtyTest < ActiveRecord::TestCase # check the change from 1 to '' pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties") - pirate.parrot_id = '' + pirate.parrot_id = "" assert pirate.parrot_id_changed? assert_equal([1, nil], pirate.parrot_id_change) pirate.save @@ -266,7 +265,7 @@ class DirtyTest < ActiveRecord::TestCase # check the change from 0 to '' pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties") - pirate.parrot_id = '' + pirate.parrot_id = "" assert pirate.parrot_id_changed? assert_equal([0, nil], pirate.parrot_id_change) end @@ -277,11 +276,11 @@ class DirtyTest < ActiveRecord::TestCase assert_equal [], pirate.changed assert_equal Hash.new, pirate.changes - pirate.catchphrase = 'arrr' + pirate.catchphrase = "arrr" assert pirate.changed? assert_nil pirate.catchphrase_was assert_equal %w(catchphrase), pirate.changed - assert_equal({'catchphrase' => [nil, 'arrr']}, pirate.changes) + assert_equal({ "catchphrase" => [nil, "arrr"] }, pirate.changes) pirate.save assert !pirate.changed? @@ -290,21 +289,21 @@ class DirtyTest < ActiveRecord::TestCase end def test_attribute_will_change! - pirate = Pirate.create!(:catchphrase => 'arr') + pirate = Pirate.create!(catchphrase: "arr") assert !pirate.catchphrase_changed? assert pirate.catchphrase_will_change! assert pirate.catchphrase_changed? - assert_equal ['arr', 'arr'], pirate.catchphrase_change + assert_equal ["arr", "arr"], pirate.catchphrase_change - pirate.catchphrase << ' matey!' + pirate.catchphrase << " matey!" assert pirate.catchphrase_changed? - assert_equal ['arr', 'arr matey!'], pirate.catchphrase_change + assert_equal ["arr", "arr matey!"], pirate.catchphrase_change end def test_association_assignment_changes_foreign_key - pirate = Pirate.create!(:catchphrase => 'jarl') - pirate.parrot = Parrot.create!(:name => 'Lorre') + pirate = Pirate.create!(catchphrase: "jarl") + pirate.parrot = Parrot.create!(name: "Lorre") assert pirate.changed? assert_equal %w(parrot_id), pirate.changed end @@ -315,7 +314,7 @@ class DirtyTest < ActiveRecord::TestCase assert !topic.approved_changed? # Coming from web form. - params = {:topic => {:approved => 1}} + params = { topic: { approved: 1 } } # In the controller. topic.attributes = params[:topic] assert topic.approved? @@ -323,37 +322,37 @@ class DirtyTest < ActiveRecord::TestCase end def test_partial_update - pirate = Pirate.new(:catchphrase => 'foo') + pirate = Pirate.new(catchphrase: "foo") old_updated_on = 1.hour.ago.beginning_of_day with_partial_writes Pirate, false do assert_queries(2) { 2.times { pirate.save! } } - Pirate.where(id: pirate.id).update_all(:updated_on => old_updated_on) + Pirate.where(id: pirate.id).update_all(updated_on: old_updated_on) end with_partial_writes Pirate, true do assert_queries(0) { 2.times { pirate.save! } } assert_equal old_updated_on, pirate.reload.updated_on - assert_queries(1) { pirate.catchphrase = 'bar'; pirate.save! } + assert_queries(1) { pirate.catchphrase = "bar"; pirate.save! } assert_not_equal old_updated_on, pirate.reload.updated_on end end def test_partial_update_with_optimistic_locking - person = Person.new(:first_name => 'foo') - old_lock_version = 1 + person = Person.new(first_name: "foo") + old_lock_version = person.lock_version with_partial_writes Person, false do assert_queries(2) { 2.times { person.save! } } - Person.where(id: person.id).update_all(:first_name => 'baz') + Person.where(id: person.id).update_all(first_name: "baz") end with_partial_writes Person, true do assert_queries(0) { 2.times { person.save! } } assert_equal old_lock_version, person.reload.lock_version - assert_queries(1) { person.first_name = 'bar'; person.save! } + assert_queries(1) { person.first_name = "bar"; person.save! } assert_not_equal old_lock_version, person.reload.lock_version end end @@ -371,7 +370,7 @@ class DirtyTest < ActiveRecord::TestCase end def test_reload_should_clear_changed_attributes - pirate = Pirate.create!(:catchphrase => "shiver me timbers") + pirate = Pirate.create!(catchphrase: "shiver me timbers") pirate.catchphrase = "*hic*" assert pirate.changed? pirate.reload @@ -379,7 +378,7 @@ class DirtyTest < ActiveRecord::TestCase end def test_dup_objects_should_not_copy_dirty_flag_from_creator - pirate = Pirate.create!(:catchphrase => "shiver me timbers") + pirate = Pirate.create!(catchphrase: "shiver me timbers") pirate_dup = pirate.dup pirate_dup.restore_catchphrase! pirate.catchphrase = "I love Rum" @@ -389,7 +388,7 @@ class DirtyTest < ActiveRecord::TestCase def test_reverted_changes_are_not_dirty phrase = "shiver me timbers" - pirate = Pirate.create!(:catchphrase => phrase) + pirate = Pirate.create!(catchphrase: phrase) pirate.catchphrase = "*hic*" assert pirate.changed? pirate.catchphrase = phrase @@ -398,7 +397,7 @@ class DirtyTest < ActiveRecord::TestCase def test_reverted_changes_are_not_dirty_after_multiple_changes phrase = "shiver me timbers" - pirate = Pirate.create!(:catchphrase => phrase) + pirate = Pirate.create!(catchphrase: phrase) 10.times do |i| pirate.catchphrase = "*hic*" * i assert pirate.changed? @@ -408,9 +407,8 @@ class DirtyTest < ActiveRecord::TestCase assert !pirate.changed? end - def test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back - pirate = Pirate.create!(:catchphrase => "Yar!") + pirate = Pirate.create!(catchphrase: "Yar!") pirate.parrot_id = 1 assert pirate.changed? @@ -425,7 +423,7 @@ class DirtyTest < ActiveRecord::TestCase def test_save_should_store_serialized_attributes_even_with_partial_writes with_partial_writes(Topic) do - topic = Topic.create!(:content => {:a => "a"}) + topic = Topic.create!(content: { a: "a" }) assert_not topic.changed? @@ -446,25 +444,25 @@ class DirtyTest < ActiveRecord::TestCase def test_save_always_should_update_timestamps_when_serialized_attributes_are_present with_partial_writes(Topic) do - topic = Topic.create!(:content => {:a => "a"}) + topic = Topic.create!(content: { a: "a" }) topic.save! updated_at = topic.updated_at travel(1.second) do - topic.content[:hello] = 'world' + topic.content[:hello] = "world" topic.save! end assert_not_equal updated_at, topic.updated_at - assert_equal 'world', topic.content[:hello] + assert_equal "world", topic.content[:hello] end end def test_save_should_not_save_serialized_attribute_with_partial_writes_if_not_present with_partial_writes(Topic) do - Topic.create!(:author_name => 'Bill', :content => {:a => "a"}) - topic = Topic.select('id, author_name').first - topic.update_columns author_name: 'John' + Topic.create!(author_name: "Bill", content: { a: "a" }) + topic = Topic.select("id, author_name").first + topic.update_columns author_name: "John" topic = Topic.first assert_not_nil topic.content end @@ -479,13 +477,13 @@ class DirtyTest < ActiveRecord::TestCase pirate.save! assert_equal 4, pirate.previous_changes.size - assert_equal [nil, "arrr"], pirate.previous_changes['catchphrase'] - assert_equal [nil, pirate.id], pirate.previous_changes['id'] - assert_nil pirate.previous_changes['updated_on'][0] - assert_not_nil pirate.previous_changes['updated_on'][1] - assert_nil pirate.previous_changes['created_on'][0] - assert_not_nil pirate.previous_changes['created_on'][1] - assert !pirate.previous_changes.key?('parrot_id') + assert_equal [nil, "arrr"], pirate.previous_changes["catchphrase"] + assert_equal [nil, pirate.id], pirate.previous_changes["id"] + assert_nil pirate.previous_changes["updated_on"][0] + assert_not_nil pirate.previous_changes["updated_on"][1] + assert_nil pirate.previous_changes["created_on"][0] + assert_not_nil pirate.previous_changes["created_on"][1] + assert !pirate.previous_changes.key?("parrot_id") # original values should be in previous_changes pirate = Pirate.new @@ -495,11 +493,11 @@ class DirtyTest < ActiveRecord::TestCase pirate.save assert_equal 4, pirate.previous_changes.size - assert_equal [nil, "arrr"], pirate.previous_changes['catchphrase'] - assert_equal [nil, pirate.id], pirate.previous_changes['id'] - assert pirate.previous_changes.include?('updated_on') - assert pirate.previous_changes.include?('created_on') - assert !pirate.previous_changes.key?('parrot_id') + assert_equal [nil, "arrr"], pirate.previous_changes["catchphrase"] + assert_equal [nil, pirate.id], pirate.previous_changes["id"] + assert_includes pirate.previous_changes, "updated_on" + assert_includes pirate.previous_changes, "created_on" + assert !pirate.previous_changes.key?("parrot_id") pirate.catchphrase = "Yar!!" pirate.reload @@ -513,11 +511,11 @@ class DirtyTest < ActiveRecord::TestCase pirate.save! assert_equal 2, pirate.previous_changes.size - assert_equal ["arrr", "Me Maties!"], pirate.previous_changes['catchphrase'] - assert_not_nil pirate.previous_changes['updated_on'][0] - assert_not_nil pirate.previous_changes['updated_on'][1] - assert !pirate.previous_changes.key?('parrot_id') - assert !pirate.previous_changes.key?('created_on') + assert_equal ["arrr", "Me Maties!"], pirate.previous_changes["catchphrase"] + assert_not_nil pirate.previous_changes["updated_on"][0] + assert_not_nil pirate.previous_changes["updated_on"][1] + assert !pirate.previous_changes.key?("parrot_id") + assert !pirate.previous_changes.key?("created_on") pirate = Pirate.find_by_catchphrase("Me Maties!") @@ -527,11 +525,11 @@ class DirtyTest < ActiveRecord::TestCase pirate.save assert_equal 2, pirate.previous_changes.size - assert_equal ["Me Maties!", "Thar She Blows!"], pirate.previous_changes['catchphrase'] - assert_not_nil pirate.previous_changes['updated_on'][0] - assert_not_nil pirate.previous_changes['updated_on'][1] - assert !pirate.previous_changes.key?('parrot_id') - assert !pirate.previous_changes.key?('created_on') + assert_equal ["Me Maties!", "Thar She Blows!"], pirate.previous_changes["catchphrase"] + assert_not_nil pirate.previous_changes["updated_on"][0] + assert_not_nil pirate.previous_changes["updated_on"][1] + assert !pirate.previous_changes.key?("parrot_id") + assert !pirate.previous_changes.key?("created_on") travel(1.second) @@ -539,11 +537,11 @@ class DirtyTest < ActiveRecord::TestCase pirate.update(catchphrase: "Ahoy!") assert_equal 2, pirate.previous_changes.size - assert_equal ["Thar She Blows!", "Ahoy!"], pirate.previous_changes['catchphrase'] - assert_not_nil pirate.previous_changes['updated_on'][0] - assert_not_nil pirate.previous_changes['updated_on'][1] - assert !pirate.previous_changes.key?('parrot_id') - assert !pirate.previous_changes.key?('created_on') + assert_equal ["Thar She Blows!", "Ahoy!"], pirate.previous_changes["catchphrase"] + assert_not_nil pirate.previous_changes["updated_on"][0] + assert_not_nil pirate.previous_changes["updated_on"][1] + assert !pirate.previous_changes.key?("parrot_id") + assert !pirate.previous_changes.key?("created_on") travel(1.second) @@ -551,11 +549,11 @@ class DirtyTest < ActiveRecord::TestCase pirate.update_attribute(:catchphrase, "Ninjas suck!") assert_equal 2, pirate.previous_changes.size - assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes['catchphrase'] - assert_not_nil pirate.previous_changes['updated_on'][0] - assert_not_nil pirate.previous_changes['updated_on'][1] - assert !pirate.previous_changes.key?('parrot_id') - assert !pirate.previous_changes.key?('created_on') + assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes["catchphrase"] + assert_not_nil pirate.previous_changes["updated_on"][0] + assert_not_nil pirate.previous_changes["updated_on"][1] + assert !pirate.previous_changes.key?("parrot_id") + assert !pirate.previous_changes.key?("created_on") ensure travel_back end @@ -576,24 +574,24 @@ class DirtyTest < ActiveRecord::TestCase def test_datetime_attribute_can_be_updated_with_fractional_seconds skip "Fractional seconds are not supported" unless subsecond_precision_supported? - in_time_zone 'Paris' do + in_time_zone "Paris" do target = Class.new(ActiveRecord::Base) - target.table_name = 'topics' + target.table_name = "topics" - written_on = Time.utc(2012, 12, 1, 12, 0, 0).in_time_zone('Paris') + written_on = Time.utc(2012, 12, 1, 12, 0, 0).in_time_zone("Paris") - topic = target.create(:written_on => written_on) + topic = target.create(written_on: written_on) topic.written_on += 0.3 - assert topic.written_on_changed?, 'Fractional second update not detected' + assert topic.written_on_changed?, "Fractional second update not detected" end end def test_datetime_attribute_doesnt_change_if_zone_is_modified_in_string - time_in_paris = Time.utc(2014, 1, 1, 12, 0, 0).in_time_zone('Paris') - pirate = Pirate.create!(:catchphrase => 'rrrr', :created_on => time_in_paris) + time_in_paris = Time.utc(2014, 1, 1, 12, 0, 0).in_time_zone("Paris") + pirate = Pirate.create!(catchphrase: "rrrr", created_on: time_in_paris) - pirate.created_on = pirate.created_on.in_time_zone('Tokyo').to_s + pirate.created_on = pirate.created_on.in_time_zone("Tokyo").to_s assert !pirate.created_on_changed? end @@ -601,13 +599,13 @@ class DirtyTest < ActiveRecord::TestCase with_partial_writes Person do jon = nil assert_sql(/first_name/i) do - jon = Person.create! first_name: 'Jon' + jon = Person.create! first_name: "Jon" end - assert ActiveRecord::SQLCounter.log_all.none? { |sql| sql =~ /followers_count/ } + assert ActiveRecord::SQLCounter.log_all.none? { |sql| sql.include?("followers_count") } jon.reload - assert_equal 'Jon', jon.first_name + assert_equal "Jon", jon.first_name assert_equal 0, jon.followers_count assert_not_nil jon.id end @@ -633,7 +631,7 @@ class DirtyTest < ActiveRecord::TestCase assert_equal("arrrr", pirate.catchphrase_was) assert pirate.catchphrase_changed?(from: "arrrr") assert_not pirate.catchphrase_changed?(from: "anything else") - assert pirate.changed_attributes.include?(:catchphrase) + assert_includes pirate.changed_attributes, :catchphrase pirate.save! pirate.reload @@ -672,7 +670,7 @@ class DirtyTest < ActiveRecord::TestCase end end klass = Class.new(ActiveRecord::Base) do - self.table_name = 'people' + self.table_name = "people" attribute :foo, test_type_class.new end @@ -682,7 +680,7 @@ class DirtyTest < ActiveRecord::TestCase test "attribute_will_change! doesn't try to save non-persistable attributes" do klass = Class.new(ActiveRecord::Base) do - self.table_name = 'people' + self.table_name = "people" attribute :non_persisted_attribute, :string end diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb index 638cffe0e6..3821e0c949 100644 --- a/activerecord/test/cases/dup_test.rb +++ b/activerecord/test/cases/dup_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'models/reply' -require 'models/topic' +require "models/reply" +require "models/topic" module ActiveRecord class DupTest < ActiveRecord::TestCase @@ -14,7 +14,7 @@ module ActiveRecord topic = Topic.first duped = topic.dup - assert !duped.readonly?, 'should not be readonly' + assert !duped.readonly?, "should not be readonly" end def test_is_readonly @@ -22,15 +22,15 @@ module ActiveRecord topic.readonly! duped = topic.dup - assert duped.readonly?, 'should be readonly' + assert duped.readonly?, "should be readonly" end def test_dup_not_persisted topic = Topic.first duped = topic.dup - assert !duped.persisted?, 'topic not persisted' - assert duped.new_record?, 'topic is new' + assert !duped.persisted?, "topic not persisted" + assert duped.new_record?, "topic is new" end def test_dup_not_destroyed @@ -49,9 +49,9 @@ module ActiveRecord def test_dup_with_modified_attributes topic = Topic.first - topic.author_name = 'Aaron' + topic.author_name = "Aaron" duped = topic.dup - assert_equal 'Aaron', duped.author_name + assert_equal "Aaron", duped.author_name end def test_dup_with_changes @@ -71,10 +71,10 @@ module ActiveRecord def test_dup_topics_are_independent topic = Topic.first - topic.author_name = 'Aaron' + topic.author_name = "Aaron" duped = topic.dup - duped.author_name = 'meow' + duped.author_name = "meow" assert_not_equal topic.changes, duped.changes end @@ -83,11 +83,11 @@ module ActiveRecord topic = Topic.first duped = topic.dup - duped.author_name = 'meow' - topic.author_name = 'Aaron' + duped.author_name = "meow" + topic.author_name = "Aaron" - assert_equal 'Aaron', topic.author_name - assert_equal 'meow', duped.author_name + assert_equal "Aaron", topic.author_name + assert_equal "meow", duped.author_name end def test_dup_timestamps_are_cleared @@ -127,7 +127,7 @@ module ActiveRecord assert duped.invalid? topic.title = nil - duped.title = 'Mathematics' + duped.title = "Mathematics" assert topic.invalid? assert duped.valid? end @@ -135,8 +135,8 @@ module ActiveRecord def test_dup_with_default_scope prev_default_scopes = Topic.default_scopes - Topic.default_scopes = [proc { Topic.where(:approved => true) }] - topic = Topic.new(:approved => false) + Topic.default_scopes = [proc { Topic.where(approved: true) }] + topic = Topic.new(approved: false) assert !topic.dup.approved?, "should not be overridden by default scopes" ensure Topic.default_scopes = prev_default_scopes @@ -144,7 +144,7 @@ module ActiveRecord def test_dup_without_primary_key klass = Class.new(ActiveRecord::Base) do - self.table_name = 'parrots_pirates' + self.table_name = "parrots_pirates" end record = klass.create! diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb index babacd1ee9..b7641fcf32 100644 --- a/activerecord/test/cases/enum_test.rb +++ b/activerecord/test/cases/enum_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'models/book' +require "cases/helper" +require "models/book" class EnumTest < ActiveRecord::TestCase fixtures :books @@ -18,6 +18,7 @@ class EnumTest < ActiveRecord::TestCase assert @book.author_visibility_visible? assert @book.illustrator_visibility_visible? assert @book.with_medium_font_size? + assert @book.medium_to_read? end test "query state with strings" do @@ -26,6 +27,7 @@ class EnumTest < ActiveRecord::TestCase assert_equal "english", @book.language assert_equal "visible", @book.author_visibility assert_equal "visible", @book.illustrator_visibility + assert_equal "medium", @book.difficulty end test "find via scope" do @@ -34,6 +36,7 @@ class EnumTest < ActiveRecord::TestCase assert_equal @book, Book.in_english.first assert_equal @book, Book.author_visibility_visible.first assert_equal @book, Book.illustrator_visibility_visible.first + assert_equal @book, Book.medium_to_read.first end test "find via where with values" do @@ -122,8 +125,8 @@ class EnumTest < ActiveRecord::TestCase old_language = @book.language @book.status = :proposed @book.language = :spanish - assert_equal [old_status, 'proposed'], @book.changes[:status] - assert_equal [old_language, 'spanish'], @book.changes[:language] + assert_equal [old_status, "proposed"], @book.changes[:status] + assert_equal [old_language, "spanish"], @book.changes[:language] end test "enum attribute was" do @@ -145,8 +148,8 @@ class EnumTest < ActiveRecord::TestCase test "enum attribute changed to" do @book.status = :proposed @book.language = :french - assert @book.attribute_changed?(:status, to: 'proposed') - assert @book.attribute_changed?(:language, to: 'french') + assert @book.attribute_changed?(:status, to: "proposed") + assert @book.attribute_changed?(:language, to: "french") end test "enum attribute changed from" do @@ -163,8 +166,8 @@ class EnumTest < ActiveRecord::TestCase old_language = @book.language @book.status = :proposed @book.language = :french - assert @book.attribute_changed?(:status, from: old_status, to: 'proposed') - assert @book.attribute_changed?(:language, from: old_language, to: 'french') + assert @book.attribute_changed?(:status, from: old_status, to: "proposed") + assert @book.attribute_changed?(:language, from: old_language, to: "french") end test "enum didn't change" do @@ -216,12 +219,12 @@ class EnumTest < ActiveRecord::TestCase end test "assign empty string value" do - @book.status = '' + @book.status = "" assert_nil @book.status end test "assign long empty string value" do - @book.status = ' ' + @book.status = " " assert_nil @book.status end @@ -318,7 +321,7 @@ class EnumTest < ActiveRecord::TestCase test "validate uniqueness" do klass = Class.new(ActiveRecord::Base) do - def self.name; 'Book'; end + def self.name; "Book"; end enum status: [:proposed, :written] validates_uniqueness_of :status end @@ -332,7 +335,7 @@ class EnumTest < ActiveRecord::TestCase test "validate inclusion of value in array" do klass = Class.new(ActiveRecord::Base) do - def self.name; 'Book'; end + def self.name; "Book"; end enum status: [:proposed, :written] validates_inclusion_of :status, in: ["written"] end @@ -356,11 +359,11 @@ class EnumTest < ActiveRecord::TestCase book1 = klass1.proposed.create! book1.status = :written - assert_equal ['proposed', 'written'], book1.status_change + assert_equal ["proposed", "written"], book1.status_change book2 = klass2.drafted.create! book2.status = :uploaded - assert_equal ['drafted', 'uploaded'], book2.status_change + assert_equal ["drafted", "uploaded"], book2.status_change end test "enums are inheritable" do @@ -372,11 +375,11 @@ class EnumTest < ActiveRecord::TestCase book1 = subklass1.proposed.create! book1.status = :written - assert_equal ['proposed', 'written'], book1.status_change + assert_equal ["proposed", "written"], book1.status_change book2 = subklass2.drafted.create! book2.status = :uploaded - assert_equal ['drafted', 'uploaded'], book2.status_change + assert_equal ["drafted", "uploaded"], book2.status_change end test "declare multiple enums at a time" do @@ -393,6 +396,22 @@ class EnumTest < ActiveRecord::TestCase assert book2.single? end + test "enum with alias_attribute" do + klass = Class.new(ActiveRecord::Base) do + self.table_name = "books" + alias_attribute :aliased_status, :status + enum aliased_status: [:proposed, :written, :published] + end + + book = klass.proposed.create! + assert book.proposed? + assert_equal "proposed", book.aliased_status + + book = klass.find(book.id) + assert book.proposed? + assert_equal "proposed", book.aliased_status + end + test "query state by predicate with prefix" do assert @book.author_visibility_visible? assert_not @book.author_visibility_invisible? @@ -406,6 +425,43 @@ class EnumTest < ActiveRecord::TestCase assert_not @book.in_french? end + test "query state by predicate with custom suffix" do + assert @book.medium_to_read? + assert_not @book.easy_to_read? + assert_not @book.hard_to_read? + end + + test "enum methods with custom suffix defined" do + assert @book.class.respond_to?(:easy_to_read) + assert @book.class.respond_to?(:medium_to_read) + assert @book.class.respond_to?(:hard_to_read) + + assert @book.respond_to?(:easy_to_read?) + assert @book.respond_to?(:medium_to_read?) + assert @book.respond_to?(:hard_to_read?) + + assert @book.respond_to?(:easy_to_read!) + assert @book.respond_to?(:medium_to_read!) + assert @book.respond_to?(:hard_to_read!) + end + + test "update enum attributes with custom suffix" do + @book.medium_to_read! + assert_not @book.easy_to_read? + assert @book.medium_to_read? + assert_not @book.hard_to_read? + + @book.easy_to_read! + assert @book.easy_to_read? + assert_not @book.medium_to_read? + assert_not @book.hard_to_read? + + @book.hard_to_read! + assert_not @book.easy_to_read? + assert_not @book.medium_to_read? + assert @book.hard_to_read? + end + test "uses default status when no status is provided in fixtures" do book = books(:tlg) assert book.proposed?, "expected fixture to default to proposed status" @@ -421,4 +477,8 @@ class EnumTest < ActiveRecord::TestCase book = Book.new assert book.hard? end + + test "data type of Enum type" do + assert_equal :integer, Book.type_for_attribute("status").type + end end diff --git a/activerecord/test/cases/explain_subscriber_test.rb b/activerecord/test/cases/explain_subscriber_test.rb index 2dee8a26a5..ca87e04012 100644 --- a/activerecord/test/cases/explain_subscriber_test.rb +++ b/activerecord/test/cases/explain_subscriber_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'active_record/explain_subscriber' -require 'active_record/explain_registry' +require "cases/helper" +require "active_record/explain_subscriber" +require "active_record/explain_registry" if ActiveRecord::Base.connection.supports_explain? class ExplainSubscriberTest < ActiveRecord::TestCase @@ -25,31 +25,31 @@ if ActiveRecord::Base.connection.supports_explain? def test_collects_nothing_if_collect_is_false ActiveRecord::ExplainRegistry.collect = false - SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select 1 from users', binds: [1, 2]) + SUBSCRIBER.finish(nil, nil, name: "SQL", sql: "select 1 from users", binds: [1, 2]) assert queries.empty? end def test_collects_pairs_of_queries_and_binds - sql = 'select 1 from users' + sql = "select 1 from users" binds = [1, 2] - SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: sql, binds: binds) + SUBSCRIBER.finish(nil, nil, name: "SQL", sql: sql, binds: binds) assert_equal 1, queries.size assert_equal sql, queries[0][0] assert_equal binds, queries[0][1] end def test_collects_nothing_if_the_statement_is_not_whitelisted - SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'SHOW max_identifier_length') + SUBSCRIBER.finish(nil, nil, name: "SQL", sql: "SHOW max_identifier_length") assert queries.empty? end def test_collects_nothing_if_the_statement_is_only_partially_matched - SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select_db yo_mama') + SUBSCRIBER.finish(nil, nil, name: "SQL", sql: "select_db yo_mama") assert queries.empty? end def test_collects_cte_queries - SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'with s as (values(3)) select 1 from s') + SUBSCRIBER.finish(nil, nil, name: "SQL", sql: "with s as (values(3)) select 1 from s") assert_equal 1, queries.size end diff --git a/activerecord/test/cases/explain_test.rb b/activerecord/test/cases/explain_test.rb index 64dfd86ce2..86fe90ae51 100644 --- a/activerecord/test/cases/explain_test.rb +++ b/activerecord/test/cases/explain_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/car' -require 'active_support/core_ext/string/strip' +require "cases/helper" +require "models/car" +require "active_support/core_ext/string/strip" if ActiveRecord::Base.connection.supports_explain? class ExplainTest < ActiveRecord::TestCase @@ -15,13 +15,13 @@ if ActiveRecord::Base.connection.supports_explain? end def test_relation_explain - message = Car.where(:name => 'honda').explain + message = Car.where(name: "honda").explain assert_match(/^EXPLAIN for:/, message) end def test_collecting_queries_for_explain queries = ActiveRecord::Base.collecting_queries_for_explain do - Car.where(:name => 'honda').to_a + Car.where(name: "honda").to_a end sql, binds = queries[0] @@ -30,7 +30,7 @@ if ActiveRecord::Base.connection.supports_explain? assert_equal 1, binds.length assert_equal "honda", binds.last.value else - assert_match 'honda', sql + assert_match "honda", sql end end @@ -40,17 +40,14 @@ if ActiveRecord::Base.connection.supports_explain? queries = sqls.zip(binds) stub_explain_for_query_plans do - expected = sqls.map {|sql| "EXPLAIN for: #{sql}\nquery plan #{sql}"}.join("\n") + expected = sqls.map { |sql| "EXPLAIN for: #{sql}\nquery plan #{sql}" }.join("\n") assert_equal expected, base.exec_explain(queries) end end def test_exec_explain_with_binds - object = Struct.new(:name) - cols = [object.new('wadus'), object.new('chaflan')] - sqls = %w(foo bar) - binds = [[[cols[0], 1]], [[cols[1], 2]]] + binds = [[bind_param("wadus", 1)], [bind_param("chaflan", 2)]] queries = sqls.zip(binds) stub_explain_for_query_plans(["query plan foo\n", "query plan bar\n"]) do @@ -68,20 +65,23 @@ if ActiveRecord::Base.connection.supports_explain? def test_unsupported_connection_adapter connection.stub(:supports_explain?, false) do assert_not_called(base.logger, :warn) do - Car.where(:name => 'honda').to_a + Car.where(name: "honda").to_a end end end private - def stub_explain_for_query_plans(query_plans = ['query plan foo', 'query plan bar']) + def stub_explain_for_query_plans(query_plans = ["query plan foo", "query plan bar"]) explain_called = 0 - connection.stub(:explain, proc{ explain_called += 1; query_plans[explain_called - 1] }) do + connection.stub(:explain, proc { explain_called += 1; query_plans[explain_called - 1] }) do yield end end + def bind_param(name, value) + ActiveRecord::Relation::QueryAttribute.new(name, value, ActiveRecord::Type::Value.new) + end end end diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb index 6ab2657c44..3eaa993d45 100644 --- a/activerecord/test/cases/finder_respond_to_test.rb +++ b/activerecord/test/cases/finder_respond_to_test.rb @@ -1,8 +1,7 @@ require "cases/helper" -require 'models/topic' +require "models/topic" class FinderRespondToTest < ActiveRecord::TestCase - fixtures :topics def test_should_preserve_normal_respond_to_behaviour_on_base @@ -11,7 +10,7 @@ class FinderRespondToTest < ActiveRecord::TestCase end def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method - class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { } + class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) {} assert_respond_to Topic, :method_added_for_finder_respond_to_test ensure class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test) @@ -54,7 +53,7 @@ class FinderRespondToTest < ActiveRecord::TestCase private - def ensure_topic_method_is_not_cached(method_id) - class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.include? method_id - end + def ensure_topic_method_is_not_cached(method_id) + class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.include? method_id + end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 6eaaa30cd0..51563b347c 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -1,35 +1,35 @@ require "cases/helper" -require 'models/post' -require 'models/author' -require 'models/categorization' -require 'models/comment' -require 'models/company' -require 'models/tagging' -require 'models/topic' -require 'models/reply' -require 'models/entrant' -require 'models/project' -require 'models/developer' -require 'models/computer' -require 'models/customer' -require 'models/toy' -require 'models/matey' -require 'models/dog' -require 'models/car' -require 'models/tyre' +require "models/post" +require "models/author" +require "models/categorization" +require "models/comment" +require "models/company" +require "models/tagging" +require "models/topic" +require "models/reply" +require "models/entrant" +require "models/project" +require "models/developer" +require "models/computer" +require "models/customer" +require "models/toy" +require "models/matey" +require "models/dog" +require "models/car" +require "models/tyre" class FinderTest < ActiveRecord::TestCase fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :author_addresses, :customers, :categories, :categorizations, :cars def test_find_by_id_with_hash - assert_raises(ActiveRecord::StatementInvalid) do - Post.find_by_id(:limit => 1) + assert_nothing_raised do + Post.find_by_id(limit: 1) end end def test_find_by_title_and_id_with_hash - assert_raises(ActiveRecord::StatementInvalid) do - Post.find_by_title_and_id('foo', :limit => 1) + assert_nothing_raised do + Post.find_by_title_and_id("foo", limit: 1) end end @@ -50,53 +50,53 @@ class FinderTest < ActiveRecord::TestCase def test_find_with_ids_returning_ordered records = Topic.find([4,2,5]) - assert_equal 'The Fourth Topic of the day', records[0].title - assert_equal 'The Second Topic of the day', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + assert_equal "The Fourth Topic of the day", records[0].title + assert_equal "The Second Topic of the day", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title records = Topic.find(4,2,5) - assert_equal 'The Fourth Topic of the day', records[0].title - assert_equal 'The Second Topic of the day', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + assert_equal "The Fourth Topic of the day", records[0].title + assert_equal "The Second Topic of the day", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title - records = Topic.find(['4','2','5']) - assert_equal 'The Fourth Topic of the day', records[0].title - assert_equal 'The Second Topic of the day', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + records = Topic.find(["4","2","5"]) + assert_equal "The Fourth Topic of the day", records[0].title + assert_equal "The Second Topic of the day", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title - records = Topic.find('4','2','5') - assert_equal 'The Fourth Topic of the day', records[0].title - assert_equal 'The Second Topic of the day', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + records = Topic.find("4","2","5") + assert_equal "The Fourth Topic of the day", records[0].title + assert_equal "The Second Topic of the day", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title end def test_find_with_ids_and_order_clause # The order clause takes precedence over the informed ids records = Topic.order(:author_name).find([5,3,1]) - assert_equal 'The Third Topic of the day', records[0].title - assert_equal 'The First Topic', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + assert_equal "The Third Topic of the day", records[0].title + assert_equal "The First Topic", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title records = Topic.order(:id).find([5,3,1]) - assert_equal 'The First Topic', records[0].title - assert_equal 'The Third Topic of the day', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + assert_equal "The First Topic", records[0].title + assert_equal "The Third Topic of the day", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title end def test_find_with_ids_with_limit_and_order_clause # The order clause takes precedence over the informed ids records = Topic.limit(2).order(:id).find([5,3,1]) assert_equal 2, records.size - assert_equal 'The First Topic', records[0].title - assert_equal 'The Third Topic of the day', records[1].title + assert_equal "The First Topic", records[0].title + assert_equal "The Third Topic of the day", records[1].title end def test_find_with_ids_and_limit records = Topic.limit(3).find([3,2,5,1,4]) assert_equal 3, records.size - assert_equal 'The Third Topic of the day', records[0].title - assert_equal 'The Second Topic of the day', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + assert_equal "The Third Topic of the day", records[0].title + assert_equal "The Second Topic of the day", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title end def test_find_with_ids_where_and_limit @@ -104,17 +104,17 @@ class FinderTest < ActiveRecord::TestCase # if it were among the first 3 it would raise an ActiveRecord::RecordNotFound records = Topic.where(approved: true).limit(3).find([3,2,5,1,4]) assert_equal 3, records.size - assert_equal 'The Third Topic of the day', records[0].title - assert_equal 'The Second Topic of the day', records[1].title - assert_equal 'The Fifth Topic of the day', records[2].title + assert_equal "The Third Topic of the day", records[0].title + assert_equal "The Second Topic of the day", records[1].title + assert_equal "The Fifth Topic of the day", records[2].title end def test_find_with_ids_and_offset records = Topic.offset(2).find([3,2,5,1,4]) assert_equal 3, records.size - assert_equal 'The Fifth Topic of the day', records[0].title - assert_equal 'The First Topic', records[1].title - assert_equal 'The Fourth Topic of the day', records[2].title + assert_equal "The Fifth Topic of the day", records[0].title + assert_equal "The First Topic", records[1].title + assert_equal "The Fourth Topic of the day", records[2].title end def test_find_passing_active_record_object_is_deprecated @@ -127,7 +127,7 @@ class FinderTest < ActiveRecord::TestCase gc_disabled = GC.disable Post.where("author_id" => nil) # warm up x = Symbol.all_symbols.count - Post.where("title" => {"xxxqqqq" => "bar"}) + Post.where("title" => { "xxxqqqq" => "bar" }) assert_equal x, Symbol.all_symbols.count ensure GC.enable if gc_disabled == false @@ -144,7 +144,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal true, Topic.exists?("1") assert_equal true, Topic.exists?(title: "The First Topic") assert_equal true, Topic.exists?(heading: "The First Topic") - assert_equal true, Topic.exists?(:author_name => "Mary", :approved => true) + assert_equal true, Topic.exists?(author_name: "Mary", approved: true) assert_equal true, Topic.exists?(["parent_id = ?", 1]) assert_equal true, Topic.exists?(id: [1, 9999]) @@ -155,11 +155,11 @@ class FinderTest < ActiveRecord::TestCase end def test_exists_with_polymorphic_relation - post = Post.create!(title: 'Post', body: 'default', taggings: [Tagging.new(comment: 'tagging comment')]) - relation = Post.tagged_with_comment('tagging comment') + post = Post.create!(title: "Post", body: "default", taggings: [Tagging.new(comment: "tagging comment")]) + relation = Post.tagged_with_comment("tagging comment") - assert_equal true, relation.exists?(title: ['Post']) - assert_equal true, relation.exists?(['title LIKE ?', 'Post%']) + assert_equal true, relation.exists?(title: ["Post"]) + assert_equal true, relation.exists?(["title LIKE ?", "Post%"]) assert_equal true, relation.exists? assert_equal true, relation.exists?(post.id) assert_equal true, relation.exists?(post.id.to_s) @@ -209,7 +209,7 @@ class FinderTest < ActiveRecord::TestCase def test_exists_with_includes_limit_and_empty_result assert_equal false, Topic.includes(:replies).limit(0).exists? - assert_equal false, Topic.includes(:replies).limit(1).where('0 = 1').exists? + assert_equal false, Topic.includes(:replies).limit(1).where("0 = 1").exists? end def test_exists_with_distinct_association_includes_and_limit @@ -220,8 +220,8 @@ class FinderTest < ActiveRecord::TestCase def test_exists_with_distinct_association_includes_limit_and_order author = Author.first - assert_equal false, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(0).exists? - assert_equal true, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(1).exists? + assert_equal false, author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC").limit(0).exists? + assert_equal true, author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC").limit(1).exists? end def test_exists_with_empty_table_and_no_args_given @@ -231,17 +231,14 @@ class FinderTest < ActiveRecord::TestCase def test_exists_with_aggregate_having_three_mappings existing_address = customers(:david).address - assert_equal true, Customer.exists?(:address => existing_address) + assert_equal true, Customer.exists?(address: existing_address) end def test_exists_with_aggregate_having_three_mappings_with_one_difference existing_address = customers(:david).address - assert_equal false, Customer.exists?(:address => - Address.new(existing_address.street, existing_address.city, existing_address.country + "1")) - assert_equal false, Customer.exists?(:address => - Address.new(existing_address.street, existing_address.city + "1", existing_address.country)) - assert_equal false, Customer.exists?(:address => - Address.new(existing_address.street + "1", existing_address.city, existing_address.country)) + assert_equal false, Customer.exists?(address: Address.new(existing_address.street, existing_address.city, existing_address.country + "1")) + assert_equal false, Customer.exists?(address: Address.new(existing_address.street, existing_address.city + "1", existing_address.country)) + assert_equal false, Customer.exists?(address: Address.new(existing_address.street + "1", existing_address.city, existing_address.country)) end def test_exists_does_not_instantiate_records @@ -264,7 +261,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal 2, Entrant.limit(2).find([1,3,2]).size entrants = Entrant.limit(3).offset(2).find([1,3,2]) assert_equal 1, entrants.size - assert_equal 'Ruby Guru', entrants.first.name + assert_equal "Ruby Guru", entrants.first.name # Also test an edge case: If you have 11 results, and you set a # limit of 3 and offset of 9, then you should find that there @@ -272,29 +269,29 @@ class FinderTest < ActiveRecord::TestCase devs = Developer.all last_devs = Developer.limit(3).offset(9).find devs.map(&:id) assert_equal 2, last_devs.size - assert_equal 'fixture_10', last_devs[0].name - assert_equal 'Jamis', last_devs[1].name + assert_equal "fixture_10", last_devs[0].name + assert_equal "Jamis", last_devs[1].name end def test_find_with_large_number - assert_raises(ActiveRecord::RecordNotFound) { Topic.find('9999999999999999999999999999999') } + assert_raises(ActiveRecord::RecordNotFound) { Topic.find("9999999999999999999999999999999") } end def test_find_by_with_large_number - assert_nil Topic.find_by(id: '9999999999999999999999999999999') + assert_nil Topic.find_by(id: "9999999999999999999999999999999") end def test_find_by_id_with_large_number - assert_nil Topic.find_by_id('9999999999999999999999999999999') + assert_nil Topic.find_by_id("9999999999999999999999999999999") end def test_find_on_relation_with_large_number - assert_nil Topic.where('1=1').find_by(id: 9999999999999999999999999999999) + assert_nil Topic.where("1=1").find_by(id: 9999999999999999999999999999999) end def test_find_by_bang_on_relation_with_large_number assert_raises(ActiveRecord::RecordNotFound) do - Topic.where('1=1').find_by!(id: 9999999999999999999999999999999) + Topic.where("1=1").find_by!(id: 9999999999999999999999999999999) end end @@ -311,7 +308,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_with_group_and_sanitized_having_method - developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select('salary').to_a + developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select("salary").to_a assert_equal 3, developers.size assert_equal 3, developers.map(&:salary).uniq.size assert developers.all? { |developer| developer.salary > 10000 } @@ -565,9 +562,9 @@ class FinderTest < ActiveRecord::TestCase end def test_take_and_first_and_last_with_integer_should_use_sql_limit - assert_sql(/LIMIT|ROWNUM <=/) { Topic.take(3).entries } - assert_sql(/LIMIT|ROWNUM <=/) { Topic.first(2).entries } - assert_sql(/LIMIT|ROWNUM <=/) { Topic.last(5).entries } + assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.take(3).entries } + assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.first(2).entries } + assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.last(5).entries } end def test_last_with_integer_and_order_should_keep_the_order @@ -601,7 +598,7 @@ class FinderTest < ActiveRecord::TestCase end def test_last_on_relation_with_limit_and_offset - post = posts('sti_comments') + post = posts("sti_comments") comments = post.comments.order(id: :asc) assert_equal comments.limit(2).to_a.last, comments.limit(2).last @@ -630,8 +627,8 @@ class FinderTest < ActiveRecord::TestCase def test_find_only_some_columns topic = Topic.select("author_name").find(1) - assert_raise(ActiveModel::MissingAttributeError) {topic.title} - assert_raise(ActiveModel::MissingAttributeError) {topic.title?} + assert_raise(ActiveModel::MissingAttributeError) { topic.title } + assert_raise(ActiveModel::MissingAttributeError) { topic.title? } assert_nil topic.read_attribute("title") assert_equal "David", topic.author_name assert !topic.attribute_present?("title") @@ -651,8 +648,8 @@ class FinderTest < ActiveRecord::TestCase end def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_string - assert Topic.where('topics.approved' => false).find(1) - assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true).find(1) } + assert Topic.where("topics.approved" => false).find(1) + assert_raise(ActiveRecord::RecordNotFound) { Topic.where("topics.approved" => true).find(1) } end def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_symbol @@ -666,28 +663,28 @@ class FinderTest < ActiveRecord::TestCase end def test_find_on_combined_explicit_and_hashed_table_names - assert Topic.where('topics.approved' => false, topics: { author_name: "David" }).find(1) - assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true, topics: { author_name: "David" }).find(1) } - assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => false, topics: { author_name: "Melanie" }).find(1) } + assert Topic.where("topics.approved" => false, topics: { author_name: "David" }).find(1) + assert_raise(ActiveRecord::RecordNotFound) { Topic.where("topics.approved" => true, topics: { author_name: "David" }).find(1) } + assert_raise(ActiveRecord::RecordNotFound) { Topic.where("topics.approved" => false, topics: { author_name: "Melanie" }).find(1) } end def test_find_with_hash_conditions_on_joined_table - firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 }) + firms = Firm.joins(:account).where(accounts: { credit_limit: 50 }) assert_equal 1, firms.size assert_equal companies(:first_firm), firms.first end def test_find_with_hash_conditions_on_joined_table_and_with_range - firms = DependentFirm.joins(:account).where(name: 'RailsCore', accounts: { credit_limit: 55..60 }) + firms = DependentFirm.joins(:account).where(name: "RailsCore", accounts: { credit_limit: 55..60 }) assert_equal 1, firms.size assert_equal companies(:rails_core), firms.first end def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate david = customers(:david) - assert Customer.where('customers.name' => david.name, :address => david.address).find(david.id) + assert Customer.where("customers.name" => david.name, :address => david.address).find(david.id) assert_raise(ActiveRecord::RecordNotFound) { - Customer.where('customers.name' => david.name + "1", :address => david.address).find(david.id) + Customer.where("customers.name" => david.name + "1", :address => david.address).find(david.id) } end @@ -758,9 +755,9 @@ class FinderTest < ActiveRecord::TestCase end def test_hash_condition_find_with_array - p1, p2 = Post.limit(2).order('id asc').to_a - assert_equal [p1, p2], Post.where(id: [p1, p2]).order('id asc').to_a - assert_equal [p1, p2], Post.where(id: [p1, p2.id]).order('id asc').to_a + p1, p2 = Post.limit(2).order("id asc").to_a + assert_equal [p1, p2], Post.where(id: [p1, p2]).order("id asc").to_a + assert_equal [p1, p2], Post.where(id: [p1, p2.id]).order("id asc").to_a end def test_hash_condition_find_with_nil @@ -772,56 +769,56 @@ class FinderTest < ActiveRecord::TestCase def test_hash_condition_find_with_aggregate_having_one_mapping balance = customers(:david).balance assert_kind_of Money, balance - found_customer = Customer.where(:balance => balance).first + found_customer = Customer.where(balance: balance).first assert_equal customers(:david), found_customer end def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate gps_location = customers(:david).gps_location assert_kind_of GpsLocation, gps_location - found_customer = Customer.where(:gps_location => gps_location).first + found_customer = Customer.where(gps_location: gps_location).first assert_equal customers(:david), found_customer end def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value balance = customers(:david).balance assert_kind_of Money, balance - found_customer = Customer.where(:balance => balance.amount).first + found_customer = Customer.where(balance: balance.amount).first assert_equal customers(:david), found_customer end def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value gps_location = customers(:david).gps_location assert_kind_of GpsLocation, gps_location - found_customer = Customer.where(:gps_location => gps_location.gps_location).first + found_customer = Customer.where(gps_location: gps_location.gps_location).first assert_equal customers(:david), found_customer end def test_hash_condition_find_with_aggregate_having_three_mappings address = customers(:david).address assert_kind_of Address, address - found_customer = Customer.where(:address => address).first + found_customer = Customer.where(address: address).first assert_equal customers(:david), found_customer end def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not address = customers(:david).address assert_kind_of Address, address - found_customer = Customer.where(:address => address, :name => customers(:david).name).first + found_customer = Customer.where(address: address, name: customers(:david).name).first assert_equal customers(:david), found_customer end def test_condition_utc_time_interpolation_with_default_timezone_local - with_env_tz 'America/New_York' do + with_env_tz "America/New_York" do with_timezone_config default: :local do topic = Topic.first - assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getutc]).first + assert_equal topic, Topic.where(["written_on = ?", topic.written_on.getutc]).first end end end def test_hash_condition_utc_time_interpolation_with_default_timezone_local - with_env_tz 'America/New_York' do + with_env_tz "America/New_York" do with_timezone_config default: :local do topic = Topic.first assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first @@ -830,16 +827,16 @@ class FinderTest < ActiveRecord::TestCase end def test_condition_local_time_interpolation_with_default_timezone_utc - with_env_tz 'America/New_York' do + with_env_tz "America/New_York" do with_timezone_config default: :utc do topic = Topic.first - assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getlocal]).first + assert_equal topic, Topic.where(["written_on = ?", topic.written_on.getlocal]).first end end end def test_hash_condition_local_time_interpolation_with_default_timezone_utc - with_env_tz 'America/New_York' do + with_env_tz "America/New_York" do with_timezone_config default: :utc do topic = Topic.first assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first @@ -856,7 +853,7 @@ class FinderTest < ActiveRecord::TestCase Company.where(["id=? AND name = ?", 2]).first } assert_raise(ActiveRecord::PreparedStatementInvalid) { - Company.where(["id=?", 2, 3, 4]).first + Company.where(["id=?", 2, 3, 4]).first } end @@ -867,7 +864,7 @@ class FinderTest < ActiveRecord::TestCase def test_named_bind_variables_with_quotes Company.create("name" => "37signals' go'es agains") - assert Company.where(["name = :name", {name: "37signals' go'es agains"}]).first + assert Company.where(["name = :name", { name: "37signals' go'es agains" }]).first end def test_named_bind_variables @@ -877,11 +874,6 @@ class FinderTest < ActiveRecord::TestCase assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on end - def test_string_sanitation - assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1") - assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table") - end - def test_count_by_sql assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3")) assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2])) @@ -901,7 +893,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_by_on_attribute_that_is_a_reserved_word - dog_alias = 'Dog' + dog_alias = "Dog" dog = Dog.create(alias: dog_alias) assert_equal dog, Dog.find_by_alias(dog_alias) @@ -918,7 +910,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_by_one_attribute_with_conditions - assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50) + assert_equal accounts(:rails_core_account), Account.where("firm_id = ?", 6).find_by_credit_limit(50) end def test_find_by_one_attribute_that_is_an_aggregate @@ -958,12 +950,12 @@ class FinderTest < ActiveRecord::TestCase def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching # ensure this test can run independently of order class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.include?(:find_by_credit_limit) - a = Account.where('firm_id = ?', 6).find_by_credit_limit(50) - assert_equal a, Account.where('firm_id = ?', 6).find_by_credit_limit(50) # find_by_credit_limit has been cached + a = Account.where("firm_id = ?", 6).find_by_credit_limit(50) + assert_equal a, Account.where("firm_id = ?", 6).find_by_credit_limit(50) # find_by_credit_limit has been cached end def test_find_by_one_attribute_with_several_options - assert_equal accounts(:unknown), Account.order('id DESC').where('id != ?', 3).find_by_credit_limit(50) + assert_equal accounts(:unknown), Account.order("id DESC").where("id != ?", 3).find_by_credit_limit(50) end def test_find_by_one_missing_attribute @@ -987,12 +979,12 @@ class FinderTest < ActiveRecord::TestCase end def test_find_last_with_offset - devs = Developer.order('id') + devs = Developer.order("id") assert_equal devs[2], Developer.offset(2).first assert_equal devs[-3], Developer.offset(2).last assert_equal devs[-3], Developer.offset(2).last - assert_equal devs[-3], Developer.offset(2).order('id DESC').first + assert_equal devs[-3], Developer.offset(2).order("id DESC").first end def test_find_by_nil_attribute @@ -1012,18 +1004,18 @@ class FinderTest < ActiveRecord::TestCase def test_find_all_with_join developers_on_project_one = Developer. - joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id'). - where('project_id=1').to_a + joins("LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id"). + where("project_id=1").to_a assert_equal 3, developers_on_project_one.length developer_names = developers_on_project_one.map(&:name) - assert developer_names.include?('David') - assert developer_names.include?('Jamis') + assert_includes developer_names, "David" + assert_includes developer_names, "Jamis" end def test_joins_dont_clobber_id first = Firm. - joins('INNER JOIN companies clients ON clients.firm_id = companies.id'). - where('companies.id = 1').first + joins("INNER JOIN companies clients ON clients.firm_id = companies.id"). + where("companies.id = 1").first assert_equal 1, first.id end @@ -1042,7 +1034,7 @@ class FinderTest < ActiveRecord::TestCase end def test_find_ignores_previously_inserted_record - Post.create!(:title => 'test', :body => 'it out') + Post.create!(title: "test", body: "it out") assert_equal [], Post.where(id: nil) end @@ -1051,13 +1043,13 @@ class FinderTest < ActiveRecord::TestCase end def test_find_by_empty_in_condition - assert_equal [], Post.where('id in (?)', []) + assert_equal [], Post.where("id in (?)", []) end def test_find_by_records - p1, p2 = Post.limit(2).order('id asc').to_a - assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2]]).order('id asc') - assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2.id]]).order('id asc') + p1, p2 = Post.limit(2).order("id asc").to_a + assert_equal [p1, p2], Post.where(["id in (?)", [p1, p2]]).order("id asc") + assert_equal [p1, p2], Post.where(["id in (?)", [p1, p2.id]]).order("id asc") end def test_select_value @@ -1078,36 +1070,36 @@ class FinderTest < ActiveRecord::TestCase [["1", "1", nil, "37signals"], ["2", "1", "2", "Summit"], ["3", "1", "1", "Microsoft"]], - Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}}) + Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! { |i| i.map! { |j| j.to_s unless j.nil? } }) assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]], - Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}} + Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! { |i| i.map! { |j| j.to_s unless j.nil? } } end def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct assert_equal 2, Post.includes(authors: :author_address). where.not(author_addresses: { id: nil }). - order('author_addresses.id DESC').limit(2).to_a.size + order("author_addresses.id DESC").limit(2).to_a.size assert_equal 3, Post.includes(author: :author_address, authors: :author_address). where.not(author_addresses_authors: { id: nil }). - order('author_addresses_authors.id DESC').limit(3).to_a.size + order("author_addresses_authors.id DESC").limit(3).to_a.size end def test_find_with_nil_inside_set_passed_for_one_attribute client_of = Company. where(client_of: [2, 1, nil], - name: ['37signals', 'Summit', 'Microsoft']). - order('client_of DESC'). + name: ["37signals", "Summit", "Microsoft"]). + order("client_of DESC"). map(&:client_of) - assert client_of.include?(nil) + assert_includes client_of, nil assert_equal [2, 1].sort, client_of.compact.sort end def test_find_with_nil_inside_set_passed_for_attribute client_of = Company. where(client_of: [nil]). - order('client_of DESC'). + order("client_of DESC"). map(&:client_of) assert_equal [], client_of.compact @@ -1115,20 +1107,30 @@ class FinderTest < ActiveRecord::TestCase def test_with_limiting_with_custom_select posts = Post.references(:authors).merge( - :includes => :author, :select => 'posts.*, authors.id as "author_id"', - :limit => 3, :order => 'posts.id' + includes: :author, select: 'posts.*, authors.id as "author_id"', + limit: 3, order: "posts.id" ).to_a assert_equal 3, posts.size assert_equal [0, 1, 1], posts.map(&:author_id).sort end + def test_find_one_message_on_primary_key + e = assert_raises(ActiveRecord::RecordNotFound) do + Car.find(0) + end + assert_equal 0, e.id + assert_equal "id", e.primary_key + assert_equal "Car", e.model + assert_equal "Couldn't find Car with 'id'=0", e.message + end + def test_find_one_message_with_custom_primary_key table_with_custom_primary_key do |model| model.primary_key = :name e = assert_raises(ActiveRecord::RecordNotFound) do - model.find 'Hello World!' + model.find "Hello World!" end - assert_equal %Q{Couldn't find MercedesCar with 'name'=Hello World!}, e.message + assert_equal "Couldn't find MercedesCar with 'name'=Hello World!", e.message end end @@ -1136,9 +1138,9 @@ class FinderTest < ActiveRecord::TestCase table_with_custom_primary_key do |model| model.primary_key = :name e = assert_raises(ActiveRecord::RecordNotFound) do - model.find 'Hello', 'World!' + model.find "Hello", "World!" end - assert_equal %Q{Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2)}, e.message + assert_equal "Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2)", e.message end end @@ -1161,7 +1163,7 @@ class FinderTest < ActiveRecord::TestCase end test "find_by with multi-arg conditions returns the first matching record" do - assert_equal posts(:eager_other), Post.find_by('id = ?', posts(:eager_other).id) + assert_equal posts(:eager_other), Post.find_by("id = ?", posts(:eager_other).id) end test "find_by returns nil if the record is missing" do @@ -1186,7 +1188,7 @@ class FinderTest < ActiveRecord::TestCase end test "find_by! with multi-arg conditions returns the first matching record" do - assert_equal posts(:eager_other), Post.find_by!('id = ?', posts(:eager_other).id) + assert_equal posts(:eager_other), Post.find_by!("id = ?", posts(:eager_other).id) end test "find_by! doesn't have implicit ordering" do @@ -1223,7 +1225,7 @@ class FinderTest < ActiveRecord::TestCase def table_with_custom_primary_key yield(Class.new(Toy) do def self.name - 'MercedesCar' + "MercedesCar" end end) end @@ -1232,5 +1234,4 @@ class FinderTest < ActiveRecord::TestCase err = assert_raises(exception_class) { block.call } assert_match message, err.message end - end diff --git a/activerecord/test/cases/fixture_set/file_test.rb b/activerecord/test/cases/fixture_set/file_test.rb index e64b90507e..cf2a73595a 100644 --- a/activerecord/test/cases/fixture_set/file_test.rb +++ b/activerecord/test/cases/fixture_set/file_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'tempfile' +require "cases/helper" +require "tempfile" module ActiveRecord class FixtureSet @@ -15,7 +15,7 @@ module ActiveRecord called = true assert_equal 6, fh.to_a.length end - assert called, 'block called' + assert called, "block called" end def test_names @@ -32,7 +32,7 @@ module ActiveRecord def test_values File.open(::File.join(FIXTURES_ROOT, "accounts.yml")) do |fh| assert_equal [1,2,3,4,5,6].sort, fh.to_a.map(&:last).map { |x| - x['id'] + x["id"] }.sort end end @@ -45,7 +45,7 @@ module ActiveRecord end def test_empty_file - tmp_yaml ['empty', 'yml'], '' do |t| + tmp_yaml ["empty", "yml"], "" do |t| assert_equal [], File.open(t.path) { |fh| fh.to_a } end end @@ -53,7 +53,7 @@ module ActiveRecord # A valid YAML file is not necessarily a value Fixture file. Make sure # an exception is raised if the format is not valid Fixture format. def test_wrong_fixture_format_string - tmp_yaml ['empty', 'yml'], 'qwerty' do |t| + tmp_yaml ["empty", "yml"], "qwerty" do |t| assert_raises(ActiveRecord::Fixture::FormatError) do File.open(t.path) { |fh| fh.to_a } end @@ -61,7 +61,7 @@ module ActiveRecord end def test_wrong_fixture_format_nested - tmp_yaml ['empty', 'yml'], 'one: two' do |t| + tmp_yaml ["empty", "yml"], "one: two" do |t| assert_raises(ActiveRecord::Fixture::FormatError) do File.open(t.path) { |fh| fh.to_a } end @@ -75,9 +75,9 @@ module ActiveRecord end end yaml = "one:\n name: <%= fixture_helper %>\n" - tmp_yaml ['curious', 'yml'], yaml do |t| + tmp_yaml ["curious", "yml"], yaml do |t| golden = - [["one", {"name" => "Fixture helper"}]] + [["one", { "name" => "Fixture helper" }]] assert_equal golden, File.open(t.path) { |fh| fh.to_a } end ActiveRecord::FixtureSet.context_class.class_eval do @@ -95,15 +95,15 @@ one: File: <%= File.name %> END - golden = [['one', { - 'ActiveRecord' => 'constant', - 'ActiveRecord_FixtureSet' => 'constant', - 'FixtureSet' => nil, - 'ActiveRecord_FixtureSet_File' => 'constant', - 'File' => 'File' + golden = [["one", { + "ActiveRecord" => "constant", + "ActiveRecord_FixtureSet" => "constant", + "FixtureSet" => nil, + "ActiveRecord_FixtureSet_File" => "constant", + "File" => "File" }]] - tmp_yaml ['curious', 'yml'], yaml do |t| + tmp_yaml ["curious", "yml"], yaml do |t| assert_equal golden, File.open(t.path) { |fh| fh.to_a } end end @@ -113,8 +113,8 @@ END def test_independent_render_contexts yaml1 = "<% def leaked_method; 'leak'; end %>\n" yaml2 = "one:\n name: <%= leaked_method %>\n" - tmp_yaml ['leaky', 'yml'], yaml1 do |t1| - tmp_yaml ['curious', 'yml'], yaml2 do |t2| + tmp_yaml ["leaky", "yml"], yaml1 do |t1| + tmp_yaml ["curious", "yml"], yaml2 do |t2| File.open(t1.path) { |fh| fh.to_a } assert_raises(NameError) do File.open(t2.path) { |fh| fh.to_a } @@ -124,33 +124,33 @@ END end def test_removes_fixture_config_row - File.open(::File.join(FIXTURES_ROOT, 'other_posts.yml')) do |fh| - assert_equal(['second_welcome'], fh.each.map { |name, _| name }) + File.open(::File.join(FIXTURES_ROOT, "other_posts.yml")) do |fh| + assert_equal(["second_welcome"], fh.each.map { |name, _| name }) end end def test_extracts_model_class_from_config_row - File.open(::File.join(FIXTURES_ROOT, 'other_posts.yml')) do |fh| - assert_equal 'Post', fh.model_class + File.open(::File.join(FIXTURES_ROOT, "other_posts.yml")) do |fh| + assert_equal "Post", fh.model_class end end def test_erb_filename - filename = 'filename.yaml' + filename = "filename.yaml" erb = File.new(filename).send(:prepare_erb, "<% Rails.env %>\n") assert_equal erb.filename, filename end private - def tmp_yaml(name, contents) - t = Tempfile.new name - t.binmode - t.write contents - t.close - yield t - ensure - t.close true - end + def tmp_yaml(name, contents) + t = Tempfile.new name + t.binmode + t.write contents + t.close + yield t + ensure + t.close true + end end end end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 9455d4886c..3f111447ff 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -1,31 +1,31 @@ -require 'cases/helper' -require 'models/admin' -require 'models/admin/account' -require 'models/admin/randomly_named_c1' -require 'models/admin/user' -require 'models/binary' -require 'models/book' -require 'models/bulb' -require 'models/category' -require 'models/comment' -require 'models/company' -require 'models/computer' -require 'models/course' -require 'models/developer' -require 'models/doubloon' -require 'models/joke' -require 'models/matey' -require 'models/parrot' -require 'models/pirate' -require 'models/post' -require 'models/randomly_named_c1' -require 'models/reply' -require 'models/ship' -require 'models/task' -require 'models/topic' -require 'models/traffic_light' -require 'models/treasure' -require 'tempfile' +require "cases/helper" +require "models/admin" +require "models/admin/account" +require "models/admin/randomly_named_c1" +require "models/admin/user" +require "models/binary" +require "models/book" +require "models/bulb" +require "models/category" +require "models/comment" +require "models/company" +require "models/computer" +require "models/course" +require "models/developer" +require "models/doubloon" +require "models/joke" +require "models/matey" +require "models/parrot" +require "models/pirate" +require "models/post" +require "models/randomly_named_c1" +require "models/reply" +require "models/ship" +require "models/task" +require "models/topic" +require "models/traffic_light" +require "models/treasure" +require "tempfile" class FixturesTest < ActiveRecord::TestCase self.use_instantiated_fixtures = true @@ -53,12 +53,12 @@ class FixturesTest < ActiveRecord::TestCase end def test_broken_yaml_exception - badyaml = Tempfile.new ['foo', '.yml'] - badyaml.write 'a: : ' + badyaml = Tempfile.new ["foo", ".yml"] + badyaml.write "a: : " badyaml.flush dir = File.dirname badyaml.path - name = File.basename badyaml.path, '.yml' + name = File.basename badyaml.path, ".yml" assert_raises(ActiveRecord::Fixture::FormatError) do ActiveRecord::FixtureSet.create_fixtures(dir, name) end @@ -69,8 +69,8 @@ class FixturesTest < ActiveRecord::TestCase def test_create_fixtures fixtures = ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, "parrots") - assert Parrot.find_by_name('Curious George'), 'George is not in the database' - assert fixtures.detect { |f| f.name == 'parrots' }, "no fixtures named 'parrots' in #{fixtures.map(&:name).inspect}" + assert Parrot.find_by_name("Curious George"), "George is not in the database" + assert fixtures.detect { |f| f.name == "parrots" }, "no fixtures named 'parrots' in #{fixtures.map(&:name).inspect}" end def test_multiple_clean_fixtures @@ -81,10 +81,10 @@ class FixturesTest < ActiveRecord::TestCase end def test_create_symbol_fixtures - fixtures = ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, :collections, :collections => Course) { Course.connection } + fixtures = ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, :collections, collections: Course) { Course.connection } - assert Course.find_by_name('Collection'), 'course is not in the database' - assert fixtures.detect { |f| f.name == 'collections' }, "no fixtures named 'collections' in #{fixtures.map(&:name).inspect}" + assert Course.find_by_name("Collection"), "course is not in the database" + assert fixtures.detect { |f| f.name == "collections" }, "no fixtures named 'collections' in #{fixtures.map(&:name).inspect}" end def test_attributes @@ -115,10 +115,10 @@ class FixturesTest < ActiveRecord::TestCase t.column :bonus_time, :time t.column :last_read, :date t.column :content, :string - t.column :approved, :boolean, :default => true - t.column :replies_count, :integer, :default => 0 + t.column :approved, :boolean, default: true + t.column :replies_count, :integer, default: 0 t.column :parent_id, :integer - t.column :type, :string, :limit => 50 + t.column :type, :string, limit: 50 end # Store existing prefix/suffix @@ -126,8 +126,8 @@ class FixturesTest < ActiveRecord::TestCase old_suffix = ActiveRecord::Base.table_name_suffix # Set a prefix/suffix we can test against - ActiveRecord::Base.table_name_prefix = 'prefix_' - ActiveRecord::Base.table_name_suffix = '_suffix' + ActiveRecord::Base.table_name_prefix = "prefix_" + ActiveRecord::Base.table_name_suffix = "_suffix" other_topic_klass = Class.new(ActiveRecord::Base) do def self.name @@ -170,7 +170,7 @@ class FixturesTest < ActiveRecord::TestCase def test_logger_level_invariant level = ActiveRecord::Base.logger.level - create_fixtures('topics') + create_fixtures("topics") assert_equal level, ActiveRecord::Base.logger.level end @@ -229,11 +229,11 @@ class FixturesTest < ActiveRecord::TestCase def test_omap_fixtures assert_nothing_raised do - fixtures = ActiveRecord::FixtureSet.new(Account.connection, 'categories', Category, FIXTURES_ROOT + "/categories_ordered") + fixtures = ActiveRecord::FixtureSet.new(Account.connection, "categories", Category, FIXTURES_ROOT + "/categories_ordered") fixtures.each.with_index do |(name, fixture), i| assert_equal "fixture_no_#{i}", name - assert_equal "Category #{i}", fixture['name'] + assert_equal "Category #{i}", fixture["name"] end end end @@ -249,8 +249,8 @@ class FixturesTest < ActiveRecord::TestCase end def test_binary_in_fixtures - data = File.open(ASSETS_ROOT + "/flowers.jpg", 'rb') { |f| f.read } - data.force_encoding('ASCII-8BIT') + data = File.open(ASSETS_ROOT + "/flowers.jpg", "rb") { |f| f.read } + data.force_encoding("ASCII-8BIT") data.freeze assert_equal data, @flowers.data end @@ -260,8 +260,8 @@ class FixturesTest < ActiveRecord::TestCase end def test_fixtures_are_set_up_with_database_env_variable - db_url_tmp = ENV['DATABASE_URL'] - ENV['DATABASE_URL'] = "sqlite3::memory:" + db_url_tmp = ENV["DATABASE_URL"] + ENV["DATABASE_URL"] = "sqlite3::memory:" ActiveRecord::Base.stub(:configurations, {}) do test_case = Class.new(ActiveRecord::TestCase) do fixtures :accounts @@ -276,11 +276,11 @@ class FixturesTest < ActiveRecord::TestCase assert result.passed?, "Expected #{result.name} to pass:\n#{result}" end ensure - ENV['DATABASE_URL'] = db_url_tmp + ENV["DATABASE_URL"] = db_url_tmp end end -class HasManyThroughFixture < ActiveSupport::TestCase +class HasManyThroughFixture < ActiveRecord::TestCase def make_model(name) Class.new(ActiveRecord::Base) { define_singleton_method(:name) { name } } end @@ -291,17 +291,17 @@ class HasManyThroughFixture < ActiveSupport::TestCase treasure = make_model "Treasure" pt.table_name = "parrots_treasures" - pt.belongs_to :parrot, :anonymous_class => parrot - pt.belongs_to :treasure, :anonymous_class => treasure + pt.belongs_to :parrot, anonymous_class: parrot + pt.belongs_to :treasure, anonymous_class: treasure - parrot.has_many :parrot_treasures, :anonymous_class => pt - parrot.has_many :treasures, :through => :parrot_treasures + parrot.has_many :parrot_treasures, anonymous_class: pt + parrot.has_many :treasures, through: :parrot_treasures - parrots = File.join FIXTURES_ROOT, 'parrots' + parrots = File.join FIXTURES_ROOT, "parrots" fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots rows = fs.table_rows - assert_equal load_has_and_belongs_to_many['parrots_treasures'], rows['parrots_treasures'] + assert_equal load_has_and_belongs_to_many["parrots_treasures"], rows["parrots_treasures"] end def test_has_many_through_with_renamed_table @@ -309,24 +309,24 @@ class HasManyThroughFixture < ActiveSupport::TestCase parrot = make_model "Parrot" treasure = make_model "Treasure" - pt.belongs_to :parrot, :anonymous_class => parrot - pt.belongs_to :treasure, :anonymous_class => treasure + pt.belongs_to :parrot, anonymous_class: parrot + pt.belongs_to :treasure, anonymous_class: treasure - parrot.has_many :parrot_treasures, :anonymous_class => pt - parrot.has_many :treasures, :through => :parrot_treasures + parrot.has_many :parrot_treasures, anonymous_class: pt + parrot.has_many :treasures, through: :parrot_treasures - parrots = File.join FIXTURES_ROOT, 'parrots' + parrots = File.join FIXTURES_ROOT, "parrots" fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots rows = fs.table_rows - assert_equal load_has_and_belongs_to_many['parrots_treasures'], rows['parrot_treasures'] + assert_equal load_has_and_belongs_to_many["parrots_treasures"], rows["parrot_treasures"] end def load_has_and_belongs_to_many parrot = make_model "Parrot" parrot.has_and_belongs_to_many :treasures - parrots = File.join FIXTURES_ROOT, 'parrots' + parrots = File.join FIXTURES_ROOT, "parrots" fs = ActiveRecord::FixtureSet.new parrot.connection, "parrots", parrot, parrots fs.table_rows @@ -339,7 +339,7 @@ if Account.connection.respond_to?(:reset_pk_sequence!) fixtures :companies def setup - @instances = [Account.new(:credit_limit => 50), Company.new(:name => 'RoR Consulting'), Course.new(name: 'Test')] + @instances = [Account.new(credit_limit: 50), Company.new(name: "RoR Consulting"), Course.new(name: "Test")] ActiveRecord::FixtureSet.reset_cache # make sure tables get reinitialized end @@ -368,7 +368,7 @@ if Account.connection.respond_to?(:reset_pk_sequence!) def test_create_fixtures_resets_sequences_when_not_cached @instances.each do |instance| max_id = create_fixtures(instance.class.table_name).first.fixtures.inject(0) do |_max_id, (_, fixture)| - fixture_id = fixture['id'].to_i + fixture_id = fixture["id"].to_i fixture_id > _max_id ? fixture_id : _max_id end @@ -414,7 +414,7 @@ class FixturesWithoutInstantiationTest < ActiveRecord::TestCase def test_reloading_fixtures_through_accessor_methods topic = Struct.new(:title) assert_equal "The First Topic", topics(:first).title - assert_called(@loaded_fixtures['topics']['first'], :find, returns: topic.new("Fresh Topic!")) do + assert_called(@loaded_fixtures["topics"]["first"], :find, returns: topic.new("Fresh Topic!")) do assert_equal "Fresh Topic!", topics(:first, true).title end end @@ -479,7 +479,6 @@ class SetupSubclassTest < SetupTest end end - class OverlappingFixturesTest < ActiveRecord::TestCase fixtures :topics, :developers fixtures :developers, :accounts @@ -510,13 +509,13 @@ class OverRideFixtureMethodTest < ActiveRecord::TestCase def topics(name) topic = super - topic.title = 'omg' + topic.title = "omg" topic end def test_fixture_methods_can_be_overridden x = topics :first - assert_equal 'omg', x.title + assert_equal "omg", x.title end end @@ -553,7 +552,7 @@ class SetFixtureClassPrevailsTest < ActiveRecord::TestCase end class CheckSetTableNameFixturesTest < ActiveRecord::TestCase - set_fixture_class :funny_jokes => Joke + set_fixture_class funny_jokes: Joke fixtures :funny_jokes # Set to false to blow away fixtures cache and ensure our fixtures are loaded # and thus takes into account our set_fixture_class @@ -565,7 +564,7 @@ class CheckSetTableNameFixturesTest < ActiveRecord::TestCase end class FixtureNameIsNotTableNameFixturesTest < ActiveRecord::TestCase - set_fixture_class :items => Book + set_fixture_class items: Book fixtures :items # Set to false to blow away fixtures cache and ensure our fixtures are loaded # and thus takes into account our set_fixture_class @@ -577,7 +576,7 @@ class FixtureNameIsNotTableNameFixturesTest < ActiveRecord::TestCase end class FixtureNameIsNotTableNameMultipleFixturesTest < ActiveRecord::TestCase - set_fixture_class :items => Book, :funny_jokes => Joke + set_fixture_class items: Book, funny_jokes: Joke fixtures :items, :funny_jokes # Set to false to blow away fixtures cache and ensure our fixtures are loaded # and thus takes into account our set_fixture_class @@ -593,7 +592,7 @@ class FixtureNameIsNotTableNameMultipleFixturesTest < ActiveRecord::TestCase end class CustomConnectionFixturesTest < ActiveRecord::TestCase - set_fixture_class :courses => Course + set_fixture_class courses: Course fixtures :courses self.use_transactional_tests = false @@ -608,7 +607,7 @@ class CustomConnectionFixturesTest < ActiveRecord::TestCase end class TransactionalFixturesOnCustomConnectionTest < ActiveRecord::TestCase - set_fixture_class :courses => Course + set_fixture_class courses: Course fixtures :courses self.use_transactional_tests = true @@ -622,6 +621,46 @@ class TransactionalFixturesOnCustomConnectionTest < ActiveRecord::TestCase end end +class TransactionalFixturesOnConnectionNotification < ActiveRecord::TestCase + self.use_transactional_tests = true + self.use_instantiated_fixtures = false + + def test_transaction_created_on_connection_notification + connection = stub(transaction_open?: false) + connection.expects(:begin_transaction).with(joinable: false) + fire_connection_notification(connection) + end + + def test_notification_established_transactions_are_rolled_back + # Mocha is not thread-safe so define our own stub to test + connection = Class.new do + attr_accessor :rollback_transaction_called + def transaction_open?; true; end + def begin_transaction(*args); end + def rollback_transaction(*args) + @rollback_transaction_called = true + end + end.new + fire_connection_notification(connection) + teardown_fixtures + assert(connection.rollback_transaction_called, "Expected <mock connection>#rollback_transaction to be called but was not") + end + + private + + def fire_connection_notification(connection) + ActiveRecord::Base.connection_handler.stubs(:retrieve_connection).with("book").returns(connection) + message_bus = ActiveSupport::Notifications.instrumenter + payload = { + spec_name: "book", + config: nil, + connection_id: connection.object_id + } + + message_bus.instrument("!connection.active_record", payload) {} + end +end + class InvalidTableNameFixturesTest < ActiveRecord::TestCase fixtures :funny_jokes # Set to false to blow away fixtures cache and ensure our fixtures are loaded @@ -636,7 +675,7 @@ class InvalidTableNameFixturesTest < ActiveRecord::TestCase end class CheckEscapedYamlFixturesTest < ActiveRecord::TestCase - set_fixture_class :funny_jokes => Joke + set_fixture_class funny_jokes: Joke fixtures :funny_jokes # Set to false to blow away fixtures cache and ensure our fixtures are loaded # and thus takes into account our set_fixture_class @@ -679,7 +718,7 @@ class FixturesBrokenRollbackTest < ActiveRecord::TestCase private def load_fixtures(config) - raise 'argh' + raise "argh" end end @@ -689,7 +728,7 @@ class LoadAllFixturesTest < ActiveRecord::TestCase self.class.fixtures :all if File.symlink? FIXTURES_ROOT + "/all/admin" - assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort end ensure ActiveRecord::FixtureSet.reset_cache @@ -698,11 +737,11 @@ end class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase def test_all_there - self.class.fixture_path = Pathname.new(FIXTURES_ROOT).join('all') + self.class.fixture_path = Pathname.new(FIXTURES_ROOT).join("all") self.class.fixtures :all if File.symlink? FIXTURES_ROOT + "/all/admin" - assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort end ensure ActiveRecord::FixtureSet.reset_cache @@ -720,18 +759,18 @@ class FasterFixturesTest < ActiveRecord::TestCase end def test_cache - assert ActiveRecord::FixtureSet.fixture_is_cached?(ActiveRecord::Base.connection, 'categories') - assert ActiveRecord::FixtureSet.fixture_is_cached?(ActiveRecord::Base.connection, 'authors') + assert ActiveRecord::FixtureSet.fixture_is_cached?(ActiveRecord::Base.connection, "categories") + assert ActiveRecord::FixtureSet.fixture_is_cached?(ActiveRecord::Base.connection, "authors") assert_no_queries do - create_fixtures('categories') - create_fixtures('authors') + create_fixtures("categories") + create_fixtures("authors") end - load_extra_fixture('posts') - assert ActiveRecord::FixtureSet.fixture_is_cached?(ActiveRecord::Base.connection, 'posts') + load_extra_fixture("posts") + assert ActiveRecord::FixtureSet.fixture_is_cached?(ActiveRecord::Base.connection, "posts") self.class.setup_fixture_accessors :posts - assert_equal 'Welcome to the weblog', posts(:welcome).title + assert_equal "Welcome to the weblog", posts(:welcome).title end end @@ -739,9 +778,9 @@ class FoxyFixturesTest < ActiveRecord::TestCase fixtures :parrots, :parrots_pirates, :pirates, :treasures, :mateys, :ships, :computers, :developers, :"admin/accounts", :"admin/users", :live_parrots, :dead_parrots, :books - if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' - require 'models/uuid_parent' - require 'models/uuid_child' + if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + require "models/uuid_parent" + require "models/uuid_child" fixtures :uuid_parents, :uuid_children end @@ -758,8 +797,8 @@ class FoxyFixturesTest < ActiveRecord::TestCase assert_equal 207281424, ActiveRecord::FixtureSet.identify(:ruby) assert_equal 1066363776, ActiveRecord::FixtureSet.identify(:sapphire_2) - assert_equal 'f92b6bda-0d0d-5fe1-9124-502b18badded', ActiveRecord::FixtureSet.identify(:daddy, :uuid) - assert_equal 'b4b10018-ad47-595d-b42f-d8bdaa6d01bf', ActiveRecord::FixtureSet.identify(:sonny, :uuid) + assert_equal "f92b6bda-0d0d-5fe1-9124-502b18badded", ActiveRecord::FixtureSet.identify(:daddy, :uuid) + assert_equal "b4b10018-ad47-595d-b42f-d8bdaa6d01bf", ActiveRecord::FixtureSet.identify(:sonny, :uuid) end TIMESTAMP_COLUMNS = %w(created_at created_on updated_at updated_on) @@ -884,7 +923,7 @@ class FoxyFixturesTest < ActiveRecord::TestCase end def test_namespaced_models - assert admin_accounts(:signals37).users.include?(admin_users(:david)) + assert_includes admin_accounts(:signals37).users, admin_users(:david) assert_equal 2, admin_accounts(:signals37).users.size end @@ -913,10 +952,10 @@ class CustomNameForFixtureOrModelTest < ActiveRecord::TestCase ClassNameThatDoesNotFollowCONVENTIONS, :'admin/randomly_named_a9' => Admin::ClassNameThatDoesNotFollowCONVENTIONS1, - 'admin/randomly_named_b0' => + "admin/randomly_named_b0" => Admin::ClassNameThatDoesNotFollowCONVENTIONS2 - fixtures :randomly_named_a9, 'admin/randomly_named_a9', + fixtures :randomly_named_a9, "admin/randomly_named_a9", :'admin/randomly_named_b0' def test_named_accessor_for_randomly_named_fixture_and_class @@ -932,8 +971,8 @@ class CustomNameForFixtureOrModelTest < ActiveRecord::TestCase end def test_table_name_is_defined_in_the_model - assert_equal 'randomly_named_table2', ActiveRecord::FixtureSet::all_loaded_fixtures["admin/randomly_named_a9"].table_name - assert_equal 'randomly_named_table2', Admin::ClassNameThatDoesNotFollowCONVENTIONS1.table_name + assert_equal "randomly_named_table2", ActiveRecord::FixtureSet::all_loaded_fixtures["admin/randomly_named_a9"].table_name + assert_equal "randomly_named_table2", Admin::ClassNameThatDoesNotFollowCONVENTIONS1.table_name end end @@ -965,10 +1004,10 @@ class FixtureClassNamesTest < ActiveRecord::TestCase end def teardown - self.fixture_class_names.replace(@saved_cache) + fixture_class_names.replace(@saved_cache) end test "fixture_class_names returns nil for unregistered identifier" do - assert_nil self.fixture_class_names['unregistered_identifier'] + assert_nil fixture_class_names["unregistered_identifier"] end end diff --git a/activerecord/test/cases/forbidden_attributes_protection_test.rb b/activerecord/test/cases/forbidden_attributes_protection_test.rb index 91921469b8..75c3493527 100644 --- a/activerecord/test/cases/forbidden_attributes_protection_test.rb +++ b/activerecord/test/cases/forbidden_attributes_protection_test.rb @@ -1,11 +1,11 @@ -require 'cases/helper' -require 'active_support/core_ext/hash/indifferent_access' +require "cases/helper" +require "active_support/core_ext/hash/indifferent_access" -require 'models/company' -require 'models/person' -require 'models/ship' -require 'models/ship_part' -require 'models/treasure' +require "models/company" +require "models/person" +require "models/ship" +require "models/ship_part" +require "models/treasure" class ProtectedParams attr_accessor :permitted @@ -44,40 +44,40 @@ end class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase def test_forbidden_attributes_cannot_be_used_for_mass_assignment - params = ProtectedParams.new(first_name: 'Guille', gender: 'm') + params = ProtectedParams.new(first_name: "Guille", gender: "m") assert_raises(ActiveModel::ForbiddenAttributesError) do Person.new(params) end end def test_permitted_attributes_can_be_used_for_mass_assignment - params = ProtectedParams.new(first_name: 'Guille', gender: 'm') + params = ProtectedParams.new(first_name: "Guille", gender: "m") params.permit! person = Person.new(params) - assert_equal 'Guille', person.first_name - assert_equal 'm', person.gender + assert_equal "Guille", person.first_name + assert_equal "m", person.gender end def test_forbidden_attributes_cannot_be_used_for_sti_inheritance_column - params = ProtectedParams.new(type: 'Client') + params = ProtectedParams.new(type: "Client") assert_raises(ActiveModel::ForbiddenAttributesError) do Company.new(params) end end def test_permitted_attributes_can_be_used_for_sti_inheritance_column - params = ProtectedParams.new(type: 'Client') + params = ProtectedParams.new(type: "Client") params.permit! person = Company.new(params) assert_equal person.class, Client end def test_regular_hash_should_still_be_used_for_mass_assignment - person = Person.new(first_name: 'Guille', gender: 'm') + person = Person.new(first_name: "Guille", gender: "m") - assert_equal 'Guille', person.first_name - assert_equal 'm', person.gender + assert_equal "Guille", person.first_name + assert_equal "m", person.gender end def test_blank_attributes_should_not_raise @@ -86,7 +86,7 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase end def test_create_with_checks_permitted - params = ProtectedParams.new(first_name: 'Guille', gender: 'm') + params = ProtectedParams.new(first_name: "Guille", gender: "m") assert_raises(ActiveModel::ForbiddenAttributesError) do Person.create_with(params).create! @@ -94,21 +94,21 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase end def test_create_with_works_with_permitted_params - params = ProtectedParams.new(first_name: 'Guille').permit! + params = ProtectedParams.new(first_name: "Guille").permit! person = Person.create_with(params).create! - assert_equal 'Guille', person.first_name + assert_equal "Guille", person.first_name end def test_create_with_works_with_params_values - params = ProtectedParams.new(first_name: 'Guille') + params = ProtectedParams.new(first_name: "Guille") person = Person.create_with(first_name: params[:first_name]).create! - assert_equal 'Guille', person.first_name + assert_equal "Guille", person.first_name end def test_where_checks_permitted - params = ProtectedParams.new(first_name: 'Guille', gender: 'm') + params = ProtectedParams.new(first_name: "Guille", gender: "m") assert_raises(ActiveModel::ForbiddenAttributesError) do Person.where(params).create! @@ -116,21 +116,21 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase end def test_where_works_with_permitted_params - params = ProtectedParams.new(first_name: 'Guille').permit! + params = ProtectedParams.new(first_name: "Guille").permit! person = Person.where(params).create! - assert_equal 'Guille', person.first_name + assert_equal "Guille", person.first_name end def test_where_works_with_params_values - params = ProtectedParams.new(first_name: 'Guille') + params = ProtectedParams.new(first_name: "Guille") person = Person.where(first_name: params[:first_name]).create! - assert_equal 'Guille', person.first_name + assert_equal "Guille", person.first_name end def test_where_not_checks_permitted - params = ProtectedParams.new(first_name: 'Guille', gender: 'm') + params = ProtectedParams.new(first_name: "Guille", gender: "m") assert_raises(ActiveModel::ForbiddenAttributesError) do Person.where().not(params) @@ -138,9 +138,9 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase end def test_where_not_works_with_permitted_params - params = ProtectedParams.new(first_name: 'Guille').permit! + params = ProtectedParams.new(first_name: "Guille").permit! Person.create!(params) - assert_empty Person.where.not(params).select {|p| p.first_name == 'Guille' } + assert_empty Person.where.not(params).select { |p| p.first_name == "Guille" } end def test_strong_params_style_objects_work_with_singular_associations @@ -161,5 +161,4 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase assert_equal "Necklace", part.trinkets[0].name assert_equal "Spoon", part.trinkets[1].name end - end diff --git a/activerecord/test/cases/habtm_destroy_order_test.rb b/activerecord/test/cases/habtm_destroy_order_test.rb index 2ce0de360e..365d4576dd 100644 --- a/activerecord/test/cases/habtm_destroy_order_test.rb +++ b/activerecord/test/cases/habtm_destroy_order_test.rb @@ -4,21 +4,21 @@ require "models/student" class HabtmDestroyOrderTest < ActiveRecord::TestCase test "may not delete a lesson with students" do - sicp = Lesson.new(:name => "SICP") - ben = Student.new(:name => "Ben Bitdiddle") + sicp = Lesson.new(name: "SICP") + ben = Student.new(name: "Ben Bitdiddle") sicp.students << ben sicp.save! assert_raises LessonError do - assert_no_difference('Lesson.count') do + assert_no_difference("Lesson.count") do sicp.destroy end end assert !sicp.destroyed? end - test 'should not raise error if have foreign key in the join table' do - student = Student.new(:name => "Ben Bitdiddle") - lesson = Lesson.new(:name => "SICP") + test "should not raise error if have foreign key in the join table" do + student = Student.new(name: "Ben Bitdiddle") + lesson = Lesson.new(name: "SICP") lesson.students << student lesson.save! assert_nothing_raised do @@ -29,8 +29,8 @@ class HabtmDestroyOrderTest < ActiveRecord::TestCase test "not destroying a student with lessons leaves student<=>lesson association intact" do # test a normal before_destroy doesn't destroy the habtm joins begin - sicp = Lesson.new(:name => "SICP") - ben = Student.new(:name => "Ben Bitdiddle") + sicp = Lesson.new(name: "SICP") + ben = Student.new(name: "Ben Bitdiddle") # add a before destroy to student Student.class_eval do before_destroy do @@ -49,8 +49,8 @@ class HabtmDestroyOrderTest < ActiveRecord::TestCase test "not destroying a lesson with students leaves student<=>lesson association intact" do # test a more aggressive before_destroy doesn't destroy the habtm joins and still throws the exception - sicp = Lesson.new(:name => "SICP") - ben = Student.new(:name => "Ben Bitdiddle") + sicp = Lesson.new(name: "SICP") + ben = Student.new(name: "Ben Bitdiddle") sicp.students << ben sicp.save! assert_raises LessonError do diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index d2fdf03e9d..f1d69a215a 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -1,17 +1,15 @@ -require 'config' +require "config" -require 'active_support/testing/autorun' -require 'active_support/testing/method_call_assertions' -require 'stringio' +require "stringio" -require 'active_record' -require 'cases/test_case' -require 'active_support/dependencies' -require 'active_support/logger' -require 'active_support/core_ext/string/strip' +require "active_record" +require "cases/test_case" +require "active_support/dependencies" +require "active_support/logger" +require "active_support/core_ext/string/strip" -require 'support/config' -require 'support/connection' +require "support/config" +require "support/connection" # TODO: Move all these random hacks into the ARTest namespace and into the support/ dir @@ -27,7 +25,7 @@ I18n.enforce_available_locales = false ARTest.connect # Quote "type" if it's a reserved word for the current connection. -QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') +QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name("type") # FIXME: Remove this when the deprecation cycle on TZ aware types by default ends. ActiveRecord::Base.time_zone_aware_types << :time @@ -49,18 +47,18 @@ def subsecond_precision_supported? end def mysql_enforcing_gtid_consistency? - current_adapter?(:Mysql2Adapter) && 'ON' == ActiveRecord::Base.connection.show_variable('enforce_gtid_consistency') + current_adapter?(:Mysql2Adapter) && "ON" == ActiveRecord::Base.connection.show_variable("enforce_gtid_consistency") end def supports_savepoints? ActiveRecord::Base.connection.supports_savepoints? end -def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz +def with_env_tz(new_tz = "US/Eastern") + old_tz, ENV["TZ"] = ENV["TZ"], new_tz yield ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + old_tz ? ENV["TZ"] = old_tz : ENV.delete("TZ") end def with_timezone_config(cfg) @@ -134,21 +132,6 @@ def disable_extension!(extension, connection) connection.reconnect! end -require "cases/validations_repair_helper" -class ActiveSupport::TestCase - include ActiveRecord::TestFixtures - include ActiveRecord::ValidationsRepairHelper - include ActiveSupport::Testing::MethodCallAssertions - - self.fixture_path = FIXTURES_ROOT - self.use_instantiated_fixtures = false - self.use_transactional_tests = true - - def create_fixtures(*fixture_set_names, &block) - ActiveRecord::FixtureSet.create_fixtures(ActiveSupport::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block) - end -end - def load_schema # silence verbose schema loading original_stdout = $stdout @@ -188,17 +171,17 @@ end module InTimeZone private - def in_time_zone(zone) - old_zone = Time.zone - old_tz = ActiveRecord::Base.time_zone_aware_attributes - - Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil - ActiveRecord::Base.time_zone_aware_attributes = !zone.nil? - yield - ensure - Time.zone = old_zone - ActiveRecord::Base.time_zone_aware_attributes = old_tz - end + def in_time_zone(zone) + old_zone = Time.zone + old_tz = ActiveRecord::Base.time_zone_aware_attributes + + Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil + ActiveRecord::Base.time_zone_aware_attributes = !zone.nil? + yield + ensure + Time.zone = old_zone + ActiveRecord::Base.time_zone_aware_attributes = old_tz + end end -require 'mocha/setup' # FIXME: stop using mocha +require "mocha/setup" # FIXME: stop using mocha diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb index 9fc75b7377..e107ff2362 100644 --- a/activerecord/test/cases/hot_compatibility_test.rb +++ b/activerecord/test/cases/hot_compatibility_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'support/connection_helper' +require "cases/helper" +require "support/connection_helper" class HotCompatibilityTest < ActiveRecord::TestCase self.use_transactional_tests = false @@ -12,7 +12,7 @@ class HotCompatibilityTest < ActiveRecord::TestCase t.string :bar end - def self.name; 'HotCompatibility'; end + def self.name; "HotCompatibility"; end end end @@ -35,29 +35,29 @@ class HotCompatibilityTest < ActiveRecord::TestCase # but we can successfully create a record so long as we don't # reference the removed column - record = @klass.create! foo: 'foo' + record = @klass.create! foo: "foo" record.reload - assert_equal 'foo', record.foo + assert_equal "foo", record.foo end test "update after remove_column" do - record = @klass.create! foo: 'foo' + record = @klass.create! foo: "foo" assert_equal 3, @klass.columns.length @klass.connection.remove_column :hot_compatibilities, :bar assert_equal 3, @klass.columns.length record.reload - assert_equal 'foo', record.foo - record.foo = 'bar' + assert_equal "foo", record.foo + record.foo = "bar" record.save! record.reload - assert_equal 'bar', record.foo + assert_equal "bar", record.foo end if current_adapter?(:PostgreSQLAdapter) test "cleans up after prepared statement failure in a transaction" do with_two_connections do |original_connection, ddl_connection| - record = @klass.create! bar: 'bar' + record = @klass.create! bar: "bar" # prepare the reload statement in a transaction @klass.transaction do @@ -83,7 +83,7 @@ class HotCompatibilityTest < ActiveRecord::TestCase test "cleans up after prepared statement failure in nested transactions" do with_two_connections do |original_connection, ddl_connection| - record = @klass.create! bar: 'bar' + record = @klass.create! bar: "bar" # prepare the reload statement in a transaction @klass.transaction do @@ -114,29 +114,29 @@ class HotCompatibilityTest < ActiveRecord::TestCase private - def get_prepared_statement_cache(connection) - connection.instance_variable_get(:@statements) - .instance_variable_get(:@cache)[Process.pid] - end + def get_prepared_statement_cache(connection) + connection.instance_variable_get(:@statements) + .instance_variable_get(:@cache)[Process.pid] + end - # Rails will automatically clear the prepared statements on the connection - # that runs the migration, so we use two connections to simulate what would - # actually happen on a production system; we'd have one connection running the - # migration from the rake task ("ddl_connection" here), and we'd have another - # connection in a web worker. - def with_two_connections - run_without_connection do |original_connection| - ActiveRecord::Base.establish_connection(original_connection.merge(pool_size: 2)) - begin - ddl_connection = ActiveRecord::Base.connection_pool.checkout + # Rails will automatically clear the prepared statements on the connection + # that runs the migration, so we use two connections to simulate what would + # actually happen on a production system; we'd have one connection running the + # migration from the rake task ("ddl_connection" here), and we'd have another + # connection in a web worker. + def with_two_connections + run_without_connection do |original_connection| + ActiveRecord::Base.establish_connection(original_connection.merge(pool_size: 2)) begin - yield original_connection, ddl_connection + ddl_connection = ActiveRecord::Base.connection_pool.checkout + begin + yield original_connection, ddl_connection + ensure + ActiveRecord::Base.connection_pool.checkin ddl_connection + end ensure - ActiveRecord::Base.connection_pool.checkin ddl_connection + ActiveRecord::Base.clear_all_connections! end - ensure - ActiveRecord::Base.clear_all_connections! end end - end end diff --git a/activerecord/test/cases/i18n_test.rb b/activerecord/test/cases/i18n_test.rb index a428f1d87b..7f03c5b23d 100644 --- a/activerecord/test/cases/i18n_test.rb +++ b/activerecord/test/cases/i18n_test.rb @@ -1,45 +1,44 @@ require "cases/helper" -require 'models/topic' -require 'models/reply' +require "models/topic" +require "models/reply" class ActiveRecordI18nTests < ActiveRecord::TestCase - def setup I18n.backend = I18n::Backend::Simple.new end def test_translated_model_attributes - I18n.backend.store_translations 'en', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } } - assert_equal 'topic title attribute', Topic.human_attribute_name('title') + I18n.backend.store_translations "en", activerecord: { attributes: { topic: { title: "topic title attribute" } } } + assert_equal "topic title attribute", Topic.human_attribute_name("title") end def test_translated_model_attributes_with_symbols - I18n.backend.store_translations 'en', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } } - assert_equal 'topic title attribute', Topic.human_attribute_name(:title) + I18n.backend.store_translations "en", activerecord: { attributes: { topic: { title: "topic title attribute" } } } + assert_equal "topic title attribute", Topic.human_attribute_name(:title) end def test_translated_model_attributes_with_sti - I18n.backend.store_translations 'en', :activerecord => {:attributes => {:reply => {:title => 'reply title attribute'} } } - assert_equal 'reply title attribute', Reply.human_attribute_name('title') + I18n.backend.store_translations "en", activerecord: { attributes: { reply: { title: "reply title attribute" } } } + assert_equal "reply title attribute", Reply.human_attribute_name("title") end def test_translated_model_attributes_with_sti_fallback - I18n.backend.store_translations 'en', :activerecord => {:attributes => {:topic => {:title => 'topic title attribute'} } } - assert_equal 'topic title attribute', Reply.human_attribute_name('title') + I18n.backend.store_translations "en", activerecord: { attributes: { topic: { title: "topic title attribute" } } } + assert_equal "topic title attribute", Reply.human_attribute_name("title") end def test_translated_model_names - I18n.backend.store_translations 'en', :activerecord => {:models => {:topic => 'topic model'} } - assert_equal 'topic model', Topic.model_name.human + I18n.backend.store_translations "en", activerecord: { models: { topic: "topic model" } } + assert_equal "topic model", Topic.model_name.human end def test_translated_model_names_with_sti - I18n.backend.store_translations 'en', :activerecord => {:models => {:reply => 'reply model'} } - assert_equal 'reply model', Reply.model_name.human + I18n.backend.store_translations "en", activerecord: { models: { reply: "reply model" } } + assert_equal "reply model", Reply.model_name.human end def test_translated_model_names_with_sti_fallback - I18n.backend.store_translations 'en', :activerecord => {:models => {:topic => 'topic model'} } - assert_equal 'topic model', Reply.model_name.human + I18n.backend.store_translations "en", activerecord: { models: { topic: "topic model" } } + assert_equal "topic model", Reply.model_name.human end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index e234b9a6a9..9ad4664567 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -1,13 +1,13 @@ -require 'cases/helper' -require 'models/author' -require 'models/company' -require 'models/person' -require 'models/post' -require 'models/project' -require 'models/subscriber' -require 'models/vegetables' -require 'models/shop' -require 'models/sponsor' +require "cases/helper" +require "models/author" +require "models/company" +require "models/person" +require "models/post" +require "models/project" +require "models/subscriber" +require "models/vegetables" +require "models/shop" +require "models/sponsor" module InheritanceTestHelper def with_store_full_sti_class(&block) @@ -33,7 +33,7 @@ class InheritanceTest < ActiveRecord::TestCase def test_class_with_store_full_sti_class_returns_full_name with_store_full_sti_class do - assert_equal 'Namespaced::Company', Namespaced::Company.sti_name + assert_equal "Namespaced::Company", Namespaced::Company.sti_name end end @@ -42,37 +42,37 @@ class InheritanceTest < ActiveRecord::TestCase company = company.dup company.extend(Module.new { def _read_attribute(name) - return ' ' if name == 'type' + return " " if name == "type" super end }) company.save! company = Company.all.to_a.find { |x| x.id == company.id } - assert_equal ' ', company.type + assert_equal " ", company.type end def test_class_without_store_full_sti_class_returns_demodulized_name without_store_full_sti_class do - assert_equal 'Company', Namespaced::Company.sti_name + assert_equal "Company", Namespaced::Company.sti_name end end def test_compute_type_success - assert_equal Author, ActiveRecord::Base.send(:compute_type, 'Author') + assert_equal Author, ActiveRecord::Base.send(:compute_type, "Author") end def test_compute_type_nonexistent_constant e = assert_raises NameError do - ActiveRecord::Base.send :compute_type, 'NonexistentModel' + ActiveRecord::Base.send :compute_type, "NonexistentModel" end - assert_equal 'uninitialized constant ActiveRecord::Base::NonexistentModel', e.message - assert_equal 'ActiveRecord::Base::NonexistentModel', e.name + assert_equal "uninitialized constant ActiveRecord::Base::NonexistentModel", e.message + assert_equal "ActiveRecord::Base::NonexistentModel", e.name end def test_compute_type_no_method_error - ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise NoMethodError }) do + ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise NoMethodError }) do assert_raises NoMethodError do - ActiveRecord::Base.send :compute_type, 'InvalidModel' + ActiveRecord::Base.send :compute_type, "InvalidModel" end end end @@ -87,19 +87,19 @@ class InheritanceTest < ActiveRecord::TestCase error = e end - ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise e }) do + ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise e }) do exception = assert_raises NameError do - ActiveRecord::Base.send :compute_type, 'InvalidModel' + ActiveRecord::Base.send :compute_type, "InvalidModel" end assert_equal error.message, exception.message end end def test_compute_type_argument_error - ActiveSupport::Dependencies.stub(:safe_constantize, proc{ raise ArgumentError }) do + ActiveSupport::Dependencies.stub(:safe_constantize, proc { raise ArgumentError }) do assert_raises ArgumentError do - ActiveRecord::Base.send :compute_type, 'InvalidModel' + ActiveRecord::Base.send :compute_type, "InvalidModel" end end end @@ -107,14 +107,14 @@ class InheritanceTest < ActiveRecord::TestCase def test_should_store_demodulized_class_name_with_store_full_sti_class_option_disabled without_store_full_sti_class do item = Namespaced::Company.new - assert_equal 'Company', item[:type] + assert_equal "Company", item[:type] end end def test_should_store_full_class_name_with_store_full_sti_class_option_enabled with_store_full_sti_class do item = Namespaced::Company.new - assert_equal 'Namespaced::Company', item[:type] + assert_equal "Namespaced::Company", item[:type] end end @@ -154,9 +154,9 @@ class InheritanceTest < ActiveRecord::TestCase def test_company_descends_from_active_record assert !ActiveRecord::Base.descends_from_active_record? - assert AbstractCompany.descends_from_active_record?, 'AbstractCompany should descend from ActiveRecord::Base' - assert Company.descends_from_active_record?, 'Company should descend from ActiveRecord::Base' - assert !Class.new(Company).descends_from_active_record?, 'Company subclass should not descend from ActiveRecord::Base' + assert AbstractCompany.descends_from_active_record?, "AbstractCompany should descend from ActiveRecord::Base" + assert Company.descends_from_active_record?, "Company should descend from ActiveRecord::Base" + assert !Class.new(Company).descends_from_active_record?, "Company subclass should not descend from ActiveRecord::Base" end def test_abstract_class @@ -214,7 +214,7 @@ class InheritanceTest < ActiveRecord::TestCase def test_becomes_and_change_tracking_for_inheritance_columns cucumber = Vegetable.find(1) cabbage = cucumber.becomes!(Cabbage) - assert_equal ['Cucumber', 'Cabbage'], cabbage.custom_type_change + assert_equal ["Cucumber", "Cabbage"], cabbage.custom_type_change end def test_alt_becomes_bang_resets_inheritance_type_column @@ -229,13 +229,13 @@ class InheritanceTest < ActiveRecord::TestCase end def test_inheritance_find_all - companies = Company.all.merge!(:order => 'id').to_a + companies = Company.all.merge!(order: "id").to_a assert_kind_of Firm, companies[0], "37signals should be a firm" assert_kind_of Client, companies[1], "Summit should be a client" end def test_alt_inheritance_find_all - companies = Vegetable.all.merge!(:order => 'id').to_a + companies = Vegetable.all.merge!(order: "id").to_a assert_kind_of Cucumber, companies[0] assert_kind_of Cabbage, companies[1] end @@ -250,7 +250,7 @@ class InheritanceTest < ActiveRecord::TestCase end def test_alt_inheritance_save - cabbage = Cabbage.new(:name => 'Savoy') + cabbage = Cabbage.new(name: "Savoy") cabbage.save! savoy = Vegetable.find(cabbage.id) @@ -263,12 +263,12 @@ class InheritanceTest < ActiveRecord::TestCase end def test_inheritance_new_with_base_class - company = Company.new(:type => 'Company') + company = Company.new(type: "Company") assert_equal Company, company.class end def test_inheritance_new_with_subclass - firm = Company.new(:type => 'Firm') + firm = Company.new(type: "Firm") assert_equal Firm, firm.class end @@ -287,17 +287,17 @@ class InheritanceTest < ActiveRecord::TestCase end def test_new_with_invalid_type - assert_raise(ActiveRecord::SubclassNotFound) { Company.new(:type => 'InvalidType') } + assert_raise(ActiveRecord::SubclassNotFound) { Company.new(type: "InvalidType") } end def test_new_with_unrelated_type - assert_raise(ActiveRecord::SubclassNotFound) { Company.new(:type => 'Account') } + assert_raise(ActiveRecord::SubclassNotFound) { Company.new(type: "Account") } end def test_new_with_unrelated_namespaced_type without_store_full_sti_class do e = assert_raises ActiveRecord::SubclassNotFound do - Namespaced::Company.new(type: 'Firm') + Namespaced::Company.new(type: "Firm") end assert_equal "Invalid single-table inheritance type: Namespaced::Firm is not a subclass of Namespaced::Company", e.message @@ -305,21 +305,21 @@ class InheritanceTest < ActiveRecord::TestCase end def test_new_with_complex_inheritance - assert_nothing_raised { Client.new(type: 'VerySpecialClient') } + assert_nothing_raised { Client.new(type: "VerySpecialClient") } end def test_new_without_storing_full_sti_class without_store_full_sti_class do - item = Company.new(type: 'SpecialCo') + item = Company.new(type: "SpecialCo") assert_instance_of Company::SpecialCo, item end end def test_new_with_autoload_paths - path = File.expand_path('../../models/autoloadable', __FILE__) + path = File.expand_path("../../models/autoloadable", __FILE__) ActiveSupport::Dependencies.autoload_paths << path - firm = Company.new(:type => 'ExtraFirm') + firm = Company.new(type: "ExtraFirm") assert_equal ExtraFirm, firm.class ensure ActiveSupport::Dependencies.autoload_paths.reject! { |p| p == path } @@ -352,7 +352,7 @@ class InheritanceTest < ActiveRecord::TestCase Client.update_all "name = 'I am a client'" assert_equal "I am a client", Client.first.name # Order by added as otherwise Oracle tests were failing because of different order of results - assert_equal "37signals", Firm.all.merge!(:order => "id").to_a.first.name + assert_equal "37signals", Firm.all.merge!(order: "id").to_a.first.name end def test_alt_update_all_within_inheritance @@ -374,51 +374,51 @@ class InheritanceTest < ActiveRecord::TestCase end def test_find_first_within_inheritance - assert_kind_of Firm, Company.all.merge!(:where => "name = '37signals'").first - assert_kind_of Firm, Firm.all.merge!(:where => "name = '37signals'").first - assert_nil Client.all.merge!(:where => "name = '37signals'").first + assert_kind_of Firm, Company.all.merge!(where: "name = '37signals'").first + assert_kind_of Firm, Firm.all.merge!(where: "name = '37signals'").first + assert_nil Client.all.merge!(where: "name = '37signals'").first end def test_alt_find_first_within_inheritance - assert_kind_of Cabbage, Vegetable.all.merge!(:where => "name = 'his cabbage'").first - assert_kind_of Cabbage, Cabbage.all.merge!(:where => "name = 'his cabbage'").first - assert_nil Cucumber.all.merge!(:where => "name = 'his cabbage'").first + assert_kind_of Cabbage, Vegetable.all.merge!(where: "name = 'his cabbage'").first + assert_kind_of Cabbage, Cabbage.all.merge!(where: "name = 'his cabbage'").first + assert_nil Cucumber.all.merge!(where: "name = 'his cabbage'").first end def test_complex_inheritance very_special_client = VerySpecialClient.create("name" => "veryspecial") assert_equal very_special_client, VerySpecialClient.where("name = 'veryspecial'").first - assert_equal very_special_client, SpecialClient.all.merge!(:where => "name = 'veryspecial'").first - assert_equal very_special_client, Company.all.merge!(:where => "name = 'veryspecial'").first - assert_equal very_special_client, Client.all.merge!(:where => "name = 'veryspecial'").first - assert_equal 1, Client.all.merge!(:where => "name = 'Summit'").to_a.size + assert_equal very_special_client, SpecialClient.all.merge!(where: "name = 'veryspecial'").first + assert_equal very_special_client, Company.all.merge!(where: "name = 'veryspecial'").first + assert_equal very_special_client, Client.all.merge!(where: "name = 'veryspecial'").first + assert_equal 1, Client.all.merge!(where: "name = 'Summit'").to_a.size assert_equal very_special_client, Client.find(very_special_client.id) end def test_alt_complex_inheritance king_cole = KingCole.create("name" => "uniform heads") assert_equal king_cole, KingCole.where("name = 'uniform heads'").first - assert_equal king_cole, GreenCabbage.all.merge!(:where => "name = 'uniform heads'").first - assert_equal king_cole, Cabbage.all.merge!(:where => "name = 'uniform heads'").first - assert_equal king_cole, Vegetable.all.merge!(:where => "name = 'uniform heads'").first - assert_equal 1, Cabbage.all.merge!(:where => "name = 'his cabbage'").to_a.size + assert_equal king_cole, GreenCabbage.all.merge!(where: "name = 'uniform heads'").first + assert_equal king_cole, Cabbage.all.merge!(where: "name = 'uniform heads'").first + assert_equal king_cole, Vegetable.all.merge!(where: "name = 'uniform heads'").first + assert_equal 1, Cabbage.all.merge!(where: "name = 'his cabbage'").to_a.size assert_equal king_cole, Cabbage.find(king_cole.id) end def test_eager_load_belongs_to_something_inherited - account = Account.all.merge!(:includes => :firm).find(1) + account = Account.all.merge!(includes: :firm).find(1) assert account.association(:firm).loaded?, "association was not eager loaded" end def test_alt_eager_loading - cabbage = RedCabbage.all.merge!(:includes => :seller).find(4) + cabbage = RedCabbage.all.merge!(includes: :seller).find(4) assert cabbage.association(:seller).loaded?, "association was not eager loaded" end def test_eager_load_belongs_to_primary_key_quoting con = Account.connection assert_sql(/#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} = 1/) do - Account.all.merge!(:includes => :firm).find(1) + Account.all.merge!(includes: :firm).find(1) end end @@ -428,7 +428,7 @@ class InheritanceTest < ActiveRecord::TestCase def test_inheritance_without_mapping assert_kind_of SpecialSubscriber, SpecialSubscriber.find("webster132") - assert_nothing_raised { s = SpecialSubscriber.new("name" => "And breaaaaathe!"); s.id = 'roger'; s.save } + assert_nothing_raised { s = SpecialSubscriber.new("name" => "And breaaaaathe!"); s.id = "roger"; s.save } end def test_scope_inherited_properly @@ -449,7 +449,7 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase def test_instantiation_doesnt_try_to_require_corresponding_file without_store_full_sti_class do foo = Firm.first.clone - foo.type = 'FirmOnTheFly' + foo.type = "FirmOnTheFly" foo.save! # Should fail without FirmOnTheFly in the type condition. @@ -470,30 +470,30 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase end def test_sti_type_from_attributes_disabled_in_non_sti_class - phone = Shop::Product::Type.new(name: 'Phone') - product = Shop::Product.new(:type => phone) + phone = Shop::Product::Type.new(name: "Phone") + product = Shop::Product.new(type: phone) assert product.save end def test_inheritance_new_with_subclass_as_default original_type = Company.columns_hash["type"].default - ActiveRecord::Base.connection.change_column_default :companies, :type, 'Firm' + ActiveRecord::Base.connection.change_column_default :companies, :type, "Firm" Company.reset_column_information firm = Company.new # without arguments - assert_equal 'Firm', firm.type + assert_equal "Firm", firm.type assert_instance_of Firm, firm - firm = Company.new(firm_name: 'Shri Hans Plastic') # with arguments - assert_equal 'Firm', firm.type + firm = Company.new(firm_name: "Shri Hans Plastic") # with arguments + assert_equal "Firm", firm.type assert_instance_of Firm, firm client = Client.new - assert_equal 'Client', client.type + assert_equal "Client", client.type assert_instance_of Client, client - firm = Company.new(type: 'Client') # overwrite the default type - assert_equal 'Client', firm.type + firm = Company.new(type: "Client") # overwrite the default type + assert_equal "Client", firm.type assert_instance_of Client, firm ensure ActiveRecord::Base.connection.change_column_default :companies, :type, original_type @@ -502,9 +502,8 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase end class InheritanceAttributeTest < ActiveRecord::TestCase - class Company < ActiveRecord::Base - self.table_name = 'companies' + self.table_name = "companies" attribute :type, :string, default: "InheritanceAttributeTest::Startup" end @@ -516,11 +515,11 @@ class InheritanceAttributeTest < ActiveRecord::TestCase def test_inheritance_new_with_subclass_as_default startup = Company.new # without arguments - assert_equal 'InheritanceAttributeTest::Startup', startup.type + assert_equal "InheritanceAttributeTest::Startup", startup.type assert_instance_of Startup, startup - empire = Company.new(type: 'InheritanceAttributeTest::Empire') # without arguments - assert_equal 'InheritanceAttributeTest::Empire', empire.type + empire = Company.new(type: "InheritanceAttributeTest::Empire") # without arguments + assert_equal "InheritanceAttributeTest::Empire", empire.type assert_instance_of Empire, empire end end @@ -555,7 +554,7 @@ class InheritanceAttributeMappingTest < ActiveRecord::TestCase end class Company < ActiveRecord::Base - self.table_name = 'companies' + self.table_name = "companies" attribute :type, :omg_sti end @@ -563,18 +562,18 @@ class InheritanceAttributeMappingTest < ActiveRecord::TestCase class Empire < Company; end class Sponsor < ActiveRecord::Base - self.table_name = 'sponsors' + self.table_name = "sponsors" attribute :sponsorable_type, :omg_sti belongs_to :sponsorable, polymorphic: true end def test_sti_with_custom_type - Startup.create! name: 'a Startup' - Empire.create! name: 'an Empire' + Startup.create! name: "a Startup" + Empire.create! name: "an Empire" assert_equal [["a Startup", "omg_inheritance_attribute_mapping_test/startup"], - ["an Empire", "omg_inheritance_attribute_mapping_test/empire"]], ActiveRecord::Base.connection.select_rows('SELECT name, type FROM companies').sort + ["an Empire", "omg_inheritance_attribute_mapping_test/empire"]], ActiveRecord::Base.connection.select_rows("SELECT name, type FROM companies").sort assert_equal [["a Startup", "InheritanceAttributeMappingTest::Startup"], ["an Empire", "InheritanceAttributeMappingTest::Empire"]], Company.all.map { |a| [a.name, a.type] }.sort @@ -583,17 +582,17 @@ class InheritanceAttributeMappingTest < ActiveRecord::TestCase startup.save! assert_equal [["a Startup", "omg_inheritance_attribute_mapping_test/empire"], - ["an Empire", "omg_inheritance_attribute_mapping_test/empire"]], ActiveRecord::Base.connection.select_rows('SELECT name, type FROM companies').sort + ["an Empire", "omg_inheritance_attribute_mapping_test/empire"]], ActiveRecord::Base.connection.select_rows("SELECT name, type FROM companies").sort assert_equal [["a Startup", "InheritanceAttributeMappingTest::Empire"], ["an Empire", "InheritanceAttributeMappingTest::Empire"]], Company.all.map { |a| [a.name, a.type] }.sort end def test_polymorphic_associations_custom_type - startup = Startup.create! name: 'a Startup' + startup = Startup.create! name: "a Startup" sponsor = Sponsor.create! sponsorable: startup - assert_equal ["omg_inheritance_attribute_mapping_test/company"], ActiveRecord::Base.connection.select_values('SELECT sponsorable_type FROM sponsors') + assert_equal ["omg_inheritance_attribute_mapping_test/company"], ActiveRecord::Base.connection.select_values("SELECT sponsorable_type FROM sponsors") sponsor = Sponsor.first assert_equal startup, sponsor.sponsorable diff --git a/activerecord/test/cases/integration_test.rb b/activerecord/test/cases/integration_test.rb index 08a186ae07..00457965d7 100644 --- a/activerecord/test/cases/integration_test.rb +++ b/activerecord/test/cases/integration_test.rb @@ -1,10 +1,10 @@ -require 'cases/helper' -require 'models/company' -require 'models/developer' -require 'models/computer' -require 'models/owner' -require 'models/pet' +require "cases/helper" +require "models/company" +require "models/developer" +require "models/computer" +require "models/owner" +require "models/pet" class IntegrationTest < ActiveRecord::TestCase fixtures :companies, :developers, :owners, :pets @@ -21,53 +21,79 @@ class IntegrationTest < ActiveRecord::TestCase def test_to_param_returns_id_if_not_persisted_but_id_is_set client = Client.new client.id = 1 - assert_equal '1', client.to_param + assert_equal "1", client.to_param end def test_to_param_class_method firm = Firm.find(4) - assert_equal '4-flamboyant-software', firm.to_param + assert_equal "4-flamboyant-software", firm.to_param + end + + def test_to_param_class_method_truncates_words_properly + firm = Firm.find(4) + firm.name << ", Inc." + assert_equal "4-flamboyant-software", firm.to_param + end + + def test_to_param_class_method_truncates_after_parameterize + firm = Firm.find(4) + firm.name = "Huey, Dewey, & Louie LLC" + # 123456789T123456789v + assert_equal "4-huey-dewey-louie-llc", firm.to_param + end + + def test_to_param_class_method_truncates_after_parameterize_with_hyphens + firm = Firm.find(4) + firm.name = "Door-to-Door Wash-n-Fold Service" + # 123456789T123456789v + assert_equal "4-door-to-door-wash-n", firm.to_param end def test_to_param_class_method_truncates firm = Firm.find(4) - firm.name = 'a ' * 100 - assert_equal '4-a-a-a-a-a-a-a-a-a', firm.to_param + firm.name = "a " * 100 + assert_equal "4-a-a-a-a-a-a-a-a-a-a", firm.to_param end def test_to_param_class_method_truncates_edge_case firm = Firm.find(4) - firm.name = 'David HeinemeierHansson' - assert_equal '4-david', firm.to_param + firm.name = "David HeinemeierHansson" + assert_equal "4-david", firm.to_param + end + + def test_to_param_class_method_truncates_case_shown_in_doc + firm = Firm.find(4) + firm.name = "David Heinemeier Hansson" + assert_equal "4-david-heinemeier", firm.to_param end def test_to_param_class_method_squishes firm = Firm.find(4) firm.name = "ab \n" * 100 - assert_equal '4-ab-ab-ab-ab-ab-ab', firm.to_param + assert_equal "4-ab-ab-ab-ab-ab-ab-ab", firm.to_param end def test_to_param_class_method_multibyte_character firm = Firm.find(4) firm.name = "æˆ¦å ´ãƒ¶åŽŸ ã²ãŸãŽ" - assert_equal '4', firm.to_param + assert_equal "4", firm.to_param end def test_to_param_class_method_uses_default_if_blank firm = Firm.find(4) firm.name = nil - assert_equal '4', firm.to_param - firm.name = ' ' - assert_equal '4', firm.to_param + assert_equal "4", firm.to_param + firm.name = " " + assert_equal "4", firm.to_param end def test_to_param_class_method_uses_default_if_not_persisted - firm = Firm.new(name: 'Fancy Shirts') + firm = Firm.new(name: "Fancy Shirts") assert_equal nil, firm.to_param end def test_to_param_with_no_arguments - assert_equal 'Firm', Firm.to_param + assert_equal "Firm", Firm.to_param end def test_cache_key_for_existing_record_is_not_timezone_dependent @@ -146,4 +172,10 @@ class IntegrationTest < ActiveRecord::TestCase owner = owners(:blackbeard) assert_equal "owners/#{owner.id}-#{owner.happy_at.utc.to_s(:usec)}", owner.cache_key(:updated_at, :happy_at) end + + def test_cache_key_when_named_timestamp_is_nil + owner = owners(:blackbeard) + owner.happy_at = nil + assert_equal "owners/#{owner.id}", owner.cache_key(:happy_at) + end end diff --git a/activerecord/test/cases/invalid_connection_test.rb b/activerecord/test/cases/invalid_connection_test.rb index a16b52751a..1367af2859 100644 --- a/activerecord/test/cases/invalid_connection_test.rb +++ b/activerecord/test/cases/invalid_connection_test.rb @@ -1,24 +1,24 @@ require "cases/helper" if current_adapter?(:Mysql2Adapter) -class TestAdapterWithInvalidConnection < ActiveRecord::TestCase - self.use_transactional_tests = false + class TestAdapterWithInvalidConnection < ActiveRecord::TestCase + self.use_transactional_tests = false - class Bird < ActiveRecord::Base - end + class Bird < ActiveRecord::Base + end - def setup - # Can't just use current adapter; sqlite3 will create a database - # file on the fly. - Bird.establish_connection adapter: 'mysql2', database: 'i_do_not_exist' - end + def setup + # Can't just use current adapter; sqlite3 will create a database + # file on the fly. + Bird.establish_connection adapter: "mysql2", database: "i_do_not_exist" + end - teardown do - Bird.remove_connection - end + teardown do + Bird.remove_connection + end - test "inspect on Model class does not raise" do - assert_equal "#{Bird.name} (call '#{Bird.name}.connection' to establish a connection)", Bird.inspect + test "inspect on Model class does not raise" do + assert_equal "#{Bird.name} (call '#{Bird.name}.connection' to establish a connection)", Bird.inspect + end end end -end diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index aba854820b..9d5aace7db 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -6,7 +6,7 @@ end module ActiveRecord class InvertibleMigrationTest < ActiveRecord::TestCase class SilentMigration < ActiveRecord::Migration::Current - def write(text = '') + def write(text = "") # sssshhhhh!! end end @@ -225,7 +225,7 @@ module ActiveRecord InvertibleMigration.new.migrate :up received = [] migration = InvertibleByPartsMigration.new - migration.test = ->(dir){ + migration.test = ->(dir) { ActiveSupport::Deprecation.silence do assert migration.connection.table_exists?("horses") assert migration.connection.table_exists?("new_horses") @@ -291,21 +291,21 @@ module ActiveRecord migration1.migrate(:up) migration2.migrate(:up) - assert_equal true, Horse.connection.extension_enabled?('hstore') + assert_equal true, Horse.connection.extension_enabled?("hstore") migration3.migrate(:up) - assert_equal false, Horse.connection.extension_enabled?('hstore') + assert_equal false, Horse.connection.extension_enabled?("hstore") migration3.migrate(:down) - assert_equal true, Horse.connection.extension_enabled?('hstore') + assert_equal true, Horse.connection.extension_enabled?("hstore") migration2.migrate(:down) - assert_equal false, Horse.connection.extension_enabled?('hstore') + assert_equal false, Horse.connection.extension_enabled?("hstore") end end def test_revert_order - block = Proc.new{|t| t.string :name } + block = Proc.new { |t| t.string :name } recorder = ActiveRecord::Migration::CommandRecorder.new(ActiveRecord::Base.connection) recorder.instance_eval do create_table("apples", &block) @@ -351,14 +351,14 @@ module ActiveRecord end def test_migrate_down_with_table_name_prefix - ActiveRecord::Base.table_name_prefix = 'p_' - ActiveRecord::Base.table_name_suffix = '_s' + ActiveRecord::Base.table_name_prefix = "p_" + ActiveRecord::Base.table_name_suffix = "_s" migration = InvertibleMigration.new migration.migrate(:up) assert_nothing_raised { migration.migrate(:down) } ActiveSupport::Deprecation.silence { assert !ActiveRecord::Base.connection.table_exists?("p_horses_s"), "p_horses_s should not exist" } ensure - ActiveRecord::Base.table_name_prefix = ActiveRecord::Base.table_name_suffix = '' + ActiveRecord::Base.table_name_prefix = ActiveRecord::Base.table_name_suffix = "" end def test_migrations_can_handle_foreign_keys_to_specific_tables @@ -382,6 +382,5 @@ module ActiveRecord "horses_index_named index should not exist" end end - end end diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb index a222675918..b06fed4f0d 100644 --- a/activerecord/test/cases/json_serialization_test.rb +++ b/activerecord/test/cases/json_serialization_test.rb @@ -1,21 +1,21 @@ require "cases/helper" -require 'models/contact' -require 'models/post' -require 'models/author' -require 'models/tagging' -require 'models/tag' -require 'models/comment' +require "models/contact" +require "models/post" +require "models/author" +require "models/tagging" +require "models/tag" +require "models/comment" module JsonSerializationHelpers private - def set_include_root_in_json(value) - original_root_in_json = ActiveRecord::Base.include_root_in_json - ActiveRecord::Base.include_root_in_json = value - yield - ensure - ActiveRecord::Base.include_root_in_json = original_root_in_json - end + def set_include_root_in_json(value) + original_root_in_json = ActiveRecord::Base.include_root_in_json + ActiveRecord::Base.include_root_in_json = value + yield + ensure + ActiveRecord::Base.include_root_in_json = original_root_in_json + end end class JsonSerializationTest < ActiveRecord::TestCase @@ -27,18 +27,18 @@ class JsonSerializationTest < ActiveRecord::TestCase def setup @contact = Contact.new( - :name => 'Konata Izumi', - :age => 16, - :avatar => 'binarydata', - :created_at => Time.utc(2006, 8, 1), - :awesome => true, - :preferences => { :shows => 'anime' } + name: "Konata Izumi", + age: 16, + avatar: "binarydata", + created_at: Time.utc(2006, 8, 1), + awesome: true, + preferences: { shows: "anime" } ) end def test_should_demodulize_root_in_json set_include_root_in_json(true) do - @contact = NamespacedContact.new name: 'whatever' + @contact = NamespacedContact.new name: "whatever" json = @contact.to_json assert_match %r{^\{"namespaced_contact":\{}, json end @@ -51,7 +51,7 @@ class JsonSerializationTest < ActiveRecord::TestCase assert_match %r{^\{"contact":\{}, json assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -62,28 +62,28 @@ class JsonSerializationTest < ActiveRecord::TestCase assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"awesome":true}, json assert_match %r{"preferences":\{"shows":"anime"\}}, json end def test_should_allow_attribute_filtering_with_only - json = @contact.to_json(:only => [:name, :age]) + json = @contact.to_json(only: [:name, :age]) assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json assert_no_match %r{"awesome":true}, json - assert !json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_not_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_no_match %r{"preferences":\{"shows":"anime"\}}, json end def test_should_allow_attribute_filtering_with_except - json = @contact.to_json(:except => [:name, :age]) + json = @contact.to_json(except: [:name, :age]) assert_no_match %r{"name":"Konata Izumi"}, json assert_no_match %r{"age":16}, json assert_match %r{"awesome":true}, json - assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))})) + assert_includes json, %("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}) assert_match %r{"preferences":\{"shows":"anime"\}}, json end @@ -93,10 +93,10 @@ class JsonSerializationTest < ActiveRecord::TestCase def @contact.favorite_quote; "Constraints are liberating"; end # Single method. - assert_match %r{"label":"Has cheezburger"}, @contact.to_json(:only => :name, :methods => :label) + assert_match %r{"label":"Has cheezburger"}, @contact.to_json(only: :name, methods: :label) # Both methods. - methods_json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote]) + methods_json = @contact.to_json(only: :name, methods: [:label, :favorite_quote]) assert_match %r{"label":"Has cheezburger"}, methods_json assert_match %r{"favorite_quote":"Constraints are liberating"}, methods_json end @@ -125,7 +125,7 @@ class JsonSerializationTest < ActiveRecord::TestCase def test_does_not_include_inheritance_column_from_sti @contact = ContactSti.new(@contact.attributes) - assert_equal 'ContactSti', @contact.type + assert_equal "ContactSti", @contact.type json = @contact.to_json assert_match %r{"name":"Konata Izumi"}, json @@ -135,7 +135,7 @@ class JsonSerializationTest < ActiveRecord::TestCase def test_serializable_hash_with_default_except_option_and_excluding_inheritance_column_from_sti @contact = ContactSti.new(@contact.attributes) - assert_equal 'ContactSti', @contact.type + assert_equal "ContactSti", @contact.type def @contact.serializable_hash(options={}) super({ except: %w(age) }.merge!(options)) @@ -149,7 +149,7 @@ class JsonSerializationTest < ActiveRecord::TestCase end def test_serializable_hash_should_not_modify_options_in_argument - options = { :only => :name } + options = { only: :name } @contact.serializable_hash(options) assert_nil options[:except] @@ -167,7 +167,7 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase end def test_includes_uses_association_name - json = @david.to_json(:include => :posts) + json = @david.to_json(include: :posts) assert_match %r{"posts":\[}, json @@ -183,7 +183,7 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase end def test_includes_uses_association_name_and_applies_attribute_filters - json = @david.to_json(:include => { :posts => { :only => :title } }) + json = @david.to_json(include: { posts: { only: :title } }) assert_match %r{"name":"David"}, json assert_match %r{"posts":\[}, json @@ -196,7 +196,7 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase end def test_includes_fetches_second_level_associations - json = @david.to_json(:include => { :posts => { :include => { :comments => { :only => :body } } } }) + json = @david.to_json(include: { posts: { include: { comments: { only: :body } } } }) assert_match %r{"name":"David"}, json assert_match %r{"posts":\[}, json @@ -209,12 +209,12 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase def test_includes_fetches_nth_level_associations json = @david.to_json( - :include => { - :posts => { - :include => { - :taggings => { - :include => { - :tag => { :only => :name } + include: { + posts: { + include: { + taggings: { + include: { + tag: { only: :name } } } } @@ -230,8 +230,8 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase def test_includes_doesnt_merge_opts_from_base json = @david.to_json( - :only => :id, - :include => :posts + only: :id, + include: :posts ) assert_match %{"title":"Welcome to the weblog"}, json @@ -239,7 +239,7 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase def test_should_not_call_methods_on_associations_that_dont_respond def @david.favorite_quote; "Constraints are liberating"; end - json = @david.to_json(:include => :posts, :methods => :favorite_quote) + json = @david.to_json(include: :posts, methods: :favorite_quote) assert !@david.posts.first.respond_to?(:favorite_quote) assert_match %r{"favorite_quote":"Constraints are liberating"}, json @@ -267,15 +267,15 @@ class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase def test_should_allow_includes_for_list_of_authors authors = [@david, @mary] json = ActiveSupport::JSON.encode(authors, - :only => :name, - :include => { - :posts => { :only => :id } + only: :name, + include: { + posts: { only: :id } } ) ['"name":"David"', '"posts":[', '{"id":1}', '{"id":2}', '{"id":4}', '{"id":5}', '{"id":6}', '"name":"Mary"', '"posts":[', '{"id":7}', '{"id":9}'].each do |fragment| - assert json.include?(fragment), json + assert_includes json, fragment, json end end diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 9fc0041892..0579df0a07 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -1,18 +1,18 @@ -require 'thread' +require "thread" require "cases/helper" -require 'models/person' -require 'models/job' -require 'models/reader' -require 'models/ship' -require 'models/legacy_thing' -require 'models/personal_legacy_thing' -require 'models/reference' -require 'models/string_key_object' -require 'models/car' -require 'models/bulb' -require 'models/engine' -require 'models/wheel' -require 'models/treasure' +require "models/person" +require "models/job" +require "models/reader" +require "models/ship" +require "models/legacy_thing" +require "models/personal_legacy_thing" +require "models/reference" +require "models/string_key_object" +require "models/car" +require "models/bulb" +require "models/engine" +require "models/wheel" +require "models/treasure" class LockWithoutDefault < ActiveRecord::Base; end @@ -33,7 +33,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase p1 = Person.find(1) assert_equal 0, p1.lock_version - p1.first_name = 'anika2' + p1.first_name = "anika2" p1.save! assert_equal 1, p1.lock_version @@ -45,12 +45,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, s1.lock_version assert_equal 0, s2.lock_version - s1.name = 'updated record' + s1.name = "updated record" s1.save! assert_equal 1, s1.lock_version assert_equal 0, s2.lock_version - s2.name = 'doubly updated record' + s2.name = "doubly updated record" assert_raise(ActiveRecord::StaleObjectError) { s2.save! } end @@ -60,7 +60,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, s1.lock_version assert_equal 0, s2.lock_version - s1.name = 'updated record' + s1.name = "updated record" s1.save! assert_equal 1, s1.lock_version assert_equal 0, s2.lock_version @@ -78,12 +78,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, p1.lock_version assert_equal 0, p2.lock_version - p1.first_name = 'stu' + p1.first_name = "stu" p1.save! assert_equal 1, p1.lock_version assert_equal 0, p2.lock_version - p2.first_name = 'sue' + p2.first_name = "sue" assert_raise(ActiveRecord::StaleObjectError) { p2.save! } end @@ -94,7 +94,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, p1.lock_version assert_equal 0, p2.lock_version - p1.first_name = 'stu' + p1.first_name = "stu" p1.save! assert_equal 1, p1.lock_version assert_equal 0, p2.lock_version @@ -113,64 +113,56 @@ class OptimisticLockingTest < ActiveRecord::TestCase assert_equal 0, p1.lock_version assert_equal 0, p2.lock_version - p1.first_name = 'stu' + p1.first_name = "stu" p1.save! assert_equal 1, p1.lock_version assert_equal 0, p2.lock_version - p2.first_name = 'sue' + p2.first_name = "sue" assert_raise(ActiveRecord::StaleObjectError) { p2.save! } - p2.first_name = 'sue2' + p2.first_name = "sue2" assert_raise(ActiveRecord::StaleObjectError) { p2.save! } end def test_lock_new - p1 = Person.new(:first_name => 'anika') + p1 = Person.new(first_name: "anika") assert_equal 0, p1.lock_version - p1.first_name = 'anika2' + p1.first_name = "anika2" p1.save! p2 = Person.find(p1.id) assert_equal 0, p1.lock_version assert_equal 0, p2.lock_version - p1.first_name = 'anika3' + p1.first_name = "anika3" p1.save! assert_equal 1, p1.lock_version assert_equal 0, p2.lock_version - p2.first_name = 'sue' + p2.first_name = "sue" assert_raise(ActiveRecord::StaleObjectError) { p2.save! } end def test_lock_exception_record - p1 = Person.new(:first_name => 'mira') + p1 = Person.new(first_name: "mira") assert_equal 0, p1.lock_version - p1.first_name = 'mira2' + p1.first_name = "mira2" p1.save! p2 = Person.find(p1.id) assert_equal 0, p1.lock_version assert_equal 0, p2.lock_version - p1.first_name = 'mira3' + p1.first_name = "mira3" p1.save! - p2.first_name = 'sue' + p2.first_name = "sue" error = assert_raise(ActiveRecord::StaleObjectError) { p2.save! } assert_equal(error.record.object_id, p2.object_id) end - def test_lock_new_with_nil - p1 = Person.new(:first_name => 'anika') - p1.save! - p1.lock_version = nil # simulate bad fixture or column with no default - p1.save! - assert_equal 1, p1.lock_version - end - def test_lock_new_when_explicitly_passing_nil - p1 = Person.new(:first_name => 'anika', lock_version: nil) + p1 = Person.new(first_name: "anika", lock_version: nil) p1.save! assert_equal 0, p1.lock_version end @@ -181,12 +173,13 @@ class OptimisticLockingTest < ActiveRecord::TestCase p1.touch assert_equal 1, p1.lock_version + assert_not p1.changed?, "Changes should have been cleared" end def test_touch_stale_object - person = Person.create!(first_name: 'Mehmet Emin') + person = Person.create!(first_name: "Mehmet Emin") stale_person = Person.find(person.id) - person.update_attribute(:gender, 'M') + person.update_attribute(:gender, "M") assert_raises(ActiveRecord::StaleObjectError) do stale_person.touch @@ -209,11 +202,11 @@ class OptimisticLockingTest < ActiveRecord::TestCase end def test_lock_column_is_mass_assignable - p1 = Person.create(:first_name => 'bianca') + p1 = Person.create(first_name: "bianca") assert_equal 0, p1.lock_version assert_equal p1.lock_version, Person.new(p1.attributes).lock_version - p1.first_name = 'bianca2' + p1.first_name = "bianca2" p1.save! assert_equal 1, p1.lock_version assert_equal p1.lock_version, Person.new(p1.attributes).lock_version @@ -221,28 +214,155 @@ class OptimisticLockingTest < ActiveRecord::TestCase def test_lock_without_default_sets_version_to_zero t1 = LockWithoutDefault.new + + assert_equal 0, t1.lock_version + assert_nil t1.lock_version_before_type_cast + + t1.save! + t1.reload + assert_equal 0, t1.lock_version + assert_equal 0, t1.lock_version_before_type_cast + end + + def test_lock_without_default_should_work_with_null_in_the_database + ActiveRecord::Base.connection.execute("INSERT INTO lock_without_defaults(title) VALUES('title1')") + t1 = LockWithoutDefault.last + t2 = LockWithoutDefault.last - t1.save - t1 = LockWithoutDefault.find(t1.id) assert_equal 0, t1.lock_version + assert_nil t1.lock_version_before_type_cast + assert_equal 0, t2.lock_version + assert_nil t2.lock_version_before_type_cast + + t1.title = "new title1" + t2.title = "new title2" + + assert_nothing_raised { t1.save! } + assert_equal 1, t1.lock_version + assert_equal "new title1", t1.title + + assert_raise(ActiveRecord::StaleObjectError) { t2.save! } + assert_equal 0, t2.lock_version + assert_equal "new title2", t2.title + end + + def test_lock_without_default_should_update_with_lock_col + t1 = LockWithoutDefault.create(title: "title1", lock_version: 6) + + assert_equal 6, t1.lock_version + + t1.update(lock_version: 0) + t1.reload + + assert_equal 0, t1.lock_version + end + + def test_lock_without_default_queries_count + t1 = LockWithoutDefault.create(title: "title1") + + assert_equal "title1", t1.title + assert_equal 0, t1.lock_version + + assert_queries(1) { t1.update(title: "title2") } + + t1.reload + assert_equal "title2", t1.title + assert_equal 1, t1.lock_version + + assert_queries(1) { t1.update(title: "title3", lock_version: 6) } + + t1.reload + assert_equal "title3", t1.title + assert_equal 6, t1.lock_version + + t2 = LockWithoutDefault.new(title: "title1") + + assert_queries(1) { t2.save! } + + t2.reload + assert_equal "title1", t2.title + assert_equal 0, t2.lock_version end def test_lock_with_custom_column_without_default_sets_version_to_zero t1 = LockWithCustomColumnWithoutDefault.new + assert_equal 0, t1.custom_lock_version assert_nil t1.custom_lock_version_before_type_cast t1.save! t1.reload + + assert_equal 0, t1.custom_lock_version + assert_equal 0, t1.custom_lock_version_before_type_cast + end + + def test_lock_with_custom_column_without_default_should_work_with_null_in_the_database + ActiveRecord::Base.connection.execute("INSERT INTO lock_without_defaults_cust(title) VALUES('title1')") + + t1 = LockWithCustomColumnWithoutDefault.last + t2 = LockWithCustomColumnWithoutDefault.last + + assert_equal 0, t1.custom_lock_version + assert_nil t1.custom_lock_version_before_type_cast + assert_equal 0, t2.custom_lock_version + assert_nil t2.custom_lock_version_before_type_cast + + t1.title = "new title1" + t2.title = "new title2" + + assert_nothing_raised { t1.save! } + assert_equal 1, t1.custom_lock_version + assert_equal "new title1", t1.title + + assert_raise(ActiveRecord::StaleObjectError) { t2.save! } + assert_equal 0, t2.custom_lock_version + assert_equal "new title2", t2.title + end + + def test_lock_with_custom_column_without_default_should_update_with_lock_col + t1 = LockWithCustomColumnWithoutDefault.create(title: "title1", custom_lock_version: 6) + + assert_equal 6, t1.custom_lock_version + + t1.update(custom_lock_version: 0) + t1.reload + assert_equal 0, t1.custom_lock_version - assert [0, "0"].include?(t1.custom_lock_version_before_type_cast) + end + + def test_lock_with_custom_column_without_default_queries_count + t1 = LockWithCustomColumnWithoutDefault.create(title: "title1") + + assert_equal "title1", t1.title + assert_equal 0, t1.custom_lock_version + + assert_queries(1) { t1.update(title: "title2") } + + t1.reload + assert_equal "title2", t1.title + assert_equal 1, t1.custom_lock_version + + assert_queries(1) { t1.update(title: "title3", custom_lock_version: 6) } + + t1.reload + assert_equal "title3", t1.title + assert_equal 6, t1.custom_lock_version + + t2 = LockWithCustomColumnWithoutDefault.new(title: "title1") + + assert_queries(1) { t2.save! } + + t2.reload + assert_equal "title1", t2.title + assert_equal 0, t2.custom_lock_version end def test_readonly_attributes - assert_equal Set.new([ 'name' ]), ReadonlyNameShip.readonly_attributes + assert_equal Set.new([ "name" ]), ReadonlyNameShip.readonly_attributes - s = ReadonlyNameShip.create(:name => "unchangeable name") + s = ReadonlyNameShip.create(name: "unchangeable name") s.reload assert_equal "unchangeable name", s.name @@ -261,7 +381,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase # is nothing else being updated. def test_update_without_attributes_does_not_only_update_lock_version assert_nothing_raised do - p1 = Person.create!(:first_name => 'anika') + p1 = Person.create!(first_name: "anika") lock_version = p1.lock_version p1.save p1.reload @@ -272,17 +392,17 @@ class OptimisticLockingTest < ActiveRecord::TestCase def test_polymorphic_destroy_with_dependencies_and_lock_version car = Car.create! - assert_difference 'car.wheels.count' do + assert_difference "car.wheels.count" do car.wheels << Wheel.create! end - assert_difference 'car.wheels.count', -1 do + assert_difference "car.wheels.count", -1 do car.reload.destroy end assert car.destroyed? end def test_removing_has_and_belongs_to_many_associations_upon_destroy - p = RichPerson.create! first_name: 'Jon' + p = RichPerson.create! first_name: "Jon" p.treasures.create! assert !p.treasures.empty? p.destroy @@ -306,7 +426,7 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase # of a test (see test_increment_counter_*). self.use_transactional_tests = false - { :lock_version => Person, :custom_lock_version => LegacyThing }.each do |name, model| + { lock_version: Person, custom_lock_version: LegacyThing }.each do |name, model| define_method("test_increment_counter_updates_#{name}") do counter_test model, 1 do |id| model.increment_counter :test_count, id @@ -321,7 +441,7 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase define_method("test_update_counters_updates_#{name}") do counter_test model, 1 do |id| - model.update_counters id, :test_count => 1 + model.update_counters id, test_count: 1 end end end @@ -329,13 +449,13 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase # See Lighthouse ticket #1966 def test_destroy_dependents # Establish dependent relationship between Person and PersonalLegacyThing - add_counter_column_to(Person, 'personal_legacy_things_count') + add_counter_column_to(Person, "personal_legacy_things_count") PersonalLegacyThing.reset_column_information # Make sure that counter incrementing doesn't cause problems - p1 = Person.new(:first_name => 'fjord') + p1 = Person.new(first_name: "fjord") p1.save! - t = PersonalLegacyThing.new(:person => p1) + t = PersonalLegacyThing.new(person: p1) t.save! p1.reload assert_equal 1, p1.personal_legacy_things_count @@ -344,14 +464,14 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase assert_raises(ActiveRecord::RecordNotFound) { Person.find(p1.id) } assert_raises(ActiveRecord::RecordNotFound) { PersonalLegacyThing.find(t.id) } ensure - remove_counter_column_from(Person, 'personal_legacy_things_count') + remove_counter_column_from(Person, "personal_legacy_things_count") PersonalLegacyThing.reset_column_information end private - def add_counter_column_to(model, col='test_count') - model.connection.add_column model.table_name, col, :integer, :null => false, :default => 0 + def add_counter_column_to(model, col="test_count") + model.connection.add_column model.table_name, col, :integer, null: false, default: 0 model.reset_column_information end @@ -374,7 +494,6 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase end end - # TODO: test against the generated SQL since testing locking behavior itself # is so cumbersome. Will deadlock Ruby threads if the underlying db.execute # blocks, so separate script called by Kernel#system is needed. @@ -416,7 +535,7 @@ unless in_memory_db? assert_nothing_raised do Person.transaction do person = Person.find 1 - old, person.first_name = person.first_name, 'fooman' + old, person.first_name = person.first_name, "fooman" person.lock! assert_equal old, person.first_name end @@ -426,19 +545,19 @@ unless in_memory_db? def test_with_lock_commits_transaction person = Person.find 1 person.with_lock do - person.first_name = 'fooman' + person.first_name = "fooman" person.save! end - assert_equal 'fooman', person.reload.first_name + assert_equal "fooman", person.reload.first_name end def test_with_lock_rolls_back_transaction person = Person.find 1 old = person.first_name person.with_lock do - person.first_name = 'fooman' + person.first_name = "fooman" person.save! - raise 'oops' + raise "oops" end rescue nil assert_equal old, person.reload.first_name end @@ -448,7 +567,7 @@ unless in_memory_db? Person.transaction do person = Person.find(1) assert_sql(/LIMIT \$?\d FOR SHARE NOWAIT/) do - person.lock!('FOR SHARE NOWAIT') + person.lock!("FOR SHARE NOWAIT") end end end @@ -461,33 +580,34 @@ unless in_memory_db? end protected - def duel(zzz = 5) - t0, t1, t2, t3 = nil, nil, nil, nil - - a = Thread.new do - t0 = Time.now - Person.transaction do - yield - sleep zzz # block thread 2 for zzz seconds - end - t1 = Time.now - end - b = Thread.new do - sleep zzz / 2.0 # ensure thread 1 tx starts first - t2 = Time.now - Person.transaction { yield } - t3 = Time.now - end + def duel(zzz = 5) + t0, t1, t2, t3 = nil, nil, nil, nil - a.join - b.join + a = Thread.new do + t0 = Time.now + Person.transaction do + yield + sleep zzz # block thread 2 for zzz seconds + end + t1 = Time.now + end - assert t1 > t0 + zzz - assert t2 > t0 - assert t3 > t2 - [t0.to_f..t1.to_f, t2.to_f..t3.to_f] + b = Thread.new do + sleep zzz / 2.0 # ensure thread 1 tx starts first + t2 = Time.now + Person.transaction { yield } + t3 = Time.now end + + a.join + b.join + + assert t1 > t0 + zzz + assert t2 > t0 + assert t3 > t2 + [t0.to_f..t1.to_f, t2.to_f..t3.to_f] + end end end end diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb index c97960a412..90ad970e16 100644 --- a/activerecord/test/cases/log_subscriber_test.rb +++ b/activerecord/test/cases/log_subscriber_test.rb @@ -30,7 +30,7 @@ class LogSubscriberTest < ActiveRecord::TestCase super end - def debug message + def debug(message) @debugs << message end end @@ -60,20 +60,20 @@ class LogSubscriberTest < ActiveRecord::TestCase logger = TestDebugLogSubscriber.new assert_equal 0, logger.debugs.length - logger.sql(event.new(0, sql: 'hi mom!')) + logger.sql(event.new(0, sql: "hi mom!")) assert_equal 1, logger.debugs.length - logger.sql(event.new(0, sql: 'hi mom!', name: 'foo')) + logger.sql(event.new(0, sql: "hi mom!", name: "foo")) assert_equal 2, logger.debugs.length - logger.sql(event.new(0, sql: 'hi mom!', name: 'SCHEMA')) + logger.sql(event.new(0, sql: "hi mom!", name: "SCHEMA")) assert_equal 2, logger.debugs.length end def test_sql_statements_are_not_squeezed event = Struct.new(:duration, :payload) logger = TestDebugLogSubscriber.new - logger.sql(event.new(0, sql: 'ruby rails')) + logger.sql(event.new(0, sql: "ruby rails")) assert_match(/ruby rails/, logger.debugs.first) end @@ -103,7 +103,7 @@ class LogSubscriberTest < ActiveRecord::TestCase logger.sql(event.new(0, sql: verb.to_s)) assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA} \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last) - logger.sql(event.new(0, {sql: verb.to_s, name: "SQL"})) + logger.sql(event.new(0, sql: verb.to_s, name: "SQL")) assert_match(/#{REGEXP_BOLD}#{REGEXP_MAGENTA}SQL \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last) end end @@ -113,13 +113,13 @@ class LogSubscriberTest < ActiveRecord::TestCase logger = TestDebugLogSubscriber.new logger.colorize_logging = true SQL_COLORINGS.each do |verb, _| - logger.sql(event.new(0, {sql: verb.to_s, name: "Model Load"})) + logger.sql(event.new(0, sql: verb.to_s, name: "Model Load")) assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}Model Load \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last) - logger.sql(event.new(0, {sql: verb.to_s, name: "Model Exists"})) + logger.sql(event.new(0, sql: verb.to_s, name: "Model Exists")) assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}Model Exists \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last) - logger.sql(event.new(0, {sql: verb.to_s, name: "ANY SPECIFIC NAME"})) + logger.sql(event.new(0, sql: verb.to_s, name: "ANY SPECIFIC NAME")) assert_match(/#{REGEXP_BOLD}#{REGEXP_CYAN}ANY SPECIFIC NAME \(0.0ms\)#{REGEXP_CLEAR}/i, logger.debugs.last) end end @@ -211,7 +211,7 @@ class LogSubscriberTest < ActiveRecord::TestCase if ActiveRecord::Base.connection.prepared_statements def test_binary_data_is_not_logged - Binary.create(data: 'some binary data') + Binary.create(data: "some binary data") wait assert_match(/<16 bytes of binary data>/, @logger.logged(:debug).join) end diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb index d6963b48d7..bdb90eaa74 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration @@ -40,7 +40,7 @@ module ActiveRecord def test_create_table_with_not_null_column connection.create_table :testings do |t| - t.column :foo, :string, :null => false + t.column :foo, :string, null: false end assert_raises(ActiveRecord::StatementInvalid) do @@ -53,11 +53,11 @@ module ActiveRecord mysql = current_adapter?(:Mysql2Adapter) connection.create_table :testings do |t| - t.column :one, :string, :default => "hello" - t.column :two, :boolean, :default => true - t.column :three, :boolean, :default => false - t.column :four, :integer, :default => 1 - t.column :five, :text, :default => "hello" unless mysql + t.column :one, :string, default: "hello" + t.column :two, :boolean, default: true + t.column :three, :boolean, default: false + t.column :four, :integer, default: 1 + t.column :five, :text, default: "hello" unless mysql end columns = connection.columns(:testings) @@ -70,14 +70,14 @@ module ActiveRecord assert_equal "hello", one.default assert_equal true, connection.lookup_cast_type_from_column(two).deserialize(two.default) assert_equal false, connection.lookup_cast_type_from_column(three).deserialize(three.default) - assert_equal '1', four.default + assert_equal "1", four.default assert_equal "hello", five.default unless mysql end if current_adapter?(:PostgreSQLAdapter) def test_add_column_with_array connection.create_table :testings - connection.add_column :testings, :foo, :string, :array => true + connection.add_column :testings, :foo, :string, array: true columns = connection.columns(:testings) array_column = columns.detect { |c| c.name == "foo" } @@ -87,7 +87,7 @@ module ActiveRecord def test_create_table_with_array_column connection.create_table :testings do |t| - t.string :foo, :array => true + t.string :foo, array: true end columns = connection.columns(:testings) @@ -105,9 +105,9 @@ module ActiveRecord eight = columns.detect { |c| c.name == "eight_int" } if current_adapter?(:OracleAdapter) - assert_equal 'NUMBER(19)', eight.sql_type + assert_equal "NUMBER(19)", eight.sql_type elsif current_adapter?(:SQLite3Adapter) - assert_equal 'bigint', eight.sql_type + assert_equal "bigint", eight.sql_type else assert_equal :integer, eight.type assert_equal 8, eight.limit @@ -118,13 +118,13 @@ module ActiveRecord def test_create_table_with_limits connection.create_table :testings do |t| - t.column :foo, :string, :limit => 255 + t.column :foo, :string, limit: 255 t.column :default_int, :integer - t.column :one_int, :integer, :limit => 1 - t.column :four_int, :integer, :limit => 4 - t.column :eight_int, :integer, :limit => 8 + t.column :one_int, :integer, limit: 1 + t.column :four_int, :integer, limit: 4 + t.column :eight_int, :integer, limit: 8 end columns = connection.columns(:testings) @@ -137,20 +137,20 @@ module ActiveRecord eight = columns.detect { |c| c.name == "eight_int" } if current_adapter?(:PostgreSQLAdapter) - assert_equal 'integer', default.sql_type - assert_equal 'smallint', one.sql_type - assert_equal 'integer', four.sql_type - assert_equal 'bigint', eight.sql_type + assert_equal "integer", default.sql_type + assert_equal "smallint", one.sql_type + assert_equal "integer", four.sql_type + assert_equal "bigint", eight.sql_type elsif current_adapter?(:Mysql2Adapter) - assert_match 'int(11)', default.sql_type - assert_match 'tinyint', one.sql_type - assert_match 'int', four.sql_type - assert_match 'bigint', eight.sql_type + assert_match "int(11)", default.sql_type + assert_match "tinyint", one.sql_type + assert_match "int", four.sql_type + assert_match "bigint", eight.sql_type elsif current_adapter?(:OracleAdapter) - assert_equal 'NUMBER(38)', default.sql_type - assert_equal 'NUMBER(1)', one.sql_type - assert_equal 'NUMBER(4)', four.sql_type - assert_equal 'NUMBER(8)', eight.sql_type + assert_equal "NUMBER(38)", default.sql_type + assert_equal "NUMBER(1)", one.sql_type + assert_equal "NUMBER(4)", four.sql_type + assert_equal "NUMBER(8)", eight.sql_type end end @@ -200,8 +200,8 @@ module ActiveRecord end created_columns = connection.columns(table_name) - created_at_column = created_columns.detect {|c| c.name == 'created_at' } - updated_at_column = created_columns.detect {|c| c.name == 'updated_at' } + created_at_column = created_columns.detect { |c| c.name == "created_at" } + updated_at_column = created_columns.detect { |c| c.name == "updated_at" } assert !created_at_column.null assert !updated_at_column.null @@ -213,8 +213,8 @@ module ActiveRecord end created_columns = connection.columns(table_name) - created_at_column = created_columns.detect {|c| c.name == 'created_at' } - updated_at_column = created_columns.detect {|c| c.name == 'updated_at' } + created_at_column = created_columns.detect { |c| c.name == "created_at" } + updated_at_column = created_columns.detect { |c| c.name == "updated_at" } assert created_at_column.null assert updated_at_column.null @@ -231,7 +231,7 @@ module ActiveRecord connection.create_table :testings do |t| t.column :foo, :string end - connection.add_column :testings, :bar, :string, :null => false + connection.add_column :testings, :bar, :string, null: false assert_raise(ActiveRecord::StatementInvalid) do connection.execute "insert into testings (foo, bar) values ('hello', NULL)" @@ -246,7 +246,7 @@ module ActiveRecord con = connection connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')" - assert_nothing_raised {connection.add_column :testings, :bar, :string, :null => false, :default => "default" } + assert_nothing_raised { connection.add_column :testings, :bar, :string, null: false, default: "default" } assert_raises(ActiveRecord::StatementInvalid) do connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) values (2, 'hello', NULL)" @@ -259,14 +259,14 @@ module ActiveRecord end klass = Class.new(ActiveRecord::Base) - klass.table_name = 'testings' + klass.table_name = "testings" - assert_equal :datetime, klass.columns_hash['foo'].type + assert_equal :datetime, klass.columns_hash["foo"].type if current_adapter?(:PostgreSQLAdapter) - assert_equal 'timestamp without time zone', klass.columns_hash['foo'].sql_type + assert_equal "timestamp without time zone", klass.columns_hash["foo"].sql_type else - assert_equal klass.connection.type_to_sql('datetime'), klass.columns_hash['foo'].sql_type + assert_equal klass.connection.type_to_sql("datetime"), klass.columns_hash["foo"].sql_type end end @@ -275,7 +275,7 @@ module ActiveRecord t.column :select, :string end - connection.change_column :testings, :select, :string, :limit => 10 + connection.change_column :testings, :select, :string, limit: 10 # Oracle needs primary key value from sequence if current_adapter?(:OracleAdapter) @@ -290,17 +290,17 @@ module ActiveRecord t.column :title, :string end person_klass = Class.new(ActiveRecord::Base) - person_klass.table_name = 'testings' + person_klass.table_name = "testings" - person_klass.connection.add_column "testings", "wealth", :integer, :null => false, :default => 99 + person_klass.connection.add_column "testings", "wealth", :integer, null: false, default: 99 person_klass.reset_column_information assert_equal 99, person_klass.column_defaults["wealth"] assert_equal false, person_klass.columns_hash["wealth"].null # Oracle needs primary key value from sequence if current_adapter?(:OracleAdapter) - assert_nothing_raised {person_klass.connection.execute("insert into testings (id, title) values (testings_seq.nextval, 'tester')")} + assert_nothing_raised { person_klass.connection.execute("insert into testings (id, title) values (testings_seq.nextval, 'tester')") } else - assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")} + assert_nothing_raised { person_klass.connection.execute("insert into testings (title) values ('tester')") } end # change column default to see that column doesn't lose its not null definition @@ -317,19 +317,19 @@ module ActiveRecord assert_equal false, person_klass.columns_hash["money"].null # change column - person_klass.connection.change_column "testings", "money", :integer, :null => false, :default => 1000 + person_klass.connection.change_column "testings", "money", :integer, null: false, default: 1000 person_klass.reset_column_information assert_equal 1000, person_klass.column_defaults["money"] assert_equal false, person_klass.columns_hash["money"].null # change column, make it nullable and clear default - person_klass.connection.change_column "testings", "money", :integer, :null => true, :default => nil + person_klass.connection.change_column "testings", "money", :integer, null: true, default: nil person_klass.reset_column_information assert_nil person_klass.columns_hash["money"].default assert_equal true, person_klass.columns_hash["money"].null # change_column_null, make it not nullable and set null values to a default value - person_klass.connection.execute('UPDATE testings SET money = NULL') + person_klass.connection.execute("UPDATE testings SET money = NULL") person_klass.connection.change_column_null "testings", "money", false, 2000 person_klass.reset_column_information assert_nil person_klass.columns_hash["money"].default @@ -346,9 +346,9 @@ module ActiveRecord end notnull_migration.new.suppress_messages do notnull_migration.migrate(:up) - assert_equal false, connection.columns(:testings).find{ |c| c.name == "foo"}.null + assert_equal false, connection.columns(:testings).find { |c| c.name == "foo" }.null notnull_migration.migrate(:down) - assert connection.columns(:testings).find{ |c| c.name == "foo"}.null + assert connection.columns(:testings).find { |c| c.name == "foo" }.null end end end @@ -365,7 +365,7 @@ module ActiveRecord def test_column_exists_with_type connection.create_table :testings do |t| t.column :foo, :string - t.column :bar, :decimal, :precision => 8, :scale => 2 + t.column :bar, :decimal, precision: 8, scale: 2 end assert connection.column_exists?(:testings, :foo, :string) @@ -380,7 +380,7 @@ module ActiveRecord t.column :foo, :string, limit: 100 t.column :bar, :decimal, precision: 8, scale: 2 t.column :taggable_id, :integer, null: false - t.column :taggable_type, :string, default: 'Photo' + t.column :taggable_type, :string, default: "Photo" end assert connection.column_exists?(:testings, :foo, :string, limit: 100) @@ -389,7 +389,7 @@ module ActiveRecord assert_not connection.column_exists?(:testings, :bar, :decimal, precision: nil, scale: nil) assert connection.column_exists?(:testings, :taggable_id, :integer, null: false) assert_not connection.column_exists?(:testings, :taggable_id, :integer, null: true) - assert connection.column_exists?(:testings, :taggable_type, :string, default: 'Photo') + assert connection.column_exists?(:testings, :taggable_type, :string, default: "Photo") assert_not connection.column_exists?(:testings, :taggable_type, :string, default: nil) end @@ -415,13 +415,13 @@ module ActiveRecord end private - def testing_table_with_only_foo_attribute - connection.create_table :testings, :id => false do |t| - t.column :foo, :string - end + def testing_table_with_only_foo_attribute + connection.create_table :testings, id: false do |t| + t.column :foo, :string + end - yield - end + yield + end end if ActiveRecord::Base.connection.supports_foreign_keys? diff --git a/activerecord/test/cases/migration/change_table_test.rb b/activerecord/test/cases/migration/change_table_test.rb index 2f9c50141f..ec817a579b 100644 --- a/activerecord/test/cases/migration/change_table_test.rb +++ b/activerecord/test/cases/migration/change_table_test.rb @@ -95,7 +95,7 @@ module ActiveRecord def test_remove_timestamps_creates_updated_at_and_created_at with_change_table do |t| @connection.expect :remove_timestamps, nil, [:delete_me, { null: true }] - t.remove_timestamps({ null: true }) + t.remove_timestamps(null: true) end end @@ -157,8 +157,8 @@ module ActiveRecord def test_column_creates_column_with_options with_change_table do |t| - @connection.expect :add_column, nil, [:delete_me, :bar, :integer, {:null => false}] - t.column :bar, :integer, :null => false + @connection.expect :add_column, nil, [:delete_me, :bar, :integer, { null: false }] + t.column :bar, :integer, null: false end end @@ -171,8 +171,8 @@ module ActiveRecord def test_index_creates_index_with_options with_change_table do |t| - @connection.expect :add_index, nil, [:delete_me, :bar, {:unique => true}] - t.index :bar, :unique => true + @connection.expect :add_index, nil, [:delete_me, :bar, { unique: true }] + t.index :bar, unique: true end end @@ -185,8 +185,8 @@ module ActiveRecord def test_index_exists_with_options with_change_table do |t| - @connection.expect :index_exists?, nil, [:delete_me, :bar, {:unique => true}] - t.index_exists?(:bar, :unique => true) + @connection.expect :index_exists?, nil, [:delete_me, :bar, { unique: true }] + t.index_exists?(:bar, unique: true) end end @@ -206,8 +206,8 @@ module ActiveRecord def test_change_changes_column_with_options with_change_table do |t| - @connection.expect :change_column, nil, [:delete_me, :bar, :string, {:null => true}] - t.change :bar, :string, :null => true + @connection.expect :change_column, nil, [:delete_me, :bar, :string, { null: true }] + t.change :bar, :string, null: true end end @@ -234,8 +234,8 @@ module ActiveRecord def test_remove_index_removes_index_with_options with_change_table do |t| - @connection.expect :remove_index, nil, [:delete_me, {:unique => true}] - t.remove_index :unique => true + @connection.expect :remove_index, nil, [:delete_me, { unique: true }] + t.remove_index unique: true end end diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb index 29546525f3..48df931543 100644 --- a/activerecord/test/cases/migration/column_attributes_test.rb +++ b/activerecord/test/cases/migration/column_attributes_test.rb @@ -9,7 +9,7 @@ module ActiveRecord def test_add_column_newline_default string = "foo\nbar" - add_column 'test_models', 'command', :string, :default => string + add_column "test_models", "command", :string, default: string TestModel.reset_column_information assert_equal string, TestModel.new.command @@ -18,10 +18,10 @@ module ActiveRecord def test_add_remove_single_field_using_string_arguments assert_no_column TestModel, :last_name - add_column 'test_models', 'last_name', :string + add_column "test_models", "last_name", :string assert_column TestModel, :last_name - remove_column 'test_models', 'last_name' + remove_column "test_models", "last_name" assert_no_column TestModel, :last_name end @@ -47,7 +47,7 @@ module ActiveRecord def test_unabstracted_database_dependent_types add_column :test_models, :intelligence_quotient, :tinyint TestModel.reset_column_information - assert_match(/tinyint/, TestModel.columns_hash['intelligence_quotient'].sql_type) + assert_match(/tinyint/, TestModel.columns_hash["intelligence_quotient"].sql_type) end end @@ -56,15 +56,13 @@ module ActiveRecord # functionality. This allows us to more easily catch INSERT being broken, # but SELECT actually working fine. def test_native_decimal_insert_manual_vs_automatic - correct_value = '0012345678901234567890.0123456789'.to_d + correct_value = "0012345678901234567890.0123456789".to_d - connection.add_column "test_models", "wealth", :decimal, :precision => '30', :scale => '10' + connection.add_column "test_models", "wealth", :decimal, precision: "30", scale: "10" # Do a manual insertion if current_adapter?(:OracleAdapter) connection.execute "insert into test_models (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)" - elsif current_adapter?(:PostgreSQLAdapter) - connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)" else connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)" end @@ -74,15 +72,13 @@ module ActiveRecord assert_kind_of BigDecimal, row.wealth # If this assert fails, that means the SELECT is broken! - unless current_adapter?(:SQLite3Adapter) - assert_equal correct_value, row.wealth - end + assert_equal correct_value, row.wealth # Reset to old state TestModel.delete_all # Now use the Rails insertion - TestModel.create :wealth => BigDecimal.new("12345678901234567890.0123456789") + TestModel.create wealth: BigDecimal.new("12345678901234567890.0123456789") # SELECT row = TestModel.first @@ -94,26 +90,26 @@ module ActiveRecord end def test_add_column_with_precision_and_scale - connection.add_column 'test_models', 'wealth', :decimal, :precision => 9, :scale => 7 + connection.add_column "test_models", "wealth", :decimal, precision: 9, scale: 7 - wealth_column = TestModel.columns_hash['wealth'] + wealth_column = TestModel.columns_hash["wealth"] assert_equal 9, wealth_column.precision assert_equal 7, wealth_column.scale end if current_adapter?(:SQLite3Adapter) def test_change_column_preserve_other_column_precision_and_scale - connection.add_column 'test_models', 'last_name', :string - connection.add_column 'test_models', 'wealth', :decimal, :precision => 9, :scale => 7 + connection.add_column "test_models", "last_name", :string + connection.add_column "test_models", "wealth", :decimal, precision: 9, scale: 7 - wealth_column = TestModel.columns_hash['wealth'] + wealth_column = TestModel.columns_hash["wealth"] assert_equal 9, wealth_column.precision assert_equal 7, wealth_column.scale - connection.change_column 'test_models', 'last_name', :string, :null => false + connection.change_column "test_models", "last_name", :string, null: false TestModel.reset_column_information - wealth_column = TestModel.columns_hash['wealth'] + wealth_column = TestModel.columns_hash["wealth"] assert_equal 9, wealth_column.precision assert_equal 7, wealth_column.scale end @@ -126,21 +122,21 @@ module ActiveRecord add_column "test_models", "bio", :text add_column "test_models", "age", :integer add_column "test_models", "height", :float - add_column "test_models", "wealth", :decimal, :precision => '30', :scale => '10' + add_column "test_models", "wealth", :decimal, precision: "30", scale: "10" add_column "test_models", "birthday", :datetime add_column "test_models", "favorite_day", :date add_column "test_models", "moment_of_truth", :datetime add_column "test_models", "male", :boolean - TestModel.create :first_name => 'bob', :last_name => 'bobsen', - :bio => "I was born ....", :age => 18, :height => 1.78, - :wealth => BigDecimal.new("12345678901234567890.0123456789"), - :birthday => 18.years.ago, :favorite_day => 10.days.ago, - :moment_of_truth => "1782-10-10 21:40:18", :male => true + TestModel.create first_name: "bob", last_name: "bobsen", + bio: "I was born ....", age: 18, height: 1.78, + wealth: BigDecimal.new("12345678901234567890.0123456789"), + birthday: 18.years.ago, favorite_day: 10.days.ago, + moment_of_truth: "1782-10-10 21:40:18", male: true bob = TestModel.first - assert_equal 'bob', bob.first_name - assert_equal 'bobsen', bob.last_name + assert_equal "bob", bob.first_name + assert_equal "bobsen", bob.last_name assert_equal "I was born ....", bob.bio assert_equal 18, bob.age @@ -156,14 +152,7 @@ module ActiveRecord assert_equal String, bob.bio.class assert_kind_of Integer, bob.age assert_equal Time, bob.birthday.class - - if current_adapter?(:OracleAdapter) - # Oracle doesn't differentiate between date/time - assert_equal Time, bob.favorite_day.class - else - assert_equal Date, bob.favorite_day.class - end - + assert_equal Date, bob.favorite_day.class assert_instance_of TrueClass, bob.male? assert_kind_of BigDecimal, bob.wealth end @@ -171,10 +160,10 @@ module ActiveRecord if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter) def test_out_of_range_limit_should_raise - assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, :limit => 10 } + assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, limit: 10 } unless current_adapter?(:PostgreSQLAdapter) - assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, :limit => 0xfffffffff } + assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :text, limit: 0xfffffffff } end end end diff --git a/activerecord/test/cases/migration/column_positioning_test.rb b/activerecord/test/cases/migration/column_positioning_test.rb index 8294da0373..f2162d91b1 100644 --- a/activerecord/test/cases/migration/column_positioning_test.rb +++ b/activerecord/test/cases/migration/column_positioning_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration @@ -11,7 +11,7 @@ module ActiveRecord @connection = ActiveRecord::Base.connection - connection.create_table :testings, :id => false do |t| + connection.create_table :testings, id: false do |t| t.column :first, :integer t.column :second, :integer t.column :third, :integer @@ -34,20 +34,20 @@ module ActiveRecord end def test_add_column_with_positioning_first - conn.add_column :testings, :new_col, :integer, :first => true + conn.add_column :testings, :new_col, :integer, first: true assert_equal %w(new_col first second third), conn.columns(:testings).map(&:name) end def test_add_column_with_positioning_after - conn.add_column :testings, :new_col, :integer, :after => :first + conn.add_column :testings, :new_col, :integer, after: :first assert_equal %w(first new_col second third), conn.columns(:testings).map(&:name) end def test_change_column_with_positioning - conn.change_column :testings, :second, :integer, :first => true + conn.change_column :testings, :second, :integer, first: true assert_equal %w(second first third), conn.columns(:testings).map(&:name) - conn.change_column :testings, :second, :integer, :after => :third + conn.change_column :testings, :second, :integer, after: :third assert_equal %w(first third second), conn.columns(:testings).map(&:name) end end diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb index fca1cb7e97..55c06da411 100644 --- a/activerecord/test/cases/migration/columns_test.rb +++ b/activerecord/test/cases/migration/columns_test.rb @@ -13,7 +13,7 @@ module ActiveRecord add_column "test_models", "girlfriend", :string TestModel.reset_column_information - TestModel.create :girlfriend => 'bobette' + TestModel.create girlfriend: "bobette" rename_column "test_models", "girlfriend", "exgirlfriend" @@ -28,12 +28,12 @@ module ActiveRecord def test_rename_column_using_symbol_arguments add_column :test_models, :first_name, :string - TestModel.create :first_name => 'foo' + TestModel.create first_name: "foo" rename_column :test_models, :first_name, :nick_name TestModel.reset_column_information - assert TestModel.column_names.include?("nick_name") - assert_equal ['foo'], TestModel.all.map(&:nick_name) + assert_includes TestModel.column_names, "nick_name" + assert_equal ["foo"], TestModel.all.map(&:nick_name) end # FIXME: another integration test. We should decouple this from the @@ -41,25 +41,25 @@ module ActiveRecord def test_rename_column add_column "test_models", "first_name", "string" - TestModel.create :first_name => 'foo' + TestModel.create first_name: "foo" rename_column "test_models", "first_name", "nick_name" TestModel.reset_column_information - assert TestModel.column_names.include?("nick_name") - assert_equal ['foo'], TestModel.all.map(&:nick_name) + assert_includes TestModel.column_names, "nick_name" + assert_equal ["foo"], TestModel.all.map(&:nick_name) end def test_rename_column_preserves_default_value_not_null - add_column 'test_models', 'salary', :integer, :default => 70000 + add_column "test_models", "salary", :integer, default: 70000 default_before = connection.columns("test_models").find { |c| c.name == "salary" }.default - assert_equal '70000', default_before + assert_equal "70000", default_before rename_column "test_models", "salary", "annual_salary" - assert TestModel.column_names.include?("annual_salary") + assert_includes TestModel.column_names, "annual_salary" default_after = connection.columns("test_models").find { |c| c.name == "annual_salary" }.default - assert_equal '70000', default_after + assert_equal "70000", default_after end if current_adapter?(:Mysql2Adapter) @@ -74,30 +74,31 @@ module ActiveRecord def test_rename_nonexistent_column exception = if current_adapter?(:PostgreSQLAdapter, :OracleAdapter) - ActiveRecord::StatementInvalid - else - ActiveRecord::ActiveRecordError - end + ActiveRecord::StatementInvalid + else + ActiveRecord::ActiveRecordError + end + assert_raise(exception) do rename_column "test_models", "nonexistent", "should_fail" end end def test_rename_column_with_sql_reserved_word - add_column 'test_models', 'first_name', :string + add_column "test_models", "first_name", :string rename_column "test_models", "first_name", "group" - assert TestModel.column_names.include?("group") + assert_includes TestModel.column_names, "group" end def test_rename_column_with_an_index add_column "test_models", :hat_name, :string add_index :test_models, :hat_name - assert_equal 1, connection.indexes('test_models').size + assert_equal 1, connection.indexes("test_models").size rename_column "test_models", "hat_name", "name" - assert_equal ['index_test_models_on_name'], connection.indexes('test_models').map(&:name) + assert_equal ["index_test_models_on_name"], connection.indexes("test_models").map(&:name) end def test_rename_column_with_multi_column_index @@ -105,153 +106,153 @@ module ActiveRecord add_column "test_models", :hat_style, :string, limit: 100 add_index "test_models", ["hat_style", "hat_size"], unique: true - rename_column "test_models", "hat_size", 'size' + rename_column "test_models", "hat_size", "size" if current_adapter? :OracleAdapter - assert_equal ['i_test_models_hat_style_size'], connection.indexes('test_models').map(&:name) + assert_equal ["i_test_models_hat_style_size"], connection.indexes("test_models").map(&:name) else - assert_equal ['index_test_models_on_hat_style_and_size'], connection.indexes('test_models').map(&:name) + assert_equal ["index_test_models_on_hat_style_and_size"], connection.indexes("test_models").map(&:name) end - rename_column "test_models", "hat_style", 'style' + rename_column "test_models", "hat_style", "style" if current_adapter? :OracleAdapter - assert_equal ['i_test_models_style_size'], connection.indexes('test_models').map(&:name) + assert_equal ["i_test_models_style_size"], connection.indexes("test_models").map(&:name) else - assert_equal ['index_test_models_on_style_and_size'], connection.indexes('test_models').map(&:name) + assert_equal ["index_test_models_on_style_and_size"], connection.indexes("test_models").map(&:name) end end def test_rename_column_does_not_rename_custom_named_index add_column "test_models", :hat_name, :string - add_index :test_models, :hat_name, :name => 'idx_hat_name' + add_index :test_models, :hat_name, name: "idx_hat_name" - assert_equal 1, connection.indexes('test_models').size + assert_equal 1, connection.indexes("test_models").size rename_column "test_models", "hat_name", "name" - assert_equal ['idx_hat_name'], connection.indexes('test_models').map(&:name) + assert_equal ["idx_hat_name"], connection.indexes("test_models").map(&:name) end def test_remove_column_with_index add_column "test_models", :hat_name, :string add_index :test_models, :hat_name - assert_equal 1, connection.indexes('test_models').size + assert_equal 1, connection.indexes("test_models").size remove_column("test_models", "hat_name") - assert_equal 0, connection.indexes('test_models').size + assert_equal 0, connection.indexes("test_models").size end def test_remove_column_with_multi_column_index add_column "test_models", :hat_size, :integer - add_column "test_models", :hat_style, :string, :limit => 100 - add_index "test_models", ["hat_style", "hat_size"], :unique => true + add_column "test_models", :hat_style, :string, limit: 100 + add_index "test_models", ["hat_style", "hat_size"], unique: true - assert_equal 1, connection.indexes('test_models').size + assert_equal 1, connection.indexes("test_models").size remove_column("test_models", "hat_size") # Every database and/or database adapter has their own behavior # if it drops the multi-column index when any of the indexed columns dropped by remove_column. if current_adapter?(:PostgreSQLAdapter, :OracleAdapter) - assert_equal [], connection.indexes('test_models').map(&:name) + assert_equal [], connection.indexes("test_models").map(&:name) else - assert_equal ['index_test_models_on_hat_style_and_hat_size'], connection.indexes('test_models').map(&:name) + assert_equal ["index_test_models_on_hat_style_and_hat_size"], connection.indexes("test_models").map(&:name) end end def test_change_type_of_not_null_column - change_column "test_models", "updated_at", :datetime, :null => false - change_column "test_models", "updated_at", :datetime, :null => false + change_column "test_models", "updated_at", :datetime, null: false + change_column "test_models", "updated_at", :datetime, null: false TestModel.reset_column_information - assert_equal false, TestModel.columns_hash['updated_at'].null + assert_equal false, TestModel.columns_hash["updated_at"].null ensure - change_column "test_models", "updated_at", :datetime, :null => true + change_column "test_models", "updated_at", :datetime, null: true end def test_change_column_nullability add_column "test_models", "funny", :boolean assert TestModel.columns_hash["funny"].null, "Column 'funny' must initially allow nulls" - change_column "test_models", "funny", :boolean, :null => false, :default => true + change_column "test_models", "funny", :boolean, null: false, default: true TestModel.reset_column_information assert_not TestModel.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point" - change_column "test_models", "funny", :boolean, :null => true + change_column "test_models", "funny", :boolean, null: true TestModel.reset_column_information assert TestModel.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point" end def test_change_column - add_column 'test_models', 'age', :integer - add_column 'test_models', 'approved', :boolean, :default => true + add_column "test_models", "age", :integer + add_column "test_models", "approved", :boolean, default: true old_columns = connection.columns(TestModel.table_name) - assert old_columns.find { |c| c.name == 'age' && c.type == :integer } + assert old_columns.find { |c| c.name == "age" && c.type == :integer } change_column "test_models", "age", :string new_columns = connection.columns(TestModel.table_name) - assert_not new_columns.find { |c| c.name == 'age' and c.type == :integer } - assert new_columns.find { |c| c.name == 'age' and c.type == :string } + assert_not new_columns.find { |c| c.name == "age" && c.type == :integer } + assert new_columns.find { |c| c.name == "age" && c.type == :string } old_columns = connection.columns(TestModel.table_name) assert old_columns.find { |c| default = connection.lookup_cast_type_from_column(c).deserialize(c.default) - c.name == 'approved' && c.type == :boolean && default == true + c.name == "approved" && c.type == :boolean && default == true } - change_column :test_models, :approved, :boolean, :default => false + change_column :test_models, :approved, :boolean, default: false new_columns = connection.columns(TestModel.table_name) assert_not new_columns.find { |c| default = connection.lookup_cast_type_from_column(c).deserialize(c.default) - c.name == 'approved' and c.type == :boolean and default == true + c.name == "approved" && c.type == :boolean && default == true } assert new_columns.find { |c| default = connection.lookup_cast_type_from_column(c).deserialize(c.default) - c.name == 'approved' and c.type == :boolean and default == false + c.name == "approved" && c.type == :boolean && default == false } - change_column :test_models, :approved, :boolean, :default => true + change_column :test_models, :approved, :boolean, default: true end def test_change_column_with_nil_default - add_column "test_models", "contributor", :boolean, :default => true + add_column "test_models", "contributor", :boolean, default: true assert TestModel.new.contributor? - change_column "test_models", "contributor", :boolean, :default => nil + change_column "test_models", "contributor", :boolean, default: nil TestModel.reset_column_information assert_not TestModel.new.contributor? assert_nil TestModel.new.contributor end def test_change_column_with_new_default - add_column "test_models", "administrator", :boolean, :default => true + add_column "test_models", "administrator", :boolean, default: true assert TestModel.new.administrator? - change_column "test_models", "administrator", :boolean, :default => false + change_column "test_models", "administrator", :boolean, default: false TestModel.reset_column_information assert_not TestModel.new.administrator? end def test_change_column_with_custom_index_name add_column "test_models", "category", :string - add_index :test_models, :category, name: 'test_models_categories_idx' + add_index :test_models, :category, name: "test_models_categories_idx" - assert_equal ['test_models_categories_idx'], connection.indexes('test_models').map(&:name) - change_column "test_models", "category", :string, null: false, default: 'article' + assert_equal ["test_models_categories_idx"], connection.indexes("test_models").map(&:name) + change_column "test_models", "category", :string, null: false, default: "article" - assert_equal ['test_models_categories_idx'], connection.indexes('test_models').map(&:name) + assert_equal ["test_models_categories_idx"], connection.indexes("test_models").map(&:name) end def test_change_column_with_long_index_name - table_name_prefix = 'test_models_' - long_index_name = table_name_prefix + ('x' * (connection.allowed_index_name_length - table_name_prefix.length)) + table_name_prefix = "test_models_" + long_index_name = table_name_prefix + ("x" * (connection.allowed_index_name_length - table_name_prefix.length)) add_column "test_models", "category", :string add_index :test_models, :category, name: long_index_name - change_column "test_models", "category", :string, null: false, default: 'article' + change_column "test_models", "category", :string, null: false, default: "article" - assert_equal [long_index_name], connection.indexes('test_models').map(&:name) + assert_equal [long_index_name], connection.indexes("test_models").map(&:name) end def test_change_column_default @@ -287,7 +288,7 @@ module ActiveRecord remove_column("my_table", "col_two") rename_column("my_table", "col_one", "col_three") - assert_equal 'my_table_id', connection.primary_key('my_table') + assert_equal "my_table_id", connection.primary_key("my_table") ensure connection.drop_table(:my_table) rescue nil end diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 1e3529db54..802a969cb7 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -25,26 +25,26 @@ module ActiveRecord recorder = CommandRecorder.new(Class.new { def create_table(name); end }.new) - assert recorder.respond_to?(:create_table), 'respond_to? create_table' + assert recorder.respond_to?(:create_table), "respond_to? create_table" recorder.send(:create_table, :horses) assert_equal [[:create_table, [:horses], nil]], recorder.commands end def test_unknown_commands_delegate recorder = Struct.new(:foo) - recorder = CommandRecorder.new(recorder.new('bar')) - assert_equal 'bar', recorder.foo + recorder = CommandRecorder.new(recorder.new("bar")) + assert_equal "bar", recorder.foo end def test_inverse_of_raise_exception_on_unknown_commands assert_raises(ActiveRecord::IrreversibleMigration) do - @recorder.inverse_of :execute, ['some sql'] + @recorder.inverse_of :execute, ["some sql"] end end def test_irreversible_commands_raise_exception assert_raises(ActiveRecord::IrreversibleMigration) do - @recorder.revert{ @recorder.execute 'some sql' } + @recorder.revert { @recorder.execute "some sql" } end end @@ -58,12 +58,12 @@ module ActiveRecord @recorder.record :create_table, [:hello] @recorder.record :create_table, [:world] end - tables = @recorder.commands.map{|_cmd, args, _block| args} + tables = @recorder.commands.map { |_cmd, args, _block| args } assert_equal [[:world], [:hello]], tables end def test_revert_order - block = Proc.new{|t| t.string :name } + block = Proc.new { |t| t.string :name } @recorder.instance_eval do create_table("apples", &block) revert do @@ -115,13 +115,13 @@ module ActiveRecord end def test_invert_create_table_with_options_and_block - block = Proc.new{} + block = Proc.new {} drop_table = @recorder.inverse_of :create_table, [:people_reminders, id: false], &block assert_equal [:drop_table, [:people_reminders, id: false], block], drop_table end def test_invert_drop_table - block = Proc.new{} + block = Proc.new {} create_table = @recorder.inverse_of :drop_table, [:people_reminders, id: false], &block assert_equal [:create_table, [:people_reminders, id: false], block], create_table end @@ -143,7 +143,7 @@ module ActiveRecord end def test_invert_drop_join_table - block = Proc.new{} + block = Proc.new {} create_join_table = @recorder.inverse_of :drop_join_table, [:musics, :artists, table_name: :catalog], &block assert_equal [:create_join_table, [:musics, :artists, table_name: :catalog], block], create_join_table end @@ -166,7 +166,7 @@ module ActiveRecord def test_invert_change_column_default assert_raises(ActiveRecord::IrreversibleMigration) do - @recorder.inverse_of :change_column_default, [:table, :column, 'default_value'] + @recorder.inverse_of :change_column_default, [:table, :column, "default_value"] end end @@ -203,17 +203,17 @@ module ActiveRecord def test_invert_add_index remove = @recorder.inverse_of :add_index, [:table, [:one, :two]] - assert_equal [:remove_index, [:table, {column: [:one, :two]}]], remove + assert_equal [:remove_index, [:table, { column: [:one, :two] }]], remove end def test_invert_add_index_with_name remove = @recorder.inverse_of :add_index, [:table, [:one, :two], name: "new_index"] - assert_equal [:remove_index, [:table, {name: "new_index"}]], remove + assert_equal [:remove_index, [:table, { name: "new_index" }]], remove end def test_invert_add_index_with_no_options remove = @recorder.inverse_of :add_index, [:table, [:one, :two]] - assert_equal [:remove_index, [:table, {column: [:one, :two]}]], remove + assert_equal [:remove_index, [:table, { column: [:one, :two] }]], remove end def test_invert_remove_index @@ -222,17 +222,17 @@ module ActiveRecord end def test_invert_remove_index_with_column - add = @recorder.inverse_of :remove_index, [:table, {column: [:one, :two], options: true}] + add = @recorder.inverse_of :remove_index, [:table, { column: [:one, :two], options: true }] assert_equal [:add_index, [:table, [:one, :two], options: true]], add end def test_invert_remove_index_with_name - add = @recorder.inverse_of :remove_index, [:table, {column: [:one, :two], name: "new_index"}] + add = @recorder.inverse_of :remove_index, [:table, { column: [:one, :two], name: "new_index" }] assert_equal [:add_index, [:table, [:one, :two], name: "new_index"]], add end def test_invert_remove_index_with_no_special_options - add = @recorder.inverse_of :remove_index, [:table, {column: [:one, :two]}] + add = @recorder.inverse_of :remove_index, [:table, { column: [:one, :two] }] assert_equal [:add_index, [:table, [:one, :two], {}]], add end @@ -254,7 +254,7 @@ module ActiveRecord def test_invert_remove_timestamps add = @recorder.inverse_of :remove_timestamps, [:table, { null: true }] - assert_equal [:add_timestamps, [:table, {null: true }], nil], add + assert_equal [:add_timestamps, [:table, { null: true }], nil], add end def test_invert_add_reference @@ -283,13 +283,13 @@ module ActiveRecord end def test_invert_enable_extension - disable = @recorder.inverse_of :enable_extension, ['uuid-ossp'] - assert_equal [:disable_extension, ['uuid-ossp'], nil], disable + disable = @recorder.inverse_of :enable_extension, ["uuid-ossp"] + assert_equal [:disable_extension, ["uuid-ossp"], nil], disable end def test_invert_disable_extension - enable = @recorder.inverse_of :disable_extension, ['uuid-ossp'] - assert_equal [:enable_extension, ['uuid-ossp'], nil], enable + enable = @recorder.inverse_of :disable_extension, ["uuid-ossp"] + assert_equal [:enable_extension, ["uuid-ossp"], nil], enable end def test_invert_add_foreign_key diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb index 60ca90464d..0a4b604601 100644 --- a/activerecord/test/cases/migration/compatibility_test.rb +++ b/activerecord/test/cases/migration/compatibility_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration @@ -13,8 +13,8 @@ module ActiveRecord ActiveRecord::Migration.verbose = false connection.create_table :testings do |t| - t.column :foo, :string, :limit => 100 - t.column :bar, :string, :limit => 100 + t.column :foo, :string, limit: 100 + t.column :bar, :string, limit: 100 end end @@ -25,7 +25,7 @@ module ActiveRecord end def test_migration_doesnt_remove_named_index - connection.add_index :testings, :foo, :name => "custom_index_name" + connection.add_index :testings, :foo, name: "custom_index_name" migration = Class.new(ActiveRecord::Migration[4.2]) { def version; 101 end @@ -83,8 +83,8 @@ module ActiveRecord ActiveRecord::Migrator.new(:up, [migration]).migrate - assert connection.columns(:more_testings).find { |c| c.name == 'created_at' }.null - assert connection.columns(:more_testings).find { |c| c.name == 'updated_at' }.null + assert connection.columns(:more_testings).find { |c| c.name == "created_at" }.null + assert connection.columns(:more_testings).find { |c| c.name == "updated_at" }.null ensure connection.drop_table :more_testings rescue nil end @@ -98,8 +98,8 @@ module ActiveRecord ActiveRecord::Migrator.new(:up, [migration]).migrate - assert connection.columns(:testings).find { |c| c.name == 'created_at' }.null - assert connection.columns(:testings).find { |c| c.name == 'updated_at' }.null + assert connection.columns(:testings).find { |c| c.name == "created_at" }.null + assert connection.columns(:testings).find { |c| c.name == "updated_at" }.null end def test_legacy_migrations_get_deprecation_warning_when_run diff --git a/activerecord/test/cases/migration/create_join_table_test.rb b/activerecord/test/cases/migration/create_join_table_test.rb index 920c472c73..f14d68f12b 100644 --- a/activerecord/test/cases/migration/create_join_table_test.rb +++ b/activerecord/test/cases/migration/create_join_table_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration @@ -31,13 +31,13 @@ module ActiveRecord end def test_create_join_table_with_strings - connection.create_join_table 'artists', 'musics' + connection.create_join_table "artists", "musics" assert_equal %w(artist_id music_id), connection.columns(:artists_musics).map(&:name).sort end def test_create_join_table_with_symbol_and_string - connection.create_join_table :artists, 'musics' + connection.create_join_table :artists, "musics" assert_equal %w(artist_id music_id), connection.columns(:artists_musics).map(&:name).sort end @@ -55,13 +55,13 @@ module ActiveRecord end def test_create_join_table_with_the_table_name_as_string - connection.create_join_table :artists, :musics, table_name: 'catalog' + connection.create_join_table :artists, :musics, table_name: "catalog" assert_equal %w(artist_id music_id), connection.columns(:catalog).map(&:name).sort end def test_create_join_table_with_column_options - connection.create_join_table :artists, :musics, column_options: {null: true} + connection.create_join_table :artists, :musics, column_options: { null: true } assert_equal [true, true], connection.columns(:artists_musics).map(&:null) end @@ -84,51 +84,51 @@ module ActiveRecord connection.create_join_table :artists, :musics connection.drop_join_table :artists, :musics - ActiveSupport::Deprecation.silence { assert !connection.table_exists?('artists_musics') } + ActiveSupport::Deprecation.silence { assert !connection.table_exists?("artists_musics") } end def test_drop_join_table_with_strings connection.create_join_table :artists, :musics - connection.drop_join_table 'artists', 'musics' + connection.drop_join_table "artists", "musics" - ActiveSupport::Deprecation.silence { assert !connection.table_exists?('artists_musics') } + ActiveSupport::Deprecation.silence { assert !connection.table_exists?("artists_musics") } end def test_drop_join_table_with_the_proper_order connection.create_join_table :videos, :musics connection.drop_join_table :videos, :musics - ActiveSupport::Deprecation.silence { assert !connection.table_exists?('musics_videos') } + ActiveSupport::Deprecation.silence { assert !connection.table_exists?("musics_videos") } end def test_drop_join_table_with_the_table_name connection.create_join_table :artists, :musics, table_name: :catalog connection.drop_join_table :artists, :musics, table_name: :catalog - ActiveSupport::Deprecation.silence { assert !connection.table_exists?('catalog') } + ActiveSupport::Deprecation.silence { assert !connection.table_exists?("catalog") } end def test_drop_join_table_with_the_table_name_as_string - connection.create_join_table :artists, :musics, table_name: 'catalog' - connection.drop_join_table :artists, :musics, table_name: 'catalog' + connection.create_join_table :artists, :musics, table_name: "catalog" + connection.drop_join_table :artists, :musics, table_name: "catalog" - ActiveSupport::Deprecation.silence { assert !connection.table_exists?('catalog') } + ActiveSupport::Deprecation.silence { assert !connection.table_exists?("catalog") } end def test_drop_join_table_with_column_options - connection.create_join_table :artists, :musics, column_options: {null: true} - connection.drop_join_table :artists, :musics, column_options: {null: true} + connection.create_join_table :artists, :musics, column_options: { null: true } + connection.drop_join_table :artists, :musics, column_options: { null: true } - ActiveSupport::Deprecation.silence { assert !connection.table_exists?('artists_musics') } + ActiveSupport::Deprecation.silence { assert !connection.table_exists?("artists_musics") } end def test_create_and_drop_join_table_with_common_prefix with_table_cleanup do - connection.create_join_table 'audio_artists', 'audio_musics' - ActiveSupport::Deprecation.silence { assert connection.table_exists?('audio_artists_musics') } + connection.create_join_table "audio_artists", "audio_musics" + ActiveSupport::Deprecation.silence { assert connection.table_exists?("audio_artists_musics") } - connection.drop_join_table 'audio_artists', 'audio_musics' - ActiveSupport::Deprecation.silence { assert !connection.table_exists?('audio_artists_musics'), "Should have dropped join table, but didn't" } + connection.drop_join_table "audio_artists", "audio_musics" + ActiveSupport::Deprecation.silence { assert !connection.table_exists?("audio_artists_musics"), "Should have dropped join table, but didn't" } end end diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb index 01162dcefe..cab2069754 100644 --- a/activerecord/test/cases/migration/foreign_key_test.rb +++ b/activerecord/test/cases/migration/foreign_key_test.rb @@ -1,304 +1,316 @@ -require 'cases/helper' -require 'support/ddl_helper' -require 'support/schema_dumping_helper' +require "cases/helper" +require "support/ddl_helper" +require "support/schema_dumping_helper" if ActiveRecord::Base.connection.supports_foreign_keys? -module ActiveRecord - class Migration - class ForeignKeyTest < ActiveRecord::TestCase - include DdlHelper - include SchemaDumpingHelper - include ActiveSupport::Testing::Stream - - class Rocket < ActiveRecord::Base - end - - class Astronaut < ActiveRecord::Base - end - - setup do - @connection = ActiveRecord::Base.connection - @connection.create_table "rockets", force: true do |t| - t.string :name + module ActiveRecord + class Migration + class ForeignKeyTest < ActiveRecord::TestCase + include DdlHelper + include SchemaDumpingHelper + include ActiveSupport::Testing::Stream + + class Rocket < ActiveRecord::Base end - @connection.create_table "astronauts", force: true do |t| - t.string :name - t.references :rocket + class Astronaut < ActiveRecord::Base end - end - teardown do - if defined?(@connection) - @connection.drop_table "astronauts", if_exists: true - @connection.drop_table "rockets", if_exists: true - end - end - - def test_foreign_keys - foreign_keys = @connection.foreign_keys("fk_test_has_fk") - assert_equal 1, foreign_keys.size + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table "rockets", force: true do |t| + t.string :name + end - fk = foreign_keys.first - assert_equal "fk_test_has_fk", fk.from_table - assert_equal "fk_test_has_pk", fk.to_table - assert_equal "fk_id", fk.column - assert_equal "pk_id", fk.primary_key - assert_equal "fk_name", fk.name - end + @connection.create_table "astronauts", force: true do |t| + t.string :name + t.references :rocket + end + end - def test_add_foreign_key_inferes_column - @connection.add_foreign_key :astronauts, :rockets + teardown do + if defined?(@connection) + @connection.drop_table "astronauts", if_exists: true + @connection.drop_table "rockets", if_exists: true + end + end - foreign_keys = @connection.foreign_keys("astronauts") - assert_equal 1, foreign_keys.size + def test_foreign_keys + foreign_keys = @connection.foreign_keys("fk_test_has_fk") + assert_equal 1, foreign_keys.size - fk = foreign_keys.first - assert_equal "astronauts", fk.from_table - assert_equal "rockets", fk.to_table - assert_equal "rocket_id", fk.column - assert_equal "id", fk.primary_key - assert_equal("fk_rails_78146ddd2e", fk.name) - end + fk = foreign_keys.first + assert_equal "fk_test_has_fk", fk.from_table + assert_equal "fk_test_has_pk", fk.to_table + assert_equal "fk_id", fk.column + assert_equal "pk_id", fk.primary_key + assert_equal "fk_name", fk.name + end - def test_add_foreign_key_with_column - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" + def test_add_foreign_key_inferes_column + @connection.add_foreign_key :astronauts, :rockets - foreign_keys = @connection.foreign_keys("astronauts") - assert_equal 1, foreign_keys.size + foreign_keys = @connection.foreign_keys("astronauts") + assert_equal 1, foreign_keys.size - fk = foreign_keys.first - assert_equal "astronauts", fk.from_table - assert_equal "rockets", fk.to_table - assert_equal "rocket_id", fk.column - assert_equal "id", fk.primary_key - assert_equal("fk_rails_78146ddd2e", fk.name) - end + fk = foreign_keys.first + assert_equal "astronauts", fk.from_table + assert_equal "rockets", fk.to_table + assert_equal "rocket_id", fk.column + assert_equal "id", fk.primary_key + assert_equal("fk_rails_78146ddd2e", fk.name) + end - def test_add_foreign_key_with_non_standard_primary_key - with_example_table @connection, "space_shuttles", "pk integer PRIMARY KEY" do - @connection.add_foreign_key(:astronauts, :space_shuttles, - column: "rocket_id", primary_key: "pk", name: "custom_pk") + def test_add_foreign_key_with_column + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" foreign_keys = @connection.foreign_keys("astronauts") assert_equal 1, foreign_keys.size fk = foreign_keys.first assert_equal "astronauts", fk.from_table - assert_equal "space_shuttles", fk.to_table - assert_equal "pk", fk.primary_key - - @connection.remove_foreign_key :astronauts, name: "custom_pk" + assert_equal "rockets", fk.to_table + assert_equal "rocket_id", fk.column + assert_equal "id", fk.primary_key + assert_equal("fk_rails_78146ddd2e", fk.name) end - end - def test_add_on_delete_restrict_foreign_key - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :restrict + def test_add_foreign_key_with_non_standard_primary_key + with_example_table @connection, "space_shuttles", "pk integer PRIMARY KEY" do + @connection.add_foreign_key(:astronauts, :space_shuttles, + column: "rocket_id", primary_key: "pk", name: "custom_pk") + + foreign_keys = @connection.foreign_keys("astronauts") + assert_equal 1, foreign_keys.size - foreign_keys = @connection.foreign_keys("astronauts") - assert_equal 1, foreign_keys.size + fk = foreign_keys.first + assert_equal "astronauts", fk.from_table + assert_equal "space_shuttles", fk.to_table + assert_equal "pk", fk.primary_key - fk = foreign_keys.first - if current_adapter?(:Mysql2Adapter) - # ON DELETE RESTRICT is the default on MySQL - assert_equal nil, fk.on_delete - else - assert_equal :restrict, fk.on_delete + @connection.remove_foreign_key :astronauts, name: "custom_pk" + end end - end - def test_add_on_delete_cascade_foreign_key - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :cascade + def test_add_on_delete_restrict_foreign_key + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :restrict + + foreign_keys = @connection.foreign_keys("astronauts") + assert_equal 1, foreign_keys.size + + fk = foreign_keys.first + if current_adapter?(:Mysql2Adapter) + # ON DELETE RESTRICT is the default on MySQL + assert_equal nil, fk.on_delete + else + assert_equal :restrict, fk.on_delete + end + end - foreign_keys = @connection.foreign_keys("astronauts") - assert_equal 1, foreign_keys.size + def test_add_on_delete_cascade_foreign_key + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :cascade - fk = foreign_keys.first - assert_equal :cascade, fk.on_delete - end + foreign_keys = @connection.foreign_keys("astronauts") + assert_equal 1, foreign_keys.size - def test_add_on_delete_nullify_foreign_key - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :nullify + fk = foreign_keys.first + assert_equal :cascade, fk.on_delete + end - foreign_keys = @connection.foreign_keys("astronauts") - assert_equal 1, foreign_keys.size + def test_add_on_delete_nullify_foreign_key + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :nullify - fk = foreign_keys.first - assert_equal :nullify, fk.on_delete - end + foreign_keys = @connection.foreign_keys("astronauts") + assert_equal 1, foreign_keys.size - def test_on_update_and_on_delete_raises_with_invalid_values - assert_raises ArgumentError do - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :invalid + fk = foreign_keys.first + assert_equal :nullify, fk.on_delete end - assert_raises ArgumentError do - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :invalid + def test_on_update_and_on_delete_raises_with_invalid_values + assert_raises ArgumentError do + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :invalid + end + + assert_raises ArgumentError do + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :invalid + end end - end - def test_add_foreign_key_with_on_update - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :nullify + def test_add_foreign_key_with_on_update + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :nullify - foreign_keys = @connection.foreign_keys("astronauts") - assert_equal 1, foreign_keys.size + foreign_keys = @connection.foreign_keys("astronauts") + assert_equal 1, foreign_keys.size - fk = foreign_keys.first - assert_equal :nullify, fk.on_update - end + fk = foreign_keys.first + assert_equal :nullify, fk.on_update + end - def test_foreign_key_exists - @connection.add_foreign_key :astronauts, :rockets + def test_foreign_key_exists + @connection.add_foreign_key :astronauts, :rockets - assert @connection.foreign_key_exists?(:astronauts, :rockets) - assert_not @connection.foreign_key_exists?(:astronauts, :stars) - end + assert @connection.foreign_key_exists?(:astronauts, :rockets) + assert_not @connection.foreign_key_exists?(:astronauts, :stars) + end - def test_foreign_key_exists_by_column - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" + def test_foreign_key_exists_by_column + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" - assert @connection.foreign_key_exists?(:astronauts, column: "rocket_id") - assert_not @connection.foreign_key_exists?(:astronauts, column: "star_id") - end + assert @connection.foreign_key_exists?(:astronauts, column: "rocket_id") + assert_not @connection.foreign_key_exists?(:astronauts, column: "star_id") + end - def test_foreign_key_exists_by_name - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk" + def test_foreign_key_exists_by_name + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk" - assert @connection.foreign_key_exists?(:astronauts, name: "fancy_named_fk") - assert_not @connection.foreign_key_exists?(:astronauts, name: "other_fancy_named_fk") - end + assert @connection.foreign_key_exists?(:astronauts, name: "fancy_named_fk") + assert_not @connection.foreign_key_exists?(:astronauts, name: "other_fancy_named_fk") + end - def test_remove_foreign_key_inferes_column - @connection.add_foreign_key :astronauts, :rockets + def test_remove_foreign_key_inferes_column + @connection.add_foreign_key :astronauts, :rockets - assert_equal 1, @connection.foreign_keys("astronauts").size - @connection.remove_foreign_key :astronauts, :rockets - assert_equal [], @connection.foreign_keys("astronauts") - end + assert_equal 1, @connection.foreign_keys("astronauts").size + @connection.remove_foreign_key :astronauts, :rockets + assert_equal [], @connection.foreign_keys("astronauts") + end - def test_remove_foreign_key_by_column - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" + def test_remove_foreign_key_by_column + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" - assert_equal 1, @connection.foreign_keys("astronauts").size - @connection.remove_foreign_key :astronauts, column: "rocket_id" - assert_equal [], @connection.foreign_keys("astronauts") - end + assert_equal 1, @connection.foreign_keys("astronauts").size + @connection.remove_foreign_key :astronauts, column: "rocket_id" + assert_equal [], @connection.foreign_keys("astronauts") + end - def test_remove_foreign_key_by_symbol_column - @connection.add_foreign_key :astronauts, :rockets, column: :rocket_id + def test_remove_foreign_key_by_symbol_column + @connection.add_foreign_key :astronauts, :rockets, column: :rocket_id - assert_equal 1, @connection.foreign_keys("astronauts").size - @connection.remove_foreign_key :astronauts, column: :rocket_id - assert_equal [], @connection.foreign_keys("astronauts") - end + assert_equal 1, @connection.foreign_keys("astronauts").size + @connection.remove_foreign_key :astronauts, column: :rocket_id + assert_equal [], @connection.foreign_keys("astronauts") + end - def test_remove_foreign_key_by_name - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk" + def test_remove_foreign_key_by_name + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk" - assert_equal 1, @connection.foreign_keys("astronauts").size - @connection.remove_foreign_key :astronauts, name: "fancy_named_fk" - assert_equal [], @connection.foreign_keys("astronauts") - end + assert_equal 1, @connection.foreign_keys("astronauts").size + @connection.remove_foreign_key :astronauts, name: "fancy_named_fk" + assert_equal [], @connection.foreign_keys("astronauts") + end - def test_remove_foreign_non_existing_foreign_key_raises - assert_raises ArgumentError do - @connection.remove_foreign_key :astronauts, :rockets + def test_remove_foreign_non_existing_foreign_key_raises + assert_raises ArgumentError do + @connection.remove_foreign_key :astronauts, :rockets + end end - end - def test_schema_dumping - @connection.add_foreign_key :astronauts, :rockets - output = dump_table_schema "astronauts" - assert_match %r{\s+add_foreign_key "astronauts", "rockets"$}, output - end + def test_schema_dumping + @connection.add_foreign_key :astronauts, :rockets + output = dump_table_schema "astronauts" + assert_match %r{\s+add_foreign_key "astronauts", "rockets"$}, output + end - def test_schema_dumping_with_options - output = dump_table_schema "fk_test_has_fk" - assert_match %r{\s+add_foreign_key "fk_test_has_fk", "fk_test_has_pk", column: "fk_id", primary_key: "pk_id", name: "fk_name"$}, output - end + def test_schema_dumping_with_options + output = dump_table_schema "fk_test_has_fk" + assert_match %r{\s+add_foreign_key "fk_test_has_fk", "fk_test_has_pk", column: "fk_id", primary_key: "pk_id", name: "fk_name"$}, output + end - def test_schema_dumping_on_delete_and_on_update_options - @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :nullify, on_update: :cascade + def test_schema_dumping_on_delete_and_on_update_options + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :nullify, on_update: :cascade - output = dump_table_schema "astronauts" - assert_match %r{\s+add_foreign_key "astronauts",.+on_update: :cascade,.+on_delete: :nullify$}, output - end + output = dump_table_schema "astronauts" + assert_match %r{\s+add_foreign_key "astronauts",.+on_update: :cascade,.+on_delete: :nullify$}, output + end + + class CreateCitiesAndHousesMigration < ActiveRecord::Migration::Current + def change + create_table("cities") { |t| } - class CreateCitiesAndHousesMigration < ActiveRecord::Migration::Current - def change - create_table("cities") { |t| } + create_table("houses") do |t| + t.column :city_id, :integer + end + add_foreign_key :houses, :cities, column: "city_id" - create_table("houses") do |t| - t.column :city_id, :integer + # remove and re-add to test that schema is updated and not accidentally cached + remove_foreign_key :houses, :cities + add_foreign_key :houses, :cities, column: "city_id", on_delete: :cascade end - add_foreign_key :houses, :cities, column: "city_id" end - end - def test_add_foreign_key_is_reversible - migration = CreateCitiesAndHousesMigration.new - silence_stream($stdout) { migration.migrate(:up) } - assert_equal 1, @connection.foreign_keys("houses").size - ensure - silence_stream($stdout) { migration.migrate(:down) } - end + def test_add_foreign_key_is_reversible + migration = CreateCitiesAndHousesMigration.new + silence_stream($stdout) { migration.migrate(:up) } + assert_equal 1, @connection.foreign_keys("houses").size + ensure + silence_stream($stdout) { migration.migrate(:down) } + end + + def test_foreign_key_constraint_is_not_cached_incorrectly + migration = CreateCitiesAndHousesMigration.new + silence_stream($stdout) { migration.migrate(:up) } + output = dump_table_schema "houses" + assert_match %r{\s+add_foreign_key "houses",.+on_delete: :cascade$}, output + ensure + silence_stream($stdout) { migration.migrate(:down) } + end - class CreateSchoolsAndClassesMigration < ActiveRecord::Migration::Current - def change - create_table(:schools) + class CreateSchoolsAndClassesMigration < ActiveRecord::Migration::Current + def change + create_table(:schools) - create_table(:classes) do |t| - t.column :school_id, :integer + create_table(:classes) do |t| + t.column :school_id, :integer + end + add_foreign_key :classes, :schools end - add_foreign_key :classes, :schools end - end - def test_add_foreign_key_with_prefix - ActiveRecord::Base.table_name_prefix = 'p_' - migration = CreateSchoolsAndClassesMigration.new - silence_stream($stdout) { migration.migrate(:up) } - assert_equal 1, @connection.foreign_keys("p_classes").size - ensure - silence_stream($stdout) { migration.migrate(:down) } - ActiveRecord::Base.table_name_prefix = nil - end + def test_add_foreign_key_with_prefix + ActiveRecord::Base.table_name_prefix = "p_" + migration = CreateSchoolsAndClassesMigration.new + silence_stream($stdout) { migration.migrate(:up) } + assert_equal 1, @connection.foreign_keys("p_classes").size + ensure + silence_stream($stdout) { migration.migrate(:down) } + ActiveRecord::Base.table_name_prefix = nil + end - def test_add_foreign_key_with_suffix - ActiveRecord::Base.table_name_suffix = '_s' - migration = CreateSchoolsAndClassesMigration.new - silence_stream($stdout) { migration.migrate(:up) } - assert_equal 1, @connection.foreign_keys("classes_s").size - ensure - silence_stream($stdout) { migration.migrate(:down) } - ActiveRecord::Base.table_name_suffix = nil + def test_add_foreign_key_with_suffix + ActiveRecord::Base.table_name_suffix = "_s" + migration = CreateSchoolsAndClassesMigration.new + silence_stream($stdout) { migration.migrate(:up) } + assert_equal 1, @connection.foreign_keys("classes_s").size + ensure + silence_stream($stdout) { migration.migrate(:down) } + ActiveRecord::Base.table_name_suffix = nil + end end - end end -end else -module ActiveRecord - class Migration - class NoForeignKeySupportTest < ActiveRecord::TestCase - setup do - @connection = ActiveRecord::Base.connection - end + module ActiveRecord + class Migration + class NoForeignKeySupportTest < ActiveRecord::TestCase + setup do + @connection = ActiveRecord::Base.connection + end - def test_add_foreign_key_should_be_noop - @connection.add_foreign_key :clubs, :categories - end + def test_add_foreign_key_should_be_noop + @connection.add_foreign_key :clubs, :categories + end - def test_remove_foreign_key_should_be_noop - @connection.remove_foreign_key :clubs, :categories - end + def test_remove_foreign_key_should_be_noop + @connection.remove_foreign_key :clubs, :categories + end - def test_foreign_keys_should_raise_not_implemented - assert_raises NotImplementedError do - @connection.foreign_keys("clubs") + def test_foreign_keys_should_raise_not_implemented + assert_raises NotImplementedError do + @connection.foreign_keys("clubs") + end end end end end end -end diff --git a/activerecord/test/cases/migration/helper.rb b/activerecord/test/cases/migration/helper.rb index ad85684c0b..9c0fa7339d 100644 --- a/activerecord/test/cases/migration/helper.rb +++ b/activerecord/test/cases/migration/helper.rb @@ -33,7 +33,7 @@ module ActiveRecord private - delegate(*CONNECTION_METHODS, to: :connection) + delegate(*CONNECTION_METHODS, to: :connection) end end end diff --git a/activerecord/test/cases/migration/index_test.rb b/activerecord/test/cases/migration/index_test.rb index 5abd37bfa2..0f975026b8 100644 --- a/activerecord/test/cases/migration/index_test.rb +++ b/activerecord/test/cases/migration/index_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration @@ -11,12 +11,12 @@ module ActiveRecord @table_name = :testings connection.create_table table_name do |t| - t.column :foo, :string, :limit => 100 - t.column :bar, :string, :limit => 100 + t.column :foo, :string, limit: 100 + t.column :bar, :string, limit: 100 t.string :first_name - t.string :last_name, :limit => 100 - t.string :key, :limit => 100 + t.string :last_name, limit: 100 + t.string :key, limit: 100 t.boolean :administrator end end @@ -28,32 +28,31 @@ module ActiveRecord def test_rename_index # keep the names short to make Oracle and similar behave - connection.add_index(table_name, [:foo], :name => 'old_idx') - connection.rename_index(table_name, 'old_idx', 'new_idx') + connection.add_index(table_name, [:foo], name: "old_idx") + connection.rename_index(table_name, "old_idx", "new_idx") # if the adapter doesn't support the indexes call, pick defaults that let the test pass - assert_not connection.index_name_exists?(table_name, 'old_idx', false) - assert connection.index_name_exists?(table_name, 'new_idx', true) + assert_not connection.index_name_exists?(table_name, "old_idx", false) + assert connection.index_name_exists?(table_name, "new_idx", true) end def test_rename_index_too_long - too_long_index_name = good_index_name + 'x' + too_long_index_name = good_index_name + "x" # keep the names short to make Oracle and similar behave - connection.add_index(table_name, [:foo], :name => 'old_idx') + connection.add_index(table_name, [:foo], name: "old_idx") e = assert_raises(ArgumentError) { - connection.rename_index(table_name, 'old_idx', too_long_index_name) + connection.rename_index(table_name, "old_idx", too_long_index_name) } assert_match(/too long; the limit is #{connection.allowed_index_name_length} characters/, e.message) # if the adapter doesn't support the indexes call, pick defaults that let the test pass - assert connection.index_name_exists?(table_name, 'old_idx', false) + assert connection.index_name_exists?(table_name, "old_idx", false) end - def test_double_add_index - connection.add_index(table_name, [:foo], :name => 'some_idx') + connection.add_index(table_name, [:foo], name: "some_idx") assert_raises(ArgumentError) { - connection.add_index(table_name, [:foo], :name => 'some_idx') + connection.add_index(table_name, [:foo], name: "some_idx") } end @@ -69,7 +68,7 @@ module ActiveRecord end def test_add_index_does_not_accept_too_long_index_names - too_long_index_name = good_index_name + 'x' + too_long_index_name = good_index_name + "x" e = assert_raises(ArgumentError) { connection.add_index(table_name, "foo", name: too_long_index_name) @@ -77,11 +76,11 @@ module ActiveRecord assert_match(/too long; the limit is #{connection.allowed_index_name_length} characters/, e.message) assert_not connection.index_name_exists?(table_name, too_long_index_name, false) - connection.add_index(table_name, "foo", :name => good_index_name) + connection.add_index(table_name, "foo", name: good_index_name) end def test_internal_index_with_name_matching_database_limit - good_index_name = 'x' * connection.index_name_length + good_index_name = "x" * connection.index_name_length connection.add_index(table_name, "foo", name: good_index_name, internal: true) assert connection.index_name_exists?(table_name, good_index_name, false) @@ -89,11 +88,11 @@ module ActiveRecord end def test_index_symbol_names - connection.add_index table_name, :foo, :name => :symbol_index_name - assert connection.index_exists?(table_name, :foo, :name => :symbol_index_name) + connection.add_index table_name, :foo, name: :symbol_index_name + assert connection.index_exists?(table_name, :foo, name: :symbol_index_name) - connection.remove_index table_name, :name => :symbol_index_name - assert_not connection.index_exists?(table_name, :foo, :name => :symbol_index_name) + connection.remove_index table_name, name: :symbol_index_name + assert_not connection.index_exists?(table_name, :foo, name: :symbol_index_name) end def test_index_exists @@ -122,21 +121,21 @@ module ActiveRecord end def test_unique_index_exists - connection.add_index :testings, :foo, :unique => true + connection.add_index :testings, :foo, unique: true - assert connection.index_exists?(:testings, :foo, :unique => true) + assert connection.index_exists?(:testings, :foo, unique: true) end def test_named_index_exists - connection.add_index :testings, :foo, :name => "custom_index_name" + connection.add_index :testings, :foo, name: "custom_index_name" assert connection.index_exists?(:testings, :foo) - assert connection.index_exists?(:testings, :foo, :name => "custom_index_name") - assert !connection.index_exists?(:testings, :foo, :name => "other_index_name") + assert connection.index_exists?(:testings, :foo, name: "custom_index_name") + assert !connection.index_exists?(:testings, :foo, name: "other_index_name") end def test_remove_named_index - connection.add_index :testings, :foo, :name => "custom_index_name" + connection.add_index :testings, :foo, name: "custom_index_name" assert connection.index_exists?(:testings, :foo) connection.remove_index :testings, :foo @@ -144,7 +143,7 @@ module ActiveRecord end def test_add_index_attribute_length_limit - connection.add_index :testings, [:foo, :bar], :length => {:foo => 10, :bar => nil} + connection.add_index :testings, [:foo, :bar], length: { foo: 10, bar: nil } assert connection.index_exists?(:testings, [:foo, :bar]) end @@ -154,53 +153,53 @@ module ActiveRecord connection.remove_index("testings", "last_name") connection.add_index("testings", ["last_name", "first_name"]) - connection.remove_index("testings", :column => ["last_name", "first_name"]) + connection.remove_index("testings", column: ["last_name", "first_name"]) # Oracle adapter cannot have specified index name larger than 30 characters # Oracle adapter is shortening index name when just column list is given unless current_adapter?(:OracleAdapter) connection.add_index("testings", ["last_name", "first_name"]) - connection.remove_index("testings", :name => :index_testings_on_last_name_and_first_name) + connection.remove_index("testings", name: :index_testings_on_last_name_and_first_name) connection.add_index("testings", ["last_name", "first_name"]) connection.remove_index("testings", "last_name_and_first_name") end connection.add_index("testings", ["last_name", "first_name"]) connection.remove_index("testings", ["last_name", "first_name"]) - connection.add_index("testings", ["last_name"], :length => 10) + connection.add_index("testings", ["last_name"], length: 10) connection.remove_index("testings", "last_name") - connection.add_index("testings", ["last_name"], :length => {:last_name => 10}) + connection.add_index("testings", ["last_name"], length: { last_name: 10 }) connection.remove_index("testings", ["last_name"]) - connection.add_index("testings", ["last_name", "first_name"], :length => 10) + connection.add_index("testings", ["last_name", "first_name"], length: 10) connection.remove_index("testings", ["last_name", "first_name"]) - connection.add_index("testings", ["last_name", "first_name"], :length => {:last_name => 10, :first_name => 20}) + connection.add_index("testings", ["last_name", "first_name"], length: { last_name: 10, first_name: 20 }) connection.remove_index("testings", ["last_name", "first_name"]) - connection.add_index("testings", ["key"], :name => "key_idx", :unique => true) - connection.remove_index("testings", :name => "key_idx", :unique => true) + connection.add_index("testings", ["key"], name: "key_idx", unique: true) + connection.remove_index("testings", name: "key_idx", unique: true) - connection.add_index("testings", %w(last_name first_name administrator), :name => "named_admin") - connection.remove_index("testings", :name => "named_admin") + connection.add_index("testings", %w(last_name first_name administrator), name: "named_admin") + connection.remove_index("testings", name: "named_admin") # Selected adapters support index sort order if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter) - connection.add_index("testings", ["last_name"], :order => {:last_name => :desc}) + connection.add_index("testings", ["last_name"], order: { last_name: :desc }) connection.remove_index("testings", ["last_name"]) - connection.add_index("testings", ["last_name", "first_name"], :order => {:last_name => :desc}) + connection.add_index("testings", ["last_name", "first_name"], order: { last_name: :desc }) connection.remove_index("testings", ["last_name", "first_name"]) - connection.add_index("testings", ["last_name", "first_name"], :order => {:last_name => :desc, :first_name => :asc}) + connection.add_index("testings", ["last_name", "first_name"], order: { last_name: :desc, first_name: :asc }) connection.remove_index("testings", ["last_name", "first_name"]) - connection.add_index("testings", ["last_name", "first_name"], :order => :desc) + connection.add_index("testings", ["last_name", "first_name"], order: :desc) connection.remove_index("testings", ["last_name", "first_name"]) end end if current_adapter?(:PostgreSQLAdapter) def test_add_partial_index - connection.add_index("testings", "last_name", :where => "first_name = 'john doe'") + connection.add_index("testings", "last_name", where: "first_name = 'john doe'") assert connection.index_exists?("testings", "last_name") connection.remove_index("testings", "last_name") @@ -210,9 +209,8 @@ module ActiveRecord private def good_index_name - 'x' * connection.allowed_index_name_length + "x" * connection.allowed_index_name_length end - end end end diff --git a/activerecord/test/cases/migration/logger_test.rb b/activerecord/test/cases/migration/logger_test.rb index bf6e684887..3d7c7ad469 100644 --- a/activerecord/test/cases/migration/logger_test.rb +++ b/activerecord/test/cases/migration/logger_test.rb @@ -8,7 +8,7 @@ module ActiveRecord Migration = Struct.new(:name, :version) do def disable_ddl_transaction; false end - def migrate direction + def migrate(direction) # do nothing end end @@ -26,7 +26,7 @@ module ActiveRecord def test_migration_should_be_run_without_logger previous_logger = ActiveRecord::Base.logger ActiveRecord::Base.logger = nil - migrations = [Migration.new('a', 1), Migration.new('b', 2), Migration.new('c', 3)] + migrations = [Migration.new("a", 1), Migration.new("b", 2), Migration.new("c", 3)] ActiveRecord::Migrator.new(:up, migrations).migrate ensure ActiveRecord::Base.logger = previous_logger diff --git a/activerecord/test/cases/migration/pending_migrations_test.rb b/activerecord/test/cases/migration/pending_migrations_test.rb index 4f5589f32a..61f5a061b0 100644 --- a/activerecord/test/cases/migration/pending_migrations_test.rb +++ b/activerecord/test/cases/migration/pending_migrations_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration diff --git a/activerecord/test/cases/migration/references_foreign_key_test.rb b/activerecord/test/cases/migration/references_foreign_key_test.rb index 9e19eb9f73..528811db49 100644 --- a/activerecord/test/cases/migration/references_foreign_key_test.rb +++ b/activerecord/test/cases/migration/references_foreign_key_test.rb @@ -1,216 +1,216 @@ -require 'cases/helper' +require "cases/helper" if ActiveRecord::Base.connection.supports_foreign_keys? -module ActiveRecord - class Migration - class ReferencesForeignKeyTest < ActiveRecord::TestCase - setup do - @connection = ActiveRecord::Base.connection - @connection.create_table(:testing_parents, force: true) - end - - teardown do - @connection.drop_table "testings", if_exists: true - @connection.drop_table "testing_parents", if_exists: true - end + module ActiveRecord + class Migration + class ReferencesForeignKeyTest < ActiveRecord::TestCase + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table(:testing_parents, force: true) + end - test "foreign keys can be created with the table" do - @connection.create_table :testings do |t| - t.references :testing_parent, foreign_key: true + teardown do + @connection.drop_table "testings", if_exists: true + @connection.drop_table "testing_parents", if_exists: true end - fk = @connection.foreign_keys("testings").first - assert_equal "testings", fk.from_table - assert_equal "testing_parents", fk.to_table - end + test "foreign keys can be created with the table" do + @connection.create_table :testings do |t| + t.references :testing_parent, foreign_key: true + end - test "no foreign key is created by default" do - @connection.create_table :testings do |t| - t.references :testing_parent + fk = @connection.foreign_keys("testings").first + assert_equal "testings", fk.from_table + assert_equal "testing_parents", fk.to_table end - assert_equal [], @connection.foreign_keys("testings") - end - - test "foreign keys can be created in one query when index is not added" do - assert_queries(1) do + test "no foreign key is created by default" do @connection.create_table :testings do |t| - t.references :testing_parent, foreign_key: true, index: false + t.references :testing_parent end - end - end - test "options hash can be passed" do - @connection.change_table :testing_parents do |t| - t.integer :other_id - t.index :other_id, unique: true + assert_equal [], @connection.foreign_keys("testings") end - @connection.create_table :testings do |t| - t.references :testing_parent, foreign_key: { primary_key: :other_id } + + test "foreign keys can be created in one query when index is not added" do + assert_queries(1) do + @connection.create_table :testings do |t| + t.references :testing_parent, foreign_key: true, index: false + end + end end - fk = @connection.foreign_keys("testings").find { |k| k.to_table == "testing_parents" } - assert_equal "other_id", fk.primary_key - end + test "options hash can be passed" do + @connection.change_table :testing_parents do |t| + t.integer :other_id + t.index :other_id, unique: true + end + @connection.create_table :testings do |t| + t.references :testing_parent, foreign_key: { primary_key: :other_id } + end - test "to_table option can be passed" do - @connection.create_table :testings do |t| - t.references :parent, foreign_key: { to_table: :testing_parents } + fk = @connection.foreign_keys("testings").find { |k| k.to_table == "testing_parents" } + assert_equal "other_id", fk.primary_key end - fks = @connection.foreign_keys("testings") - assert_equal([["testings", "testing_parents", "parent_id"]], - fks.map {|fk| [fk.from_table, fk.to_table, fk.column] }) - end - test "foreign keys cannot be added to polymorphic relations when creating the table" do - @connection.create_table :testings do |t| - assert_raises(ArgumentError) do - t.references :testing_parent, polymorphic: true, foreign_key: true + test "to_table option can be passed" do + @connection.create_table :testings do |t| + t.references :parent, foreign_key: { to_table: :testing_parents } end + fks = @connection.foreign_keys("testings") + assert_equal([["testings", "testing_parents", "parent_id"]], + fks.map { |fk| [fk.from_table, fk.to_table, fk.column] }) end - end - test "foreign keys can be created while changing the table" do - @connection.create_table :testings - @connection.change_table :testings do |t| - t.references :testing_parent, foreign_key: true + test "foreign keys cannot be added to polymorphic relations when creating the table" do + @connection.create_table :testings do |t| + assert_raises(ArgumentError) do + t.references :testing_parent, polymorphic: true, foreign_key: true + end + end end - fk = @connection.foreign_keys("testings").first - assert_equal "testings", fk.from_table - assert_equal "testing_parents", fk.to_table - end + test "foreign keys can be created while changing the table" do + @connection.create_table :testings + @connection.change_table :testings do |t| + t.references :testing_parent, foreign_key: true + end - test "foreign keys are not added by default when changing the table" do - @connection.create_table :testings - @connection.change_table :testings do |t| - t.references :testing_parent + fk = @connection.foreign_keys("testings").first + assert_equal "testings", fk.from_table + assert_equal "testing_parents", fk.to_table end - assert_equal [], @connection.foreign_keys("testings") - end + test "foreign keys are not added by default when changing the table" do + @connection.create_table :testings + @connection.change_table :testings do |t| + t.references :testing_parent + end - test "foreign keys accept options when changing the table" do - @connection.change_table :testing_parents do |t| - t.integer :other_id - t.index :other_id, unique: true - end - @connection.create_table :testings - @connection.change_table :testings do |t| - t.references :testing_parent, foreign_key: { primary_key: :other_id } + assert_equal [], @connection.foreign_keys("testings") end - fk = @connection.foreign_keys("testings").find { |k| k.to_table == "testing_parents" } - assert_equal "other_id", fk.primary_key - end - - test "foreign keys cannot be added to polymorphic relations when changing the table" do - @connection.create_table :testings - @connection.change_table :testings do |t| - assert_raises(ArgumentError) do - t.references :testing_parent, polymorphic: true, foreign_key: true + test "foreign keys accept options when changing the table" do + @connection.change_table :testing_parents do |t| + t.integer :other_id + t.index :other_id, unique: true + end + @connection.create_table :testings + @connection.change_table :testings do |t| + t.references :testing_parent, foreign_key: { primary_key: :other_id } end - end - end - test "foreign key column can be removed" do - @connection.create_table :testings do |t| - t.references :testing_parent, index: true, foreign_key: true + fk = @connection.foreign_keys("testings").find { |k| k.to_table == "testing_parents" } + assert_equal "other_id", fk.primary_key end - assert_difference "@connection.foreign_keys('testings').size", -1 do - @connection.remove_reference :testings, :testing_parent, foreign_key: true + test "foreign keys cannot be added to polymorphic relations when changing the table" do + @connection.create_table :testings + @connection.change_table :testings do |t| + assert_raises(ArgumentError) do + t.references :testing_parent, polymorphic: true, foreign_key: true + end + end end - end - test "foreign key methods respect pluralize_table_names" do - begin - original_pluralize_table_names = ActiveRecord::Base.pluralize_table_names - ActiveRecord::Base.pluralize_table_names = false - @connection.create_table :testing - @connection.change_table :testing_parents do |t| - t.references :testing, foreign_key: true + test "foreign key column can be removed" do + @connection.create_table :testings do |t| + t.references :testing_parent, index: true, foreign_key: true end - fk = @connection.foreign_keys("testing_parents").first - assert_equal "testing_parents", fk.from_table - assert_equal "testing", fk.to_table + assert_difference "@connection.foreign_keys('testings').size", -1 do + @connection.remove_reference :testings, :testing_parent, foreign_key: true + end + end - assert_difference "@connection.foreign_keys('testing_parents').size", -1 do - @connection.remove_reference :testing_parents, :testing, foreign_key: true + test "foreign key methods respect pluralize_table_names" do + begin + original_pluralize_table_names = ActiveRecord::Base.pluralize_table_names + ActiveRecord::Base.pluralize_table_names = false + @connection.create_table :testing + @connection.change_table :testing_parents do |t| + t.references :testing, foreign_key: true + end + + fk = @connection.foreign_keys("testing_parents").first + assert_equal "testing_parents", fk.from_table + assert_equal "testing", fk.to_table + + assert_difference "@connection.foreign_keys('testing_parents').size", -1 do + @connection.remove_reference :testing_parents, :testing, foreign_key: true + end + ensure + ActiveRecord::Base.pluralize_table_names = original_pluralize_table_names + @connection.drop_table "testing", if_exists: true end - ensure - ActiveRecord::Base.pluralize_table_names = original_pluralize_table_names - @connection.drop_table "testing", if_exists: true end - end - class CreateDogsMigration < ActiveRecord::Migration::Current - def change - create_table :dog_owners + class CreateDogsMigration < ActiveRecord::Migration::Current + def change + create_table :dog_owners - create_table :dogs do |t| - t.references :dog_owner, foreign_key: true + create_table :dogs do |t| + t.references :dog_owner, foreign_key: true + end end end - end - def test_references_foreign_key_with_prefix - ActiveRecord::Base.table_name_prefix = 'p_' - migration = CreateDogsMigration.new - silence_stream($stdout) { migration.migrate(:up) } - assert_equal 1, @connection.foreign_keys("p_dogs").size - ensure - silence_stream($stdout) { migration.migrate(:down) } - ActiveRecord::Base.table_name_prefix = nil - end + def test_references_foreign_key_with_prefix + ActiveRecord::Base.table_name_prefix = "p_" + migration = CreateDogsMigration.new + silence_stream($stdout) { migration.migrate(:up) } + assert_equal 1, @connection.foreign_keys("p_dogs").size + ensure + silence_stream($stdout) { migration.migrate(:down) } + ActiveRecord::Base.table_name_prefix = nil + end - def test_references_foreign_key_with_suffix - ActiveRecord::Base.table_name_suffix = '_s' - migration = CreateDogsMigration.new - silence_stream($stdout) { migration.migrate(:up) } - assert_equal 1, @connection.foreign_keys("dogs_s").size - ensure - silence_stream($stdout) { migration.migrate(:down) } - ActiveRecord::Base.table_name_suffix = nil - end + def test_references_foreign_key_with_suffix + ActiveRecord::Base.table_name_suffix = "_s" + migration = CreateDogsMigration.new + silence_stream($stdout) { migration.migrate(:up) } + assert_equal 1, @connection.foreign_keys("dogs_s").size + ensure + silence_stream($stdout) { migration.migrate(:down) } + ActiveRecord::Base.table_name_suffix = nil + end - test "multiple foreign keys can be added to the same table" do - @connection.create_table :testings do |t| - t.integer :col_1 - t.integer :col_2 + test "multiple foreign keys can be added to the same table" do + @connection.create_table :testings do |t| + t.integer :col_1 + t.integer :col_2 - t.foreign_key :testing_parents, column: :col_1 - t.foreign_key :testing_parents, column: :col_2 - end + t.foreign_key :testing_parents, column: :col_1 + t.foreign_key :testing_parents, column: :col_2 + end - fks = @connection.foreign_keys("testings") + fks = @connection.foreign_keys("testings") - fk_definitions = fks.map {|fk| [fk.from_table, fk.to_table, fk.column] } - assert_equal([["testings", "testing_parents", "col_1"], - ["testings", "testing_parents", "col_2"]], fk_definitions) + fk_definitions = fks.map { |fk| [fk.from_table, fk.to_table, fk.column] } + assert_equal([["testings", "testing_parents", "col_1"], + ["testings", "testing_parents", "col_2"]], fk_definitions) + end end end end -end else -class ReferencesWithoutForeignKeySupportTest < ActiveRecord::TestCase - setup do - @connection = ActiveRecord::Base.connection - @connection.create_table(:testing_parents, force: true) - end - - teardown do - @connection.drop_table("testings", if_exists: true) - @connection.drop_table("testing_parents", if_exists: true) - end + class ReferencesWithoutForeignKeySupportTest < ActiveRecord::TestCase + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table(:testing_parents, force: true) + end - test "ignores foreign keys defined with the table" do - @connection.create_table :testings do |t| - t.references :testing_parent, foreign_key: true + teardown do + @connection.drop_table("testings", if_exists: true) + @connection.drop_table("testing_parents", if_exists: true) end - assert_includes @connection.data_sources, "testings" + test "ignores foreign keys defined with the table" do + @connection.create_table :testings do |t| + t.references :testing_parent, foreign_key: true + end + + assert_includes @connection.data_sources, "testings" + end end end -end diff --git a/activerecord/test/cases/migration/references_index_test.rb b/activerecord/test/cases/migration/references_index_test.rb index a9a7f0f4c4..2866cabab6 100644 --- a/activerecord/test/cases/migration/references_index_test.rb +++ b/activerecord/test/cases/migration/references_index_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class Migration @@ -17,10 +17,10 @@ module ActiveRecord def test_creates_index connection.create_table table_name do |t| - t.references :foo, :index => true + t.references :foo, index: true end - assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id) + assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id) end def test_creates_index_by_default_even_if_index_option_is_not_passed @@ -28,31 +28,31 @@ module ActiveRecord t.references :foo end - assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id) + assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id) end def test_does_not_create_index_explicit connection.create_table table_name do |t| - t.references :foo, :index => false + t.references :foo, index: false end - assert_not connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id) + assert_not connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id) end def test_creates_index_with_options connection.create_table table_name do |t| - t.references :foo, :index => {:name => :index_testings_on_yo_momma} - t.references :bar, :index => {:unique => true} + t.references :foo, index: { name: :index_testings_on_yo_momma } + t.references :bar, index: { unique: true } end - assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_yo_momma) - assert connection.index_exists?(table_name, :bar_id, :name => :index_testings_on_bar_id, :unique => true) + assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_yo_momma) + assert connection.index_exists?(table_name, :bar_id, name: :index_testings_on_bar_id, unique: true) end unless current_adapter? :OracleAdapter def test_creates_polymorphic_index connection.create_table table_name do |t| - t.references :foo, :polymorphic => true, :index => true + t.references :foo, polymorphic: true, index: true end assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo_type_and_foo_id) @@ -62,10 +62,10 @@ module ActiveRecord def test_creates_index_for_existing_table connection.create_table table_name connection.change_table table_name do |t| - t.references :foo, :index => true + t.references :foo, index: true end - assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id) + assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id) end def test_creates_index_for_existing_table_even_if_index_option_is_not_passed @@ -74,23 +74,23 @@ module ActiveRecord t.references :foo end - assert connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id) + assert connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id) end def test_does_not_create_index_for_existing_table_explicit connection.create_table table_name connection.change_table table_name do |t| - t.references :foo, :index => false + t.references :foo, index: false end - assert_not connection.index_exists?(table_name, :foo_id, :name => :index_testings_on_foo_id) + assert_not connection.index_exists?(table_name, :foo_id, name: :index_testings_on_foo_id) end unless current_adapter? :OracleAdapter def test_creates_polymorphic_index_for_existing_table connection.create_table table_name connection.change_table table_name do |t| - t.references :foo, :polymorphic => true, :index => true + t.references :foo, polymorphic: true, index: true end assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo_type_and_foo_id) diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb index 70c64f3e71..8fbe60f24e 100644 --- a/activerecord/test/cases/migration/references_statements_test.rb +++ b/activerecord/test/cases/migration/references_statements_test.rb @@ -35,7 +35,7 @@ module ActiveRecord assert_not index_exists?(table_name, :user_id) end - def test_create_reference_id_index_even_if_index_option_is_passed + def test_create_reference_id_index_even_if_index_option_is_not_passed add_reference table_name, :user assert index_exists?(table_name, :user_id) end @@ -46,18 +46,18 @@ module ActiveRecord end def test_creates_reference_type_column_with_default - add_reference table_name, :taggable, polymorphic: { default: 'Photo' }, index: true - assert column_exists?(table_name, :taggable_type, :string, default: 'Photo') + add_reference table_name, :taggable, polymorphic: { default: "Photo" }, index: true + assert column_exists?(table_name, :taggable_type, :string, default: "Photo") end def test_creates_named_index - add_reference table_name, :tag, index: { name: 'index_taggings_on_tag_id' } - assert index_exists?(table_name, :tag_id, name: 'index_taggings_on_tag_id') + add_reference table_name, :tag, index: { name: "index_taggings_on_tag_id" } + assert index_exists?(table_name, :tag_id, name: "index_taggings_on_tag_id") end def test_creates_named_unique_index - add_reference table_name, :tag, index: { name: 'index_taggings_on_tag_id', unique: true } - assert index_exists?(table_name, :tag_id, name: 'index_taggings_on_tag_id', unique: true ) + add_reference table_name, :tag, index: { name: "index_taggings_on_tag_id", unique: true } + assert index_exists?(table_name, :tag_id, name: "index_taggings_on_tag_id", unique: true ) end def test_creates_reference_id_with_specified_type @@ -110,12 +110,12 @@ module ActiveRecord private - def with_polymorphic_column - add_column table_name, :supplier_type, :string - add_index table_name, [:supplier_id, :supplier_type] + def with_polymorphic_column + add_column table_name, :supplier_type, :string + add_index table_name, [:supplier_id, :supplier_type] - yield - end + yield + end end end end diff --git a/activerecord/test/cases/migration/rename_table_test.rb b/activerecord/test/cases/migration/rename_table_test.rb index b926a92849..fc4f700916 100644 --- a/activerecord/test/cases/migration/rename_table_test.rb +++ b/activerecord/test/cases/migration/rename_table_test.rb @@ -9,9 +9,9 @@ module ActiveRecord def setup super - add_column 'test_models', :url, :string - remove_column 'test_models', :created_at - remove_column 'test_models', :updated_at + add_column "test_models", :url, :string + remove_column "test_models", :created_at + remove_column "test_models", :updated_at end def teardown @@ -31,7 +31,7 @@ module ActiveRecord # Using explicit id in insert for compatibility across all databases connection.execute "INSERT INTO 'references' (url, created_at, updated_at) VALUES ('http://rubyonrails.com', 0, 0)" - assert_equal 'http://rubyonrails.com', connection.select_value("SELECT url FROM 'references' WHERE id=1") + assert_equal "http://rubyonrails.com", connection.select_value("SELECT url FROM 'references' WHERE id=1") ensure return unless renamed connection.rename_table :references, :test_models @@ -45,7 +45,7 @@ module ActiveRecord connection.execute "INSERT INTO octopi (#{connection.quote_column_name('id')}, #{connection.quote_column_name('url')}) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')" - assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', connection.select_value("SELECT url FROM octopi WHERE id=1") + assert_equal "http://www.foreverflying.com/octopus-black7.jpg", connection.select_value("SELECT url FROM octopi WHERE id=1") end def test_rename_table_with_an_index @@ -55,18 +55,18 @@ module ActiveRecord connection.execute "INSERT INTO octopi (#{connection.quote_column_name('id')}, #{connection.quote_column_name('url')}) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')" - assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', connection.select_value("SELECT url FROM octopi WHERE id=1") + assert_equal "http://www.foreverflying.com/octopus-black7.jpg", connection.select_value("SELECT url FROM octopi WHERE id=1") index = connection.indexes(:octopi).first - assert index.columns.include?("url") - assert_equal 'index_octopi_on_url', index.name + assert_includes index.columns, "url" + assert_equal "index_octopi_on_url", index.name end def test_rename_table_does_not_rename_custom_named_index - add_index :test_models, :url, name: 'special_url_idx' + add_index :test_models, :url, name: "special_url_idx" rename_table :test_models, :octopi - assert_equal ['special_url_idx'], connection.indexes(:octopi).map(&:name) + assert_equal ["special_url_idx"], connection.indexes(:octopi).map(&:name) end end @@ -74,7 +74,7 @@ module ActiveRecord def test_rename_table_for_postgresql_should_also_rename_default_sequence rename_table :test_models, :octopi - pk, seq = connection.pk_and_sequence_for('octopi') + pk, seq = connection.pk_and_sequence_for("octopi") assert_equal ConnectionAdapters::PostgreSQL::Name.new("public", "octopi_#{pk}_seq"), seq end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 36b6662820..151f3c8efd 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -1,12 +1,12 @@ -require 'cases/helper' -require 'cases/migration/helper' -require 'bigdecimal/util' -require 'concurrent/atomic/count_down_latch' +require "cases/helper" +require "cases/migration/helper" +require "bigdecimal/util" +require "concurrent/atomic/count_down_latch" -require 'models/person' -require 'models/topic' -require 'models/developer' -require 'models/computer' +require "models/person" +require "models/topic" +require "models/developer" +require "models/computer" require MIGRATIONS_ROOT + "/valid/2_we_need_reminders" require MIGRATIONS_ROOT + "/rename/1_we_need_things" @@ -59,7 +59,7 @@ class MigrationTest < ActiveRecord::TestCase %w(last_name key bio age height wealth birthday favorite_day moment_of_truth male administrator funny).each do |column| - Person.connection.remove_column('people', column) rescue nil + Person.connection.remove_column("people", column) rescue nil end Person.connection.remove_column("people", "first_name") rescue nil Person.connection.remove_column("people", "middle_name") rescue nil @@ -93,7 +93,7 @@ class MigrationTest < ActiveRecord::TestCase end def test_migration_detection_without_schema_migration_table - ActiveRecord::Base.connection.drop_table 'schema_migrations', if_exists: true + ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true migrations_path = MIGRATIONS_ROOT + "/valid" old_path = ActiveRecord::Migrator.migrations_paths @@ -128,7 +128,7 @@ class MigrationTest < ActiveRecord::TestCase assert_not_equal temp_conn, Person.connection - temp_conn.create_table :testings2, :force => true do |t| + temp_conn.create_table :testings2, force: true do |t| t.column :foo, :string end ensure @@ -160,11 +160,11 @@ class MigrationTest < ActiveRecord::TestCase BigNumber.reset_column_information assert BigNumber.create( - :bank_balance => 1586.43, - :big_bank_balance => BigDecimal("1000234000567.95"), - :world_population => 6000000000, - :my_house_population => 3, - :value_of_e => BigDecimal("2.7182818284590452353602875") + bank_balance: 1586.43, + big_bank_balance: BigDecimal("1000234000567.95"), + world_population: 6000000000, + my_house_population: 3, + value_of_e: BigDecimal("2.7182818284590452353602875") ) b = BigNumber.first @@ -248,22 +248,22 @@ class MigrationTest < ActiveRecord::TestCase def test_instance_based_migration_up migration = MockMigration.new - assert !migration.went_up, 'have not gone up' - assert !migration.went_down, 'have not gone down' + assert !migration.went_up, "have not gone up" + assert !migration.went_down, "have not gone down" migration.migrate :up - assert migration.went_up, 'have gone up' - assert !migration.went_down, 'have not gone down' + assert migration.went_up, "have gone up" + assert !migration.went_down, "have not gone down" end def test_instance_based_migration_down migration = MockMigration.new - assert !migration.went_up, 'have not gone up' - assert !migration.went_down, 'have not gone down' + assert !migration.went_up, "have not gone up" + assert !migration.went_down, "have not gone down" migration.migrate :down - assert !migration.went_up, 'have gone up' - assert migration.went_down, 'have not gone down' + assert !migration.went_up, "have gone up" + assert migration.went_down, "have not gone down" end if ActiveRecord::Base.connection.supports_ddl_transactions? @@ -274,7 +274,7 @@ class MigrationTest < ActiveRecord::TestCase def version; 100 end def migrate(x) add_column "people", "last_name", :string - raise 'Something broke' + raise "Something broke" end }.new @@ -295,7 +295,7 @@ class MigrationTest < ActiveRecord::TestCase def version; 100 end def migrate(x) add_column "people", "last_name", :string - raise 'Something broke' + raise "Something broke" end }.new @@ -313,12 +313,12 @@ class MigrationTest < ActiveRecord::TestCase assert_no_column Person, :last_name migration = Class.new(ActiveRecord::Migration::Current) { - self.disable_ddl_transaction! + disable_ddl_transaction! def version; 101 end def migrate(x) add_column "people", "last_name", :string - raise 'Something broke' + raise "Something broke" end }.new @@ -330,8 +330,8 @@ class MigrationTest < ActiveRecord::TestCase "without ddl transactions, the Migrator should not rollback on error but it did." ensure Person.reset_column_information - if Person.column_names.include?('last_name') - Person.connection.remove_column('people', 'last_name') + if Person.column_names.include?("last_name") + Person.connection.remove_column("people", "last_name") end end end @@ -401,7 +401,6 @@ class MigrationTest < ActiveRecord::TestCase ENV["RACK_ENV"] = original_rack_env end - def test_migration_sets_internal_metadata_even_when_fully_migrated current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call migrations_path = MIGRATIONS_ROOT + "/valid" @@ -430,7 +429,7 @@ class MigrationTest < ActiveRecord::TestCase def test_internal_metadata_stores_environment_when_other_data_exists ActiveRecord::InternalMetadata.delete_all - ActiveRecord::InternalMetadata[:foo] = 'bar' + ActiveRecord::InternalMetadata[:foo] = "bar" current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call migrations_path = MIGRATIONS_ROOT + "/valid" @@ -440,30 +439,15 @@ class MigrationTest < ActiveRecord::TestCase current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call ActiveRecord::Migrator.up(migrations_path) assert_equal current_env, ActiveRecord::InternalMetadata[:environment] - assert_equal 'bar', ActiveRecord::InternalMetadata[:foo] + assert_equal "bar", ActiveRecord::InternalMetadata[:foo] ensure ActiveRecord::Migrator.migrations_paths = old_path end - def test_rename_internal_metadata_table - original_internal_metadata_table_name = ActiveRecord::Base.internal_metadata_table_name - - ActiveRecord::Base.internal_metadata_table_name = "active_record_internal_metadatas" - Reminder.reset_table_name - - ActiveRecord::Base.internal_metadata_table_name = original_internal_metadata_table_name - Reminder.reset_table_name - - assert_equal "ar_internal_metadata", ActiveRecord::InternalMetadata.table_name - ensure - ActiveRecord::Base.internal_metadata_table_name = original_internal_metadata_table_name - Reminder.reset_table_name - end - def test_proper_table_name_on_migration reminder_class = new_isolated_reminder_class migration = ActiveRecord::Migration.new - assert_equal "table", migration.proper_table_name('table') + assert_equal "table", migration.proper_table_name("table") assert_equal "table", migration.proper_table_name(:table) assert_equal "reminders", migration.proper_table_name(reminder_class) reminder_class.reset_table_name @@ -472,26 +456,26 @@ class MigrationTest < ActiveRecord::TestCase # Use the model's own prefix/suffix if a model is given ActiveRecord::Base.table_name_prefix = "ARprefix_" ActiveRecord::Base.table_name_suffix = "_ARsuffix" - reminder_class.table_name_prefix = 'prefix_' - reminder_class.table_name_suffix = '_suffix' + reminder_class.table_name_prefix = "prefix_" + reminder_class.table_name_suffix = "_suffix" reminder_class.reset_table_name assert_equal "prefix_reminders_suffix", migration.proper_table_name(reminder_class) - reminder_class.table_name_prefix = '' - reminder_class.table_name_suffix = '' + reminder_class.table_name_prefix = "" + reminder_class.table_name_suffix = "" reminder_class.reset_table_name # Use AR::Base's prefix/suffix if string or symbol is given ActiveRecord::Base.table_name_prefix = "prefix_" ActiveRecord::Base.table_name_suffix = "_suffix" reminder_class.reset_table_name - assert_equal "prefix_table_suffix", migration.proper_table_name('table', migration.table_name_options) + assert_equal "prefix_table_suffix", migration.proper_table_name("table", migration.table_name_options) assert_equal "prefix_table_suffix", migration.proper_table_name(:table, migration.table_name_options) end def test_rename_table_with_prefix_and_suffix assert !Thing.table_exists? - ActiveRecord::Base.table_name_prefix = 'p_' - ActiveRecord::Base.table_name_suffix = '_s' + ActiveRecord::Base.table_name_prefix = "p_" + ActiveRecord::Base.table_name_suffix = "_s" Thing.reset_table_name Thing.reset_sequence_name WeNeedThings.up @@ -511,8 +495,8 @@ class MigrationTest < ActiveRecord::TestCase def test_add_drop_table_with_prefix_and_suffix assert !Reminder.table_exists? - ActiveRecord::Base.table_name_prefix = 'prefix_' - ActiveRecord::Base.table_name_suffix = '_suffix' + ActiveRecord::Base.table_name_prefix = "prefix_" + ActiveRecord::Base.table_name_suffix = "_suffix" Reminder.reset_table_name Reminder.reset_sequence_name Reminder.reset_column_information @@ -529,7 +513,7 @@ class MigrationTest < ActiveRecord::TestCase def test_create_table_with_binary_column assert_nothing_raised { Person.connection.create_table :binary_testings do |t| - t.column "data", :binary, :null => false + t.column "data", :binary, null: false end } @@ -567,6 +551,23 @@ class MigrationTest < ActiveRecord::TestCase end end + if current_adapter?(:SQLite3Adapter) + def test_allows_sqlite3_rollback_on_invalid_column_type + Person.connection.create_table :something, force: true do |t| + t.column :number, :integer + t.column :name, :string + t.column :foo, :bar + end + assert Person.connection.column_exists?(:something, :foo) + assert_nothing_raised { Person.connection.remove_column :something, :foo, :bar } + assert !Person.connection.column_exists?(:something, :foo) + assert Person.connection.column_exists?(:something, :name) + assert Person.connection.column_exists?(:something, :number) + ensure + Person.connection.drop_table :something, if_exists: true + end + end + if current_adapter? :OracleAdapter def test_create_table_with_custom_sequence_name # table name is 29 chars, the standard sequence name will @@ -574,7 +575,7 @@ class MigrationTest < ActiveRecord::TestCase assert_nothing_raised do begin Person.connection.create_table :table_with_name_thats_just_ok do |t| - t.column :foo, :string, :null => false + t.column :foo, :string, null: false end ensure Person.connection.drop_table :table_with_name_thats_just_ok rescue nil @@ -585,15 +586,15 @@ class MigrationTest < ActiveRecord::TestCase assert_nothing_raised do begin Person.connection.create_table :table_with_name_thats_just_ok, - :sequence_name => 'suitably_short_seq' do |t| - t.column :foo, :string, :null => false + sequence_name: "suitably_short_seq" do |t| + t.column :foo, :string, null: false end Person.connection.execute("select suitably_short_seq.nextval from dual") ensure Person.connection.drop_table :table_with_name_thats_just_ok, - :sequence_name => 'suitably_short_seq' rescue nil + sequence_name: "suitably_short_seq" rescue nil end end @@ -607,8 +608,8 @@ class MigrationTest < ActiveRecord::TestCase if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter) def test_out_of_range_integer_limit_should_raise e = assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do - Person.connection.create_table :test_integer_limits, :force => true do |t| - t.column :bigone, :integer, :limit => 10 + Person.connection.create_table :test_integer_limits, force: true do |t| + t.column :bigone, :integer, limit: 10 end end @@ -742,13 +743,13 @@ end class ReservedWordsMigrationTest < ActiveRecord::TestCase def test_drop_index_from_table_named_values connection = Person.connection - connection.create_table :values, :force => true do |t| + connection.create_table :values, force: true do |t| t.integer :value end assert_nothing_raised do connection.add_index :values, :value - connection.remove_index :values, :column => :value + connection.remove_index :values, column: :value end ensure connection.drop_table :values rescue nil @@ -763,8 +764,8 @@ class ExplicitlyNamedIndexMigrationTest < ActiveRecord::TestCase end assert_nothing_raised do - connection.add_index :values, :value, name: 'a_different_name' - connection.remove_index :values, column: :value, name: 'a_different_name' + connection.add_index :values, :value, name: "a_different_name" + connection.remove_index :values, column: :value, name: "a_different_name" end ensure connection.drop_table :values rescue nil @@ -775,7 +776,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? class BulkAlterTableMigrationsTest < ActiveRecord::TestCase def setup @connection = Person.connection - @connection.create_table(:delete_me, :force => true) {|t| } + @connection.create_table(:delete_me, force: true) { |t| } Person.reset_column_information Person.reset_sequence_name end @@ -789,15 +790,15 @@ if ActiveRecord::Base.connection.supports_bulk_alter? with_bulk_change_table do |t| t.column :name, :string t.string :qualification, :experience - t.integer :age, :default => 0 + t.integer :age, default: 0 t.date :birthdate t.timestamps null: true end end assert_equal 8, columns.size - [:name, :qualification, :experience].each {|s| assert_equal :string, column(s).type } - assert_equal '0', column(:age).default + [:name, :qualification, :experience].each { |s| assert_equal :string, column(s).type } + assert_equal "0", column(:age).default end def test_removing_columns @@ -805,7 +806,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? t.string :qualification, :experience end - [:qualification, :experience].each {|c| assert column(c) } + [:qualification, :experience].each { |c| assert column(c) } assert_queries(1) do with_bulk_change_table do |t| @@ -814,7 +815,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? end end - [:qualification, :experience].each {|c| assert ! column(c) } + [:qualification, :experience].each { |c| assert ! column(c) } assert column(:qualification_experience) end @@ -828,7 +829,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? # Adding an index fires a query every time to check if an index already exists or not assert_queries(3) do with_bulk_change_table do |t| - t.index :username, :unique => true, :name => :awesome_username_index + t.index :username, unique: true, name: :awesome_username_index t.index [:name, :age] end end @@ -836,7 +837,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? assert_equal 2, indexes.size name_age_index = index(:index_delete_me_on_name_and_age) - assert_equal ['name', 'age'].sort, name_age_index.columns.sort + assert_equal ["name", "age"].sort, name_age_index.columns.sort assert ! name_age_index.unique assert index(:awesome_username_index).unique @@ -853,7 +854,7 @@ if ActiveRecord::Base.connection.supports_bulk_alter? assert_queries(3) do with_bulk_change_table do |t| t.remove_index :name - t.index :name, :name => :new_name_index, :unique => true + t.index :name, name: :new_name_index, unique: true end end @@ -875,43 +876,43 @@ if ActiveRecord::Base.connection.supports_bulk_alter? # One query for columns (delete_me table) # One query for primary key (delete_me table) # One query to do the bulk change - assert_queries(3, :ignore_none => true) do + assert_queries(3, ignore_none: true) do with_bulk_change_table do |t| - t.change :name, :string, :default => 'NONAME' + t.change :name, :string, default: "NONAME" t.change :birthdate, :datetime end end - assert_equal 'NONAME', column(:name).default + assert_equal "NONAME", column(:name).default assert_equal :datetime, column(:birthdate).type end protected - def with_bulk_change_table - # Reset columns/indexes cache as we're changing the table - @columns = @indexes = nil + def with_bulk_change_table + # Reset columns/indexes cache as we're changing the table + @columns = @indexes = nil - Person.connection.change_table(:delete_me, :bulk => true) do |t| - yield t + Person.connection.change_table(:delete_me, bulk: true) do |t| + yield t + end end - end - def column(name) - columns.detect {|c| c.name == name.to_s } - end + def column(name) + columns.detect { |c| c.name == name.to_s } + end - def columns - @columns ||= Person.connection.columns('delete_me') - end + def columns + @columns ||= Person.connection.columns("delete_me") + end - def index(name) - indexes.detect {|i| i.name == name.to_s } - end + def index(name) + indexes.detect { |i| i.name == name.to_s } + end - def indexes - @indexes ||= Person.connection.indexes('delete_me') - end + def indexes + @indexes ||= Person.connection.indexes("delete_me") + end end # AlterTableMigrationsTest end @@ -933,7 +934,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase @migrations_path = MIGRATIONS_ROOT + "/valid" @existing_migrations = Dir[@migrations_path + "/*.rb"] - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy") assert File.exist?(@migrations_path + "/4_people_have_hobbies.bukkits.rb") assert File.exist?(@migrations_path + "/5_people_have_descriptions.bukkits.rb") assert_equal [@migrations_path + "/4_people_have_hobbies.bukkits.rb", @migrations_path + "/5_people_have_descriptions.bukkits.rb"], copied.map(&:filename) @@ -942,7 +943,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase assert_equal expected, IO.readlines(@migrations_path + "/4_people_have_hobbies.bukkits.rb")[0].chomp files_count = Dir[@migrations_path + "/*.rb"].length - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy") assert_equal files_count, Dir[@migrations_path + "/*.rb"].length assert copied.empty? ensure @@ -975,7 +976,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase @existing_migrations = Dir[@migrations_path + "/*.rb"] travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps") assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb") assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb") expected = [@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb", @@ -983,7 +984,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase assert_equal expected, copied.map(&:filename) files_count = Dir[@migrations_path + "/*.rb"].length - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps") assert_equal files_count, Dir[@migrations_path + "/*.rb"].length assert copied.empty? end @@ -1020,12 +1021,12 @@ class CopyMigrationsTest < ActiveRecord::TestCase @existing_migrations = Dir[@migrations_path + "/*.rb"] travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do - ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"}) + ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps") assert File.exist?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb") assert File.exist?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb") files_count = Dir[@migrations_path + "/*.rb"].length - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps") assert_equal files_count, Dir[@migrations_path + "/*.rb"].length assert copied.empty? end @@ -1038,7 +1039,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase @migrations_path = MIGRATIONS_ROOT + "/valid" @existing_migrations = Dir[@migrations_path + "/*.rb"] - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/magic"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/magic") assert File.exist?(@migrations_path + "/4_currencies_have_symbols.bukkits.rb") assert_equal [@migrations_path + "/4_currencies_have_symbols.bukkits.rb"], copied.map(&:filename) @@ -1046,7 +1047,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase assert_equal expected, IO.readlines(@migrations_path + "/4_currencies_have_symbols.bukkits.rb")[0..1].join.chomp files_count = Dir[@migrations_path + "/*.rb"].length - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/magic"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/magic") assert_equal files_count, Dir[@migrations_path + "/*.rb"].length assert copied.empty? ensure @@ -1063,7 +1064,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase skipped = [] on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" } - copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip) + copied = ActiveRecord::Migration.copy(@migrations_path, sources, on_skip: on_skip) assert_equal 2, copied.length assert_equal 1, skipped.length @@ -1081,8 +1082,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase skipped = [] on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" } - copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip) - ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip) + copied = ActiveRecord::Migration.copy(@migrations_path, sources, on_skip: on_skip) + ActiveRecord::Migration.copy(@migrations_path, sources, on_skip: on_skip) assert_equal 2, copied.length assert_equal 0, skipped.length @@ -1095,7 +1096,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase @existing_migrations = [] travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps") assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb") assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb") assert_equal 2, copied.length @@ -1110,7 +1111,7 @@ class CopyMigrationsTest < ActiveRecord::TestCase @existing_migrations = [] travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do - copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"}) + copied = ActiveRecord::Migration.copy(@migrations_path, bukkits: MIGRATIONS_ROOT + "/to_copy_with_timestamps") assert File.exist?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb") assert File.exist?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb") assert_equal 2, copied.length diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb index 86eca53141..1ba18bc9c2 100644 --- a/activerecord/test/cases/migrator_test.rb +++ b/activerecord/test/cases/migrator_test.rb @@ -9,7 +9,7 @@ class MigratorTest < ActiveRecord::TestCase class Sensor < ActiveRecord::Migration::Current attr_reader :went_up, :went_down - def initialize name = self.class.name, version = nil + def initialize(name = self.class.name, version = nil) super @went_up = false @went_down = false @@ -46,21 +46,21 @@ class MigratorTest < ActiveRecord::TestCase def test_migrator_with_duplicate_names assert_raises(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do - list = [ActiveRecord::Migration.new('Chunky'), ActiveRecord::Migration.new('Chunky')] + list = [ActiveRecord::Migration.new("Chunky"), ActiveRecord::Migration.new("Chunky")] ActiveRecord::Migrator.new(:up, list) end end def test_migrator_with_duplicate_versions assert_raises(ActiveRecord::DuplicateMigrationVersionError) do - list = [ActiveRecord::Migration.new('Foo', 1), ActiveRecord::Migration.new('Bar', 1)] + list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 1)] ActiveRecord::Migrator.new(:up, list) end end def test_migrator_with_missing_version_numbers assert_raises(ActiveRecord::UnknownMigrationVersionError) do - list = [ActiveRecord::Migration.new('Foo', 1), ActiveRecord::Migration.new('Bar', 2)] + list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)] ActiveRecord::Migrator.new(:up, list, 3).run end end @@ -68,7 +68,7 @@ class MigratorTest < ActiveRecord::TestCase def test_finds_migrations migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid") - [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i| + [[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i| assert_equal migrations[i].version, pair.first assert_equal migrations[i].name, pair.last end @@ -77,14 +77,14 @@ class MigratorTest < ActiveRecord::TestCase def test_finds_migrations_in_subdirectories migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid_with_subdirectories") - [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i| + [[1, "ValidPeopleHaveLastNames"], [2, "WeNeedReminders"], [3, "InnocentJointable"]].each_with_index do |pair, i| assert_equal migrations[i].version, pair.first assert_equal migrations[i].name, pair.last end end def test_finds_migrations_from_two_directories - directories = [MIGRATIONS_ROOT + '/valid_with_timestamps', MIGRATIONS_ROOT + '/to_copy_with_timestamps'] + directories = [MIGRATIONS_ROOT + "/valid_with_timestamps", MIGRATIONS_ROOT + "/to_copy_with_timestamps"] migrations = ActiveRecord::Migrator.migrations directories [[20090101010101, "PeopleHaveHobbies"], @@ -92,15 +92,15 @@ class MigratorTest < ActiveRecord::TestCase [20100101010101, "ValidWithTimestampsPeopleHaveLastNames"], [20100201010101, "ValidWithTimestampsWeNeedReminders"], [20100301010101, "ValidWithTimestampsInnocentJointable"]].each_with_index do |pair, i| - assert_equal pair.first, migrations[i].version - assert_equal pair.last, migrations[i].name + assert_equal pair.first, migrations[i].version + assert_equal pair.last, migrations[i].name end end def test_finds_migrations_in_numbered_directory - migrations = ActiveRecord::Migrator.migrations [MIGRATIONS_ROOT + '/10_urban'] + migrations = ActiveRecord::Migrator.migrations [MIGRATIONS_ROOT + "/10_urban"] assert_equal 9, migrations[0].version - assert_equal 'AddExpressions', migrations[0].name + assert_equal "AddExpressions", migrations[0].name end def test_relative_migrations @@ -109,14 +109,14 @@ class MigratorTest < ActiveRecord::TestCase end migration_proxy = list.find { |item| - item.name == 'ValidPeopleHaveLastNames' + item.name == "ValidPeopleHaveLastNames" } - assert migration_proxy, 'should find pending migration' + assert migration_proxy, "should find pending migration" end def test_finds_pending_migrations - ActiveRecord::SchemaMigration.create!(:version => '1') - migration_list = [ActiveRecord::Migration.new('foo', 1), ActiveRecord::Migration.new('bar', 3)] + ActiveRecord::SchemaMigration.create!(version: "1") + migration_list = [ActiveRecord::Migration.new("foo", 1), ActiveRecord::Migration.new("bar", 3)] migrations = ActiveRecord::Migrator.new(:up, migration_list).pending_migrations assert_equal 1, migrations.size @@ -124,21 +124,21 @@ class MigratorTest < ActiveRecord::TestCase end def test_migrator_interleaved_migrations - pass_one = [Sensor.new('One', 1)] + pass_one = [Sensor.new("One", 1)] ActiveRecord::Migrator.new(:up, pass_one).migrate assert pass_one.first.went_up assert_not pass_one.first.went_down - pass_two = [Sensor.new('One', 1), Sensor.new('Three', 3)] + pass_two = [Sensor.new("One", 1), Sensor.new("Three", 3)] ActiveRecord::Migrator.new(:up, pass_two).migrate assert_not pass_two[0].went_up assert pass_two[1].went_up assert pass_two.all? { |x| !x.went_down } - pass_three = [Sensor.new('One', 1), - Sensor.new('Two', 2), - Sensor.new('Three', 3)] + pass_three = [Sensor.new("One", 1), + Sensor.new("Two", 2), + Sensor.new("Three", 3)] ActiveRecord::Migrator.new(:down, pass_three).migrate assert pass_three[0].went_down @@ -165,7 +165,7 @@ class MigratorTest < ActiveRecord::TestCase end def test_current_version - ActiveRecord::SchemaMigration.create!(:version => '1000') + ActiveRecord::SchemaMigration.create!(version: "1000") assert_equal 1000, ActiveRecord::Migrator.current_version end @@ -313,9 +313,9 @@ class MigratorTest < ActiveRecord::TestCase _, migrator = migrator_class(3) ActiveRecord::Base.connection.drop_table "schema_migrations", if_exists: true - ActiveSupport::Deprecation.silence { assert_not ActiveRecord::Base.connection.table_exists?('schema_migrations') } + ActiveSupport::Deprecation.silence { assert_not ActiveRecord::Base.connection.table_exists?("schema_migrations") } migrator.migrate("valid", 1) - ActiveSupport::Deprecation.silence { assert ActiveRecord::Base.connection.table_exists?('schema_migrations') } + ActiveSupport::Deprecation.silence { assert ActiveRecord::Base.connection.table_exists?("schema_migrations") } end def test_migrator_forward @@ -332,7 +332,7 @@ class MigratorTest < ActiveRecord::TestCase def test_only_loads_pending_migrations # migrate up to 1 - ActiveRecord::SchemaMigration.create!(:version => '1') + ActiveRecord::SchemaMigration.create!(version: "1") calls, migrator = migrator_class(3) migrator.migrate("valid", nil) @@ -357,32 +357,32 @@ class MigratorTest < ActiveRecord::TestCase end private - def m(name, version) - x = Sensor.new name, version - x.extend(Module.new { - define_method(:up) { yield(:up, x); super() } - define_method(:down) { yield(:down, x); super() } - }) if block_given? - end + def m(name, version) + x = Sensor.new name, version + x.extend(Module.new { + define_method(:up) { yield(:up, x); super() } + define_method(:down) { yield(:down, x); super() } + }) if block_given? + end - def sensors(count) - calls = [] - migrations = count.times.map { |i| - m(nil, i + 1) { |c,migration| - calls << [c, migration.version] + def sensors(count) + calls = [] + migrations = count.times.map { |i| + m(nil, i + 1) { |c,migration| + calls << [c, migration.version] + } } - } - [calls, migrations] - end + [calls, migrations] + end - def migrator_class(count) - calls, migrations = sensors(count) + def migrator_class(count) + calls, migrations = sensors(count) - migrator = Class.new(ActiveRecord::Migrator).extend(Module.new { - define_method(:migrations) { |paths| - migrations - } - }) - [calls, migrator] - end + migrator = Class.new(ActiveRecord::Migrator).extend(Module.new { + define_method(:migrations) { |paths| + migrations + } + }) + [calls, migrator] + end end diff --git a/activerecord/test/cases/mixin_test.rb b/activerecord/test/cases/mixin_test.rb index 7ebdcac711..a8af8e30f7 100644 --- a/activerecord/test/cases/mixin_test.rb +++ b/activerecord/test/cases/mixin_test.rb @@ -41,13 +41,12 @@ class TouchTest < ActiveRecord::TestCase old_updated_at = stamped.updated_at - travel 5.minutes do - stamped.lft_will_change! - stamped.save + travel 5.minutes + stamped.lft_will_change! + stamped.save - assert_equal Time.now, stamped.updated_at - assert_equal old_updated_at, stamped.created_at - end + assert_equal Time.now, stamped.updated_at + assert_equal old_updated_at, stamped.created_at end def test_create_turned_off @@ -64,5 +63,4 @@ class TouchTest < ActiveRecord::TestCase ensure Mixin.record_timestamps = true end - end diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb index 486bcc22df..f8a7bab35f 100644 --- a/activerecord/test/cases/modules_test.rb +++ b/activerecord/test/cases/modules_test.rb @@ -1,8 +1,8 @@ require "cases/helper" -require 'models/company_in_module' -require 'models/shop' -require 'models/developer' -require 'models/computer' +require "models/company_in_module" +require "models/shop" +require "models/developer" +require "models/computer" class ModulesTest < ActiveRecord::TestCase fixtures :accounts, :companies, :projects, :developers, :collections, :products, :variants @@ -31,7 +31,7 @@ class ModulesTest < ActiveRecord::TestCase def test_module_spanning_associations firm = MyApplication::Business::Firm.first assert !firm.clients.empty?, "Firm should have clients" - assert_nil firm.class.table_name.match('::'), "Firm shouldn't have the module appear in its table name" + assert_nil firm.class.table_name.match("::"), "Firm shouldn't have the module appear in its table name" end def test_module_spanning_has_and_belongs_to_many_associations @@ -41,7 +41,7 @@ class ModulesTest < ActiveRecord::TestCase end def test_associations_spanning_cross_modules - account = MyApplication::Billing::Account.all.merge!(:order => 'id').first + account = MyApplication::Billing::Account.all.merge!(order: "id").first assert_kind_of MyApplication::Business::Firm, account.firm assert_kind_of MyApplication::Billing::Firm, account.qualified_billing_firm assert_kind_of MyApplication::Billing::Firm, account.unqualified_billing_firm @@ -50,14 +50,14 @@ class ModulesTest < ActiveRecord::TestCase end def test_find_account_and_include_company - account = MyApplication::Billing::Account.all.merge!(:includes => :firm).find(1) + account = MyApplication::Billing::Account.all.merge!(includes: :firm).find(1) assert_kind_of MyApplication::Business::Firm, account.firm end def test_table_name - assert_equal 'accounts', MyApplication::Billing::Account.table_name, 'table_name for ActiveRecord model in module' - assert_equal 'companies', MyApplication::Business::Client.table_name, 'table_name for ActiveRecord model subclass' - assert_equal 'company_contacts', MyApplication::Business::Client::Contact.table_name, 'table_name for ActiveRecord model enclosed by another ActiveRecord model' + assert_equal "accounts", MyApplication::Billing::Account.table_name, "table_name for ActiveRecord model in module" + assert_equal "companies", MyApplication::Business::Client.table_name, "table_name for ActiveRecord model subclass" + assert_equal "company_contacts", MyApplication::Business::Client::Contact.table_name, "table_name for ActiveRecord model enclosed by another ActiveRecord model" end def test_assign_ids @@ -73,8 +73,8 @@ class ModulesTest < ActiveRecord::TestCase clients = [] assert_nothing_raised do - clients << MyApplication::Business::Client.references(:accounts).merge!(:includes => {:firm => :account}, :where => 'accounts.id IS NOT NULL').find(3) - clients << MyApplication::Business::Client.includes(:firm => :account).find(3) + clients << MyApplication::Business::Client.references(:accounts).merge!(includes: { firm: :account }, where: "accounts.id IS NOT NULL").find(3) + clients << MyApplication::Business::Client.includes(firm: :account).find(3) end clients.each do |client| @@ -85,9 +85,9 @@ class ModulesTest < ActiveRecord::TestCase end def test_module_table_name_prefix - assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Company.table_name, 'inferred table_name for ActiveRecord model in module with table_name_prefix' - assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Nested::Company.table_name, 'table_name for ActiveRecord model in nested module with a parent table_name_prefix' - assert_equal 'companies', MyApplication::Business::Prefixed::Firm.table_name, 'explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed' + assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_prefix" + assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_prefix" + assert_equal "companies", MyApplication::Business::Prefixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed" end def test_module_table_name_prefix_with_global_prefix @@ -101,21 +101,21 @@ class ModulesTest < ActiveRecord::TestCase MyApplication::Business::Prefixed::Nested::Company, MyApplication::Billing::Account ] - ActiveRecord::Base.table_name_prefix = 'global_' + ActiveRecord::Base.table_name_prefix = "global_" classes.each(&:reset_table_name) - assert_equal 'global_companies', MyApplication::Business::Company.table_name, 'inferred table_name for ActiveRecord model in module without table_name_prefix' - assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Company.table_name, 'inferred table_name for ActiveRecord model in module with table_name_prefix' - assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Nested::Company.table_name, 'table_name for ActiveRecord model in nested module with a parent table_name_prefix' - assert_equal 'companies', MyApplication::Business::Prefixed::Firm.table_name, 'explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed' + assert_equal "global_companies", MyApplication::Business::Company.table_name, "inferred table_name for ActiveRecord model in module without table_name_prefix" + assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_prefix" + assert_equal "prefixed_companies", MyApplication::Business::Prefixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_prefix" + assert_equal "companies", MyApplication::Business::Prefixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed" ensure - ActiveRecord::Base.table_name_prefix = '' + ActiveRecord::Base.table_name_prefix = "" classes.each(&:reset_table_name) end def test_module_table_name_suffix - assert_equal 'companies_suffixed', MyApplication::Business::Suffixed::Company.table_name, 'inferred table_name for ActiveRecord model in module with table_name_suffix' - assert_equal 'companies_suffixed', MyApplication::Business::Suffixed::Nested::Company.table_name, 'table_name for ActiveRecord model in nested module with a parent table_name_suffix' - assert_equal 'companies', MyApplication::Business::Suffixed::Firm.table_name, 'explicit table_name for ActiveRecord model in module with table_name_suffix should not be suffixed' + assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_suffix" + assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_suffix" + assert_equal "companies", MyApplication::Business::Suffixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_suffix should not be suffixed" end def test_module_table_name_suffix_with_global_suffix @@ -129,14 +129,14 @@ class ModulesTest < ActiveRecord::TestCase MyApplication::Business::Suffixed::Nested::Company, MyApplication::Billing::Account ] - ActiveRecord::Base.table_name_suffix = '_global' + ActiveRecord::Base.table_name_suffix = "_global" classes.each(&:reset_table_name) - assert_equal 'companies_global', MyApplication::Business::Company.table_name, 'inferred table_name for ActiveRecord model in module without table_name_suffix' - assert_equal 'companies_suffixed', MyApplication::Business::Suffixed::Company.table_name, 'inferred table_name for ActiveRecord model in module with table_name_suffix' - assert_equal 'companies_suffixed', MyApplication::Business::Suffixed::Nested::Company.table_name, 'table_name for ActiveRecord model in nested module with a parent table_name_suffix' - assert_equal 'companies', MyApplication::Business::Suffixed::Firm.table_name, 'explicit table_name for ActiveRecord model in module with table_name_suffix should not be suffixed' + assert_equal "companies_global", MyApplication::Business::Company.table_name, "inferred table_name for ActiveRecord model in module without table_name_suffix" + assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Company.table_name, "inferred table_name for ActiveRecord model in module with table_name_suffix" + assert_equal "companies_suffixed", MyApplication::Business::Suffixed::Nested::Company.table_name, "table_name for ActiveRecord model in nested module with a parent table_name_suffix" + assert_equal "companies", MyApplication::Business::Suffixed::Firm.table_name, "explicit table_name for ActiveRecord model in module with table_name_suffix should not be suffixed" ensure - ActiveRecord::Base.table_name_suffix = '' + ActiveRecord::Base.table_name_suffix = "" classes.each(&:reset_table_name) end diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb index d05cb22740..b2f76398df 100644 --- a/activerecord/test/cases/multiparameter_attributes_test.rb +++ b/activerecord/test/cases/multiparameter_attributes_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'models/topic' -require 'models/customer' +require "models/topic" +require "models/customer" class MultiParameterAttributeTest < ActiveRecord::TestCase fixtures :topics @@ -202,6 +202,20 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase Topic.reset_column_information end + def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes_and_invalid_time_params + with_timezone_config aware_attributes: true do + Topic.reset_column_information + attributes = { + "written_on(1i)" => "2004", "written_on(2i)" => "", "written_on(3i)" => "" + } + topic = Topic.find(1) + topic.attributes = attributes + assert_nil topic.written_on + end + ensure + Topic.reset_column_information + end + def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes_false with_timezone_config default: :local, aware_attributes: false, zone: -28800 do attributes = { diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb index a4fbf579a1..e3bb51bd77 100644 --- a/activerecord/test/cases/multiple_db_test.rb +++ b/activerecord/test/cases/multiple_db_test.rb @@ -1,7 +1,7 @@ require "cases/helper" -require 'models/entrant' -require 'models/bird' -require 'models/course' +require "models/entrant" +require "models/bird" +require "models/course" class MultipleDbTest < ActiveRecord::TestCase self.use_transactional_tests = false @@ -60,7 +60,7 @@ class MultipleDbTest < ActiveRecord::TestCase ActiveSupport::Dependencies.clear Object.send(:remove_const, :Course) - require_dependency 'models/course' + require_dependency "models/course" assert Course.connection end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 11fb164d50..a9c3733c20 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -9,11 +9,11 @@ require "models/man" require "models/interest" require "models/owner" require "models/pet" -require 'active_support/hash_with_indifferent_access' +require "active_support/hash_with_indifferent_access" class TestNestedAttributesInGeneral < ActiveRecord::TestCase teardown do - Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc(&:empty?) + Pirate.accepts_nested_attributes_for :ship, allow_destroy: true, reject_if: proc(&:empty?) end def test_base_should_have_an_empty_nested_attributes_options @@ -30,28 +30,28 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase end def test_should_not_build_a_new_record_using_reject_all_even_if_destroy_is_given - pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") - pirate.birds_with_reject_all_blank_attributes = [{:name => '', :color => '', :_destroy => '0'}] + pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + pirate.birds_with_reject_all_blank_attributes = [{ name: "", color: "", _destroy: "0" }] pirate.save! assert pirate.birds_with_reject_all_blank.empty? end def test_should_not_build_a_new_record_if_reject_all_blank_returns_false - pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") - pirate.birds_with_reject_all_blank_attributes = [{:name => '', :color => ''}] + pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + pirate.birds_with_reject_all_blank_attributes = [{ name: "", color: "" }] pirate.save! assert pirate.birds_with_reject_all_blank.empty? end def test_should_build_a_new_record_if_reject_all_blank_does_not_return_false - pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") - pirate.birds_with_reject_all_blank_attributes = [{:name => 'Tweetie', :color => ''}] + pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + pirate.birds_with_reject_all_blank_attributes = [{ name: "Tweetie", color: "" }] pirate.save! assert_equal 1, pirate.birds_with_reject_all_blank.count - assert_equal 'Tweetie', pirate.birds_with_reject_all_blank.first.name + assert_equal "Tweetie", pirate.birds_with_reject_all_blank.first.name end def test_should_raise_an_ArgumentError_for_non_existing_associations @@ -63,7 +63,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase def test_should_raise_an_UnknownAttributeError_for_non_existing_nested_attributes exception = assert_raise ActiveModel::UnknownAttributeError do - Pirate.new(:ship_attributes => { :sail => true }) + Pirate.new(ship_attributes: { sail: true }) end assert_equal "unknown attribute 'sail' for Ship.", exception.message end @@ -72,84 +72,84 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase Pirate.accepts_nested_attributes_for :ship pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") - ship = pirate.create_ship(name: 'Nights Dirty Lightning') + ship = pirate.create_ship(name: "Nights Dirty Lightning") - pirate.update(ship_attributes: { '_destroy' => true, :id => ship.id }) + pirate.update(ship_attributes: { "_destroy" => true, :id => ship.id }) assert_nothing_raised { pirate.ship.reload } end def test_a_model_should_respond_to_underscore_destroy_and_return_if_it_is_marked_for_destruction - ship = Ship.create!(:name => 'Nights Dirty Lightning') + ship = Ship.create!(name: "Nights Dirty Lightning") assert !ship._destroy ship.mark_for_destruction assert ship._destroy end def test_reject_if_method_without_arguments - Pirate.accepts_nested_attributes_for :ship, :reject_if => :new_record? + Pirate.accepts_nested_attributes_for :ship, reject_if: :new_record? - pirate = Pirate.new(:catchphrase => "Stop wastin' me time") - pirate.ship_attributes = { :name => 'Black Pearl' } - assert_no_difference('Ship.count') { pirate.save! } + pirate = Pirate.new(catchphrase: "Stop wastin' me time") + pirate.ship_attributes = { name: "Black Pearl" } + assert_no_difference("Ship.count") { pirate.save! } end def test_reject_if_method_with_arguments - Pirate.accepts_nested_attributes_for :ship, :reject_if => :reject_empty_ships_on_create + Pirate.accepts_nested_attributes_for :ship, reject_if: :reject_empty_ships_on_create - pirate = Pirate.new(:catchphrase => "Stop wastin' me time") - pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true } - assert_no_difference('Ship.count') { pirate.save! } + pirate = Pirate.new(catchphrase: "Stop wastin' me time") + pirate.ship_attributes = { name: "Red Pearl", _reject_me_if_new: true } + assert_no_difference("Ship.count") { pirate.save! } # pirate.reject_empty_ships_on_create returns false for saved pirate records # in the previous step note that pirate gets saved but ship fails - pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true } - assert_difference('Ship.count') { pirate.save! } + pirate.ship_attributes = { name: "Red Pearl", _reject_me_if_new: true } + assert_difference("Ship.count") { pirate.save! } end def test_reject_if_with_indifferent_keys - Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:name].blank? } + Pirate.accepts_nested_attributes_for :ship, reject_if: proc { |attributes| attributes[:name].blank? } - pirate = Pirate.new(:catchphrase => "Stop wastin' me time") - pirate.ship_attributes = { :name => 'Hello Pearl' } - assert_difference('Ship.count') { pirate.save! } + pirate = Pirate.new(catchphrase: "Stop wastin' me time") + pirate.ship_attributes = { name: "Hello Pearl" } + assert_difference("Ship.count") { pirate.save! } end def test_reject_if_with_a_proc_which_returns_true_always_for_has_one - Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| true } + Pirate.accepts_nested_attributes_for :ship, reject_if: proc { |attributes| true } pirate = Pirate.new(catchphrase: "Stop wastin' me time") - ship = pirate.create_ship(name: 's1') - pirate.update({ship_attributes: { name: 's2', id: ship.id } }) - assert_equal 's1', ship.reload.name + ship = pirate.create_ship(name: "s1") + pirate.update(ship_attributes: { name: "s2", id: ship.id }) + assert_equal "s1", ship.reload.name end def test_reuse_already_built_new_record pirate = Pirate.new ship_built_first = pirate.build_ship - pirate.ship_attributes = { name: 'Ship 1' } + pirate.ship_attributes = { name: "Ship 1" } assert_equal ship_built_first.object_id, pirate.ship.object_id end def test_do_not_allow_assigning_foreign_key_when_reusing_existing_new_record pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") pirate.build_ship - pirate.ship_attributes = { name: 'Ship 1', pirate_id: pirate.id + 1 } + pirate.ship_attributes = { name: "Ship 1", pirate_id: pirate.id + 1 } assert_equal pirate.id, pirate.ship.pirate_id end def test_reject_if_with_a_proc_which_returns_true_always_for_has_many - Man.accepts_nested_attributes_for :interests, :reject_if => proc {|attributes| true } + Man.accepts_nested_attributes_for :interests, reject_if: proc { |attributes| true } man = Man.create(name: "John") - interest = man.interests.create(topic: 'photography') - man.update({interests_attributes: { topic: 'gardening', id: interest.id } }) - assert_equal 'photography', interest.reload.topic + interest = man.interests.create(topic: "photography") + man.update(interests_attributes: { topic: "gardening", id: interest.id }) + assert_equal "photography", interest.reload.topic end def test_destroy_works_independent_of_reject_if - Man.accepts_nested_attributes_for :interests, :reject_if => proc {|attributes| true }, :allow_destroy => true + Man.accepts_nested_attributes_for :interests, reject_if: proc { |attributes| true }, allow_destroy: true man = Man.create(name: "Jon") - interest = man.interests.create(topic: 'the ladies') - man.update({interests_attributes: { _destroy: "1", id: interest.id } }) + interest = man.interests.create(topic: "the ladies") + man.update(interests_attributes: { _destroy: "1", id: interest.id }) assert man.reload.interests.empty? end @@ -168,27 +168,27 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase def test_has_many_association_updating_a_single_record Man.accepts_nested_attributes_for(:interests) - man = Man.create(name: 'John') - interest = man.interests.create(topic: 'photography') - man.update({interests_attributes: {topic: 'gardening', id: interest.id}}) - assert_equal 'gardening', interest.reload.topic + man = Man.create(name: "John") + interest = man.interests.create(topic: "photography") + man.update(interests_attributes: { topic: "gardening", id: interest.id }) + assert_equal "gardening", interest.reload.topic end def test_reject_if_with_blank_nested_attributes_id # When using a select list to choose an existing 'ship' id, with include_blank: true - Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:id].blank? } + Pirate.accepts_nested_attributes_for :ship, reject_if: proc { |attributes| attributes[:id].blank? } - pirate = Pirate.new(:catchphrase => "Stop wastin' me time") - pirate.ship_attributes = { :id => "" } + pirate = Pirate.new(catchphrase: "Stop wastin' me time") + pirate.ship_attributes = { id: "" } assert_nothing_raised { pirate.save! } end def test_first_and_array_index_zero_methods_return_the_same_value_when_nested_attributes_are_set_to_update_existing_record Man.accepts_nested_attributes_for(:interests) - man = Man.create(:name => "John") - interest = man.interests.create :topic => 'gardening' + man = Man.create(name: "John") + interest = man.interests.create topic: "gardening" man = Man.find man.id - man.interests_attributes = [{:id => interest.id, :topic => 'gardening'}] + man.interests_attributes = [{ id: interest.id, topic: "gardening" }] assert_equal man.interests.first.topic, man.interests[0].topic end @@ -196,11 +196,11 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase mean_pirate_class = Class.new(Pirate) do accepts_nested_attributes_for :parrot def parrot_attributes=(attrs) - super(attrs.merge(:color => "blue")) + super(attrs.merge(color: "blue")) end end mean_pirate = mean_pirate_class.new - mean_pirate.parrot_attributes = { :name => "James" } + mean_pirate.parrot_attributes = { name: "James" } assert_equal "James", mean_pirate.parrot.name assert_equal "blue", mean_pirate.parrot.color end @@ -212,20 +212,20 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase accepts_nested_attributes_for :parrot end mean_pirate = mean_pirate_class.new - mean_pirate.parrot_attributes = { :name => "James" } + mean_pirate.parrot_attributes = { name: "James" } assert_equal "James", mean_pirate.parrot.name end end class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def setup - @pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @ship = @pirate.create_ship(:name => 'Nights Dirty Lightning') + @pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + @ship = @pirate.create_ship(name: "Nights Dirty Lightning") end def test_should_raise_argument_error_if_trying_to_build_polymorphic_belongs_to exception = assert_raise ArgumentError do - Treasure.new(:name => 'pearl', :looter_attributes => {:catchphrase => "Arrr"}) + Treasure.new(name: "pearl", looter_attributes: { catchphrase: "Arrr" }) end assert_equal "Cannot build association `looter'. Are you trying to build a polymorphic one-to-one association?", exception.message end @@ -236,15 +236,15 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def test_should_build_a_new_record_if_there_is_no_id @ship.destroy - @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' } + @pirate.reload.ship_attributes = { name: "Davy Jones Gold Dagger" } assert !@pirate.ship.persisted? - assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name + assert_equal "Davy Jones Gold Dagger", @pirate.ship.name end def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy @ship.destroy - @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' } + @pirate.reload.ship_attributes = { name: "Davy Jones Gold Dagger", _destroy: "1" } assert_nil @pirate.ship end @@ -257,54 +257,54 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_replace_an_existing_record_if_there_is_no_id - @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' } + @pirate.reload.ship_attributes = { name: "Davy Jones Gold Dagger" } assert !@pirate.ship.persisted? - assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name - assert_equal 'Nights Dirty Lightning', @ship.name + assert_equal "Davy Jones Gold Dagger", @pirate.ship.name + assert_equal "Nights Dirty Lightning", @ship.name end def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy - @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger', :_destroy => '1' } + @pirate.reload.ship_attributes = { name: "Davy Jones Gold Dagger", _destroy: "1" } assert_equal @ship, @pirate.ship - assert_equal 'Nights Dirty Lightning', @pirate.ship.name + assert_equal "Nights Dirty Lightning", @pirate.ship.name end def test_should_modify_an_existing_record_if_there_is_a_matching_id - @pirate.reload.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' } + @pirate.reload.ship_attributes = { id: @ship.id, name: "Davy Jones Gold Dagger" } assert_equal @ship, @pirate.ship - assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name + assert_equal "Davy Jones Gold Dagger", @pirate.ship.name end def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record exception = assert_raise ActiveRecord::RecordNotFound do - @pirate.ship_attributes = { :id => 1234567890 } + @pirate.ship_attributes = { id: 1234567890 } end assert_equal "Couldn't find Ship with ID=1234567890 for Pirate with ID=#{@pirate.id}", exception.message end def test_should_take_a_hash_with_string_keys_and_update_the_associated_model - @pirate.reload.ship_attributes = { 'id' => @ship.id, 'name' => 'Davy Jones Gold Dagger' } + @pirate.reload.ship_attributes = { "id" => @ship.id, "name" => "Davy Jones Gold Dagger" } assert_equal @ship, @pirate.ship - assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name + assert_equal "Davy Jones Gold Dagger", @pirate.ship.name end def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id - @ship.stub(:id, 'ABC1X') do - @pirate.ship_attributes = { :id => @ship.id, :name => 'Davy Jones Gold Dagger' } + @ship.stub(:id, "ABC1X") do + @pirate.ship_attributes = { id: @ship.id, name: "Davy Jones Gold Dagger" } - assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name + assert_equal "Davy Jones Gold Dagger", @pirate.ship.name end end def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy @pirate.ship.destroy - [1, '1', true, 'true'].each do |truth| - ship = @pirate.reload.create_ship(name: 'Mister Pablo') + [1, "1", true, "true"].each do |truth| + ship = @pirate.reload.create_ship(name: "Mister Pablo") @pirate.update(ship_attributes: { id: ship.id, _destroy: truth }) assert_nil @pirate.reload.ship @@ -313,7 +313,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy - [nil, '0', 0, 'false', false].each do |not_truth| + [nil, "0", 0, "false", false].each do |not_truth| @pirate.update(ship_attributes: { id: @pirate.ship.id, _destroy: not_truth }) assert_equal @ship, @pirate.reload.ship @@ -321,32 +321,32 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false - Pirate.accepts_nested_attributes_for :ship, :allow_destroy => false, :reject_if => proc(&:empty?) + Pirate.accepts_nested_attributes_for :ship, allow_destroy: false, reject_if: proc(&:empty?) - @pirate.update(ship_attributes: { id: @pirate.ship.id, _destroy: '1' }) + @pirate.update(ship_attributes: { id: @pirate.ship.id, _destroy: "1" }) assert_equal @ship, @pirate.reload.ship - Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc(&:empty?) + Pirate.accepts_nested_attributes_for :ship, allow_destroy: true, reject_if: proc(&:empty?) end def test_should_also_work_with_a_HashWithIndifferentAccess - @pirate.ship_attributes = ActiveSupport::HashWithIndifferentAccess.new(:id => @ship.id, :name => 'Davy Jones Gold Dagger') + @pirate.ship_attributes = ActiveSupport::HashWithIndifferentAccess.new(id: @ship.id, name: "Davy Jones Gold Dagger") assert @pirate.ship.persisted? - assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name + assert_equal "Davy Jones Gold Dagger", @pirate.ship.name end def test_should_work_with_update_as_well - @pirate.update({ catchphrase: 'Arr', ship_attributes: { id: @ship.id, name: 'Mister Pablo' } }) + @pirate.update(catchphrase: "Arr", ship_attributes: { id: @ship.id, name: "Mister Pablo" }) @pirate.reload - assert_equal 'Arr', @pirate.catchphrase - assert_equal 'Mister Pablo', @pirate.ship.name + assert_equal "Arr", @pirate.catchphrase + assert_equal "Mister Pablo", @pirate.ship.name end def test_should_not_destroy_the_associated_model_until_the_parent_is_saved - @pirate.attributes = { :ship_attributes => { :id => @ship.id, :_destroy => '1' } } + @pirate.attributes = { ship_attributes: { id: @ship.id, _destroy: "1" } } assert !@pirate.ship.destroyed? assert @pirate.ship.marked_for_destruction? @@ -362,56 +362,55 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase end def test_should_accept_update_only_option - @pirate.update(update_only_ship_attributes: { id: @pirate.ship.id, name: 'Mayflower' }) + @pirate.update(update_only_ship_attributes: { id: @pirate.ship.id, name: "Mayflower" }) end def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true @ship.delete - @pirate.reload.update(update_only_ship_attributes: { name: 'Mayflower' }) + @pirate.reload.update(update_only_ship_attributes: { name: "Mayflower" }) assert_not_nil @pirate.ship end def test_should_update_existing_when_update_only_is_true_and_no_id_is_given @ship.delete - @ship = @pirate.create_update_only_ship(name: 'Nights Dirty Lightning') + @ship = @pirate.create_update_only_ship(name: "Nights Dirty Lightning") - @pirate.update(update_only_ship_attributes: { name: 'Mayflower' }) + @pirate.update(update_only_ship_attributes: { name: "Mayflower" }) - assert_equal 'Mayflower', @ship.reload.name + assert_equal "Mayflower", @ship.reload.name assert_equal @ship, @pirate.reload.ship end def test_should_update_existing_when_update_only_is_true_and_id_is_given @ship.delete - @ship = @pirate.create_update_only_ship(name: 'Nights Dirty Lightning') + @ship = @pirate.create_update_only_ship(name: "Nights Dirty Lightning") - @pirate.update(update_only_ship_attributes: { name: 'Mayflower', id: @ship.id }) + @pirate.update(update_only_ship_attributes: { name: "Mayflower", id: @ship.id }) - assert_equal 'Mayflower', @ship.reload.name + assert_equal "Mayflower", @ship.reload.name assert_equal @ship, @pirate.reload.ship end def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction - Pirate.accepts_nested_attributes_for :update_only_ship, :update_only => true, :allow_destroy => true + Pirate.accepts_nested_attributes_for :update_only_ship, update_only: true, allow_destroy: true @ship.delete - @ship = @pirate.create_update_only_ship(name: 'Nights Dirty Lightning') + @ship = @pirate.create_update_only_ship(name: "Nights Dirty Lightning") - @pirate.update(update_only_ship_attributes: { name: 'Mayflower', id: @ship.id, _destroy: true }) + @pirate.update(update_only_ship_attributes: { name: "Mayflower", id: @ship.id, _destroy: true }) assert_nil @pirate.reload.ship assert_raise(ActiveRecord::RecordNotFound) { Ship.find(@ship.id) } - Pirate.accepts_nested_attributes_for :update_only_ship, :update_only => true, :allow_destroy => false + Pirate.accepts_nested_attributes_for :update_only_ship, update_only: true, allow_destroy: false end - end class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase def setup - @ship = Ship.new(:name => 'Nights Dirty Lightning') - @pirate = @ship.build_pirate(:catchphrase => 'Aye') + @ship = Ship.new(name: "Nights Dirty Lightning") + @pirate = @ship.build_pirate(catchphrase: "Aye") @ship.save! end @@ -421,15 +420,15 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase def test_should_build_a_new_record_if_there_is_no_id @pirate.destroy - @ship.reload.pirate_attributes = { :catchphrase => 'Arr' } + @ship.reload.pirate_attributes = { catchphrase: "Arr" } assert !@ship.pirate.persisted? - assert_equal 'Arr', @ship.pirate.catchphrase + assert_equal "Arr", @ship.pirate.catchphrase end def test_should_not_build_a_new_record_if_there_is_no_id_and_destroy_is_truthy @pirate.destroy - @ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' } + @ship.reload.pirate_attributes = { catchphrase: "Arr", _destroy: "1" } assert_nil @ship.pirate end @@ -442,53 +441,53 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase end def test_should_replace_an_existing_record_if_there_is_no_id - @ship.reload.pirate_attributes = { :catchphrase => 'Arr' } + @ship.reload.pirate_attributes = { catchphrase: "Arr" } assert !@ship.pirate.persisted? - assert_equal 'Arr', @ship.pirate.catchphrase - assert_equal 'Aye', @pirate.catchphrase + assert_equal "Arr", @ship.pirate.catchphrase + assert_equal "Aye", @pirate.catchphrase end def test_should_not_replace_an_existing_record_if_there_is_no_id_and_destroy_is_truthy - @ship.reload.pirate_attributes = { :catchphrase => 'Arr', :_destroy => '1' } + @ship.reload.pirate_attributes = { catchphrase: "Arr", _destroy: "1" } assert_equal @pirate, @ship.pirate - assert_equal 'Aye', @ship.pirate.catchphrase + assert_equal "Aye", @ship.pirate.catchphrase end def test_should_modify_an_existing_record_if_there_is_a_matching_id - @ship.reload.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' } + @ship.reload.pirate_attributes = { id: @pirate.id, catchphrase: "Arr" } assert_equal @pirate, @ship.pirate - assert_equal 'Arr', @ship.pirate.catchphrase + assert_equal "Arr", @ship.pirate.catchphrase end def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record exception = assert_raise ActiveRecord::RecordNotFound do - @ship.pirate_attributes = { :id => 1234567890 } + @ship.pirate_attributes = { id: 1234567890 } end assert_equal "Couldn't find Pirate with ID=1234567890 for Ship with ID=#{@ship.id}", exception.message end def test_should_take_a_hash_with_string_keys_and_update_the_associated_model - @ship.reload.pirate_attributes = { 'id' => @pirate.id, 'catchphrase' => 'Arr' } + @ship.reload.pirate_attributes = { "id" => @pirate.id, "catchphrase" => "Arr" } assert_equal @pirate, @ship.pirate - assert_equal 'Arr', @ship.pirate.catchphrase + assert_equal "Arr", @ship.pirate.catchphrase end def test_should_modify_an_existing_record_if_there_is_a_matching_composite_id - @pirate.stub(:id, 'ABC1X') do - @ship.pirate_attributes = { :id => @pirate.id, :catchphrase => 'Arr' } + @pirate.stub(:id, "ABC1X") do + @ship.pirate_attributes = { id: @pirate.id, catchphrase: "Arr" } - assert_equal 'Arr', @ship.pirate.catchphrase + assert_equal "Arr", @ship.pirate.catchphrase end end def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy @ship.pirate.destroy - [1, '1', true, 'true'].each do |truth| - pirate = @ship.reload.create_pirate(catchphrase: 'Arr') + [1, "1", true, "true"].each do |truth| + pirate = @ship.reload.create_pirate(catchphrase: "Arr") @ship.update(pirate_attributes: { id: pirate.id, _destroy: truth }) assert_raise(ActiveRecord::RecordNotFound) { pirate.reload } end @@ -509,33 +508,33 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase end def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy - [nil, '0', 0, 'false', false].each do |not_truth| + [nil, "0", 0, "false", false].each do |not_truth| @ship.update(pirate_attributes: { id: @ship.pirate.id, _destroy: not_truth }) assert_nothing_raised { @ship.pirate.reload } end end def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false - Ship.accepts_nested_attributes_for :pirate, :allow_destroy => false, :reject_if => proc(&:empty?) + Ship.accepts_nested_attributes_for :pirate, allow_destroy: false, reject_if: proc(&:empty?) - @ship.update(pirate_attributes: { id: @ship.pirate.id, _destroy: '1' }) + @ship.update(pirate_attributes: { id: @ship.pirate.id, _destroy: "1" }) assert_nothing_raised { @ship.pirate.reload } ensure - Ship.accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc(&:empty?) + Ship.accepts_nested_attributes_for :pirate, allow_destroy: true, reject_if: proc(&:empty?) end def test_should_work_with_update_as_well - @ship.update({ name: 'Mister Pablo', pirate_attributes: { catchphrase: 'Arr' } }) + @ship.update(name: "Mister Pablo", pirate_attributes: { catchphrase: "Arr" }) @ship.reload - assert_equal 'Mister Pablo', @ship.name - assert_equal 'Arr', @ship.pirate.catchphrase + assert_equal "Mister Pablo", @ship.name + assert_equal "Arr", @ship.pirate.catchphrase end def test_should_not_destroy_the_associated_model_until_the_parent_is_saved pirate = @ship.pirate - @ship.attributes = { :pirate_attributes => { :id => pirate.id, '_destroy' => true } } + @ship.attributes = { pirate_attributes: { :id => pirate.id, "_destroy" => true } } assert_nothing_raised { Pirate.find(pirate.id) } @ship.save assert_raise(ActiveRecord::RecordNotFound) { Pirate.find(pirate.id) } @@ -547,40 +546,40 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true @pirate.delete - @ship.reload.attributes = { :update_only_pirate_attributes => { :catchphrase => 'Arr' } } + @ship.reload.attributes = { update_only_pirate_attributes: { catchphrase: "Arr" } } assert !@ship.update_only_pirate.persisted? end def test_should_update_existing_when_update_only_is_true_and_no_id_is_given @pirate.delete - @pirate = @ship.create_update_only_pirate(catchphrase: 'Aye') + @pirate = @ship.create_update_only_pirate(catchphrase: "Aye") - @ship.update(update_only_pirate_attributes: { catchphrase: 'Arr' }) - assert_equal 'Arr', @pirate.reload.catchphrase + @ship.update(update_only_pirate_attributes: { catchphrase: "Arr" }) + assert_equal "Arr", @pirate.reload.catchphrase assert_equal @pirate, @ship.reload.update_only_pirate end def test_should_update_existing_when_update_only_is_true_and_id_is_given @pirate.delete - @pirate = @ship.create_update_only_pirate(catchphrase: 'Aye') + @pirate = @ship.create_update_only_pirate(catchphrase: "Aye") - @ship.update(update_only_pirate_attributes: { catchphrase: 'Arr', id: @pirate.id }) + @ship.update(update_only_pirate_attributes: { catchphrase: "Arr", id: @pirate.id }) - assert_equal 'Arr', @pirate.reload.catchphrase + assert_equal "Arr", @pirate.reload.catchphrase assert_equal @pirate, @ship.reload.update_only_pirate end def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction - Ship.accepts_nested_attributes_for :update_only_pirate, :update_only => true, :allow_destroy => true + Ship.accepts_nested_attributes_for :update_only_pirate, update_only: true, allow_destroy: true @pirate.delete - @pirate = @ship.create_update_only_pirate(catchphrase: 'Aye') + @pirate = @ship.create_update_only_pirate(catchphrase: "Aye") - @ship.update(update_only_pirate_attributes: { catchphrase: 'Arr', id: @pirate.id, _destroy: true }) + @ship.update(update_only_pirate_attributes: { catchphrase: "Arr", id: @pirate.id, _destroy: true }) assert_raise(ActiveRecord::RecordNotFound) { @pirate.reload } - Ship.accepts_nested_attributes_for :update_only_pirate, :update_only => true, :allow_destroy => false + Ship.accepts_nested_attributes_for :update_only_pirate, update_only: true, allow_destroy: false end end @@ -597,10 +596,9 @@ module NestedAttributesOnACollectionAssociationTests end def test_should_save_only_one_association_on_create - pirate = Pirate.create!({ - :catchphrase => 'Arr', - association_getter => { 'foo' => { :name => 'Grace OMalley' } } - }) + pirate = Pirate.create!( + :catchphrase => "Arr", + association_getter => { "foo" => { name: "Grace OMalley" } }) assert_equal 1, pirate.reload.send(@association_name).count end @@ -608,90 +606,90 @@ module NestedAttributesOnACollectionAssociationTests def test_should_take_a_hash_with_string_keys_and_assign_the_attributes_to_the_associated_models @alternate_params[association_getter].stringify_keys! @pirate.update @alternate_params - assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name] + assert_equal ["Grace OMalley", "Privateers Greed"], [@child_1.reload.name, @child_2.reload.name] end def test_should_take_an_array_and_assign_the_attributes_to_the_associated_models @pirate.send(association_setter, @alternate_params[association_getter].values) @pirate.save - assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.reload.name, @child_2.reload.name] + assert_equal ["Grace OMalley", "Privateers Greed"], [@child_1.reload.name, @child_2.reload.name] end def test_should_also_work_with_a_HashWithIndifferentAccess - @pirate.send(association_setter, ActiveSupport::HashWithIndifferentAccess.new('foo' => ActiveSupport::HashWithIndifferentAccess.new(:id => @child_1.id, :name => 'Grace OMalley'))) + @pirate.send(association_setter, ActiveSupport::HashWithIndifferentAccess.new("foo" => ActiveSupport::HashWithIndifferentAccess.new(id: @child_1.id, name: "Grace OMalley"))) @pirate.save - assert_equal 'Grace OMalley', @child_1.reload.name + assert_equal "Grace OMalley", @child_1.reload.name end def test_should_take_a_hash_and_assign_the_attributes_to_the_associated_models @pirate.attributes = @alternate_params - assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name - assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name + assert_equal "Grace OMalley", @pirate.send(@association_name).first.name + assert_equal "Privateers Greed", @pirate.send(@association_name).last.name end def test_should_not_load_association_when_updating_existing_records @pirate.reload - @pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }]) + @pirate.send(association_setter, [{ id: @child_1.id, name: "Grace OMalley" }]) assert ! @pirate.send(@association_name).loaded? @pirate.save assert ! @pirate.send(@association_name).loaded? - assert_equal 'Grace OMalley', @child_1.reload.name + assert_equal "Grace OMalley", @child_1.reload.name end def test_should_not_overwrite_unsaved_updates_when_loading_association @pirate.reload - @pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }]) - assert_equal 'Grace OMalley', @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.name + @pirate.send(association_setter, [{ id: @child_1.id, name: "Grace OMalley" }]) + assert_equal "Grace OMalley", @pirate.send(@association_name).load_target.find { |r| r.id == @child_1.id }.name end def test_should_preserve_order_when_not_overwriting_unsaved_updates @pirate.reload - @pirate.send(association_setter, [{ :id => @child_1.id, :name => 'Grace OMalley' }]) - assert_equal @child_1.id, @pirate.send(@association_name).send(:load_target).first.id + @pirate.send(association_setter, [{ id: @child_1.id, name: "Grace OMalley" }]) + assert_equal @child_1.id, @pirate.send(@association_name).load_target.first.id end def test_should_refresh_saved_records_when_not_overwriting_unsaved_updates @pirate.reload - record = @pirate.class.reflect_on_association(@association_name).klass.new(name: 'Grace OMalley') + record = @pirate.class.reflect_on_association(@association_name).klass.new(name: "Grace OMalley") @pirate.send(@association_name) << record record.save! - @pirate.send(@association_name).last.update!(name: 'Polly') - assert_equal 'Polly', @pirate.send(@association_name).send(:load_target).last.name + @pirate.send(@association_name).last.update!(name: "Polly") + assert_equal "Polly", @pirate.send(@association_name).load_target.last.name end def test_should_not_remove_scheduled_destroys_when_loading_association @pirate.reload - @pirate.send(association_setter, [{ :id => @child_1.id, :_destroy => '1' }]) - assert @pirate.send(@association_name).send(:load_target).find { |r| r.id == @child_1.id }.marked_for_destruction? + @pirate.send(association_setter, [{ id: @child_1.id, _destroy: "1" }]) + assert @pirate.send(@association_name).load_target.find { |r| r.id == @child_1.id }.marked_for_destruction? end def test_should_take_a_hash_with_composite_id_keys_and_assign_the_attributes_to_the_associated_models - @child_1.stub(:id, 'ABC1X') do - @child_2.stub(:id, 'ABC2X') do + @child_1.stub(:id, "ABC1X") do + @child_2.stub(:id, "ABC2X") do @pirate.attributes = { association_getter => [ - { :id => @child_1.id, :name => 'Grace OMalley' }, - { :id => @child_2.id, :name => 'Privateers Greed' } + { id: @child_1.id, name: "Grace OMalley" }, + { id: @child_2.id, name: "Privateers Greed" } ] } - assert_equal ['Grace OMalley', 'Privateers Greed'], [@child_1.name, @child_2.name] + assert_equal ["Grace OMalley", "Privateers Greed"], [@child_1.name, @child_2.name] end end end def test_should_raise_RecordNotFound_if_an_id_is_given_but_doesnt_return_a_record exception = assert_raise ActiveRecord::RecordNotFound do - @pirate.attributes = { association_getter => [{ :id => 1234567890 }] } + @pirate.attributes = { association_getter => [{ id: 1234567890 }] } end assert_equal "Couldn't find #{@child_1.class.name} with ID=1234567890 for Pirate with ID=#{@pirate.id}", exception.message end def test_should_raise_RecordNotFound_if_an_id_belonging_to_a_different_record_is_given - other_pirate = Pirate.create! catchphrase: 'Ahoy!' - other_child = other_pirate.send(@association_name).create! name: 'Buccaneers Servant' + other_pirate = Pirate.create! catchphrase: "Ahoy!" + other_child = other_pirate.send(@association_name).create! name: "Buccaneers Servant" exception = assert_raise ActiveRecord::RecordNotFound do @pirate.attributes = { association_getter => [{ id: other_child.id }] } @@ -702,19 +700,19 @@ module NestedAttributesOnACollectionAssociationTests def test_should_automatically_build_new_associated_models_for_each_entry_in_a_hash_where_the_id_is_missing @pirate.send(@association_name).destroy_all @pirate.reload.attributes = { - association_getter => { 'foo' => { :name => 'Grace OMalley' }, 'bar' => { :name => 'Privateers Greed' }} + association_getter => { "foo" => { name: "Grace OMalley" }, "bar" => { name: "Privateers Greed" } } } assert !@pirate.send(@association_name).first.persisted? - assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name + assert_equal "Grace OMalley", @pirate.send(@association_name).first.name assert !@pirate.send(@association_name).last.persisted? - assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name + assert_equal "Privateers Greed", @pirate.send(@association_name).last.name end def test_should_not_assign_destroy_key_to_a_record assert_nothing_raised do - @pirate.send(association_setter, { 'foo' => { '_destroy' => '0' }}) + @pirate.send(association_setter, "foo" => { "_destroy" => "0" }) end end @@ -722,17 +720,17 @@ module NestedAttributesOnACollectionAssociationTests @pirate.send(@association_name).destroy_all @pirate.reload.attributes = { association_getter => { - 'foo' => { :name => 'Grace OMalley' }, - 'bar' => { :name => 'Privateers Greed', '_destroy' => '1' } + "foo" => { name: "Grace OMalley" }, + "bar" => { :name => "Privateers Greed", "_destroy" => "1" } } } assert_equal 1, @pirate.send(@association_name).length - assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name + assert_equal "Grace OMalley", @pirate.send(@association_name).first.name end def test_should_ignore_new_associated_records_if_a_reject_if_proc_returns_false - @alternate_params[association_getter]['baz'] = {} + @alternate_params[association_getter]["baz"] = {} assert_no_difference("@pirate.send(@association_name).count") do @pirate.attributes = @alternate_params end @@ -740,11 +738,11 @@ module NestedAttributesOnACollectionAssociationTests def test_should_sort_the_hash_by_the_keys_before_building_new_associated_models attributes = {} - attributes['123726353'] = { :name => 'Grace OMalley' } - attributes['2'] = { :name => 'Privateers Greed' } # 2 is lower then 123726353 + attributes["123726353"] = { name: "Grace OMalley" } + attributes["2"] = { name: "Privateers Greed" } # 2 is lower then 123726353 @pirate.send(association_setter, attributes) - assert_equal ['Posideons Killer', 'Killer bandita Dionne', 'Privateers Greed', 'Grace OMalley'].to_set, @pirate.send(@association_name).map(&:name).to_set + assert_equal ["Posideons Killer", "Killer bandita Dionne", "Privateers Greed", "Grace OMalley"].to_set, @pirate.send(@association_name).map(&:name).to_set end def test_should_raise_an_argument_error_if_something_else_than_a_hash_is_passed @@ -758,47 +756,47 @@ module NestedAttributesOnACollectionAssociationTests end def test_should_work_with_update_as_well - @pirate.update(catchphrase: 'Arr', - association_getter => { 'foo' => { :id => @child_1.id, :name => 'Grace OMalley' }}) + @pirate.update(catchphrase: "Arr", + association_getter => { "foo" => { id: @child_1.id, name: "Grace OMalley" } }) - assert_equal 'Grace OMalley', @child_1.reload.name + assert_equal "Grace OMalley", @child_1.reload.name end def test_should_update_existing_records_and_add_new_ones_that_have_no_id - @alternate_params[association_getter]['baz'] = { name: 'Buccaneers Servant' } - assert_difference('@pirate.send(@association_name).count', +1) do + @alternate_params[association_getter]["baz"] = { name: "Buccaneers Servant" } + assert_difference("@pirate.send(@association_name).count", +1) do @pirate.update @alternate_params end - assert_equal ['Grace OMalley', 'Privateers Greed', 'Buccaneers Servant'].to_set, @pirate.reload.send(@association_name).map(&:name).to_set + assert_equal ["Grace OMalley", "Privateers Greed", "Buccaneers Servant"].to_set, @pirate.reload.send(@association_name).map(&:name).to_set end def test_should_be_possible_to_destroy_a_record - ['1', 1, 'true', true].each do |true_variable| - record = @pirate.reload.send(@association_name).create!(:name => 'Grace OMalley') + ["1", 1, "true", true].each do |true_variable| + record = @pirate.reload.send(@association_name).create!(name: "Grace OMalley") @pirate.send(association_setter, - @alternate_params[association_getter].merge('baz' => { :id => record.id, '_destroy' => true_variable }) + @alternate_params[association_getter].merge("baz" => { :id => record.id, "_destroy" => true_variable }) ) - assert_difference('@pirate.send(@association_name).count', -1) do + assert_difference("@pirate.send(@association_name).count", -1) do @pirate.save end end end def test_should_not_destroy_the_associated_model_with_a_non_truthy_argument - [nil, '', '0', 0, 'false', false].each do |false_variable| - @alternate_params[association_getter]['foo']['_destroy'] = false_variable - assert_no_difference('@pirate.send(@association_name).count') do + [nil, "", "0", 0, "false", false].each do |false_variable| + @alternate_params[association_getter]["foo"]["_destroy"] = false_variable + assert_no_difference("@pirate.send(@association_name).count") do @pirate.update(@alternate_params) end end end def test_should_not_destroy_the_associated_model_until_the_parent_is_saved - assert_no_difference('@pirate.send(@association_name).count') do - @pirate.send(association_setter, @alternate_params[association_getter].merge('baz' => { :id => @child_1.id, '_destroy' => true })) + assert_no_difference("@pirate.send(@association_name).count") do + @pirate.send(association_setter, @alternate_params[association_getter].merge("baz" => { :id => @child_1.id, "_destroy" => true })) end - assert_difference('@pirate.send(@association_name).count', -1) { @pirate.save } + assert_difference("@pirate.send(@association_name).count", -1) { @pirate.save } end def test_should_automatically_enable_autosave_on_the_association @@ -812,10 +810,10 @@ module NestedAttributesOnACollectionAssociationTests repair_validations(Interest) do Interest.validates_presence_of(:man) - assert_difference 'Man.count' do - assert_difference 'Interest.count', 2 do - man = Man.create!(:name => 'John', - :interests_attributes => [{:topic=>'Cars'}, {:topic=>'Sports'}]) + assert_difference "Man.count" do + assert_difference "Interest.count", 2 do + man = Man.create!(name: "John", + interests_attributes: [{ topic: "Cars" }, { topic: "Sports" }]) assert_equal 2, man.interests.count end end @@ -823,7 +821,7 @@ module NestedAttributesOnACollectionAssociationTests end def test_can_use_symbols_as_object_identifier - @pirate.attributes = { :parrots_attributes => { :foo => { :name => 'Lovely Day' }, :bar => { :name => 'Blown Away' } } } + @pirate.attributes = { parrots_attributes: { foo: { name: "Lovely Day" }, bar: { name: "Blown Away" } } } assert_nothing_raised { @pirate.save! } end @@ -832,22 +830,22 @@ module NestedAttributesOnACollectionAssociationTests repair_validations(Interest) do Interest.validates_numericality_of(:zine_id) - man = Man.create(name: 'John') - interest = man.interests.create(topic: 'bar', zine_id: 0) + man = Man.create(name: "John") + interest = man.interests.create(topic: "bar", zine_id: 0) assert interest.save - assert !man.update({interests_attributes: { id: interest.id, zine_id: 'foo' }}) + assert !man.update(interests_attributes: { id: interest.id, zine_id: "foo" }) end end private - def association_setter - @association_setter ||= "#{@association_name}_attributes=".to_sym - end + def association_setter + @association_setter ||= "#{@association_name}_attributes=".to_sym + end - def association_getter - @association_getter ||= "#{@association_name}_attributes".to_sym - end + def association_getter + @association_getter ||= "#{@association_name}_attributes".to_sym + end end class TestNestedAttributesOnAHasManyAssociation < ActiveRecord::TestCase @@ -855,16 +853,16 @@ class TestNestedAttributesOnAHasManyAssociation < ActiveRecord::TestCase @association_type = :has_many @association_name = :birds - @pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @pirate.birds.create!(:name => 'Posideons Killer') - @pirate.birds.create!(:name => 'Killer bandita Dionne') + @pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + @pirate.birds.create!(name: "Posideons Killer") + @pirate.birds.create!(name: "Killer bandita Dionne") @child_1, @child_2 = @pirate.birds @alternate_params = { - :birds_attributes => { - 'foo' => { :id => @child_1.id, :name => 'Grace OMalley' }, - 'bar' => { :id => @child_2.id, :name => 'Privateers Greed' } + birds_attributes: { + "foo" => { id: @child_1.id, name: "Grace OMalley" }, + "bar" => { id: @child_2.id, name: "Privateers Greed" } } } end @@ -877,16 +875,16 @@ class TestNestedAttributesOnAHasAndBelongsToManyAssociation < ActiveRecord::Test @association_type = :has_and_belongs_to_many @association_name = :parrots - @pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") - @pirate.parrots.create!(:name => 'Posideons Killer') - @pirate.parrots.create!(:name => 'Killer bandita Dionne') + @pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + @pirate.parrots.create!(name: "Posideons Killer") + @pirate.parrots.create!(name: "Killer bandita Dionne") @child_1, @child_2 = @pirate.parrots @alternate_params = { - :parrots_attributes => { - 'foo' => { :id => @child_1.id, :name => 'Grace OMalley' }, - 'bar' => { :id => @child_2.id, :name => 'Privateers Greed' } + parrots_attributes: { + "foo" => { id: @child_1.id, name: "Grace OMalley" }, + "bar" => { id: @child_2.id, name: "Privateers Greed" } } } end @@ -896,33 +894,33 @@ end module NestedAttributesLimitTests def teardown - Pirate.accepts_nested_attributes_for :parrots, :allow_destroy => true, :reject_if => proc(&:empty?) + Pirate.accepts_nested_attributes_for :parrots, allow_destroy: true, reject_if: proc(&:empty?) end def test_limit_with_less_records - @pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Big Big Love' } } } - assert_difference('Parrot.count') { @pirate.save! } + @pirate.attributes = { parrots_attributes: { "foo" => { name: "Big Big Love" } } } + assert_difference("Parrot.count") { @pirate.save! } end def test_limit_with_number_exact_records - @pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' }, 'bar' => { :name => 'Blown Away' } } } - assert_difference('Parrot.count', 2) { @pirate.save! } + @pirate.attributes = { parrots_attributes: { "foo" => { name: "Lovely Day" }, "bar" => { name: "Blown Away" } } } + assert_difference("Parrot.count", 2) { @pirate.save! } end def test_limit_with_exceeding_records assert_raises(ActiveRecord::NestedAttributes::TooManyRecords) do - @pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' }, - 'bar' => { :name => 'Blown Away' }, - 'car' => { :name => 'The Happening' }} } + @pirate.attributes = { parrots_attributes: { "foo" => { name: "Lovely Day" }, + "bar" => { name: "Blown Away" }, + "car" => { name: "The Happening" } } } end end end class TestNestedAttributesLimitNumeric < ActiveRecord::TestCase def setup - Pirate.accepts_nested_attributes_for :parrots, :limit => 2 + Pirate.accepts_nested_attributes_for :parrots, limit: 2 - @pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") + @pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") end include NestedAttributesLimitTests @@ -930,9 +928,9 @@ end class TestNestedAttributesLimitSymbol < ActiveRecord::TestCase def setup - Pirate.accepts_nested_attributes_for :parrots, :limit => :parrots_limit + Pirate.accepts_nested_attributes_for :parrots, limit: :parrots_limit - @pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?", :parrots_limit => 2) + @pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?", parrots_limit: 2) end include NestedAttributesLimitTests @@ -940,9 +938,9 @@ end class TestNestedAttributesLimitProc < ActiveRecord::TestCase def setup - Pirate.accepts_nested_attributes_for :parrots, :limit => proc { 2 } + Pirate.accepts_nested_attributes_for :parrots, limit: proc { 2 } - @pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?") + @pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") end include NestedAttributesLimitTests @@ -952,45 +950,44 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase fixtures :owners, :pets def setup - Owner.accepts_nested_attributes_for :pets, :allow_destroy => true + Owner.accepts_nested_attributes_for :pets, allow_destroy: true @owner = owners(:ashley) @pet1, @pet2 = pets(:chew), pets(:mochi) @params = { - :pets_attributes => { - '0' => { :id => @pet1.id, :name => 'Foo' }, - '1' => { :id => @pet2.id, :name => 'Bar' } + pets_attributes: { + "0" => { id: @pet1.id, name: "Foo" }, + "1" => { id: @pet2.id, name: "Bar" } } } end def test_should_update_existing_records_with_non_standard_primary_key @owner.update(@params) - assert_equal ['Foo', 'Bar'], @owner.pets.map(&:name) + assert_equal ["Foo", "Bar"], @owner.pets.map(&:name) end def test_attr_accessor_of_child_should_be_value_provided_during_update @owner = owners(:ashley) @pet1 = pets(:chew) - attributes = {:pets_attributes => { "1"=> { :id => @pet1.id, - :name => "Foo2", - :current_user => "John", - :_destroy=>true }}} + attributes = { pets_attributes: { "1"=> { id: @pet1.id, + name: "Foo2", + current_user: "John", + _destroy: true } } } @owner.update(attributes) - assert_equal 'John', Pet.after_destroy_output + assert_equal "John", Pet.after_destroy_output end - end class TestHasOneAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase self.use_transactional_tests = false unless supports_savepoints? def setup - @pirate = Pirate.create!(:catchphrase => "My baby takes tha mornin' train!") - @ship = @pirate.create_ship(:name => "The good ship Dollypop") - @part = @ship.parts.create!(:name => "Mast") - @trinket = @part.trinkets.create!(:name => "Necklace") + @pirate = Pirate.create!(catchphrase: "My baby takes tha mornin' train!") + @ship = @pirate.create_ship(name: "The good ship Dollypop") + @part = @ship.parts.create!(name: "Mast") + @trinket = @part.trinkets.create!(name: "Necklace") end test "when great-grandchild changed in memory, saving parent should save great-grandchild" do @@ -1000,25 +997,25 @@ class TestHasOneAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveRe end test "when great-grandchild changed via attributes, saving parent should save great-grandchild" do - @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]}} + @pirate.attributes = { ship_attributes: { id: @ship.id, parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, name: "changed" }] }] } } @pirate.save assert_equal "changed", @trinket.reload.name end test "when great-grandchild marked_for_destruction via attributes, saving parent should destroy great-grandchild" do - @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]}} - assert_difference('@part.trinkets.count', -1) { @pirate.save } + @pirate.attributes = { ship_attributes: { id: @ship.id, parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, _destroy: true }] }] } } + assert_difference("@part.trinkets.count", -1) { @pirate.save } end test "when great-grandchild added via attributes, saving parent should create great-grandchild" do - @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]}} - assert_difference('@part.trinkets.count', 1) { @pirate.save } + @pirate.attributes = { ship_attributes: { id: @ship.id, parts_attributes: [{ id: @part.id, trinkets_attributes: [{ name: "created" }] }] } } + assert_difference("@part.trinkets.count", 1) { @pirate.save } end test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do @trinket.name = "changed" - Ship.create!(:pirate => @pirate, :name => "The Black Rock") - ShipPart.create!(:ship => @ship, :name => "Stern") + Ship.create!(pirate: @pirate, name: "The Black Rock") + ShipPart.create!(ship: @ship, name: "Stern") assert_no_queries { @pirate.valid? } end end @@ -1027,27 +1024,27 @@ class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveR self.use_transactional_tests = false unless supports_savepoints? def setup - @ship = Ship.create!(:name => "The good ship Dollypop") - @part = @ship.parts.create!(:name => "Mast") - @trinket = @part.trinkets.create!(:name => "Necklace") + @ship = Ship.create!(name: "The good ship Dollypop") + @part = @ship.parts.create!(name: "Mast") + @trinket = @part.trinkets.create!(name: "Necklace") end test "if association is not loaded and association record is saved and then in memory record attributes should be saved" do - @ship.parts_attributes=[{:id => @part.id,:name =>'Deck'}] + @ship.parts_attributes=[{ id: @part.id,name: "Deck" }] assert_equal 1, @ship.association(:parts).target.size - assert_equal 'Deck', @ship.parts[0].name + assert_equal "Deck", @ship.parts[0].name end test "if association is not loaded and child doesn't change and I am saving a grandchild then in memory record should be used" do - @ship.parts_attributes=[{:id => @part.id,:trinkets_attributes =>[{:id => @trinket.id, :name => 'Ruby'}]}] + @ship.parts_attributes=[{ id: @part.id,trinkets_attributes: [{ id: @trinket.id, name: "Ruby" }] }] assert_equal 1, @ship.association(:parts).target.size - assert_equal 'Mast', @ship.parts[0].name + assert_equal "Mast", @ship.parts[0].name assert_no_difference("@ship.parts[0].association(:trinkets).target.size") do @ship.parts[0].association(:trinkets).target.size end - assert_equal 'Ruby', @ship.parts[0].trinkets[0].name + assert_equal "Ruby", @ship.parts[0].trinkets[0].name @ship.save - assert_equal 'Ruby', @ship.parts[0].trinkets[0].name + assert_equal "Ruby", @ship.parts[0].trinkets[0].name end test "when grandchild changed in memory, saving parent should save grandchild" do @@ -1057,25 +1054,25 @@ class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveR end test "when grandchild changed via attributes, saving parent should save grandchild" do - @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]} + @ship.attributes = { parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, name: "changed" }] }] } @ship.save assert_equal "changed", @trinket.reload.name end test "when grandchild marked_for_destruction via attributes, saving parent should destroy grandchild" do - @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]} - assert_difference('@part.trinkets.count', -1) { @ship.save } + @ship.attributes = { parts_attributes: [{ id: @part.id, trinkets_attributes: [{ id: @trinket.id, _destroy: true }] }] } + assert_difference("@part.trinkets.count", -1) { @ship.save } end test "when grandchild added via attributes, saving parent should create grandchild" do - @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]} - assert_difference('@part.trinkets.count', 1) { @ship.save } + @ship.attributes = { parts_attributes: [{ id: @part.id, trinkets_attributes: [{ name: "created" }] }] } + assert_difference("@part.trinkets.count", 1) { @ship.save } end test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do @trinket.name = "changed" - Ship.create!(:name => "The Black Rock") - ShipPart.create!(:ship => @ship, :name => "Stern") + Ship.create!(name: "The Black Rock") + ShipPart.create!(ship: @ship, name: "Stern") assert_no_queries { @ship.valid? } end diff --git a/activerecord/test/cases/nested_attributes_with_callbacks_test.rb b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb index 43a69928b6..8954e8c7e3 100644 --- a/activerecord/test/cases/nested_attributes_with_callbacks_test.rb +++ b/activerecord/test/cases/nested_attributes_with_callbacks_test.rb @@ -4,24 +4,24 @@ require "models/bird" class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase Pirate.has_many(:birds_with_add_load, - :class_name => "Bird", - :before_add => proc { |p,b| + class_name: "Bird", + before_add: proc { |p,b| @@add_callback_called << b p.birds_with_add_load.to_a }) Pirate.has_many(:birds_with_add, - :class_name => "Bird", - :before_add => proc { |p,b| @@add_callback_called << b }) + class_name: "Bird", + before_add: proc { |p,b| @@add_callback_called << b }) Pirate.accepts_nested_attributes_for(:birds_with_add_load, :birds_with_add, - :allow_destroy => true) + allow_destroy: true) def setup @@add_callback_called = [] @pirate = Pirate.new.tap do |pirate| pirate.catchphrase = "Don't call me!" - pirate.birds_attributes = [{:name => 'Bird1'},{:name => 'Bird2'}] + pirate.birds_attributes = [{ name: "Bird1" },{ name: "Bird2" }] pirate.save! end @birds = @pirate.birds.to_a @@ -46,17 +46,17 @@ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase end def new_bird_attributes - [{'name' => "New Bird"}] + [{ "name" => "New Bird" }] end def destroy_bird_attributes - [{'id' => bird_to_destroy.id.to_s, "_destroy" => true}] + [{ "id" => bird_to_destroy.id.to_s, "_destroy" => true }] end def update_new_and_destroy_bird_attributes - [{'id' => @birds[0].id.to_s, 'name' => 'New Name'}, - {'name' => "New Bird"}, - {'id' => bird_to_destroy.id.to_s, "_destroy" => true}] + [{ "id" => @birds[0].id.to_s, "name" => "New Name" }, + { "name" => "New Bird" }, + { "id" => bird_to_destroy.id.to_s, "_destroy" => true }] end # Characterizing when :before_add callback is called @@ -136,9 +136,9 @@ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase def assert_assignment_affects_records_in_target(association_name) association = @pirate.send(association_name) - assert association.detect {|b| b == bird_to_update }.name_changed?, - 'Update record not updated' - assert association.detect {|b| b == bird_to_destroy }.marked_for_destruction?, - 'Destroy record not marked for destruction' + assert association.detect { |b| b == bird_to_update }.name_changed?, + "Update record not updated" + assert association.detect { |b| b == bird_to_destroy }.marked_for_destruction?, + "Destroy record not marked for destruction" end end diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index 56092aaa0c..688c3ed2b1 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -1,30 +1,30 @@ require "cases/helper" -require 'models/aircraft' -require 'models/post' -require 'models/comment' -require 'models/author' -require 'models/topic' -require 'models/reply' -require 'models/category' -require 'models/company' -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/minimalistic' -require 'models/warehouse_thing' -require 'models/parrot' -require 'models/minivan' -require 'models/owner' -require 'models/person' -require 'models/pet' -require 'models/ship' -require 'models/toy' -require 'models/admin' -require 'models/admin/user' -require 'rexml/document' +require "models/aircraft" +require "models/post" +require "models/comment" +require "models/author" +require "models/topic" +require "models/reply" +require "models/category" +require "models/company" +require "models/developer" +require "models/computer" +require "models/project" +require "models/minimalistic" +require "models/warehouse_thing" +require "models/parrot" +require "models/minivan" +require "models/owner" +require "models/person" +require "models/pet" +require "models/ship" +require "models/toy" +require "models/admin" +require "models/admin/user" +require "rexml/document" class PersistenceTest < ActiveRecord::TestCase - fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :author_addresses, :categorizations, :categories, :posts, :minivans, :pets, :toys + fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, "warehouse-things", :authors, :author_addresses, :categorizations, :categories, :posts, :minivans, :pets, :toys # Oracle UPDATE does not support ORDER BY unless current_adapter?(:OracleAdapter) @@ -39,18 +39,18 @@ class PersistenceTest < ActiveRecord::TestCase assert_equal authors(:david).id + 1, authors(:mary).id # make sure there is going to be a duplicate PK error test_update_with_order_succeeds = lambda do |order| begin - Author.order(order).update_all('id = id + 1') + Author.order(order).update_all("id = id + 1") rescue ActiveRecord::ActiveRecordError false end end - if test_update_with_order_succeeds.call('id DESC') - assert !test_update_with_order_succeeds.call('id ASC') # test that this wasn't a fluke and using an incorrect order results in an exception + if test_update_with_order_succeeds.call("id DESC") + assert !test_update_with_order_succeeds.call("id ASC") # test that this wasn't a fluke and using an incorrect order results in an exception else # test that we're failing because the current Arel's engine doesn't support UPDATE ORDER BY queries is using subselects instead assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\Z/i) do - test_update_with_order_succeeds.call('id DESC') + test_update_with_order_succeeds.call("id DESC") end end end @@ -83,7 +83,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_delete_all_with_joins_and_where_part_is_hash - where_args = {:toys => {:name => 'Bone'}} + where_args = { toys: { name: "Bone" } } count = Pet.joins(:toys).where(where_args).count assert_equal count, 1 @@ -91,7 +91,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_delete_all_with_joins_and_where_part_is_not_hash - where_args = ['toys.name = ?', 'Bone'] + where_args = ["toys.name = ?", "Bone"] count = Pet.joins(:toys).where(where_args).count assert_equal count, 1 @@ -133,10 +133,10 @@ class PersistenceTest < ActiveRecord::TestCase def test_destroy_all conditions = "author_name = 'Mary'" - topics_by_mary = Topic.all.merge!(:where => conditions, :order => 'id').to_a + topics_by_mary = Topic.all.merge!(where: conditions, order: "id").to_a assert ! topics_by_mary.empty? - assert_difference('Topic.count', -topics_by_mary.size) do + assert_difference("Topic.count", -topics_by_mary.size) do destroyed = Topic.where(conditions).destroy_all.sort_by(&:id) assert_equal topics_by_mary, destroyed assert destroyed.all?(&:frozen?), "destroyed topics should be frozen" @@ -144,9 +144,9 @@ class PersistenceTest < ActiveRecord::TestCase end def test_destroy_many - clients = Client.all.merge!(:order => 'id').find([2, 3]) + clients = Client.all.merge!(order: "id").find([2, 3]) - assert_difference('Client.count', -2) do + assert_difference("Client.count", -2) do destroyed = Client.destroy([2, 3]).sort_by(&:id) assert_equal clients, destroyed assert destroyed.all?(&:frozen?), "destroyed clients should be frozen" @@ -159,7 +159,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_becomes_includes_errors - company = Company.new(:name => nil) + company = Company.new(name: nil) assert !company.valid? original_errors = company.errors client = company.becomes(Client) @@ -170,7 +170,7 @@ class PersistenceTest < ActiveRecord::TestCase child_class = Class.new(Admin::User) do store_accessor :settings, :foo - def self.name; 'Admin::ChildUser'; end + def self.name; "Admin::ChildUser"; end end admin = Admin::User.new @@ -231,7 +231,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_save! - topic = Topic.new(:title => "New Topic") + topic = Topic.new(title: "New Topic") assert topic.save! reply = WrongReply.new @@ -261,7 +261,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_save_for_record_with_only_primary_key_that_is_provided - assert_nothing_raised { Minimalistic.create!(:id => 2) } + assert_nothing_raised { Minimalistic.create!(id: 2) } end def test_save_with_duping_of_destroyed_object @@ -281,9 +281,9 @@ class PersistenceTest < ActiveRecord::TestCase def test_create_columns_not_equal_attributes topic = Topic.instantiate( - 'attributes' => { - 'title' => 'Another New Topic', - 'does_not_exist' => 'test' + "attributes" => { + "title" => "Another New Topic", + "does_not_exist" => "test" } ) assert_nothing_raised { topic.save } @@ -330,8 +330,8 @@ class PersistenceTest < ActiveRecord::TestCase topic.title = "Still another topic" topic.save - topic_reloaded = Topic.instantiate(topic.attributes.merge('does_not_exist' => 'test')) - topic_reloaded.title = 'A New Topic' + topic_reloaded = Topic.instantiate(topic.attributes.merge("does_not_exist" => "test")) + topic_reloaded.title = "A New Topic" assert_nothing_raised { topic_reloaded.save } end @@ -371,7 +371,7 @@ class PersistenceTest < ActiveRecord::TestCase def test_update_after_create klass = Class.new(Topic) do - def self.name; 'Topic'; end + def self.name; "Topic"; end after_create do update_attribute("author_name", "David") end @@ -387,24 +387,24 @@ class PersistenceTest < ActiveRecord::TestCase def test_update_attribute_does_not_run_sql_if_attribute_is_not_changed klass = Class.new(Topic) do - def self.name; 'Topic'; end + def self.name; "Topic"; end end - topic = klass.create(title: 'Another New Topic') + topic = klass.create(title: "Another New Topic") assert_queries(0) do - topic.update_attribute(:title, 'Another New Topic') + assert topic.update_attribute(:title, "Another New Topic") end end def test_update_does_not_run_sql_if_record_has_not_changed - topic = Topic.create(title: 'Another New Topic') - assert_queries(0) { topic.update(title: 'Another New Topic') } - assert_queries(0) { topic.update_attributes(title: 'Another New Topic') } + topic = Topic.create(title: "Another New Topic") + assert_queries(0) { assert topic.update(title: "Another New Topic") } + assert_queries(0) { assert topic.update_attributes(title: "Another New Topic") } end def test_delete topic = Topic.find(1) - assert_equal topic, topic.delete, 'topic.delete did not return self' - assert topic.frozen?, 'topic not frozen after delete' + assert_equal topic, topic.delete, "topic.delete did not return self" + assert topic.frozen?, "topic not frozen after delete" assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) } end @@ -415,15 +415,15 @@ class PersistenceTest < ActiveRecord::TestCase def test_destroy topic = Topic.find(1) - assert_equal topic, topic.destroy, 'topic.destroy did not return self' - assert topic.frozen?, 'topic not frozen after destroy' + assert_equal topic, topic.destroy, "topic.destroy did not return self" + assert topic.frozen?, "topic not frozen after destroy" assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) } end def test_destroy! topic = Topic.find(1) - assert_equal topic, topic.destroy!, 'topic.destroy! did not return self' - assert topic.frozen?, 'topic not frozen after destroy!' + assert_equal topic, topic.destroy!, "topic.destroy! did not return self" + assert topic.frozen?, "topic not frozen after destroy!" assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) } end @@ -436,17 +436,17 @@ class PersistenceTest < ActiveRecord::TestCase assert_equal "bulk updated!", Topic.find(1).content assert_equal "bulk updated!", Topic.find(2).content - assert_equal Topic.count, Topic.update_all(['content = ?', 'bulk updated again!']) + assert_equal Topic.count, Topic.update_all(["content = ?", "bulk updated again!"]) assert_equal "bulk updated again!", Topic.find(1).content assert_equal "bulk updated again!", Topic.find(2).content - assert_equal Topic.count, Topic.update_all(['content = ?', nil]) + assert_equal Topic.count, Topic.update_all(["content = ?", nil]) assert_nil Topic.find(1).content end def test_update_all_with_hash assert_not_nil Topic.find(1).last_read - assert_equal Topic.count, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil) + assert_equal Topic.count, Topic.update_all(content: "bulk updated with hash!", last_read: nil) assert_equal "bulk updated with hash!", Topic.find(1).content assert_equal "bulk updated with hash!", Topic.find(2).content assert_nil Topic.find(1).last_read @@ -454,7 +454,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_update_all_with_non_standard_table_name - assert_equal 1, WarehouseThing.where(id: 1).update_all(['value = ?', 0]) + assert_equal 1, WarehouseThing.where(id: 1).update_all(["value = ?", 0]) assert_equal 0, WarehouseThing.find(1).value end @@ -496,20 +496,20 @@ class PersistenceTest < ActiveRecord::TestCase end def test_update_attribute_for_readonly_attribute - minivan = Minivan.find('m1') - assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') } + minivan = Minivan.find("m1") + assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, "black") } end def test_update_attribute_with_one_updated t = Topic.first - t.update_attribute(:title, 'super_title') - assert_equal 'super_title', t.title + t.update_attribute(:title, "super_title") + assert_equal "super_title", t.title assert !t.changed?, "topic should not have changed" assert !t.title_changed?, "title should not have changed" - assert_nil t.title_change, 'title change should be nil' + assert_nil t.title_change, "title change should be nil" t.reload - assert_equal 'super_title', t.title + assert_equal "super_title", t.title end def test_update_attribute_for_updated_at_on @@ -569,17 +569,17 @@ class PersistenceTest < ActiveRecord::TestCase end def test_update_column_with_model_having_primary_key_other_than_id - minivan = Minivan.find('m1') - new_name = 'sebavan' + minivan = Minivan.find("m1") + new_name = "sebavan" minivan.update_column(:name, new_name) assert_equal new_name, minivan.name end def test_update_column_for_readonly_attribute - minivan = Minivan.find('m1') + minivan = Minivan.find("m1") prev_color = minivan.color - assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_column(:color, 'black') } + assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_column(:color, "black") } assert_equal prev_color, minivan.color end @@ -598,31 +598,31 @@ class PersistenceTest < ActiveRecord::TestCase end def test_update_column_with_one_changed_and_one_updated - t = Topic.order('id').limit(1).first + t = Topic.order("id").limit(1).first author_name = t.author_name - t.author_name = 'John' - t.update_column(:title, 'super_title') - assert_equal 'John', t.author_name - assert_equal 'super_title', t.title + t.author_name = "John" + t.update_column(:title, "super_title") + assert_equal "John", t.author_name + assert_equal "super_title", t.title assert t.changed?, "topic should have changed" assert t.author_name_changed?, "author_name should have changed" t.reload assert_equal author_name, t.author_name - assert_equal 'super_title', t.title + assert_equal "super_title", t.title end def test_update_column_with_default_scope developer = DeveloperCalledDavid.first - developer.name = 'John' + developer.name = "John" developer.save! - assert developer.update_column(:name, 'Will'), 'did not update record due to default scope' + assert developer.update_column(:name, "Will"), "did not update record due to default scope" end def test_update_columns topic = Topic.find(1) - topic.update_columns({ "approved" => true, title: "Sebastian Topic" }) + topic.update_columns("approved" => true, title: "Sebastian Topic") assert topic.approved? assert_equal "Sebastian Topic", topic.title topic.reload @@ -643,35 +643,35 @@ class PersistenceTest < ActiveRecord::TestCase def test_update_columns_should_raise_exception_if_new_record topic = Topic.new - assert_raises(ActiveRecord::ActiveRecordError) { topic.update_columns({ approved: false }) } + assert_raises(ActiveRecord::ActiveRecordError) { topic.update_columns(approved: false) } end def test_update_columns_should_not_leave_the_object_dirty topic = Topic.find(1) - topic.update({ "content" => "--- Have a nice day\n...\n", :author_name => "Jose" }) + topic.update("content" => "--- Have a nice day\n...\n", :author_name => "Jose") topic.reload - topic.update_columns({ content: "--- You too\n...\n", "author_name" => "Sebastian" }) + topic.update_columns(content: "--- You too\n...\n", "author_name" => "Sebastian") assert_equal [], topic.changed topic.reload - topic.update_columns({ content: "--- Have a nice day\n...\n", author_name: "Jose" }) + topic.update_columns(content: "--- Have a nice day\n...\n", author_name: "Jose") assert_equal [], topic.changed end def test_update_columns_with_model_having_primary_key_other_than_id - minivan = Minivan.find('m1') - new_name = 'sebavan' + minivan = Minivan.find("m1") + new_name = "sebavan" minivan.update_columns(name: new_name) assert_equal new_name, minivan.name end def test_update_columns_with_one_readonly_attribute - minivan = Minivan.find('m1') + minivan = Minivan.find("m1") prev_color = minivan.color prev_name = minivan.name - assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_columns({ name: "My old minivan", color: 'black' }) } + assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_columns(name: "My old minivan", color: "black") } assert_equal prev_color, minivan.color assert_equal prev_name, minivan.name @@ -697,18 +697,18 @@ class PersistenceTest < ActiveRecord::TestCase end def test_update_columns_with_one_changed_and_one_updated - t = Topic.order('id').limit(1).first + t = Topic.order("id").limit(1).first author_name = t.author_name - t.author_name = 'John' - t.update_columns(title: 'super_title') - assert_equal 'John', t.author_name - assert_equal 'super_title', t.title + t.author_name = "John" + t.update_columns(title: "super_title") + assert_equal "John", t.author_name + assert_equal "super_title", t.title assert t.changed?, "topic should have changed" assert t.author_name_changed?, "author_name should have changed" t.reload assert_equal author_name, t.author_name - assert_equal 'super_title', t.title + assert_equal "super_title", t.title end def test_update_columns_changing_id @@ -726,10 +726,10 @@ class PersistenceTest < ActiveRecord::TestCase def test_update_columns_with_default_scope developer = DeveloperCalledDavid.first - developer.name = 'John' + developer.name = "John" developer.save! - assert developer.update_columns(name: 'Will'), 'did not update record due to default scope' + assert developer.update_columns(name: "Will"), "did not update record due to default scope" end def test_update @@ -840,7 +840,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_persisted_returns_boolean - developer = Developer.new(:name => "Jose") + developer = Developer.new(name: "Jose") assert_equal false, developer.persisted? developer.save! assert_equal true, developer.persisted? @@ -909,7 +909,7 @@ class PersistenceTest < ActiveRecord::TestCase end def test_reload_removes_custom_selects - post = Post.select('posts.*, 1 as wibble').last! + post = Post.select("posts.*, 1 as wibble").last! assert_equal 1, post[:wibble] assert_nil post.reload[:wibble] @@ -930,8 +930,8 @@ class PersistenceTest < ActiveRecord::TestCase def test_reload_via_querycache ActiveRecord::Base.connection.enable_query_cache! ActiveRecord::Base.connection.clear_query_cache - assert ActiveRecord::Base.connection.query_cache_enabled, 'cache should be on' - parrot = Parrot.create(:name => 'Shane') + assert ActiveRecord::Base.connection.query_cache_enabled, "cache should be on" + parrot = Parrot.create(name: "Shane") # populate the cache with the SELECT result found_parrot = Parrot.find(parrot.id) @@ -940,16 +940,16 @@ class PersistenceTest < ActiveRecord::TestCase # Manually update the 'name' attribute in the DB directly assert_equal 1, ActiveRecord::Base.connection.query_cache.length ActiveRecord::Base.uncached do - found_parrot.name = 'Mary' + found_parrot.name = "Mary" found_parrot.save end # Now reload, and verify that it gets the DB version, and not the querycache version found_parrot.reload - assert_equal 'Mary', found_parrot.name + assert_equal "Mary", found_parrot.name found_parrot = Parrot.find(parrot.id) - assert_equal 'Mary', found_parrot.name + assert_equal "Mary", found_parrot.name ensure ActiveRecord::Base.connection.disable_query_cache! end @@ -967,16 +967,15 @@ class PersistenceTest < ActiveRecord::TestCase self.table_name = :widgets end - instance = widget.create!({ - name: 'Bob', + instance = widget.create!( + name: "Bob", created_at: 1.day.ago, - updated_at: 1.day.ago - }) + updated_at: 1.day.ago) created_at = instance.created_at updated_at = instance.updated_at - instance.name = 'Barb' + instance.name = "Barb" instance.save!(touch: false) assert_equal instance.created_at, created_at assert_equal instance.updated_at, updated_at diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb index bca50dd008..f1b0d08765 100644 --- a/activerecord/test/cases/pooled_connections_test.rb +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -18,7 +18,7 @@ class PooledConnectionsTest < ActiveRecord::TestCase # Will deadlock due to lack of Monitor timeouts in 1.9 def checkout_checkin_connections(pool_size, threads) - ActiveRecord::Base.establish_connection(@connection.merge({:pool => pool_size, :checkout_timeout => 0.5})) + ActiveRecord::Base.establish_connection(@connection.merge(pool: pool_size, checkout_timeout: 0.5)) @connection_count = 0 @timed_out = 0 threads.times do @@ -36,7 +36,7 @@ class PooledConnectionsTest < ActiveRecord::TestCase end def checkout_checkin_connections_loop(pool_size, loops) - ActiveRecord::Base.establish_connection(@connection.merge({:pool => pool_size, :checkout_timeout => 0.5})) + ActiveRecord::Base.establish_connection(@connection.merge(pool: pool_size, checkout_timeout: 0.5)) @connection_count = 0 @timed_out = 0 loops.times do @@ -66,7 +66,7 @@ class PooledConnectionsTest < ActiveRecord::TestCase end def test_pooled_connection_remove - ActiveRecord::Base.establish_connection(@connection.merge({:pool => 2, :checkout_timeout => 0.5})) + ActiveRecord::Base.establish_connection(@connection.merge(pool: 2, checkout_timeout: 0.5)) old_connection = ActiveRecord::Base.connection extra_connection = ActiveRecord::Base.connection_pool.checkout ActiveRecord::Base.connection_pool.remove(extra_connection) @@ -75,7 +75,7 @@ class PooledConnectionsTest < ActiveRecord::TestCase private - def add_record(name) - ActiveRecord::Base.connection_pool.with_connection { Project.create! :name => name } - end + def add_record(name) + ActiveRecord::Base.connection_pool.with_connection { Project.create! name: name } + end end unless in_memory_db? diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb index 52eac4a124..31d612abd1 100644 --- a/activerecord/test/cases/primary_keys_test.rb +++ b/activerecord/test/cases/primary_keys_test.rb @@ -1,12 +1,12 @@ require "cases/helper" -require 'support/schema_dumping_helper' -require 'models/topic' -require 'models/reply' -require 'models/subscriber' -require 'models/movie' -require 'models/keyboard' -require 'models/mixed_case_monkey' -require 'models/dashboard' +require "support/schema_dumping_helper" +require "models/topic" +require "models/reply" +require "models/subscriber" +require "models/movie" +require "models/keyboard" +require "models/mixed_case_monkey" +require "models/dashboard" class PrimaryKeysTest < ActiveRecord::TestCase fixtures :topics, :subscribers, :movies, :mixed_case_monkeys @@ -54,9 +54,9 @@ class PrimaryKeysTest < ActiveRecord::TestCase def test_customized_primary_key_auto_assigns_on_save Keyboard.delete_all - keyboard = Keyboard.new(:name => 'HHKB') + keyboard = Keyboard.new(name: "HHKB") assert_nothing_raised { keyboard.save! } - assert_equal keyboard.id, Keyboard.find_by_name('HHKB').id + assert_equal keyboard.id, Keyboard.find_by_name("HHKB").id end def test_customized_primary_key_can_be_get_before_saving @@ -67,9 +67,9 @@ class PrimaryKeysTest < ActiveRecord::TestCase def test_customized_string_primary_key_settable_before_save subscriber = Subscriber.new - assert_nothing_raised { subscriber.id = 'webster123' } - assert_equal 'webster123', subscriber.id - assert_equal 'webster123', subscriber.nick + assert_nothing_raised { subscriber.id = "webster123" } + assert_equal "webster123", subscriber.id + assert_equal "webster123", subscriber.nick end def test_string_key @@ -114,7 +114,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase assert_nothing_raised { MixedCaseMonkey.delete(1) } end def test_update_counters_should_quote_pkey_and_quote_counter_columns - assert_nothing_raised { MixedCaseMonkey.update_counters(1, :fleaCount => 99) } + assert_nothing_raised { MixedCaseMonkey.update_counters(1, fleaCount: 99) } end def test_find_with_one_id_should_quote_pkey assert_nothing_raised { MixedCaseMonkey.find(1) } @@ -138,15 +138,15 @@ class PrimaryKeysTest < ActiveRecord::TestCase if ActiveRecord::Base.connection.supports_primary_key? def test_primary_key_returns_value_if_it_exists klass = Class.new(ActiveRecord::Base) do - self.table_name = 'developers' + self.table_name = "developers" end - assert_equal 'id', klass.primary_key + assert_equal "id", klass.primary_key end def test_primary_key_returns_nil_if_it_does_not_exist klass = Class.new(ActiveRecord::Base) do - self.table_name = 'developers_projects' + self.table_name = "developers_projects" end assert_nil klass.primary_key @@ -166,12 +166,20 @@ class PrimaryKeysTest < ActiveRecord::TestCase end def test_primary_key_update_with_custom_key_name - dashboard = Dashboard.create!(dashboard_id: '1') - dashboard.id = '2' + dashboard = Dashboard.create!(dashboard_id: "1") + dashboard.id = "2" dashboard.save! dashboard = Dashboard.first - assert_equal '2', dashboard.id + assert_equal "2", dashboard.id + end + + def test_create_without_primary_key_no_extra_query + klass = Class.new(ActiveRecord::Base) do + self.table_name = "dashboards" + end + klass.create! # warmup schema cache + assert_queries(3, ignore_none: true) { klass.create! } end if current_adapter?(:PostgreSQLAdapter) @@ -197,13 +205,13 @@ class PrimaryKeyWithNoConnectionTest < ActiveRecord::TestCase connection = ActiveRecord::Base.remove_connection model = Class.new(ActiveRecord::Base) - model.primary_key = 'foo' + model.primary_key = "foo" - assert_equal 'foo', model.primary_key + assert_equal "foo", model.primary_key ActiveRecord::Base.establish_connection(connection) - assert_equal 'foo', model.primary_key + assert_equal "foo", model.primary_key end end end @@ -247,6 +255,7 @@ class CompositePrimaryKeyTest < ActiveRecord::TestCase def setup @connection = ActiveRecord::Base.connection + @connection.schema_cache.clear! @connection.create_table(:barcodes, primary_key: ["region", "code"], force: true) do |t| t.string :region t.integer :code @@ -262,10 +271,15 @@ class CompositePrimaryKeyTest < ActiveRecord::TestCase end def test_primary_key_issues_warning + model = Class.new(ActiveRecord::Base) do + def self.table_name + "barcodes" + end + end warning = capture(:stderr) do - assert_nil @connection.primary_key("barcodes") + assert_nil model.primary_key end - assert_match(/WARNING: Rails does not support composite primary key\./, warning) + assert_match(/WARNING: Active Record does not support composite primary key\./, warning) end def test_collectly_dump_composite_primary_key @@ -275,18 +289,6 @@ class CompositePrimaryKeyTest < ActiveRecord::TestCase end if current_adapter?(:Mysql2Adapter) - class PrimaryKeyWithAnsiQuotesTest < ActiveRecord::TestCase - self.use_transactional_tests = false - - def test_primary_key_method_with_ansi_quotes - con = ActiveRecord::Base.connection - con.execute("SET SESSION sql_mode='ANSI_QUOTES'") - assert_equal "id", con.primary_key("topics") - ensure - con.reconnect! - end - end - class PrimaryKeyBigintNilDefaultTest < ActiveRecord::TestCase include SchemaDumpingHelper @@ -302,7 +304,7 @@ if current_adapter?(:Mysql2Adapter) end test "primary key with bigint allows default override via nil" do - column = @connection.columns(:bigint_defaults).find { |c| c.name == 'id' } + column = @connection.columns(:bigint_defaults).find { |c| c.name == "id" } assert column.bigint? assert_not column.auto_increment? end @@ -360,7 +362,7 @@ if current_adapter?(:PostgreSQLAdapter, :Mysql2Adapter) if current_adapter?(:Mysql2Adapter) test "primary key column type with options" do @connection.create_table(:widgets, id: :primary_key, limit: 8, unsigned: true, force: true) - column = @connection.columns(:widgets).find { |c| c.name == 'id' } + column = @connection.columns(:widgets).find { |c| c.name == "id" } assert column.auto_increment? assert_equal :integer, column.type assert_equal 8, column.limit diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index d5c01315c1..4cd258695d 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -1,20 +1,43 @@ require "cases/helper" -require 'models/topic' -require 'models/task' -require 'models/category' -require 'models/post' -require 'rack' +require "models/topic" +require "models/task" +require "models/category" +require "models/post" +require "rack" class QueryCacheTest < ActiveRecord::TestCase + self.use_transactional_tests = false + fixtures :tasks, :topics, :categories, :posts, :categories_posts - teardown do + class ShouldNotHaveExceptionsLogger < ActiveRecord::LogSubscriber + attr_reader :logger + + def initialize + super + @logger = ::Logger.new File::NULL + @exception = false + end + + def exception? + @exception + end + + def sql(event) + super + rescue + @exception = true + end + end + + def teardown Task.connection.clear_query_cache ActiveRecord::Base.connection.disable_query_cache! + super end def test_exceptional_middleware_clears_and_disables_cache_on_error - assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + assert !ActiveRecord::Base.connection.query_cache_enabled, "cache off" mw = middleware { |env| Task.find 1 @@ -25,7 +48,7 @@ class QueryCacheTest < ActiveRecord::TestCase assert_raises(RuntimeError) { mw.call({}) } assert_equal 0, ActiveRecord::Base.connection.query_cache.length - assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + assert !ActiveRecord::Base.connection.query_cache_enabled, "cache off" end def test_exceptional_middleware_leaves_enabled_cache_alone @@ -36,19 +59,7 @@ class QueryCacheTest < ActiveRecord::TestCase } assert_raises(RuntimeError) { mw.call({}) } - assert ActiveRecord::Base.connection.query_cache_enabled, 'cache on' - end - - def test_exceptional_middleware_assigns_original_connection_id_on_error - connection_id = ActiveRecord::Base.connection_id - - mw = middleware { |env| - ActiveRecord::Base.connection_id = self.object_id - raise "lol borked" - } - assert_raises(RuntimeError) { mw.call({}) } - - assert_equal connection_id, ActiveRecord::Base.connection_id + assert ActiveRecord::Base.connection.query_cache_enabled, "cache on" end def test_middleware_delegates @@ -58,7 +69,7 @@ class QueryCacheTest < ActiveRecord::TestCase [200, {}, nil] } mw.call({}) - assert called, 'middleware should delegate' + assert called, "middleware should delegate" end def test_middleware_caches @@ -72,10 +83,10 @@ class QueryCacheTest < ActiveRecord::TestCase end def test_cache_enabled_during_call - assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + assert !ActiveRecord::Base.connection.query_cache_enabled, "cache off" mw = middleware { |env| - assert ActiveRecord::Base.connection.query_cache_enabled, 'cache on' + assert ActiveRecord::Base.connection.query_cache_enabled, "cache on" [200, {}, nil] } mw.call({}) @@ -131,6 +142,19 @@ class QueryCacheTest < ActiveRecord::TestCase end end + def test_cache_does_not_raise_exceptions + logger = ShouldNotHaveExceptionsLogger.new + subscriber = ActiveSupport::Notifications.subscribe "sql.active_record", logger + + ActiveRecord::Base.cache do + assert_queries(1) { Task.find(1); Task.find(1) } + end + + assert_not_predicate logger, :exception? + ensure + ActiveSupport::Notifications.unsubscribe subscriber + end + def test_cache_is_flat Task.cache do assert_queries(1) { Topic.find(1); Topic.find(1); } @@ -148,7 +172,7 @@ class QueryCacheTest < ActiveRecord::TestCase assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter) # Future versions of the sqlite3 adapter will return numeric - assert_instance_of Fixnum, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") + assert_instance_of 0.class, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") else assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") end @@ -176,7 +200,7 @@ class QueryCacheTest < ActiveRecord::TestCase def test_cache_is_not_available_when_using_a_not_connected_connection spec_name = Task.connection_specification_name - conf = ActiveRecord::Base.configurations['arunit'].merge('name' => 'test2') + conf = ActiveRecord::Base.configurations["arunit"].merge("name" => "test2") ActiveRecord::Base.connection_handler.establish_connection(conf) Task.connection_specification_name = "test2" refute Task.connected? @@ -195,30 +219,50 @@ class QueryCacheTest < ActiveRecord::TestCase post = Post.first Post.transaction do - post.update_attributes(title: 'rollback') - assert_equal 1, Post.where(title: 'rollback').to_a.count + post.update_attributes(title: "rollback") + assert_equal 1, Post.where(title: "rollback").to_a.count raise ActiveRecord::Rollback end - assert_equal 0, Post.where(title: 'rollback').to_a.count + assert_equal 0, Post.where(title: "rollback").to_a.count ActiveRecord::Base.connection.uncached do - assert_equal 0, Post.where(title: 'rollback').to_a.count + assert_equal 0, Post.where(title: "rollback").to_a.count end begin Post.transaction do - post.update_attributes(title: 'rollback') - assert_equal 1, Post.where(title: 'rollback').to_a.count - raise 'broken' + post.update_attributes(title: "rollback") + assert_equal 1, Post.where(title: "rollback").to_a.count + raise "broken" end rescue Exception end - assert_equal 0, Post.where(title: 'rollback').to_a.count + assert_equal 0, Post.where(title: "rollback").to_a.count ActiveRecord::Base.connection.uncached do - assert_equal 0, Post.where(title: 'rollback').to_a.count + assert_equal 0, Post.where(title: "rollback").to_a.count + end + end + + def test_query_cached_even_when_types_are_reset + Task.cache do + # Warm the cache + Task.find(1) + + Task.connection.type_map.clear + + # Preload the type cache again (so we don't have those queries issued during our assertions) + Task.connection.send(:initialize_type_map, Task.connection.type_map) + + # Clear places where type information is cached + Task.reset_column_information + Task.initialize_find_by_cache + + assert_queries(0) do + Task.find(1) + end end end diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index c01c82f4f5..296dafacc2 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -16,20 +16,20 @@ module ActiveRecord end def test_quote_column_name - assert_equal "foo", @quoter.quote_column_name('foo') + assert_equal "foo", @quoter.quote_column_name("foo") end def test_quote_table_name - assert_equal "foo", @quoter.quote_table_name('foo') + assert_equal "foo", @quoter.quote_table_name("foo") end def test_quote_table_name_calls_quote_column_name @quoter.extend(Module.new { def quote_column_name(string) - 'lol' + "lol" end }) - assert_equal 'lol', @quoter.quote_table_name('foo') + assert_equal "lol", @quoter.quote_table_name("foo") end def test_quote_string @@ -86,7 +86,7 @@ module ActiveRecord end def test_quote_nil - assert_equal 'NULL', @quoter.quote(nil, nil) + assert_equal "NULL", @quoter.quote(nil, nil) end def test_quote_true @@ -114,11 +114,11 @@ module ActiveRecord def test_quote_bigdecimal bigdec = BigDecimal.new((1 << 100).to_s) - assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, nil) + assert_equal bigdec.to_s("F"), @quoter.quote(bigdec, nil) end def test_dates_and_times - @quoter.extend(Module.new { def quoted_date(value) 'lol' end }) + @quoter.extend(Module.new { def quoted_date(value) "lol" end }) assert_equal "'lol'", @quoter.quote(Date.today, nil) assert_equal "'lol'", @quoter.quote(Time.now, nil) assert_equal "'lol'", @quoter.quote(DateTime.now, nil) @@ -133,21 +133,33 @@ module ActiveRecord end def test_quote_string_no_column - assert_equal "'lo\\\\l'", @quoter.quote('lo\l', nil) + assert_equal "'lo\\\\l'", @quoter.quote('lo\l') end def test_quote_as_mb_chars_no_column string = ActiveSupport::Multibyte::Chars.new('lo\l') - assert_equal "'lo\\\\l'", @quoter.quote(string, nil) - end - - def test_string_with_crazy_column - assert_equal "'lo\\\\l'", @quoter.quote('lo\l') + assert_equal "'lo\\\\l'", @quoter.quote(string) end def test_quote_duration assert_equal "1800", @quoter.quote(30.minutes) end end + + class QuoteBooleanTest < ActiveRecord::TestCase + def setup + @connection = ActiveRecord::Base.connection + end + + def test_quote_returns_frozen_string + assert_predicate @connection.quote(true), :frozen? + assert_predicate @connection.quote(false), :frozen? + end + + def test_type_cast_returns_frozen_value + assert_predicate @connection.type_cast(true), :frozen? + assert_predicate @connection.type_cast(false), :frozen? + end + end end end diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb index 5f6eb41240..a93061b516 100644 --- a/activerecord/test/cases/readonly_test.rb +++ b/activerecord/test/cases/readonly_test.rb @@ -1,13 +1,13 @@ require "cases/helper" -require 'models/author' -require 'models/post' -require 'models/comment' -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/reader' -require 'models/person' -require 'models/ship' +require "models/author" +require "models/post" +require "models/comment" +require "models/developer" +require "models/computer" +require "models/project" +require "models/reader" +require "models/person" +require "models/ship" class ReadOnlyTest < ActiveRecord::TestCase fixtures :authors, :posts, :comments, :developers, :projects, :developers_projects, :people, :readers @@ -20,9 +20,9 @@ class ReadOnlyTest < ActiveRecord::TestCase assert dev.readonly? assert_nothing_raised do - dev.name = 'Luscious forbidden fruit.' + dev.name = "Luscious forbidden fruit." assert !dev.save - dev.name = 'Forbidden.' + dev.name = "Forbidden." end e = assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save } @@ -35,7 +35,6 @@ class ReadOnlyTest < ActiveRecord::TestCase assert_equal "Developer is marked as readonly", e.message end - def test_find_with_readonly_option Developer.all.each { |d| assert !d.readonly? } Developer.readonly(false).each { |d| assert !d.readonly? } @@ -44,11 +43,11 @@ class ReadOnlyTest < ActiveRecord::TestCase end def test_find_with_joins_option_does_not_imply_readonly - Developer.joins(' ').each { |d| assert_not d.readonly? } - Developer.joins(' ').readonly(true).each { |d| assert d.readonly? } + Developer.joins(" ").each { |d| assert_not d.readonly? } + Developer.joins(" ").readonly(true).each { |d| assert d.readonly? } - Developer.joins(', projects').each { |d| assert_not d.readonly? } - Developer.joins(', projects').readonly(true).each { |d| assert d.readonly? } + Developer.joins(", projects").each { |d| assert_not d.readonly? } + Developer.joins(", projects").readonly(true).each { |d| assert d.readonly? } end def test_has_many_find_readonly @@ -77,13 +76,13 @@ class ReadOnlyTest < ActiveRecord::TestCase end def test_readonly_scoping - Post.where('1=1').scoping do + Post.where("1=1").scoping do assert !Post.find(1).readonly? assert Post.readonly(true).find(1).readonly? assert !Post.readonly(false).find(1).readonly? end - Post.joins(' ').scoping do + Post.joins(" ").scoping do assert !Post.find(1).readonly? assert Post.readonly.find(1).readonly? assert !Post.readonly(false).find(1).readonly? @@ -92,7 +91,7 @@ class ReadOnlyTest < ActiveRecord::TestCase # Oracle barfs on this because the join includes unqualified and # conflicting column names unless current_adapter?(:OracleAdapter) - Post.joins(', developers').scoping do + Post.joins(", developers").scoping do assert_not Post.find(1).readonly? assert Post.readonly.find(1).readonly? assert !Post.readonly(false).find(1).readonly? diff --git a/activerecord/test/cases/reaper_test.rb b/activerecord/test/cases/reaper_test.rb index cccfc6774e..249878b67d 100644 --- a/activerecord/test/cases/reaper_test.rb +++ b/activerecord/test/cases/reaper_test.rb @@ -60,7 +60,7 @@ module ActiveRecord def test_connection_pool_starts_reaper spec = ActiveRecord::Base.connection_pool.spec.dup - spec.config[:reaping_frequency] = '0.0001' + spec.config[:reaping_frequency] = "0.0001" pool = ConnectionPool.new spec diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 710c86b151..5dac3d064b 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -1,30 +1,30 @@ require "cases/helper" -require 'models/topic' -require 'models/customer' -require 'models/company' -require 'models/company_in_module' -require 'models/ship' -require 'models/pirate' -require 'models/price_estimate' -require 'models/essay' -require 'models/author' -require 'models/organization' -require 'models/post' -require 'models/tagging' -require 'models/category' -require 'models/book' -require 'models/subscriber' -require 'models/subscription' -require 'models/tag' -require 'models/sponsor' -require 'models/edge' -require 'models/hotel' -require 'models/chef' -require 'models/department' -require 'models/cake_designer' -require 'models/drink_designer' -require 'models/mocktail_designer' -require 'models/recipe' +require "models/topic" +require "models/customer" +require "models/company" +require "models/company_in_module" +require "models/ship" +require "models/pirate" +require "models/price_estimate" +require "models/essay" +require "models/author" +require "models/organization" +require "models/post" +require "models/tagging" +require "models/category" +require "models/book" +require "models/subscriber" +require "models/subscription" +require "models/tag" +require "models/sponsor" +require "models/edge" +require "models/hotel" +require "models/chef" +require "models/department" +require "models/cake_designer" +require "models/drink_designer" +require "models/mocktail_designer" +require "models/recipe" class ReflectionTest < ActiveRecord::TestCase include ActiveRecord::Reflection @@ -100,7 +100,7 @@ class ReflectionTest < ActiveRecord::TestCase end def test_reflection_klass_for_nested_class_name - reflection = ActiveRecord::Reflection.create(:has_many, nil, nil, { :class_name => 'MyApplication::Business::Company' }, ActiveRecord::Base) + reflection = ActiveRecord::Reflection.create(:has_many, nil, nil, { class_name: "MyApplication::Business::Company" }, ActiveRecord::Base) assert_nothing_raised do assert_equal MyApplication::Business::Company, reflection.klass end @@ -108,28 +108,28 @@ class ReflectionTest < ActiveRecord::TestCase def test_irregular_reflection_class_name ActiveSupport::Inflector.inflections do |inflect| - inflect.irregular 'plural_irregular', 'plurales_irregulares' + inflect.irregular "plural_irregular", "plurales_irregulares" end - reflection = ActiveRecord::Reflection.create(:has_many, 'plurales_irregulares', nil, {}, ActiveRecord::Base) - assert_equal 'PluralIrregular', reflection.class_name + reflection = ActiveRecord::Reflection.create(:has_many, "plurales_irregulares", nil, {}, ActiveRecord::Base) + assert_equal "PluralIrregular", reflection.class_name end def test_aggregation_reflection reflection_for_address = AggregateReflection.new( - :address, nil, { :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer + :address, nil, { mapping: [ %w(address_street street), %w(address_city city), %w(address_country country) ] }, Customer ) reflection_for_balance = AggregateReflection.new( - :balance, nil, { :class_name => "Money", :mapping => %w(balance amount) }, Customer + :balance, nil, { class_name: "Money", mapping: %w(balance amount) }, Customer ) reflection_for_gps_location = AggregateReflection.new( - :gps_location, nil, { }, Customer + :gps_location, nil, {}, Customer ) - assert Customer.reflect_on_all_aggregations.include?(reflection_for_gps_location) - assert Customer.reflect_on_all_aggregations.include?(reflection_for_balance) - assert Customer.reflect_on_all_aggregations.include?(reflection_for_address) + assert_includes Customer.reflect_on_all_aggregations, reflection_for_gps_location + assert_includes Customer.reflect_on_all_aggregations, reflection_for_balance + assert_includes Customer.reflect_on_all_aggregations, reflection_for_address assert_equal reflection_for_address, Customer.reflect_on_aggregation(:address) @@ -148,31 +148,31 @@ class ReflectionTest < ActiveRecord::TestCase end def test_has_many_reflection - reflection_for_clients = ActiveRecord::Reflection.create(:has_many, :clients, nil, { :order => "id", :dependent => :destroy }, Firm) + reflection_for_clients = ActiveRecord::Reflection.create(:has_many, :clients, nil, { order: "id", dependent: :destroy }, Firm) assert_equal reflection_for_clients, Firm.reflect_on_association(:clients) assert_equal Client, Firm.reflect_on_association(:clients).klass - assert_equal 'companies', Firm.reflect_on_association(:clients).table_name + assert_equal "companies", Firm.reflect_on_association(:clients).table_name assert_equal Client, Firm.reflect_on_association(:clients_of_firm).klass - assert_equal 'companies', Firm.reflect_on_association(:clients_of_firm).table_name + assert_equal "companies", Firm.reflect_on_association(:clients_of_firm).table_name end def test_has_one_reflection - reflection_for_account = ActiveRecord::Reflection.create(:has_one, :account, nil, { :foreign_key => "firm_id", :dependent => :destroy }, Firm) + reflection_for_account = ActiveRecord::Reflection.create(:has_one, :account, nil, { foreign_key: "firm_id", dependent: :destroy }, Firm) assert_equal reflection_for_account, Firm.reflect_on_association(:account) assert_equal Account, Firm.reflect_on_association(:account).klass - assert_equal 'accounts', Firm.reflect_on_association(:account).table_name + assert_equal "accounts", Firm.reflect_on_association(:account).table_name end def test_belongs_to_inferred_foreign_key_from_assoc_name Company.belongs_to :foo assert_equal "foo_id", Company.reflect_on_association(:foo).foreign_key - Company.belongs_to :bar, :class_name => "Xyzzy" + Company.belongs_to :bar, class_name: "Xyzzy" assert_equal "bar_id", Company.reflect_on_association(:bar).foreign_key - Company.belongs_to :baz, :class_name => "Xyzzy", :foreign_key => "xyzzy_id" + Company.belongs_to :baz, class_name: "Xyzzy", foreign_key: "xyzzy_id" assert_equal "xyzzy_id", Company.reflect_on_association(:baz).foreign_key end @@ -181,45 +181,45 @@ class ReflectionTest < ActiveRecord::TestCase assert_reflection MyApplication::Business::Firm, :clients_of_firm, - :klass => MyApplication::Business::Client, - :class_name => 'Client', - :table_name => 'companies' + klass: MyApplication::Business::Client, + class_name: "Client", + table_name: "companies" assert_reflection MyApplication::Billing::Account, :firm, - :klass => MyApplication::Business::Firm, - :class_name => 'MyApplication::Business::Firm', - :table_name => 'companies' + klass: MyApplication::Business::Firm, + class_name: "MyApplication::Business::Firm", + table_name: "companies" assert_reflection MyApplication::Billing::Account, :qualified_billing_firm, - :klass => MyApplication::Billing::Firm, - :class_name => 'MyApplication::Billing::Firm', - :table_name => 'companies' + klass: MyApplication::Billing::Firm, + class_name: "MyApplication::Billing::Firm", + table_name: "companies" assert_reflection MyApplication::Billing::Account, :unqualified_billing_firm, - :klass => MyApplication::Billing::Firm, - :class_name => 'Firm', - :table_name => 'companies' + klass: MyApplication::Billing::Firm, + class_name: "Firm", + table_name: "companies" assert_reflection MyApplication::Billing::Account, :nested_qualified_billing_firm, - :klass => MyApplication::Billing::Nested::Firm, - :class_name => 'MyApplication::Billing::Nested::Firm', - :table_name => 'companies' + klass: MyApplication::Billing::Nested::Firm, + class_name: "MyApplication::Billing::Nested::Firm", + table_name: "companies" assert_reflection MyApplication::Billing::Account, :nested_unqualified_billing_firm, - :klass => MyApplication::Billing::Nested::Firm, - :class_name => 'Nested::Firm', - :table_name => 'companies' + klass: MyApplication::Billing::Nested::Firm, + class_name: "Nested::Firm", + table_name: "companies" ensure ActiveRecord::Base.store_full_sti_class = true end def test_reflection_should_not_raise_error_when_compared_to_other_object - assert_not_equal Object.new, Firm._reflections['clients'] + assert_not_equal Object.new, Firm._reflections["clients"] end def test_reflections_should_return_keys_as_strings @@ -227,7 +227,7 @@ class ReflectionTest < ActiveRecord::TestCase end def test_has_and_belongs_to_many_reflection - assert_equal :has_and_belongs_to_many, Category.reflections['posts'].macro + assert_equal :has_and_belongs_to_many, Category.reflections["posts"].macro assert_equal :posts, Category.reflect_on_all_associations(:has_and_belongs_to_many).first.name end @@ -366,21 +366,21 @@ class ReflectionTest < ActiveRecord::TestCase end def test_always_validate_association_if_explicit - assert ActiveRecord::Reflection.create(:has_one, :client, nil, { :validate => true }, Firm).validate? - assert ActiveRecord::Reflection.create(:belongs_to, :client, nil, { :validate => true }, Firm).validate? - assert ActiveRecord::Reflection.create(:has_many, :clients, nil, { :validate => true }, Firm).validate? + assert ActiveRecord::Reflection.create(:has_one, :client, nil, { validate: true }, Firm).validate? + assert ActiveRecord::Reflection.create(:belongs_to, :client, nil, { validate: true }, Firm).validate? + assert ActiveRecord::Reflection.create(:has_many, :clients, nil, { validate: true }, Firm).validate? end def test_validate_association_if_autosave - assert ActiveRecord::Reflection.create(:has_one, :client, nil, { :autosave => true }, Firm).validate? - assert ActiveRecord::Reflection.create(:belongs_to, :client, nil, { :autosave => true }, Firm).validate? - assert ActiveRecord::Reflection.create(:has_many, :clients, nil, { :autosave => true }, Firm).validate? + assert ActiveRecord::Reflection.create(:has_one, :client, nil, { autosave: true }, Firm).validate? + assert ActiveRecord::Reflection.create(:belongs_to, :client, nil, { autosave: true }, Firm).validate? + assert ActiveRecord::Reflection.create(:has_many, :clients, nil, { autosave: true }, Firm).validate? end def test_never_validate_association_if_explicit - assert !ActiveRecord::Reflection.create(:has_one, :client, nil, { :autosave => true, :validate => false }, Firm).validate? - assert !ActiveRecord::Reflection.create(:belongs_to, :client, nil, { :autosave => true, :validate => false }, Firm).validate? - assert !ActiveRecord::Reflection.create(:has_many, :clients, nil, { :autosave => true, :validate => false }, Firm).validate? + assert !ActiveRecord::Reflection.create(:has_one, :client, nil, { autosave: true, validate: false }, Firm).validate? + assert !ActiveRecord::Reflection.create(:belongs_to, :client, nil, { autosave: true, validate: false }, Firm).validate? + assert !ActiveRecord::Reflection.create(:has_many, :clients, nil, { autosave: true, validate: false }, Firm).validate? end def test_foreign_key @@ -399,62 +399,62 @@ class ReflectionTest < ActiveRecord::TestCase end def test_join_table - category = Struct.new(:table_name, :pluralize_table_names).new('categories', true) - product = Struct.new(:table_name, :pluralize_table_names).new('products', true) + category = Struct.new(:table_name, :pluralize_table_names).new("categories", true) + product = Struct.new(:table_name, :pluralize_table_names).new("products", true) reflection = ActiveRecord::Reflection.create(:has_many, :categories, nil, {}, product) reflection.stub(:klass, category) do - assert_equal 'categories_products', reflection.join_table + assert_equal "categories_products", reflection.join_table end reflection = ActiveRecord::Reflection.create(:has_many, :products, nil, {}, category) reflection.stub(:klass, product) do - assert_equal 'categories_products', reflection.join_table + assert_equal "categories_products", reflection.join_table end end def test_join_table_with_common_prefix - category = Struct.new(:table_name, :pluralize_table_names).new('catalog_categories', true) - product = Struct.new(:table_name, :pluralize_table_names).new('catalog_products', true) + category = Struct.new(:table_name, :pluralize_table_names).new("catalog_categories", true) + product = Struct.new(:table_name, :pluralize_table_names).new("catalog_products", true) reflection = ActiveRecord::Reflection.create(:has_many, :categories, nil, {}, product) reflection.stub(:klass, category) do - assert_equal 'catalog_categories_products', reflection.join_table + assert_equal "catalog_categories_products", reflection.join_table end reflection = ActiveRecord::Reflection.create(:has_many, :products, nil, {}, category) reflection.stub(:klass, product) do - assert_equal 'catalog_categories_products', reflection.join_table + assert_equal "catalog_categories_products", reflection.join_table end end def test_join_table_with_different_prefix - category = Struct.new(:table_name, :pluralize_table_names).new('catalog_categories', true) - page = Struct.new(:table_name, :pluralize_table_names).new('content_pages', true) + category = Struct.new(:table_name, :pluralize_table_names).new("catalog_categories", true) + page = Struct.new(:table_name, :pluralize_table_names).new("content_pages", true) reflection = ActiveRecord::Reflection.create(:has_many, :categories, nil, {}, page) reflection.stub(:klass, category) do - assert_equal 'catalog_categories_content_pages', reflection.join_table + assert_equal "catalog_categories_content_pages", reflection.join_table end reflection = ActiveRecord::Reflection.create(:has_many, :pages, nil, {}, category) reflection.stub(:klass, page) do - assert_equal 'catalog_categories_content_pages', reflection.join_table + assert_equal "catalog_categories_content_pages", reflection.join_table end end def test_join_table_can_be_overridden - category = Struct.new(:table_name, :pluralize_table_names).new('categories', true) - product = Struct.new(:table_name, :pluralize_table_names).new('products', true) + category = Struct.new(:table_name, :pluralize_table_names).new("categories", true) + product = Struct.new(:table_name, :pluralize_table_names).new("products", true) - reflection = ActiveRecord::Reflection.create(:has_many, :categories, nil, { :join_table => 'product_categories' }, product) + reflection = ActiveRecord::Reflection.create(:has_many, :categories, nil, { join_table: "product_categories" }, product) reflection.stub(:klass, category) do - assert_equal 'product_categories', reflection.join_table + assert_equal "product_categories", reflection.join_table end - reflection = ActiveRecord::Reflection.create(:has_many, :products, nil, { :join_table => 'product_categories' }, category) + reflection = ActiveRecord::Reflection.create(:has_many, :products, nil, { join_table: "product_categories" }, category) reflection.stub(:klass, product) do - assert_equal 'product_categories', reflection.join_table + assert_equal "product_categories", reflection.join_table end end @@ -474,7 +474,7 @@ class ReflectionTest < ActiveRecord::TestCase department.chefs.create! assert_nothing_raised do - assert_equal department.chefs, Hotel.includes(['departments' => 'chefs']).first.chefs + assert_equal department.chefs, Hotel.includes(["departments" => "chefs"]).first.chefs end end diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb index f0e07e0731..d2382b9bb2 100644 --- a/activerecord/test/cases/relation/delegation_test.rb +++ b/activerecord/test/cases/relation/delegation_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/post' -require 'models/comment' +require "cases/helper" +require "models/post" +require "models/comment" module ActiveRecord class DelegationTest < ActiveRecord::TestCase @@ -18,7 +18,7 @@ module ActiveRecord target.public_send(method, 1) end elsif method_arity == 1 - target.public_send(method, 1) + target.public_send(method, 1) else raise NotImplementedError end diff --git a/activerecord/test/cases/relation/merging_test.rb b/activerecord/test/cases/relation/merging_test.rb index 60a806c05a..278dac8171 100644 --- a/activerecord/test/cases/relation/merging_test.rb +++ b/activerecord/test/cases/relation/merging_test.rb @@ -1,20 +1,20 @@ -require 'cases/helper' -require 'models/author' -require 'models/comment' -require 'models/developer' -require 'models/computer' -require 'models/post' -require 'models/project' -require 'models/rating' +require "cases/helper" +require "models/author" +require "models/comment" +require "models/developer" +require "models/computer" +require "models/post" +require "models/project" +require "models/rating" class RelationMergingTest < ActiveRecord::TestCase fixtures :developers, :comments, :authors, :posts def test_relation_merging - devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order('id ASC').where("id < 3")) + devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order("id ASC").where("id < 3")) assert_equal [developers(:david), developers(:jamis)], devs.to_a - dev_with_count = Developer.limit(1).merge(Developer.order('id DESC')).merge(Developer.select('developers.*')) + dev_with_count = Developer.limit(1).merge(Developer.order("id DESC")).merge(Developer.select("developers.*")) assert_equal [developers(:poor_jamis)], dev_with_count.to_a end @@ -34,10 +34,10 @@ class RelationMergingTest < ActiveRecord::TestCase def test_relation_merging_with_arel_equalities_keeps_last_equality_with_non_attribute_left_hand salary_attr = Developer.arel_table[:salary] devs = Developer.where( - Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(80000) + Arel::Nodes::NamedFunction.new("abs", [salary_attr]).eq(80000) ).merge( Developer.where( - Arel::Nodes::NamedFunction.new('abs', [salary_attr]).eq(9000) + Arel::Nodes::NamedFunction.new("abs", [salary_attr]).eq(9000) ) ) assert_equal [developers(:poor_jamis)], devs.to_a @@ -45,8 +45,8 @@ class RelationMergingTest < ActiveRecord::TestCase def test_relation_merging_with_eager_load relations = [] - relations << Post.order('comments.id DESC').merge(Post.eager_load(:last_comment)).merge(Post.all) - relations << Post.eager_load(:last_comment).merge(Post.order('comments.id DESC')).merge(Post.all) + relations << Post.order("comments.id DESC").merge(Post.eager_load(:last_comment)).merge(Post.all) + relations << Post.eager_load(:last_comment).merge(Post.order("comments.id DESC")).merge(Post.all) relations.each do |posts| post = posts.find { |p| p.id == 1 } @@ -66,14 +66,14 @@ class RelationMergingTest < ActiveRecord::TestCase end def test_relation_merging_with_joins - comments = Comment.joins(:post).where(:body => 'Thank you for the welcome').merge(Post.where(:body => 'Such a lovely day')) + comments = Comment.joins(:post).where(body: "Thank you for the welcome").merge(Post.where(body: "Such a lovely day")) assert_equal 1, comments.count end def test_relation_merging_with_association assert_queries(2) do # one for loading post, and another one merged query - post = Post.where(:body => 'Such a lovely day').first - comments = Comment.where(:body => 'Thank you for the welcome').merge(post.comments) + post = Post.where(body: "Such a lovely day").first + comments = Comment.where(body: "Thank you for the welcome").merge(post.comments) assert_equal 1, comments.count end end @@ -86,9 +86,9 @@ class RelationMergingTest < ActiveRecord::TestCase merged = left.merge(right) assert_equal expected, merged.bound_attributes - assert !merged.to_sql.include?("omg") - assert merged.to_sql.include?("wtf") - assert merged.to_sql.include?("bbq") + assert_not_includes merged.to_sql, "omg" + assert_includes merged.to_sql, "wtf" + assert_includes merged.to_sql, "bbq" end def test_merging_reorders_bind_params diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb index ffb2da7a26..966ae83a3f 100644 --- a/activerecord/test/cases/relation/mutation_test.rb +++ b/activerecord/test/cases/relation/mutation_test.rb @@ -1,8 +1,8 @@ -require 'cases/helper' -require 'models/post' +require "cases/helper" +require "models/post" module ActiveRecord - class RelationMutationTest < ActiveSupport::TestCase + class RelationMutationTest < ActiveRecord::TestCase class FakeKlass < Struct.new(:table_name, :name) extend ActiveRecord::Delegation::DelegateCache inherited self @@ -33,7 +33,7 @@ module ActiveRecord end def relation - @relation ||= Relation.new FakeKlass.new('posts'), Post.arel_table, Post.predicate_builder + @relation ||= Relation.new FakeKlass.new("posts"), Post.arel_table, Post.predicate_builder end (Relation::MULTI_VALUE_METHODS - [:references, :extending, :order, :unscope, :select, :left_joins]).each do |method| @@ -44,16 +44,16 @@ module ActiveRecord end test "#_select!" do - assert relation.public_send("_select!", :foo).equal?(relation) - assert_equal [:foo], relation.public_send("select_values") + assert relation._select!(:foo).equal?(relation) + assert_equal [:foo], relation.select_values end - test '#order!' do - assert relation.order!('name ASC').equal?(relation) - assert_equal ['name ASC'], relation.order_values + test "#order!" do + assert relation.order!("name ASC").equal?(relation) + assert_equal ["name ASC"], relation.order_values end - test '#order! with symbol prepends the table name' do + test "#order! with symbol prepends the table name" do assert relation.order!(:name).equal?(relation) node = relation.order_values.first assert node.ascending? @@ -61,7 +61,7 @@ module ActiveRecord assert_equal "posts", node.expr.relation.name end - test '#order! on non-string does not attempt regexp match for references' do + test "#order! on non-string does not attempt regexp match for references" do obj = Object.new assert_not_called(obj, :=~) do assert relation.order!(obj) @@ -69,12 +69,12 @@ module ActiveRecord end end - test '#references!' do + test "#references!" do assert relation.references!(:foo).equal?(relation) - assert relation.references_values.include?('foo') + assert_includes relation.references_values, "foo" end - test 'extending!' do + test "extending!" do mod, mod2 = Module.new, Module.new assert relation.extending!(mod).equal?(relation) @@ -85,7 +85,7 @@ module ActiveRecord assert_equal [mod, mod2], relation.extending_values end - test 'extending! with empty args' do + test "extending! with empty args" do relation.extending! assert_equal [], relation.extending_values end @@ -97,25 +97,25 @@ module ActiveRecord end end - test '#from!' do - assert relation.from!('foo').equal?(relation) - assert_equal 'foo', relation.from_clause.value + test "#from!" do + assert relation.from!("foo").equal?(relation) + assert_equal "foo", relation.from_clause.value end - test '#lock!' do - assert relation.lock!('foo').equal?(relation) - assert_equal 'foo', relation.lock_value + test "#lock!" do + assert relation.lock!("foo").equal?(relation) + assert_equal "foo", relation.lock_value end - test '#reorder!' do - @relation = self.relation.order('foo') + test "#reorder!" do + @relation = self.relation.order("foo") - assert relation.reorder!('bar').equal?(relation) - assert_equal ['bar'], relation.order_values + assert relation.reorder!("bar").equal?(relation) + assert_equal ["bar"], relation.order_values assert relation.reordering_value end - test '#reorder! with symbol prepends the table name' do + test "#reorder! with symbol prepends the table name" do assert relation.reorder!(:name).equal?(relation) node = relation.order_values.first @@ -124,42 +124,41 @@ module ActiveRecord assert_equal "posts", node.expr.relation.name end - test 'reverse_order!' do - @relation = Post.order('title ASC, comments_count DESC') + test "reverse_order!" do + @relation = Post.order("title ASC, comments_count DESC") relation.reverse_order! - assert_equal 'title DESC', relation.order_values.first - assert_equal 'comments_count ASC', relation.order_values.last - + assert_equal "title DESC", relation.order_values.first + assert_equal "comments_count ASC", relation.order_values.last relation.reverse_order! - assert_equal 'title ASC', relation.order_values.first - assert_equal 'comments_count DESC', relation.order_values.last + assert_equal "title ASC", relation.order_values.first + assert_equal "comments_count DESC", relation.order_values.last end - test 'create_with!' do - assert relation.create_with!(foo: 'bar').equal?(relation) - assert_equal({foo: 'bar'}, relation.create_with_value) + test "create_with!" do + assert relation.create_with!(foo: "bar").equal?(relation) + assert_equal({ foo: "bar" }, relation.create_with_value) end - test 'test_merge!' do + test "test_merge!" do assert relation.merge!(select: :foo).equal?(relation) assert_equal [:foo], relation.select_values end - test 'merge with a proc' do + test "merge with a proc" do assert_equal [:foo], relation.merge(-> { select(:foo) }).select_values end - test 'none!' do + test "none!" do assert relation.none!.equal?(relation) assert_equal [NullRelation], relation.extending_values assert relation.is_a?(NullRelation) end - test 'distinct!' do + test "distinct!" do relation.distinct! :foo assert_equal :foo, relation.distinct_value @@ -168,7 +167,7 @@ module ActiveRecord end end - test 'uniq! was replaced by distinct!' do + test "uniq! was replaced by distinct!" do assert_deprecated(/use distinct! instead/) do relation.uniq! :foo end diff --git a/activerecord/test/cases/relation/or_test.rb b/activerecord/test/cases/relation/or_test.rb index ce8c5ca489..2796595523 100644 --- a/activerecord/test/cases/relation/or_test.rb +++ b/activerecord/test/cases/relation/or_test.rb @@ -1,28 +1,28 @@ require "cases/helper" -require 'models/post' +require "models/post" module ActiveRecord class OrTest < ActiveRecord::TestCase fixtures :posts def test_or_with_relation - expected = Post.where('id = 1 or id = 2').to_a - assert_equal expected, Post.where('id = 1').or(Post.where('id = 2')).to_a + expected = Post.where("id = 1 or id = 2").to_a + assert_equal expected, Post.where("id = 1").or(Post.where("id = 2")).to_a end def test_or_identity - expected = Post.where('id = 1').to_a - assert_equal expected, Post.where('id = 1').or(Post.where('id = 1')).to_a + expected = Post.where("id = 1").to_a + assert_equal expected, Post.where("id = 1").or(Post.where("id = 1")).to_a end def test_or_with_null_left - expected = Post.where('id = 1').to_a - assert_equal expected, Post.none.or(Post.where('id = 1')).to_a + expected = Post.where("id = 1").to_a + assert_equal expected, Post.none.or(Post.where("id = 1")).to_a end def test_or_with_null_right - expected = Post.where('id = 1').to_a - assert_equal expected, Post.where('id = 1').or(Post.none).to_a + expected = Post.where("id = 1").to_a + assert_equal expected, Post.where("id = 1").or(Post.none).to_a end def test_or_with_bind_params @@ -36,56 +36,56 @@ module ActiveRecord def test_or_without_left_where expected = Post.all - assert_equal expected, Post.or(Post.where('id = 1')).to_a + assert_equal expected, Post.or(Post.where("id = 1")).to_a end def test_or_without_right_where expected = Post.all - assert_equal expected, Post.where('id = 1').or(Post.all).to_a + assert_equal expected, Post.where("id = 1").or(Post.all).to_a end def test_or_preserves_other_querying_methods - expected = Post.where('id = 1 or id = 2 or id = 3').order('body asc').to_a - partial = Post.order('body asc') - assert_equal expected, partial.where('id = 1').or(partial.where(:id => [2, 3])).to_a - assert_equal expected, Post.order('body asc').where('id = 1').or(Post.order('body asc').where(:id => [2, 3])).to_a + expected = Post.where("id = 1 or id = 2 or id = 3").order("body asc").to_a + partial = Post.order("body asc") + assert_equal expected, partial.where("id = 1").or(partial.where(id: [2, 3])).to_a + assert_equal expected, Post.order("body asc").where("id = 1").or(Post.order("body asc").where(id: [2, 3])).to_a end def test_or_with_incompatible_relations error = assert_raises ArgumentError do - Post.order('body asc').where('id = 1').or(Post.order('id desc').where(:id => [2, 3])).to_a + Post.order("body asc").where("id = 1").or(Post.order("id desc").where(id: [2, 3])).to_a end assert_equal "Relation passed to #or must be structurally compatible. Incompatible values: [:order]", error.message end def test_or_when_grouping - groups = Post.where('id < 10').group('body').select('body, COUNT(*) AS c') - expected = groups.having("COUNT(*) > 1 OR body like 'Such%'").to_a.map {|o| [o.body, o.c] } - assert_equal expected, groups.having('COUNT(*) > 1').or(groups.having("body like 'Such%'")).to_a.map {|o| [o.body, o.c] } + groups = Post.where("id < 10").group("body").select("body, COUNT(*) AS c") + expected = groups.having("COUNT(*) > 1 OR body like 'Such%'").to_a.map { |o| [o.body, o.c] } + assert_equal expected, groups.having("COUNT(*) > 1").or(groups.having("body like 'Such%'")).to_a.map { |o| [o.body, o.c] } end def test_or_with_named_scope expected = Post.where("id = 1 or body LIKE '\%a\%'").to_a - assert_equal expected, Post.where('id = 1').or(Post.containing_the_letter_a) + assert_equal expected, Post.where("id = 1").or(Post.containing_the_letter_a) end def test_or_inside_named_scope - expected = Post.where("body LIKE '\%a\%' OR title LIKE ?", "%'%").order('id DESC').to_a + expected = Post.where("body LIKE '\%a\%' OR title LIKE ?", "%'%").order("id DESC").to_a assert_equal expected, Post.order(id: :desc).typographically_interesting end def test_or_on_loaded_relation - expected = Post.where('id = 1 or id = 2').to_a - p = Post.where('id = 1') + expected = Post.where("id = 1 or id = 2").to_a + p = Post.where("id = 1") p.load assert_equal p.loaded?, true - assert_equal expected, p.or(Post.where('id = 2')).to_a + assert_equal expected, p.or(Post.where("id = 2")).to_a end def test_or_with_non_relation_object_raises_error assert_raises ArgumentError do - Post.where(id: [1, 2, 3]).or(title: 'Rails') + Post.where(id: [1, 2, 3]).or(title: "Rails") end end end diff --git a/activerecord/test/cases/relation/predicate_builder_test.rb b/activerecord/test/cases/relation/predicate_builder_test.rb index 8f62014622..48758dc148 100644 --- a/activerecord/test/cases/relation/predicate_builder_test.rb +++ b/activerecord/test/cases/relation/predicate_builder_test.rb @@ -1,11 +1,11 @@ require "cases/helper" -require 'models/topic' +require "models/topic" module ActiveRecord class PredicateBuilderTest < ActiveRecord::TestCase def test_registering_new_handlers Topic.predicate_builder.register_handler(Regexp, proc do |column, value| - Arel::Nodes::InfixOperation.new('~', column, Arel.sql(value.source)) + Arel::Nodes::InfixOperation.new("~", column, Arel.sql(value.source)) end) assert_match %r{["`]topics["`]\.["`]title["`] ~ rails}i, Topic.where(title: /rails/).to_sql diff --git a/activerecord/test/cases/relation/record_fetch_warning_test.rb b/activerecord/test/cases/relation/record_fetch_warning_test.rb index 0e0e23b24b..62ca051431 100644 --- a/activerecord/test/cases/relation/record_fetch_warning_test.rb +++ b/activerecord/test/cases/relation/record_fetch_warning_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/post' -require 'active_record/relation/record_fetch_warning' +require "cases/helper" +require "models/post" +require "active_record/relation/record_fetch_warning" module ActiveRecord class RecordFetchWarningTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb index 27bbd80f79..a96d1ae5b5 100644 --- a/activerecord/test/cases/relation/where_chain_test.rb +++ b/activerecord/test/cases/relation/where_chain_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/post' -require 'models/comment' +require "cases/helper" +require "models/post" +require "models/comment" module ActiveRecord class WhereChainTest < ActiveRecord::TestCase @@ -8,12 +8,12 @@ module ActiveRecord def setup super - @name = 'title' + @name = "title" end def test_not_inverts_where_clause - relation = Post.where.not(title: 'hello') - expected_where_clause = Post.where(title: 'hello').where_clause.invert + relation = Post.where.not(title: "hello") + expected_where_clause = Post.where(title: "hello").where_clause.invert assert_equal expected_where_clause, relation.where_clause end @@ -26,54 +26,54 @@ module ActiveRecord def test_association_not_eq expected = Arel::Nodes::Grouping.new(Comment.arel_table[@name].not_eq(Arel::Nodes::BindParam.new)) - relation = Post.joins(:comments).where.not(comments: {title: 'hello'}) + relation = Post.joins(:comments).where.not(comments: { title: "hello" }) assert_equal(expected.to_sql, relation.where_clause.ast.to_sql) end def test_not_eq_with_preceding_where - relation = Post.where(title: 'hello').where.not(title: 'world') + relation = Post.where(title: "hello").where.not(title: "world") expected_where_clause = - Post.where(title: 'hello').where_clause + - Post.where(title: 'world').where_clause.invert + Post.where(title: "hello").where_clause + + Post.where(title: "world").where_clause.invert assert_equal expected_where_clause, relation.where_clause end def test_not_eq_with_succeeding_where - relation = Post.where.not(title: 'hello').where(title: 'world') + relation = Post.where.not(title: "hello").where(title: "world") expected_where_clause = - Post.where(title: 'hello').where_clause.invert + - Post.where(title: 'world').where_clause + Post.where(title: "hello").where_clause.invert + + Post.where(title: "world").where_clause assert_equal expected_where_clause, relation.where_clause end def test_chaining_multiple - relation = Post.where.not(author_id: [1, 2]).where.not(title: 'ruby on rails') + relation = Post.where.not(author_id: [1, 2]).where.not(title: "ruby on rails") expected_where_clause = Post.where(author_id: [1, 2]).where_clause.invert + - Post.where(title: 'ruby on rails').where_clause.invert + Post.where(title: "ruby on rails").where_clause.invert assert_equal expected_where_clause, relation.where_clause end def test_rewhere_with_one_condition - relation = Post.where(title: 'hello').where(title: 'world').rewhere(title: 'alone') - expected = Post.where(title: 'alone') + relation = Post.where(title: "hello").where(title: "world").rewhere(title: "alone") + expected = Post.where(title: "alone") assert_equal expected.where_clause, relation.where_clause end def test_rewhere_with_multiple_overwriting_conditions - relation = Post.where(title: 'hello').where(body: 'world').rewhere(title: 'alone', body: 'again') - expected = Post.where(title: 'alone', body: 'again') + relation = Post.where(title: "hello").where(body: "world").rewhere(title: "alone", body: "again") + expected = Post.where(title: "alone", body: "again") assert_equal expected.where_clause, relation.where_clause end def test_rewhere_with_one_overwriting_condition_and_one_unrelated - relation = Post.where(title: 'hello').where(body: 'world').rewhere(title: 'alone') - expected = Post.where(body: 'world', title: 'alone') + relation = Post.where(title: "hello").where(body: "world").rewhere(title: "alone") + expected = Post.where(body: "world", title: "alone") assert_equal expected.where_clause, relation.where_clause end diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb index c20ed94d90..d8e4c304f0 100644 --- a/activerecord/test/cases/relation/where_clause_test.rb +++ b/activerecord/test/cases/relation/where_clause_test.rb @@ -140,7 +140,7 @@ class ActiveRecord::Relation test "ast removes any empty strings" do where_clause = WhereClause.new([table["id"].in([1, 2, 3])], []) - where_clause_with_empty = WhereClause.new([table["id"].in([1, 2, 3]), ''], []) + where_clause_with_empty = WhereClause.new([table["id"].in([1, 2, 3]), ""], []) assert_equal where_clause.ast, where_clause_with_empty.ast end @@ -167,16 +167,16 @@ class ActiveRecord::Relation private - def table - Arel::Table.new("table") - end + def table + Arel::Table.new("table") + end - def bind_param - Arel::Nodes::BindParam.new - end + def bind_param + Arel::Nodes::BindParam.new + end - def attribute(name, value) - ActiveRecord::Attribute.with_cast_value(name, value, ActiveRecord::Type::Value.new) - end + def attribute(name, value) + ActiveRecord::Attribute.with_cast_value(name, value, ActiveRecord::Type::Value.new) + end end end diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb index 56a2b5b8c6..925af49ffe 100644 --- a/activerecord/test/cases/relation/where_test.rb +++ b/activerecord/test/cases/relation/where_test.rb @@ -4,10 +4,10 @@ require "models/binary" require "models/cake_designer" require "models/car" require "models/chef" +require "models/post" require "models/comment" require "models/edge" require "models/essay" -require "models/post" require "models/price_estimate" require "models/topic" require "models/treasure" @@ -19,7 +19,7 @@ module ActiveRecord def test_where_copies_bind_params author = authors(:david) - posts = author.posts.where('posts.id != 1') + posts = author.posts.where("posts.id != 1") joined = Post.where(id: posts) assert_operator joined.length, :>, 0 @@ -49,7 +49,7 @@ module ActiveRecord end def test_rewhere_on_root - assert_equal posts(:welcome), Post.rewhere(title: 'Welcome to the weblog').first + assert_equal posts(:welcome), Post.rewhere(title: "Welcome to the weblog").first end def test_belongs_to_shallow_where @@ -97,7 +97,7 @@ module ActiveRecord treasure = Treasure.new treasure.id = 1 - expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: 1) + expected = PriceEstimate.where(estimate_of_type: "Treasure", estimate_of_id: 1) actual = PriceEstimate.where(estimate_of: treasure) assert_equal expected.to_sql, actual.to_sql @@ -109,7 +109,7 @@ module ActiveRecord hidden = HiddenTreasure.new hidden.id = 2 - expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: [treasure, hidden]) + expected = PriceEstimate.where(estimate_of_type: "Treasure", estimate_of_id: [treasure, hidden]) actual = PriceEstimate.where(estimate_of: [treasure, hidden]) assert_equal expected.to_sql, actual.to_sql @@ -127,7 +127,7 @@ module ActiveRecord end def test_polymorphic_nested_relation_where - expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: Treasure.where(id: [1,2])) + expected = PriceEstimate.where(estimate_of_type: "Treasure", estimate_of_id: Treasure.where(id: [1,2])) actual = PriceEstimate.where(estimate_of: Treasure.where(id: [1,2])) assert_equal expected.to_sql, actual.to_sql @@ -137,7 +137,7 @@ module ActiveRecord treasure = HiddenTreasure.new treasure.id = 1 - expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: 1) + expected = PriceEstimate.where(estimate_of_type: "Treasure", estimate_of_id: 1) actual = PriceEstimate.where(estimate_of: treasure) assert_equal expected.to_sql, actual.to_sql @@ -147,7 +147,7 @@ module ActiveRecord thing = Post.new thing.id = 1 - expected = Treasure.where(price_estimates: { thing_type: 'Post', thing_id: 1 }).joins(:price_estimates) + expected = Treasure.where(price_estimates: { thing_type: "Post", thing_id: 1 }).joins(:price_estimates) actual = Treasure.where(price_estimates: { thing: thing }).joins(:price_estimates) assert_equal expected.to_sql, actual.to_sql @@ -157,7 +157,7 @@ module ActiveRecord treasure = HiddenTreasure.new treasure.id = 1 - expected = Treasure.where(price_estimates: { estimate_of_type: 'Treasure', estimate_of_id: 1 }).joins(:price_estimates) + expected = Treasure.where(price_estimates: { estimate_of_type: "Treasure", estimate_of_id: 1 }).joins(:price_estimates) actual = Treasure.where(price_estimates: { estimate_of: treasure }).joins(:price_estimates) assert_equal expected.to_sql, actual.to_sql @@ -182,40 +182,40 @@ module ActiveRecord treasure.id = 1 decorated_treasure = treasure_decorator.new(treasure) - expected = PriceEstimate.where(estimate_of_type: 'Treasure', estimate_of_id: 1) + expected = PriceEstimate.where(estimate_of_type: "Treasure", estimate_of_id: 1) actual = PriceEstimate.where(estimate_of: decorated_treasure) assert_equal expected.to_sql, actual.to_sql end def test_aliased_attribute - expected = Topic.where(heading: 'The First Topic') - actual = Topic.where(title: 'The First Topic') + expected = Topic.where(heading: "The First Topic") + actual = Topic.where(title: "The First Topic") assert_equal expected.to_sql, actual.to_sql end def test_where_error - assert_raises(ActiveRecord::StatementInvalid) do - Post.where(:id => { 'posts.author_id' => 10 }).first + assert_nothing_raised do + Post.where(id: { "posts.author_id" => 10 }).first end end def test_where_with_table_name post = Post.first - assert_equal post, Post.where(:posts => { 'id' => post.id }).first + assert_equal post, Post.where(posts: { "id" => post.id }).first end def test_where_with_table_name_and_empty_hash - assert_equal 0, Post.where(:posts => {}).count + assert_equal 0, Post.where(posts: {}).count end def test_where_with_table_name_and_empty_array - assert_equal 0, Post.where(:id => []).count + assert_equal 0, Post.where(id: []).count end def test_where_with_empty_hash_and_no_foreign_key - assert_equal 0, Edge.where(:sink => {}).count + assert_equal 0, Edge.where(sink: {}).count end def test_where_with_blank_conditions @@ -225,32 +225,32 @@ module ActiveRecord end def test_where_with_integer_for_string_column - count = Post.where(:title => 0).count + count = Post.where(title: 0).count assert_equal 0, count end def test_where_with_float_for_string_column - count = Post.where(:title => 0.0).count + count = Post.where(title: 0.0).count assert_equal 0, count end def test_where_with_boolean_for_string_column - count = Post.where(:title => false).count + count = Post.where(title: false).count assert_equal 0, count end def test_where_with_decimal_for_string_column - count = Post.where(:title => BigDecimal.new(0)).count + count = Post.where(title: BigDecimal.new(0)).count assert_equal 0, count end def test_where_with_duration_for_string_column - count = Post.where(:title => 0.seconds).count + count = Post.where(title: 0.seconds).count assert_equal 0, count end def test_where_with_integer_for_binary_column - count = Binary.where(:data => 0).count + count = Binary.where(data: 0).count assert_equal 0, count end diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 03583344a8..23d27ab90a 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -1,8 +1,8 @@ require "cases/helper" -require 'models/post' -require 'models/comment' -require 'models/author' -require 'models/rating' +require "models/post" +require "models/comment" +require "models/author" +require "models/rating" module ActiveRecord class RelationTest < ActiveRecord::TestCase @@ -18,7 +18,7 @@ module ActiveRecord end def self.table_name - 'fake_table' + "fake_table" end def self.sanitize_sql_for_order(sql) @@ -30,7 +30,7 @@ module ActiveRecord relation = Relation.new(FakeKlass, :b, nil) assert_equal FakeKlass, relation.klass assert_equal :b, relation.table - assert !relation.loaded, 'relation is not loaded' + assert !relation.loaded, "relation is not loaded" end def test_responds_to_model_and_returns_klass @@ -40,9 +40,10 @@ module ActiveRecord def test_initialize_single_values relation = Relation.new(FakeKlass, :b, nil) - (Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |method| + (Relation::SINGLE_VALUE_METHODS - [:create_with, :readonly]).each do |method| assert_nil relation.send("#{method}_value"), method.to_s end + assert_equal false, relation.readonly_value value = relation.create_with_value assert_equal({}, value) assert_predicate value, :frozen? @@ -70,7 +71,7 @@ module ActiveRecord def test_has_values relation = Relation.new(Post, Post.arel_table, Post.predicate_builder) relation.where! relation.table[:id].eq(10) - assert_equal({:id => 10}, relation.where_values_hash) + assert_equal({ id: 10 }, relation.where_values_hash) end def test_values_wrong_table @@ -89,8 +90,8 @@ module ActiveRecord end def test_table_name_delegates_to_klass - relation = Relation.new(FakeKlass.new('posts'), :b, Post.predicate_builder) - assert_equal 'posts', relation.table_name + relation = Relation.new(FakeKlass.new("posts"), :b, Post.predicate_builder) + assert_equal "posts", relation.table_name end def test_scope_for_create @@ -100,7 +101,7 @@ module ActiveRecord def test_create_with_value relation = Relation.new(Post, Post.arel_table, Post.predicate_builder) - hash = { :hello => 'world' } + hash = { hello: "world" } relation.create_with_value = hash assert_equal hash, relation.scope_for_create end @@ -108,8 +109,8 @@ module ActiveRecord def test_create_with_value_with_wheres relation = Relation.new(Post, Post.arel_table, Post.predicate_builder) relation.where! relation.table[:id].eq(10) - relation.create_with_value = {:hello => 'world'} - assert_equal({:hello => 'world', :id => 10}, relation.scope_for_create) + relation.create_with_value = { hello: "world" } + assert_equal({ hello: "world", id: 10 }, relation.scope_for_create) end # FIXME: is this really wanted or expected behavior? @@ -120,7 +121,7 @@ module ActiveRecord relation.where! relation.table[:id].eq(10) assert_equal({}, relation.scope_for_create) - relation.create_with_value = {:hello => 'world'} + relation.create_with_value = { hello: "world" } assert_equal({}, relation.scope_for_create) end @@ -145,48 +146,48 @@ module ActiveRecord relation = Relation.new(FakeKlass, :b, nil) assert_equal [], relation.references_values relation = relation.references(:foo).references(:omg, :lol) - assert_equal ['foo', 'omg', 'lol'], relation.references_values + assert_equal ["foo", "omg", "lol"], relation.references_values end def test_references_values_dont_duplicate relation = Relation.new(FakeKlass, :b, nil) relation = relation.references(:foo).references(:foo) - assert_equal ['foo'], relation.references_values + assert_equal ["foo"], relation.references_values end - test 'merging a hash into a relation' do + test "merging a hash into a relation" do relation = Relation.new(Post, Post.arel_table, Post.predicate_builder) - relation = relation.merge where: {name: :lol}, readonly: true + relation = relation.merge where: { name: :lol }, readonly: true - assert_equal({"name"=>:lol}, relation.where_clause.to_h) + assert_equal({ "name"=>:lol }, relation.where_clause.to_h) assert_equal true, relation.readonly_value end - test 'merging an empty hash into a relation' do + test "merging an empty hash into a relation" do assert_equal Relation::WhereClause.empty, Relation.new(FakeKlass, :b, nil).merge({}).where_clause end - test 'merging a hash with unknown keys raises' do - assert_raises(ArgumentError) { Relation::HashMerger.new(nil, omg: 'lol') } + test "merging a hash with unknown keys raises" do + assert_raises(ArgumentError) { Relation::HashMerger.new(nil, omg: "lol") } end - test 'merging nil or false raises' do + test "merging nil or false raises" do relation = Relation.new(FakeKlass, :b, nil) e = assert_raises(ArgumentError) do relation = relation.merge nil end - assert_equal 'invalid argument: nil.', e.message + assert_equal "invalid argument: nil.", e.message e = assert_raises(ArgumentError) do relation = relation.merge false end - assert_equal 'invalid argument: false.', e.message + assert_equal "invalid argument: false.", e.message end - test '#values returns a dup of the values' do + test "#values returns a dup of the values" do relation = Relation.new(Post, Post.arel_table, Post.predicate_builder).where!(name: :foo) values = relation.values @@ -194,22 +195,22 @@ module ActiveRecord assert_not_nil relation.where_clause end - test 'relations can be created with a values hash' do + test "relations can be created with a values hash" do relation = Relation.new(FakeKlass, :b, nil, select: [:foo]) assert_equal [:foo], relation.select_values end - test 'merging a hash interpolates conditions' do + test "merging a hash interpolates conditions" do klass = Class.new(FakeKlass) do def self.sanitize_sql(args) - raise unless args == ['foo = ?', 'bar'] - 'foo = bar' + raise unless args == ["foo = ?", "bar"] + "foo = bar" end end relation = Relation.new(klass, :b, nil) - relation.merge!(where: ['foo = ?', 'bar']) - assert_equal Relation::WhereClause.new(['foo = bar'], []), relation.where_clause + relation.merge!(where: ["foo = ?", "bar"]) + assert_equal Relation::WhereClause.new(["foo = bar"], []), relation.where_clause end def test_merging_readonly_false @@ -223,7 +224,7 @@ module ActiveRecord def test_relation_merging_with_merged_joins_as_symbols special_comments_with_ratings = SpecialComment.joins(:ratings) posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings) - assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length + assert_equal({ 2=>1, 4=>3, 5=>1 }, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count) end def test_relation_merging_with_joins_as_join_dependency_pick_proper_parent @@ -273,7 +274,7 @@ module ActiveRecord join_string = "LEFT OUTER JOIN #{Rating.quoted_table_name} ON #{SpecialComment.quoted_table_name}.id = #{Rating.quoted_table_name}.comment_id" special_comments_with_ratings = SpecialComment.joins join_string posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings) - assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length + assert_equal({ 2=>1, 4=>3, 5=>1 }, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count) end class EnsureRoundTripTypeCasting < ActiveRecord::Type::Value @@ -293,7 +294,7 @@ module ActiveRecord end class UpdateAllTestModel < ActiveRecord::Base - self.table_name = 'posts' + self.table_name = "posts" attribute :body, EnsureRoundTripTypeCasting.new end @@ -306,23 +307,23 @@ module ActiveRecord private - def skip_if_sqlite3_version_includes_quoting_bug - if sqlite3_version_includes_quoting_bug? - skip <<-ERROR.squish - You are using an outdated version of SQLite3 which has a bug in - quoted column names. Please update SQLite3 and rebuild the sqlite3 - ruby gem - ERROR + def skip_if_sqlite3_version_includes_quoting_bug + if sqlite3_version_includes_quoting_bug? + skip <<-ERROR.squish + You are using an outdated version of SQLite3 which has a bug in + quoted column names. Please update SQLite3 and rebuild the sqlite3 + ruby gem + ERROR + end end - end - def sqlite3_version_includes_quoting_bug? - if current_adapter?(:SQLite3Adapter) - selected_quoted_column_names = ActiveRecord::Base.connection.exec_query( - 'SELECT "join" FROM (SELECT id AS "join" FROM posts) subquery' - ).columns - ["join"] != selected_quoted_column_names + def sqlite3_version_includes_quoting_bug? + if current_adapter?(:SQLite3Adapter) + selected_quoted_column_names = ActiveRecord::Base.connection.exec_query( + 'SELECT "join" FROM (SELECT id AS "join" FROM posts) subquery' + ).columns + ["join"] != selected_quoted_column_names + end end - end end end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 5604124bb3..2e18c43b1b 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1,21 +1,21 @@ require "cases/helper" -require 'models/tag' -require 'models/tagging' -require 'models/post' -require 'models/topic' -require 'models/comment' -require 'models/author' -require 'models/entrant' -require 'models/developer' -require 'models/computer' -require 'models/reply' -require 'models/company' -require 'models/bird' -require 'models/car' -require 'models/engine' -require 'models/tyre' -require 'models/minivan' -require 'models/aircraft' +require "models/tag" +require "models/tagging" +require "models/post" +require "models/topic" +require "models/comment" +require "models/author" +require "models/entrant" +require "models/developer" +require "models/computer" +require "models/reply" +require "models/company" +require "models/bird" +require "models/car" +require "models/engine" +require "models/tyre" +require "models/minivan" +require "models/aircraft" require "models/possession" require "models/reader" require "models/categorization" @@ -27,19 +27,19 @@ class RelationTest < ActiveRecord::TestCase class TopicWithCallbacks < ActiveRecord::Base self.table_name = :topics - before_update { |topic| topic.author_name = 'David' if topic.author_name.blank? } + before_update { |topic| topic.author_name = "David" if topic.author_name.blank? } end def test_do_not_double_quote_string_id van = Minivan.last assert van - assert_equal van.id, Minivan.where(:minivan_id => van).to_a.first.minivan_id + assert_equal van.id, Minivan.where(minivan_id: van).to_a.first.minivan_id end def test_do_not_double_quote_string_id_with_array van = Minivan.last assert van - assert_equal van, Minivan.where(:minivan_id => [van]).to_a.first + assert_equal van, Minivan.where(minivan_id: [van]).to_a.first end def test_two_scopes_with_includes_should_not_drop_any_include @@ -54,12 +54,12 @@ class RelationTest < ActiveRecord::TestCase end def test_dynamic_finder - x = Post.where('author_id = ?', 1) - assert x.klass.respond_to?(:find_by_id), '@klass should handle dynamic finders' + x = Post.where("author_id = ?", 1) + assert x.klass.respond_to?(:find_by_id), "@klass should handle dynamic finders" end def test_multivalue_where - posts = Post.where('author_id = ? AND id = ?', 1, 1) + posts = Post.where("author_id = ? AND id = ?", 1, 1) assert_equal 1, posts.to_a.size end @@ -101,7 +101,7 @@ class RelationTest < ActiveRecord::TestCase end def test_scoped_first - topics = Topic.all.order('id ASC') + topics = Topic.all.order("id ASC") assert_queries(1) do 2.times { assert_equal "The First Topic", topics.first.title } @@ -111,7 +111,7 @@ class RelationTest < ActiveRecord::TestCase end def test_loaded_first - topics = Topic.all.order('id ASC') + topics = Topic.all.order("id ASC") topics.to_a # force load assert_no_queries do @@ -122,7 +122,7 @@ class RelationTest < ActiveRecord::TestCase end def test_loaded_first_with_limit - topics = Topic.all.order('id ASC') + topics = Topic.all.order("id ASC") topics.to_a # force load assert_no_queries do @@ -134,7 +134,7 @@ class RelationTest < ActiveRecord::TestCase end def test_first_get_more_than_available - topics = Topic.all.order('id ASC') + topics = Topic.all.order("id ASC") unloaded_first = topics.first(10) topics.to_a # force load @@ -154,7 +154,7 @@ class RelationTest < ActiveRecord::TestCase assert topics.loaded? original_size = topics.to_a.size - Topic.create! :title => 'fake' + Topic.create! title: "fake" assert_queries(1) { topics.reload } assert_equal original_size + 1, topics.size @@ -162,17 +162,17 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_subquery - relation = Topic.where(:approved => true) - assert_equal relation.to_a, Topic.select('*').from(relation).to_a - assert_equal relation.to_a, Topic.select('subquery.*').from(relation).to_a - assert_equal relation.to_a, Topic.select('a.*').from(relation, :a).to_a + relation = Topic.where(approved: true) + assert_equal relation.to_a, Topic.select("*").from(relation).to_a + assert_equal relation.to_a, Topic.select("subquery.*").from(relation).to_a + assert_equal relation.to_a, Topic.select("a.*").from(relation, :a).to_a end def test_finding_with_subquery_with_binds relation = Post.first.comments - assert_equal relation.to_a, Comment.select('*').from(relation).to_a - assert_equal relation.to_a, Comment.select('subquery.*').from(relation).to_a - assert_equal relation.to_a, Comment.select('a.*').from(relation, :a).to_a + assert_equal relation.to_a, Comment.select("*").from(relation).to_a + assert_equal relation.to_a, Comment.select("subquery.*").from(relation).to_a + assert_equal relation.to_a, Comment.select("a.*").from(relation, :a).to_a end def test_finding_with_subquery_without_select_does_not_change_the_select @@ -183,25 +183,25 @@ class RelationTest < ActiveRecord::TestCase end def test_select_with_subquery_in_from_does_not_use_original_table_name - relation = Comment.group(:type).select('COUNT(post_id) AS post_count, type') - subquery = Comment.from(relation).select('type','post_count') + relation = Comment.group(:type).select("COUNT(post_id) AS post_count, type") + subquery = Comment.from(relation).select("type","post_count") assert_equal(relation.map(&:post_count).sort,subquery.map(&:post_count).sort) end def test_group_with_subquery_in_from_does_not_use_original_table_name - relation = Comment.group(:type).select('COUNT(post_id) AS post_count,type') - subquery = Comment.from(relation).group('type').average("post_count") + relation = Comment.group(:type).select("COUNT(post_id) AS post_count,type") + subquery = Comment.from(relation).group("type").average("post_count") assert_equal(relation.map(&:post_count).sort,subquery.values.sort) end def test_finding_with_conditions - assert_equal ["David"], Author.where(:name => 'David').map(&:name) - assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name) - assert_equal ['Mary'], Author.where("name = ?", 'Mary').map(&:name) + assert_equal ["David"], Author.where(name: "David").map(&:name) + assert_equal ["Mary"], Author.where(["name = ?", "Mary"]).map(&:name) + assert_equal ["Mary"], Author.where("name = ?", "Mary").map(&:name) end def test_finding_with_order - topics = Topic.order('id') + topics = Topic.order("id") assert_equal 5, topics.to_a.size assert_equal topics(:first).title, topics.first.title end @@ -213,13 +213,13 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_assoc_order - topics = Topic.order(:id => :desc) + topics = Topic.order(id: :desc) assert_equal 5, topics.to_a.size assert_equal topics(:fifth).title, topics.first.title end def test_finding_with_reverted_assoc_order - topics = Topic.order(:id => :asc).reverse_order + topics = Topic.order(id: :asc).reverse_order assert_equal 5, topics.to_a.size assert_equal topics(:fifth).title, topics.first.title end @@ -240,6 +240,15 @@ class RelationTest < ActiveRecord::TestCase assert_raises(ActiveRecord::IrreversibleOrderError) do Topic.order("concat(author_name, title)").reverse_order end + assert_raises(ActiveRecord::IrreversibleOrderError) do + Topic.order("concat(lower(author_name), title)").reverse_order + end + assert_raises(ActiveRecord::IrreversibleOrderError) do + Topic.order("concat(author_name, lower(title))").reverse_order + end + assert_raises(ActiveRecord::IrreversibleOrderError) do + Topic.order("concat(lower(author_name), title, length(title)").reverse_order + end end def test_reverse_order_with_nulls_first_or_last @@ -258,7 +267,7 @@ class RelationTest < ActiveRecord::TestCase end def test_order_with_hash_and_symbol_generates_the_same_sql - assert_equal Topic.order(:id).to_sql, Topic.order(:id => :asc).to_sql + assert_equal Topic.order(:id).to_sql, Topic.order(id: :asc).to_sql end def test_finding_with_desc_order_with_string @@ -268,7 +277,7 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_asc_order_with_string - topics = Topic.order(id: 'asc') + topics = Topic.order(id: "asc") assert_equal 5, topics.to_a.size assert_equal [topics(:first), topics(:second), topics(:third), topics(:fourth), topics(:fifth)], topics.to_a end @@ -296,7 +305,7 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_order_concatenated - topics = Topic.order('author_name').order('title') + topics = Topic.order("author_name").order("title") assert_equal 5, topics.to_a.size assert_equal topics(:fourth).title, topics.first.title end @@ -314,19 +323,19 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_reorder - topics = Topic.order('author_name').order('title').reorder('id').to_a + topics = Topic.order("author_name").order("title").reorder("id").to_a topics_titles = topics.map(&:title) - assert_equal ['The First Topic', 'The Second Topic of the day', 'The Third Topic of the day', 'The Fourth Topic of the day', 'The Fifth Topic of the day'], topics_titles + assert_equal ["The First Topic", "The Second Topic of the day", "The Third Topic of the day", "The Fourth Topic of the day", "The Fifth Topic of the day"], topics_titles end def test_finding_with_reorder_by_aliased_attributes - topics = Topic.order('author_name').reorder(:heading) + topics = Topic.order("author_name").reorder(:heading) assert_equal 5, topics.to_a.size assert_equal topics(:fifth).title, topics.first.title end def test_finding_with_assoc_reorder_by_aliased_attributes - topics = Topic.order('author_name').reorder(heading: :desc) + topics = Topic.order("author_name").reorder(heading: :desc) assert_equal 5, topics.to_a.size assert_equal topics(:third).title, topics.first.title end @@ -384,7 +393,7 @@ class RelationTest < ActiveRecord::TestCase end def test_select_with_block - even_ids = Developer.all.select {|d| d.id % 2 == 0 }.map(&:id) + even_ids = Developer.all.select { |d| d.id % 2 == 0 }.map(&:id) assert_equal [2, 4, 6, 8, 10], even_ids.sort end @@ -397,7 +406,7 @@ class RelationTest < ActiveRecord::TestCase def test_none_chainable assert_no_queries(ignore_none: false) do - assert_equal [], Developer.none.where(:name => 'David') + assert_equal [], Developer.none.where(name: "David") end end @@ -411,7 +420,7 @@ class RelationTest < ActiveRecord::TestCase assert_no_queries(ignore_none: false) do assert_equal [], Developer.none.pluck(:id, :name) assert_equal 0, Developer.none.delete_all - assert_equal 0, Developer.none.update_all(:name => 'David') + assert_equal 0, Developer.none.update_all(name: "David") assert_equal 0, Developer.none.delete(1) assert_equal false, Developer.none.exists?(1) end @@ -433,7 +442,7 @@ class RelationTest < ActiveRecord::TestCase assert_no_queries(ignore_none: false) do assert_equal 0, Developer.none.count assert_equal 0, Developer.none.calculate(:count, nil) - assert_equal nil, Developer.none.calculate(:average, 'salary') + assert_equal nil, Developer.none.calculate(:average, "salary") end end @@ -443,7 +452,7 @@ class RelationTest < ActiveRecord::TestCase end def test_null_relation_where_values_hash - assert_equal({ 'salary' => 100_000 }, Developer.none.where(salary: 100_000).where_values_hash) + assert_equal({ "salary" => 100_000 }, Developer.none.where(salary: 100_000).where_values_hash) end def test_null_relation_sum @@ -510,23 +519,23 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_hash_conditions_on_joined_table - firms = DependentFirm.joins(:account).where({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a + firms = DependentFirm.joins(:account).where(name: "RailsCore", accounts: { credit_limit: 55..60 }).to_a assert_equal 1, firms.size assert_equal companies(:rails_core), firms.first end def test_find_all_with_join - developers_on_project_one = Developer.joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id'). - where('project_id=1').to_a + developers_on_project_one = Developer.joins("LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id"). + where("project_id=1").to_a assert_equal 3, developers_on_project_one.length developer_names = developers_on_project_one.map(&:name) - assert developer_names.include?('David') - assert developer_names.include?('Jamis') + assert_includes developer_names, "David" + assert_includes developer_names, "Jamis" end def test_find_on_hash_conditions - assert_equal Topic.all.merge!(:where => {:approved => false}).to_a, Topic.where({ :approved => false }).to_a + assert_equal Topic.all.merge!(where: { approved: false }).to_a, Topic.where(approved: false).to_a end def test_joins_with_string_array @@ -565,7 +574,7 @@ class RelationTest < ActiveRecord::TestCase def test_respond_to_delegates_to_relation relation = Topic.all fake_arel = Struct.new(:responds) { - def respond_to? method, access = false + def respond_to?(method, access = false) responds << [method, access] end }.new [] @@ -599,8 +608,8 @@ class RelationTest < ActiveRecord::TestCase end def test_eager_association_loading_of_stis_with_multiple_references - authors = Author.eager_load(:posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } }). - order('comments.body, very_special_comments_posts.body').where('posts.id = 4').to_a + authors = Author.eager_load(posts: { special_comments: { post: [ :special_comments, :very_special_comment ] } }). + order("comments.body, very_special_comments_posts.body").where("posts.id = 4").to_a assert_equal [authors(:david)], authors assert_no_queries do @@ -611,27 +620,27 @@ class RelationTest < ActiveRecord::TestCase def test_find_with_preloaded_associations assert_queries(2) do - posts = Post.preload(:comments).order('posts.id') + posts = Post.preload(:comments).order("posts.id") assert posts.first.comments.first end assert_queries(2) do - posts = Post.preload(:comments).order('posts.id') + posts = Post.preload(:comments).order("posts.id") assert posts.first.comments.first end assert_queries(2) do - posts = Post.preload(:author).order('posts.id') + posts = Post.preload(:author).order("posts.id") assert posts.first.author end assert_queries(2) do - posts = Post.preload(:author).order('posts.id') + posts = Post.preload(:author).order("posts.id") assert posts.first.author end assert_queries(3) do - posts = Post.preload(:author, :comments).order('posts.id') + posts = Post.preload(:author, :comments).order("posts.id") assert posts.first.author assert posts.first.comments.first end @@ -646,58 +655,58 @@ class RelationTest < ActiveRecord::TestCase def test_find_with_included_associations assert_queries(2) do - posts = Post.includes(:comments).order('posts.id') + posts = Post.includes(:comments).order("posts.id") assert posts.first.comments.first end assert_queries(2) do - posts = Post.all.includes(:comments).order('posts.id') + posts = Post.all.includes(:comments).order("posts.id") assert posts.first.comments.first end assert_queries(2) do - posts = Post.includes(:author).order('posts.id') + posts = Post.includes(:author).order("posts.id") assert posts.first.author end assert_queries(3) do - posts = Post.includes(:author, :comments).order('posts.id') + posts = Post.includes(:author, :comments).order("posts.id") assert posts.first.author assert posts.first.comments.first end end def test_default_scope_with_conditions_string - assert_equal Developer.where(name: 'David').map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort + assert_equal Developer.where(name: "David").map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort assert_nil DeveloperCalledDavid.create!.name end def test_default_scope_with_conditions_hash - assert_equal Developer.where(name: 'Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort - assert_equal 'Jamis', DeveloperCalledJamis.create!.name + assert_equal Developer.where(name: "Jamis").map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort + assert_equal "Jamis", DeveloperCalledJamis.create!.name end def test_default_scoping_finder_methods - developers = DeveloperCalledDavid.order('id').map(&:id).sort - assert_equal Developer.where(name: 'David').map(&:id).sort, developers + developers = DeveloperCalledDavid.order("id").map(&:id).sort + assert_equal Developer.where(name: "David").map(&:id).sort, developers end def test_includes_with_select - query = Post.select('comments_count AS ranking').order('ranking').includes(:comments) + query = Post.select("comments_count AS ranking").order("ranking").includes(:comments) .where(comments: { id: 1 }) - assert_equal ['comments_count AS ranking'], query.select_values + assert_equal ["comments_count AS ranking"], query.select_values assert_equal 1, query.to_a.size end def test_preloading_with_associations_and_merges - post = Post.create! title: 'Uhuu', body: 'body' + post = Post.create! title: "Uhuu", body: "body" reader = Reader.create! post_id: post.id, person_id: 1 - comment = Comment.create! post_id: post.id, body: 'body' + comment = Comment.create! post_id: post.id, body: "body" assert !comment.respond_to?(:readers) - post_rel = Post.preload(:readers).joins(:readers).where(title: 'Uhuu') + post_rel = Post.preload(:readers).joins(:readers).where(title: "Uhuu") result_comment = Comment.joins(:post).merge(post_rel).to_a.first assert_equal comment, result_comment @@ -706,7 +715,7 @@ class RelationTest < ActiveRecord::TestCase assert_equal [reader], result_comment.post.readers.to_a end - post_rel = Post.includes(:readers).where(title: 'Uhuu') + post_rel = Post.includes(:readers).where(title: "Uhuu") result_comment = Comment.joins(:post).merge(post_rel).first assert_equal comment, result_comment @@ -717,17 +726,17 @@ class RelationTest < ActiveRecord::TestCase end def test_preloading_with_associations_default_scopes_and_merges - post = Post.create! title: 'Uhuu', body: 'body' + post = Post.create! title: "Uhuu", body: "body" reader = Reader.create! post_id: post.id, person_id: 1 - post_rel = PostWithPreloadDefaultScope.preload(:readers).joins(:readers).where(title: 'Uhuu') + post_rel = PostWithPreloadDefaultScope.preload(:readers).joins(:readers).where(title: "Uhuu") result_post = PostWithPreloadDefaultScope.all.merge(post_rel).to_a.first assert_no_queries do assert_equal [reader], result_post.readers.to_a end - post_rel = PostWithIncludesDefaultScope.includes(:readers).where(title: 'Uhuu') + post_rel = PostWithIncludesDefaultScope.includes(:readers).where(title: "Uhuu") result_post = PostWithIncludesDefaultScope.all.merge(post_rel).to_a.first assert_no_queries do @@ -739,11 +748,11 @@ class RelationTest < ActiveRecord::TestCase posts = Post.preload(:comments) post = posts.find { |p| p.id == 1 } assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) post = Post.where("posts.title = 'Welcome to the weblog'").preload(:comments).first assert_equal 2, post.comments.size - assert post.comments.include?(comments(:greetings)) + assert_includes post.comments, comments(:greetings) posts = Post.preload(:last_comment) post = posts.find { |p| p.id == 1 } @@ -752,9 +761,9 @@ class RelationTest < ActiveRecord::TestCase def test_to_sql_on_eager_join expected = assert_sql { - Post.eager_load(:last_comment).order('comments.id DESC').to_a + Post.eager_load(:last_comment).order("comments.id DESC").to_a }.first - actual = Post.eager_load(:last_comment).order('comments.id DESC').to_sql + actual = Post.eager_load(:last_comment).order("comments.id DESC").to_sql assert_equal expected, actual end @@ -765,7 +774,7 @@ class RelationTest < ActiveRecord::TestCase end def test_loading_with_one_association_with_non_preload - posts = Post.eager_load(:last_comment).order('comments.id DESC') + posts = Post.eager_load(:last_comment).order("comments.id DESC") post = posts.find { |p| p.id == 1 } assert_equal Post.find(1).last_comment, post.last_comment end @@ -789,40 +798,40 @@ class RelationTest < ActiveRecord::TestCase author = Author.all.find_by_id!(authors(:david).id) assert_equal "David", author.name - assert_raises(ActiveRecord::RecordNotFound) { Author.all.find_by_id_and_name!(20, 'invalid') } + assert_raises(ActiveRecord::RecordNotFound) { Author.all.find_by_id_and_name!(20, "invalid") } end def test_find_id authors = Author.all david = authors.find(authors(:david).id) - assert_equal 'David', david.name + assert_equal "David", david.name - assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('42') } + assert_raises(ActiveRecord::RecordNotFound) { authors.where(name: "lifo").find("42") } end def test_find_ids - authors = Author.order('id ASC') + authors = Author.order("id ASC") results = authors.find(authors(:david).id, authors(:mary).id) assert_kind_of Array, results assert_equal 2, results.size - assert_equal 'David', results[0].name - assert_equal 'Mary', results[1].name + assert_equal "David", results[0].name + assert_equal "Mary", results[1].name assert_equal results, authors.find([authors(:david).id, authors(:mary).id]) - assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, '42') } - assert_raises(ActiveRecord::RecordNotFound) { authors.find(['42', 43]) } + assert_raises(ActiveRecord::RecordNotFound) { authors.where(name: "lifo").find(authors(:david).id, "42") } + assert_raises(ActiveRecord::RecordNotFound) { authors.find(["42", 43]) } end def test_find_in_empty_array - authors = Author.all.where(:id => []) + authors = Author.all.where(id: []) assert authors.to_a.blank? end def test_where_with_ar_object author = Author.first - authors = Author.all.where(:id => author) + authors = Author.all.where(id: author) assert_equal 1, authors.to_a.length end @@ -835,9 +844,9 @@ class RelationTest < ActiveRecord::TestCase class Mary < Author; end def test_find_by_classname - Author.create!(:name => Mary.name) + Author.create!(name: Mary.name) assert_deprecated do - assert_equal 1, Author.where(:name => Mary).size + assert_equal 1, Author.where(name: Mary).size end end @@ -850,25 +859,25 @@ class RelationTest < ActiveRecord::TestCase def test_find_all_using_where_twice_should_or_the_relation david = authors(:david) relation = Author.unscoped - relation = relation.where(:name => david.name) - relation = relation.where(:name => 'Santiago') - relation = relation.where(:id => david.id) + relation = relation.where(name: david.name) + relation = relation.where(name: "Santiago") + relation = relation.where(id: david.id) assert_equal [], relation.to_a end def test_multi_where_ands_queries relation = Author.unscoped david = authors(:david) - sql = relation.where(:name => david.name).where(:name => 'Santiago').to_sql - assert_match('AND', sql) + sql = relation.where(name: david.name).where(name: "Santiago").to_sql + assert_match("AND", sql) end def test_find_all_with_multiple_should_use_and david = authors(:david) relation = [ - { :name => david.name }, - { :name => 'Santiago' }, - { :name => 'tenderlove' }, + { name: david.name }, + { name: "Santiago" }, + { name: "tenderlove" }, ].inject(Author.unscoped) do |memo, param| memo.where(param) end @@ -887,17 +896,17 @@ class RelationTest < ActiveRecord::TestCase # switching the lines below would succeed in current rails # assert_queries(2) { assert_queries(1) { - relation = Author.where(:id => Author.where(:id => david.id)) + relation = Author.where(id: Author.where(id: david.id)) assert_equal [david], relation.to_a } assert_queries(1) { - relation = Author.where('id in (?)', Author.where(id: david).select(:id)) + relation = Author.where("id in (?)", Author.where(id: david).select(:id)) assert_equal [david], relation.to_a } assert_queries(1) do - relation = Author.where('id in (:author_ids)', author_ids: Author.where(id: david).select(:id)) + relation = Author.where("id in (:author_ids)", author_ids: Author.where(id: david).select(:id)) assert_equal [david], relation.to_a end end @@ -912,13 +921,13 @@ class RelationTest < ActiveRecord::TestCase end assert_queries(1) do - relation = Post.where('id in (?)', david.posts.select(:id)) - assert_equal davids_posts, relation.order(:id).to_a, 'should process Relation as bind variables' + relation = Post.where("id in (?)", david.posts.select(:id)) + assert_equal davids_posts, relation.order(:id).to_a, "should process Relation as bind variables" end assert_queries(1) do - relation = Post.where('id in (:post_ids)', post_ids: david.posts.select(:id)) - assert_equal davids_posts, relation.order(:id).to_a, 'should process Relation as named bind variables' + relation = Post.where("id in (:post_ids)", post_ids: david.posts.select(:id)) + assert_equal davids_posts, relation.order(:id).to_a, "should process Relation as named bind variables" end end @@ -927,7 +936,7 @@ class RelationTest < ActiveRecord::TestCase # switching the lines below would succeed in current rails # assert_queries(2) { assert_queries(1) { - relation = Minivan.where(:minivan_id => Minivan.where(:name => cool_first.name)) + relation = Minivan.where(minivan_id: Minivan.where(name: cool_first.name)) assert_equal [cool_first], relation.to_a } end @@ -935,10 +944,10 @@ class RelationTest < ActiveRecord::TestCase def test_find_all_using_where_with_relation_does_not_alter_select_values david = authors(:david) - subquery = Author.where(:id => david.id) + subquery = Author.where(id: david.id) assert_queries(1) { - relation = Author.where(:id => subquery) + relation = Author.where(id: subquery) assert_equal [david], relation.to_a } @@ -948,22 +957,21 @@ class RelationTest < ActiveRecord::TestCase def test_find_all_using_where_with_relation_with_joins david = authors(:david) assert_queries(1) { - relation = Author.where(:id => Author.joins(:posts).where(:id => david.id)) + relation = Author.where(id: Author.joins(:posts).where(id: david.id)) assert_equal [david], relation.to_a } end - def test_find_all_using_where_with_relation_with_select_to_build_subquery david = authors(:david) assert_queries(1) { - relation = Author.where(:name => Author.where(:id => david.id).select(:name)) + relation = Author.where(name: Author.where(id: david.id).select(:name)) assert_equal [david], relation.to_a } end def test_exists - davids = Author.where(:name => 'David') + davids = Author.where(name: "David") assert davids.exists? assert davids.exists?(authors(:david).id) assert ! davids.exists?(authors(:mary).id) @@ -971,7 +979,7 @@ class RelationTest < ActiveRecord::TestCase assert ! davids.exists?(42) assert ! davids.exists?(davids.new.id) - fake = Author.where(:name => 'fake author') + fake = Author.where(name: "fake author") assert ! fake.exists? assert ! fake.exists?(authors(:david).id) end @@ -994,13 +1002,13 @@ class RelationTest < ActiveRecord::TestCase end def test_destroy_all - davids = Author.where(:name => 'David') + davids = Author.where(name: "David") # Force load assert_equal [authors(:david)], davids.to_a assert davids.loaded? - assert_difference('Author.count', -1) { davids.destroy_all } + assert_difference("Author.count", -1) { davids.destroy_all } assert_equal [], davids.to_a assert davids.loaded? @@ -1008,31 +1016,31 @@ class RelationTest < ActiveRecord::TestCase def test_destroy_all_with_conditions_is_deprecated assert_deprecated do - assert_difference('Author.count', -1) { Author.destroy_all(name: 'David') } + assert_difference("Author.count", -1) { Author.destroy_all(name: "David") } end end def test_delete_all - davids = Author.where(:name => 'David') + davids = Author.where(name: "David") - assert_difference('Author.count', -1) { davids.delete_all } + assert_difference("Author.count", -1) { davids.delete_all } assert ! davids.loaded? end def test_delete_all_with_conditions_is_deprecated assert_deprecated do - assert_difference('Author.count', -1) { Author.delete_all(name: 'David') } + assert_difference("Author.count", -1) { Author.delete_all(name: "David") } end end def test_delete_all_loaded - davids = Author.where(:name => 'David') + davids = Author.where(name: "David") # Force load assert_equal [authors(:david)], davids.to_a assert davids.loaded? - assert_difference('Author.count', -1) { davids.delete_all } + assert_difference("Author.count", -1) { davids.delete_all } assert_equal [], davids.to_a assert davids.loaded? @@ -1042,7 +1050,7 @@ class RelationTest < ActiveRecord::TestCase assert_raises(ActiveRecord::ActiveRecordError) { Author.limit(10).delete_all } assert_raises(ActiveRecord::ActiveRecordError) { Author.distinct.delete_all } assert_raises(ActiveRecord::ActiveRecordError) { Author.group(:name).delete_all } - assert_raises(ActiveRecord::ActiveRecordError) { Author.having('SUM(id) < 3').delete_all } + assert_raises(ActiveRecord::ActiveRecordError) { Author.having("SUM(id) < 3").delete_all } assert_raises(ActiveRecord::ActiveRecordError) { Author.offset(10).delete_all } end @@ -1082,8 +1090,8 @@ class RelationTest < ActiveRecord::TestCase assert_equal 11, posts.count(:all) assert_equal 11, posts.count(:id) - assert_equal 1, posts.where('comments_count > 1').count - assert_equal 9, posts.where(:comments_count => 0).count + assert_equal 1, posts.where("comments_count > 1").count + assert_equal 9, posts.where(comments_count: 0).count end def test_count_with_block @@ -1117,24 +1125,24 @@ class RelationTest < ActiveRecord::TestCase Post.tagged_with(tag.id).update_all title: "rofl" list = Post.tagged_with(tag.id).all.to_a assert_operator list.length, :>, 0 - list.each { |post| assert_equal 'rofl', post.title } + list.each { |post| assert_equal "rofl", post.title } end def test_count_explicit_columns - Post.update_all(:comments_count => nil) + Post.update_all(comments_count: nil) posts = Post.all - assert_equal [0], posts.select('comments_count').where('id is not null').group('id').order('id').count.values.uniq - assert_equal 0, posts.where('id is not null').select('comments_count').count + assert_equal [0], posts.select("comments_count").where("id is not null").group("id").order("id").count.values.uniq + assert_equal 0, posts.where("id is not null").select("comments_count").count - assert_equal 11, posts.select('comments_count').count('id') - assert_equal 0, posts.select('comments_count').count + assert_equal 11, posts.select("comments_count").count("id") + assert_equal 0, posts.select("comments_count").count assert_equal 0, posts.count(:comments_count) - assert_equal 0, posts.count('comments_count') + assert_equal 0, posts.count("comments_count") end def test_multiple_selects - post = Post.all.select('comments_count').select('title').order("id ASC").first + post = Post.all.select("comments_count").select("title").order("id ASC").first assert_equal "Welcome to the weblog", post.title assert_equal 2, post.comments_count end @@ -1145,7 +1153,7 @@ class RelationTest < ActiveRecord::TestCase assert_queries(1) { assert_equal 11, posts.size } assert ! posts.loaded? - best_posts = posts.where(:comments_count => 0) + best_posts = posts.where(comments_count: 0) best_posts.to_a # force load assert_no_queries { assert_equal 9, best_posts.size } end @@ -1156,7 +1164,7 @@ class RelationTest < ActiveRecord::TestCase assert_queries(1) { assert_equal 10, posts.size } assert ! posts.loaded? - best_posts = posts.where(:comments_count => 0) + best_posts = posts.where(comments_count: 0) best_posts.to_a # force load assert_no_queries { assert_equal 9, best_posts.size } end @@ -1179,7 +1187,7 @@ class RelationTest < ActiveRecord::TestCase end def test_count_complex_chained_relations - posts = Post.select('comments_count').where('id is not null').group("author_id").where("comments_count > 0") + posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0") expected = { 1 => 2 } assert_equal expected, posts.count @@ -1191,11 +1199,11 @@ class RelationTest < ActiveRecord::TestCase assert_queries(1) { assert_equal false, posts.empty? } assert ! posts.loaded? - no_posts = posts.where(:title => "") + no_posts = posts.where(title: "") assert_queries(1) { assert_equal true, no_posts.empty? } assert ! no_posts.loaded? - best_posts = posts.where(:comments_count => 0) + best_posts = posts.where(comments_count: 0) best_posts.to_a # force load assert_no_queries { assert_equal false, best_posts.empty? } end @@ -1206,7 +1214,7 @@ class RelationTest < ActiveRecord::TestCase assert_queries(1) { assert_equal false, posts.empty? } assert ! posts.loaded? - no_posts = posts.where(:title => "") + no_posts = posts.where(title: "") assert_queries(1) { assert_equal true, no_posts.empty? } assert ! no_posts.loaded? end @@ -1220,14 +1228,14 @@ class RelationTest < ActiveRecord::TestCase # the SHOW TABLES result to be cached so we don't have to do it again in the block. # # This is obviously a rubbish fix but it's the best I can come up with for now... - posts.where(:id => nil).any? + posts.where(id: nil).any? assert_queries(3) do assert posts.any? # Uses COUNT() - assert ! posts.where(:id => nil).any? + assert ! posts.where(id: nil).any? - assert posts.any? {|p| p.id > 0 } - assert ! posts.any? {|p| p.id <= 0 } + assert posts.any? { |p| p.id > 0 } + assert ! posts.any? { |p| p.id <= 0 } end assert posts.loaded? @@ -1238,8 +1246,8 @@ class RelationTest < ActiveRecord::TestCase assert_queries(2) do assert posts.many? # Uses COUNT() - assert posts.many? {|p| p.id > 0 } - assert ! posts.many? {|p| p.id < 2 } + assert posts.many? { |p| p.id > 0 } + assert ! posts.many? { |p| p.id < 2 } end assert posts.loaded? @@ -1261,8 +1269,8 @@ class RelationTest < ActiveRecord::TestCase assert ! posts.loaded? assert_queries(1) do - assert posts.none? {|p| p.id < 0 } - assert ! posts.none? {|p| p.id == 1 } + assert posts.none? { |p| p.id < 0 } + assert ! posts.none? { |p| p.id == 1 } end assert posts.loaded? @@ -1277,8 +1285,8 @@ class RelationTest < ActiveRecord::TestCase assert ! posts.loaded? assert_queries(1) do - assert ! posts.one? {|p| p.id < 3 } - assert posts.one? {|p| p.id == 1 } + assert ! posts.one? { |p| p.id < 3 } + assert posts.one? { |p| p.id == 1 } end assert posts.loaded? @@ -1302,11 +1310,11 @@ class RelationTest < ActiveRecord::TestCase end def test_scoped_build - posts = Post.where(:title => 'You told a lie') + posts = Post.where(title: "You told a lie") post = posts.new assert_kind_of Post, post - assert_equal 'You told a lie', post.title + assert_equal "You told a lie", post.title end def test_create @@ -1316,9 +1324,9 @@ class RelationTest < ActiveRecord::TestCase assert_kind_of Bird, sparrow assert !sparrow.persisted? - hen = birds.where(:name => 'hen').create + hen = birds.where(name: "hen").create assert hen.persisted? - assert_equal 'hen', hen.name + assert_equal "hen", hen.name end def test_create_bang @@ -1326,201 +1334,201 @@ class RelationTest < ActiveRecord::TestCase assert_raises(ActiveRecord::RecordInvalid) { birds.create! } - hen = birds.where(:name => 'hen').create! + hen = birds.where(name: "hen").create! assert_kind_of Bird, hen assert hen.persisted? - assert_equal 'hen', hen.name + assert_equal "hen", hen.name end def test_first_or_create - parrot = Bird.where(:color => 'green').first_or_create(:name => 'parrot') + parrot = Bird.where(color: "green").first_or_create(name: "parrot") assert_kind_of Bird, parrot assert parrot.persisted? - assert_equal 'parrot', parrot.name - assert_equal 'green', parrot.color + assert_equal "parrot", parrot.name + assert_equal "green", parrot.color - same_parrot = Bird.where(:color => 'green').first_or_create(:name => 'parakeet') + same_parrot = Bird.where(color: "green").first_or_create(name: "parakeet") assert_kind_of Bird, same_parrot assert same_parrot.persisted? assert_equal parrot, same_parrot end def test_first_or_create_with_no_parameters - parrot = Bird.where(:color => 'green').first_or_create + parrot = Bird.where(color: "green").first_or_create assert_kind_of Bird, parrot assert !parrot.persisted? - assert_equal 'green', parrot.color + assert_equal "green", parrot.color end def test_first_or_create_with_block - parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parrot' } + parrot = Bird.where(color: "green").first_or_create { |bird| bird.name = "parrot" } assert_kind_of Bird, parrot assert parrot.persisted? - assert_equal 'green', parrot.color - assert_equal 'parrot', parrot.name + assert_equal "green", parrot.color + assert_equal "parrot", parrot.name - same_parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parakeet' } + same_parrot = Bird.where(color: "green").first_or_create { |bird| bird.name = "parakeet" } assert_equal parrot, same_parrot end def test_first_or_create_with_array - several_green_birds = Bird.where(:color => 'green').first_or_create([{:name => 'parrot'}, {:name => 'parakeet'}]) + several_green_birds = Bird.where(color: "green").first_or_create([{ name: "parrot" }, { name: "parakeet" }]) assert_kind_of Array, several_green_birds several_green_birds.each { |bird| assert bird.persisted? } - same_parrot = Bird.where(:color => 'green').first_or_create([{:name => 'hummingbird'}, {:name => 'macaw'}]) + same_parrot = Bird.where(color: "green").first_or_create([{ name: "hummingbird" }, { name: "macaw" }]) assert_kind_of Bird, same_parrot assert_equal several_green_birds.first, same_parrot end def test_first_or_create_bang_with_valid_options - parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parrot') + parrot = Bird.where(color: "green").first_or_create!(name: "parrot") assert_kind_of Bird, parrot assert parrot.persisted? - assert_equal 'parrot', parrot.name - assert_equal 'green', parrot.color + assert_equal "parrot", parrot.name + assert_equal "green", parrot.color - same_parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parakeet') + same_parrot = Bird.where(color: "green").first_or_create!(name: "parakeet") assert_kind_of Bird, same_parrot assert same_parrot.persisted? assert_equal parrot, same_parrot end def test_first_or_create_bang_with_invalid_options - assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!(:pirate_id => 1) } + assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create!(pirate_id: 1) } end def test_first_or_create_bang_with_no_parameters - assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create! } + assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create! } end def test_first_or_create_bang_with_valid_block - parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parrot' } + parrot = Bird.where(color: "green").first_or_create! { |bird| bird.name = "parrot" } assert_kind_of Bird, parrot assert parrot.persisted? - assert_equal 'green', parrot.color - assert_equal 'parrot', parrot.name + assert_equal "green", parrot.color + assert_equal "parrot", parrot.name - same_parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parakeet' } + same_parrot = Bird.where(color: "green").first_or_create! { |bird| bird.name = "parakeet" } assert_equal parrot, same_parrot end def test_first_or_create_bang_with_invalid_block assert_raise(ActiveRecord::RecordInvalid) do - Bird.where(:color => 'green').first_or_create! { |bird| bird.pirate_id = 1 } + Bird.where(color: "green").first_or_create! { |bird| bird.pirate_id = 1 } end end def test_first_or_create_with_valid_array - several_green_birds = Bird.where(:color => 'green').first_or_create!([{:name => 'parrot'}, {:name => 'parakeet'}]) + several_green_birds = Bird.where(color: "green").first_or_create!([{ name: "parrot" }, { name: "parakeet" }]) assert_kind_of Array, several_green_birds several_green_birds.each { |bird| assert bird.persisted? } - same_parrot = Bird.where(:color => 'green').first_or_create!([{:name => 'hummingbird'}, {:name => 'macaw'}]) + same_parrot = Bird.where(color: "green").first_or_create!([{ name: "hummingbird" }, { name: "macaw" }]) assert_kind_of Bird, same_parrot assert_equal several_green_birds.first, same_parrot end def test_first_or_create_with_invalid_array - assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!([ {:name => 'parrot'}, {:pirate_id => 1} ]) } + assert_raises(ActiveRecord::RecordInvalid) { Bird.where(color: "green").first_or_create!([ { name: "parrot" }, { pirate_id: 1 } ]) } end def test_first_or_initialize - parrot = Bird.where(:color => 'green').first_or_initialize(:name => 'parrot') + parrot = Bird.where(color: "green").first_or_initialize(name: "parrot") assert_kind_of Bird, parrot assert !parrot.persisted? assert parrot.valid? assert parrot.new_record? - assert_equal 'parrot', parrot.name - assert_equal 'green', parrot.color + assert_equal "parrot", parrot.name + assert_equal "green", parrot.color end def test_first_or_initialize_with_no_parameters - parrot = Bird.where(:color => 'green').first_or_initialize + parrot = Bird.where(color: "green").first_or_initialize assert_kind_of Bird, parrot assert !parrot.persisted? assert !parrot.valid? assert parrot.new_record? - assert_equal 'green', parrot.color + assert_equal "green", parrot.color end def test_first_or_initialize_with_block - parrot = Bird.where(:color => 'green').first_or_initialize { |bird| bird.name = 'parrot' } + parrot = Bird.where(color: "green").first_or_initialize { |bird| bird.name = "parrot" } assert_kind_of Bird, parrot assert !parrot.persisted? assert parrot.valid? assert parrot.new_record? - assert_equal 'green', parrot.color - assert_equal 'parrot', parrot.name + assert_equal "green", parrot.color + assert_equal "parrot", parrot.name end def test_find_or_create_by - assert_nil Bird.find_by(name: 'bob') + assert_nil Bird.find_by(name: "bob") - bird = Bird.find_or_create_by(name: 'bob') + bird = Bird.find_or_create_by(name: "bob") assert bird.persisted? - assert_equal bird, Bird.find_or_create_by(name: 'bob') + assert_equal bird, Bird.find_or_create_by(name: "bob") end def test_find_or_create_by_with_create_with - assert_nil Bird.find_by(name: 'bob') + assert_nil Bird.find_by(name: "bob") - bird = Bird.create_with(color: 'green').find_or_create_by(name: 'bob') + bird = Bird.create_with(color: "green").find_or_create_by(name: "bob") assert bird.persisted? - assert_equal 'green', bird.color + assert_equal "green", bird.color - assert_equal bird, Bird.create_with(color: 'blue').find_or_create_by(name: 'bob') + assert_equal bird, Bird.create_with(color: "blue").find_or_create_by(name: "bob") end def test_find_or_create_by! - assert_raises(ActiveRecord::RecordInvalid) { Bird.find_or_create_by!(color: 'green') } + assert_raises(ActiveRecord::RecordInvalid) { Bird.find_or_create_by!(color: "green") } end def test_find_or_initialize_by - assert_nil Bird.find_by(name: 'bob') + assert_nil Bird.find_by(name: "bob") - bird = Bird.find_or_initialize_by(name: 'bob') + bird = Bird.find_or_initialize_by(name: "bob") assert bird.new_record? bird.save! - assert_equal bird, Bird.find_or_initialize_by(name: 'bob') + assert_equal bird, Bird.find_or_initialize_by(name: "bob") end def test_explicit_create_scope - hens = Bird.where(:name => 'hen') - assert_equal 'hen', hens.new.name + hens = Bird.where(name: "hen") + assert_equal "hen", hens.new.name - hens = hens.create_with(:name => 'cock') - assert_equal 'cock', hens.new.name + hens = hens.create_with(name: "cock") + assert_equal "cock", hens.new.name end def test_except - relation = Post.where(:author_id => 1).order('id ASC').limit(1) + relation = Post.where(author_id: 1).order("id ASC").limit(1) assert_equal [posts(:welcome)], relation.to_a author_posts = relation.except(:order, :limit) - assert_equal Post.where(:author_id => 1).to_a, author_posts.to_a + assert_equal Post.where(author_id: 1).to_a, author_posts.to_a all_posts = relation.except(:where, :order, :limit) assert_equal Post.all, all_posts end def test_only - relation = Post.where(:author_id => 1).order('id ASC').limit(1) + relation = Post.where(author_id: 1).order("id ASC").limit(1) assert_equal [posts(:welcome)], relation.to_a author_posts = relation.only(:where) - assert_equal Post.where(:author_id => 1).to_a, author_posts.to_a + assert_equal Post.where(author_id: 1).to_a, author_posts.to_a all_posts = relation.only(:limit) - assert_equal Post.limit(1).to_a.first, all_posts.first + assert_equal Post.limit(1).to_a, all_posts.to_a end def test_anonymous_extension - relation = Post.where(:author_id => 1).order('id ASC').extending do + relation = Post.where(author_id: 1).order("id ASC").extending do def author - 'lifo' + "lifo" end end @@ -1529,7 +1537,7 @@ class RelationTest < ActiveRecord::TestCase end def test_named_extension - relation = Post.where(:author_id => 1).order('id ASC').extending(Post::NamedExtension) + relation = Post.where(author_id: 1).order("id ASC").extending(Post::NamedExtension) assert_equal "lifo", relation.author assert_equal "lifo", relation.limit(1).author end @@ -1539,29 +1547,29 @@ class RelationTest < ActiveRecord::TestCase end def test_default_scope_order_with_scope_order - assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name - assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name + assert_equal "zyke", CoolCar.order_using_new_style.limit(1).first.name + assert_equal "zyke", FastCar.order_using_new_style.limit(1).first.name end def test_order_using_scoping - car1 = CoolCar.order('id DESC').scoping do - CoolCar.all.merge!(order: 'id asc').first + car1 = CoolCar.order("id DESC").scoping do + CoolCar.all.merge!(order: "id asc").first end - assert_equal 'zyke', car1.name + assert_equal "zyke", car1.name - car2 = FastCar.order('id DESC').scoping do - FastCar.all.merge!(order: 'id asc').first + car2 = FastCar.order("id DESC").scoping do + FastCar.all.merge!(order: "id asc").first end - assert_equal 'zyke', car2.name + assert_equal "zyke", car2.name end def test_unscoped_block_style - assert_equal 'honda', CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name} - assert_equal 'honda', FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name} + assert_equal "honda", CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name } + assert_equal "honda", FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name } end def test_intersection_with_array - relation = Author.where(:name => "David") + relation = Author.where(name: "David") rails_author = relation.first assert_equal [rails_author], [rails_author] & relation @@ -1573,7 +1581,7 @@ class RelationTest < ActiveRecord::TestCase end def test_ordering_with_extra_spaces - assert_equal authors(:david), Author.order('id DESC , name DESC').last + assert_equal authors(:david), Author.order("id DESC , name DESC").last end def test_update_all_with_blank_argument @@ -1581,87 +1589,87 @@ class RelationTest < ActiveRecord::TestCase end def test_update_all_with_joins - comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id) + comments = Comment.joins(:post).where("posts.id" => posts(:welcome).id) count = comments.count - assert_equal count, comments.update_all(:post_id => posts(:thinking).id) + assert_equal count, comments.update_all(post_id: posts(:thinking).id) assert_equal posts(:thinking), comments(:greetings).post end def test_update_all_with_joins_and_limit - comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).limit(1) - assert_equal 1, comments.update_all(:post_id => posts(:thinking).id) + comments = Comment.joins(:post).where("posts.id" => posts(:welcome).id).limit(1) + assert_equal 1, comments.update_all(post_id: posts(:thinking).id) end def test_update_all_with_joins_and_limit_and_order - comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('comments.id').limit(1) - assert_equal 1, comments.update_all(:post_id => posts(:thinking).id) + comments = Comment.joins(:post).where("posts.id" => posts(:welcome).id).order("comments.id").limit(1) + assert_equal 1, comments.update_all(post_id: posts(:thinking).id) assert_equal posts(:thinking), comments(:greetings).post assert_equal posts(:welcome), comments(:more_greetings).post end def test_update_all_with_joins_and_offset - all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id) + all_comments = Comment.joins(:post).where("posts.id" => posts(:welcome).id) count = all_comments.count comments = all_comments.offset(1) - assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id) + assert_equal count - 1, comments.update_all(post_id: posts(:thinking).id) end def test_update_all_with_joins_and_offset_and_order - all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('posts.id', 'comments.id') + all_comments = Comment.joins(:post).where("posts.id" => posts(:welcome).id).order("posts.id", "comments.id") count = all_comments.count comments = all_comments.offset(1) - assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id) + assert_equal count - 1, comments.update_all(post_id: posts(:thinking).id) assert_equal posts(:thinking), comments(:more_greetings).post assert_equal posts(:welcome), comments(:greetings).post end def test_update_on_relation - topic1 = TopicWithCallbacks.create! title: 'arel', author_name: nil - topic2 = TopicWithCallbacks.create! title: 'activerecord', author_name: nil + topic1 = TopicWithCallbacks.create! title: "arel", author_name: nil + topic2 = TopicWithCallbacks.create! title: "activerecord", author_name: nil topics = TopicWithCallbacks.where(id: [topic1.id, topic2.id]) - topics.update(title: 'adequaterecord') + topics.update(title: "adequaterecord") - assert_equal 'adequaterecord', topic1.reload.title - assert_equal 'adequaterecord', topic2.reload.title + assert_equal "adequaterecord", topic1.reload.title + assert_equal "adequaterecord", topic2.reload.title # Testing that the before_update callbacks have run - assert_equal 'David', topic1.reload.author_name - assert_equal 'David', topic2.reload.author_name + assert_equal "David", topic1.reload.author_name + assert_equal "David", topic2.reload.author_name end def test_update_on_relation_passing_active_record_object_is_deprecated - topic = Topic.create!(title: 'Foo', author_name: nil) + topic = Topic.create!(title: "Foo", author_name: nil) assert_deprecated(/update/) do - Topic.where(id: topic.id).update(topic, title: 'Bar') + Topic.where(id: topic.id).update(topic, title: "Bar") end end def test_distinct - tag1 = Tag.create(:name => 'Foo') - tag2 = Tag.create(:name => 'Foo') + tag1 = Tag.create(name: "Foo") + tag2 = Tag.create(name: "Foo") - query = Tag.select(:name).where(:id => [tag1.id, tag2.id]) + query = Tag.select(:name).where(id: [tag1.id, tag2.id]) - assert_equal ['Foo', 'Foo'], query.map(&:name) + assert_equal ["Foo", "Foo"], query.map(&:name) assert_sql(/DISTINCT/) do - assert_equal ['Foo'], query.distinct.map(&:name) - assert_deprecated { assert_equal ['Foo'], query.uniq.map(&:name) } + assert_equal ["Foo"], query.distinct.map(&:name) + assert_deprecated { assert_equal ["Foo"], query.uniq.map(&:name) } end assert_sql(/DISTINCT/) do - assert_equal ['Foo'], query.distinct(true).map(&:name) - assert_deprecated { assert_equal ['Foo'], query.uniq(true).map(&:name) } + assert_equal ["Foo"], query.distinct(true).map(&:name) + assert_deprecated { assert_equal ["Foo"], query.uniq(true).map(&:name) } end - assert_equal ['Foo', 'Foo'], query.distinct(true).distinct(false).map(&:name) + assert_equal ["Foo", "Foo"], query.distinct(true).distinct(false).map(&:name) assert_deprecated do - assert_equal ['Foo', 'Foo'], query.uniq(true).uniq(false).map(&:name) + assert_equal ["Foo", "Foo"], query.uniq(true).uniq(false).map(&:name) end end def test_doesnt_add_having_values_if_options_are_blank - scope = Post.having('') + scope = Post.having("") assert scope.having_clause.empty? scope = Post.having([]) @@ -1701,62 +1709,62 @@ class RelationTest < ActiveRecord::TestCase end def test_automatically_added_where_references - scope = Post.where(:comments => { :body => "Bla" }) - assert_equal ['comments'], scope.references_values + scope = Post.where(comments: { body: "Bla" }) + assert_equal ["comments"], scope.references_values - scope = Post.where('comments.body' => 'Bla') - assert_equal ['comments'], scope.references_values + scope = Post.where("comments.body" => "Bla") + assert_equal ["comments"], scope.references_values end def test_automatically_added_where_not_references scope = Post.where.not(comments: { body: "Bla" }) - assert_equal ['comments'], scope.references_values + assert_equal ["comments"], scope.references_values - scope = Post.where.not('comments.body' => 'Bla') - assert_equal ['comments'], scope.references_values + scope = Post.where.not("comments.body" => "Bla") + assert_equal ["comments"], scope.references_values end def test_automatically_added_having_references - scope = Post.having(:comments => { :body => "Bla" }) - assert_equal ['comments'], scope.references_values + scope = Post.having(comments: { body: "Bla" }) + assert_equal ["comments"], scope.references_values - scope = Post.having('comments.body' => 'Bla') - assert_equal ['comments'], scope.references_values + scope = Post.having("comments.body" => "Bla") + assert_equal ["comments"], scope.references_values end def test_automatically_added_order_references - scope = Post.order('comments.body') - assert_equal ['comments'], scope.references_values + scope = Post.order("comments.body") + assert_equal ["comments"], scope.references_values - scope = Post.order('comments.body', 'yaks.body') - assert_equal ['comments', 'yaks'], scope.references_values + scope = Post.order("comments.body", "yaks.body") + assert_equal ["comments", "yaks"], scope.references_values # Don't infer yaks, let's not go down that road again... - scope = Post.order('comments.body, yaks.body') - assert_equal ['comments'], scope.references_values + scope = Post.order("comments.body, yaks.body") + assert_equal ["comments"], scope.references_values - scope = Post.order('comments.body asc') - assert_equal ['comments'], scope.references_values + scope = Post.order("comments.body asc") + assert_equal ["comments"], scope.references_values - scope = Post.order('foo(comments.body)') + scope = Post.order("foo(comments.body)") assert_equal [], scope.references_values end def test_automatically_added_reorder_references - scope = Post.reorder('comments.body') + scope = Post.reorder("comments.body") assert_equal %w(comments), scope.references_values - scope = Post.reorder('comments.body', 'yaks.body') + scope = Post.reorder("comments.body", "yaks.body") assert_equal %w(comments yaks), scope.references_values # Don't infer yaks, let's not go down that road again... - scope = Post.reorder('comments.body, yaks.body') + scope = Post.reorder("comments.body, yaks.body") assert_equal %w(comments), scope.references_values - scope = Post.reorder('comments.body asc') + scope = Post.reorder("comments.body asc") assert_equal %w(comments), scope.references_values - scope = Post.reorder('foo(comments.body)') + scope = Post.reorder("foo(comments.body)") assert_equal [], scope.references_values end @@ -1803,7 +1811,7 @@ class RelationTest < ActiveRecord::TestCase end test "find_by with multi-arg conditions returns the first matching record" do - assert_equal posts(:eager_other), Post.order(:id).find_by('author_id = ?', 2) + assert_equal posts(:eager_other), Post.order(:id).find_by("author_id = ?", 2) end test "find_by returns nil if the record is missing" do @@ -1827,7 +1835,7 @@ class RelationTest < ActiveRecord::TestCase end test "find_by! with multi-arg conditions returns the first matching record" do - assert_equal posts(:eager_other), Post.order(:id).find_by!('author_id = ?', 2) + assert_equal posts(:eager_other), Post.order(:id).find_by!("author_id = ?", 2) end test "find_by! doesn't have implicit ordering" do @@ -1849,7 +1857,7 @@ class RelationTest < ActiveRecord::TestCase relation.to_a assert_raises(ActiveRecord::ImmutableRelation) do - relation.where! 'foo' + relation.where! "foo" end end @@ -1867,7 +1875,7 @@ class RelationTest < ActiveRecord::TestCase relation.to_a assert_raises(ActiveRecord::ImmutableRelation) do - relation.merge! where: 'foo' + relation.merge! where: "foo" end end @@ -1909,19 +1917,19 @@ class RelationTest < ActiveRecord::TestCase end end - test 'using a custom table affects the wheres' do - table_alias = Post.arel_table.alias('omg_posts') + test "using a custom table affects the wheres" do + table_alias = Post.arel_table.alias("omg_posts") table_metadata = ActiveRecord::TableMetadata.new(Post, table_alias) predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata) relation = ActiveRecord::Relation.new(Post, table_alias, predicate_builder) - relation.where!(:foo => "bar") + relation.where!(foo: "bar") node = relation.arel.constraints.first.grep(Arel::Attributes::Attribute).first assert_equal table_alias, node.relation end - test '#load' do + test "#load" do relation = Post.all assert_queries(1) do assert_equal relation, relation.load @@ -1929,9 +1937,9 @@ class RelationTest < ActiveRecord::TestCase assert_no_queries { relation.to_a } end - test 'group with select and includes' do - authors_count = Post.select('author_id, COUNT(author_id) AS num_posts'). - group('author_id').order('author_id').includes(:author).to_a + test "group with select and includes" do + authors_count = Post.select("author_id, COUNT(author_id) AS num_posts"). + group("author_id").order("author_id").includes(:author).to_a assert_no_queries do result = authors_count.map do |post| @@ -1957,7 +1965,7 @@ class RelationTest < ActiveRecord::TestCase def test_unscope_removes_binds left = Post.where(id: Arel::Nodes::BindParam.new) - column = Post.columns_hash['id'] + column = Post.columns_hash["id"] left.bind_values += [[column, 20]] relation = left.unscope(where: :id) @@ -1992,7 +2000,7 @@ class RelationTest < ActiveRecord::TestCase end def test_relation_join_method - assert_equal 'Thank you for the welcome,Thank you again for the welcome', Post.first.comments.join(",") + assert_equal "Thank you for the welcome,Thank you again for the welcome", Post.first.comments.join(",") end def test_connection_adapters_can_reorder_binds diff --git a/activerecord/test/cases/reload_models_test.rb b/activerecord/test/cases/reload_models_test.rb index 431fbf1297..5dc9d6d8b7 100644 --- a/activerecord/test/cases/reload_models_test.rb +++ b/activerecord/test/cases/reload_models_test.rb @@ -1,13 +1,13 @@ require "cases/helper" -require 'models/owner' -require 'models/pet' +require "models/owner" +require "models/pet" class ReloadModelsTest < ActiveRecord::TestCase fixtures :pets, :owners def test_has_one_with_reload - pet = Pet.find_by_name('parrot') - pet.owner = Owner.find_by_name('ashley') + pet = Pet.find_by_name("parrot") + pet.owner = Owner.find_by_name("ashley") # Reload the class Owner, simulating auto-reloading of model classes in a # development environment. Note that meanwhile the class Pet is not @@ -15,8 +15,8 @@ class ReloadModelsTest < ActiveRecord::TestCase Object.class_eval { remove_const :Owner } Kernel.load(File.expand_path(File.join(File.dirname(__FILE__), "../models/owner.rb"))) - pet = Pet.find_by_name('parrot') - pet.owner = Owner.find_by_name('ashley') - assert_equal pet.owner, Owner.find_by_name('ashley') + pet = Pet.find_by_name("parrot") + pet.owner = Owner.find_by_name("ashley") + assert_equal pet.owner, Owner.find_by_name("ashley") end end diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb index dec01dfa76..949086fda0 100644 --- a/activerecord/test/cases/result_test.rb +++ b/activerecord/test/cases/result_test.rb @@ -3,10 +3,10 @@ require "cases/helper" module ActiveRecord class ResultTest < ActiveRecord::TestCase def result - Result.new(['col_1', 'col_2'], [ - ['row 1 col 1', 'row 1 col 2'], - ['row 2 col 1', 'row 2 col 2'], - ['row 3 col 1', 'row 3 col 2'], + Result.new(["col_1", "col_2"], [ + ["row 1 col 1", "row 1 col 2"], + ["row 2 col 1", "row 2 col 2"], + ["row 3 col 1", "row 3 col 2"], ]) end @@ -16,21 +16,31 @@ module ActiveRecord test "to_hash returns row_hashes" do assert_equal [ - {'col_1' => 'row 1 col 1', 'col_2' => 'row 1 col 2'}, - {'col_1' => 'row 2 col 1', 'col_2' => 'row 2 col 2'}, - {'col_1' => 'row 3 col 1', 'col_2' => 'row 3 col 2'}, + { "col_1" => "row 1 col 1", "col_2" => "row 1 col 2" }, + { "col_1" => "row 2 col 1", "col_2" => "row 2 col 2" }, + { "col_1" => "row 3 col 1", "col_2" => "row 3 col 2" }, ], result.to_hash end + test "first returns first row as a hash" do + assert_equal( + { "col_1" => "row 1 col 1", "col_2" => "row 1 col 2" }, result.first) + end + + test "last returns last row as a hash" do + assert_equal( + { "col_1" => "row 3 col 1", "col_2" => "row 3 col 2" }, result.last) + end + test "each with block returns row hashes" do result.each do |row| - assert_equal ['col_1', 'col_2'], row.keys + assert_equal ["col_1", "col_2"], row.keys end end test "each without block returns an enumerator" do result.each.with_index do |row, index| - assert_equal ['col_1', 'col_2'], row.keys + assert_equal ["col_1", "col_2"], row.keys assert_kind_of Integer, index end end diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb index 239f63d27b..464bb12ccb 100644 --- a/activerecord/test/cases/sanitize_test.rb +++ b/activerecord/test/cases/sanitize_test.rb @@ -1,7 +1,7 @@ require "cases/helper" -require 'models/binary' -require 'models/author' -require 'models/post' +require "models/binary" +require "models/author" +require "models/post" class SanitizeTest < ActiveRecord::TestCase def setup @@ -36,42 +36,42 @@ class SanitizeTest < ActiveRecord::TestCase end def test_sanitize_sql_array_handles_relations - david = Author.create!(name: 'David') + david = Author.create!(name: "David") david_posts = david.posts.select(:id) sub_query_pattern = /\(\bselect\b.*?\bwhere\b.*?\)/i - select_author_sql = Post.send(:sanitize_sql_array, ['id in (?)', david_posts]) - assert_match(sub_query_pattern, select_author_sql, 'should sanitize `Relation` as subquery for bind variables') + select_author_sql = Post.send(:sanitize_sql_array, ["id in (?)", david_posts]) + assert_match(sub_query_pattern, select_author_sql, "should sanitize `Relation` as subquery for bind variables") - select_author_sql = Post.send(:sanitize_sql_array, ['id in (:post_ids)', post_ids: david_posts]) - assert_match(sub_query_pattern, select_author_sql, 'should sanitize `Relation` as subquery for named bind variables') + select_author_sql = Post.send(:sanitize_sql_array, ["id in (:post_ids)", post_ids: david_posts]) + assert_match(sub_query_pattern, select_author_sql, "should sanitize `Relation` as subquery for named bind variables") end def test_sanitize_sql_array_handles_empty_statement - select_author_sql = Post.send(:sanitize_sql_array, ['']) - assert_equal('', select_author_sql) + select_author_sql = Post.send(:sanitize_sql_array, [""]) + assert_equal("", select_author_sql) end def test_sanitize_sql_like - assert_equal '100\%', Binary.send(:sanitize_sql_like, '100%') - assert_equal 'snake\_cased\_string', Binary.send(:sanitize_sql_like, 'snake_cased_string') + assert_equal '100\%', Binary.send(:sanitize_sql_like, "100%") + assert_equal 'snake\_cased\_string', Binary.send(:sanitize_sql_like, "snake_cased_string") assert_equal 'C:\\\\Programs\\\\MsPaint', Binary.send(:sanitize_sql_like, 'C:\\Programs\\MsPaint') - assert_equal 'normal string 42', Binary.send(:sanitize_sql_like, 'normal string 42') + assert_equal "normal string 42", Binary.send(:sanitize_sql_like, "normal string 42") end def test_sanitize_sql_like_with_custom_escape_character - assert_equal '100!%', Binary.send(:sanitize_sql_like, '100%', '!') - assert_equal 'snake!_cased!_string', Binary.send(:sanitize_sql_like, 'snake_cased_string', '!') - assert_equal 'great!!', Binary.send(:sanitize_sql_like, 'great!', '!') - assert_equal 'C:\\Programs\\MsPaint', Binary.send(:sanitize_sql_like, 'C:\\Programs\\MsPaint', '!') - assert_equal 'normal string 42', Binary.send(:sanitize_sql_like, 'normal string 42', '!') + assert_equal "100!%", Binary.send(:sanitize_sql_like, "100%", "!") + assert_equal "snake!_cased!_string", Binary.send(:sanitize_sql_like, "snake_cased_string", "!") + assert_equal "great!!", Binary.send(:sanitize_sql_like, "great!", "!") + assert_equal 'C:\\Programs\\MsPaint', Binary.send(:sanitize_sql_like, 'C:\\Programs\\MsPaint', "!") + assert_equal "normal string 42", Binary.send(:sanitize_sql_like, "normal string 42", "!") end def test_sanitize_sql_like_example_use_case searchable_post = Class.new(Post) do def self.search(term) - where("title LIKE ?", sanitize_sql_like(term, '!')) + where("title LIKE ?", sanitize_sql_like(term, "!")) end end @@ -81,25 +81,25 @@ class SanitizeTest < ActiveRecord::TestCase end def test_bind_arity - assert_nothing_raised { bind '' } - assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 } + assert_nothing_raised { bind "" } + assert_raise(ActiveRecord::PreparedStatementInvalid) { bind "", 1 } - assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' } - assert_nothing_raised { bind '?', 1 } - assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 } + assert_raise(ActiveRecord::PreparedStatementInvalid) { bind "?" } + assert_nothing_raised { bind "?", 1 } + assert_raise(ActiveRecord::PreparedStatementInvalid) { bind "?", 1, 1 } end def test_named_bind_variables - assert_equal '1', bind(':a', :a => 1) # ' ruby-mode - assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode + assert_equal "1", bind(":a", a: 1) # ' ruby-mode + assert_equal "1 1", bind(":a :a", a: 1) # ' ruby-mode - assert_nothing_raised { bind("'+00:00'", :foo => "bar") } + assert_nothing_raised { bind("'+00:00'", foo: "bar") } end def test_named_bind_arity - assert_nothing_raised { bind "name = :name", { name: "37signals" } } - assert_nothing_raised { bind "name = :name", { name: "37signals", id: 1 } } - assert_raise(ActiveRecord::PreparedStatementInvalid) { bind "name = :name", { id: 1 } } + assert_nothing_raised { bind "name = :name", name: "37signals" } + assert_nothing_raised { bind "name = :name", name: "37signals", id: 1 } + assert_raise(ActiveRecord::PreparedStatementInvalid) { bind "name = :name", id: 1 } end class SimpleEnumerable @@ -117,50 +117,50 @@ class SanitizeTest < ActiveRecord::TestCase def test_bind_enumerable quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')}) - assert_equal '1,2,3', bind('?', [1, 2, 3]) - assert_equal quoted_abc, bind('?', %w(a b c)) + assert_equal "1,2,3", bind("?", [1, 2, 3]) + assert_equal quoted_abc, bind("?", %w(a b c)) - assert_equal '1,2,3', bind(':a', :a => [1, 2, 3]) - assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # ' + assert_equal "1,2,3", bind(":a", a: [1, 2, 3]) + assert_equal quoted_abc, bind(":a", a: %w(a b c)) # ' - assert_equal '1,2,3', bind('?', SimpleEnumerable.new([1, 2, 3])) - assert_equal quoted_abc, bind('?', SimpleEnumerable.new(%w(a b c))) + assert_equal "1,2,3", bind("?", SimpleEnumerable.new([1, 2, 3])) + assert_equal quoted_abc, bind("?", SimpleEnumerable.new(%w(a b c))) - assert_equal '1,2,3', bind(':a', :a => SimpleEnumerable.new([1, 2, 3])) - assert_equal quoted_abc, bind(':a', :a => SimpleEnumerable.new(%w(a b c))) # ' + assert_equal "1,2,3", bind(":a", a: SimpleEnumerable.new([1, 2, 3])) + assert_equal quoted_abc, bind(":a", a: SimpleEnumerable.new(%w(a b c))) # ' end def test_bind_empty_enumerable quoted_nil = ActiveRecord::Base.connection.quote(nil) - assert_equal quoted_nil, bind('?', []) - assert_equal " in (#{quoted_nil})", bind(' in (?)', []) - assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', []) + assert_equal quoted_nil, bind("?", []) + assert_equal " in (#{quoted_nil})", bind(" in (?)", []) + assert_equal "foo in (#{quoted_nil})", bind("foo in (?)", []) end def test_bind_empty_string - quoted_empty = ActiveRecord::Base.connection.quote('') - assert_equal quoted_empty, bind('?', '') + quoted_empty = ActiveRecord::Base.connection.quote("") + assert_equal quoted_empty, bind("?", "") end def test_bind_chars quoted_bambi = ActiveRecord::Base.connection.quote("Bambi") quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper") - assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi") - assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper") - assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars) - assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars) + assert_equal "name=#{quoted_bambi}", bind("name=?", "Bambi") + assert_equal "name=#{quoted_bambi_and_thumper}", bind("name=?", "Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi}", bind("name=?", "Bambi".mb_chars) + assert_equal "name=#{quoted_bambi_and_thumper}", bind("name=?", "Bambi\nand\nThumper".mb_chars) end def test_bind_record o = Struct.new(:quoted_id).new(1) - assert_equal '1', bind('?', o) + assert_equal "1", bind("?", o) os = [o] * 3 - assert_equal '1,1,1', bind('?', os) + assert_equal "1,1,1", bind("?", os) end def test_named_bind_with_postgresql_type_casts - l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') } + l = Proc.new { bind(":a::integer '2009-01-01'::date", a: "10") } assert_nothing_raised(&l) assert_equal "#{ActiveRecord::Base.connection.quote('10')}::integer '2009-01-01'::date", l.call end diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 12f4196724..ae3a5651a1 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'support/schema_dumping_helper' +require "support/schema_dumping_helper" class SchemaDumperTest < ActiveRecord::TestCase include SchemaDumpingHelper @@ -20,7 +20,7 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_dump_schema_information_outputs_lexically_ordered_versions versions = %w{ 20100101010101 20100201010101 20100301010101 } versions.reverse_each do |v| - ActiveRecord::SchemaMigration.create!(:version => v) + ActiveRecord::SchemaMigration.create!(version: v) end schema_info = ActiveRecord::Base.connection.dump_schema_information @@ -37,7 +37,7 @@ class SchemaDumperTest < ActiveRecord::TestCase versions = %w{ 20100101010101 20100201010101 20100301010101 } versions.reverse_each do |v| - ActiveRecord::SchemaMigration.create!(:version => v) + ActiveRecord::SchemaMigration.create!(version: v) end schema_info = ActiveRecord::Base.connection.dump_schema_information @@ -51,6 +51,7 @@ class SchemaDumperTest < ActiveRecord::TestCase output = standard_dump assert_match %r{create_table "accounts"}, output assert_match %r{create_table "authors"}, output + assert_no_match %r{(?<=, ) do \|t\|}, output assert_no_match %r{create_table "schema_migrations"}, output assert_no_match %r{create_table "ar_internal_metadata"}, output end @@ -70,38 +71,35 @@ class SchemaDumperTest < ActiveRecord::TestCase assert_match %r{create_table "CamelCase"}, output end - def assert_line_up(lines, pattern, required = false) + def assert_no_line_up(lines, pattern) return assert(true) if lines.empty? matches = lines.map { |line| line.match(pattern) } - assert matches.all? if required matches.compact! return assert(true) if matches.empty? - assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length + line_matches = lines.map { |line| [line, line.match(pattern)] }.select { |line, match| match } + assert line_matches.all? { |line, match| + start = match.offset(0).first + line[start - 2..start - 1] == ", " + } end def column_definition_lines(output = standard_dump) - output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) } + output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map { |m| m.last.split(/\n/) } end - def test_types_line_up + def test_types_no_line_up column_definition_lines.each do |column_set| next if column_set.empty? - lengths = column_set.map do |column| - if match = column.match(/\bt\.\w+\s+(?="\w+?")/) - match[0].length - end - end.compact - - assert_equal 1, lengths.uniq.length + assert column_set.all? { |column| !column.match(/\bt\.\w+\s{2,}/) } end end - def test_arguments_line_up + def test_arguments_no_line_up column_definition_lines.each do |column_set| - assert_line_up(column_set, /default: /) - assert_line_up(column_set, /limit: /) - assert_line_up(column_set, /null: /) + assert_no_line_up(column_set, /default: /) + assert_no_line_up(column_set, /limit: /) + assert_no_line_up(column_set, /null: /) end end @@ -169,7 +167,7 @@ class SchemaDumperTest < ActiveRecord::TestCase end def test_schema_dump_with_string_ignored_table - output = dump_all_table_schema(['accounts']) + output = dump_all_table_schema(["accounts"]) assert_no_match %r{create_table "accounts"}, output assert_match %r{create_table "authors"}, output assert_no_match %r{create_table "schema_migrations"}, output @@ -186,8 +184,10 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dumps_index_columns_in_right_order index_definition = standard_dump.split(/\n/).grep(/t\.index.*company_index/).first.strip - if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter) - assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index", using: :btree', index_definition + if current_adapter?(:PostgreSQLAdapter) + assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index", order: { rating: :desc }, using: :btree', index_definition + elsif current_adapter?(:Mysql2Adapter) + assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index", length: { type: 10 }, using: :btree', index_definition else assert_equal 't.index ["firm_id", "type", "rating"], name: "company_index"', index_definition end @@ -289,7 +289,7 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dump_includes_extensions connection = ActiveRecord::Base.connection - connection.stubs(:extensions).returns(['hstore']) + connection.stubs(:extensions).returns(["hstore"]) output = perform_schema_dump assert_match "# These are extensions that must be enabled", output assert_match %r{enable_extension "hstore"}, output @@ -359,8 +359,8 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dump_with_table_name_prefix_and_suffix original, $stdout = $stdout, StringIO.new - ActiveRecord::Base.table_name_prefix = 'foo_' - ActiveRecord::Base.table_name_suffix = '_bar' + ActiveRecord::Base.table_name_prefix = "foo_" + ActiveRecord::Base.table_name_suffix = "_bar" migration = CreateDogMigration.new migration.migrate(:up) @@ -378,7 +378,7 @@ class SchemaDumperTest < ActiveRecord::TestCase ensure migration.migrate(:down) - ActiveRecord::Base.table_name_suffix = ActiveRecord::Base.table_name_prefix = '' + ActiveRecord::Base.table_name_suffix = ActiveRecord::Base.table_name_prefix = "" $stdout = original end @@ -396,7 +396,7 @@ class SchemaDumperTest < ActiveRecord::TestCase original_table_name_prefix = ActiveRecord::Base.table_name_prefix original_schema_dumper_ignore_tables = ActiveRecord::SchemaDumper.ignore_tables - ActiveRecord::Base.table_name_prefix = 'omg_' + ActiveRecord::Base.table_name_prefix = "omg_" ActiveRecord::SchemaDumper.ignore_tables = ["cats"] migration = create_cat_migration.new migration.migrate(:up) @@ -422,23 +422,37 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase @connection = ActiveRecord::Base.connection @connection.create_table :defaults, force: true do |t| t.string :string_with_default, default: "Hello!" - t.date :date_with_default, default: '2014-06-05' + t.date :date_with_default, default: "2014-06-05" t.datetime :datetime_with_default, default: "2014-06-05 07:17:04" t.time :time_with_default, default: "07:17:04" end + + if current_adapter?(:PostgreSQLAdapter) + @connection.create_table :infinity_defaults, force: true do |t| + t.float :float_with_inf_default, default: Float::INFINITY + t.float :float_with_nan_default, default: Float::NAN + end + end end teardown do return unless @connection - @connection.drop_table 'defaults', if_exists: true + @connection.drop_table "defaults", if_exists: true end def test_schema_dump_defaults_with_universally_supported_types - output = dump_table_schema('defaults') + output = dump_table_schema("defaults") assert_match %r{t\.string\s+"string_with_default",.*?default: "Hello!"}, output assert_match %r{t\.date\s+"date_with_default",\s+default: '2014-06-05'}, output assert_match %r{t\.datetime\s+"datetime_with_default",\s+default: '2014-06-05 07:17:04'}, output assert_match %r{t\.time\s+"time_with_default",\s+default: '2000-01-01 07:17:04'}, output end + + def test_schema_dump_with_float_column_infinity_default + skip unless current_adapter?(:PostgreSQLAdapter) + output = dump_table_schema('infinity_defaults') + assert_match %r{t\.float\s+"float_with_inf_default",\s+default: ::Float::INFINITY}, output + assert_match %r{t\.float\s+"float_with_nan_default",\s+default: ::Float::NAN}, output + end end diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb index dcd09b6973..61062da3e1 100644 --- a/activerecord/test/cases/scoping/default_scoping_test.rb +++ b/activerecord/test/cases/scoping/default_scoping_test.rb @@ -1,16 +1,17 @@ -require 'cases/helper' -require 'models/post' -require 'models/comment' -require 'models/developer' -require 'models/computer' -require 'models/vehicle' -require 'models/cat' +require "cases/helper" +require "models/post" +require "models/comment" +require "models/developer" +require "models/computer" +require "models/vehicle" +require "models/cat" +require "active_support/core_ext/regexp" class DefaultScopingTest < ActiveRecord::TestCase fixtures :developers, :posts, :comments def test_default_scope - expected = Developer.all.merge!(:order => 'salary DESC').to_a.collect(&:salary) + expected = Developer.all.merge!(order: "salary DESC").to_a.collect(&:salary) received = DeveloperOrderedBySalary.all.collect(&:salary) assert_equal expected, received end @@ -49,20 +50,20 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_default_scope_with_conditions_string - assert_equal Developer.where(name: 'David').map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort + assert_equal Developer.where(name: "David").map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort assert_equal nil, DeveloperCalledDavid.create!.name end def test_default_scope_with_conditions_hash - assert_equal Developer.where(name: 'Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort - assert_equal 'Jamis', DeveloperCalledJamis.create!.name + assert_equal Developer.where(name: "Jamis").map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort + assert_equal "Jamis", DeveloperCalledJamis.create!.name end unless in_memory_db? def test_default_scoping_with_threads 2.times do Thread.new { - assert DeveloperOrderedBySalary.all.to_sql.include?('salary DESC') + assert_includes DeveloperOrderedBySalary.all.to_sql, "salary DESC" DeveloperOrderedBySalary.connection.close }.join end @@ -71,37 +72,37 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_default_scope_with_inheritance wheres = InheritedPoorDeveloperCalledJamis.all.where_values_hash - assert_equal "Jamis", wheres['name'] - assert_equal 50000, wheres['salary'] + assert_equal "Jamis", wheres["name"] + assert_equal 50000, wheres["salary"] end def test_default_scope_with_module_includes wheres = ModuleIncludedPoorDeveloperCalledJamis.all.where_values_hash - assert_equal "Jamis", wheres['name'] - assert_equal 50000, wheres['salary'] + assert_equal "Jamis", wheres["name"] + assert_equal 50000, wheres["salary"] end def test_default_scope_with_multiple_calls wheres = MultiplePoorDeveloperCalledJamis.all.where_values_hash - assert_equal "Jamis", wheres['name'] - assert_equal 50000, wheres['salary'] + assert_equal "Jamis", wheres["name"] + assert_equal 50000, wheres["salary"] end def test_scope_overwrites_default - expected = Developer.all.merge!(order: 'salary DESC, name DESC').to_a.collect(&:name) + expected = Developer.all.merge!(order: "salary DESC, name DESC").to_a.collect(&:name) received = DeveloperOrderedBySalary.by_name.to_a.collect(&:name) assert_equal expected, received end def test_reorder_overrides_default_scope_order - expected = Developer.order('name DESC').collect(&:name) - received = DeveloperOrderedBySalary.reorder('name DESC').collect(&:name) + expected = Developer.order("name DESC").collect(&:name) + received = DeveloperOrderedBySalary.reorder("name DESC").collect(&:name) assert_equal expected, received end def test_order_after_reorder_combines_orders - expected = Developer.order('name DESC, id DESC').collect { |dev| [dev.name, dev.id] } - received = Developer.order('name ASC').reorder('name DESC').order('id DESC').collect { |dev| [dev.name, dev.id] } + expected = Developer.order("name DESC, id DESC").collect { |dev| [dev.name, dev.id] } + received = Developer.order("name ASC").reorder("name DESC").order("id DESC").collect { |dev| [dev.name, dev.id] } assert_equal expected, received end @@ -112,107 +113,107 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_unscope_after_reordering_and_combining - expected = Developer.order('id DESC, name DESC').collect { |dev| [dev.name, dev.id] } - received = DeveloperOrderedBySalary.reorder('name DESC').unscope(:order).order('id DESC, name DESC').collect { |dev| [dev.name, dev.id] } + expected = Developer.order("id DESC, name DESC").collect { |dev| [dev.name, dev.id] } + received = DeveloperOrderedBySalary.reorder("name DESC").unscope(:order).order("id DESC, name DESC").collect { |dev| [dev.name, dev.id] } assert_equal expected, received expected_2 = Developer.all.collect { |dev| [dev.name, dev.id] } - received_2 = Developer.order('id DESC, name DESC').unscope(:order).collect { |dev| [dev.name, dev.id] } + received_2 = Developer.order("id DESC, name DESC").unscope(:order).collect { |dev| [dev.name, dev.id] } assert_equal expected_2, received_2 expected_3 = Developer.all.collect { |dev| [dev.name, dev.id] } - received_3 = Developer.reorder('name DESC').unscope(:order).collect { |dev| [dev.name, dev.id] } + received_3 = Developer.reorder("name DESC").unscope(:order).collect { |dev| [dev.name, dev.id] } assert_equal expected_3, received_3 end def test_unscope_with_where_attributes - expected = Developer.order('salary DESC').collect(&:name) - received = DeveloperOrderedBySalary.where(name: 'David').unscope(where: :name).collect(&:name) + expected = Developer.order("salary DESC").collect(&:name) + received = DeveloperOrderedBySalary.where(name: "David").unscope(where: :name).collect(&:name) assert_equal expected, received - expected_2 = Developer.order('salary DESC').collect(&:name) - received_2 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope({:where => :name}, :select).collect(&:name) + expected_2 = Developer.order("salary DESC").collect(&:name) + received_2 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope({ where: :name }, :select).collect(&:name) assert_equal expected_2, received_2 - expected_3 = Developer.order('salary DESC').collect(&:name) + expected_3 = Developer.order("salary DESC").collect(&:name) received_3 = DeveloperOrderedBySalary.select("id").where("name" => "Jamis").unscope(:select, :where).collect(&:name) assert_equal expected_3, received_3 - expected_4 = Developer.order('salary DESC').collect(&:name) + expected_4 = Developer.order("salary DESC").collect(&:name) received_4 = DeveloperOrderedBySalary.where.not("name" => "Jamis").unscope(where: :name).collect(&:name) assert_equal expected_4, received_4 - expected_5 = Developer.order('salary DESC').collect(&:name) + expected_5 = Developer.order("salary DESC").collect(&:name) received_5 = DeveloperOrderedBySalary.where.not("name" => ["Jamis", "David"]).unscope(where: :name).collect(&:name) assert_equal expected_5, received_5 - expected_6 = Developer.order('salary DESC').collect(&:name) - received_6 = DeveloperOrderedBySalary.where(Developer.arel_table['name'].eq('David')).unscope(where: :name).collect(&:name) + expected_6 = Developer.order("salary DESC").collect(&:name) + received_6 = DeveloperOrderedBySalary.where(Developer.arel_table["name"].eq("David")).unscope(where: :name).collect(&:name) assert_equal expected_6, received_6 - expected_7 = Developer.order('salary DESC').collect(&:name) - received_7 = DeveloperOrderedBySalary.where(Developer.arel_table[:name].eq('David')).unscope(where: :name).collect(&:name) + expected_7 = Developer.order("salary DESC").collect(&:name) + received_7 = DeveloperOrderedBySalary.where(Developer.arel_table[:name].eq("David")).unscope(where: :name).collect(&:name) assert_equal expected_7, received_7 end def test_unscope_comparison_where_clauses # unscoped for WHERE (`developers`.`id` <= 2) - expected = Developer.order('salary DESC').collect(&:name) + expected = Developer.order("salary DESC").collect(&:name) received = DeveloperOrderedBySalary.where(id: -Float::INFINITY..2).unscope(where: :id).collect { |dev| dev.name } assert_equal expected, received # unscoped for WHERE (`developers`.`id` < 2) - expected = Developer.order('salary DESC').collect(&:name) + expected = Developer.order("salary DESC").collect(&:name) received = DeveloperOrderedBySalary.where(id: -Float::INFINITY...2).unscope(where: :id).collect { |dev| dev.name } assert_equal expected, received end def test_unscope_multiple_where_clauses - expected = Developer.order('salary DESC').collect(&:name) - received = DeveloperOrderedBySalary.where(name: 'Jamis').where(id: 1).unscope(where: [:name, :id]).collect(&:name) + expected = Developer.order("salary DESC").collect(&:name) + received = DeveloperOrderedBySalary.where(name: "Jamis").where(id: 1).unscope(where: [:name, :id]).collect(&:name) assert_equal expected, received end def test_unscope_string_where_clauses_involved - dev_relation = Developer.order('salary DESC').where("created_at > ?", 1.year.ago) + dev_relation = Developer.order("salary DESC").where("created_at > ?", 1.year.ago) expected = dev_relation.collect(&:name) - dev_ordered_relation = DeveloperOrderedBySalary.where(name: 'Jamis').where("created_at > ?", 1.year.ago) + dev_ordered_relation = DeveloperOrderedBySalary.where(name: "Jamis").where("created_at > ?", 1.year.ago) received = dev_ordered_relation.unscope(where: [:name]).collect(&:name) assert_equal expected, received end def test_unscope_with_grouping_attributes - expected = Developer.order('salary DESC').collect(&:name) + expected = Developer.order("salary DESC").collect(&:name) received = DeveloperOrderedBySalary.group(:name).unscope(:group).collect(&:name) assert_equal expected, received - expected_2 = Developer.order('salary DESC').collect(&:name) + expected_2 = Developer.order("salary DESC").collect(&:name) received_2 = DeveloperOrderedBySalary.group("name").unscope(:group).collect(&:name) assert_equal expected_2, received_2 end def test_unscope_with_limit_in_query - expected = Developer.order('salary DESC').collect(&:name) + expected = Developer.order("salary DESC").collect(&:name) received = DeveloperOrderedBySalary.limit(1).unscope(:limit).collect(&:name) assert_equal expected, received end def test_order_to_unscope_reordering - scope = DeveloperOrderedBySalary.order('salary DESC, name ASC').reverse_order.unscope(:order) - assert !(scope.to_sql =~ /order/i) + scope = DeveloperOrderedBySalary.order("salary DESC, name ASC").reverse_order.unscope(:order) + assert !/order/i.match?(scope.to_sql) end def test_unscope_reverse_order expected = Developer.all.collect(&:name) - received = Developer.order('salary DESC').reverse_order.unscope(:order).collect(&:name) + received = Developer.order("salary DESC").reverse_order.unscope(:order).collect(&:name) assert_equal expected, received end def test_unscope_select - expected = Developer.order('salary ASC').collect(&:name) - received = Developer.order('salary DESC').reverse_order.select(:name).unscope(:select).collect(&:name) + expected = Developer.order("salary ASC").collect(&:name) + received = Developer.order("salary DESC").reverse_order.select(:name).unscope(:select).collect(&:name) assert_equal expected, received expected_2 = Developer.all.collect(&:id) @@ -228,7 +229,7 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_unscope_joins_and_select_on_developers_projects expected = Developer.all.collect(&:name) - received = Developer.joins('JOIN developers_projects ON id = developer_id').select(:id).unscope(:joins, :select).collect(&:name) + received = Developer.joins("JOIN developers_projects ON id = developer_id").select(:id).unscope(:joins, :select).collect(&:name) assert_equal expected, received end @@ -249,8 +250,8 @@ class DefaultScopingTest < ActiveRecord::TestCase scope :by_name, -> name { unscope(where: :name).where(name: name) } end - expected = developer_klass.where(name: 'Jamis').collect { |dev| [dev.name, dev.id] } - received = developer_klass.where(name: 'David').by_name('Jamis').collect { |dev| [dev.name, dev.id] } + expected = developer_klass.where(name: "Jamis").collect { |dev| [dev.name, dev.id] } + received = developer_klass.where(name: "David").by_name("Jamis").collect { |dev| [dev.name, dev.id] } assert_equal expected, received end @@ -264,11 +265,11 @@ class DefaultScopingTest < ActiveRecord::TestCase end assert_raises(ArgumentError) do - Developer.order('name DESC').reverse_order.unscope(:reverse_order) + Developer.order("name DESC").reverse_order.unscope(:reverse_order) end assert_raises(ArgumentError) do - Developer.order('name DESC').where(name: "Jamis").unscope() + Developer.order("name DESC").where(name: "Jamis").unscope() end end @@ -303,35 +304,35 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_order_in_default_scope_should_not_prevail - expected = Developer.all.merge!(order: 'salary desc').to_a.collect(&:salary) - received = DeveloperOrderedBySalary.all.merge!(order: 'salary').to_a.collect(&:salary) + expected = Developer.all.merge!(order: "salary desc").to_a.collect(&:salary) + received = DeveloperOrderedBySalary.all.merge!(order: "salary").to_a.collect(&:salary) assert_equal expected, received end def test_create_attribute_overwrites_default_scoping - assert_equal 'David', PoorDeveloperCalledJamis.create!(:name => 'David').name - assert_equal 200000, PoorDeveloperCalledJamis.create!(:name => 'David', :salary => 200000).salary + assert_equal "David", PoorDeveloperCalledJamis.create!(name: "David").name + assert_equal 200000, PoorDeveloperCalledJamis.create!(name: "David", salary: 200000).salary end def test_create_attribute_overwrites_default_values - assert_equal nil, PoorDeveloperCalledJamis.create!(:salary => nil).salary - assert_equal 50000, PoorDeveloperCalledJamis.create!(:name => 'David').salary + assert_equal nil, PoorDeveloperCalledJamis.create!(salary: nil).salary + assert_equal 50000, PoorDeveloperCalledJamis.create!(name: "David").salary end def test_default_scope_attribute - jamis = PoorDeveloperCalledJamis.new(:name => 'David') + jamis = PoorDeveloperCalledJamis.new(name: "David") assert_equal 50000, jamis.salary end def test_where_attribute - aaron = PoorDeveloperCalledJamis.where(:salary => 20).new(:name => 'Aaron') + aaron = PoorDeveloperCalledJamis.where(salary: 20).new(name: "Aaron") assert_equal 20, aaron.salary - assert_equal 'Aaron', aaron.name + assert_equal "Aaron", aaron.name end def test_where_attribute_merge - aaron = PoorDeveloperCalledJamis.where(:name => 'foo').new(:name => 'Aaron') - assert_equal 'Aaron', aaron.name + aaron = PoorDeveloperCalledJamis.where(name: "foo").new(name: "Aaron") + assert_equal "Aaron", aaron.name end def test_scope_composed_by_limit_and_then_offset_is_equal_to_scope_composed_by_offset_and_then_limit @@ -341,33 +342,33 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_create_with_merge - aaron = PoorDeveloperCalledJamis.create_with(:name => 'foo', :salary => 20).merge( - PoorDeveloperCalledJamis.create_with(:name => 'Aaron')).new + aaron = PoorDeveloperCalledJamis.create_with(name: "foo", salary: 20).merge( + PoorDeveloperCalledJamis.create_with(name: "Aaron")).new assert_equal 20, aaron.salary - assert_equal 'Aaron', aaron.name + assert_equal "Aaron", aaron.name - aaron = PoorDeveloperCalledJamis.create_with(:name => 'foo', :salary => 20). - create_with(:name => 'Aaron').new + aaron = PoorDeveloperCalledJamis.create_with(name: "foo", salary: 20). + create_with(name: "Aaron").new assert_equal 20, aaron.salary - assert_equal 'Aaron', aaron.name + assert_equal "Aaron", aaron.name end def test_create_with_reset - jamis = PoorDeveloperCalledJamis.create_with(:name => 'Aaron').create_with(nil).new - assert_equal 'Jamis', jamis.name + jamis = PoorDeveloperCalledJamis.create_with(name: "Aaron").create_with(nil).new + assert_equal "Jamis", jamis.name end # FIXME: I don't know if this is *desired* behavior, but it is *today's* # behavior. def test_create_with_empty_hash_will_not_reset - jamis = PoorDeveloperCalledJamis.create_with(:name => 'Aaron').create_with({}).new - assert_equal 'Aaron', jamis.name + jamis = PoorDeveloperCalledJamis.create_with(name: "Aaron").create_with({}).new + assert_equal "Aaron", jamis.name end def test_unscoped_with_named_scope_should_not_have_default_scope assert_equal [DeveloperCalledJamis.find(developers(:poor_jamis).id)], DeveloperCalledJamis.poor - assert DeveloperCalledJamis.unscoped.poor.include?(developers(:david).becomes(DeveloperCalledJamis)) + assert_includes DeveloperCalledJamis.unscoped.poor, developers(:david).becomes(DeveloperCalledJamis) assert_equal 11, DeveloperCalledJamis.unscoped.length assert_equal 1, DeveloperCalledJamis.poor.length @@ -409,9 +410,9 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_default_scope_include_with_count d = DeveloperWithIncludes.create! - d.audit_logs.create! :message => 'foo' + d.audit_logs.create! message: "foo" - assert_equal 1, DeveloperWithIncludes.where(:audit_logs => { :message => 'foo' }).count + assert_equal 1, DeveloperWithIncludes.where(audit_logs: { message: "foo" }).count end def test_default_scope_with_references_works_through_collection_association @@ -474,9 +475,9 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_sti_conditions_are_not_carried_in_default_scope - ConditionalStiPost.create! body: '' - SubConditionalStiPost.create! body: '' - SubConditionalStiPost.create! title: 'Hello world', body: '' + ConditionalStiPost.create! body: "" + SubConditionalStiPost.create! body: "" + SubConditionalStiPost.create! title: "Hello world", body: "" assert_equal 2, ConditionalStiPost.count assert_equal 2, ConditionalStiPost.all.to_a.size diff --git a/activerecord/test/cases/scoping/named_scoping_test.rb b/activerecord/test/cases/scoping/named_scoping_test.rb index 0e277ed235..58e1310ab0 100644 --- a/activerecord/test/cases/scoping/named_scoping_test.rb +++ b/activerecord/test/cases/scoping/named_scoping_test.rb @@ -1,11 +1,11 @@ require "cases/helper" -require 'models/post' -require 'models/topic' -require 'models/comment' -require 'models/reply' -require 'models/author' -require 'models/developer' -require 'models/computer' +require "models/post" +require "models/topic" +require "models/comment" +require "models/reply" +require "models/author" +require "models/developer" +require "models/computer" class NamedScopingTest < ActiveRecord::TestCase fixtures :posts, :authors, :topics, :comments, :author_addresses @@ -33,8 +33,8 @@ class NamedScopingTest < ActiveRecord::TestCase all_posts.to_a new_post = Topic.create! - assert !all_posts.include?(new_post) - assert all_posts.reload.include?(new_post) + assert_not_includes all_posts, new_post + assert_includes all_posts.reload, new_post end def test_delegates_finds_and_calculations_to_the_base_class @@ -46,11 +46,18 @@ class NamedScopingTest < ActiveRecord::TestCase assert_equal Topic.average(:replies_count), Topic.base.average(:replies_count) end + def test_calling_merge_at_first_in_scope + Topic.class_eval do + scope :calling_merge_at_first_in_scope, Proc.new { merge(Topic.replied) } + end + assert_equal Topic.calling_merge_at_first_in_scope.to_a, Topic.replied.to_a + end + def test_method_missing_priority_when_delegating klazz = Class.new(ActiveRecord::Base) do self.table_name = "topics" - scope :since, Proc.new { where('written_on >= ?', Time.now - 1.day) } - scope :to, Proc.new { where('written_on <= ?', Time.now) } + scope :since, Proc.new { where("written_on >= ?", Time.now - 1.day) } + scope :to, Proc.new { where("written_on <= ?", Time.now) } end assert_equal klazz.to.since.to_a, klazz.since.to.to_a end @@ -62,10 +69,10 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified - assert !Topic.all.merge!(:where => {:approved => true}).to_a.empty? + assert !Topic.all.merge!(where: { approved: true }).to_a.empty? - assert_equal Topic.all.merge!(:where => {:approved => true}).to_a, Topic.approved - assert_equal Topic.where(:approved => true).count, Topic.approved.count + assert_equal Topic.all.merge!(where: { approved: true }).to_a, Topic.approved + assert_equal Topic.where(approved: true).count, Topic.approved.count end def test_scopes_with_string_name_can_be_composed @@ -75,8 +82,8 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_scopes_are_composable - assert_equal((approved = Topic.all.merge!(:where => {:approved => true}).to_a), Topic.approved) - assert_equal((replied = Topic.all.merge!(:where => 'replies_count > 0').to_a), Topic.replied) + assert_equal((approved = Topic.all.merge!(where: { approved: true }).to_a), Topic.approved) + assert_equal((replied = Topic.all.merge!(where: "replies_count > 0").to_a), Topic.replied) assert !(approved == replied) assert !(approved & replied).empty? @@ -84,8 +91,8 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_procedural_scopes - topics_written_before_the_third = Topic.where('written_on < ?', topics(:third).written_on) - topics_written_before_the_second = Topic.where('written_on < ?', topics(:second).written_on) + topics_written_before_the_third = Topic.where("written_on < ?", topics(:third).written_on) + topics_written_before_the_second = Topic.where("written_on < ?", topics(:second).written_on) assert_not_equal topics_written_before_the_second, topics_written_before_the_third assert_equal topics_written_before_the_third, Topic.written_before(topics(:third).written_on) @@ -101,7 +108,7 @@ class NamedScopingTest < ActiveRecord::TestCase def test_scope_with_object objects = Topic.with_object assert_operator objects.length, :>, 0 - assert objects.all?(&:approved?), 'all objects should be approved' + assert objects.all?(&:approved?), "all objects should be approved" end def test_has_many_associations_have_access_to_scopes @@ -231,9 +238,9 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_many_should_return_false_if_none_or_one - topics = Topic.base.where(:id => 0) + topics = Topic.base.where(id: 0) assert !topics.many? - topics = Topic.base.where(:id => 1) + topics = Topic.base.where(id: 1) assert !topics.many? end @@ -273,7 +280,7 @@ class NamedScopingTest < ActiveRecord::TestCase def test_should_build_on_top_of_chained_scopes topic = Topic.approved.by_lifo.build({}) assert topic.approved - assert_equal 'lifo', topic.author_name + assert_equal "lifo", topic.author_name end def test_reserved_scope_names @@ -320,12 +327,12 @@ class NamedScopingTest < ActiveRecord::TestCase conflicts.each do |name| e = assert_raises(ArgumentError, "scope `#{name}` should not be allowed") do - klass.class_eval { scope name, ->{ where(approved: true) } } + klass.class_eval { scope name, -> { where(approved: true) } } end assert_match(/You tried to define a scope named \"#{name}\" on the model/, e.message) e = assert_raises(ArgumentError, "scope `#{name}` should not be allowed") do - subklass.class_eval { scope name, ->{ where(approved: true) } } + subklass.class_eval { scope name, -> { where(approved: true) } } end assert_match(/You tried to define a scope named \"#{name}\" on the model/, e.message) end @@ -333,12 +340,12 @@ class NamedScopingTest < ActiveRecord::TestCase non_conflicts.each do |name| assert_nothing_raised do silence_warnings do - klass.class_eval { scope name, ->{ where(approved: true) } } + klass.class_eval { scope name, -> { where(approved: true) } } end end assert_nothing_raised do - subklass.class_eval { scope name, ->{ where(approved: true) } } + subklass.class_eval { scope name, -> { where(approved: true) } } end end end @@ -350,7 +357,7 @@ class NamedScopingTest < ActiveRecord::TestCase klass = Class.new(ActiveRecord::Base) do self.table_name = "topics" scope :"title containing space", -> { where("title LIKE '% %'") } - scope :approved, -> { where(:approved => true) } + scope :approved, -> { where(approved: true) } end assert_equal klass.send(:"title containing space"), klass.where("title LIKE '% %'") assert_equal klass.approved.send(:"title containing space"), klass.approved.where("title LIKE '% %'") @@ -365,7 +372,7 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_should_use_where_in_query_for_scope - assert_equal Developer.where(name: 'Jamis').to_set, Developer.where(id: Developer.jamises).to_set + assert_equal Developer.where(name: "Jamis").to_set, Developer.where(id: Developer.jamises).to_set end def test_size_should_use_count_when_results_are_not_loaded @@ -424,12 +431,12 @@ class NamedScopingTest < ActiveRecord::TestCase assert_equal 4, Topic.approved.count assert_queries(5) do - Topic.approved.find_each(:batch_size => 1) {|t| assert t.approved? } + Topic.approved.find_each(batch_size: 1) { |t| assert t.approved? } end assert_queries(3) do - Topic.approved.find_in_batches(:batch_size => 2) do |group| - group.each {|t| assert t.approved? } + Topic.approved.find_in_batches(batch_size: 2) do |group| + group.each { |t| assert t.approved? } end end end @@ -455,13 +462,13 @@ class NamedScopingTest < ActiveRecord::TestCase [:public_method, :protected_method, :private_method].each do |reserved_method| assert Topic.respond_to?(reserved_method, true) ActiveRecord::Base.logger.expects(:warn) - silence_warnings { Topic.scope(reserved_method, -> { }) } + silence_warnings { Topic.scope(reserved_method, -> {}) } end end def test_scopes_on_relations # Topic.replied - approved_topics = Topic.all.approved.order('id DESC') + approved_topics = Topic.all.approved.order("id DESC") assert_equal topics(:fifth), approved_topics.first replied_approved_topics = approved_topics.replied @@ -469,7 +476,7 @@ class NamedScopingTest < ActiveRecord::TestCase end def test_index_on_scope - approved = Topic.approved.order('id ASC') + approved = Topic.approved.order("id ASC") assert_equal topics(:second), approved[0] assert approved.loaded? end @@ -510,7 +517,7 @@ class NamedScopingTest < ActiveRecord::TestCase def test_scopes_to_get_newest post = posts(:welcome) old_last_comment = post.comments.newest - new_comment = post.comments.create(:body => "My new comment") + new_comment = post.comments.create(body: "My new comment") assert_equal new_comment, post.comments.newest assert_not_equal old_last_comment, post.comments.newest end @@ -533,15 +540,15 @@ class NamedScopingTest < ActiveRecord::TestCase def test_eager_default_scope_relations_are_remove klass = Class.new(ActiveRecord::Base) - klass.table_name = 'posts' + klass.table_name = "posts" assert_raises(ArgumentError) do - klass.send(:default_scope, klass.where(:id => posts(:welcome).id)) + klass.send(:default_scope, klass.where(id: posts(:welcome).id)) end end def test_subclass_merges_scopes_properly - assert_equal 1, SpecialComment.where(body: 'go crazy').created.count + assert_equal 1, SpecialComment.where(body: "go crazy").created.count end def test_model_class_should_respond_to_none @@ -557,5 +564,4 @@ class NamedScopingTest < ActiveRecord::TestCase Topic.create! assert Topic.one? end - end diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb index c15d57460b..27b4583457 100644 --- a/activerecord/test/cases/scoping/relation_scoping_test.rb +++ b/activerecord/test/cases/scoping/relation_scoping_test.rb @@ -1,13 +1,13 @@ require "cases/helper" -require 'models/post' -require 'models/author' -require 'models/developer' -require 'models/computer' -require 'models/project' -require 'models/comment' -require 'models/category' -require 'models/person' -require 'models/reference' +require "models/post" +require "models/author" +require "models/developer" +require "models/computer" +require "models/project" +require "models/comment" +require "models/category" +require "models/person" +require "models/reference" class RelationScopingTest < ActiveRecord::TestCase fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects @@ -109,7 +109,7 @@ class RelationScopingTest < ActiveRecord::TestCase def test_scope_select_concatenates Developer.select("id, name").scoping do - developer = Developer.select('salary').where("name = 'David'").first + developer = Developer.select("salary").where("name = 'David'").first assert_equal 80000, developer.salary assert developer.has_attribute?(:id) assert developer.has_attribute?(:name) @@ -122,7 +122,7 @@ class RelationScopingTest < ActiveRecord::TestCase assert_equal 1, Developer.count end - Developer.where('salary = 100000').scoping do + Developer.where("salary = 100000").scoping do assert_equal 8, Developer.count assert_equal 1, Developer.where("name LIKE 'fixture_1%'").count end @@ -131,49 +131,49 @@ class RelationScopingTest < ActiveRecord::TestCase def test_scoped_find_include # with the include, will retrieve only developers for the given project scoped_developers = Developer.includes(:projects).scoping do - Developer.where('projects.id' => 2).to_a + Developer.where("projects.id" => 2).to_a end - assert scoped_developers.include?(developers(:david)) - assert !scoped_developers.include?(developers(:jamis)) + assert_includes scoped_developers, developers(:david) + assert_not_includes scoped_developers, developers(:jamis) assert_equal 1, scoped_developers.size end def test_scoped_find_joins - scoped_developers = Developer.joins('JOIN developers_projects ON id = developer_id').scoping do - Developer.where('developers_projects.project_id = 2').to_a + scoped_developers = Developer.joins("JOIN developers_projects ON id = developer_id").scoping do + Developer.where("developers_projects.project_id = 2").to_a end - assert scoped_developers.include?(developers(:david)) - assert !scoped_developers.include?(developers(:jamis)) + assert_includes scoped_developers, developers(:david) + assert_not_includes scoped_developers, developers(:jamis) assert_equal 1, scoped_developers.size assert_equal developers(:david).attributes, scoped_developers.first.attributes end def test_scoped_create_with_where - new_comment = VerySpecialComment.where(:post_id => 1).scoping do - VerySpecialComment.create :body => "Wonderful world" + new_comment = VerySpecialComment.where(post_id: 1).scoping do + VerySpecialComment.create body: "Wonderful world" end assert_equal 1, new_comment.post_id - assert Post.find(1).comments.include?(new_comment) + assert_includes Post.find(1).comments, new_comment end def test_scoped_create_with_create_with - new_comment = VerySpecialComment.create_with(:post_id => 1).scoping do - VerySpecialComment.create :body => "Wonderful world" + new_comment = VerySpecialComment.create_with(post_id: 1).scoping do + VerySpecialComment.create body: "Wonderful world" end assert_equal 1, new_comment.post_id - assert Post.find(1).comments.include?(new_comment) + assert_includes Post.find(1).comments, new_comment end def test_scoped_create_with_create_with_has_higher_priority - new_comment = VerySpecialComment.where(:post_id => 2).create_with(:post_id => 1).scoping do - VerySpecialComment.create :body => "Wonderful world" + new_comment = VerySpecialComment.where(post_id: 2).create_with(post_id: 1).scoping do + VerySpecialComment.create body: "Wonderful world" end assert_equal 1, new_comment.post_id - assert Post.find(1).comments.include?(new_comment) + assert_includes Post.find(1).comments, new_comment end def test_ensure_that_method_scoping_is_correctly_restored @@ -193,7 +193,7 @@ class RelationScopingTest < ActiveRecord::TestCase end def test_update_all_default_scope_filters_on_joins - DeveloperFilteredOnJoins.update_all(:salary => 65000) + DeveloperFilteredOnJoins.update_all(salary: 65000) assert_equal 65000, Developer.find(developers(:david).id).salary # has not changed jamis @@ -228,18 +228,25 @@ class RelationScopingTest < ActiveRecord::TestCase assert SpecialComment.all.any? end end + + def test_circular_joins_with_current_scope_does_not_crash + posts = Post.joins(comments: :post).scoping do + Post.current_scope.first(10) + end + assert_equal posts, Post.joins(comments: :post).first(10) + end end class NestedRelationScopingTest < ActiveRecord::TestCase fixtures :authors, :developers, :projects, :comments, :posts def test_merge_options - Developer.where('salary = 80000').scoping do + Developer.where("salary = 80000").scoping do Developer.limit(10).scoping do devs = Developer.all sql = devs.to_sql - assert_match '(salary = 80000)', sql - assert_match 'LIMIT 10', sql + assert_match "(salary = 80000)", sql + assert_match(/LIMIT 10|ROWNUM <= 10|FETCH FIRST 10 ROWS ONLY/, sql) end end end @@ -253,39 +260,39 @@ class NestedRelationScopingTest < ActiveRecord::TestCase end def test_replace_options - Developer.where(:name => 'David').scoping do + Developer.where(name: "David").scoping do Developer.unscoped do - assert_equal 'Jamis', Developer.where(:name => 'Jamis').first[:name] + assert_equal "Jamis", Developer.where(name: "Jamis").first[:name] end - assert_equal 'David', Developer.first[:name] + assert_equal "David", Developer.first[:name] end end def test_three_level_nested_exclusive_scoped_find Developer.where("name = 'Jamis'").scoping do - assert_equal 'Jamis', Developer.first.name + assert_equal "Jamis", Developer.first.name Developer.unscoped.where("name = 'David'") do - assert_equal 'David', Developer.first.name + assert_equal "David", Developer.first.name Developer.unscoped.where("name = 'Maiha'") do assert_equal nil, Developer.first end # ensure that scoping is restored - assert_equal 'David', Developer.first.name + assert_equal "David", Developer.first.name end # ensure that scoping is restored - assert_equal 'Jamis', Developer.first.name + assert_equal "Jamis", Developer.first.name end end def test_nested_scoped_create - comment = Comment.create_with(:post_id => 1).scoping do - Comment.create_with(:post_id => 2).scoping do - Comment.create :body => "Hey guys, nested scopes are broken. Please fix!" + comment = Comment.create_with(post_id: 1).scoping do + Comment.create_with(post_id: 2).scoping do + Comment.create body: "Hey guys, nested scopes are broken. Please fix!" end end @@ -293,15 +300,15 @@ class NestedRelationScopingTest < ActiveRecord::TestCase end def test_nested_exclusive_scope_for_create - comment = Comment.create_with(:body => "Hey guys, nested scopes are broken. Please fix!").scoping do - Comment.unscoped.create_with(:post_id => 1).scoping do + comment = Comment.create_with(body: "Hey guys, nested scopes are broken. Please fix!").scoping do + Comment.unscoped.create_with(post_id: 1).scoping do assert Comment.new.body.blank? - Comment.create :body => "Hey guys" + Comment.create body: "Hey guys" end end assert_equal 1, comment.post_id - assert_equal 'Hey guys', comment.body + assert_equal "Hey guys", comment.body end end @@ -313,24 +320,24 @@ class HasManyScopingTest < ActiveRecord::TestCase end def test_forwarding_of_static_methods - assert_equal 'a comment...', Comment.what_are_you - assert_equal 'a comment...', @welcome.comments.what_are_you + assert_equal "a comment...", Comment.what_are_you + assert_equal "a comment...", @welcome.comments.what_are_you end def test_forwarding_to_scoped - assert_equal 4, Comment.search_by_type('Comment').size - assert_equal 2, @welcome.comments.search_by_type('Comment').size + assert_equal 4, Comment.search_by_type("Comment").size + assert_equal 2, @welcome.comments.search_by_type("Comment").size end def test_nested_scope_finder - Comment.where('1=0').scoping do + Comment.where("1=0").scoping do assert_equal 0, @welcome.comments.count - assert_equal 'a comment...', @welcome.comments.what_are_you + assert_equal "a comment...", @welcome.comments.what_are_you end - Comment.where('1=1').scoping do + Comment.where("1=1").scoping do assert_equal 2, @welcome.comments.count - assert_equal 'a comment...', @welcome.comments.what_are_you + assert_equal "a comment...", @welcome.comments.what_are_you end end @@ -345,7 +352,7 @@ class HasManyScopingTest < ActiveRecord::TestCase end def test_should_maintain_default_scope_on_eager_loaded_associations - michael = Person.where(:id => people(:michael).id).includes(:bad_references).first + michael = Person.where(id: people(:michael).id).includes(:bad_references).first magician = BadReference.find(1) assert_equal [magician], michael.bad_references end @@ -359,19 +366,19 @@ class HasAndBelongsToManyScopingTest < ActiveRecord::TestCase end def test_forwarding_of_static_methods - assert_equal 'a category...', Category.what_are_you - assert_equal 'a category...', @welcome.categories.what_are_you + assert_equal "a category...", Category.what_are_you + assert_equal "a category...", @welcome.categories.what_are_you end def test_nested_scope_finder - Category.where('1=0').scoping do + Category.where("1=0").scoping do assert_equal 0, @welcome.categories.count - assert_equal 'a category...', @welcome.categories.what_are_you + assert_equal "a category...", @welcome.categories.what_are_you end - Category.where('1=1').scoping do + Category.where("1=1").scoping do assert_equal 2, @welcome.categories.count - assert_equal 'a category...', @welcome.categories.what_are_you + assert_equal "a category...", @welcome.categories.what_are_you end end end diff --git a/activerecord/test/cases/secure_token_test.rb b/activerecord/test/cases/secure_token_test.rb index e731443fc2..eda0229c26 100644 --- a/activerecord/test/cases/secure_token_test.rb +++ b/activerecord/test/cases/secure_token_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'models/user' +require "cases/helper" +require "models/user" class SecureTokenTest < ActiveRecord::TestCase setup do diff --git a/activerecord/test/cases/serialization_test.rb b/activerecord/test/cases/serialization_test.rb index 14b80f4df4..ec33ad38f2 100644 --- a/activerecord/test/cases/serialization_test.rb +++ b/activerecord/test/cases/serialization_test.rb @@ -1,9 +1,9 @@ require "cases/helper" -require 'models/contact' -require 'models/topic' -require 'models/book' -require 'models/author' -require 'models/post' +require "models/contact" +require "models/topic" +require "models/book" +require "models/author" +require "models/post" class SerializationTest < ActiveRecord::TestCase fixtures :books @@ -12,14 +12,14 @@ class SerializationTest < ActiveRecord::TestCase def setup @contact_attributes = { - :name => 'aaron stack', - :age => 25, - :avatar => 'binarydata', - :created_at => Time.utc(2006, 8, 1), - :awesome => false, - :preferences => { :gem => '<strong>ruby</strong>' }, - :alternative_id => nil, - :id => nil + name: "aaron stack", + age: 25, + avatar: "binarydata", + created_at: Time.utc(2006, 8, 1), + awesome: false, + preferences: { gem: "<strong>ruby</strong>" }, + alternative_id: nil, + id: nil } end @@ -38,7 +38,7 @@ class SerializationTest < ActiveRecord::TestCase def test_serialize_should_allow_attribute_only_filtering FORMATS.each do |format| - @serialized = Contact.new(@contact_attributes).send("to_#{format}", :only => [ :age, :name ]) + @serialized = Contact.new(@contact_attributes).send("to_#{format}", only: [ :age, :name ]) contact = Contact.new.send("from_#{format}", @serialized) assert_equal @contact_attributes[:name], contact.name, "For #{format}" assert_nil contact.avatar, "For #{format}" @@ -47,7 +47,7 @@ class SerializationTest < ActiveRecord::TestCase def test_serialize_should_allow_attribute_except_filtering FORMATS.each do |format| - @serialized = Contact.new(@contact_attributes).send("to_#{format}", :except => [ :age, :name ]) + @serialized = Contact.new(@contact_attributes).send("to_#{format}", except: [ :age, :name ]) contact = Contact.new.send("from_#{format}", @serialized) assert_nil contact.name, "For #{format}" assert_nil contact.age, "For #{format}" @@ -60,7 +60,7 @@ class SerializationTest < ActiveRecord::TestCase ActiveRecord::Base.include_root_in_json = true klazz = Class.new(ActiveRecord::Base) - klazz.table_name = 'topics' + klazz.table_name = "topics" assert klazz.include_root_in_json klazz.include_root_in_json = false @@ -73,7 +73,7 @@ class SerializationTest < ActiveRecord::TestCase def test_read_attribute_for_serialization_with_format_without_method_missing klazz = Class.new(ActiveRecord::Base) - klazz.table_name = 'books' + klazz.table_name = "books" book = klazz.new assert_nil book.read_attribute_for_serialization(:format) @@ -81,18 +81,18 @@ class SerializationTest < ActiveRecord::TestCase def test_read_attribute_for_serialization_with_format_after_init klazz = Class.new(ActiveRecord::Base) - klazz.table_name = 'books' + klazz.table_name = "books" - book = klazz.new(format: 'paperback') - assert_equal 'paperback', book.read_attribute_for_serialization(:format) + book = klazz.new(format: "paperback") + assert_equal "paperback", book.read_attribute_for_serialization(:format) end def test_read_attribute_for_serialization_with_format_after_find klazz = Class.new(ActiveRecord::Base) - klazz.table_name = 'books' + klazz.table_name = "books" book = klazz.find(books(:awdr).id) - assert_equal 'paperback', book.read_attribute_for_serialization(:format) + assert_equal "paperback", book.read_attribute_for_serialization(:format) end def test_find_records_by_serialized_attributes_through_join diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index 846be857d0..bebd856faf 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -1,10 +1,10 @@ -require 'cases/helper' -require 'models/topic' -require 'models/reply' -require 'models/person' -require 'models/traffic_light' -require 'models/post' -require 'bcrypt' +require "cases/helper" +require "models/topic" +require "models/reply" +require "models/person" +require "models/traffic_light" +require "models/post" +require "bcrypt" class SerializedAttributeTest < ActiveRecord::TestCase fixtures :topics, :posts @@ -25,7 +25,7 @@ class SerializedAttributeTest < ActiveRecord::TestCase def test_serialized_attribute Topic.serialize("content", MyObject) - myobj = MyObject.new('value1', 'value2') + myobj = MyObject.new("value1", "value2") topic = Topic.create("content" => myobj) assert_equal(myobj, topic.content) @@ -36,7 +36,7 @@ class SerializedAttributeTest < ActiveRecord::TestCase def test_serialized_attribute_in_base_class Topic.serialize("content", Hash) - hash = { 'content1' => 'value1', 'content2' => 'value2' } + hash = { "content1" => "value1", "content2" => "value2" } important_topic = ImportantTopic.create("content" => hash) assert_equal(hash, important_topic.content) @@ -97,7 +97,7 @@ class SerializedAttributeTest < ActiveRecord::TestCase end def test_serialized_attribute_declared_in_subclass - hash = { 'important1' => 'value1', 'important2' => 'value2' } + hash = { "important1" => "value1", "important2" => "value2" } important_topic = ImportantTopic.create("important" => hash) assert_equal(hash, important_topic.important) @@ -124,26 +124,26 @@ class SerializedAttributeTest < ActiveRecord::TestCase end def test_nil_not_serialized_without_class_constraint - assert Topic.new(:content => nil).save - assert_equal 1, Topic.where(:content => nil).count + assert Topic.new(content: nil).save + assert_equal 1, Topic.where(content: nil).count end def test_nil_not_serialized_with_class_constraint Topic.serialize :content, Hash - assert Topic.new(:content => nil).save - assert_equal 1, Topic.where(:content => nil).count + assert Topic.new(content: nil).save + assert_equal 1, Topic.where(content: nil).count end def test_serialized_attribute_should_raise_exception_on_assignment_with_wrong_type Topic.serialize(:content, Hash) assert_raise(ActiveRecord::SerializationTypeMismatch) do - Topic.new(content: 'string') + Topic.new(content: "string") end end def test_should_raise_exception_on_serialized_attribute_with_type_mismatch - myobj = MyObject.new('value1', 'value2') - topic = Topic.new(:content => myobj) + myobj = MyObject.new("value1", "value2") + topic = Topic.new(content: myobj) assert topic.save Topic.serialize(:content, Hash) assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content } @@ -152,11 +152,18 @@ class SerializedAttributeTest < ActiveRecord::TestCase def test_serialized_attribute_with_class_constraint settings = { "color" => "blue" } Topic.serialize(:content, Hash) - topic = Topic.new(:content => settings) + topic = Topic.new(content: settings) assert topic.save assert_equal(settings, Topic.find(topic.id).content) end + def test_where_by_serialized_attribute_with_hash + settings = { "color" => "green" } + Topic.serialize(:content, Hash) + topic = Topic.create!(content: settings) + assert_equal topic, Topic.where(content: settings).take + end + def test_serialized_default_class Topic.serialize(:content, Hash) topic = Topic.new @@ -175,14 +182,14 @@ class SerializedAttributeTest < ActiveRecord::TestCase end def test_serialized_boolean_value_true - topic = Topic.new(:content => true) + topic = Topic.new(content: true) assert topic.save topic = topic.reload assert_equal topic.content, true end def test_serialized_boolean_value_false - topic = Topic.new(:content => false) + topic = Topic.new(content: false) assert topic.save topic = topic.reload assert_equal topic.content, false @@ -200,18 +207,18 @@ class SerializedAttributeTest < ActiveRecord::TestCase end Topic.serialize(:content, some_class) - topic = Topic.new(:content => some_class.new('my value')) + topic = Topic.new(content: some_class.new("my value")) topic.save! topic.reload assert_kind_of some_class, topic.content - assert_equal topic.content, some_class.new('my value') + assert_equal topic.content, some_class.new("my value") end def test_serialize_attribute_via_select_method_when_time_zone_available with_timezone_config aware_attributes: true do Topic.serialize(:content, MyObject) - myobj = MyObject.new('value1', 'value2') + myobj = MyObject.new("value1", "value2") topic = Topic.create(content: myobj) assert_equal(myobj, Topic.select(:content).find(topic.id).content) @@ -220,8 +227,8 @@ class SerializedAttributeTest < ActiveRecord::TestCase end def test_serialize_attribute_can_be_serialized_in_an_integer_column - insures = ['life'] - person = SerializedPerson.new(first_name: 'David', insures: insures) + insures = ["life"] + person = SerializedPerson.new(first_name: "David", insures: insures) assert person.save person = person.reload assert_equal(insures, person.insures) diff --git a/activerecord/test/cases/statement_cache_test.rb b/activerecord/test/cases/statement_cache_test.rb index 104226010a..f45f63c68e 100644 --- a/activerecord/test/cases/statement_cache_test.rb +++ b/activerecord/test/cases/statement_cache_test.rb @@ -1,8 +1,8 @@ -require 'cases/helper' -require 'models/book' -require 'models/liquid' -require 'models/molecule' -require 'models/electron' +require "cases/helper" +require "models/book" +require "models/liquid" +require "models/molecule" +require "models/electron" module ActiveRecord class StatementCacheTest < ActiveRecord::TestCase @@ -16,7 +16,7 @@ module ActiveRecord Book.create(name: "my other book") cache = StatementCache.create(Book.connection) do |params| - Book.where(:name => params.bind) + Book.where(name: params.bind) end b = cache.execute([ "my book" ], Book, Book.connection) @@ -25,7 +25,6 @@ module ActiveRecord assert_equal "my other book", b[0].name end - def test_statement_cache_id b1 = Book.create(name: "my book") b2 = Book.create(name: "my other book") @@ -65,12 +64,12 @@ module ActiveRecord def test_statement_cache_with_complex_statement cache = ActiveRecord::StatementCache.create(Book.connection) do |params| - Liquid.joins(:molecules => :electrons).where('molecules.name' => 'dioxane', 'electrons.name' => 'lepton') + Liquid.joins(molecules: :electrons).where("molecules.name" => "dioxane", "electrons.name" => "lepton") end - salty = Liquid.create(name: 'salty') - molecule = salty.molecules.create(name: 'dioxane') - molecule.electrons.create(name: 'lepton') + salty = Liquid.create(name: "salty") + molecule = salty.molecules.create(name: "dioxane") + molecule.electrons.create(name: "lepton") liquids = cache.execute([], Book, Book.connection) assert_equal "salty", liquids[0].name diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb index bce86875e1..633a8a0ebc 100644 --- a/activerecord/test/cases/store_test.rb +++ b/activerecord/test/cases/store_test.rb @@ -1,55 +1,55 @@ -require 'cases/helper' -require 'models/admin' -require 'models/admin/user' +require "cases/helper" +require "models/admin" +require "models/admin/user" class StoreTest < ActiveRecord::TestCase fixtures :'admin/users' setup do - @john = Admin::User.create!(:name => 'John Doe', :color => 'black', :remember_login => true, :height => 'tall', :is_a_good_guy => true) + @john = Admin::User.create!(name: "John Doe", color: "black", remember_login: true, height: "tall", is_a_good_guy: true) end test "reading store attributes through accessors" do - assert_equal 'black', @john.color + assert_equal "black", @john.color assert_nil @john.homepage end test "writing store attributes through accessors" do - @john.color = 'red' - @john.homepage = '37signals.com' + @john.color = "red" + @john.homepage = "37signals.com" - assert_equal 'red', @john.color - assert_equal '37signals.com', @john.homepage + assert_equal "red", @john.color + assert_equal "37signals.com", @john.homepage end test "accessing attributes not exposed by accessors" do - @john.settings[:icecream] = 'graeters' + @john.settings[:icecream] = "graeters" @john.save - assert_equal 'graeters', @john.reload.settings[:icecream] + assert_equal "graeters", @john.reload.settings[:icecream] end test "overriding a read accessor" do - @john.settings[:phone_number] = '1234567890' + @john.settings[:phone_number] = "1234567890" - assert_equal '(123) 456-7890', @john.phone_number + assert_equal "(123) 456-7890", @john.phone_number end test "overriding a read accessor using super" do @john.settings[:color] = nil - assert_equal 'red', @john.color + assert_equal "red", @john.color end test "updating the store will mark it as changed" do - @john.color = 'red' + @john.color = "red" assert @john.settings_changed? end test "updating the store populates the changed array correctly" do - @john.color = 'red' - assert_equal 'black', @john.settings_change[0]['color'] - assert_equal 'red', @john.settings_change[1]['color'] + @john.color = "red" + assert_equal "black", @john.settings_change[0]["color"] + assert_equal "red", @john.settings_change[1]["color"] end test "updating the store won't mark it as changed if an attribute isn't changed" do @@ -67,74 +67,74 @@ class StoreTest < ActiveRecord::TestCase end test "overriding a write accessor" do - @john.phone_number = '(123) 456-7890' + @john.phone_number = "(123) 456-7890" - assert_equal '1234567890', @john.settings[:phone_number] + assert_equal "1234567890", @john.settings[:phone_number] end test "overriding a write accessor using super" do - @john.color = 'yellow' + @john.color = "yellow" - assert_equal 'blue', @john.color + assert_equal "blue", @john.color end test "preserve store attributes data in HashWithIndifferentAccess format without any conversion" do - @john.json_data = ActiveSupport::HashWithIndifferentAccess.new(:height => 'tall', 'weight' => 'heavy') - @john.height = 'low' + @john.json_data = ActiveSupport::HashWithIndifferentAccess.new(:height => "tall", "weight" => "heavy") + @john.height = "low" assert_equal true, @john.json_data.instance_of?(ActiveSupport::HashWithIndifferentAccess) - assert_equal 'low', @john.json_data[:height] - assert_equal 'low', @john.json_data['height'] - assert_equal 'heavy', @john.json_data[:weight] - assert_equal 'heavy', @john.json_data['weight'] + assert_equal "low", @john.json_data[:height] + assert_equal "low", @john.json_data["height"] + assert_equal "heavy", @john.json_data[:weight] + assert_equal "heavy", @john.json_data["weight"] end test "convert store attributes from Hash to HashWithIndifferentAccess saving the data and access attributes indifferently" do - user = Admin::User.find_by_name('Jamis') - assert_equal 'symbol', user.settings[:symbol] - assert_equal 'symbol', user.settings['symbol'] - assert_equal 'string', user.settings[:string] - assert_equal 'string', user.settings['string'] + user = Admin::User.find_by_name("Jamis") + assert_equal "symbol", user.settings[:symbol] + assert_equal "symbol", user.settings["symbol"] + assert_equal "string", user.settings[:string] + assert_equal "string", user.settings["string"] assert_equal true, user.settings.instance_of?(ActiveSupport::HashWithIndifferentAccess) - user.height = 'low' - assert_equal 'symbol', user.settings[:symbol] - assert_equal 'symbol', user.settings['symbol'] - assert_equal 'string', user.settings[:string] - assert_equal 'string', user.settings['string'] + user.height = "low" + assert_equal "symbol", user.settings[:symbol] + assert_equal "symbol", user.settings["symbol"] + assert_equal "string", user.settings[:string] + assert_equal "string", user.settings["string"] assert_equal true, user.settings.instance_of?(ActiveSupport::HashWithIndifferentAccess) end test "convert store attributes from any format other than Hash or HashWithIndifferentAccess losing the data" do @john.json_data = "somedata" - @john.height = 'low' + @john.height = "low" assert_equal true, @john.json_data.instance_of?(ActiveSupport::HashWithIndifferentAccess) - assert_equal 'low', @john.json_data[:height] - assert_equal 'low', @john.json_data['height'] - assert_equal false, @john.json_data.delete_if { |k, v| k == 'height' }.any? + assert_equal "low", @john.json_data[:height] + assert_equal "low", @john.json_data["height"] + assert_equal false, @john.json_data.delete_if { |k, v| k == "height" }.any? end test "reading store attributes through accessors encoded with JSON" do - assert_equal 'tall', @john.height + assert_equal "tall", @john.height assert_nil @john.weight end test "writing store attributes through accessors encoded with JSON" do - @john.height = 'short' - @john.weight = 'heavy' + @john.height = "short" + @john.weight = "heavy" - assert_equal 'short', @john.height - assert_equal 'heavy', @john.weight + assert_equal "short", @john.height + assert_equal "heavy", @john.weight end test "accessing attributes not exposed by accessors encoded with JSON" do - @john.json_data['somestuff'] = 'somecoolstuff' + @john.json_data["somestuff"] = "somecoolstuff" @john.save - assert_equal 'somecoolstuff', @john.reload.json_data['somestuff'] + assert_equal "somecoolstuff", @john.reload.json_data["somestuff"] end test "updating the store will mark it as changed encoded with JSON" do - @john.height = 'short' + @john.height = "short" assert @john.json_data_changed? end diff --git a/activerecord/test/cases/suppressor_test.rb b/activerecord/test/cases/suppressor_test.rb index 2f00241de2..a7d16b7cdb 100644 --- a/activerecord/test/cases/suppressor_test.rb +++ b/activerecord/test/cases/suppressor_test.rb @@ -1,6 +1,6 @@ -require 'cases/helper' -require 'models/notification' -require 'models/user' +require "cases/helper" +require "models/notification" +require "models/user" class SuppressorTest < ActiveRecord::TestCase def test_suppresses_create @@ -15,22 +15,22 @@ class SuppressorTest < ActiveRecord::TestCase end def test_suppresses_update - user = User.create! token: 'asdf' + user = User.create! token: "asdf" User.suppress do - user.update token: 'ghjkl' - assert_equal 'asdf', user.reload.token + user.update token: "ghjkl" + assert_equal "asdf", user.reload.token - user.update! token: 'zxcvbnm' - assert_equal 'asdf', user.reload.token + user.update! token: "zxcvbnm" + assert_equal "asdf", user.reload.token - user.token = 'qwerty' + user.token = "qwerty" user.save - assert_equal 'asdf', user.reload.token + assert_equal "asdf", user.reload.token - user.token = 'uiop' + user.token = "uiop" user.save! - assert_equal 'asdf', user.reload.token + assert_equal "asdf", user.reload.token end end @@ -64,7 +64,7 @@ class SuppressorTest < ActiveRecord::TestCase def test_suppresses_when_nested_multiple_times assert_no_difference -> { Notification.count } do Notification.suppress do - Notification.suppress { } + Notification.suppress {} Notification.create Notification.create! Notification.new.save diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb index 510bb088c8..d847a02679 100644 --- a/activerecord/test/cases/tasks/database_tasks_test.rb +++ b/activerecord/test/cases/tasks/database_tasks_test.rb @@ -1,5 +1,5 @@ -require 'cases/helper' -require 'active_record/tasks/database_tasks' +require "cases/helper" +require "active_record/tasks/database_tasks" module ActiveRecord module DatabaseTasksSetupper @@ -30,7 +30,7 @@ module ActiveRecord protected_environments = ActiveRecord::Base.protected_environments.dup current_env = ActiveRecord::Migrator.current_environment - assert !protected_environments.include?(current_env) + assert_not_includes protected_environments, current_env # Assert no error ActiveRecord::Tasks::DatabaseTasks.check_protected_environments! @@ -64,12 +64,12 @@ module ActiveRecord instance.expects(:structure_dump).with("awesome-file.sql") ActiveRecord::Tasks::DatabaseTasks.register_task(/foo/, klazz) - ActiveRecord::Tasks::DatabaseTasks.structure_dump({'adapter' => :foo}, "awesome-file.sql") + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :foo }, "awesome-file.sql") end def test_unregistered_task assert_raise(ActiveRecord::Tasks::DatabaseNotSupported) do - ActiveRecord::Tasks::DatabaseTasks.structure_dump({'adapter' => :bar}, "awesome-file.sql") + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => :bar }, "awesome-file.sql") end end end @@ -80,20 +80,20 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_create") do eval("@#{v}").expects(:create) - ActiveRecord::Tasks::DatabaseTasks.create 'adapter' => k + ActiveRecord::Tasks::DatabaseTasks.create "adapter" => k end end end class DatabaseTasksCreateAllTest < ActiveRecord::TestCase def setup - @configurations = {'development' => {'database' => 'my-db'}} + @configurations = { "development" => { "database" => "my-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) end def test_ignores_configurations_without_databases - @configurations['development'].merge!('database' => nil) + @configurations["development"].merge!("database" => nil) ActiveRecord::Tasks::DatabaseTasks.expects(:create).never @@ -101,7 +101,7 @@ module ActiveRecord end def test_ignores_remote_databases - @configurations['development'].merge!('host' => 'my.server.tld') + @configurations["development"].merge!("host" => "my.server.tld") $stderr.stubs(:puts).returns(nil) ActiveRecord::Tasks::DatabaseTasks.expects(:create).never @@ -110,15 +110,15 @@ module ActiveRecord end def test_warning_for_remote_databases - @configurations['development'].merge!('host' => 'my.server.tld') + @configurations["development"].merge!("host" => "my.server.tld") - $stderr.expects(:puts).with('This task only modifies local databases. my-db is on a remote host.') + $stderr.expects(:puts).with("This task only modifies local databases. my-db is on a remote host.") ActiveRecord::Tasks::DatabaseTasks.create_all end def test_creates_configurations_with_local_ip - @configurations['development'].merge!('host' => '127.0.0.1') + @configurations["development"].merge!("host" => "127.0.0.1") ActiveRecord::Tasks::DatabaseTasks.expects(:create) @@ -126,7 +126,7 @@ module ActiveRecord end def test_creates_configurations_with_local_host - @configurations['development'].merge!('host' => 'localhost') + @configurations["development"].merge!("host" => "localhost") ActiveRecord::Tasks::DatabaseTasks.expects(:create) @@ -134,7 +134,7 @@ module ActiveRecord end def test_creates_configurations_with_blank_hosts - @configurations['development'].merge!('host' => nil) + @configurations["development"].merge!("host" => nil) ActiveRecord::Tasks::DatabaseTasks.expects(:create) @@ -145,9 +145,9 @@ module ActiveRecord class DatabaseTasksCreateCurrentTest < ActiveRecord::TestCase def setup @configurations = { - 'development' => {'database' => 'dev-db'}, - 'test' => {'database' => 'test-db'}, - 'production' => {'database' => 'prod-db'} + "development" => { "database" => "dev-db" }, + "test" => { "database" => "test-db" }, + "production" => { "database" => "prod-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) @@ -156,37 +156,37 @@ module ActiveRecord def test_creates_current_environment_database ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with('database' => 'prod-db') + with("database" => "prod-db") ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new('production') + ActiveSupport::StringInquirer.new("production") ) end def test_creates_test_and_development_databases_when_env_was_not_specified ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with('database' => 'dev-db') + with("database" => "dev-db") ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with('database' => 'test-db') + with("database" => "test-db") ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new('development') + ActiveSupport::StringInquirer.new("development") ) end def test_creates_test_and_development_databases_when_rails_env_is_development - old_env = ENV['RAILS_ENV'] - ENV['RAILS_ENV'] = 'development' + old_env = ENV["RAILS_ENV"] + ENV["RAILS_ENV"] = "development" ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with('database' => 'dev-db') + with("database" => "dev-db") ActiveRecord::Tasks::DatabaseTasks.expects(:create). - with('database' => 'test-db') + with("database" => "test-db") ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new('development') + ActiveSupport::StringInquirer.new("development") ) ensure - ENV['RAILS_ENV'] = old_env + ENV["RAILS_ENV"] = old_env end def test_establishes_connection_for_the_given_environment @@ -195,7 +195,7 @@ module ActiveRecord ActiveRecord::Base.expects(:establish_connection).with(:development) ActiveRecord::Tasks::DatabaseTasks.create_current( - ActiveSupport::StringInquirer.new('development') + ActiveSupport::StringInquirer.new("development") ) end end @@ -206,20 +206,20 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_drop") do eval("@#{v}").expects(:drop) - ActiveRecord::Tasks::DatabaseTasks.drop 'adapter' => k + ActiveRecord::Tasks::DatabaseTasks.drop "adapter" => k end end end class DatabaseTasksDropAllTest < ActiveRecord::TestCase def setup - @configurations = {:development => {'database' => 'my-db'}} + @configurations = { development: { "database" => "my-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) end def test_ignores_configurations_without_databases - @configurations[:development].merge!('database' => nil) + @configurations[:development].merge!("database" => nil) ActiveRecord::Tasks::DatabaseTasks.expects(:drop).never @@ -227,7 +227,7 @@ module ActiveRecord end def test_ignores_remote_databases - @configurations[:development].merge!('host' => 'my.server.tld') + @configurations[:development].merge!("host" => "my.server.tld") $stderr.stubs(:puts).returns(nil) ActiveRecord::Tasks::DatabaseTasks.expects(:drop).never @@ -236,15 +236,15 @@ module ActiveRecord end def test_warning_for_remote_databases - @configurations[:development].merge!('host' => 'my.server.tld') + @configurations[:development].merge!("host" => "my.server.tld") - $stderr.expects(:puts).with('This task only modifies local databases. my-db is on a remote host.') + $stderr.expects(:puts).with("This task only modifies local databases. my-db is on a remote host.") ActiveRecord::Tasks::DatabaseTasks.drop_all end def test_drops_configurations_with_local_ip - @configurations[:development].merge!('host' => '127.0.0.1') + @configurations[:development].merge!("host" => "127.0.0.1") ActiveRecord::Tasks::DatabaseTasks.expects(:drop) @@ -252,7 +252,7 @@ module ActiveRecord end def test_drops_configurations_with_local_host - @configurations[:development].merge!('host' => 'localhost') + @configurations[:development].merge!("host" => "localhost") ActiveRecord::Tasks::DatabaseTasks.expects(:drop) @@ -260,7 +260,7 @@ module ActiveRecord end def test_drops_configurations_with_blank_hosts - @configurations[:development].merge!('host' => nil) + @configurations[:development].merge!("host" => nil) ActiveRecord::Tasks::DatabaseTasks.expects(:drop) @@ -271,9 +271,9 @@ module ActiveRecord class DatabaseTasksDropCurrentTest < ActiveRecord::TestCase def setup @configurations = { - 'development' => {'database' => 'dev-db'}, - 'test' => {'database' => 'test-db'}, - 'production' => {'database' => 'prod-db'} + "development" => { "database" => "dev-db" }, + "test" => { "database" => "test-db" }, + "production" => { "database" => "prod-db" } } ActiveRecord::Base.stubs(:configurations).returns(@configurations) @@ -281,37 +281,37 @@ module ActiveRecord def test_drops_current_environment_database ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with('database' => 'prod-db') + with("database" => "prod-db") ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new('production') + ActiveSupport::StringInquirer.new("production") ) end def test_drops_test_and_development_databases_when_env_was_not_specified ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with('database' => 'dev-db') + with("database" => "dev-db") ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with('database' => 'test-db') + with("database" => "test-db") ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new('development') + ActiveSupport::StringInquirer.new("development") ) end def test_drops_testand_development_databases_when_rails_env_is_development - old_env = ENV['RAILS_ENV'] - ENV['RAILS_ENV'] = 'development' + old_env = ENV["RAILS_ENV"] + ENV["RAILS_ENV"] = "development" ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with('database' => 'dev-db') + with("database" => "dev-db") ActiveRecord::Tasks::DatabaseTasks.expects(:drop). - with('database' => 'test-db') + with("database" => "test-db") ActiveRecord::Tasks::DatabaseTasks.drop_current( - ActiveSupport::StringInquirer.new('development') + ActiveSupport::StringInquirer.new("development") ) ensure - ENV['RAILS_ENV'] = old_env + ENV["RAILS_ENV"] = old_env end end @@ -319,7 +319,7 @@ module ActiveRecord self.use_transactional_tests = false def setup - ActiveRecord::Tasks::DatabaseTasks.migrations_paths = 'custom/path' + ActiveRecord::Tasks::DatabaseTasks.migrations_paths = "custom/path" end def teardown @@ -327,15 +327,15 @@ module ActiveRecord end def test_migrate_receives_correct_env_vars - verbose, version = ENV['VERBOSE'], ENV['VERSION'] + verbose, version = ENV["VERBOSE"], ENV["VERSION"] - ENV['VERBOSE'] = 'false' - ENV['VERSION'] = '4' + ENV["VERBOSE"] = "false" + ENV["VERSION"] = "4" - ActiveRecord::Migrator.expects(:migrate).with('custom/path', 4) + ActiveRecord::Migrator.expects(:migrate).with("custom/path", 4) ActiveRecord::Tasks::DatabaseTasks.migrate ensure - ENV['VERBOSE'], ENV['VERSION'] = verbose, version + ENV["VERBOSE"], ENV["VERSION"] = verbose, version end def test_migrate_clears_schema_cache_afterward @@ -350,7 +350,7 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_purge") do eval("@#{v}").expects(:purge) - ActiveRecord::Tasks::DatabaseTasks.purge 'adapter' => k + ActiveRecord::Tasks::DatabaseTasks.purge "adapter" => k end end end @@ -358,27 +358,27 @@ module ActiveRecord class DatabaseTasksPurgeCurrentTest < ActiveRecord::TestCase def test_purges_current_environment_database configurations = { - 'development' => {'database' => 'dev-db'}, - 'test' => {'database' => 'test-db'}, - 'production' => {'database' => 'prod-db'} + "development" => { "database" => "dev-db" }, + "test" => { "database" => "test-db" }, + "production" => { "database" => "prod-db" } } ActiveRecord::Base.stubs(:configurations).returns(configurations) ActiveRecord::Tasks::DatabaseTasks.expects(:purge). - with('database' => 'prod-db') + with("database" => "prod-db") ActiveRecord::Base.expects(:establish_connection).with(:production) - ActiveRecord::Tasks::DatabaseTasks.purge_current('production') + ActiveRecord::Tasks::DatabaseTasks.purge_current("production") end end class DatabaseTasksPurgeAllTest < ActiveRecord::TestCase def test_purge_all_local_configurations - configurations = {:development => {'database' => 'my-db'}} + configurations = { development: { "database" => "my-db" } } ActiveRecord::Base.stubs(:configurations).returns(configurations) ActiveRecord::Tasks::DatabaseTasks.expects(:purge). - with('database' => 'my-db') + with("database" => "my-db") ActiveRecord::Tasks::DatabaseTasks.purge_all end @@ -390,7 +390,7 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_charset") do eval("@#{v}").expects(:charset) - ActiveRecord::Tasks::DatabaseTasks.charset 'adapter' => k + ActiveRecord::Tasks::DatabaseTasks.charset "adapter" => k end end end @@ -401,7 +401,7 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_collation") do eval("@#{v}").expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation 'adapter' => k + ActiveRecord::Tasks::DatabaseTasks.collation "adapter" => k end end end @@ -412,7 +412,7 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_dump") do eval("@#{v}").expects(:structure_dump).with("awesome-file.sql") - ActiveRecord::Tasks::DatabaseTasks.structure_dump({'adapter' => k}, "awesome-file.sql") + ActiveRecord::Tasks::DatabaseTasks.structure_dump({ "adapter" => k }, "awesome-file.sql") end end end @@ -423,7 +423,7 @@ module ActiveRecord ADAPTERS_TASKS.each do |k, v| define_method("test_#{k}_structure_load") do eval("@#{v}").expects(:structure_load).with("awesome-file.sql") - ActiveRecord::Tasks::DatabaseTasks.structure_load({'adapter' => k}, "awesome-file.sql") + ActiveRecord::Tasks::DatabaseTasks.structure_load({ "adapter" => k }, "awesome-file.sql") end end end @@ -437,15 +437,15 @@ module ActiveRecord class DatabaseTasksCheckSchemaFileDefaultsTest < ActiveRecord::TestCase def test_check_schema_file_defaults - ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns('/tmp') - assert_equal '/tmp/schema.rb', ActiveRecord::Tasks::DatabaseTasks.schema_file + ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns("/tmp") + assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.schema_file end end class DatabaseTasksCheckSchemaFileSpecifiedFormatsTest < ActiveRecord::TestCase - {ruby: 'schema.rb', sql: 'structure.sql'}.each_pair do |fmt, filename| + { ruby: "schema.rb", sql: "structure.sql" }.each_pair do |fmt, filename| define_method("test_check_schema_file_for_#{fmt}_format") do - ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns('/tmp') + ActiveRecord::Tasks::DatabaseTasks.stubs(:db_dir).returns("/tmp") assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_file(fmt) end end diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index 70e406038f..dbe935808e 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -1,345 +1,345 @@ -require 'cases/helper' -require 'active_record/tasks/database_tasks' +require "cases/helper" +require "active_record/tasks/database_tasks" if current_adapter?(:Mysql2Adapter) -module ActiveRecord - class MysqlDBCreateTest < ActiveRecord::TestCase - def setup - @connection = stub(:create_database => true) - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'my-app-db' - } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - - $stdout, @original_stdout = StringIO.new, $stdout - $stderr, @original_stderr = StringIO.new, $stderr - end + module ActiveRecord + class MysqlDBCreateTest < ActiveRecord::TestCase + def setup + @connection = stub(create_database: true) + @configuration = { + "adapter" => "mysql2", + "database" => "my-app-db" + } + + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end - def teardown - $stdout, $stderr = @original_stdout, @original_stderr - end + def teardown + $stdout, $stderr = @original_stdout, @original_stderr + end - def test_establishes_connection_without_database - ActiveRecord::Base.expects(:establish_connection). - with('adapter' => 'mysql2', 'database' => nil) + def test_establishes_connection_without_database + ActiveRecord::Base.expects(:establish_connection). + with("adapter" => "mysql2", "database" => nil) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_creates_database_with_no_default_options - @connection.expects(:create_database). - with('my-app-db', {}) + def test_creates_database_with_no_default_options + @connection.expects(:create_database). + with("my-app-db", {}) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_creates_database_with_given_encoding - @connection.expects(:create_database). - with('my-app-db', charset: 'latin1') + def test_creates_database_with_given_encoding + @connection.expects(:create_database). + with("my-app-db", charset: "latin1") - ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge('encoding' => 'latin1') - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("encoding" => "latin1") + end - def test_creates_database_with_given_collation - @connection.expects(:create_database). - with('my-app-db', collation: 'latin1_swedish_ci') + def test_creates_database_with_given_collation + @connection.expects(:create_database). + with("my-app-db", collation: "latin1_swedish_ci") - ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge('collation' => 'latin1_swedish_ci') - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge("collation" => "latin1_swedish_ci") + end - def test_establishes_connection_to_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + def test_establishes_connection_to_database + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_when_database_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration + def test_when_database_created_successfully_outputs_info_to_stdout + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stdout.string, "Created database 'my-app-db'\n" - end + assert_equal $stdout.string, "Created database 'my-app-db'\n" + end - def test_create_when_database_exists_outputs_info_to_stderr - ActiveRecord::Base.connection.stubs(:create_database).raises( - ActiveRecord::Tasks::DatabaseAlreadyExists - ) + def test_create_when_database_exists_outputs_info_to_stderr + ActiveRecord::Base.connection.stubs(:create_database).raises( + ActiveRecord::Tasks::DatabaseAlreadyExists + ) - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stderr.string, "Database 'my-app-db' already exists\n" + assert_equal $stderr.string, "Database 'my-app-db' already exists\n" + end end - end - class MysqlDBCreateAsRootTest < ActiveRecord::TestCase - def setup - @connection = stub("Connection", create_database: true) - @error = Mysql2::Error.new("Invalid permissions") - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'my-app-db', - 'username' => 'pat', - 'password' => 'wossname' - } - - $stdin.stubs(:gets).returns("secret\n") - $stdout.stubs(:print).returns(nil) - @error.stubs(:errno).returns(1045) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection). - raises(@error). - then.returns(true) - - $stdout, @original_stdout = StringIO.new, $stdout - $stderr, @original_stderr = StringIO.new, $stderr - end + class MysqlDBCreateAsRootTest < ActiveRecord::TestCase + def setup + @connection = stub("Connection", create_database: true) + @error = Mysql2::Error.new("Invalid permissions") + @configuration = { + "adapter" => "mysql2", + "database" => "my-app-db", + "username" => "pat", + "password" => "wossname" + } + + $stdin.stubs(:gets).returns("secret\n") + $stdout.stubs(:print).returns(nil) + @error.stubs(:errno).returns(1045) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection). + raises(@error). + then.returns(true) + + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end - def teardown - $stdout, $stderr = @original_stdout, @original_stderr - end + def teardown + $stdout, $stderr = @original_stdout, @original_stderr + end - def test_root_password_is_requested - assert_permissions_granted_for("pat") - $stdin.expects(:gets).returns("secret\n") + def test_root_password_is_requested + assert_permissions_granted_for("pat") + $stdin.expects(:gets).returns("secret\n") - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_connection_established_as_root - assert_permissions_granted_for("pat") - ActiveRecord::Base.expects(:establish_connection).with( - 'adapter' => 'mysql2', - 'database' => nil, - 'username' => 'root', - 'password' => 'secret' - ) + def test_connection_established_as_root + assert_permissions_granted_for("pat") + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "mysql2", + "database" => nil, + "username" => "root", + "password" => "secret" + ) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_database_created_by_root - assert_permissions_granted_for("pat") - @connection.expects(:create_database). - with('my-app-db', {}) + def test_database_created_by_root + assert_permissions_granted_for("pat") + @connection.expects(:create_database). + with("my-app-db", {}) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_grant_privileges_for_normal_user - assert_permissions_granted_for("pat") - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + def test_grant_privileges_for_normal_user + assert_permissions_granted_for("pat") + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_do_not_grant_privileges_for_root_user - @configuration['username'] = 'root' - @configuration['password'] = '' - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + def test_do_not_grant_privileges_for_root_user + @configuration["username"] = "root" + @configuration["password"] = "" + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_connection_established_as_normal_user - assert_permissions_granted_for("pat") - ActiveRecord::Base.expects(:establish_connection).returns do - ActiveRecord::Base.expects(:establish_connection).with( - 'adapter' => 'mysql2', - 'database' => 'my-app-db', - 'username' => 'pat', - 'password' => 'secret' - ) + def test_connection_established_as_normal_user + assert_permissions_granted_for("pat") + ActiveRecord::Base.expects(:establish_connection).returns do + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "mysql2", + "database" => "my-app-db", + "username" => "pat", + "password" => "secret" + ) - raise @error - end + raise @error + end - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_sends_output_to_stderr_when_other_errors - @error.stubs(:errno).returns(42) + def test_sends_output_to_stderr_when_other_errors + @error.stubs(:errno).returns(42) - $stderr.expects(:puts).at_least_once.returns(nil) + $stderr.expects(:puts).at_least_once.returns(nil) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - private + private - def assert_permissions_granted_for(db_user) - db_name = @configuration['database'] - db_password = @configuration['password'] - @connection.expects(:execute).with("GRANT ALL PRIVILEGES ON #{db_name}.* TO '#{db_user}'@'localhost' IDENTIFIED BY '#{db_password}' WITH GRANT OPTION;") + def assert_permissions_granted_for(db_user) + db_name = @configuration["database"] + db_password = @configuration["password"] + @connection.expects(:execute).with("GRANT ALL PRIVILEGES ON #{db_name}.* TO '#{db_user}'@'localhost' IDENTIFIED BY '#{db_password}' WITH GRANT OPTION;") + end end - end - class MySQLDBDropTest < ActiveRecord::TestCase - def setup - @connection = stub(:drop_database => true) - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'my-app-db' - } + class MySQLDBDropTest < ActiveRecord::TestCase + def setup + @connection = stub(drop_database: true) + @configuration = { + "adapter" => "mysql2", + "database" => "my-app-db" + } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout - $stderr, @original_stderr = StringIO.new, $stderr - end + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end - def teardown - $stdout, $stderr = @original_stdout, @original_stderr - end + def teardown + $stdout, $stderr = @original_stdout, @original_stderr + end - def test_establishes_connection_to_mysql_database - ActiveRecord::Base.expects(:establish_connection).with @configuration + def test_establishes_connection_to_mysql_database + ActiveRecord::Base.expects(:establish_connection).with @configuration - ActiveRecord::Tasks::DatabaseTasks.drop @configuration - end + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end - def test_drops_database - @connection.expects(:drop_database).with('my-app-db') + def test_drops_database + @connection.expects(:drop_database).with("my-app-db") - ActiveRecord::Tasks::DatabaseTasks.drop @configuration - end + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end - def test_when_database_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + def test_when_database_dropped_successfully_outputs_info_to_stdout + ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal $stdout.string, "Dropped database 'my-app-db'\n" + assert_equal $stdout.string, "Dropped database 'my-app-db'\n" + end end - end - class MySQLPurgeTest < ActiveRecord::TestCase - def setup - @connection = stub(:recreate_database => true) - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'test-db' - } + class MySQLPurgeTest < ActiveRecord::TestCase + def setup + @connection = stub(recreate_database: true) + @configuration = { + "adapter" => "mysql2", + "database" => "test-db" + } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + end - def test_establishes_connection_to_the_appropriate_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + def test_establishes_connection_to_the_appropriate_database + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration - end + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end - def test_recreates_database_with_no_default_options - @connection.expects(:recreate_database). - with('test-db', {}) + def test_recreates_database_with_no_default_options + @connection.expects(:recreate_database). + with("test-db", {}) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration - end + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end - def test_recreates_database_with_the_given_options - @connection.expects(:recreate_database). - with('test-db', charset: 'latin', collation: 'latin1_swedish_ci') + def test_recreates_database_with_the_given_options + @connection.expects(:recreate_database). + with("test-db", charset: "latin", collation: "latin1_swedish_ci") - ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge( - 'encoding' => 'latin', 'collation' => 'latin1_swedish_ci') + ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge( + "encoding" => "latin", "collation" => "latin1_swedish_ci") + end end - end - class MysqlDBCharsetTest < ActiveRecord::TestCase - def setup - @connection = stub(:create_database => true) - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'my-app-db' - } + class MysqlDBCharsetTest < ActiveRecord::TestCase + def setup + @connection = stub(create_database: true) + @configuration = { + "adapter" => "mysql2", + "database" => "my-app-db" + } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + end - def test_db_retrieves_charset - @connection.expects(:charset) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration + def test_db_retrieves_charset + @connection.expects(:charset) + ActiveRecord::Tasks::DatabaseTasks.charset @configuration + end end - end - class MysqlDBCollationTest < ActiveRecord::TestCase - def setup - @connection = stub(:create_database => true) - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'my-app-db' - } + class MysqlDBCollationTest < ActiveRecord::TestCase + def setup + @connection = stub(create_database: true) + @configuration = { + "adapter" => "mysql2", + "database" => "my-app-db" + } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + end - def test_db_retrieves_collation - @connection.expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation @configuration + def test_db_retrieves_collation + @connection.expects(:collation) + ActiveRecord::Tasks::DatabaseTasks.collation @configuration + end end - end - class MySQLStructureDumpTest < ActiveRecord::TestCase - def setup - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'test-db' - } - end + class MySQLStructureDumpTest < ActiveRecord::TestCase + def setup + @configuration = { + "adapter" => "mysql2", + "database" => "test-db" + } + end - def test_structure_dump - filename = "awesome-file.sql" - Kernel.expects(:system).with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) + def test_structure_dump + filename = "awesome-file.sql" + Kernel.expects(:system).with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) - end + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) + end - def test_warn_when_external_structure_dump_command_execution_fails - filename = "awesome-file.sql" - Kernel.expects(:system) - .with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db") - .returns(false) + def test_warn_when_external_structure_dump_command_execution_fails + filename = "awesome-file.sql" + Kernel.expects(:system) + .with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db") + .returns(false) - e = assert_raise(RuntimeError) { - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) - } - assert_match(/^failed to execute: `mysqldump`$/, e.message) - end + e = assert_raise(RuntimeError) { + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) + } + assert_match(/^failed to execute: `mysqldump`$/, e.message) + end - def test_structure_dump_with_port_number - filename = "awesome-file.sql" - Kernel.expects(:system).with("mysqldump", "--port=10000", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) + def test_structure_dump_with_port_number + filename = "awesome-file.sql" + Kernel.expects(:system).with("mysqldump", "--port=10000", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) - ActiveRecord::Tasks::DatabaseTasks.structure_dump( - @configuration.merge('port' => 10000), - filename) - end + ActiveRecord::Tasks::DatabaseTasks.structure_dump( + @configuration.merge("port" => 10000), + filename) + end - def test_structure_dump_with_ssl - filename = "awesome-file.sql" - Kernel.expects(:system).with("mysqldump", "--ssl-ca=ca.crt", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) + def test_structure_dump_with_ssl + filename = "awesome-file.sql" + Kernel.expects(:system).with("mysqldump", "--ssl-ca=ca.crt", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) - ActiveRecord::Tasks::DatabaseTasks.structure_dump( - @configuration.merge("sslca" => "ca.crt"), - filename) + ActiveRecord::Tasks::DatabaseTasks.structure_dump( + @configuration.merge("sslca" => "ca.crt"), + filename) + end end - end - class MySQLStructureLoadTest < ActiveRecord::TestCase - def setup - @configuration = { - 'adapter' => 'mysql2', - 'database' => 'test-db' - } - end + class MySQLStructureLoadTest < ActiveRecord::TestCase + def setup + @configuration = { + "adapter" => "mysql2", + "database" => "test-db" + } + end - def test_structure_load - filename = "awesome-file.sql" - Kernel.expects(:system).with('mysql', '--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}, "--database", "test-db") - .returns(true) + def test_structure_load + filename = "awesome-file.sql" + Kernel.expects(:system).with("mysql", "--execute", %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}, "--database", "test-db") + .returns(true) - ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + end end end end -end diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb index 99d73e91a4..b8c8ec88f0 100644 --- a/activerecord/test/cases/tasks/postgresql_rake_test.rb +++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb @@ -1,304 +1,304 @@ -require 'cases/helper' -require 'active_record/tasks/database_tasks' +require "cases/helper" +require "active_record/tasks/database_tasks" if current_adapter?(:PostgreSQLAdapter) -module ActiveRecord - class PostgreSQLDBCreateTest < ActiveRecord::TestCase - def setup - @connection = stub(:create_database => true) - @configuration = { - 'adapter' => 'postgresql', - 'database' => 'my-app-db' - } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - - $stdout, @original_stdout = StringIO.new, $stdout - $stderr, @original_stderr = StringIO.new, $stderr - end + module ActiveRecord + class PostgreSQLDBCreateTest < ActiveRecord::TestCase + def setup + @connection = stub(create_database: true) + @configuration = { + "adapter" => "postgresql", + "database" => "my-app-db" + } + + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end - def teardown - $stdout, $stderr = @original_stdout, @original_stderr - end + def teardown + $stdout, $stderr = @original_stdout, @original_stderr + end - def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - 'adapter' => 'postgresql', - 'database' => 'postgres', - 'schema_search_path' => 'public' - ) + def test_establishes_connection_to_postgresql_database + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_creates_database_with_default_encoding - @connection.expects(:create_database). - with('my-app-db', @configuration.merge('encoding' => 'utf8')) + def test_creates_database_with_default_encoding + @connection.expects(:create_database). + with("my-app-db", @configuration.merge("encoding" => "utf8")) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_creates_database_with_given_encoding - @connection.expects(:create_database). - with('my-app-db', @configuration.merge('encoding' => 'latin')) + def test_creates_database_with_given_encoding + @connection.expects(:create_database). + with("my-app-db", @configuration.merge("encoding" => "latin")) - ActiveRecord::Tasks::DatabaseTasks.create @configuration. - merge('encoding' => 'latin') - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration. + merge("encoding" => "latin") + end - def test_creates_database_with_given_collation_and_ctype - @connection.expects(:create_database). - with('my-app-db', @configuration.merge('encoding' => 'utf8', 'collation' => 'ja_JP.UTF8', 'ctype' => 'ja_JP.UTF8')) + def test_creates_database_with_given_collation_and_ctype + @connection.expects(:create_database). + with("my-app-db", @configuration.merge("encoding" => "utf8", "collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8")) - ActiveRecord::Tasks::DatabaseTasks.create @configuration. - merge('collation' => 'ja_JP.UTF8', 'ctype' => 'ja_JP.UTF8') - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration. + merge("collation" => "ja_JP.UTF8", "ctype" => "ja_JP.UTF8") + end - def test_establishes_connection_to_new_database - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + def test_establishes_connection_to_new_database + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.create @configuration - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration + end - def test_db_create_with_error_prints_message - ActiveRecord::Base.stubs(:establish_connection).raises(Exception) + def test_db_create_with_error_prints_message + ActiveRecord::Base.stubs(:establish_connection).raises(Exception) - $stderr.stubs(:puts).returns(true) - $stderr.expects(:puts). - with("Couldn't create database for #{@configuration.inspect}") + $stderr.stubs(:puts).returns(true) + $stderr.expects(:puts). + with("Couldn't create database for #{@configuration.inspect}") - assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration } - end + assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration } + end - def test_when_database_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration + def test_when_database_created_successfully_outputs_info_to_stdout + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stdout.string, "Created database 'my-app-db'\n" - end + assert_equal $stdout.string, "Created database 'my-app-db'\n" + end - def test_create_when_database_exists_outputs_info_to_stderr - ActiveRecord::Base.connection.stubs(:create_database).raises( - ActiveRecord::Tasks::DatabaseAlreadyExists - ) + def test_create_when_database_exists_outputs_info_to_stderr + ActiveRecord::Base.connection.stubs(:create_database).raises( + ActiveRecord::Tasks::DatabaseAlreadyExists + ) - ActiveRecord::Tasks::DatabaseTasks.create @configuration + ActiveRecord::Tasks::DatabaseTasks.create @configuration - assert_equal $stderr.string, "Database 'my-app-db' already exists\n" + assert_equal $stderr.string, "Database 'my-app-db' already exists\n" + end end - end - class PostgreSQLDBDropTest < ActiveRecord::TestCase - def setup - @connection = stub(:drop_database => true) - @configuration = { - 'adapter' => 'postgresql', - 'database' => 'my-app-db' - } + class PostgreSQLDBDropTest < ActiveRecord::TestCase + def setup + @connection = stub(drop_database: true) + @configuration = { + "adapter" => "postgresql", + "database" => "my-app-db" + } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) - $stdout, @original_stdout = StringIO.new, $stdout - $stderr, @original_stderr = StringIO.new, $stderr - end + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end - def teardown - $stdout, $stderr = @original_stdout, @original_stderr - end + def teardown + $stdout, $stderr = @original_stdout, @original_stderr + end - def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - 'adapter' => 'postgresql', - 'database' => 'postgres', - 'schema_search_path' => 'public' - ) + def test_establishes_connection_to_postgresql_database + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ) - ActiveRecord::Tasks::DatabaseTasks.drop @configuration - end + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end - def test_drops_database - @connection.expects(:drop_database).with('my-app-db') + def test_drops_database + @connection.expects(:drop_database).with("my-app-db") - ActiveRecord::Tasks::DatabaseTasks.drop @configuration - end + ActiveRecord::Tasks::DatabaseTasks.drop @configuration + end - def test_when_database_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration + def test_when_database_dropped_successfully_outputs_info_to_stdout + ActiveRecord::Tasks::DatabaseTasks.drop @configuration - assert_equal $stdout.string, "Dropped database 'my-app-db'\n" + assert_equal $stdout.string, "Dropped database 'my-app-db'\n" + end end - end - class PostgreSQLPurgeTest < ActiveRecord::TestCase - def setup - @connection = stub(:create_database => true, :drop_database => true) - @configuration = { - 'adapter' => 'postgresql', - 'database' => 'my-app-db' - } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:clear_active_connections!).returns(true) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + class PostgreSQLPurgeTest < ActiveRecord::TestCase + def setup + @connection = stub(create_database: true, drop_database: true) + @configuration = { + "adapter" => "postgresql", + "database" => "my-app-db" + } - def test_clears_active_connections - ActiveRecord::Base.expects(:clear_active_connections!) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:clear_active_connections!).returns(true) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + end - ActiveRecord::Tasks::DatabaseTasks.purge @configuration - end + def test_clears_active_connections + ActiveRecord::Base.expects(:clear_active_connections!) + + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end - def test_establishes_connection_to_postgresql_database - ActiveRecord::Base.expects(:establish_connection).with( - 'adapter' => 'postgresql', - 'database' => 'postgres', - 'schema_search_path' => 'public' - ) + def test_establishes_connection_to_postgresql_database + ActiveRecord::Base.expects(:establish_connection).with( + "adapter" => "postgresql", + "database" => "postgres", + "schema_search_path" => "public" + ) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration - end + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end - def test_drops_database - @connection.expects(:drop_database).with('my-app-db') + def test_drops_database + @connection.expects(:drop_database).with("my-app-db") - ActiveRecord::Tasks::DatabaseTasks.purge @configuration - end + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end - def test_creates_database - @connection.expects(:create_database). - with('my-app-db', @configuration.merge('encoding' => 'utf8')) + def test_creates_database + @connection.expects(:create_database). + with("my-app-db", @configuration.merge("encoding" => "utf8")) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration - end + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end - def test_establishes_connection - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + def test_establishes_connection + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.purge @configuration + ActiveRecord::Tasks::DatabaseTasks.purge @configuration + end end - end - class PostgreSQLDBCharsetTest < ActiveRecord::TestCase - def setup - @connection = stub(:create_database => true) - @configuration = { - 'adapter' => 'postgresql', - 'database' => 'my-app-db' - } + class PostgreSQLDBCharsetTest < ActiveRecord::TestCase + def setup + @connection = stub(create_database: true) + @configuration = { + "adapter" => "postgresql", + "database" => "my-app-db" + } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + end - def test_db_retrieves_charset - @connection.expects(:encoding) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration + def test_db_retrieves_charset + @connection.expects(:encoding) + ActiveRecord::Tasks::DatabaseTasks.charset @configuration + end end - end - class PostgreSQLDBCollationTest < ActiveRecord::TestCase - def setup - @connection = stub(:create_database => true) - @configuration = { - 'adapter' => 'postgresql', - 'database' => 'my-app-db' - } + class PostgreSQLDBCollationTest < ActiveRecord::TestCase + def setup + @connection = stub(create_database: true) + @configuration = { + "adapter" => "postgresql", + "database" => "my-app-db" + } - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + end - def test_db_retrieves_collation - @connection.expects(:collation) - ActiveRecord::Tasks::DatabaseTasks.collation @configuration + def test_db_retrieves_collation + @connection.expects(:collation) + ActiveRecord::Tasks::DatabaseTasks.collation @configuration + end end - end - class PostgreSQLStructureDumpTest < ActiveRecord::TestCase - def setup - @connection = stub(:structure_dump => true) - @configuration = { - 'adapter' => 'postgresql', - 'database' => 'my-app-db' - } - @filename = "awesome-file.sql" - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - Kernel.stubs(:system) - File.stubs(:open) - end + class PostgreSQLStructureDumpTest < ActiveRecord::TestCase + def setup + @connection = stub(structure_dump: true) + @configuration = { + "adapter" => "postgresql", + "database" => "my-app-db" + } + @filename = "awesome-file.sql" - def test_structure_dump - Kernel.expects(:system).with('pg_dump', '-s', '-x', '-O', '-f', @filename, 'my-app-db').returns(true) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + Kernel.stubs(:system) + File.stubs(:open) + end - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) - end + def test_structure_dump + Kernel.expects(:system).with("pg_dump", "-s", "-x", "-O", "-f", @filename, "my-app-db").returns(true) - def test_structure_dump_with_schema_search_path - @configuration['schema_search_path'] = 'foo,bar' + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + end - Kernel.expects(:system).with('pg_dump', '-s', '-x', '-O', '-f', @filename, '--schema=foo', '--schema=bar', 'my-app-db').returns(true) + def test_structure_dump_with_schema_search_path + @configuration["schema_search_path"] = "foo,bar" - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) - end + Kernel.expects(:system).with("pg_dump", "-s", "-x", "-O", "-f", @filename, "--schema=foo", "--schema=bar", "my-app-db").returns(true) - def test_structure_dump_with_schema_search_path_and_dump_schemas_all - @configuration['schema_search_path'] = 'foo,bar' + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + end - Kernel.expects(:system).with("pg_dump", '-s', '-x', '-O', '-f', @filename, 'my-app-db').returns(true) + def test_structure_dump_with_schema_search_path_and_dump_schemas_all + @configuration["schema_search_path"] = "foo,bar" - with_dump_schemas(:all) do - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + Kernel.expects(:system).with("pg_dump", "-s", "-x", "-O", "-f", @filename, "my-app-db").returns(true) + + with_dump_schemas(:all) do + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + end end - end - def test_structure_dump_with_dump_schemas_string - Kernel.expects(:system).with("pg_dump", '-s', '-x', '-O', '-f', @filename, '--schema=foo', '--schema=bar', "my-app-db").returns(true) + def test_structure_dump_with_dump_schemas_string + Kernel.expects(:system).with("pg_dump", "-s", "-x", "-O", "-f", @filename, "--schema=foo", "--schema=bar", "my-app-db").returns(true) - with_dump_schemas('foo,bar') do - ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + with_dump_schemas("foo,bar") do + ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename) + end end - end - private + private - def with_dump_schemas(value, &block) - old_dump_schemas = ActiveRecord::Base.dump_schemas - ActiveRecord::Base.dump_schemas = value - yield - ensure - ActiveRecord::Base.dump_schemas = old_dump_schemas + def with_dump_schemas(value, &block) + old_dump_schemas = ActiveRecord::Base.dump_schemas + ActiveRecord::Base.dump_schemas = value + yield + ensure + ActiveRecord::Base.dump_schemas = old_dump_schemas + end end - end - class PostgreSQLStructureLoadTest < ActiveRecord::TestCase - def setup - @connection = stub - @configuration = { - 'adapter' => 'postgresql', - 'database' => 'my-app-db' - } - - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - Kernel.stubs(:system) - end + class PostgreSQLStructureLoadTest < ActiveRecord::TestCase + def setup + @connection = stub + @configuration = { + "adapter" => "postgresql", + "database" => "my-app-db" + } - def test_structure_load - filename = "awesome-file.sql" - Kernel.expects(:system).with('psql', '-v', 'ON_ERROR_STOP=1', '-q', '-f', filename, @configuration['database']).returns(true) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + Kernel.stubs(:system) + end - ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) - end + def test_structure_load + filename = "awesome-file.sql" + Kernel.expects(:system).with("psql", "-v", "ON_ERROR_STOP=1", "-q", "-f", filename, @configuration["database"]).returns(true) - def test_structure_load_accepts_path_with_spaces - filename = "awesome file.sql" - Kernel.expects(:system).with('psql', '-v', 'ON_ERROR_STOP=1', '-q', '-f', filename, @configuration['database']).returns(true) + ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + end + + def test_structure_load_accepts_path_with_spaces + filename = "awesome file.sql" + Kernel.expects(:system).with("psql", "-v", "ON_ERROR_STOP=1", "-q", "-f", filename, @configuration["database"]).returns(true) - ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) + end end end end -end diff --git a/activerecord/test/cases/tasks/sqlite_rake_test.rb b/activerecord/test/cases/tasks/sqlite_rake_test.rb index 4be03c7f61..141048bfe7 100644 --- a/activerecord/test/cases/tasks/sqlite_rake_test.rb +++ b/activerecord/test/cases/tasks/sqlite_rake_test.rb @@ -1,220 +1,220 @@ -require 'cases/helper' -require 'active_record/tasks/database_tasks' -require 'pathname' +require "cases/helper" +require "active_record/tasks/database_tasks" +require "pathname" if current_adapter?(:SQLite3Adapter) -module ActiveRecord - class SqliteDBCreateTest < ActiveRecord::TestCase - def setup - @database = 'db_create.sqlite3' - @connection = stub :connection - @configuration = { - 'adapter' => 'sqlite3', - 'database' => @database - } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - - $stdout, @original_stdout = StringIO.new, $stdout - $stderr, @original_stderr = StringIO.new, $stderr - end + module ActiveRecord + class SqliteDBCreateTest < ActiveRecord::TestCase + def setup + @database = "db_create.sqlite3" + @connection = stub :connection + @configuration = { + "adapter" => "sqlite3", + "database" => @database + } + + File.stubs(:exist?).returns(false) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end - def teardown - $stdout, $stderr = @original_stdout, @original_stderr - end + def teardown + $stdout, $stderr = @original_stdout, @original_stderr + end - def test_db_checks_database_exists - File.expects(:exist?).with(@database).returns(false) + def test_db_checks_database_exists + File.expects(:exist?).with(@database).returns(false) - ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root' - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end - def test_when_db_created_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root' + def test_when_db_created_successfully_outputs_info_to_stdout + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal $stdout.string, "Created database '#{@database}'\n" - end + assert_equal $stdout.string, "Created database '#{@database}'\n" + end - def test_db_create_when_file_exists - File.stubs(:exist?).returns(true) + def test_db_create_when_file_exists + File.stubs(:exist?).returns(true) - ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root' + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" - assert_equal $stderr.string, "Database '#{@database}' already exists\n" - end + assert_equal $stderr.string, "Database '#{@database}' already exists\n" + end - def test_db_create_with_file_does_nothing - File.stubs(:exist?).returns(true) - $stderr.stubs(:puts).returns(nil) + def test_db_create_with_file_does_nothing + File.stubs(:exist?).returns(true) + $stderr.stubs(:puts).returns(nil) - ActiveRecord::Base.expects(:establish_connection).never + ActiveRecord::Base.expects(:establish_connection).never - ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root' - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end - def test_db_create_establishes_a_connection - ActiveRecord::Base.expects(:establish_connection).with(@configuration) + def test_db_create_establishes_a_connection + ActiveRecord::Base.expects(:establish_connection).with(@configuration) - ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root' - end + ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" + end - def test_db_create_with_error_prints_message - ActiveRecord::Base.stubs(:establish_connection).raises(Exception) + def test_db_create_with_error_prints_message + ActiveRecord::Base.stubs(:establish_connection).raises(Exception) - $stderr.stubs(:puts).returns(true) - $stderr.expects(:puts). - with("Couldn't create database for #{@configuration.inspect}") + $stderr.stubs(:puts).returns(true) + $stderr.expects(:puts). + with("Couldn't create database for #{@configuration.inspect}") - assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration, '/rails/root' } + assert_raises(Exception) { ActiveRecord::Tasks::DatabaseTasks.create @configuration, "/rails/root" } + end end - end - class SqliteDBDropTest < ActiveRecord::TestCase - def setup - @database = "db_create.sqlite3" - @path = stub(:to_s => '/absolute/path', :absolute? => true) - @configuration = { - 'adapter' => 'sqlite3', - 'database' => @database - } - - Pathname.stubs(:new).returns(@path) - File.stubs(:join).returns('/former/relative/path') - FileUtils.stubs(:rm).returns(true) - - $stdout, @original_stdout = StringIO.new, $stdout - $stderr, @original_stderr = StringIO.new, $stderr - end + class SqliteDBDropTest < ActiveRecord::TestCase + def setup + @database = "db_create.sqlite3" + @path = stub(to_s: "/absolute/path", absolute?: true) + @configuration = { + "adapter" => "sqlite3", + "database" => @database + } - def teardown - $stdout, $stderr = @original_stdout, @original_stderr - end + Pathname.stubs(:new).returns(@path) + File.stubs(:join).returns("/former/relative/path") + FileUtils.stubs(:rm).returns(true) - def test_creates_path_from_database - Pathname.expects(:new).with(@database).returns(@path) + $stdout, @original_stdout = StringIO.new, $stdout + $stderr, @original_stderr = StringIO.new, $stderr + end - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root' - end + def teardown + $stdout, $stderr = @original_stdout, @original_stderr + end - def test_removes_file_with_absolute_path - File.stubs(:exist?).returns(true) - @path.stubs(:absolute?).returns(true) + def test_creates_path_from_database + Pathname.expects(:new).with(@database).returns(@path) - FileUtils.expects(:rm).with('/absolute/path') + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root' - end + def test_removes_file_with_absolute_path + File.stubs(:exist?).returns(true) + @path.stubs(:absolute?).returns(true) - def test_generates_absolute_path_with_given_root - @path.stubs(:absolute?).returns(false) + FileUtils.expects(:rm).with("/absolute/path") - File.expects(:join).with('/rails/root', @path). - returns('/former/relative/path') + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root' - end + def test_generates_absolute_path_with_given_root + @path.stubs(:absolute?).returns(false) - def test_removes_file_with_relative_path - File.stubs(:exist?).returns(true) - @path.stubs(:absolute?).returns(false) + File.expects(:join).with("/rails/root", @path). + returns("/former/relative/path") - FileUtils.expects(:rm).with('/former/relative/path') + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root' - end + def test_removes_file_with_relative_path + File.stubs(:exist?).returns(true) + @path.stubs(:absolute?).returns(false) - def test_when_db_dropped_successfully_outputs_info_to_stdout - ActiveRecord::Tasks::DatabaseTasks.drop @configuration, '/rails/root' + FileUtils.expects(:rm).with("/former/relative/path") - assert_equal $stdout.string, "Dropped database '#{@database}'\n" - end - end + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" + end - class SqliteDBCharsetTest < ActiveRecord::TestCase - def setup - @database = 'db_create.sqlite3' - @connection = stub :connection - @configuration = { - 'adapter' => 'sqlite3', - 'database' => @database - } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + def test_when_db_dropped_successfully_outputs_info_to_stdout + ActiveRecord::Tasks::DatabaseTasks.drop @configuration, "/rails/root" - def test_db_retrieves_charset - @connection.expects(:encoding) - ActiveRecord::Tasks::DatabaseTasks.charset @configuration, '/rails/root' + assert_equal $stdout.string, "Dropped database '#{@database}'\n" + end end - end - class SqliteDBCollationTest < ActiveRecord::TestCase - def setup - @database = 'db_create.sqlite3' - @connection = stub :connection - @configuration = { - 'adapter' => 'sqlite3', - 'database' => @database - } - - File.stubs(:exist?).returns(false) - ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).returns(true) - end + class SqliteDBCharsetTest < ActiveRecord::TestCase + def setup + @database = "db_create.sqlite3" + @connection = stub :connection + @configuration = { + "adapter" => "sqlite3", + "database" => @database + } - def test_db_retrieves_collation - assert_raise NoMethodError do - ActiveRecord::Tasks::DatabaseTasks.collation @configuration, '/rails/root' + File.stubs(:exist?).returns(false) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) end - end - end - class SqliteStructureDumpTest < ActiveRecord::TestCase - def setup - @database = "db_create.sqlite3" - @configuration = { - 'adapter' => 'sqlite3', - 'database' => @database - } + def test_db_retrieves_charset + @connection.expects(:encoding) + ActiveRecord::Tasks::DatabaseTasks.charset @configuration, "/rails/root" + end end - def test_structure_dump - dbfile = @database - filename = "awesome-file.sql" + class SqliteDBCollationTest < ActiveRecord::TestCase + def setup + @database = "db_create.sqlite3" + @connection = stub :connection + @configuration = { + "adapter" => "sqlite3", + "database" => @database + } - ActiveRecord::Tasks::DatabaseTasks.structure_dump @configuration, filename, '/rails/root' - assert File.exist?(dbfile) - assert File.exist?(filename) - ensure - FileUtils.rm_f(filename) - FileUtils.rm_f(dbfile) + File.stubs(:exist?).returns(false) + ActiveRecord::Base.stubs(:connection).returns(@connection) + ActiveRecord::Base.stubs(:establish_connection).returns(true) + end + + def test_db_retrieves_collation + assert_raise NoMethodError do + ActiveRecord::Tasks::DatabaseTasks.collation @configuration, "/rails/root" + end + end end - end - class SqliteStructureLoadTest < ActiveRecord::TestCase - def setup - @database = "db_create.sqlite3" - @configuration = { - 'adapter' => 'sqlite3', - 'database' => @database - } + class SqliteStructureDumpTest < ActiveRecord::TestCase + def setup + @database = "db_create.sqlite3" + @configuration = { + "adapter" => "sqlite3", + "database" => @database + } + end + + def test_structure_dump + dbfile = @database + filename = "awesome-file.sql" + + ActiveRecord::Tasks::DatabaseTasks.structure_dump @configuration, filename, "/rails/root" + assert File.exist?(dbfile) + assert File.exist?(filename) + ensure + FileUtils.rm_f(filename) + FileUtils.rm_f(dbfile) + end end - def test_structure_load - dbfile = @database - filename = "awesome-file.sql" + class SqliteStructureLoadTest < ActiveRecord::TestCase + def setup + @database = "db_create.sqlite3" + @configuration = { + "adapter" => "sqlite3", + "database" => @database + } + end + + def test_structure_load + dbfile = @database + filename = "awesome-file.sql" - open(filename, 'w') { |f| f.puts("select datetime('now', 'localtime');") } - ActiveRecord::Tasks::DatabaseTasks.structure_load @configuration, filename, '/rails/root' - assert File.exist?(dbfile) - ensure - FileUtils.rm_f(filename) - FileUtils.rm_f(dbfile) + open(filename, "w") { |f| f.puts("select datetime('now', 'localtime');") } + ActiveRecord::Tasks::DatabaseTasks.structure_load @configuration, filename, "/rails/root" + assert File.exist?(dbfile) + ensure + FileUtils.rm_f(filename) + FileUtils.rm_f(dbfile) + end end end end -end diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index c8adc21bbc..8eddc5a9ed 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -1,12 +1,29 @@ -require 'active_support/test_case' -require 'active_support/testing/stream' +require "active_support/test_case" +require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" +require "active_support/testing/stream" +require "active_support/core_ext/regexp" +require "active_record/fixtures" + +require "cases/validations_repair_helper" module ActiveRecord # = Active Record Test Case # # Defines some test assertions to test against SQL queries. class TestCase < ActiveSupport::TestCase #:nodoc: + include ActiveSupport::Testing::MethodCallAssertions include ActiveSupport::Testing::Stream + include ActiveRecord::TestFixtures + include ActiveRecord::ValidationsRepairHelper + + self.fixture_path = FIXTURES_ROOT + self.use_instantiated_fixtures = false + self.use_transactional_tests = true + + def create_fixtures(*fixture_set_names, &block) + ActiveRecord::FixtureSet.create_fixtures(ActiveRecord::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block) + end def teardown SQLCounter.clear_log @@ -23,7 +40,7 @@ module ActiveRecord ensure failed_patterns = [] patterns_to_match.each do |pattern| - failed_patterns << pattern unless SQLCounter.log_all.any?{ |sql| pattern === sql } + failed_patterns << pattern unless SQLCounter.log_all.any? { |sql| pattern === sql } end assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}" end @@ -85,7 +102,7 @@ module ActiveRecord def clear_log; self.log = []; self.log_all = []; end end - self.clear_log + clear_log self.ignored_sql = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/] @@ -108,16 +125,13 @@ module ActiveRecord end def call(name, start, finish, message_id, values) - sql = values[:sql] - - # FIXME: this seems bad. we should probably have a better way to indicate - # the query was cached - return if 'CACHE' == values[:name] + return if values[:cached] + sql = values[:sql] self.class.log_all << sql - self.class.log << sql unless ignore =~ sql + self.class.log << sql unless ignore.match?(sql) end end - ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new) + ActiveSupport::Notifications.subscribe("sql.active_record", SQLCounter.new) end diff --git a/activerecord/test/cases/test_fixtures_test.rb b/activerecord/test/cases/test_fixtures_test.rb index 1970fe82d0..14a5faa85e 100644 --- a/activerecord/test/cases/test_fixtures_test.rb +++ b/activerecord/test/cases/test_fixtures_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" class TestFixturesTest < ActiveRecord::TestCase setup do @@ -7,7 +7,7 @@ class TestFixturesTest < ActiveRecord::TestCase end def test_deprecated_use_transactional_fixtures= - assert_deprecated 'use use_transactional_tests= instead' do + assert_deprecated "use use_transactional_tests= instead" do @klass.use_transactional_fixtures = true end end diff --git a/activerecord/test/cases/time_precision_test.rb b/activerecord/test/cases/time_precision_test.rb index 628a8eb771..03f6c234e8 100644 --- a/activerecord/test/cases/time_precision_test.rb +++ b/activerecord/test/cases/time_precision_test.rb @@ -1,84 +1,83 @@ -require 'cases/helper' -require 'support/schema_dumping_helper' +require "cases/helper" +require "support/schema_dumping_helper" if subsecond_precision_supported? -class TimePrecisionTest < ActiveRecord::TestCase - include SchemaDumpingHelper - self.use_transactional_tests = false + class TimePrecisionTest < ActiveRecord::TestCase + include SchemaDumpingHelper + self.use_transactional_tests = false - class Foo < ActiveRecord::Base; end + class Foo < ActiveRecord::Base; end - setup do - @connection = ActiveRecord::Base.connection - Foo.reset_column_information - end - - teardown do - @connection.drop_table :foos, if_exists: true - end + setup do + @connection = ActiveRecord::Base.connection + Foo.reset_column_information + end - def test_time_data_type_with_precision - @connection.create_table(:foos, force: true) - @connection.add_column :foos, :start, :time, precision: 3 - @connection.add_column :foos, :finish, :time, precision: 6 - assert_equal 3, Foo.columns_hash['start'].precision - assert_equal 6, Foo.columns_hash['finish'].precision - end + teardown do + @connection.drop_table :foos, if_exists: true + end - def test_passing_precision_to_time_does_not_set_limit - @connection.create_table(:foos, force: true) do |t| - t.time :start, precision: 3 - t.time :finish, precision: 6 + def test_time_data_type_with_precision + @connection.create_table(:foos, force: true) + @connection.add_column :foos, :start, :time, precision: 3 + @connection.add_column :foos, :finish, :time, precision: 6 + assert_equal 3, Foo.columns_hash["start"].precision + assert_equal 6, Foo.columns_hash["finish"].precision end - assert_nil Foo.columns_hash['start'].limit - assert_nil Foo.columns_hash['finish'].limit - end - def test_invalid_time_precision_raises_error - assert_raises ActiveRecord::ActiveRecordError do + def test_passing_precision_to_time_does_not_set_limit @connection.create_table(:foos, force: true) do |t| - t.time :start, precision: 7 - t.time :finish, precision: 7 + t.time :start, precision: 3 + t.time :finish, precision: 6 end + assert_nil Foo.columns_hash["start"].limit + assert_nil Foo.columns_hash["finish"].limit end - end - def test_formatting_time_according_to_precision - @connection.create_table(:foos, force: true) do |t| - t.time :start, precision: 0 - t.time :finish, precision: 4 + def test_invalid_time_precision_raises_error + assert_raises ActiveRecord::ActiveRecordError do + @connection.create_table(:foos, force: true) do |t| + t.time :start, precision: 7 + t.time :finish, precision: 7 + end + end end - time = ::Time.utc(2000, 1, 1, 12, 30, 0, 999999) - Foo.create!(start: time, finish: time) - assert foo = Foo.find_by(start: time) - assert_equal 1, Foo.where(finish: time).count - assert_equal time.to_s, foo.start.to_s - assert_equal time.to_s, foo.finish.to_s - assert_equal 000000, foo.start.usec - assert_equal 999900, foo.finish.usec - end - def test_schema_dump_includes_time_precision - @connection.create_table(:foos, force: true) do |t| - t.time :start, precision: 4 - t.time :finish, precision: 6 + def test_formatting_time_according_to_precision + @connection.create_table(:foos, force: true) do |t| + t.time :start, precision: 0 + t.time :finish, precision: 4 + end + time = ::Time.utc(2000, 1, 1, 12, 30, 0, 999999) + Foo.create!(start: time, finish: time) + assert foo = Foo.find_by(start: time) + assert_equal 1, Foo.where(finish: time).count + assert_equal time.to_s, foo.start.to_s + assert_equal time.to_s, foo.finish.to_s + assert_equal 000000, foo.start.usec + assert_equal 999900, foo.finish.usec end - output = dump_table_schema("foos") - assert_match %r{t\.time\s+"start",\s+precision: 4$}, output - assert_match %r{t\.time\s+"finish",\s+precision: 6$}, output - end - if current_adapter?(:PostgreSQLAdapter) - def test_time_precision_with_zero_should_be_dumped + def test_schema_dump_includes_time_precision @connection.create_table(:foos, force: true) do |t| - t.time :start, precision: 0 - t.time :finish, precision: 0 + t.time :start, precision: 4 + t.time :finish, precision: 6 end output = dump_table_schema("foos") - assert_match %r{t\.time\s+"start",\s+precision: 0$}, output - assert_match %r{t\.time\s+"finish",\s+precision: 0$}, output + assert_match %r{t\.time\s+"start",\s+precision: 4$}, output + assert_match %r{t\.time\s+"finish",\s+precision: 6$}, output end - end -end + if current_adapter?(:PostgreSQLAdapter) + def test_time_precision_with_zero_should_be_dumped + @connection.create_table(:foos, force: true) do |t| + t.time :start, precision: 0 + t.time :finish, precision: 0 + end + output = dump_table_schema("foos") + assert_match %r{t\.time\s+"start",\s+precision: 0$}, output + assert_match %r{t\.time\s+"finish",\s+precision: 0$}, output + end + end + end end diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index 937b84bccc..cd83518e84 100644 --- a/activerecord/test/cases/timestamp_test.rb +++ b/activerecord/test/cases/timestamp_test.rb @@ -1,12 +1,12 @@ -require 'cases/helper' -require 'support/ddl_helper' -require 'models/developer' -require 'models/computer' -require 'models/owner' -require 'models/pet' -require 'models/toy' -require 'models/car' -require 'models/task' +require "cases/helper" +require "support/ddl_helper" +require "models/developer" +require "models/computer" +require "models/owner" +require "models/pet" +require "models/toy" +require "models/car" +require "models/task" class TimestampTest < ActiveRecord::TestCase fixtures :developers, :owners, :pets, :toys, :cars, :tasks @@ -38,8 +38,8 @@ class TimestampTest < ActiveRecord::TestCase assert_not_equal @previously_updated_at, @developer.updated_at assert_equal previous_salary + 10000, @developer.salary - assert @developer.salary_changed?, 'developer salary should have changed' - assert @developer.changed?, 'developer should be marked as changed' + assert @developer.salary_changed?, "developer salary should have changed" + assert @developer.changed?, "developer should be marked as changed" @developer.reload assert_equal previous_salary, @developer.salary end @@ -74,12 +74,12 @@ class TimestampTest < ActiveRecord::TestCase end def test_touching_updates_timestamp_with_given_time - previously_updated_at = @developer.updated_at - new_time = Time.utc(2015, 2, 16, 0, 0, 0) - @developer.touch(time: new_time) + previously_updated_at = @developer.updated_at + new_time = Time.utc(2015, 2, 16, 0, 0, 0) + @developer.touch(time: new_time) - assert_not_equal previously_updated_at, @developer.updated_at - assert_equal new_time, @developer.updated_at + assert_not_equal previously_updated_at, @developer.updated_at + assert_equal new_time, @developer.updated_at end def test_touching_an_attribute_updates_timestamp @@ -88,8 +88,8 @@ class TimestampTest < ActiveRecord::TestCase @developer.touch(:created_at) end - assert !@developer.created_at_changed? , 'created_at should not be changed' - assert !@developer.changed?, 'record should not be changed' + assert !@developer.created_at_changed? , "created_at should not be changed" + assert !@developer.changed?, "record should not be changed" assert_not_equal previously_created_at, @developer.created_at assert_not_equal @previously_updated_at, @developer.updated_at end @@ -106,9 +106,9 @@ class TimestampTest < ActiveRecord::TestCase end def test_touching_an_attribute_updates_timestamp_with_given_time - previously_updated_at = @developer.updated_at + previously_updated_at = @developer.updated_at previously_created_at = @developer.created_at - new_time = Time.utc(2015, 2, 16, 4, 54, 0) + new_time = Time.utc(2015, 2, 16, 4, 54, 0) @developer.touch(:created_at, time: new_time) assert_not_equal previously_created_at, @developer.created_at @@ -228,7 +228,7 @@ class TimestampTest < ActiveRecord::TestCase def test_saving_a_new_record_belonging_to_invalid_parent_with_touch_should_not_raise_exception klass = Class.new(Owner) do - def self.name; 'Owner'; end + def self.name; "Owner"; end validate { errors.add(:base, :invalid) } end @@ -240,8 +240,8 @@ class TimestampTest < ActiveRecord::TestCase def test_saving_a_record_with_a_belongs_to_that_specifies_touching_a_specific_attribute_the_parent_should_update_that_attribute klass = Class.new(ActiveRecord::Base) do - def self.name; 'Pet'; end - belongs_to :owner, :touch => :happy_at + def self.name; "Pet"; end + belongs_to :owner, touch: :happy_at end pet = klass.first @@ -256,8 +256,8 @@ class TimestampTest < ActiveRecord::TestCase def test_touching_a_record_with_a_belongs_to_that_uses_a_counter_cache_should_update_the_parent klass = Class.new(ActiveRecord::Base) do - def self.name; 'Pet'; end - belongs_to :owner, :counter_cache => :use_count, :touch => true + def self.name; "Pet"; end + belongs_to :owner, counter_cache: :use_count, touch: true end pet = klass.first @@ -275,8 +275,8 @@ class TimestampTest < ActiveRecord::TestCase def test_touching_a_record_touches_parent_record_and_grandparent_record klass = Class.new(ActiveRecord::Base) do - def self.name; 'Toy'; end - belongs_to :pet, :touch => true + def self.name; "Toy"; end + belongs_to :pet, touch: true end toy = klass.first @@ -293,12 +293,12 @@ class TimestampTest < ActiveRecord::TestCase def test_touching_a_record_touches_polymorphic_record klass = Class.new(ActiveRecord::Base) do - def self.name; 'Toy'; end + def self.name; "Toy"; end end wheel_klass = Class.new(ActiveRecord::Base) do - def self.name; 'Wheel'; end - belongs_to :wheelable, :polymorphic => true, :touch => true + def self.name; "Wheel"; end + belongs_to :wheelable, polymorphic: true, touch: true end toy = klass.first @@ -315,7 +315,7 @@ class TimestampTest < ActiveRecord::TestCase def test_changing_parent_of_a_record_touches_both_new_and_old_parent_record klass = Class.new(ActiveRecord::Base) do - def self.name; 'Toy'; end + def self.name; "Toy"; end belongs_to :pet, touch: true end @@ -341,12 +341,12 @@ class TimestampTest < ActiveRecord::TestCase def test_changing_parent_of_a_record_touches_both_new_and_old_polymorphic_parent_record_changes_within_same_class car_class = Class.new(ActiveRecord::Base) do - def self.name; 'Car'; end + def self.name; "Car"; end end wheel_class = Class.new(ActiveRecord::Base) do - def self.name; 'Wheel'; end - belongs_to :wheelable, :polymorphic => true, :touch => true + def self.name; "Wheel"; end + belongs_to :wheelable, polymorphic: true, touch: true end car1 = car_class.find(1) @@ -368,16 +368,16 @@ class TimestampTest < ActiveRecord::TestCase def test_changing_parent_of_a_record_touches_both_new_and_old_polymorphic_parent_record_changes_with_other_class car_class = Class.new(ActiveRecord::Base) do - def self.name; 'Car'; end + def self.name; "Car"; end end toy_class = Class.new(ActiveRecord::Base) do - def self.name; 'Toy'; end + def self.name; "Toy"; end end wheel_class = Class.new(ActiveRecord::Base) do - def self.name; 'Wheel'; end - belongs_to :wheelable, :polymorphic => true, :touch => true + def self.name; "Wheel"; end + belongs_to :wheelable, polymorphic: true, touch: true end car = car_class.find(1) @@ -399,7 +399,7 @@ class TimestampTest < ActiveRecord::TestCase def test_clearing_association_touches_the_old_record klass = Class.new(ActiveRecord::Base) do - def self.name; 'Toy'; end + def self.name; "Toy"; end belongs_to :pet, touch: true end @@ -419,14 +419,14 @@ class TimestampTest < ActiveRecord::TestCase def test_timestamp_column_values_are_present_in_the_callbacks klass = Class.new(ActiveRecord::Base) do - self.table_name = 'people' + self.table_name = "people" before_create do self.born_at = self.created_at end end - person = klass.create first_name: 'David' + person = klass.create first_name: "David" assert_not_equal person.born_at, nil end @@ -462,11 +462,11 @@ class TimestampTest < ActiveRecord::TestCase def test_index_is_created_for_both_timestamps ActiveRecord::Base.connection.create_table(:foos, force: true) do |t| - t.timestamps(:foos, null: true, index: true) + t.timestamps null: true, index: true end - indexes = ActiveRecord::Base.connection.indexes('foos') - assert_equal ['created_at', 'updated_at'], indexes.flat_map(&:columns).sort + indexes = ActiveRecord::Base.connection.indexes("foos") + assert_equal ["created_at", "updated_at"], indexes.flat_map(&:columns).sort ensure ActiveRecord::Base.connection.drop_table(:foos) end diff --git a/activerecord/test/cases/touch_later_test.rb b/activerecord/test/cases/touch_later_test.rb index b47769eed7..d1e8c649d9 100644 --- a/activerecord/test/cases/touch_later_test.rb +++ b/activerecord/test/cases/touch_later_test.rb @@ -1,9 +1,9 @@ -require 'cases/helper' -require 'models/invoice' -require 'models/line_item' -require 'models/topic' -require 'models/node' -require 'models/tree' +require "cases/helper" +require "models/invoice" +require "models/line_item" +require "models/topic" +require "models/node" +require "models/tree" class TouchLaterTest < ActiveRecord::TestCase fixtures :nodes, :trees @@ -24,6 +24,15 @@ class TouchLaterTest < ActiveRecord::TestCase assert_not invoice.changed? end + def test_touch_later_respects_no_touching_policy + time = Time.now.utc - 25.days + topic = Topic.create!(updated_at: time, created_at: time) + Topic.no_touching do + topic.touch_later + end + assert_equal time.to_i, topic.updated_at.to_i + end + def test_touch_later_update_the_attributes time = Time.now.utc - 25.days topic = Topic.create!(updated_at: time, created_at: time) diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index 8a7f19293d..bd50fe55e9 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -1,7 +1,7 @@ require "cases/helper" -require 'models/owner' -require 'models/pet' -require 'models/topic' +require "models/owner" +require "models/pet" +require "models/topic" class TransactionCallbacksTest < ActiveRecord::TestCase fixtures :topics, :owners, :pets @@ -17,7 +17,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase attr_accessor :save_on_after_create after_create do - self.save! if save_on_after_create + save! if save_on_after_create end def history @@ -68,17 +68,17 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def do_before_commit(on) blocks = @before_commit[on] if defined?(@before_commit) - blocks.each{|b| b.call(self)} if blocks + blocks.each { |b| b.call(self) } if blocks end def do_after_commit(on) blocks = @after_commit[on] if defined?(@after_commit) - blocks.each{|b| b.call(self)} if blocks + blocks.each { |b| b.call(self) } if blocks end def do_after_rollback(on) blocks = @after_rollback[on] if defined?(@after_rollback) - blocks.each{|b| b.call(self)} if blocks + blocks.each { |b| b.call(self) } if blocks end end @@ -88,7 +88,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase # FIXME: Test behavior, not implementation. def test_before_commit_exception_should_pop_transaction_stack - @first.before_commit_block { raise 'better pop this txn from the stack!' } + @first.before_commit_block { raise "better pop this txn from the stack!" } original_txn = @first.class.connection.current_transaction @@ -101,8 +101,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_call_after_commit_after_transaction_commits - @first.after_commit_block{|r| r.history << :after_commit} - @first.after_rollback_block{|r| r.history << :after_rollback} + @first.after_commit_block { |r| r.history << :after_commit } + @first.after_rollback_block { |r| r.history << :after_rollback } @first.save! assert_equal [:after_commit], @first.history @@ -123,7 +123,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record - new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today) + new_record = TopicWithCallbacks.new(title: "New topic", written_on: Date.today) add_transaction_execution_blocks new_record new_record.save! @@ -131,17 +131,17 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record_if_create_succeeds_creating_through_association - topic = TopicWithCallbacks.create!(:title => "New topic", :written_on => Date.today) + topic = TopicWithCallbacks.create!(title: "New topic", written_on: Date.today) reply = topic.replies.create assert_equal [], reply.history end def test_only_call_after_commit_on_create_and_doesnt_leaky - r = ReplyWithCallbacks.new(content: 'foo') + r = ReplyWithCallbacks.new(content: "foo") r.save_on_after_create = true r.save! - r.content = 'bar' + r.content = "bar" r.save! r.save! assert_equal [:commit_on_create], r.history @@ -155,7 +155,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_commit_on_top_level_transactions - @first.after_commit_block{|r| r.history << :after_commit} + @first.after_commit_block { |r| r.history << :after_commit } assert @first.history.empty? @first.transaction do @@ -168,8 +168,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_call_after_rollback_after_transaction_rollsback - @first.after_commit_block{|r| r.history << :after_commit} - @first.after_rollback_block{|r| r.history << :after_rollback} + @first.after_commit_block { |r| r.history << :after_commit } + @first.after_rollback_block { |r| r.history << :after_rollback } Topic.transaction do @first.save! @@ -213,7 +213,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_only_call_after_rollback_on_create_after_transaction_rollsback_for_new_record - new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today) + new_record = TopicWithCallbacks.new(title: "New topic", written_on: Date.today) add_transaction_execution_blocks new_record Topic.transaction do @@ -245,18 +245,18 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end def @first.commits(i=0); @commits ||= 0; @commits += i if i; end - @first.after_rollback_block{|r| r.rollbacks(1)} - @first.after_commit_block{|r| r.commits(1)} + @first.after_rollback_block { |r| r.rollbacks(1) } + @first.after_commit_block { |r| r.commits(1) } second = TopicWithCallbacks.find(3) def second.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end def second.commits(i=0); @commits ||= 0; @commits += i if i; end - second.after_rollback_block{|r| r.rollbacks(1)} - second.after_commit_block{|r| r.commits(1)} + second.after_rollback_block { |r| r.rollbacks(1) } + second.after_commit_block { |r| r.commits(1) } Topic.transaction do @first.save! - Topic.transaction(:requires_new => true) do + Topic.transaction(requires_new: true) do second.save! raise ActiveRecord::Rollback end @@ -272,16 +272,16 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end def @first.commits(i=0); @commits ||= 0; @commits += i if i; end - @first.after_rollback_block{|r| r.rollbacks(1)} - @first.after_commit_block{|r| r.commits(1)} + @first.after_rollback_block { |r| r.rollbacks(1) } + @first.after_commit_block { |r| r.commits(1) } Topic.transaction do @first.save - Topic.transaction(:requires_new => true) do + Topic.transaction(requires_new: true) do @first.save! raise ActiveRecord::Rollback end - Topic.transaction(:requires_new => true) do + Topic.transaction(requires_new: true) do @first.save! raise ActiveRecord::Rollback end @@ -292,7 +292,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_after_commit_callback_should_not_swallow_errors - @first.after_commit_block{ fail "boom" } + @first.after_commit_block { fail "boom" } assert_raises(RuntimeError) do Topic.transaction do @first.save! @@ -303,8 +303,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def test_after_commit_callback_when_raise_should_not_restore_state first = TopicWithCallbacks.new second = TopicWithCallbacks.new - first.after_commit_block{ fail "boom" } - second.after_commit_block{ fail "boom" } + first.after_commit_block { fail "boom" } + second.after_commit_block { fail "boom" } begin Topic.transaction do @@ -322,7 +322,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def test_after_rollback_callback_should_not_swallow_errors_when_set_to_raise error_class = Class.new(StandardError) - @first.after_rollback_block{ raise error_class } + @first.after_rollback_block { raise error_class } assert_raises(error_class) do Topic.transaction do @first.save! @@ -336,8 +336,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase first = TopicWithCallbacks.new second = TopicWithCallbacks.new - first.after_rollback_block{ raise error_class } - second.after_rollback_block{ raise error_class } + first.after_rollback_block { raise error_class } + second.after_rollback_block { raise error_class } begin Topic.transaction do @@ -355,13 +355,13 @@ class TransactionCallbacksTest < ActiveRecord::TestCase def test_after_rollback_callbacks_should_validate_on_condition assert_raise(ArgumentError) { Topic.after_rollback(on: :save) } - e = assert_raise(ArgumentError) { Topic.after_rollback(on: 'create') } + e = assert_raise(ArgumentError) { Topic.after_rollback(on: "create") } assert_match(/:on conditions for after_commit and after_rollback callbacks have to be one of \[:create, :destroy, :update\]/, e.message) end def test_after_commit_callbacks_should_validate_on_condition assert_raise(ArgumentError) { Topic.after_commit(on: :save) } - e = assert_raise(ArgumentError) { Topic.after_commit(on: 'create') } + e = assert_raise(ArgumentError) { Topic.after_commit(on: "create") } assert_match(/:on conditions for after_commit and after_rollback callbacks have to be one of \[:create, :destroy, :update\]/, e.message) end @@ -449,9 +449,7 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase end end - class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase - class TopicWithoutTransactionalEnrollmentCallbacks < ActiveRecord::Base self.table_name = :topics @@ -470,7 +468,7 @@ class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase def test_commit_does_not_run_transactions_callbacks_without_enrollment @topic.transaction do - @topic.content = 'foo' + @topic.content = "foo" @topic.save! end assert @topic.history.empty? @@ -479,7 +477,7 @@ class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase def test_commit_run_transactions_callbacks_with_explicit_enrollment @topic.transaction do 2.times do - @topic.content = 'foo' + @topic.content = "foo" @topic.save! end @topic.class.connection.add_transaction_record(@topic) @@ -489,7 +487,7 @@ class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase def test_rollback_does_not_run_transactions_callbacks_without_enrollment @topic.transaction do - @topic.content = 'foo' + @topic.content = "foo" @topic.save! raise ActiveRecord::Rollback end @@ -499,7 +497,7 @@ class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase def test_rollback_run_transactions_callbacks_with_explicit_enrollment @topic.transaction do 2.times do - @topic.content = 'foo' + @topic.content = "foo" @topic.save! end @topic.class.connection.add_transaction_record(@topic) diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb index 2f7d208ed2..58abfadaf4 100644 --- a/activerecord/test/cases/transaction_isolation_test.rb +++ b/activerecord/test/cases/transaction_isolation_test.rb @@ -1,4 +1,4 @@ -require 'cases/helper' +require "cases/helper" unless ActiveRecord::Base.connection.supports_transaction_isolation? class TransactionIsolationUnsupportedTest < ActiveRecord::TestCase @@ -9,7 +9,7 @@ unless ActiveRecord::Base.connection.supports_transaction_isolation? test "setting the isolation level raises an error" do assert_raises(ActiveRecord::TransactionIsolationError) do - Tag.transaction(isolation: :serializable) { } + Tag.transaction(isolation: :serializable) {} end end end @@ -20,11 +20,11 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? self.use_transactional_tests = false class Tag < ActiveRecord::Base - self.table_name = 'tags' + self.table_name = "tags" end class Tag2 < ActiveRecord::Base - self.table_name = 'tags' + self.table_name = "tags" end setup do @@ -63,18 +63,18 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? # We are testing that a nonrepeatable read does not happen if ActiveRecord::Base.connection.transaction_isolation_levels.include?(:repeatable_read) test "repeatable read" do - tag = Tag.create(name: 'jon') + tag = Tag.create(name: "jon") Tag.transaction(isolation: :repeatable_read) do tag.reload - Tag2.find(tag.id).update(name: 'emily') + Tag2.find(tag.id).update(name: "emily") tag.reload - assert_equal 'jon', tag.name + assert_equal "jon", tag.name end tag.reload - assert_equal 'emily', tag.name + assert_equal "emily", tag.name end end @@ -90,7 +90,7 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? test "setting isolation when joining a transaction raises an error" do Tag.transaction do assert_raises(ActiveRecord::TransactionIsolationError) do - Tag.transaction(isolation: :serializable) { } + Tag.transaction(isolation: :serializable) {} end end end @@ -98,7 +98,7 @@ if ActiveRecord::Base.connection.supports_transaction_isolation? test "setting isolation when starting a nested transaction raises error" do Tag.transaction do assert_raises(ActiveRecord::TransactionIsolationError) do - Tag.transaction(requires_new: true, isolation: :serializable) { } + Tag.transaction(requires_new: true, isolation: :serializable) {} end end end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 791b895d02..834365660f 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -1,12 +1,12 @@ require "cases/helper" -require 'models/topic' -require 'models/reply' -require 'models/developer' -require 'models/computer' -require 'models/book' -require 'models/author' -require 'models/post' -require 'models/movie' +require "models/topic" +require "models/reply" +require "models/developer" +require "models/computer" +require "models/book" +require "models/author" +require "models/post" +require "models/movie" class TransactionTest < ActiveRecord::TestCase self.use_transactional_tests = false @@ -144,7 +144,7 @@ class TransactionTest < ActiveRecord::TestCase def test_raising_exception_in_callback_rollbacks_in_save def @first.after_save_for_transaction - raise 'Make the transaction rollback' + raise "Make the transaction rollback" end @first.approved = true @@ -170,7 +170,7 @@ class TransactionTest < ActiveRecord::TestCase topic = Topic.new def topic.after_save_for_transaction - raise 'Make the transaction rollback' + raise "Make the transaction rollback" end assert_raises(RuntimeError) do @@ -181,7 +181,7 @@ class TransactionTest < ActiveRecord::TestCase end def test_transaction_state_is_cleared_when_record_is_persisted - author = Author.create! name: 'foo' + author = Author.create! name: "foo" author.name = nil assert_not author.save assert_not author.new_record? @@ -230,7 +230,7 @@ class TransactionTest < ActiveRecord::TestCase send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic", @first) nbooks_before_save = Book.count original_author_name = @first.author_name - @first.author_name += '_this_should_not_end_up_in_the_db' + @first.author_name += "_this_should_not_end_up_in_the_db" status = @first.save assert !status assert_equal original_author_name, @first.reload.author_name @@ -241,7 +241,7 @@ class TransactionTest < ActiveRecord::TestCase send("add_cancelling_before_#{filter}_with_db_side_effect_to_topic", @first) nbooks_before_save = Book.count original_author_name = @first.author_name - @first.author_name += '_this_should_not_end_up_in_the_db' + @first.author_name += "_this_should_not_end_up_in_the_db" begin @first.save! @@ -256,18 +256,18 @@ class TransactionTest < ActiveRecord::TestCase def test_callback_rollback_in_create topic = Class.new(Topic) { def after_create_for_transaction - raise 'Make the transaction rollback' + raise "Make the transaction rollback" end } - new_topic = topic.new(:title => "A new topic", - :author_name => "Ben", - :author_email_address => "ben@example.com", - :written_on => "2003-07-16t15:28:11.2233+01:00", - :last_read => "2004-04-15", - :bonus_time => "2005-01-30t15:28:00.00+01:00", - :content => "Have a nice day", - :approved => false) + new_topic = topic.new(title: "A new topic", + author_name: "Ben", + author_email_address: "ben@example.com", + written_on: "2003-07-16t15:28:11.2233+01:00", + last_read: "2004-04-15", + bonus_time: "2005-01-30t15:28:00.00+01:00", + content: "Have a nice day", + approved: false) new_record_snapshot = !new_topic.persisted? id_present = new_topic.has_attribute?(Topic.primary_key) @@ -291,7 +291,7 @@ class TransactionTest < ActiveRecord::TestCase end } - new_topic = topic.create(:title => "A new topic") + new_topic = topic.create(title: "A new topic") assert !new_topic.persisted?, "The topic should not be persisted" assert_nil new_topic.id, "The topic should not have an ID" end @@ -329,7 +329,7 @@ class TransactionTest < ActiveRecord::TestCase def test_invalid_keys_for_transaction assert_raise ArgumentError do - Topic.transaction :nested => true do + Topic.transaction nested: true do end end end @@ -342,7 +342,7 @@ class TransactionTest < ActiveRecord::TestCase @second.save! begin - Topic.transaction :requires_new => true do + Topic.transaction requires_new: true do @first.happy = false @first.save! raise @@ -363,7 +363,7 @@ class TransactionTest < ActiveRecord::TestCase @second.save! begin - @second.transaction :requires_new => true do + @second.transaction requires_new: true do @first.happy = false @first.save! raise @@ -403,17 +403,17 @@ class TransactionTest < ActiveRecord::TestCase @first.save! begin - Topic.transaction :requires_new => true do + Topic.transaction requires_new: true do @first.content = "Two" @first.save! begin - Topic.transaction :requires_new => true do + Topic.transaction requires_new: true do @first.content = "Three" @first.save! begin - Topic.transaction :requires_new => true do + Topic.transaction requires_new: true do @first.content = "Four" @first.save! raise @@ -493,7 +493,7 @@ class TransactionTest < ActiveRecord::TestCase def test_rollback_when_commit_raises assert_called(Topic.connection, :begin_db_transaction) do - Topic.connection.stub(:commit_db_transaction, ->{ raise('OH NOES') }) do + Topic.connection.stub(:commit_db_transaction, -> { raise("OH NOES") }) do assert_called(Topic.connection, :rollback_db_transaction) do e = assert_raise RuntimeError do @@ -501,22 +501,23 @@ class TransactionTest < ActiveRecord::TestCase # do nothing end end - assert_equal 'OH NOES', e.message + assert_equal "OH NOES", e.message end end end end def test_rollback_when_saving_a_frozen_record - topic = Topic.new(:title => 'test') + topic = Topic.new(title: "test") topic.freeze e = assert_raise(RuntimeError) { topic.save } - assert_match(/frozen/i, e.message) # Not good enough, but we can't do much - # about it since there is no specific error - # for frozen objects. - assert !topic.persisted?, 'not persisted' + # Not good enough, but we can't do much + # about it since there is no specific error + # for frozen objects. + assert_match(/frozen/i, e.message) + assert !topic.persisted?, "not persisted" assert_nil topic.id - assert topic.frozen?, 'not frozen' + assert topic.frozen?, "not frozen" end def test_rollback_when_thread_killed @@ -549,12 +550,12 @@ class TransactionTest < ActiveRecord::TestCase def test_restore_active_record_state_for_all_records_in_a_transaction topic_without_callbacks = Class.new(ActiveRecord::Base) do - self.table_name = 'topics' + self.table_name = "topics" end - topic_1 = Topic.new(:title => 'test_1') - topic_2 = Topic.new(:title => 'test_2') - topic_3 = topic_without_callbacks.new(:title => 'test_3') + topic_1 = Topic.new(title: "test_1") + topic_2 = Topic.new(title: "test_2") + topic_3 = topic_without_callbacks.new(title: "test_3") Topic.transaction do assert topic_1.save @@ -562,27 +563,27 @@ class TransactionTest < ActiveRecord::TestCase assert topic_3.save @first.save @second.destroy - assert topic_1.persisted?, 'persisted' + assert topic_1.persisted?, "persisted" assert_not_nil topic_1.id - assert topic_2.persisted?, 'persisted' + assert topic_2.persisted?, "persisted" assert_not_nil topic_2.id - assert topic_3.persisted?, 'persisted' + assert topic_3.persisted?, "persisted" assert_not_nil topic_3.id - assert @first.persisted?, 'persisted' + assert @first.persisted?, "persisted" assert_not_nil @first.id - assert @second.destroyed?, 'destroyed' + assert @second.destroyed?, "destroyed" raise ActiveRecord::Rollback end - assert !topic_1.persisted?, 'not persisted' + assert !topic_1.persisted?, "not persisted" assert_nil topic_1.id - assert !topic_2.persisted?, 'not persisted' + assert !topic_2.persisted?, "not persisted" assert_nil topic_2.id - assert !topic_3.persisted?, 'not persisted' + assert !topic_3.persisted?, "not persisted" assert_nil topic_3.id - assert @first.persisted?, 'persisted' + assert @first.persisted?, "persisted" assert_not_nil @first.id - assert !@second.destroyed?, 'not destroyed' + assert !@second.destroyed?, "not destroyed" end def test_restore_frozen_state_after_double_destroy @@ -606,7 +607,7 @@ class TransactionTest < ActiveRecord::TestCase topic.destroy raise ActiveRecord::Rollback end - assert topic.frozen?, 'frozen' + assert topic.frozen?, "frozen" end def test_rollback_for_freshly_persisted_records @@ -615,7 +616,7 @@ class TransactionTest < ActiveRecord::TestCase topic.destroy raise ActiveRecord::Rollback end - assert topic.persisted?, 'persisted' + assert topic.persisted?, "persisted" end def test_sqlite_add_column_in_transaction @@ -629,27 +630,27 @@ class TransactionTest < ActiveRecord::TestCase assert_nothing_raised do Topic.reset_column_information - Topic.connection.add_column('topics', 'stuff', :string) - assert Topic.column_names.include?('stuff') + Topic.connection.add_column("topics", "stuff", :string) + assert_includes Topic.column_names, "stuff" Topic.reset_column_information - Topic.connection.remove_column('topics', 'stuff') - assert !Topic.column_names.include?('stuff') + Topic.connection.remove_column("topics", "stuff") + assert_not_includes Topic.column_names, "stuff" end if Topic.connection.supports_ddl_transactions? assert_nothing_raised do - Topic.transaction { Topic.connection.add_column('topics', 'stuff', :string) } + Topic.transaction { Topic.connection.add_column("topics", "stuff", :string) } end else Topic.transaction do - assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) } + assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.add_column("topics", "stuff", :string) } raise ActiveRecord::Rollback end end ensure begin - Topic.connection.remove_column('topics', 'stuff') + Topic.connection.remove_column("topics", "stuff") rescue ensure Topic.reset_column_information @@ -687,12 +688,12 @@ class TransactionTest < ActiveRecord::TestCase def test_transaction_rollback_with_primarykeyless_tables connection = ActiveRecord::Base.connection connection.create_table(:transaction_without_primary_keys, force: true, id: false) do |t| - t.integer :thing_id + t.integer :thing_id end klass = Class.new(ActiveRecord::Base) do - self.table_name = 'transaction_without_primary_keys' - after_commit { } # necessary to trigger the has_transactional_callbacks branch + self.table_name = "transaction_without_primary_keys" + after_commit {} # necessary to trigger the has_transactional_callbacks branch end assert_no_difference(-> { klass.count }) do @@ -702,20 +703,20 @@ class TransactionTest < ActiveRecord::TestCase end end ensure - connection.drop_table 'transaction_without_primary_keys', if_exists: true + connection.drop_table "transaction_without_primary_keys", if_exists: true end private - %w(validation save destroy).each do |filter| - define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do |topic| - meta = class << topic; self; end - meta.send("define_method", "before_#{filter}_for_transaction") do - Book.create - throw(:abort) + %w(validation save destroy).each do |filter| + define_method("add_cancelling_before_#{filter}_with_db_side_effect_to_topic") do |topic| + meta = class << topic; self; end + meta.send("define_method", "before_#{filter}_for_transaction") do + Book.create + throw(:abort) + end end end - end end class TransactionsWithTransactionalFixturesTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/type/date_time_test.rb b/activerecord/test/cases/type/date_time_test.rb index bc4900e1c2..6848619ece 100644 --- a/activerecord/test/cases/type/date_time_test.rb +++ b/activerecord/test/cases/type/date_time_test.rb @@ -3,7 +3,7 @@ require "models/task" module ActiveRecord module Type - class IntegerTest < ActiveRecord::TestCase + class DateTimeTest < ActiveRecord::TestCase def test_datetime_seconds_precision_applied_to_timestamp skip "This test is invalid if subsecond precision isn't supported" unless subsecond_precision_supported? p = Task.create!(starting: ::Time.now) diff --git a/activerecord/test/cases/type/integer_test.rb b/activerecord/test/cases/type/integer_test.rb index c0932d5357..368b6d7199 100644 --- a/activerecord/test/cases/type/integer_test.rb +++ b/activerecord/test/cases/type/integer_test.rb @@ -6,13 +6,13 @@ module ActiveRecord class IntegerTest < ActiveRecord::TestCase test "casting ActiveRecord models" do type = Type::Integer.new - firm = Firm.create(:name => 'Apple') + firm = Firm.create(name: "Apple") assert_nil type.cast(firm) end test "values which are out of range can be re-assigned" do klass = Class.new(ActiveRecord::Base) do - self.table_name = 'posts' + self.table_name = "posts" attribute :foo, :integer end model = klass.new diff --git a/activerecord/test/cases/type/string_test.rb b/activerecord/test/cases/type/string_test.rb index 6fe6d46711..a95da864fa 100644 --- a/activerecord/test/cases/type/string_test.rb +++ b/activerecord/test/cases/type/string_test.rb @@ -1,21 +1,21 @@ -require 'cases/helper' +require "cases/helper" module ActiveRecord class StringTypeTest < ActiveRecord::TestCase test "string mutations are detected" do klass = Class.new(Base) - klass.table_name = 'authors' + klass.table_name = "authors" - author = klass.create!(name: 'Sean') + author = klass.create!(name: "Sean") assert_not author.changed? - author.name << ' Griffin' + author.name << " Griffin" assert author.name_changed? author.save! author.reload - assert_equal 'Sean Griffin', author.name + assert_equal "Sean Griffin", author.name assert_not author.changed? end end diff --git a/activerecord/test/cases/type/type_map_test.rb b/activerecord/test/cases/type/type_map_test.rb index 172c6dfc4c..2959d36466 100644 --- a/activerecord/test/cases/type/type_map_test.rb +++ b/activerecord/test/cases/type/type_map_test.rb @@ -15,7 +15,7 @@ module ActiveRecord mapping.register_type(/boolean/i, boolean) - assert_equal mapping.lookup('boolean'), boolean + assert_equal mapping.lookup("boolean"), boolean end def test_overriding_registered_types @@ -26,7 +26,7 @@ module ActiveRecord mapping.register_type(/time/i, time) mapping.register_type(/time/i, timestamp) - assert_equal mapping.lookup('time'), timestamp + assert_equal mapping.lookup("time"), timestamp end def test_fuzzy_lookup @@ -35,7 +35,7 @@ module ActiveRecord mapping.register_type(/varchar/i, string) - assert_equal mapping.lookup('varchar(20)'), string + assert_equal mapping.lookup("varchar(20)"), string end def test_aliasing_types @@ -43,9 +43,9 @@ module ActiveRecord mapping = TypeMap.new mapping.register_type(/string/i, string) - mapping.alias_type(/varchar/i, 'string') + mapping.alias_type(/varchar/i, "string") - assert_equal mapping.lookup('varchar'), string + assert_equal mapping.lookup("varchar"), string end def test_changing_type_changes_aliases @@ -54,20 +54,20 @@ module ActiveRecord mapping = TypeMap.new mapping.register_type(/timestamp/i, time) - mapping.alias_type(/datetime/i, 'timestamp') + mapping.alias_type(/datetime/i, "timestamp") mapping.register_type(/timestamp/i, timestamp) - assert_equal mapping.lookup('datetime'), timestamp + assert_equal mapping.lookup("datetime"), timestamp end def test_aliases_keep_metadata mapping = TypeMap.new mapping.register_type(/decimal/i) { |sql_type| sql_type } - mapping.alias_type(/number/i, 'decimal') + mapping.alias_type(/number/i, "decimal") - assert_equal mapping.lookup('number(20)'), 'decimal(20)' - assert_equal mapping.lookup('number'), 'decimal' + assert_equal mapping.lookup("number(20)"), "decimal(20)" + assert_equal mapping.lookup("number"), "decimal" end def test_register_proc @@ -76,15 +76,15 @@ module ActiveRecord mapping = TypeMap.new mapping.register_type(/varchar/i) do |type| - if type.include?('(') + if type.include?("(") string else binary end end - assert_equal mapping.lookup('varchar(20)'), string - assert_equal mapping.lookup('varchar'), binary + assert_equal mapping.lookup("varchar(20)"), string + assert_equal mapping.lookup("varchar"), binary end def test_additional_lookup_args @@ -92,16 +92,16 @@ module ActiveRecord mapping.register_type(/varchar/i) do |type, limit| if limit > 255 - 'text' + "text" else - 'string' + "string" end end - mapping.alias_type(/string/i, 'varchar') + mapping.alias_type(/string/i, "varchar") - assert_equal mapping.lookup('varchar', 200), 'string' - assert_equal mapping.lookup('varchar', 400), 'text' - assert_equal mapping.lookup('string', 400), 'text' + assert_equal mapping.lookup("varchar", 200), "string" + assert_equal mapping.lookup("varchar", 400), "text" + assert_equal mapping.lookup("string", 400), "text" end def test_requires_value_or_block @@ -115,13 +115,13 @@ module ActiveRecord def test_lookup_non_strings mapping = HashLookupTypeMap.new - mapping.register_type(1, 'string') - mapping.register_type(2, 'int') + mapping.register_type(1, "string") + mapping.register_type(2, "int") mapping.alias_type(3, 1) - assert_equal mapping.lookup(1), 'string' - assert_equal mapping.lookup(2), 'int' - assert_equal mapping.lookup(3), 'string' + assert_equal mapping.lookup(1), "string" + assert_equal mapping.lookup(2), "int" + assert_equal mapping.lookup(3), "string" assert_kind_of Type::Value, mapping.lookup(4) end @@ -174,4 +174,3 @@ module ActiveRecord end end end - diff --git a/activerecord/test/cases/types_test.rb b/activerecord/test/cases/types_test.rb index 81fcf04a27..11476ea0ef 100644 --- a/activerecord/test/cases/types_test.rb +++ b/activerecord/test/cases/types_test.rb @@ -9,7 +9,7 @@ module ActiveRecord raise end klass = Class.new(ActiveRecord::Base) do - self.table_name = 'posts' + self.table_name = "posts" attribute :foo, type_which_cannot_go_to_the_database end model = klass.new diff --git a/activerecord/test/cases/validations/absence_validation_test.rb b/activerecord/test/cases/validations/absence_validation_test.rb index c0b3750bcc..870619e4e7 100644 --- a/activerecord/test/cases/validations/absence_validation_test.rb +++ b/activerecord/test/cases/validations/absence_validation_test.rb @@ -1,8 +1,8 @@ require "cases/helper" -require 'models/face' -require 'models/interest' -require 'models/man' -require 'models/topic' +require "models/face" +require "models/interest" +require "models/man" +require "models/topic" class AbsenceValidationTest < ActiveRecord::TestCase def test_non_association @@ -52,7 +52,7 @@ class AbsenceValidationTest < ActiveRecord::TestCase end face_with_to_a = Face.new - def face_with_to_a.to_a; ['(/)', '(\)']; end + def face_with_to_a.to_a; ["(/)", '(\)']; end assert_nothing_raised { boy_klass.new(face: face_with_to_a).valid? } end @@ -62,10 +62,10 @@ class AbsenceValidationTest < ActiveRecord::TestCase Interest.send(:attr_accessor, :token) Interest.validates_absence_of(:token) - interest = Interest.create!(topic: 'Thought Leadering') + interest = Interest.create!(topic: "Thought Leadering") assert interest.valid? - interest.token = 'tl' + interest.token = "tl" assert interest.invalid? end diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb index 584a3dc0d8..66d6ecb928 100644 --- a/activerecord/test/cases/validations/association_validation_test.rb +++ b/activerecord/test/cases/validations/association_validation_test.rb @@ -1,8 +1,8 @@ require "cases/helper" -require 'models/topic' -require 'models/reply' -require 'models/man' -require 'models/interest' +require "models/topic" +require "models/reply" +require "models/man" +require "models/interest" class AssociationValidationTest < ActiveRecord::TestCase fixtures :topics @@ -25,7 +25,7 @@ class AssociationValidationTest < ActiveRecord::TestCase end def test_validates_associated_one - Reply.validates :topic, :associated => true + Reply.validates :topic, associated: true Topic.validates_presence_of( :content ) r = Reply.new("title" => "A reply", "content" => "with content!") r.topic = Topic.create("title" => "uhohuhoh") @@ -58,7 +58,7 @@ class AssociationValidationTest < ActiveRecord::TestCase end def test_validates_associated_with_custom_message_using_quotes - Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes" + Reply.validates_associated :topic, message: "This string contains 'single' and \"double\" quotes" Topic.validates_presence_of :content r = Reply.create("title" => "A reply", "content" => "with content!") r.topic = Topic.create("title" => "uhohuhoh") @@ -80,8 +80,8 @@ class AssociationValidationTest < ActiveRecord::TestCase repair_validations(Interest) do # Note that Interest and Man have the :inverse_of option set Interest.validates_presence_of(:man) - man = Man.new(:name => 'John') - interest = man.interests.build(:topic => 'Airplanes') + man = Man.new(name: "John") + interest = man.interests.build(topic: "Airplanes") assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated" end end @@ -89,8 +89,8 @@ class AssociationValidationTest < ActiveRecord::TestCase def test_validates_presence_of_belongs_to_association__existing_parent repair_validations(Interest) do Interest.validates_presence_of(:man) - man = Man.create!(:name => 'John') - interest = man.interests.build(:topic => 'Airplanes') + man = Man.create!(name: "John") + interest = man.interests.build(topic: "Airplanes") assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated" end end diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb index 13d4d85afa..a57065ba75 100644 --- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb @@ -1,5 +1,5 @@ require "cases/helper" -require 'models/topic' +require "models/topic" class I18nGenerateMessageValidationTest < ActiveRecord::TestCase def setup @@ -20,20 +20,20 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase # validates_associated: generate_message(attr_name, :invalid, :message => custom_message, :value => value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @topic.errors.generate_message(:title, :invalid, :value => 'title') + assert_equal "is invalid", @topic.errors.generate_message(:title, :invalid, value: "title") end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :message => 'custom message %{value}', :value => 'title') + assert_equal "custom message title", @topic.errors.generate_message(:title, :invalid, message: "custom message %{value}", value: "title") end # validates_uniqueness_of: generate_message(attr_name, :taken, :message => custom_message) def test_generate_message_taken_with_default_message - assert_equal "has already been taken", @topic.errors.generate_message(:title, :taken, :value => 'title') + assert_equal "has already been taken", @topic.errors.generate_message(:title, :taken, value: "title") end def test_generate_message_taken_with_custom_message - assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :message => 'custom message %{value}', :value => 'title') + assert_equal "custom message title", @topic.errors.generate_message(:title, :taken, message: "custom message %{value}", value: "title") end # ActiveRecord#RecordInvalid exception @@ -47,7 +47,7 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase test "RecordInvalid exception translation falls back to the :errors namespace" do reset_i18n_load_path do - I18n.backend.store_translations 'en', :errors => {:messages => {:record_invalid => 'fallback message'}} + I18n.backend.store_translations "en", errors: { messages: { record_invalid: "fallback message" } } topic = Topic.new topic.errors.add(:title, :blank) assert_equal "fallback message", ActiveRecord::RecordInvalid.new(topic).message @@ -56,29 +56,29 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase test "translation for 'taken' can be overridden" do reset_i18n_load_path do - I18n.backend.store_translations "en", {errors: {attributes: {title: {taken: "Custom taken message" }}}} - assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title') + I18n.backend.store_translations "en", errors: { attributes: { title: { taken: "Custom taken message" } } } + assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end test "translation for 'taken' can be overridden in activerecord scope" do reset_i18n_load_path do - I18n.backend.store_translations "en", {activerecord: {errors: {messages: {taken: "Custom taken message" }}}} - assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title') + I18n.backend.store_translations "en", activerecord: { errors: { messages: { taken: "Custom taken message" } } } + assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end test "translation for 'taken' can be overridden in activerecord model scope" do reset_i18n_load_path do - I18n.backend.store_translations "en", {activerecord: {errors: {models: {topic: {taken: "Custom taken message" }}}}} - assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title') + I18n.backend.store_translations "en", activerecord: { errors: { models: { topic: { taken: "Custom taken message" } } } } + assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end test "translation for 'taken' can be overridden in activerecord attributes scope" do reset_i18n_load_path do - I18n.backend.store_translations "en", {activerecord: {errors: {models: {topic: {attributes: {title: {taken: "Custom taken message" }}}}}}} - assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title') + I18n.backend.store_translations "en", activerecord: { errors: { models: { topic: { attributes: { title: { taken: "Custom taken message" } } } } } } + assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, value: "title") end end end diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index 5b5307489a..fd88a3ea67 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -1,6 +1,6 @@ require "cases/helper" -require 'models/topic' -require 'models/reply' +require "models/topic" +require "models/reply" class I18nValidationTest < ActiveRecord::TestCase repair_validations(Topic, Reply) @@ -12,7 +12,7 @@ class I18nValidationTest < ActiveRecord::TestCase @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations('en', :errors => {:messages => {:custom => nil}}) + I18n.backend.store_translations("en", errors: { messages: { custom: nil } }) end teardown do @@ -21,12 +21,12 @@ class I18nValidationTest < ActiveRecord::TestCase end def unique_topic - @unique ||= Topic.create :title => 'unique!' + @unique ||= Topic.create title: "unique!" end def replied_topic @replied_topic ||= begin - topic = Topic.create(:title => "topic") + topic = Topic.create(title: "topic") topic.replies << Reply.new topic end @@ -36,20 +36,20 @@ class I18nValidationTest < ActiveRecord::TestCase # are used to generate tests to keep things DRY # COMMON_CASES = [ - # [ case, validation_options, generate_message_options] + # [ case, validation_options, generate_message_options] [ "given no options", {}, {}], - [ "given custom message", {:message => "custom"}, {:message => "custom"}], - [ "given if condition", {:if => lambda { true }}, {}], - [ "given unless condition", {:unless => lambda { false }}, {}], - [ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }], - [ "given on condition", {on: [:create, :update] }, {}] + [ "given custom message", { message: "custom" }, { message: "custom" }], + [ "given if condition", { if: lambda { true } }, {}], + [ "given unless condition", { unless: lambda { false } }, {}], + [ "given option that is not reserved", { format: "jpg" }, { format: "jpg" }], + [ "given on condition", { on: [:create, :update] }, {}] ] COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_uniqueness_of on generated message #{name}" do Topic.validates_uniqueness_of :title, validation_options @topic.title = unique_topic.title - assert_called_with(@topic.errors, :generate_message, [:title, :taken, generate_message_options.merge(:value => 'unique!')]) do + assert_called_with(@topic.errors, :generate_message, [:title, :taken, generate_message_options.merge(value: "unique!")]) do @topic.valid? end end @@ -58,27 +58,26 @@ class I18nValidationTest < ActiveRecord::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_associated on generated message #{name}" do Topic.validates_associated :replies, validation_options - assert_called_with(replied_topic.errors, :generate_message, [:replies, :invalid, generate_message_options.merge(:value => replied_topic.replies)]) do + assert_called_with(replied_topic.errors, :generate_message, [:replies, :invalid, generate_message_options.merge(value: replied_topic.replies)]) do replied_topic.save end end end def test_validates_associated_finds_custom_model_key_translation - I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:replies => {:invalid => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:invalid => 'global message'}}} + I18n.backend.store_translations "en", activerecord: { errors: { models: { topic: { attributes: { replies: { invalid: "custom message" } } } } } } + I18n.backend.store_translations "en", activerecord: { errors: { messages: { invalid: "global message" } } } Topic.validates_associated :replies replied_topic.valid? - assert_equal ['custom message'], replied_topic.errors[:replies].uniq + assert_equal ["custom message"], replied_topic.errors[:replies].uniq end def test_validates_associated_finds_global_default_translation - I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:invalid => 'global message'}}} + I18n.backend.store_translations "en", activerecord: { errors: { messages: { invalid: "global message" } } } Topic.validates_associated :replies replied_topic.valid? - assert_equal ['global message'], replied_topic.errors[:replies] + assert_equal ["global message"], replied_topic.errors[:replies] end - end diff --git a/activerecord/test/cases/validations/length_validation_test.rb b/activerecord/test/cases/validations/length_validation_test.rb index 78263fd955..ba45c6dcc1 100644 --- a/activerecord/test/cases/validations/length_validation_test.rb +++ b/activerecord/test/cases/validations/length_validation_test.rb @@ -1,47 +1,46 @@ require "cases/helper" -require 'models/owner' -require 'models/pet' -require 'models/person' +require "models/owner" +require "models/pet" +require "models/person" class LengthValidationTest < ActiveRecord::TestCase fixtures :owners setup do @owner = Class.new(Owner) do - def self.name; 'Owner'; end + def self.name; "Owner"; end end end - def test_validates_size_of_association assert_nothing_raised { @owner.validates_size_of :pets, minimum: 1 } - o = @owner.new('name' => 'nopets') + o = @owner.new("name" => "nopets") assert !o.save assert o.errors[:pets].any? - o.pets.build('name' => 'apet') + o.pets.build("name" => "apet") assert o.valid? end def test_validates_size_of_association_using_within assert_nothing_raised { @owner.validates_size_of :pets, within: 1..2 } - o = @owner.new('name' => 'nopets') + o = @owner.new("name" => "nopets") assert !o.save assert o.errors[:pets].any? - o.pets.build('name' => 'apet') + o.pets.build("name" => "apet") assert o.valid? - 2.times { o.pets.build('name' => 'apet') } + 2.times { o.pets.build("name" => "apet") } assert !o.save assert o.errors[:pets].any? end def test_validates_size_of_association_utf8 @owner.validates_size_of :pets, minimum: 1 - o = @owner.new('name' => 'ã‚ã„ã†ãˆãŠã‹ããã‘ã“') + o = @owner.new("name" => "ã‚ã„ã†ãˆãŠã‹ããã‘ã“") assert !o.save assert o.errors[:pets].any? - o.pets.build('name' => 'ã‚ã„ã†ãˆãŠã‹ããã‘ã“') + o.pets.build("name" => "ã‚ã„ã†ãˆãŠã‹ããã‘ã“") assert o.valid? end @@ -55,7 +54,7 @@ class LengthValidationTest < ActiveRecord::TestCase assert owner.save pet_count = Pet.count - assert_not owner.update_attributes pets_attributes: [ {_destroy: 1, id: pet.id} ] + assert_not owner.update_attributes pets_attributes: [ { _destroy: 1, id: pet.id } ] assert_not owner.valid? assert owner.errors[:pets].any? assert_equal pet_count, Pet.count @@ -67,11 +66,11 @@ class LengthValidationTest < ActiveRecord::TestCase Pet.validates_length_of(:name, minimum: 1) Pet.validates_length_of(:nickname, minimum: 1) - pet = Pet.create!(name: 'Fancy Pants', nickname: 'Fancy') + pet = Pet.create!(name: "Fancy Pants", nickname: "Fancy") assert pet.valid? - pet.nickname = '' + pet.nickname = "" assert pet.invalid? end diff --git a/activerecord/test/cases/validations/presence_validation_test.rb b/activerecord/test/cases/validations/presence_validation_test.rb index 868d111b8c..13956e26ec 100644 --- a/activerecord/test/cases/validations/presence_validation_test.rb +++ b/activerecord/test/cases/validations/presence_validation_test.rb @@ -1,9 +1,9 @@ require "cases/helper" -require 'models/man' -require 'models/face' -require 'models/interest' -require 'models/speedometer' -require 'models/dashboard' +require "models/man" +require "models/face" +require "models/interest" +require "models/speedometer" +require "models/dashboard" class PresenceValidationTest < ActiveRecord::TestCase class Boy < Man; end @@ -57,7 +57,7 @@ class PresenceValidationTest < ActiveRecord::TestCase dash = Dashboard.new # dashboard has to_a method - def dash.to_a; ['(/)', '(\)']; end + def dash.to_a; ["(/)", '(\)']; end s = speedometer.new s.dashboard = dash @@ -71,10 +71,10 @@ class PresenceValidationTest < ActiveRecord::TestCase Interest.validates_presence_of(:topic) Interest.validates_presence_of(:abbreviation) - interest = Interest.create!(topic: 'Thought Leadering', abbreviation: 'tl') + interest = Interest.create!(topic: "Thought Leadering", abbreviation: "tl") assert interest.valid? - interest.abbreviation = '' + interest.abbreviation = "" assert interest.invalid? end diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index 4b0a590adb..44b4e28777 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -1,11 +1,11 @@ require "cases/helper" -require 'models/topic' -require 'models/reply' -require 'models/warehouse_thing' -require 'models/guid' -require 'models/event' -require 'models/dashboard' -require 'models/uuid_item' +require "models/topic" +require "models/reply" +require "models/warehouse_thing" +require "models/guid" +require "models/event" +require "models/dashboard" +require "models/uuid_item" class Wizard < ActiveRecord::Base self.abstract_class = true @@ -26,7 +26,7 @@ end class ReplyTitle; end class ReplyWithTitleObject < Reply - validates_uniqueness_of :content, :scope => :title + validates_uniqueness_of :content, scope: :title def title; ReplyTitle.new; end end @@ -38,13 +38,13 @@ end class BigIntTest < ActiveRecord::Base INT_MAX_VALUE = 2147483647 - self.table_name = 'cars' + self.table_name = "cars" validates :engines_count, uniqueness: true, inclusion: { in: 0..INT_MAX_VALUE } end class BigIntReverseTest < ActiveRecord::Base INT_MAX_VALUE = 2147483647 - self.table_name = 'cars' + self.table_name = "cars" validates :engines_count, inclusion: { in: 0..INT_MAX_VALUE } validates :engines_count, uniqueness: true end @@ -57,14 +57,14 @@ class TopicWithAfterCreate < Topic after_create :set_author def set_author - update_attributes!(:author_name => "#{title} #{id}") + update_attributes!(author_name: "#{title} #{id}") end end class UniquenessValidationTest < ActiveRecord::TestCase INT_MAX_VALUE = 2147483647 - fixtures :topics, 'warehouse-things' + fixtures :topics, "warehouse-things" repair_validations(Topic, Reply) @@ -90,7 +90,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase Topic.alias_attribute :new_title, :title Topic.validates_uniqueness_of(:new_title) - topic = Topic.new(new_title: 'abc') + topic = Topic.new(new_title: "abc") assert topic.valid? end @@ -107,33 +107,33 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validates_uniqueness_with_validates - Topic.validates :title, :uniqueness => true - Topic.create!('title' => 'abc') + Topic.validates :title, uniqueness: true + Topic.create!("title" => "abc") - t2 = Topic.new('title' => 'abc') + t2 = Topic.new("title" => "abc") assert !t2.valid? assert t2.errors[:title] end def test_validate_uniqueness_when_integer_out_of_range entry = BigIntTest.create(engines_count: INT_MAX_VALUE + 1) - assert_equal entry.errors[:engines_count], ['is not included in the list'] + assert_equal entry.errors[:engines_count], ["is not included in the list"] end def test_validate_uniqueness_when_integer_out_of_range_show_order_does_not_matter entry = BigIntReverseTest.create(engines_count: INT_MAX_VALUE + 1) - assert_equal entry.errors[:engines_count], ['is not included in the list'] + assert_equal entry.errors[:engines_count], ["is not included in the list"] end def test_validates_uniqueness_with_newline_chars - Topic.validates_uniqueness_of(:title, :case_sensitive => false) + Topic.validates_uniqueness_of(:title, case_sensitive: false) t = Topic.new("title" => "new\nline") assert t.save, "Should save t as unique" end def test_validate_uniqueness_with_scope - Reply.validates_uniqueness_of(:content, :scope => "parent_id") + Reply.validates_uniqueness_of(:content, scope: "parent_id") t = Topic.create("title" => "I'm unique!") @@ -152,7 +152,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_uniqueness_with_object_scope - Reply.validates_uniqueness_of(:content, :scope => :topic) + Reply.validates_uniqueness_of(:content, scope: :topic) t = Topic.create("title" => "I'm unique!") @@ -199,7 +199,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_uniqueness_with_scope_array - Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id]) + Reply.validates_uniqueness_of(:author_name, scope: [:author_email_address, :parent_id]) t = Topic.create("title" => "The earth is actually flat!") @@ -223,7 +223,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_case_insensitive_uniqueness - Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true) + Topic.validates_uniqueness_of(:title, :parent_id, case_sensitive: false, allow_nil: true) t = Topic.new("title" => "I'm unique!", :parent_id => 2) assert t.save, "Should save t as unique" @@ -256,7 +256,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase assert t_utf8.save, "Should save t_utf8 as unique" # If database hasn't UTF-8 character set, this test fails - if Topic.all.merge!(:select => 'LOWER(title) AS title').find(t_utf8.id).title == "Ñ Ñ‚Ð¾Ð¶Ðµ уникальный!" + if Topic.all.merge!(select: "LOWER(title) AS title").find(t_utf8.id).title == "Ñ Ñ‚Ð¾Ð¶Ðµ уникальный!" t2_utf8 = Topic.new("title" => "Ñ Ñ‚Ð¾Ð¶Ðµ УÐИКÐЛЬÐЫЙ!") assert !t2_utf8.valid?, "Shouldn't be valid" assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique" @@ -264,7 +264,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_case_sensitive_uniqueness_with_special_sql_like_chars - Topic.validates_uniqueness_of(:title, :case_sensitive => true) + Topic.validates_uniqueness_of(:title, case_sensitive: true) t = Topic.new("title" => "I'm unique!") assert t.save, "Should save t as unique" @@ -277,7 +277,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_case_insensitive_uniqueness_with_special_sql_like_chars - Topic.validates_uniqueness_of(:title, :case_sensitive => false) + Topic.validates_uniqueness_of(:title, case_sensitive: false) t = Topic.new("title" => "I'm unique!") assert t.save, "Should save t as unique" @@ -290,7 +290,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_case_sensitive_uniqueness - Topic.validates_uniqueness_of(:title, :case_sensitive => true, :allow_nil => true) + Topic.validates_uniqueness_of(:title, case_sensitive: true, allow_nil: true) t = Topic.new("title" => "I'm unique!") assert t.save, "Should save t as unique" @@ -314,16 +314,16 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_case_sensitive_uniqueness_with_attribute_passed_as_integer - Topic.validates_uniqueness_of(:title, :case_sensitive => true) - Topic.create!('title' => 101) + Topic.validates_uniqueness_of(:title, case_sensitive: true) + Topic.create!("title" => 101) - t2 = Topic.new('title' => 101) + t2 = Topic.new("title" => 101) assert !t2.valid? assert t2.errors[:title] end def test_validate_uniqueness_with_non_standard_table_names - i1 = WarehouseThing.create(:value => 1000) + i1 = WarehouseThing.create(value: 1000) assert !i1.valid?, "i1 should not be valid" assert i1.errors[:value].any?, "Should not be empty" end @@ -331,7 +331,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase def test_validates_uniqueness_inside_scoping Topic.validates_uniqueness_of(:title) - Topic.where(:author_name => "David").scoping do + Topic.where(author_name: "David").scoping do t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary") assert t1.save t2 = Topic.new("title" => "I'm unique!", "author_name" => "David") @@ -387,29 +387,29 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_straight_inheritance_uniqueness - w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork") + w1 = IneptWizard.create(name: "Rincewind", city: "Ankh-Morpork") assert w1.valid?, "Saving w1" # Should use validation from base class (which is abstract) - w2 = IneptWizard.new(:name => "Rincewind", :city => "Quirm") + w2 = IneptWizard.new(name: "Rincewind", city: "Quirm") assert !w2.valid?, "w2 shouldn't be valid" assert w2.errors[:name].any?, "Should have errors for name" assert_equal ["has already been taken"], w2.errors[:name], "Should have uniqueness message for name" - w3 = Conjurer.new(:name => "Rincewind", :city => "Quirm") + w3 = Conjurer.new(name: "Rincewind", city: "Quirm") assert !w3.valid?, "w3 shouldn't be valid" assert w3.errors[:name].any?, "Should have errors for name" assert_equal ["has already been taken"], w3.errors[:name], "Should have uniqueness message for name" - w4 = Conjurer.create(:name => "The Amazing Bonko", :city => "Quirm") + w4 = Conjurer.create(name: "The Amazing Bonko", city: "Quirm") assert w4.valid?, "Saving w4" - w5 = Thaumaturgist.new(:name => "The Amazing Bonko", :city => "Lancre") + w5 = Thaumaturgist.new(name: "The Amazing Bonko", city: "Lancre") assert !w5.valid?, "w5 shouldn't be valid" assert w5.errors[:name].any?, "Should have errors for name" assert_equal ["has already been taken"], w5.errors[:name], "Should have uniqueness message for name" - w6 = Thaumaturgist.new(:name => "Mustrum Ridcully", :city => "Quirm") + w6 = Thaumaturgist.new(name: "Mustrum Ridcully", city: "Quirm") assert !w6.valid?, "w6 shouldn't be valid" assert w6.errors[:city].any?, "Should have errors for city" assert_equal ["has already been taken"], w6.errors[:city], "Should have uniqueness message for city" @@ -439,7 +439,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase topic = TopicWithUniqEvent.new(event: event) assert_not topic.valid? - assert_equal ['has already been taken'], topic.errors[:event] + assert_equal ["has already been taken"], topic.errors[:event] end def test_validate_uniqueness_on_empty_relation @@ -501,30 +501,30 @@ class UniquenessValidationTest < ActiveRecord::TestCase def test_validate_uniqueness_with_after_create_performing_save TopicWithAfterCreate.validates_uniqueness_of(:title) - topic = TopicWithAfterCreate.create!(:title => "Title1") + topic = TopicWithAfterCreate.create!(title: "Title1") assert topic.author_name.start_with?("Title1") - topic2 = TopicWithAfterCreate.new(:title => "Title1") + topic2 = TopicWithAfterCreate.new(title: "Title1") refute topic2.valid? assert_equal(["has already been taken"], topic2.errors[:title]) end def test_validate_uniqueness_uuid skip unless current_adapter?(:PostgreSQLAdapter) - item = UuidItem.create!(uuid: SecureRandom.uuid, title: 'item1') - item.update(title: 'item1-title2') + item = UuidItem.create!(uuid: SecureRandom.uuid, title: "item1") + item.update(title: "item1-title2") assert_empty item.errors - item2 = UuidValidatingItem.create!(uuid: SecureRandom.uuid, title: 'item2') - item2.update(title: 'item2-title2') + item2 = UuidValidatingItem.create!(uuid: SecureRandom.uuid, title: "item2") + item2.update(title: "item2-title2") assert_empty item2.errors end def test_validate_uniqueness_regular_id - item = CoolTopic.create!(title: 'MyItem') + item = CoolTopic.create!(title: "MyItem") assert_empty item.errors - item2 = CoolTopic.new(id: item.id, title: 'MyItem2') + item2 = CoolTopic.new(id: item.id, title: "MyItem2") refute item2.valid? assert_equal(["has already been taken"], item2.errors[:id]) diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 85e33d2218..5d9aa99497 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -1,11 +1,11 @@ require "cases/helper" -require 'models/topic' -require 'models/reply' -require 'models/person' -require 'models/developer' -require 'models/computer' -require 'models/parrot' -require 'models/company' +require "models/topic" +require "models/reply" +require "models/person" +require "models/developer" +require "models/computer" +require "models/parrot" +require "models/company" class ValidationsTest < ActiveRecord::TestCase fixtures :topics, :developers @@ -36,7 +36,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_valid_using_special_context - r = WrongReply.new(:title => "Valid title") + r = WrongReply.new(title: "Valid title") assert !r.valid?(:special_case) assert_equal "Invalid", r.errors[:author_name].join @@ -53,7 +53,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_invalid_using_multiple_contexts - r = WrongReply.new(:title => 'Wrong Create') + r = WrongReply.new(title: "Wrong Create") assert r.invalid?([:special_case, :create]) assert_equal "Invalid", r.errors[:author_name].join assert_equal "is Wrong Create", r.errors[:title].join @@ -95,7 +95,7 @@ class ValidationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::RecordInvalid) do WrongReply.new.validate!(:special_case) end - r = WrongReply.new(:title => "Valid title", :author_name => "secret", :content => "Good") + r = WrongReply.new(title: "Valid title", author_name: "secret", content: "Good") assert r.validate!(:special_case) end @@ -107,7 +107,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_exception_on_create_bang_with_block assert_raise(ActiveRecord::RecordInvalid) do - WrongReply.create!({ "title" => "OK" }) do |r| + WrongReply.create!("title" => "OK") do |r| r.content = nil end end @@ -124,7 +124,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_save_without_validation reply = WrongReply.new assert !reply.save - assert reply.save(:validate => false) + assert reply.save(validate: false) end def test_validates_acceptance_of_with_non_existent_table @@ -156,22 +156,20 @@ class ValidationsTest < ActiveRecord::TestCase end def test_numericality_validation_with_mutation - Topic.class_eval do + klass = Class.new(Topic) do attribute :wibble, :string validates_numericality_of :wibble, only_integer: true end - topic = Topic.new(wibble: '123-4567') - topic.wibble.gsub!('-', '') + topic = klass.new(wibble: "123-4567") + topic.wibble.gsub!("-", "") assert topic.valid? - ensure - Topic.reset_column_information end def test_acceptance_validator_doesnt_require_db_connection klass = Class.new(ActiveRecord::Base) do - self.table_name = 'posts' + self.table_name = "posts" end klass.reset_column_information diff --git a/activerecord/test/cases/view_test.rb b/activerecord/test/cases/view_test.rb index f3c2d2f30e..1f326d4b39 100644 --- a/activerecord/test/cases/view_test.rb +++ b/activerecord/test/cases/view_test.rb @@ -11,20 +11,21 @@ module ViewBehavior end class Ebook < ActiveRecord::Base + self.table_name = "ebooks'" self.primary_key = "id" end def setup super @connection = ActiveRecord::Base.connection - create_view "ebooks", <<-SQL + create_view "ebooks'", <<-SQL SELECT id, name, status FROM books WHERE format = 'ebook' SQL end def teardown super - drop_view "ebooks" + drop_view "ebooks'" end def test_reading @@ -60,157 +61,162 @@ module ViewBehavior end def test_attributes - assert_equal({"id" => 2, "name" => "Ruby for Rails", "status" => 0}, + assert_equal({ "id" => 2, "name" => "Ruby for Rails", "status" => 0 }, Ebook.first.attributes) end def test_does_not_assume_id_column_as_primary_key model = Class.new(ActiveRecord::Base) do - self.table_name = "ebooks" + self.table_name = "ebooks'" end assert_nil model.primary_key end def test_does_not_dump_view_as_table - schema = dump_table_schema "ebooks" - assert_no_match %r{create_table "ebooks"}, schema + schema = dump_table_schema "ebooks'" + assert_no_match %r{create_table "ebooks'"}, schema end -end - -if ActiveRecord::Base.connection.supports_views? -class ViewWithPrimaryKeyTest < ActiveRecord::TestCase - include ViewBehavior private - def create_view(name, query) - @connection.execute "CREATE VIEW #{name} AS #{query}" - end - - def drop_view(name) - @connection.execute "DROP VIEW #{name}" if @connection.view_exists? name - end + def quote_table_name(name) + @connection.quote_table_name(name) + end end -class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase - include SchemaDumpingHelper - fixtures :books - - class Paperback < ActiveRecord::Base; end - - setup do - @connection = ActiveRecord::Base.connection - @connection.execute <<-SQL - CREATE VIEW paperbacks - AS SELECT name, status FROM books WHERE format = 'paperback' - SQL - end - - teardown do - @connection.execute "DROP VIEW paperbacks" if @connection.view_exists? "paperbacks" - end +if ActiveRecord::Base.connection.supports_views? + class ViewWithPrimaryKeyTest < ActiveRecord::TestCase + include ViewBehavior - def test_reading - books = Paperback.all - assert_equal ["Agile Web Development with Rails"], books.map(&:name) - end + private + def create_view(name, query) + @connection.execute "CREATE VIEW #{quote_table_name(name)} AS #{query}" + end - def test_views - assert_equal [Paperback.table_name], @connection.views - end - - def test_view_exists - view_name = Paperback.table_name - assert @connection.view_exists?(view_name), "'#{view_name}' view should exist" + def drop_view(name) + @connection.execute "DROP VIEW #{quote_table_name(name)}" if @connection.view_exists? name + end end - def test_table_exists - view_name = Paperback.table_name - # TODO: switch this assertion around once we changed #tables to not return views. - ActiveSupport::Deprecation.silence { assert @connection.table_exists?(view_name), "'#{view_name}' table should exist" } - end + class ViewWithoutPrimaryKeyTest < ActiveRecord::TestCase + include SchemaDumpingHelper + fixtures :books - def test_column_definitions - assert_equal([["name", :string], - ["status", :integer]], Paperback.columns.map { |c| [c.name, c.type] }) - end + class Paperback < ActiveRecord::Base; end - def test_attributes - assert_equal({"name" => "Agile Web Development with Rails", "status" => 2}, - Paperback.first.attributes) - end + setup do + @connection = ActiveRecord::Base.connection + @connection.execute <<-SQL + CREATE VIEW paperbacks + AS SELECT name, status FROM books WHERE format = 'paperback' + SQL + end - def test_does_not_have_a_primary_key - assert_nil Paperback.primary_key - end + teardown do + @connection.execute "DROP VIEW paperbacks" if @connection.view_exists? "paperbacks" + end - def test_does_not_dump_view_as_table - schema = dump_table_schema "paperbacks" - assert_no_match %r{create_table "paperbacks"}, schema - end -end + def test_reading + books = Paperback.all + assert_equal ["Agile Web Development with Rails"], books.map(&:name) + end -# sqlite dose not support CREATE, INSERT, and DELETE for VIEW -if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter) -class UpdateableViewTest < ActiveRecord::TestCase - self.use_transactional_tests = false - fixtures :books + def test_views + assert_equal [Paperback.table_name], @connection.views + end - class PrintedBook < ActiveRecord::Base - self.primary_key = "id" - end + def test_view_exists + view_name = Paperback.table_name + assert @connection.view_exists?(view_name), "'#{view_name}' view should exist" + end - setup do - @connection = ActiveRecord::Base.connection - @connection.execute <<-SQL - CREATE VIEW printed_books - AS SELECT id, name, status, format FROM books WHERE format = 'paperback' - SQL - end + def test_table_exists + view_name = Paperback.table_name + # TODO: switch this assertion around once we changed #tables to not return views. + ActiveSupport::Deprecation.silence { assert @connection.table_exists?(view_name), "'#{view_name}' table should exist" } + end - teardown do - @connection.execute "DROP VIEW printed_books" if @connection.view_exists? "printed_books" - end + def test_column_definitions + assert_equal([["name", :string], + ["status", :integer]], Paperback.columns.map { |c| [c.name, c.type] }) + end - def test_update_record - book = PrintedBook.first - book.name = "AWDwR" - book.save! - book.reload - assert_equal "AWDwR", book.name - end + def test_attributes + assert_equal({ "name" => "Agile Web Development with Rails", "status" => 2 }, + Paperback.first.attributes) + end - def test_insert_record - PrintedBook.create! name: "Rails in Action", status: 0, format: "paperback" + def test_does_not_have_a_primary_key + assert_nil Paperback.primary_key + end - new_book = PrintedBook.last - assert_equal "Rails in Action", new_book.name + def test_does_not_dump_view_as_table + schema = dump_table_schema "paperbacks" + assert_no_match %r{create_table "paperbacks"}, schema + end end - def test_update_record_to_fail_view_conditions - book = PrintedBook.first - book.format = "ebook" - book.save! - - assert_raises ActiveRecord::RecordNotFound do - book.reload + # sqlite dose not support CREATE, INSERT, and DELETE for VIEW + if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter) + class UpdateableViewTest < ActiveRecord::TestCase + self.use_transactional_tests = false + fixtures :books + + class PrintedBook < ActiveRecord::Base + self.primary_key = "id" + end + + setup do + @connection = ActiveRecord::Base.connection + @connection.execute <<-SQL + CREATE VIEW printed_books + AS SELECT id, name, status, format FROM books WHERE format = 'paperback' + SQL + end + + teardown do + @connection.execute "DROP VIEW printed_books" if @connection.view_exists? "printed_books" + end + + def test_update_record + book = PrintedBook.first + book.name = "AWDwR" + book.save! + book.reload + assert_equal "AWDwR", book.name + end + + def test_insert_record + PrintedBook.create! name: "Rails in Action", status: 0, format: "paperback" + + new_book = PrintedBook.last + assert_equal "Rails in Action", new_book.name + end + + def test_update_record_to_fail_view_conditions + book = PrintedBook.first + book.format = "ebook" + book.save! + + assert_raises ActiveRecord::RecordNotFound do + book.reload + end + end end - end -end -end # end fo `if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)` + end # end fo `if current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter)` end # end fo `if ActiveRecord::Base.connection.supports_views?` if ActiveRecord::Base.connection.respond_to?(:supports_materialized_views?) && ActiveRecord::Base.connection.supports_materialized_views? -class MaterializedViewTest < ActiveRecord::PostgreSQLTestCase - include ViewBehavior + class MaterializedViewTest < ActiveRecord::PostgreSQLTestCase + include ViewBehavior - private - def create_view(name, query) - @connection.execute "CREATE MATERIALIZED VIEW #{name} AS #{query}" - end + private + def create_view(name, query) + @connection.execute "CREATE MATERIALIZED VIEW #{quote_table_name(name)} AS #{query}" + end - def drop_view(name) - @connection.execute "DROP MATERIALIZED VIEW #{name}" if @connection.view_exists? name + def drop_view(name) + @connection.execute "DROP MATERIALIZED VIEW #{quote_table_name(name)}" if @connection.view_exists? name + end end end -end diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb index d1c9a00786..5192e5050a 100644 --- a/activerecord/test/cases/yaml_serialization_test.rb +++ b/activerecord/test/cases/yaml_serialization_test.rb @@ -1,15 +1,15 @@ -require 'cases/helper' -require 'models/topic' -require 'models/reply' -require 'models/post' -require 'models/author' +require "cases/helper" +require "models/topic" +require "models/reply" +require "models/post" +require "models/author" class YamlSerializationTest < ActiveRecord::TestCase fixtures :topics, :authors, :posts def test_to_yaml_with_time_with_zone_should_not_raise_exception with_timezone_config aware_attributes: true, zone: "Pacific Time (US & Canada)" do - topic = Topic.new(:written_on => DateTime.now) + topic = Topic.new(written_on: DateTime.now) assert_nothing_raised { topic.to_yaml } end end @@ -22,8 +22,8 @@ class YamlSerializationTest < ActiveRecord::TestCase end def test_roundtrip_serialized_column - topic = Topic.new(:content => {:omg=>:lol}) - assert_equal({:omg=>:lol}, YAML.load(YAML.dump(topic)).content) + topic = Topic.new(content: { omg: :lol }) + assert_equal({ omg: :lol }, YAML.load(YAML.dump(topic)).content) end def test_psych_roundtrip @@ -67,16 +67,16 @@ class YamlSerializationTest < ActiveRecord::TestCase assert_not topic.new_record?, "Saved records are not new" assert_not YAML.load(YAML.dump(topic)).new_record?, "Saved record should not be new after deserialization" - topic = Topic.select('title').last + topic = Topic.select("title").last assert_not topic.new_record?, "Loaded records without ID are not new" assert_not YAML.load(YAML.dump(topic)).new_record?, "Record should not be new after deserialization" end def test_types_of_virtual_columns_are_not_changed_on_round_trip - author = Author.select('authors.*, count(posts.id) as posts_count') + author = Author.select("authors.*, count(posts.id) as posts_count") .joins(:posts) - .group('authors.id') + .group("authors.id") .first dumped = YAML.load(YAML.dump(author)) @@ -88,7 +88,7 @@ class YamlSerializationTest < ActiveRecord::TestCase coder = {} Topic.first.encode_with(coder) - assert coder['active_record_yaml_version'] + assert coder["active_record_yaml_version"] end def test_deserializing_rails_41_yaml @@ -121,11 +121,11 @@ class YamlSerializationTest < ActiveRecord::TestCase private - def yaml_fixture(file_name) - path = File.expand_path( - "../../support/yaml_compatibility_fixtures/#{file_name}.yml", - __FILE__ - ) - File.read(path) - end + def yaml_fixture(file_name) + path = File.expand_path( + "../../support/yaml_compatibility_fixtures/#{file_name}.yml", + __FILE__ + ) + File.read(path) + end end diff --git a/activerecord/test/fixtures/all/namespaced/accounts.yml b/activerecord/test/fixtures/all/namespaced/accounts.yml new file mode 100644 index 0000000000..9e341a15af --- /dev/null +++ b/activerecord/test/fixtures/all/namespaced/accounts.yml @@ -0,0 +1,2 @@ +signals37: + name: 37signals diff --git a/activerecord/test/fixtures/books.yml b/activerecord/test/fixtures/books.yml index a304fba399..b3625ee72e 100644 --- a/activerecord/test/fixtures/books.yml +++ b/activerecord/test/fixtures/books.yml @@ -9,6 +9,7 @@ awdr: author_visibility: :visible illustrator_visibility: :visible font_size: :medium + difficulty: :medium rfr: author_id: 1 diff --git a/activerecord/test/migrations/decimal/1_give_me_big_numbers.rb b/activerecord/test/migrations/decimal/1_give_me_big_numbers.rb index 549647de86..43c79bc20b 100644 --- a/activerecord/test/migrations/decimal/1_give_me_big_numbers.rb +++ b/activerecord/test/migrations/decimal/1_give_me_big_numbers.rb @@ -1,10 +1,10 @@ class GiveMeBigNumbers < ActiveRecord::Migration::Current def self.up create_table :big_numbers do |table| - table.column :bank_balance, :decimal, :precision => 10, :scale => 2 - table.column :big_bank_balance, :decimal, :precision => 15, :scale => 2 - table.column :world_population, :decimal, :precision => 10 - table.column :my_house_population, :decimal, :precision => 2 + table.column :bank_balance, :decimal, precision: 10, scale: 2 + table.column :big_bank_balance, :decimal, precision: 15, scale: 2 + table.column :world_population, :decimal, precision: 10 + table.column :my_house_population, :decimal, precision: 2 table.column :value_of_e, :decimal end end diff --git a/activerecord/test/migrations/magic/1_currencies_have_symbols.rb b/activerecord/test/migrations/magic/1_currencies_have_symbols.rb index 53b263bf55..d4b0e6cd95 100644 --- a/activerecord/test/migrations/magic/1_currencies_have_symbols.rb +++ b/activerecord/test/migrations/magic/1_currencies_have_symbols.rb @@ -2,8 +2,8 @@ class CurrenciesHaveSymbols < ActiveRecord::Migration::Current def self.up - # We use ¤ for default currency symbol - add_column "currencies", "symbol", :string, :default => "¤" + # We use € for default currency symbol + add_column "currencies", "symbol", :string, default: "€" end def self.down diff --git a/activerecord/test/migrations/missing/4_innocent_jointable.rb b/activerecord/test/migrations/missing/4_innocent_jointable.rb index 20fe183777..bd3bf21576 100644 --- a/activerecord/test/migrations/missing/4_innocent_jointable.rb +++ b/activerecord/test/migrations/missing/4_innocent_jointable.rb @@ -1,6 +1,6 @@ class InnocentJointable < ActiveRecord::Migration::Current def self.up - create_table("people_reminders", :id => false) do |t| + create_table("people_reminders", id: false) do |t| t.column :reminder_id, :integer t.column :person_id, :integer end diff --git a/activerecord/test/migrations/valid/3_innocent_jointable.rb b/activerecord/test/migrations/valid/3_innocent_jointable.rb index 20fe183777..bd3bf21576 100644 --- a/activerecord/test/migrations/valid/3_innocent_jointable.rb +++ b/activerecord/test/migrations/valid/3_innocent_jointable.rb @@ -1,6 +1,6 @@ class InnocentJointable < ActiveRecord::Migration::Current def self.up - create_table("people_reminders", :id => false) do |t| + create_table("people_reminders", id: false) do |t| t.column :reminder_id, :integer t.column :person_id, :integer end diff --git a/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb b/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb index 20fe183777..bd3bf21576 100644 --- a/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +++ b/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb @@ -1,6 +1,6 @@ class InnocentJointable < ActiveRecord::Migration::Current def self.up - create_table("people_reminders", :id => false) do |t| + create_table("people_reminders", id: false) do |t| t.column :reminder_id, :integer t.column :person_id, :integer end diff --git a/activerecord/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb b/activerecord/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb index bf934576c9..be24de6d70 100644 --- a/activerecord/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +++ b/activerecord/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb @@ -1,6 +1,6 @@ class ValidWithTimestampsInnocentJointable < ActiveRecord::Migration::Current def self.up - create_table("people_reminders", :id => false) do |t| + create_table("people_reminders", id: false) do |t| t.column :reminder_id, :integer t.column :person_id, :integer end diff --git a/activerecord/test/models/admin.rb b/activerecord/test/models/admin.rb index a38e3f4846..bc3ce23447 100644 --- a/activerecord/test/models/admin.rb +++ b/activerecord/test/models/admin.rb @@ -1,5 +1,5 @@ module Admin def self.table_name_prefix - 'admin_' + "admin_" end end diff --git a/activerecord/test/models/admin/user.rb b/activerecord/test/models/admin/user.rb index 48a110bd23..2e703f6219 100644 --- a/activerecord/test/models/admin/user.rb +++ b/activerecord/test/models/admin/user.rb @@ -15,26 +15,26 @@ class Admin::User < ActiveRecord::Base belongs_to :account store :params, accessors: [ :token ], coder: YAML - store :settings, :accessors => [ :color, :homepage ] + store :settings, accessors: [ :color, :homepage ] store_accessor :settings, :favorite_food - store :preferences, :accessors => [ :remember_login ] - store :json_data, :accessors => [ :height, :weight ], :coder => Coder.new - store :json_data_empty, :accessors => [ :is_a_good_guy ], :coder => Coder.new + store :preferences, accessors: [ :remember_login ] + store :json_data, accessors: [ :height, :weight ], coder: Coder.new + store :json_data_empty, accessors: [ :is_a_good_guy ], coder: Coder.new def phone_number read_store_attribute(:settings, :phone_number).gsub(/(\d{3})(\d{3})(\d{4})/,'(\1) \2-\3') end def phone_number=(value) - write_store_attribute(:settings, :phone_number, value && value.gsub(/[^\d]/,'')) + write_store_attribute(:settings, :phone_number, value && value.gsub(/[^\d]/,"")) end def color - super || 'red' + super || "red" end def color=(value) - value = 'blue' unless %w(black red green blue).include?(value) + value = "blue" unless %w(black red green blue).include?(value) super end end diff --git a/activerecord/test/models/aircraft.rb b/activerecord/test/models/aircraft.rb index c4404a8094..ebd42ff824 100644 --- a/activerecord/test/models/aircraft.rb +++ b/activerecord/test/models/aircraft.rb @@ -1,5 +1,5 @@ class Aircraft < ActiveRecord::Base self.pluralize_table_names = false - has_many :engines, :foreign_key => "car_id" + has_many :engines, foreign_key: "car_id" has_many :wheels, as: :wheelable end diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 38b983eda0..fab613afd1 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -2,145 +2,144 @@ class Author < ActiveRecord::Base has_many :posts has_many :serialized_posts has_one :post - has_many :very_special_comments, :through => :posts - has_many :posts_with_comments, -> { includes(:comments) }, :class_name => "Post" - has_many :popular_grouped_posts, -> { includes(:comments).group("type").having("SUM(comments_count) > 1").select("type") }, :class_name => "Post" - has_many :posts_with_comments_sorted_by_comment_id, -> { includes(:comments).order('comments.id') }, :class_name => "Post" - has_many :posts_sorted_by_id_limited, -> { order('posts.id').limit(1) }, :class_name => "Post" - has_many :posts_with_categories, -> { includes(:categories) }, :class_name => "Post" - has_many :posts_with_comments_and_categories, -> { includes(:comments, :categories).order("posts.id") }, :class_name => "Post" - has_many :posts_with_special_categorizations, :class_name => 'PostWithSpecialCategorization' - has_one :post_about_thinking, -> { where("posts.title like '%thinking%'") }, :class_name => 'Post' - has_one :post_about_thinking_with_last_comment, -> { where("posts.title like '%thinking%'").includes(:last_comment) }, :class_name => 'Post' + has_many :very_special_comments, through: :posts + has_many :posts_with_comments, -> { includes(:comments) }, class_name: "Post" + has_many :popular_grouped_posts, -> { includes(:comments).group("type").having("SUM(comments_count) > 1").select("type") }, class_name: "Post" + has_many :posts_with_comments_sorted_by_comment_id, -> { includes(:comments).order("comments.id") }, class_name: "Post" + has_many :posts_sorted_by_id_limited, -> { order("posts.id").limit(1) }, class_name: "Post" + has_many :posts_with_categories, -> { includes(:categories) }, class_name: "Post" + has_many :posts_with_comments_and_categories, -> { includes(:comments, :categories).order("posts.id") }, class_name: "Post" + has_many :posts_with_special_categorizations, class_name: "PostWithSpecialCategorization" + has_one :post_about_thinking, -> { where("posts.title like '%thinking%'") }, class_name: "Post" + has_one :post_about_thinking_with_last_comment, -> { where("posts.title like '%thinking%'").includes(:last_comment) }, class_name: "Post" has_many :comments, through: :posts do def ratings Rating.joins(:comment).merge(self) end end - has_many :comments_containing_the_letter_e, :through => :posts, :source => :comments - has_many :comments_with_order_and_conditions, -> { order('comments.body').where("comments.body like 'Thank%'") }, :through => :posts, :source => :comments - has_many :comments_with_include, -> { includes(:post) }, :through => :posts, :source => :comments + has_many :comments_containing_the_letter_e, through: :posts, source: :comments + has_many :comments_with_order_and_conditions, -> { order("comments.body").where("comments.body like 'Thank%'") }, through: :posts, source: :comments + has_many :comments_with_include, -> { includes(:post) }, through: :posts, source: :comments has_many :first_posts - has_many :comments_on_first_posts, -> { order('posts.id desc, comments.id asc') }, :through => :first_posts, :source => :comments + has_many :comments_on_first_posts, -> { order("posts.id desc, comments.id asc") }, through: :first_posts, source: :comments has_one :first_post - has_one :comment_on_first_post, -> { order('posts.id desc, comments.id asc') }, :through => :first_post, :source => :comments + has_one :comment_on_first_post, -> { order("posts.id desc, comments.id asc") }, through: :first_post, source: :comments - has_many :thinking_posts, -> { where(:title => 'So I was thinking') }, :dependent => :delete_all, :class_name => 'Post' - has_many :welcome_posts, -> { where(:title => 'Welcome to the weblog') }, :class_name => 'Post' + has_many :thinking_posts, -> { where(title: "So I was thinking") }, dependent: :delete_all, class_name: "Post" + has_many :welcome_posts, -> { where(title: "Welcome to the weblog") }, class_name: "Post" has_many :welcome_posts_with_one_comment, - -> { where(title: 'Welcome to the weblog').where('comments_count = ?', 1) }, - class_name: 'Post' + -> { where(title: "Welcome to the weblog").where("comments_count = ?", 1) }, + class_name: "Post" has_many :welcome_posts_with_comments, - -> { where(title: 'Welcome to the weblog').where(Post.arel_table[:comments_count].gt(0)) }, - class_name: 'Post' + -> { where(title: "Welcome to the weblog").where(Post.arel_table[:comments_count].gt(0)) }, + class_name: "Post" - has_many :comments_desc, -> { order('comments.id DESC') }, :through => :posts, :source => :comments - has_many :funky_comments, :through => :posts, :source => :comments - has_many :ordered_uniq_comments, -> { distinct.order('comments.id') }, :through => :posts, :source => :comments - has_many :ordered_uniq_comments_desc, -> { distinct.order('comments.id DESC') }, :through => :posts, :source => :comments - has_many :readonly_comments, -> { readonly }, :through => :posts, :source => :comments + has_many :comments_desc, -> { order("comments.id DESC") }, through: :posts, source: :comments + has_many :funky_comments, through: :posts, source: :comments + has_many :ordered_uniq_comments, -> { distinct.order("comments.id") }, through: :posts, source: :comments + has_many :ordered_uniq_comments_desc, -> { distinct.order("comments.id DESC") }, through: :posts, source: :comments + has_many :readonly_comments, -> { readonly }, through: :posts, source: :comments has_many :special_posts - has_many :special_post_comments, :through => :special_posts, :source => :comments - has_many :special_posts_with_default_scope, :class_name => 'SpecialPostWithDefaultScope' - - has_many :sti_posts, :class_name => 'StiPost' - has_many :sti_post_comments, :through => :sti_posts, :source => :comments - - has_many :special_nonexistent_posts, -> { where("posts.body = 'nonexistent'") }, :class_name => "SpecialPost" - has_many :special_nonexistent_post_comments, -> { where('comments.post_id' => 0) }, :through => :special_nonexistent_posts, :source => :comments - has_many :nonexistent_comments, :through => :posts - - has_many :hello_posts, -> { where "posts.body = 'hello'" }, :class_name => "Post" - has_many :hello_post_comments, :through => :hello_posts, :source => :comments - has_many :posts_with_no_comments, -> { where('comments.id' => nil).includes(:comments) }, :class_name => 'Post' - - has_many :hello_posts_with_hash_conditions, -> { where(:body => 'hello') }, :class_name => "Post" - has_many :hello_post_comments_with_hash_conditions, :through => -:hello_posts_with_hash_conditions, :source => :comments - - has_many :other_posts, :class_name => "Post" - has_many :posts_with_callbacks, :class_name => "Post", :before_add => :log_before_adding, - :after_add => :log_after_adding, - :before_remove => :log_before_removing, - :after_remove => :log_after_removing - has_many :posts_with_proc_callbacks, :class_name => "Post", - :before_add => Proc.new {|o, r| o.post_log << "before_adding#{r.id || '<new>'}"}, - :after_add => Proc.new {|o, r| o.post_log << "after_adding#{r.id || '<new>'}"}, - :before_remove => Proc.new {|o, r| o.post_log << "before_removing#{r.id}"}, - :after_remove => Proc.new {|o, r| o.post_log << "after_removing#{r.id}"} - has_many :posts_with_multiple_callbacks, :class_name => "Post", - :before_add => [:log_before_adding, Proc.new {|o, r| o.post_log << "before_adding_proc#{r.id || '<new>'}"}], - :after_add => [:log_after_adding, Proc.new {|o, r| o.post_log << "after_adding_proc#{r.id || '<new>'}"}] - has_many :unchangeable_posts, :class_name => "Post", :before_add => :raise_exception, :after_add => :log_after_adding + has_many :special_post_comments, through: :special_posts, source: :comments + has_many :special_posts_with_default_scope, class_name: "SpecialPostWithDefaultScope" + + has_many :sti_posts, class_name: "StiPost" + has_many :sti_post_comments, through: :sti_posts, source: :comments + + has_many :special_nonexistent_posts, -> { where("posts.body = 'nonexistent'") }, class_name: "SpecialPost" + has_many :special_nonexistent_post_comments, -> { where("comments.post_id" => 0) }, through: :special_nonexistent_posts, source: :comments + has_many :nonexistent_comments, through: :posts + + has_many :hello_posts, -> { where "posts.body = 'hello'" }, class_name: "Post" + has_many :hello_post_comments, through: :hello_posts, source: :comments + has_many :posts_with_no_comments, -> { where("comments.id" => nil).includes(:comments) }, class_name: "Post" + + has_many :hello_posts_with_hash_conditions, -> { where(body: "hello") }, class_name: "Post" + has_many :hello_post_comments_with_hash_conditions, through: :hello_posts_with_hash_conditions, source: :comments + + has_many :other_posts, class_name: "Post" + has_many :posts_with_callbacks, class_name: "Post", before_add: :log_before_adding, + after_add: :log_after_adding, + before_remove: :log_before_removing, + after_remove: :log_after_removing + has_many :posts_with_proc_callbacks, class_name: "Post", + before_add: Proc.new { |o, r| o.post_log << "before_adding#{r.id || '<new>'}" }, + after_add: Proc.new { |o, r| o.post_log << "after_adding#{r.id || '<new>'}" }, + before_remove: Proc.new { |o, r| o.post_log << "before_removing#{r.id}" }, + after_remove: Proc.new { |o, r| o.post_log << "after_removing#{r.id}" } + has_many :posts_with_multiple_callbacks, class_name: "Post", + before_add: [:log_before_adding, Proc.new { |o, r| o.post_log << "before_adding_proc#{r.id || '<new>'}" }], + after_add: [:log_after_adding, Proc.new { |o, r| o.post_log << "after_adding_proc#{r.id || '<new>'}" }] + has_many :unchangeable_posts, class_name: "Post", before_add: :raise_exception, after_add: :log_after_adding has_many :categorizations - has_many :categories, :through => :categorizations - has_many :named_categories, :through => :categorizations + has_many :categories, through: :categorizations + has_many :named_categories, through: :categorizations has_many :special_categorizations - has_many :special_categories, :through => :special_categorizations, :source => :category - has_one :special_category, :through => :special_categorizations, :source => :category + has_many :special_categories, through: :special_categorizations, source: :category + has_one :special_category, through: :special_categorizations, source: :category - has_many :categories_like_general, -> { where(:name => 'General') }, :through => :categorizations, :source => :category, :class_name => 'Category' + has_many :categories_like_general, -> { where(name: "General") }, through: :categorizations, source: :category, class_name: "Category" - has_many :categorized_posts, :through => :categorizations, :source => :post - has_many :unique_categorized_posts, -> { distinct }, :through => :categorizations, :source => :post + has_many :categorized_posts, through: :categorizations, source: :post + has_many :unique_categorized_posts, -> { distinct }, through: :categorizations, source: :post - has_many :nothings, :through => :kateggorisatons, :class_name => 'Category' + has_many :nothings, through: :kateggorisatons, class_name: "Category" has_many :author_favorites - has_many :favorite_authors, -> { order('name') }, :through => :author_favorites + has_many :favorite_authors, -> { order("name") }, through: :author_favorites - has_many :taggings, :through => :posts, :source => :taggings - has_many :taggings_2, :through => :posts, :source => :tagging - has_many :tags, :through => :posts - has_many :post_categories, :through => :posts, :source => :categories - has_many :tagging_tags, :through => :taggings, :source => :tag + has_many :taggings, through: :posts, source: :taggings + has_many :taggings_2, through: :posts, source: :tagging + has_many :tags, through: :posts + has_many :post_categories, through: :posts, source: :categories + has_many :tagging_tags, through: :taggings, source: :tag - has_many :similar_posts, -> { distinct }, :through => :tags, :source => :tagged_posts - has_many :distinct_tags, -> { select("DISTINCT tags.*").order("tags.name") }, :through => :posts, :source => :tags + has_many :similar_posts, -> { distinct }, through: :tags, source: :tagged_posts + has_many :distinct_tags, -> { select("DISTINCT tags.*").order("tags.name") }, through: :posts, source: :tags - has_many :tags_with_primary_key, :through => :posts + has_many :tags_with_primary_key, through: :posts has_many :books - has_many :subscriptions, :through => :books - has_many :subscribers, -> { order("subscribers.nick") }, :through => :subscriptions - has_many :distinct_subscribers, -> { select("DISTINCT subscribers.*").order("subscribers.nick") }, :through => :subscriptions, :source => :subscriber + has_many :subscriptions, through: :books + has_many :subscribers, -> { order("subscribers.nick") }, through: :subscriptions + has_many :distinct_subscribers, -> { select("DISTINCT subscribers.*").order("subscribers.nick") }, through: :subscriptions, source: :subscriber - has_one :essay, :primary_key => :name, :as => :writer - has_one :essay_category, :through => :essay, :source => :category - has_one :essay_owner, :through => :essay, :source => :owner + has_one :essay, primary_key: :name, as: :writer + has_one :essay_category, through: :essay, source: :category + has_one :essay_owner, through: :essay, source: :owner - has_one :essay_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id - has_one :essay_category_2, :through => :essay_2, :source => :category + has_one :essay_2, primary_key: :name, class_name: "Essay", foreign_key: :author_id + has_one :essay_category_2, through: :essay_2, source: :category - has_many :essays, :primary_key => :name, :as => :writer - has_many :essay_categories, :through => :essays, :source => :category - has_many :essay_owners, :through => :essays, :source => :owner + has_many :essays, primary_key: :name, as: :writer + has_many :essay_categories, through: :essays, source: :category + has_many :essay_owners, through: :essays, source: :owner - has_many :essays_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id - has_many :essay_categories_2, :through => :essays_2, :source => :category + has_many :essays_2, primary_key: :name, class_name: "Essay", foreign_key: :author_id + has_many :essay_categories_2, through: :essays_2, source: :category - belongs_to :owned_essay, :primary_key => :name, :class_name => 'Essay' - has_one :owned_essay_category, :through => :owned_essay, :source => :category + belongs_to :owned_essay, primary_key: :name, class_name: "Essay" + has_one :owned_essay_category, through: :owned_essay, source: :category - belongs_to :author_address, :dependent => :destroy - belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" + belongs_to :author_address, dependent: :destroy + belongs_to :author_address_extra, dependent: :delete, class_name: "AuthorAddress" - has_many :category_post_comments, :through => :categories, :source => :post_comments + has_many :category_post_comments, through: :categories, source: :post_comments - has_many :misc_posts, -> { where(:posts => { :title => ['misc post by bob', 'misc post by mary'] }) }, :class_name => 'Post' - has_many :misc_post_first_blue_tags, :through => :misc_posts, :source => :first_blue_tags + has_many :misc_posts, -> { where(posts: { title: ["misc post by bob", "misc post by mary"] }) }, class_name: "Post" + has_many :misc_post_first_blue_tags, through: :misc_posts, source: :first_blue_tags - has_many :misc_post_first_blue_tags_2, -> { where(:posts => { :title => ['misc post by bob', 'misc post by mary'] }) }, - :through => :posts, :source => :first_blue_tags_2 + has_many :misc_post_first_blue_tags_2, -> { where(posts: { title: ["misc post by bob", "misc post by mary"] }) }, + through: :posts, source: :first_blue_tags_2 - has_many :posts_with_default_include, :class_name => 'PostWithDefaultInclude' - has_many :comments_on_posts_with_default_include, :through => :posts_with_default_include, :source => :comments + has_many :posts_with_default_include, class_name: "PostWithDefaultInclude" + has_many :comments_on_posts_with_default_include, through: :posts_with_default_include, source: :comments has_many :posts_with_signature, ->(record) { where("posts.title LIKE ?", "%by #{record.name.downcase}%") }, class_name: "Post" @@ -205,5 +204,5 @@ end class AuthorFavorite < ActiveRecord::Base belongs_to :author - belongs_to :favorite_author, :class_name => "Author" + belongs_to :favorite_author, class_name: "Author" end diff --git a/activerecord/test/models/bird.rb b/activerecord/test/models/bird.rb index 2a51d903b8..24b839135d 100644 --- a/activerecord/test/models/bird.rb +++ b/activerecord/test/models/bird.rb @@ -5,7 +5,7 @@ class Bird < ActiveRecord::Base accepts_nested_attributes_for :pirate attr_accessor :cancel_save_from_callback - before_save :cancel_save_callback_method, :if => :cancel_save_from_callback + before_save :cancel_save_callback_method, if: :cancel_save_from_callback def cancel_save_callback_method throw(:abort) end diff --git a/activerecord/test/models/book.rb b/activerecord/test/models/book.rb index e43e5c3901..17bf3fbcb4 100644 --- a/activerecord/test/models/book.rb +++ b/activerecord/test/models/book.rb @@ -1,20 +1,21 @@ class Book < ActiveRecord::Base has_many :authors - has_many :citations, :foreign_key => 'book1_id' + has_many :citations, foreign_key: "book1_id" has_many :references, -> { distinct }, through: :citations, source: :reference_of has_many :subscriptions has_many :subscribers, through: :subscriptions enum status: [:proposed, :written, :published] - enum read_status: {unread: 0, reading: 2, read: 3} + enum read_status: { unread: 0, reading: 2, read: 3 } enum nullable_status: [:single, :married] enum language: [:english, :spanish, :french], _prefix: :in enum author_visibility: [:visible, :invisible], _prefix: true enum illustrator_visibility: [:visible, :invisible], _prefix: true enum font_size: [:small, :medium, :large], _prefix: :with, _suffix: true - enum cover: { hard: 'hard', soft: 'soft' } + enum difficulty: [:easy, :medium, :hard], _suffix: :to_read + enum cover: { hard: "hard", soft: "soft" } def published! super diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb index dc0296305a..113d21cb84 100644 --- a/activerecord/test/models/bulb.rb +++ b/activerecord/test/models/bulb.rb @@ -1,6 +1,6 @@ class Bulb < ActiveRecord::Base - default_scope { where(:name => 'defaulty') } - belongs_to :car, :touch => true + default_scope { where(name: "defaulty") } + belongs_to :car, touch: true scope :awesome, -> { where(frickinawesome: true) } attr_reader :scope_after_initialize, :attributes_after_initialize @@ -35,7 +35,7 @@ class CustomBulb < Bulb after_initialize :set_awesomeness def set_awesomeness - self.frickinawesome = true if name == 'Dude' + self.frickinawesome = true if name == "Dude" end end @@ -50,9 +50,3 @@ class FailedBulb < Bulb throw(:abort) end end - -class TrickyBulb < Bulb - after_create do |record| - record.car.bulbs.to_a - end -end diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb index 0f37e9a289..92bff7ff96 100644 --- a/activerecord/test/models/car.rb +++ b/activerecord/test/models/car.rb @@ -1,29 +1,29 @@ class Car < ActiveRecord::Base has_many :bulbs has_many :all_bulbs, -> { unscope where: :name }, class_name: "Bulb" - has_many :funky_bulbs, class_name: 'FunkyBulb', dependent: :destroy - has_many :failed_bulbs, class_name: 'FailedBulb', dependent: :destroy - has_many :foo_bulbs, -> { where(:name => 'foo') }, :class_name => "Bulb" + has_many :funky_bulbs, class_name: "FunkyBulb", dependent: :destroy + has_many :failed_bulbs, class_name: "FailedBulb", dependent: :destroy + has_many :foo_bulbs, -> { where(name: "foo") }, class_name: "Bulb" has_many :awesome_bulbs, -> { awesome }, class_name: "Bulb" has_one :bulb has_many :tyres - has_many :engines, :dependent => :destroy, inverse_of: :my_car - has_many :wheels, :as => :wheelable, :dependent => :destroy + has_many :engines, dependent: :destroy, inverse_of: :my_car + has_many :wheels, as: :wheelable, dependent: :destroy - has_many :price_estimates, :as => :estimate_of + has_many :price_estimates, as: :estimate_of scope :incl_tyres, -> { includes(:tyres) } scope :incl_engines, -> { includes(:engines) } - scope :order_using_new_style, -> { order('name asc') } + scope :order_using_new_style, -> { order("name asc") } end class CoolCar < Car - default_scope { order('name desc') } + default_scope { order("name desc") } end class FastCar < Car - default_scope { order('name desc') } + default_scope { order("name desc") } end diff --git a/activerecord/test/models/categorization.rb b/activerecord/test/models/categorization.rb index 4cd67c970a..b99383d0b1 100644 --- a/activerecord/test/models/categorization.rb +++ b/activerecord/test/models/categorization.rb @@ -1,18 +1,18 @@ class Categorization < ActiveRecord::Base belongs_to :post belongs_to :category, counter_cache: true - belongs_to :named_category, :class_name => 'Category', :foreign_key => :named_category_name, :primary_key => :name + belongs_to :named_category, class_name: "Category", foreign_key: :named_category_name, primary_key: :name belongs_to :author - has_many :post_taggings, :through => :author, :source => :taggings + has_many :post_taggings, through: :author, source: :taggings - belongs_to :author_using_custom_pk, :class_name => 'Author', :foreign_key => :author_id, :primary_key => :author_address_extra_id - has_many :authors_using_custom_pk, :class_name => 'Author', :foreign_key => :id, :primary_key => :category_id + belongs_to :author_using_custom_pk, class_name: "Author", foreign_key: :author_id, primary_key: :author_address_extra_id + has_many :authors_using_custom_pk, class_name: "Author", foreign_key: :id, primary_key: :category_id end class SpecialCategorization < ActiveRecord::Base - self.table_name = 'categorizations' - default_scope { where(:special => true) } + self.table_name = "categorizations" + default_scope { where(special: true) } belongs_to :author belongs_to :category diff --git a/activerecord/test/models/category.rb b/activerecord/test/models/category.rb index 272223e1d8..e8654dca01 100644 --- a/activerecord/test/models/category.rb +++ b/activerecord/test/models/category.rb @@ -1,34 +1,34 @@ class Category < ActiveRecord::Base has_and_belongs_to_many :posts - has_and_belongs_to_many :special_posts, :class_name => "Post" - has_and_belongs_to_many :other_posts, :class_name => "Post" - has_and_belongs_to_many :posts_with_authors_sorted_by_author_id, -> { includes(:authors).order("authors.id") }, :class_name => "Post" + has_and_belongs_to_many :special_posts, class_name: "Post" + has_and_belongs_to_many :other_posts, class_name: "Post" + has_and_belongs_to_many :posts_with_authors_sorted_by_author_id, -> { includes(:authors).order("authors.id") }, class_name: "Post" has_and_belongs_to_many :select_testing_posts, - -> { select 'posts.*, 1 as correctness_marker' }, - :class_name => 'Post', - :foreign_key => 'category_id', - :association_foreign_key => 'post_id' + -> { select "posts.*, 1 as correctness_marker" }, + class_name: "Post", + foreign_key: "category_id", + association_foreign_key: "post_id" has_and_belongs_to_many :post_with_conditions, - -> { where :title => 'Yet Another Testing Title' }, - :class_name => 'Post' + -> { where title: "Yet Another Testing Title" }, + class_name: "Post" - has_and_belongs_to_many :popular_grouped_posts, -> { group("posts.type").having("sum(comments.post_id) > 2").includes(:comments) }, :class_name => "Post" - has_and_belongs_to_many :posts_grouped_by_title, -> { group("title").select("title") }, :class_name => "Post" + has_and_belongs_to_many :popular_grouped_posts, -> { group("posts.type").having("sum(comments.post_id) > 2").includes(:comments) }, class_name: "Post" + has_and_belongs_to_many :posts_grouped_by_title, -> { group("title").select("title") }, class_name: "Post" def self.what_are_you - 'a category...' + "a category..." end has_many :categorizations has_many :special_categorizations - has_many :post_comments, :through => :posts, :source => :comments + has_many :post_comments, through: :posts, source: :comments - has_many :authors, :through => :categorizations - has_many :authors_with_select, -> { select 'authors.*, categorizations.post_id' }, :through => :categorizations, :source => :author + has_many :authors, through: :categorizations + has_many :authors_with_select, -> { select "authors.*, categorizations.post_id" }, through: :categorizations, source: :author - scope :general, -> { where(:name => 'General') } + scope :general, -> { where(name: "General") } end class SpecialCategory < Category diff --git a/activerecord/test/models/citation.rb b/activerecord/test/models/citation.rb index 3d87eb795c..7d06387f56 100644 --- a/activerecord/test/models/citation.rb +++ b/activerecord/test/models/citation.rb @@ -1,3 +1,3 @@ class Citation < ActiveRecord::Base - belongs_to :reference_of, :class_name => "Book", :foreign_key => :book2_id + belongs_to :reference_of, class_name: "Book", foreign_key: :book2_id end diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb index 6ceafe5858..49d7b24a3b 100644 --- a/activerecord/test/models/club.rb +++ b/activerecord/test/models/club.rb @@ -1,23 +1,23 @@ class Club < ActiveRecord::Base has_one :membership - has_many :memberships, :inverse_of => false - has_many :members, :through => :memberships + has_many :memberships, inverse_of: false + has_many :members, through: :memberships has_one :sponsor - has_one :sponsored_member, :through => :sponsor, :source => :sponsorable, :source_type => "Member" + has_one :sponsored_member, through: :sponsor, source: :sponsorable, source_type: "Member" belongs_to :category has_many :favourites, -> { where(memberships: { favourite: true }) }, through: :memberships, source: :member private - def private_method - "I'm sorry sir, this is a *private* club, not a *pirate* club" - end + def private_method + "I'm sorry sir, this is a *private* club, not a *pirate* club" + end end class SuperClub < ActiveRecord::Base self.table_name = "clubs" - has_many :memberships, class_name: 'SuperMembership', foreign_key: 'club_id' + has_many :memberships, class_name: "SuperMembership", foreign_key: "club_id" has_many :members, through: :memberships end diff --git a/activerecord/test/models/college.rb b/activerecord/test/models/college.rb index 501af4a8dd..c9dbe1ecc2 100644 --- a/activerecord/test/models/college.rb +++ b/activerecord/test/models/college.rb @@ -1,5 +1,5 @@ -require_dependency 'models/arunit2_model' -require 'active_support/core_ext/object/with_options' +require_dependency "models/arunit2_model" +require "active_support/core_ext/object/with_options" class College < ARUnit2Model has_many :courses diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb index dcc5c5a310..a4b81d56e0 100644 --- a/activerecord/test/models/comment.rb +++ b/activerecord/test/models/comment.rb @@ -1,26 +1,26 @@ class Comment < ActiveRecord::Base - scope :limit_by, lambda {|l| limit(l) } + scope :limit_by, lambda { |l| limit(l) } scope :containing_the_letter_e, -> { where("comments.body LIKE '%e%'") } scope :not_again, -> { where("comments.body NOT LIKE '%again%'") } - scope :for_first_post, -> { where(:post_id => 1) } + scope :for_first_post, -> { where(post_id: 1) } scope :for_first_author, -> { joins(:post).where("posts.author_id" => 1) } scope :created, -> { all } - belongs_to :post, :counter_cache => true + belongs_to :post, counter_cache: true belongs_to :author, polymorphic: true belongs_to :resource, polymorphic: true belongs_to :developer has_many :ratings - belongs_to :first_post, :foreign_key => :post_id + belongs_to :first_post, foreign_key: :post_id belongs_to :special_post_with_default_scope, foreign_key: :post_id - has_many :children, :class_name => 'Comment', :foreign_key => :parent_id - belongs_to :parent, :class_name => 'Comment', :counter_cache => :children_count + has_many :children, class_name: "Comment", foreign_key: :parent_id + belongs_to :parent, class_name: "Comment", counter_cache: :children_count def self.what_are_you - 'a comment...' + "a comment..." end def self.search_by_type(q) @@ -55,6 +55,6 @@ class CommentThatAutomaticallyAltersPostBody < Comment end class CommentWithDefaultScopeReferencesAssociation < Comment - default_scope ->{ includes(:developer).order('developers.name').references(:developer) } + default_scope -> { includes(:developer).order("developers.name").references(:developer) } belongs_to :developer end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 1dcd9fc21e..025630087c 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -7,13 +7,13 @@ class Company < AbstractCompany validates_presence_of :name - has_one :dummy_account, :foreign_key => "firm_id", :class_name => "Account" + has_one :dummy_account, foreign_key: "firm_id", class_name: "Account" has_many :contracts - has_many :developers, :through => :contracts + has_many :developers, through: :contracts scope :of_first_firm, lambda { - joins(:account => :firm). - where('firms.id' => 1) + joins(account: :firm). + where("firms.id" => 1) } def arbitrary_method @@ -22,12 +22,12 @@ class Company < AbstractCompany private - def private_method - "I am Jack's innermost fears and aspirations" - end + def private_method + "I am Jack's innermost fears and aspirations" + end - class SpecialCo < Company - end + class SpecialCo < Company + end end module Namespaced @@ -35,7 +35,7 @@ module Namespaced end class Firm < ::Company - has_many :clients, :class_name => 'Namespaced::Client' + has_many :clients, class_name: "Namespaced::Client" end class Client < ::Company @@ -45,45 +45,45 @@ end class Firm < Company to_param :name - has_many :clients, -> { order "id" }, :dependent => :destroy, :before_remove => :log_before_remove, :after_remove => :log_after_remove - has_many :unsorted_clients, :class_name => "Client" - has_many :unsorted_clients_with_symbol, :class_name => :Client - has_many :clients_sorted_desc, -> { order "id DESC" }, :class_name => "Client" - has_many :clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client", :inverse_of => :firm - has_many :clients_ordered_by_name, -> { order "name" }, :class_name => "Client" - has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false - has_many :dependent_clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client", :dependent => :destroy - has_many :exclusively_dependent_clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client", :dependent => :delete_all - has_many :limited_clients, -> { limit 1 }, :class_name => "Client" - has_many :clients_with_interpolated_conditions, ->(firm) { where "rating > #{firm.rating}" }, :class_name => "Client" - has_many :clients_like_ms, -> { where("name = 'Microsoft'").order("id") }, :class_name => "Client" - has_many :clients_like_ms_with_hash_conditions, -> { where(:name => 'Microsoft').order("id") }, :class_name => "Client" - has_many :plain_clients, :class_name => 'Client' - has_many :clients_using_primary_key, :class_name => 'Client', - :primary_key => 'name', :foreign_key => 'firm_name' - has_many :clients_using_primary_key_with_delete_all, :class_name => 'Client', - :primary_key => 'name', :foreign_key => 'firm_name', :dependent => :delete_all - has_many :clients_grouped_by_firm_id, -> { group("firm_id").select("firm_id") }, :class_name => "Client" - has_many :clients_grouped_by_name, -> { group("name").select("name") }, :class_name => "Client" - - has_one :account, :foreign_key => "firm_id", :dependent => :destroy, :validate => true - has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false - has_one :account_with_select, -> { select("id, firm_id") }, :foreign_key => "firm_id", :class_name=>'Account' - has_one :readonly_account, -> { readonly }, :foreign_key => "firm_id", :class_name => "Account" + has_many :clients, -> { order "id" }, dependent: :destroy, before_remove: :log_before_remove, after_remove: :log_after_remove + has_many :unsorted_clients, class_name: "Client" + has_many :unsorted_clients_with_symbol, class_name: :Client + has_many :clients_sorted_desc, -> { order "id DESC" }, class_name: "Client" + has_many :clients_of_firm, -> { order "id" }, foreign_key: "client_of", class_name: "Client", inverse_of: :firm + has_many :clients_ordered_by_name, -> { order "name" }, class_name: "Client" + has_many :unvalidated_clients_of_firm, foreign_key: "client_of", class_name: "Client", validate: false + has_many :dependent_clients_of_firm, -> { order "id" }, foreign_key: "client_of", class_name: "Client", dependent: :destroy + has_many :exclusively_dependent_clients_of_firm, -> { order "id" }, foreign_key: "client_of", class_name: "Client", dependent: :delete_all + has_many :limited_clients, -> { limit 1 }, class_name: "Client" + has_many :clients_with_interpolated_conditions, ->(firm) { where "rating > #{firm.rating}" }, class_name: "Client" + has_many :clients_like_ms, -> { where("name = 'Microsoft'").order("id") }, class_name: "Client" + has_many :clients_like_ms_with_hash_conditions, -> { where(name: "Microsoft").order("id") }, class_name: "Client" + has_many :plain_clients, class_name: "Client" + has_many :clients_using_primary_key, class_name: "Client", + primary_key: "name", foreign_key: "firm_name" + has_many :clients_using_primary_key_with_delete_all, class_name: "Client", + primary_key: "name", foreign_key: "firm_name", dependent: :delete_all + has_many :clients_grouped_by_firm_id, -> { group("firm_id").select("firm_id") }, class_name: "Client" + has_many :clients_grouped_by_name, -> { group("name").select("name") }, class_name: "Client" + + has_one :account, foreign_key: "firm_id", dependent: :destroy, validate: true + has_one :unvalidated_account, foreign_key: "firm_id", class_name: "Account", validate: false + has_one :account_with_select, -> { select("id, firm_id") }, foreign_key: "firm_id", class_name: "Account" + has_one :readonly_account, -> { readonly }, foreign_key: "firm_id", class_name: "Account" # added order by id as in fixtures there are two accounts for Rails Core # Oracle tests were failing because of that as the second fixture was selected - has_one :account_using_primary_key, -> { order('id') }, :primary_key => "firm_id", :class_name => "Account" - has_one :account_using_foreign_and_primary_keys, :foreign_key => "firm_name", :primary_key => "name", :class_name => "Account" - has_one :account_with_inexistent_foreign_key, class_name: 'Account', foreign_key: "inexistent" - has_one :deletable_account, :foreign_key => "firm_id", :class_name => "Account", :dependent => :delete + has_one :account_using_primary_key, -> { order("id") }, primary_key: "firm_id", class_name: "Account" + has_one :account_using_foreign_and_primary_keys, foreign_key: "firm_name", primary_key: "name", class_name: "Account" + has_one :account_with_inexistent_foreign_key, class_name: "Account", foreign_key: "inexistent" + has_one :deletable_account, foreign_key: "firm_id", class_name: "Account", dependent: :delete - has_one :account_limit_500_with_hash_conditions, -> { where :credit_limit => 500 }, :foreign_key => "firm_id", :class_name => "Account" + has_one :account_limit_500_with_hash_conditions, -> { where credit_limit: 500 }, foreign_key: "firm_id", class_name: "Account" - has_one :unautosaved_account, :foreign_key => "firm_id", :class_name => 'Account', :autosave => false + has_one :unautosaved_account, foreign_key: "firm_id", class_name: "Account", autosave: false has_many :accounts - has_many :unautosaved_accounts, :foreign_key => "firm_id", :class_name => 'Account', :autosave => false + has_many :unautosaved_accounts, foreign_key: "firm_id", class_name: "Account", autosave: false - has_many :association_with_references, -> { references(:foo) }, :class_name => 'Client' + has_many :association_with_references, -> { references(:foo) }, class_name: "Client" has_one :lead_developer, class_name: "Developer" has_many :projects @@ -103,32 +103,32 @@ class Firm < Company end class DependentFirm < Company - has_one :account, :foreign_key => "firm_id", :dependent => :nullify - has_many :companies, :foreign_key => 'client_of', :dependent => :nullify - has_one :company, :foreign_key => 'client_of', :dependent => :nullify + has_one :account, foreign_key: "firm_id", dependent: :nullify + has_many :companies, foreign_key: "client_of", dependent: :nullify + has_one :company, foreign_key: "client_of", dependent: :nullify end class RestrictedWithExceptionFirm < Company - has_one :account, -> { order("id") }, :foreign_key => "firm_id", :dependent => :restrict_with_exception - has_many :companies, -> { order("id") }, :foreign_key => 'client_of', :dependent => :restrict_with_exception + has_one :account, -> { order("id") }, foreign_key: "firm_id", dependent: :restrict_with_exception + has_many :companies, -> { order("id") }, foreign_key: "client_of", dependent: :restrict_with_exception end class RestrictedWithErrorFirm < Company - has_one :account, -> { order("id") }, :foreign_key => "firm_id", :dependent => :restrict_with_error - has_many :companies, -> { order("id") }, :foreign_key => 'client_of', :dependent => :restrict_with_error + has_one :account, -> { order("id") }, foreign_key: "firm_id", dependent: :restrict_with_error + has_many :companies, -> { order("id") }, foreign_key: "client_of", dependent: :restrict_with_error end class Client < Company - belongs_to :firm, :foreign_key => "client_of" - belongs_to :firm_with_basic_id, :class_name => "Firm", :foreign_key => "firm_id" - belongs_to :firm_with_select, -> { select("id") }, :class_name => "Firm", :foreign_key => "firm_id" - belongs_to :firm_with_other_name, :class_name => "Firm", :foreign_key => "client_of" - belongs_to :firm_with_condition, -> { where "1 = ?", 1 }, :class_name => "Firm", :foreign_key => "client_of" - belongs_to :firm_with_primary_key, :class_name => "Firm", :primary_key => "name", :foreign_key => "firm_name" - belongs_to :firm_with_primary_key_symbols, :class_name => "Firm", :primary_key => :name, :foreign_key => :firm_name - belongs_to :readonly_firm, -> { readonly }, :class_name => "Firm", :foreign_key => "firm_id" - belongs_to :bob_firm, -> { where :name => "Bob" }, :class_name => "Firm", :foreign_key => "client_of" - has_many :accounts, :through => :firm, :source => :accounts + belongs_to :firm, foreign_key: "client_of" + belongs_to :firm_with_basic_id, class_name: "Firm", foreign_key: "firm_id" + belongs_to :firm_with_select, -> { select("id") }, class_name: "Firm", foreign_key: "firm_id" + belongs_to :firm_with_other_name, class_name: "Firm", foreign_key: "client_of" + belongs_to :firm_with_condition, -> { where "1 = ?", 1 }, class_name: "Firm", foreign_key: "client_of" + belongs_to :firm_with_primary_key, class_name: "Firm", primary_key: "name", foreign_key: "firm_name" + belongs_to :firm_with_primary_key_symbols, class_name: "Firm", primary_key: :name, foreign_key: :firm_name + belongs_to :readonly_firm, -> { readonly }, class_name: "Firm", foreign_key: "firm_id" + belongs_to :bob_firm, -> { where name: "Bob" }, class_name: "Firm", foreign_key: "client_of" + has_many :accounts, through: :firm, source: :accounts belongs_to :account validate do @@ -181,9 +181,9 @@ class Client < Company end class ExclusivelyDependentFirm < Company - has_one :account, :foreign_key => "firm_id", :dependent => :delete - has_many :dependent_sanitized_conditional_clients_of_firm, -> { order("id").where("name = 'BigShot Inc.'") }, :foreign_key => "client_of", :class_name => "Client", :dependent => :delete_all - has_many :dependent_conditional_clients_of_firm, -> { order("id").where("name = ?", 'BigShot Inc.') }, :foreign_key => "client_of", :class_name => "Client", :dependent => :delete_all + has_one :account, foreign_key: "firm_id", dependent: :delete + has_many :dependent_sanitized_conditional_clients_of_firm, -> { order("id").where("name = 'BigShot Inc.'") }, foreign_key: "client_of", class_name: "Client", dependent: :delete_all + has_many :dependent_conditional_clients_of_firm, -> { order("id").where("name = ?", "BigShot Inc.") }, foreign_key: "client_of", class_name: "Client", dependent: :delete_all end class SpecialClient < Client @@ -193,8 +193,8 @@ class VerySpecialClient < SpecialClient end class Account < ActiveRecord::Base - belongs_to :firm, :class_name => 'Company' - belongs_to :unautosaved_firm, :foreign_key => "firm_id", :class_name => "Firm", :autosave => false + belongs_to :firm, class_name: "Company" + belongs_to :unautosaved_firm, foreign_key: "firm_id", class_name: "Firm", autosave: false alias_attribute :available_credit, :credit_limit @@ -204,7 +204,7 @@ class Account < ActiveRecord::Base # Test private kernel method through collection proxy using has_many. def self.open - where('firm_name = ?', '37signals') + where("firm_name = ?", "37signals") end before_destroy do |account| @@ -218,13 +218,13 @@ class Account < ActiveRecord::Base protected - def check_empty_credit_limit - errors.add("credit_limit", :blank) if credit_limit.blank? - end + def check_empty_credit_limit + errors.add("credit_limit", :blank) if credit_limit.blank? + end private - def private_method - "Sir, yes sir!" - end + def private_method + "Sir, yes sir!" + end end diff --git a/activerecord/test/models/company_in_module.rb b/activerecord/test/models/company_in_module.rb index bf0a0d1c3e..682f99e365 100644 --- a/activerecord/test/models/company_in_module.rb +++ b/activerecord/test/models/company_in_module.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/with_options' +require "active_support/core_ext/object/with_options" module MyApplication module Business @@ -6,23 +6,23 @@ module MyApplication end class Firm < Company - has_many :clients, -> { order("id") }, :dependent => :destroy - has_many :clients_sorted_desc, -> { order("id DESC") }, :class_name => "Client" - has_many :clients_of_firm, -> { order "id" }, :foreign_key => "client_of", :class_name => "Client" - has_many :clients_like_ms, -> { where("name = 'Microsoft'").order("id") }, :class_name => "Client" - has_one :account, :class_name => 'MyApplication::Billing::Account', :dependent => :destroy + has_many :clients, -> { order("id") }, dependent: :destroy + has_many :clients_sorted_desc, -> { order("id DESC") }, class_name: "Client" + has_many :clients_of_firm, -> { order "id" }, foreign_key: "client_of", class_name: "Client" + has_many :clients_like_ms, -> { where("name = 'Microsoft'").order("id") }, class_name: "Client" + has_one :account, class_name: "MyApplication::Billing::Account", dependent: :destroy end class Client < Company - belongs_to :firm, :foreign_key => "client_of" - belongs_to :firm_with_other_name, :class_name => "Firm", :foreign_key => "client_of" + belongs_to :firm, foreign_key: "client_of" + belongs_to :firm_with_other_name, class_name: "Firm", foreign_key: "client_of" class Contact < ActiveRecord::Base; end end class Developer < ActiveRecord::Base has_and_belongs_to_many :projects - validates_length_of :name, :within => (3..20) + validates_length_of :name, within: (3..20) end class Project < ActiveRecord::Base @@ -31,14 +31,14 @@ module MyApplication module Prefixed def self.table_name_prefix - 'prefixed_' + "prefixed_" end class Company < ActiveRecord::Base end class Firm < Company - self.table_name = 'companies' + self.table_name = "companies" end module Nested @@ -49,14 +49,14 @@ module MyApplication module Suffixed def self.table_name_suffix - '_suffixed' + "_suffixed" end class Company < ActiveRecord::Base end class Firm < Company - self.table_name = 'companies' + self.table_name = "companies" end module Nested @@ -68,31 +68,31 @@ module MyApplication module Billing class Firm < ActiveRecord::Base - self.table_name = 'companies' + self.table_name = "companies" end module Nested class Firm < ActiveRecord::Base - self.table_name = 'companies' + self.table_name = "companies" end end class Account < ActiveRecord::Base - with_options(:foreign_key => :firm_id) do |i| - i.belongs_to :firm, :class_name => 'MyApplication::Business::Firm' - i.belongs_to :qualified_billing_firm, :class_name => 'MyApplication::Billing::Firm' - i.belongs_to :unqualified_billing_firm, :class_name => 'Firm' - i.belongs_to :nested_qualified_billing_firm, :class_name => 'MyApplication::Billing::Nested::Firm' - i.belongs_to :nested_unqualified_billing_firm, :class_name => 'Nested::Firm' + with_options(foreign_key: :firm_id) do |i| + i.belongs_to :firm, class_name: "MyApplication::Business::Firm" + i.belongs_to :qualified_billing_firm, class_name: "MyApplication::Billing::Firm" + i.belongs_to :unqualified_billing_firm, class_name: "Firm" + i.belongs_to :nested_qualified_billing_firm, class_name: "MyApplication::Billing::Nested::Firm" + i.belongs_to :nested_unqualified_billing_firm, class_name: "Nested::Firm" end validate :check_empty_credit_limit protected - def check_empty_credit_limit - errors.add("credit_card", :blank) if credit_card.blank? - end + def check_empty_credit_limit + errors.add("credit_card", :blank) if credit_card.blank? + end end end end diff --git a/activerecord/test/models/computer.rb b/activerecord/test/models/computer.rb index cc8deb1b2b..1c9856e1af 100644 --- a/activerecord/test/models/computer.rb +++ b/activerecord/test/models/computer.rb @@ -1,3 +1,3 @@ class Computer < ActiveRecord::Base - belongs_to :developer, :foreign_key=>'developer' + belongs_to :developer, foreign_key: "developer" end diff --git a/activerecord/test/models/contact.rb b/activerecord/test/models/contact.rb index 9f2f69e1ee..47bbbbfd8b 100644 --- a/activerecord/test/models/contact.rb +++ b/activerecord/test/models/contact.rb @@ -1,11 +1,11 @@ module ContactFakeColumns def self.extended(base) base.class_eval do - establish_connection(:adapter => 'fake') + establish_connection(adapter: "fake") connection.data_sources = [table_name] connection.primary_keys = { - table_name => 'id' + table_name => "id" } column :id, :integer @@ -19,7 +19,7 @@ module ContactFakeColumns serialize :preferences - belongs_to :alternative, :class_name => 'Contact' + belongs_to :alternative, class_name: "Contact" end end @@ -37,5 +37,5 @@ class ContactSti < ActiveRecord::Base extend ContactFakeColumns column :type, :string - def type; 'ContactSti' end + def type; "ContactSti" end end diff --git a/activerecord/test/models/content.rb b/activerecord/test/models/content.rb index 140e1dfc78..68db2127d8 100644 --- a/activerecord/test/models/content.rb +++ b/activerecord/test/models/content.rb @@ -1,5 +1,5 @@ class Content < ActiveRecord::Base - self.table_name = 'content' + self.table_name = "content" has_one :content_position, dependent: :destroy def self.destroyed_ids @@ -12,8 +12,8 @@ class Content < ActiveRecord::Base end class ContentWhichRequiresTwoDestroyCalls < ActiveRecord::Base - self.table_name = 'content' - has_one :content_position, foreign_key: 'content_id', dependent: :destroy + self.table_name = "content" + has_one :content_position, foreign_key: "content_id", dependent: :destroy after_initialize do @destroy_count = 0 diff --git a/activerecord/test/models/contract.rb b/activerecord/test/models/contract.rb index cdf7b267b5..32bd581377 100644 --- a/activerecord/test/models/contract.rb +++ b/activerecord/test/models/contract.rb @@ -1,7 +1,7 @@ class Contract < ActiveRecord::Base belongs_to :company belongs_to :developer - belongs_to :firm, :foreign_key => 'company_id' + belongs_to :firm, foreign_key: "company_id" before_save :hi after_save :bye diff --git a/activerecord/test/models/country.rb b/activerecord/test/models/country.rb index 7db9a4e731..7912719ddd 100644 --- a/activerecord/test/models/country.rb +++ b/activerecord/test/models/country.rb @@ -1,7 +1,5 @@ class Country < ActiveRecord::Base - self.primary_key = :country_id has_and_belongs_to_many :treaties - end diff --git a/activerecord/test/models/course.rb b/activerecord/test/models/course.rb index f3d0e05ff7..348f2bf1e0 100644 --- a/activerecord/test/models/course.rb +++ b/activerecord/test/models/course.rb @@ -1,4 +1,4 @@ -require_dependency 'models/arunit2_model' +require_dependency "models/arunit2_model" class Course < ARUnit2Model belongs_to :college diff --git a/activerecord/test/models/customer.rb b/activerecord/test/models/customer.rb index 3338aaf7e1..60af7c2247 100644 --- a/activerecord/test/models/customer.rb +++ b/activerecord/test/models/customer.rb @@ -1,12 +1,13 @@ class Customer < ActiveRecord::Base cattr_accessor :gps_conversion_was_run - composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true - composed_of :balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new(&:to_money) - composed_of :gps_location, :allow_nil => true - composed_of :non_blank_gps_location, :class_name => "GpsLocation", :allow_nil => true, :mapping => %w(gps_location gps_location), - :converter => lambda { |gps| self.gps_conversion_was_run = true; gps.blank? ? nil : GpsLocation.new(gps)} - composed_of :fullname, :mapping => %w(name to_s), :constructor => Proc.new { |name| Fullname.parse(name) }, :converter => :parse + composed_of :address, mapping: [ %w(address_street street), %w(address_city city), %w(address_country country) ], allow_nil: true + composed_of :balance, class_name: "Money", mapping: %w(balance amount), converter: Proc.new(&:to_money) + composed_of :gps_location, allow_nil: true + composed_of :non_blank_gps_location, class_name: "GpsLocation", allow_nil: true, mapping: %w(gps_location gps_location), + converter: lambda { |gps| self.gps_conversion_was_run = true; gps.blank? ? nil : GpsLocation.new(gps) } + composed_of :fullname, mapping: %w(name to_s), constructor: Proc.new { |name| Fullname.parse(name) }, converter: :parse + composed_of :fullname_no_converter, mapping: %w(name to_s), class_name: "Fullname" end class Address diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index 9a907273f8..5ca1d37f6d 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -1,4 +1,4 @@ -require 'ostruct' +require "ostruct" module DeveloperProjectsAssociationExtension2 def find_least_recent @@ -23,35 +23,35 @@ class Developer < ActiveRecord::Base has_and_belongs_to_many :projects_extended_by_name, -> { extending(DeveloperProjectsAssociationExtension) }, - :class_name => "Project", - :join_table => "developers_projects", - :association_foreign_key => "project_id" + class_name: "Project", + join_table: "developers_projects", + association_foreign_key: "project_id" has_and_belongs_to_many :projects_extended_by_name_twice, -> { extending(DeveloperProjectsAssociationExtension, DeveloperProjectsAssociationExtension2) }, - :class_name => "Project", - :join_table => "developers_projects", - :association_foreign_key => "project_id" + class_name: "Project", + join_table: "developers_projects", + association_foreign_key: "project_id" has_and_belongs_to_many :projects_extended_by_name_and_block, -> { extending(DeveloperProjectsAssociationExtension) }, - :class_name => "Project", - :join_table => "developers_projects", - :association_foreign_key => "project_id" do + class_name: "Project", + join_table: "developers_projects", + association_foreign_key: "project_id" do def find_least_recent order("id ASC").first end end - has_and_belongs_to_many :special_projects, :join_table => 'developers_projects', :association_foreign_key => 'project_id' + has_and_belongs_to_many :special_projects, join_table: "developers_projects", association_foreign_key: "project_id" has_and_belongs_to_many :sym_special_projects, - :join_table => :developers_projects, - :association_foreign_key => 'project_id', - :class_name => 'SpecialProject' + join_table: :developers_projects, + association_foreign_key: "project_id", + class_name: "SpecialProject" has_many :audit_logs has_many :contracts - has_many :firms, :through => :contracts, :source => :firm + has_many :firms, through: :contracts, source: :firm has_many :comments, ->(developer) { where(body: "I'm #{developer.name}") } has_many :ratings, through: :comments has_one :ship, dependent: :nullify @@ -59,20 +59,20 @@ class Developer < ActiveRecord::Base belongs_to :firm has_many :contracted_projects, class_name: "Project" - scope :jamises, -> { where(:name => 'Jamis') } + scope :jamises, -> { where(name: "Jamis") } - validates_inclusion_of :salary, :in => 50000..200000 - validates_length_of :name, :within => 3..20 + validates_inclusion_of :salary, in: 50000..200000 + validates_length_of :name, within: 3..20 before_create do |developer| - developer.audit_logs.build :message => "Computer created" + developer.audit_logs.build message: "Computer created" end attr_accessor :last_name - define_attribute_method 'last_name' + define_attribute_method "last_name" def log=(message) - audit_logs.build :message => message + audit_logs.build message: message end after_find :track_instance_count @@ -83,17 +83,16 @@ class Developer < ActiveRecord::Base self.class.instance_count += 1 end private :track_instance_count - end class AuditLog < ActiveRecord::Base - belongs_to :developer, :validate => true - belongs_to :unvalidated_developer, :class_name => 'Developer' + belongs_to :developer, validate: true + belongs_to :unvalidated_developer, class_name: "Developer" end class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base - self.table_name = 'developers' - has_and_belongs_to_many :projects, :join_table => 'developers_projects', :foreign_key => 'developer_id' + self.table_name = "developers" + has_and_belongs_to_many :projects, join_table: "developers_projects", foreign_key: "developer_id" before_destroy :raise_if_projects_empty! def raise_if_projects_empty! @@ -102,63 +101,63 @@ class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base end class DeveloperWithSelect < ActiveRecord::Base - self.table_name = 'developers' - default_scope { select('name') } + self.table_name = "developers" + default_scope { select("name") } end class DeveloperWithIncludes < ActiveRecord::Base - self.table_name = 'developers' - has_many :audit_logs, :foreign_key => :developer_id + self.table_name = "developers" + has_many :audit_logs, foreign_key: :developer_id default_scope { includes(:audit_logs) } end class DeveloperFilteredOnJoins < ActiveRecord::Base - self.table_name = 'developers' - has_and_belongs_to_many :projects, -> { order('projects.id') }, :foreign_key => 'developer_id', :join_table => 'developers_projects' + self.table_name = "developers" + has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects" def self.default_scope - joins(:projects).where(:projects => { :name => 'Active Controller' }) + joins(:projects).where(projects: { name: "Active Controller" }) end end class DeveloperOrderedBySalary < ActiveRecord::Base - self.table_name = 'developers' - default_scope { order('salary DESC') } + self.table_name = "developers" + default_scope { order("salary DESC") } - scope :by_name, -> { order('name DESC') } + scope :by_name, -> { order("name DESC") } end class DeveloperCalledDavid < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" default_scope { where("name = 'David'") } end class LazyLambdaDeveloperCalledDavid < ActiveRecord::Base - self.table_name = 'developers' - default_scope lambda { where(:name => 'David') } + self.table_name = "developers" + default_scope lambda { where(name: "David") } end class LazyBlockDeveloperCalledDavid < ActiveRecord::Base - self.table_name = 'developers' - default_scope { where(:name => 'David') } + self.table_name = "developers" + default_scope { where(name: "David") } end class CallableDeveloperCalledDavid < ActiveRecord::Base - self.table_name = 'developers' - default_scope OpenStruct.new(:call => where(:name => 'David')) + self.table_name = "developers" + default_scope OpenStruct.new(call: where(name: "David")) end class ClassMethodDeveloperCalledDavid < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" def self.default_scope - where(:name => 'David') + where(name: "David") end end class ClassMethodReferencingScopeDeveloperCalledDavid < ActiveRecord::Base - self.table_name = 'developers' - scope :david, -> { where(:name => 'David') } + self.table_name = "developers" + scope :david, -> { where(name: "David") } def self.default_scope david @@ -166,61 +165,61 @@ class ClassMethodReferencingScopeDeveloperCalledDavid < ActiveRecord::Base end class LazyBlockReferencingScopeDeveloperCalledDavid < ActiveRecord::Base - self.table_name = 'developers' - scope :david, -> { where(:name => 'David') } + self.table_name = "developers" + scope :david, -> { where(name: "David") } default_scope { david } end class DeveloperCalledJamis < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" - default_scope { where(:name => 'Jamis') } - scope :poor, -> { where('salary < 150000') } + default_scope { where(name: "Jamis") } + scope :poor, -> { where("salary < 150000") } scope :david, -> { where name: "David" } scope :david2, -> { unscoped.where name: "David" } end class PoorDeveloperCalledJamis < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" - default_scope -> { where(:name => 'Jamis', :salary => 50000) } + default_scope -> { where(name: "Jamis", salary: 50000) } end class InheritedPoorDeveloperCalledJamis < DeveloperCalledJamis - self.table_name = 'developers' + self.table_name = "developers" - default_scope -> { where(:salary => 50000) } + default_scope -> { where(salary: 50000) } end class MultiplePoorDeveloperCalledJamis < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" - default_scope -> { where(:name => 'Jamis') } - default_scope -> { where(:salary => 50000) } + default_scope -> { where(name: "Jamis") } + default_scope -> { where(salary: 50000) } end module SalaryDefaultScope extend ActiveSupport::Concern - included { default_scope { where(:salary => 50000) } } + included { default_scope { where(salary: 50000) } } end class ModuleIncludedPoorDeveloperCalledJamis < DeveloperCalledJamis - self.table_name = 'developers' + self.table_name = "developers" include SalaryDefaultScope end class EagerDeveloperWithDefaultScope < ActiveRecord::Base - self.table_name = 'developers' - has_and_belongs_to_many :projects, -> { order('projects.id') }, :foreign_key => 'developer_id', :join_table => 'developers_projects' + self.table_name = "developers" + has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects" default_scope { includes(:projects) } end class EagerDeveloperWithClassMethodDefaultScope < ActiveRecord::Base - self.table_name = 'developers' - has_and_belongs_to_many :projects, -> { order('projects.id') }, :foreign_key => 'developer_id', :join_table => 'developers_projects' + self.table_name = "developers" + has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects" def self.default_scope includes(:projects) @@ -228,28 +227,28 @@ class EagerDeveloperWithClassMethodDefaultScope < ActiveRecord::Base end class EagerDeveloperWithLambdaDefaultScope < ActiveRecord::Base - self.table_name = 'developers' - has_and_belongs_to_many :projects, -> { order('projects.id') }, :foreign_key => 'developer_id', :join_table => 'developers_projects' + self.table_name = "developers" + has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects" default_scope lambda { includes(:projects) } end class EagerDeveloperWithBlockDefaultScope < ActiveRecord::Base - self.table_name = 'developers' - has_and_belongs_to_many :projects, -> { order('projects.id') }, :foreign_key => 'developer_id', :join_table => 'developers_projects' + self.table_name = "developers" + has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects" default_scope { includes(:projects) } end class EagerDeveloperWithCallableDefaultScope < ActiveRecord::Base - self.table_name = 'developers' - has_and_belongs_to_many :projects, -> { order('projects.id') }, :foreign_key => 'developer_id', :join_table => 'developers_projects' + self.table_name = "developers" + has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects" - default_scope OpenStruct.new(:call => includes(:projects)) + default_scope OpenStruct.new(call: includes(:projects)) end class ThreadsafeDeveloper < ActiveRecord::Base - self.table_name = 'developers' + self.table_name = "developers" def self.default_scope sleep 0.05 if Thread.current[:long_default_scope] diff --git a/activerecord/test/models/doubloon.rb b/activerecord/test/models/doubloon.rb index 2b11d128e2..7272504666 100644 --- a/activerecord/test/models/doubloon.rb +++ b/activerecord/test/models/doubloon.rb @@ -8,5 +8,5 @@ end class Doubloon < AbstractDoubloon # This uses an abstract class that defines attributes and associations. - self.table_name = 'doubloons' + self.table_name = "doubloons" end diff --git a/activerecord/test/models/edge.rb b/activerecord/test/models/edge.rb index 55e0c31fcb..e61d25c9bc 100644 --- a/activerecord/test/models/edge.rb +++ b/activerecord/test/models/edge.rb @@ -1,5 +1,5 @@ # This class models an edge in a directed graph. class Edge < ActiveRecord::Base - belongs_to :source, :class_name => 'Vertex', :foreign_key => 'source_id' - belongs_to :sink, :class_name => 'Vertex', :foreign_key => 'sink_id' + belongs_to :source, class_name: "Vertex", foreign_key: "source_id" + belongs_to :sink, class_name: "Vertex", foreign_key: "sink_id" end diff --git a/activerecord/test/models/engine.rb b/activerecord/test/models/engine.rb index 851ff8c22b..eada171f6a 100644 --- a/activerecord/test/models/engine.rb +++ b/activerecord/test/models/engine.rb @@ -1,4 +1,3 @@ class Engine < ActiveRecord::Base - belongs_to :my_car, :class_name => 'Car', :foreign_key => 'car_id', :counter_cache => :engines_count + belongs_to :my_car, class_name: "Car", foreign_key: "car_id", counter_cache: :engines_count end - diff --git a/activerecord/test/models/essay.rb b/activerecord/test/models/essay.rb index ec4b982b5b..13267fbc21 100644 --- a/activerecord/test/models/essay.rb +++ b/activerecord/test/models/essay.rb @@ -1,5 +1,5 @@ class Essay < ActiveRecord::Base - belongs_to :writer, :primary_key => :name, :polymorphic => true - belongs_to :category, :primary_key => :name - has_one :owner, :primary_key => :name + belongs_to :writer, primary_key: :name, polymorphic: true + belongs_to :category, primary_key: :name + has_one :owner, primary_key: :name end diff --git a/activerecord/test/models/eye.rb b/activerecord/test/models/eye.rb index dc8ae2b3f6..ab3b3eacf3 100644 --- a/activerecord/test/models/eye.rb +++ b/activerecord/test/models/eye.rb @@ -15,7 +15,7 @@ class Eye < ActiveRecord::Base after_create :trace_after_create2 after_update :trace_after_update2 after_save :trace_after_save2 - + def trace_after_create (@after_create_callbacks_stack ||= []) << !iris.persisted? end diff --git a/activerecord/test/models/face.rb b/activerecord/test/models/face.rb index af76fea52c..5913bfa969 100644 --- a/activerecord/test/models/face.rb +++ b/activerecord/test/models/face.rb @@ -1,9 +1,9 @@ class Face < ActiveRecord::Base - belongs_to :man, :inverse_of => :face - belongs_to :polymorphic_man, :polymorphic => true, :inverse_of => :polymorphic_face + belongs_to :man, inverse_of: :face + belongs_to :polymorphic_man, polymorphic: true, inverse_of: :polymorphic_face # Oracle identifier length is limited to 30 bytes or less, `polymorphic` renamed `poly` - belongs_to :poly_man_without_inverse, :polymorphic => true + belongs_to :poly_man_without_inverse, polymorphic: true # These is a "broken" inverse_of for the purposes of testing - belongs_to :horrible_man, :class_name => 'Man', :inverse_of => :horrible_face - belongs_to :horrible_polymorphic_man, :polymorphic => true, :inverse_of => :horrible_polymorphic_face + belongs_to :horrible_man, class_name: "Man", inverse_of: :horrible_face + belongs_to :horrible_polymorphic_man, polymorphic: true, inverse_of: :horrible_polymorphic_face end diff --git a/activerecord/test/models/friendship.rb b/activerecord/test/models/friendship.rb index 4b411ca8e0..578382b494 100644 --- a/activerecord/test/models/friendship.rb +++ b/activerecord/test/models/friendship.rb @@ -1,6 +1,6 @@ class Friendship < ActiveRecord::Base - belongs_to :friend, class_name: 'Person' + belongs_to :friend, class_name: "Person" # friend_too exists to test a bug, and probably shouldn't be used elsewhere - belongs_to :friend_too, foreign_key: 'friend_id', class_name: 'Person', counter_cache: :friends_too_count - belongs_to :follower, class_name: 'Person' + belongs_to :friend_too, foreign_key: "friend_id", class_name: "Person", counter_cache: :friends_too_count + belongs_to :follower, class_name: "Person" end diff --git a/activerecord/test/models/hotel.rb b/activerecord/test/models/hotel.rb index 9c90ffcff4..7bc717c891 100644 --- a/activerecord/test/models/hotel.rb +++ b/activerecord/test/models/hotel.rb @@ -1,11 +1,11 @@ class Hotel < ActiveRecord::Base has_many :departments has_many :chefs, through: :departments - has_many :cake_designers, source_type: 'CakeDesigner', source: :employable, through: :chefs - has_many :drink_designers, source_type: 'DrinkDesigner', source: :employable, through: :chefs + has_many :cake_designers, source_type: "CakeDesigner", source: :employable, through: :chefs + has_many :drink_designers, source_type: "DrinkDesigner", source: :employable, through: :chefs has_many :chef_lists, as: :employable_list - has_many :mocktail_designers, through: :chef_lists, source: :employable, :source_type => "MocktailDesigner" + has_many :mocktail_designers, through: :chef_lists, source: :employable, source_type: "MocktailDesigner" has_many :recipes, through: :chefs end diff --git a/activerecord/test/models/interest.rb b/activerecord/test/models/interest.rb index d5d9226204..ec79416ee7 100644 --- a/activerecord/test/models/interest.rb +++ b/activerecord/test/models/interest.rb @@ -1,5 +1,5 @@ class Interest < ActiveRecord::Base - belongs_to :man, :inverse_of => :interests - belongs_to :polymorphic_man, :polymorphic => true, :inverse_of => :polymorphic_interests - belongs_to :zine, :inverse_of => :interests + belongs_to :man, inverse_of: :interests + belongs_to :polymorphic_man, polymorphic: true, inverse_of: :polymorphic_interests + belongs_to :zine, inverse_of: :interests end diff --git a/activerecord/test/models/invoice.rb b/activerecord/test/models/invoice.rb index fc6ef0230e..4be5a00193 100644 --- a/activerecord/test/models/invoice.rb +++ b/activerecord/test/models/invoice.rb @@ -1,4 +1,4 @@ class Invoice < ActiveRecord::Base - has_many :line_items, :autosave => true - before_save {|record| record.balance = record.line_items.map(&:amount).sum } + has_many :line_items, autosave: true + before_save { |record| record.balance = record.line_items.map(&:amount).sum } end diff --git a/activerecord/test/models/item.rb b/activerecord/test/models/item.rb index c2571dd7fb..336fb1769a 100644 --- a/activerecord/test/models/item.rb +++ b/activerecord/test/models/item.rb @@ -1,6 +1,6 @@ class AbstractItem < ActiveRecord::Base self.abstract_class = true - has_one :tagging, :as => :taggable + has_one :tagging, as: :taggable end class Item < AbstractItem diff --git a/activerecord/test/models/job.rb b/activerecord/test/models/job.rb index f7b0e787b1..bbaef2792c 100644 --- a/activerecord/test/models/job.rb +++ b/activerecord/test/models/job.rb @@ -1,7 +1,7 @@ class Job < ActiveRecord::Base has_many :references - has_many :people, :through => :references - belongs_to :ideal_reference, :class_name => 'Reference' + has_many :people, through: :references + belongs_to :ideal_reference, class_name: "Reference" - has_many :agents, :through => :people + has_many :agents, through: :people end diff --git a/activerecord/test/models/joke.rb b/activerecord/test/models/joke.rb index edda4655dc..eeb5818a1f 100644 --- a/activerecord/test/models/joke.rb +++ b/activerecord/test/models/joke.rb @@ -1,7 +1,7 @@ class Joke < ActiveRecord::Base - self.table_name = 'funny_jokes' + self.table_name = "funny_jokes" end class GoodJoke < ActiveRecord::Base - self.table_name = 'funny_jokes' + self.table_name = "funny_jokes" end diff --git a/activerecord/test/models/keyboard.rb b/activerecord/test/models/keyboard.rb index 39347e274e..bcede53ec9 100644 --- a/activerecord/test/models/keyboard.rb +++ b/activerecord/test/models/keyboard.rb @@ -1,3 +1,3 @@ class Keyboard < ActiveRecord::Base - self.primary_key = 'key_number' + self.primary_key = "key_number" end diff --git a/activerecord/test/models/line_item.rb b/activerecord/test/models/line_item.rb index 0dd921a300..93f7cceb13 100644 --- a/activerecord/test/models/line_item.rb +++ b/activerecord/test/models/line_item.rb @@ -1,3 +1,3 @@ class LineItem < ActiveRecord::Base - belongs_to :invoice, :touch => true + belongs_to :invoice, touch: true end diff --git a/activerecord/test/models/man.rb b/activerecord/test/models/man.rb index 4fbb6b226b..d2436a735c 100644 --- a/activerecord/test/models/man.rb +++ b/activerecord/test/models/man.rb @@ -1,11 +1,11 @@ class Man < ActiveRecord::Base - has_one :face, :inverse_of => :man - has_one :polymorphic_face, :class_name => 'Face', :as => :polymorphic_man, :inverse_of => :polymorphic_man - has_one :polymorphic_face_without_inverse, :class_name => 'Face', :as => :poly_man_without_inverse - has_many :interests, :inverse_of => :man - has_many :polymorphic_interests, :class_name => 'Interest', :as => :polymorphic_man, :inverse_of => :polymorphic_man + has_one :face, inverse_of: :man + has_one :polymorphic_face, class_name: "Face", as: :polymorphic_man, inverse_of: :polymorphic_man + has_one :polymorphic_face_without_inverse, class_name: "Face", as: :poly_man_without_inverse + has_many :interests, inverse_of: :man + has_many :polymorphic_interests, class_name: "Interest", as: :polymorphic_man, inverse_of: :polymorphic_man # These are "broken" inverse_of associations for the purposes of testing - has_one :dirty_face, :class_name => 'Face', :inverse_of => :dirty_man - has_many :secret_interests, :class_name => 'Interest', :inverse_of => :secret_man + has_one :dirty_face, class_name: "Face", inverse_of: :dirty_man + has_many :secret_interests, class_name: "Interest", inverse_of: :secret_man has_one :mixed_case_monkey end diff --git a/activerecord/test/models/matey.rb b/activerecord/test/models/matey.rb index 47b0baa974..80ee5f47c5 100644 --- a/activerecord/test/models/matey.rb +++ b/activerecord/test/models/matey.rb @@ -1,4 +1,4 @@ class Matey < ActiveRecord::Base belongs_to :pirate - belongs_to :target, :class_name => 'Pirate' + belongs_to :target, class_name: "Pirate" end diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb index 7693c6e515..36f2461b84 100644 --- a/activerecord/test/models/member.rb +++ b/activerecord/test/models/member.rb @@ -2,34 +2,34 @@ class Member < ActiveRecord::Base has_one :current_membership has_one :selected_membership has_one :membership - has_one :club, :through => :current_membership - has_one :selected_club, :through => :selected_membership, :source => :club - has_one :favourite_club, -> { where "memberships.favourite = ?", true }, :through => :membership, :source => :club - has_one :hairy_club, -> { where :clubs => {:name => "Moustache and Eyebrow Fancier Club"} }, :through => :membership, :source => :club - has_one :sponsor, :as => :sponsorable - has_one :sponsor_club, :through => :sponsor - has_one :member_detail, :inverse_of => false - has_one :organization, :through => :member_detail + has_one :club, through: :current_membership + has_one :selected_club, through: :selected_membership, source: :club + has_one :favourite_club, -> { where "memberships.favourite = ?", true }, through: :membership, source: :club + has_one :hairy_club, -> { where clubs: { name: "Moustache and Eyebrow Fancier Club" } }, through: :membership, source: :club + has_one :sponsor, as: :sponsorable + has_one :sponsor_club, through: :sponsor + has_one :member_detail, inverse_of: false + has_one :organization, through: :member_detail belongs_to :member_type - has_many :nested_member_types, :through => :member_detail, :source => :member_type - has_one :nested_member_type, :through => :member_detail, :source => :member_type + has_many :nested_member_types, through: :member_detail, source: :member_type + has_one :nested_member_type, through: :member_detail, source: :member_type - has_many :nested_sponsors, :through => :sponsor_club, :source => :sponsor - has_one :nested_sponsor, :through => :sponsor_club, :source => :sponsor + has_many :nested_sponsors, through: :sponsor_club, source: :sponsor + has_one :nested_sponsor, through: :sponsor_club, source: :sponsor - has_many :organization_member_details, :through => :member_detail - has_many :organization_member_details_2, :through => :organization, :source => :member_details + has_many :organization_member_details, through: :member_detail + has_many :organization_member_details_2, through: :organization, source: :member_details - has_one :club_category, :through => :club, :source => :category + has_one :club_category, through: :club, source: :category - has_many :current_memberships, -> { where :favourite => true } - has_many :clubs, :through => :current_memberships + has_many :current_memberships, -> { where favourite: true } + has_many :clubs, through: :current_memberships has_many :tenant_memberships - has_many :tenant_clubs, through: :tenant_memberships, class_name: 'Club', source: :club + has_many :tenant_clubs, through: :tenant_memberships, class_name: "Club", source: :club - has_one :club_through_many, :through => :current_memberships, :source => :club + has_one :club_through_many, through: :current_memberships, source: :club belongs_to :admittable, polymorphic: true has_one :premium_club, through: :admittable @@ -37,5 +37,5 @@ end class SelfMember < ActiveRecord::Base self.table_name = "members" - has_and_belongs_to_many :friends, :class_name => "SelfMember", :join_table => "member_friends" + has_and_belongs_to_many :friends, class_name: "SelfMember", join_table: "member_friends" end diff --git a/activerecord/test/models/membership.rb b/activerecord/test/models/membership.rb index e181ba1f11..2c3ad230a7 100644 --- a/activerecord/test/models/membership.rb +++ b/activerecord/test/models/membership.rb @@ -9,7 +9,7 @@ class CurrentMembership < Membership end class SuperMembership < Membership - belongs_to :member, -> { order('members.id DESC') } + belongs_to :member, -> { order("members.id DESC") } belongs_to :club end diff --git a/activerecord/test/models/mentor.rb b/activerecord/test/models/mentor.rb index 11f1e4bff8..66504b4e91 100644 --- a/activerecord/test/models/mentor.rb +++ b/activerecord/test/models/mentor.rb @@ -1,3 +1,3 @@ class Mentor < ActiveRecord::Base has_many :developers -end
\ No newline at end of file +end diff --git a/activerecord/test/models/minivan.rb b/activerecord/test/models/minivan.rb index 4fe79720ad..e9b05dadf2 100644 --- a/activerecord/test/models/minivan.rb +++ b/activerecord/test/models/minivan.rb @@ -2,8 +2,7 @@ class Minivan < ActiveRecord::Base self.primary_key = :minivan_id belongs_to :speedometer - has_one :dashboard, :through => :speedometer + has_one :dashboard, through: :speedometer attr_readonly :color - end diff --git a/activerecord/test/models/node.rb b/activerecord/test/models/node.rb index 07dd2dbccb..459ea8cf95 100644 --- a/activerecord/test/models/node.rb +++ b/activerecord/test/models/node.rb @@ -1,5 +1,5 @@ class Node < ActiveRecord::Base belongs_to :tree, touch: true - belongs_to :parent, class_name: 'Node', touch: true, optional: true - has_many :children, class_name: 'Node', foreign_key: :parent_id, dependent: :destroy + belongs_to :parent, class_name: "Node", touch: true, optional: true + has_many :children, class_name: "Node", foreign_key: :parent_id, dependent: :destroy end diff --git a/activerecord/test/models/order.rb b/activerecord/test/models/order.rb index e838c0b70d..699be53959 100644 --- a/activerecord/test/models/order.rb +++ b/activerecord/test/models/order.rb @@ -1,4 +1,4 @@ class Order < ActiveRecord::Base - belongs_to :billing, :class_name => 'Customer', :foreign_key => 'billing_customer_id' - belongs_to :shipping, :class_name => 'Customer', :foreign_key => 'shipping_customer_id' + belongs_to :billing, class_name: "Customer", foreign_key: "billing_customer_id" + belongs_to :shipping, class_name: "Customer", foreign_key: "shipping_customer_id" end diff --git a/activerecord/test/models/organization.rb b/activerecord/test/models/organization.rb index f3e92f3067..462830dadc 100644 --- a/activerecord/test/models/organization.rb +++ b/activerecord/test/models/organization.rb @@ -1,14 +1,14 @@ class Organization < ActiveRecord::Base has_many :member_details - has_many :members, :through => :member_details + has_many :members, through: :member_details - has_many :authors, :primary_key => :name - has_many :author_essay_categories, :through => :authors, :source => :essay_categories + has_many :authors, primary_key: :name + has_many :author_essay_categories, through: :authors, source: :essay_categories - has_one :author, :primary_key => :name - has_one :author_owned_essay_category, :through => :author, :source => :owned_essay_category + has_one :author, primary_key: :name + has_one :author_owned_essay_category, through: :author, source: :owned_essay_category - has_many :posts, :through => :author, :source => :posts + has_many :posts, through: :author, source: :posts - scope :clubs, -> { from('clubs') } + scope :clubs, -> { from("clubs") } end diff --git a/activerecord/test/models/owner.rb b/activerecord/test/models/owner.rb index ce8242cf2f..21fc9b6eb8 100644 --- a/activerecord/test/models/owner.rb +++ b/activerecord/test/models/owner.rb @@ -1,19 +1,19 @@ class Owner < ActiveRecord::Base self.primary_key = :owner_id - has_many :pets, -> { order 'pets.name desc' } + has_many :pets, -> { order "pets.name desc" } has_many :toys, through: :pets has_many :persons, through: :pets - belongs_to :last_pet, class_name: 'Pet' + belongs_to :last_pet, class_name: "Pet" scope :including_last_pet, -> { - select(%q[ + select(' owners.*, ( select p.pet_id from pets p where p.owner_id = owners.owner_id order by p.name desc limit 1 ) as last_pet_id - ]).includes(:last_pet) + ').includes(:last_pet) } after_commit :execute_blocks diff --git a/activerecord/test/models/parrot.rb b/activerecord/test/models/parrot.rb index ddc9dcaf29..5b693664d4 100644 --- a/activerecord/test/models/parrot.rb +++ b/activerecord/test/models/parrot.rb @@ -3,13 +3,13 @@ class Parrot < ActiveRecord::Base has_and_belongs_to_many :pirates has_and_belongs_to_many :treasures - has_many :loots, :as => :looter + has_many :loots, as: :looter alias_attribute :title, :name validates_presence_of :name attr_accessor :cancel_save_from_callback - before_save :cancel_save_callback_method, :if => :cancel_save_from_callback + before_save :cancel_save_callback_method, if: :cancel_save_from_callback def cancel_save_callback_method throw(:abort) end @@ -19,5 +19,5 @@ class LiveParrot < Parrot end class DeadParrot < Parrot - belongs_to :killer, :class_name => 'Pirate', foreign_key: :killer_id + belongs_to :killer, class_name: "Pirate", foreign_key: :killer_id end diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb index a4a9c6b0d4..18994d6f18 100644 --- a/activerecord/test/models/person.rb +++ b/activerecord/test/models/person.rb @@ -3,71 +3,70 @@ class Person < ActiveRecord::Base has_many :secure_readers has_one :reader - has_many :posts, :through => :readers - has_many :secure_posts, :through => :secure_readers - has_many :posts_with_no_comments, -> { includes(:comments).where('comments.id is null').references(:comments) }, - :through => :readers, :source => :post + has_many :posts, through: :readers + has_many :secure_posts, through: :secure_readers + has_many :posts_with_no_comments, -> { includes(:comments).where("comments.id is null").references(:comments) }, + through: :readers, source: :post - has_many :friendships, foreign_key: 'friend_id' + has_many :friendships, foreign_key: "friend_id" # friends_too exists to test a bug, and probably shouldn't be used elsewhere - has_many :friends_too, foreign_key: 'friend_id', class_name: 'Friendship' + has_many :friends_too, foreign_key: "friend_id", class_name: "Friendship" has_many :followers, through: :friendships has_many :references has_many :bad_references - has_many :fixed_bad_references, -> { where :favourite => true }, :class_name => 'BadReference' - has_one :favourite_reference, -> { where 'favourite=?', true }, :class_name => 'Reference' - has_many :posts_with_comments_sorted_by_comment_id, -> { includes(:comments).order('comments.id') }, :through => :readers, :source => :post + has_many :fixed_bad_references, -> { where favourite: true }, class_name: "BadReference" + has_one :favourite_reference, -> { where "favourite=?", true }, class_name: "Reference" + has_many :posts_with_comments_sorted_by_comment_id, -> { includes(:comments).order("comments.id") }, through: :readers, source: :post has_many :first_posts, -> { where(id: [1, 2]) }, through: :readers - has_many :jobs, :through => :references - has_many :jobs_with_dependent_destroy, :source => :job, :through => :references, :dependent => :destroy - has_many :jobs_with_dependent_delete_all, :source => :job, :through => :references, :dependent => :delete_all - has_many :jobs_with_dependent_nullify, :source => :job, :through => :references, :dependent => :nullify + has_many :jobs, through: :references + has_many :jobs_with_dependent_destroy, source: :job, through: :references, dependent: :destroy + has_many :jobs_with_dependent_delete_all, source: :job, through: :references, dependent: :delete_all + has_many :jobs_with_dependent_nullify, source: :job, through: :references, dependent: :nullify - belongs_to :primary_contact, :class_name => 'Person' - has_many :agents, :class_name => 'Person', :foreign_key => 'primary_contact_id' - has_many :agents_of_agents, :through => :agents, :source => :agents - belongs_to :number1_fan, :class_name => 'Person' + belongs_to :primary_contact, class_name: "Person" + has_many :agents, class_name: "Person", foreign_key: "primary_contact_id" + has_many :agents_of_agents, through: :agents, source: :agents + belongs_to :number1_fan, class_name: "Person" - has_many :personal_legacy_things, :dependent => :destroy + has_many :personal_legacy_things, dependent: :destroy - has_many :agents_posts, :through => :agents, :source => :posts - has_many :agents_posts_authors, :through => :agents_posts, :source => :author + has_many :agents_posts, through: :agents, source: :posts + has_many :agents_posts_authors, through: :agents_posts, source: :author has_many :essays, primary_key: "first_name", foreign_key: "writer_id" - scope :males, -> { where(:gender => 'M') } + scope :males, -> { where(gender: "M") } end class PersonWithDependentDestroyJobs < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" - has_many :references, :foreign_key => :person_id - has_many :jobs, :source => :job, :through => :references, :dependent => :destroy + has_many :references, foreign_key: :person_id + has_many :jobs, source: :job, through: :references, dependent: :destroy end class PersonWithDependentDeleteAllJobs < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" - has_many :references, :foreign_key => :person_id - has_many :jobs, :source => :job, :through => :references, :dependent => :delete_all + has_many :references, foreign_key: :person_id + has_many :jobs, source: :job, through: :references, dependent: :delete_all end class PersonWithDependentNullifyJobs < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" - has_many :references, :foreign_key => :person_id - has_many :jobs, :source => :job, :through => :references, :dependent => :nullify + has_many :references, foreign_key: :person_id + has_many :jobs, source: :job, through: :references, dependent: :nullify end - class LoosePerson < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" self.abstract_class = true - has_one :best_friend, :class_name => 'LoosePerson', :foreign_key => :best_friend_id - belongs_to :best_friend_of, :class_name => 'LoosePerson', :foreign_key => :best_friend_of_id - has_many :best_friends, :class_name => 'LoosePerson', :foreign_key => :best_friend_id + has_one :best_friend, class_name: "LoosePerson", foreign_key: :best_friend_id + belongs_to :best_friend_of, class_name: "LoosePerson", foreign_key: :best_friend_of_id + has_many :best_friends, class_name: "LoosePerson", foreign_key: :best_friend_id accepts_nested_attributes_for :best_friend, :best_friend_of, :best_friends end @@ -75,11 +74,11 @@ end class LooseDescendant < LoosePerson; end class TightPerson < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" - has_one :best_friend, :class_name => 'TightPerson', :foreign_key => :best_friend_id - belongs_to :best_friend_of, :class_name => 'TightPerson', :foreign_key => :best_friend_of_id - has_many :best_friends, :class_name => 'TightPerson', :foreign_key => :best_friend_id + has_one :best_friend, class_name: "TightPerson", foreign_key: :best_friend_id + belongs_to :best_friend_of, class_name: "TightPerson", foreign_key: :best_friend_of_id + has_many :best_friends, class_name: "TightPerson", foreign_key: :best_friend_id accepts_nested_attributes_for :best_friend, :best_friend_of, :best_friends end @@ -87,56 +86,56 @@ end class TightDescendant < TightPerson; end class RichPerson < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" - has_and_belongs_to_many :treasures, :join_table => 'peoples_treasures' + has_and_belongs_to_many :treasures, join_table: "peoples_treasures" before_validation :run_before_create, on: :create before_validation :run_before_validation private - def run_before_create - self.first_name = first_name.to_s + 'run_before_create' - end + def run_before_create + self.first_name = first_name.to_s + "run_before_create" + end - def run_before_validation - self.first_name = first_name.to_s + 'run_before_validation' - end + def run_before_validation + self.first_name = first_name.to_s + "run_before_validation" + end end class NestedPerson < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" - has_one :best_friend, :class_name => 'NestedPerson', :foreign_key => :best_friend_id - accepts_nested_attributes_for :best_friend, :update_only => true + has_one :best_friend, class_name: "NestedPerson", foreign_key: :best_friend_id + accepts_nested_attributes_for :best_friend, update_only: true def comments=(new_comments) raise RuntimeError end def best_friend_first_name=(new_name) - assign_attributes({ :best_friend_attributes => { :first_name => new_name } }) + assign_attributes(best_friend_attributes: { first_name: new_name }) end end class Insure INSURES = %W{life annuality} - def self.load mask + def self.load(mask) INSURES.select do |insure| (1 << INSURES.index(insure)) & mask.to_i > 0 end end - def self.dump insures + def self.dump(insures) numbers = insures.map { |insure| INSURES.index(insure) } numbers.inject(0) { |sum, n| sum + (1 << n) } end end class SerializedPerson < ActiveRecord::Base - self.table_name = 'people' + self.table_name = "people" serialize :insures, Insure end diff --git a/activerecord/test/models/personal_legacy_thing.rb b/activerecord/test/models/personal_legacy_thing.rb index a7ee3a0bca..adde7a504a 100644 --- a/activerecord/test/models/personal_legacy_thing.rb +++ b/activerecord/test/models/personal_legacy_thing.rb @@ -1,4 +1,4 @@ class PersonalLegacyThing < ActiveRecord::Base self.locking_column = :version - belongs_to :person, :counter_cache => true + belongs_to :person, counter_cache: true end diff --git a/activerecord/test/models/pet.rb b/activerecord/test/models/pet.rb index 53489fa1b3..51a3e42815 100644 --- a/activerecord/test/models/pet.rb +++ b/activerecord/test/models/pet.rb @@ -2,11 +2,11 @@ class Pet < ActiveRecord::Base attr_accessor :current_user self.primary_key = :pet_id - belongs_to :owner, :touch => true + belongs_to :owner, touch: true has_many :toys has_many :pet_treasures has_many :treasures, through: :pet_treasures - has_many :persons, through: :treasures, source: :looter, source_type: 'Person' + has_many :persons, through: :treasures, source: :looter, source_type: "Person" class << self attr_accessor :after_destroy_output diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index 30545bdcd7..2dc8f9bd84 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -1,47 +1,47 @@ class Pirate < ActiveRecord::Base - belongs_to :parrot, :validate => true - belongs_to :non_validated_parrot, :class_name => 'Parrot' - has_and_belongs_to_many :parrots, -> { order('parrots.id ASC') }, :validate => true - has_and_belongs_to_many :non_validated_parrots, :class_name => 'Parrot' - has_and_belongs_to_many :parrots_with_method_callbacks, :class_name => "Parrot", - :before_add => :log_before_add, - :after_add => :log_after_add, - :before_remove => :log_before_remove, - :after_remove => :log_after_remove - has_and_belongs_to_many :parrots_with_proc_callbacks, :class_name => "Parrot", - :before_add => proc {|p,pa| p.ship_log << "before_adding_proc_parrot_#{pa.id || '<new>'}"}, - :after_add => proc {|p,pa| p.ship_log << "after_adding_proc_parrot_#{pa.id || '<new>'}"}, - :before_remove => proc {|p,pa| p.ship_log << "before_removing_proc_parrot_#{pa.id}"}, - :after_remove => proc {|p,pa| p.ship_log << "after_removing_proc_parrot_#{pa.id}"} + belongs_to :parrot, validate: true + belongs_to :non_validated_parrot, class_name: "Parrot" + has_and_belongs_to_many :parrots, -> { order("parrots.id ASC") }, validate: true + has_and_belongs_to_many :non_validated_parrots, class_name: "Parrot" + has_and_belongs_to_many :parrots_with_method_callbacks, class_name: "Parrot", + before_add: :log_before_add, + after_add: :log_after_add, + before_remove: :log_before_remove, + after_remove: :log_after_remove + has_and_belongs_to_many :parrots_with_proc_callbacks, class_name: "Parrot", + before_add: proc { |p,pa| p.ship_log << "before_adding_proc_parrot_#{pa.id || '<new>'}" }, + after_add: proc { |p,pa| p.ship_log << "after_adding_proc_parrot_#{pa.id || '<new>'}" }, + before_remove: proc { |p,pa| p.ship_log << "before_removing_proc_parrot_#{pa.id}" }, + after_remove: proc { |p,pa| p.ship_log << "after_removing_proc_parrot_#{pa.id}" } has_and_belongs_to_many :autosaved_parrots, class_name: "Parrot", autosave: true - has_many :treasures, :as => :looter - has_many :treasure_estimates, :through => :treasures, :source => :price_estimates + has_many :treasures, as: :looter + has_many :treasure_estimates, through: :treasures, source: :price_estimates has_one :ship - has_one :update_only_ship, :class_name => 'Ship' - has_one :non_validated_ship, :class_name => 'Ship' - has_many :birds, -> { order('birds.id ASC') } - has_many :birds_with_method_callbacks, :class_name => "Bird", - :before_add => :log_before_add, - :after_add => :log_after_add, - :before_remove => :log_before_remove, - :after_remove => :log_after_remove - has_many :birds_with_proc_callbacks, :class_name => "Bird", - :before_add => proc {|p,b| p.ship_log << "before_adding_proc_bird_#{b.id || '<new>'}"}, - :after_add => proc {|p,b| p.ship_log << "after_adding_proc_bird_#{b.id || '<new>'}"}, - :before_remove => proc {|p,b| p.ship_log << "before_removing_proc_bird_#{b.id}"}, - :after_remove => proc {|p,b| p.ship_log << "after_removing_proc_bird_#{b.id}"} - has_many :birds_with_reject_all_blank, :class_name => "Bird" + has_one :update_only_ship, class_name: "Ship" + has_one :non_validated_ship, class_name: "Ship" + has_many :birds, -> { order("birds.id ASC") } + has_many :birds_with_method_callbacks, class_name: "Bird", + before_add: :log_before_add, + after_add: :log_after_add, + before_remove: :log_before_remove, + after_remove: :log_after_remove + has_many :birds_with_proc_callbacks, class_name: "Bird", + before_add: proc { |p,b| p.ship_log << "before_adding_proc_bird_#{b.id || '<new>'}" }, + after_add: proc { |p,b| p.ship_log << "after_adding_proc_bird_#{b.id || '<new>'}" }, + before_remove: proc { |p,b| p.ship_log << "before_removing_proc_bird_#{b.id}" }, + after_remove: proc { |p,b| p.ship_log << "after_removing_proc_bird_#{b.id}" } + has_many :birds_with_reject_all_blank, class_name: "Bird" - has_one :foo_bulb, -> { where :name => 'foo' }, :foreign_key => :car_id, :class_name => "Bulb" + has_one :foo_bulb, -> { where name: "foo" }, foreign_key: :car_id, class_name: "Bulb" - accepts_nested_attributes_for :parrots, :birds, :allow_destroy => true, :reject_if => proc(&:empty?) - accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc(&:empty?) - accepts_nested_attributes_for :update_only_ship, :update_only => true + accepts_nested_attributes_for :parrots, :birds, allow_destroy: true, reject_if: proc(&:empty?) + accepts_nested_attributes_for :ship, allow_destroy: true, reject_if: proc(&:empty?) + accepts_nested_attributes_for :update_only_ship, update_only: true accepts_nested_attributes_for :parrots_with_method_callbacks, :parrots_with_proc_callbacks, - :birds_with_method_callbacks, :birds_with_proc_callbacks, :allow_destroy => true - accepts_nested_attributes_for :birds_with_reject_all_blank, :reject_if => :all_blank + :birds_with_method_callbacks, :birds_with_proc_callbacks, allow_destroy: true + accepts_nested_attributes_for :birds_with_reject_all_blank, reject_if: :all_blank validates_presence_of :catchphrase @@ -50,11 +50,11 @@ class Pirate < ActiveRecord::Base end def reject_empty_ships_on_create(attributes) - attributes.delete('_reject_me_if_new').present? && !persisted? + attributes.delete("_reject_me_if_new").present? && !persisted? end attr_accessor :cancel_save_from_callback, :parrots_limit - before_save :cancel_save_callback_method, :if => :cancel_save_from_callback + before_save :cancel_save_callback_method, if: :cancel_save_from_callback def cancel_save_callback_method throw(:abort) end @@ -82,11 +82,11 @@ class Pirate < ActiveRecord::Base end class DestructivePirate < Pirate - has_one :dependent_ship, :class_name => 'Ship', :foreign_key => :pirate_id, :dependent => :destroy + has_one :dependent_ship, class_name: "Ship", foreign_key: :pirate_id, dependent: :destroy end class FamousPirate < ActiveRecord::Base - self.table_name = 'pirates' + self.table_name = "pirates" has_many :famous_ships validates_presence_of :catchphrase, on: :conference end diff --git a/activerecord/test/models/possession.rb b/activerecord/test/models/possession.rb index ddf759113b..0226336c16 100644 --- a/activerecord/test/models/possession.rb +++ b/activerecord/test/models/possession.rb @@ -1,3 +1,3 @@ class Possession < ActiveRecord::Base - self.table_name = 'having' + self.table_name = "having" end diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index bf3079a1df..66a99cbcda 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -7,7 +7,7 @@ class Post < ActiveRecord::Base module NamedExtension def author - 'lifo' + "lifo" end end @@ -21,22 +21,23 @@ class Post < ActiveRecord::Base scope :titled_with_an_apostrophe, -> { where("title LIKE '%''%'") } scope :ranked_by_comments, -> { order("comments_count DESC") } - scope :limit_by, lambda {|l| limit(l) } + scope :limit_by, lambda { |l| limit(l) } belongs_to :author + belongs_to :readonly_author, -> { readonly }, class_name: "Author", foreign_key: :author_id - belongs_to :author_with_posts, -> { includes(:posts) }, :class_name => "Author", :foreign_key => :author_id - belongs_to :author_with_address, -> { includes(:author_address) }, :class_name => "Author", :foreign_key => :author_id + belongs_to :author_with_posts, -> { includes(:posts) }, class_name: "Author", foreign_key: :author_id + belongs_to :author_with_address, -> { includes(:author_address) }, class_name: "Author", foreign_key: :author_id def first_comment super.body end - has_one :first_comment, -> { order('id ASC') }, :class_name => 'Comment' - has_one :last_comment, -> { order('id desc') }, :class_name => 'Comment' + has_one :first_comment, -> { order("id ASC") }, class_name: "Comment" + has_one :last_comment, -> { order("id desc") }, class_name: "Comment" - scope :with_special_comments, -> { joins(:comments).where(:comments => {:type => 'SpecialComment'}) } - scope :with_very_special_comments, -> { joins(:comments).where(:comments => {:type => 'VerySpecialComment'}) } - scope :with_post, ->(post_id) { joins(:comments).where(:comments => { :post_id => post_id }) } + scope :with_special_comments, -> { joins(:comments).where(comments: { type: "SpecialComment" }) } + scope :with_very_special_comments, -> { joins(:comments).where(comments: { type: "VerySpecialComment" }) } + scope :with_post, ->(post_id) { joins(:comments).where(comments: { post_id: post_id }) } scope :with_comments, -> { preload(:comments) } scope :with_tags, -> { preload(:taggings) } @@ -68,92 +69,92 @@ class Post < ActiveRecord::Base has_many :comments_with_extend_2, extend: [NamedExtension, NamedExtension2], class_name: "Comment", foreign_key: "post_id" - has_many :author_favorites, :through => :author - has_many :author_categorizations, :through => :author, :source => :categorizations - has_many :author_addresses, :through => :author + has_many :author_favorites, through: :author + has_many :author_categorizations, through: :author, source: :categorizations + has_many :author_addresses, through: :author has_many :author_address_extra_with_address, through: :author_with_address, source: :author_address_extra has_one :very_special_comment - has_one :very_special_comment_with_post, -> { includes(:post) }, :class_name => "VerySpecialComment" - has_one :very_special_comment_with_post_with_joins, -> { joins(:post).order('posts.id') }, class_name: "VerySpecialComment" + has_one :very_special_comment_with_post, -> { includes(:post) }, class_name: "VerySpecialComment" + has_one :very_special_comment_with_post_with_joins, -> { joins(:post).order("posts.id") }, class_name: "VerySpecialComment" has_many :special_comments - has_many :nonexistent_comments, -> { where 'comments.id < 0' }, :class_name => 'Comment' + has_many :nonexistent_comments, -> { where "comments.id < 0" }, class_name: "Comment" - has_many :special_comments_ratings, :through => :special_comments, :source => :ratings - has_many :special_comments_ratings_taggings, :through => :special_comments_ratings, :source => :taggings + has_many :special_comments_ratings, through: :special_comments, source: :ratings + has_many :special_comments_ratings_taggings, through: :special_comments_ratings, source: :taggings - has_many :category_posts, :class_name => 'CategoryPost' + has_many :category_posts, class_name: "CategoryPost" has_many :scategories, through: :category_posts, source: :category has_and_belongs_to_many :categories - has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id' + has_and_belongs_to_many :special_categories, join_table: "categories_posts", association_foreign_key: "category_id" - has_many :taggings, :as => :taggable, :counter_cache => :tags_count - has_many :tags, :through => :taggings do + has_many :taggings, as: :taggable, counter_cache: :tags_count + has_many :tags, through: :taggings do def add_joins_and_select - select('tags.*, authors.id as author_id') - .joins('left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id') + select("tags.*, authors.id as author_id") + .joins("left outer join posts on taggings.taggable_id = posts.id left outer join authors on posts.author_id = authors.id") .to_a end end - has_many :taggings_with_delete_all, :class_name => 'Tagging', :as => :taggable, :dependent => :delete_all, counter_cache: :taggings_with_delete_all_count - has_many :taggings_with_destroy, :class_name => 'Tagging', :as => :taggable, :dependent => :destroy, counter_cache: :taggings_with_destroy_count + has_many :taggings_with_delete_all, class_name: "Tagging", as: :taggable, dependent: :delete_all, counter_cache: :taggings_with_delete_all_count + has_many :taggings_with_destroy, class_name: "Tagging", as: :taggable, dependent: :destroy, counter_cache: :taggings_with_destroy_count - has_many :tags_with_destroy, :through => :taggings, :source => :tag, :dependent => :destroy, counter_cache: :tags_with_destroy_count - has_many :tags_with_nullify, :through => :taggings, :source => :tag, :dependent => :nullify, counter_cache: :tags_with_nullify_count + has_many :tags_with_destroy, through: :taggings, source: :tag, dependent: :destroy, counter_cache: :tags_with_destroy_count + has_many :tags_with_nullify, through: :taggings, source: :tag, dependent: :nullify, counter_cache: :tags_with_nullify_count - has_many :misc_tags, -> { where :tags => { :name => 'Misc' } }, :through => :taggings, :source => :tag - has_many :funky_tags, :through => :taggings, :source => :tag - has_many :super_tags, :through => :taggings - has_many :tags_with_primary_key, :through => :taggings, :source => :tag_with_primary_key - has_one :tagging, :as => :taggable + has_many :misc_tags, -> { where tags: { name: "Misc" } }, through: :taggings, source: :tag + has_many :funky_tags, through: :taggings, source: :tag + has_many :super_tags, through: :taggings + has_many :tags_with_primary_key, through: :taggings, source: :tag_with_primary_key + has_one :tagging, as: :taggable - has_many :first_taggings, -> { where :taggings => { :comment => 'first' } }, :as => :taggable, :class_name => 'Tagging' - has_many :first_blue_tags, -> { where :tags => { :name => 'Blue' } }, :through => :first_taggings, :source => :tag + has_many :first_taggings, -> { where taggings: { comment: "first" } }, as: :taggable, class_name: "Tagging" + has_many :first_blue_tags, -> { where tags: { name: "Blue" } }, through: :first_taggings, source: :tag - has_many :first_blue_tags_2, -> { where :taggings => { :comment => 'first' } }, :through => :taggings, :source => :blue_tag + has_many :first_blue_tags_2, -> { where taggings: { comment: "first" } }, through: :taggings, source: :blue_tag - has_many :invalid_taggings, -> { where 'taggings.id < 0' }, :as => :taggable, :class_name => "Tagging" - has_many :invalid_tags, :through => :invalid_taggings, :source => :tag + has_many :invalid_taggings, -> { where "taggings.id < 0" }, as: :taggable, class_name: "Tagging" + has_many :invalid_tags, through: :invalid_taggings, source: :tag - has_many :categorizations, :foreign_key => :category_id - has_many :authors, :through => :categorizations + has_many :categorizations, foreign_key: :category_id + has_many :authors, through: :categorizations - has_many :categorizations_using_author_id, :primary_key => :author_id, :foreign_key => :post_id, :class_name => 'Categorization' - has_many :authors_using_author_id, :through => :categorizations_using_author_id, :source => :author + has_many :categorizations_using_author_id, primary_key: :author_id, foreign_key: :post_id, class_name: "Categorization" + has_many :authors_using_author_id, through: :categorizations_using_author_id, source: :author - has_many :taggings_using_author_id, :primary_key => :author_id, :as => :taggable, :class_name => 'Tagging' - has_many :tags_using_author_id, :through => :taggings_using_author_id, :source => :tag + has_many :taggings_using_author_id, primary_key: :author_id, as: :taggable, class_name: "Tagging" + has_many :tags_using_author_id, through: :taggings_using_author_id, source: :tag - has_many :images, :as => :imageable, :foreign_key => :imageable_identifier, :foreign_type => :imageable_class - has_one :main_image, :as => :imageable, :foreign_key => :imageable_identifier, :foreign_type => :imageable_class, :class_name => 'Image' + has_many :images, as: :imageable, foreign_key: :imageable_identifier, foreign_type: :imageable_class + has_one :main_image, as: :imageable, foreign_key: :imageable_identifier, foreign_type: :imageable_class, class_name: "Image" - has_many :standard_categorizations, :class_name => 'Categorization', :foreign_key => :post_id - has_many :author_using_custom_pk, :through => :standard_categorizations - has_many :authors_using_custom_pk, :through => :standard_categorizations - has_many :named_categories, :through => :standard_categorizations + has_many :standard_categorizations, class_name: "Categorization", foreign_key: :post_id + has_many :author_using_custom_pk, through: :standard_categorizations + has_many :authors_using_custom_pk, through: :standard_categorizations + has_many :named_categories, through: :standard_categorizations has_many :readers has_many :secure_readers - has_many :readers_with_person, -> { includes(:person) }, :class_name => "Reader" - has_many :people, :through => :readers - has_many :single_people, :through => :readers - has_many :people_with_callbacks, :source=>:person, :through => :readers, - :before_add => lambda {|owner, reader| log(:added, :before, reader.first_name) }, - :after_add => lambda {|owner, reader| log(:added, :after, reader.first_name) }, - :before_remove => lambda {|owner, reader| log(:removed, :before, reader.first_name) }, - :after_remove => lambda {|owner, reader| log(:removed, :after, reader.first_name) } - has_many :skimmers, -> { where :skimmer => true }, :class_name => 'Reader' - has_many :impatient_people, :through => :skimmers, :source => :person + has_many :readers_with_person, -> { includes(:person) }, class_name: "Reader" + has_many :people, through: :readers + has_many :single_people, through: :readers + has_many :people_with_callbacks, source: :person, through: :readers, + before_add: lambda { |owner, reader| log(:added, :before, reader.first_name) }, + after_add: lambda { |owner, reader| log(:added, :after, reader.first_name) }, + before_remove: lambda { |owner, reader| log(:removed, :before, reader.first_name) }, + after_remove: lambda { |owner, reader| log(:removed, :after, reader.first_name) } + has_many :skimmers, -> { where skimmer: true }, class_name: "Reader" + has_many :impatient_people, through: :skimmers, source: :person has_many :lazy_readers - has_many :lazy_readers_skimmers_or_not, -> { where(skimmer: [ true, false ]) }, :class_name => 'LazyReader' + has_many :lazy_readers_skimmers_or_not, -> { where(skimmer: [ true, false ]) }, class_name: "LazyReader" - has_many :lazy_people, :through => :lazy_readers, :source => :person - has_many :lazy_readers_unscope_skimmers, -> { skimmers_or_not }, :class_name => 'LazyReader' - has_many :lazy_people_unscope_skimmers, :through => :lazy_readers_unscope_skimmers, :source => :person + has_many :lazy_people, through: :lazy_readers, source: :person + has_many :lazy_readers_unscope_skimmers, -> { skimmers_or_not }, class_name: "LazyReader" + has_many :lazy_people_unscope_skimmers, through: :lazy_readers_unscope_skimmers, source: :person def self.top(limit) ranked_by_comments.limit_by(limit) @@ -177,7 +178,7 @@ class SpecialPost < Post; end class StiPost < Post self.abstract_class = true - has_one :special_comment, :class_name => "SpecialComment" + has_one :special_comment, class_name: "SpecialComment" end class SubStiPost < StiPost @@ -186,56 +187,56 @@ end class FirstPost < ActiveRecord::Base self.inheritance_column = :disabled - self.table_name = 'posts' - default_scope { where(:id => 1) } + self.table_name = "posts" + default_scope { where(id: 1) } - has_many :comments, :foreign_key => :post_id - has_one :comment, :foreign_key => :post_id + has_many :comments, foreign_key: :post_id + has_one :comment, foreign_key: :post_id end class PostWithDefaultInclude < ActiveRecord::Base self.inheritance_column = :disabled - self.table_name = 'posts' + self.table_name = "posts" default_scope { includes(:comments) } - has_many :comments, :foreign_key => :post_id + has_many :comments, foreign_key: :post_id end class PostWithSpecialCategorization < Post - has_many :categorizations, :foreign_key => :post_id - default_scope { where(:type => 'PostWithSpecialCategorization').joins(:categorizations).where(:categorizations => { :special => true }) } + has_many :categorizations, foreign_key: :post_id + default_scope { where(type: "PostWithSpecialCategorization").joins(:categorizations).where(categorizations: { special: true }) } end class PostWithDefaultScope < ActiveRecord::Base self.inheritance_column = :disabled - self.table_name = 'posts' + self.table_name = "posts" default_scope { order(:title) } end class PostWithPreloadDefaultScope < ActiveRecord::Base - self.table_name = 'posts' + self.table_name = "posts" - has_many :readers, foreign_key: 'post_id' + has_many :readers, foreign_key: "post_id" default_scope { preload(:readers) } end class PostWithIncludesDefaultScope < ActiveRecord::Base - self.table_name = 'posts' + self.table_name = "posts" - has_many :readers, foreign_key: 'post_id' + has_many :readers, foreign_key: "post_id" default_scope { includes(:readers) } end class SpecialPostWithDefaultScope < ActiveRecord::Base self.inheritance_column = :disabled - self.table_name = 'posts' - default_scope { where(:id => [1, 5,6]) } + self.table_name = "posts" + default_scope { where(id: [1, 5,6]) } end class PostThatLoadsCommentsInAnAfterSaveHook < ActiveRecord::Base self.inheritance_column = :disabled - self.table_name = 'posts' + self.table_name = "posts" has_many :comments, class_name: "CommentThatAutomaticallyAltersPostBody", foreign_key: :post_id after_save do |post| @@ -245,7 +246,7 @@ end class PostWithAfterCreateCallback < ActiveRecord::Base self.inheritance_column = :disabled - self.table_name = 'posts' + self.table_name = "posts" has_many :comments, foreign_key: :post_id after_create do |post| @@ -255,7 +256,7 @@ end class PostWithCommentWithDefaultScopeReferencesAssociation < ActiveRecord::Base self.inheritance_column = :disabled - self.table_name = 'posts' + self.table_name = "posts" has_many :comment_with_default_scope_references_associations, foreign_key: :post_id has_one :first_comment, class_name: "CommentWithDefaultScopeReferencesAssociation", foreign_key: :post_id end @@ -265,7 +266,7 @@ class SerializedPost < ActiveRecord::Base end class ConditionalStiPost < Post - default_scope { where(title: 'Untitled') } + default_scope { where(title: "Untitled") } end class SubConditionalStiPost < ConditionalStiPost diff --git a/activerecord/test/models/price_estimate.rb b/activerecord/test/models/price_estimate.rb index d09e2a88a3..ce086e40a3 100644 --- a/activerecord/test/models/price_estimate.rb +++ b/activerecord/test/models/price_estimate.rb @@ -1,4 +1,4 @@ class PriceEstimate < ActiveRecord::Base - belongs_to :estimate_of, :polymorphic => true + belongs_to :estimate_of, polymorphic: true belongs_to :thing, polymorphic: true end diff --git a/activerecord/test/models/professor.rb b/activerecord/test/models/professor.rb index 7654eda0ef..4dfb1a9602 100644 --- a/activerecord/test/models/professor.rb +++ b/activerecord/test/models/professor.rb @@ -1,4 +1,4 @@ -require_dependency 'models/arunit2_model' +require_dependency "models/arunit2_model" class Professor < ARUnit2Model has_and_belongs_to_many :courses diff --git a/activerecord/test/models/project.rb b/activerecord/test/models/project.rb index efa8246f1e..5009f8f54b 100644 --- a/activerecord/test/models/project.rb +++ b/activerecord/test/models/project.rb @@ -1,17 +1,17 @@ class Project < ActiveRecord::Base belongs_to :mentor - has_and_belongs_to_many :developers, -> { distinct.order 'developers.name desc, developers.id desc' } - has_and_belongs_to_many :readonly_developers, -> { readonly }, :class_name => "Developer" - has_and_belongs_to_many :non_unique_developers, -> { order 'developers.name desc, developers.id desc' }, :class_name => 'Developer' - has_and_belongs_to_many :limited_developers, -> { limit 1 }, :class_name => "Developer" - has_and_belongs_to_many :developers_named_david, -> { where("name = 'David'").distinct }, :class_name => "Developer" - has_and_belongs_to_many :developers_named_david_with_hash_conditions, -> { where(:name => 'David').distinct }, :class_name => "Developer" - has_and_belongs_to_many :salaried_developers, -> { where "salary > 0" }, :class_name => "Developer" - has_and_belongs_to_many :developers_with_callbacks, :class_name => "Developer", :before_add => Proc.new {|o, r| o.developers_log << "before_adding#{r.id || '<new>'}"}, - :after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id || '<new>'}"}, - :before_remove => Proc.new {|o, r| o.developers_log << "before_removing#{r.id}"}, - :after_remove => Proc.new {|o, r| o.developers_log << "after_removing#{r.id}"} - has_and_belongs_to_many :well_payed_salary_groups, -> { group("developers.salary").having("SUM(salary) > 10000").select("SUM(salary) as salary") }, :class_name => "Developer" + has_and_belongs_to_many :developers, -> { distinct.order "developers.name desc, developers.id desc" } + has_and_belongs_to_many :readonly_developers, -> { readonly }, class_name: "Developer" + has_and_belongs_to_many :non_unique_developers, -> { order "developers.name desc, developers.id desc" }, class_name: "Developer" + has_and_belongs_to_many :limited_developers, -> { limit 1 }, class_name: "Developer" + has_and_belongs_to_many :developers_named_david, -> { where("name = 'David'").distinct }, class_name: "Developer" + has_and_belongs_to_many :developers_named_david_with_hash_conditions, -> { where(name: "David").distinct }, class_name: "Developer" + has_and_belongs_to_many :salaried_developers, -> { where "salary > 0" }, class_name: "Developer" + has_and_belongs_to_many :developers_with_callbacks, class_name: "Developer", before_add: Proc.new { |o, r| o.developers_log << "before_adding#{r.id || '<new>'}" }, + after_add: Proc.new { |o, r| o.developers_log << "after_adding#{r.id || '<new>'}" }, + before_remove: Proc.new { |o, r| o.developers_log << "before_removing#{r.id}" }, + after_remove: Proc.new { |o, r| o.developers_log << "after_removing#{r.id}" } + has_and_belongs_to_many :well_payed_salary_groups, -> { group("developers.salary").having("SUM(salary) > 10000").select("SUM(salary) as salary") }, class_name: "Developer" belongs_to :firm has_one :lead_developer, through: :firm, inverse_of: :contracted_projects diff --git a/activerecord/test/models/rating.rb b/activerecord/test/models/rating.rb index 25a52c4ad7..7420821db0 100644 --- a/activerecord/test/models/rating.rb +++ b/activerecord/test/models/rating.rb @@ -1,4 +1,4 @@ class Rating < ActiveRecord::Base belongs_to :comment - has_many :taggings, :as => :taggable + has_many :taggings, as: :taggable end diff --git a/activerecord/test/models/reader.rb b/activerecord/test/models/reader.rb index 91afc1898c..7c5a159fe0 100644 --- a/activerecord/test/models/reader.rb +++ b/activerecord/test/models/reader.rb @@ -1,22 +1,22 @@ class Reader < ActiveRecord::Base belongs_to :post - belongs_to :person, :inverse_of => :readers - belongs_to :single_person, :class_name => 'Person', :foreign_key => :person_id, :inverse_of => :reader + belongs_to :person, inverse_of: :readers + belongs_to :single_person, class_name: "Person", foreign_key: :person_id, inverse_of: :reader belongs_to :first_post, -> { where(id: [2, 3]) } end class SecureReader < ActiveRecord::Base self.table_name = "readers" - belongs_to :secure_post, :class_name => "Post", :foreign_key => "post_id" - belongs_to :secure_person, :inverse_of => :secure_readers, :class_name => "Person", :foreign_key => "person_id" + belongs_to :secure_post, class_name: "Post", foreign_key: "post_id" + belongs_to :secure_person, inverse_of: :secure_readers, class_name: "Person", foreign_key: "person_id" end class LazyReader < ActiveRecord::Base self.table_name = "readers" default_scope -> { where(skimmer: true) } - scope :skimmers_or_not, -> { unscope(:where => :skimmer) } + scope :skimmers_or_not, -> { unscope(where: :skimmer) } belongs_to :post belongs_to :person diff --git a/activerecord/test/models/reference.rb b/activerecord/test/models/reference.rb index c2f9068f57..e2bb980fed 100644 --- a/activerecord/test/models/reference.rb +++ b/activerecord/test/models/reference.rb @@ -2,7 +2,7 @@ class Reference < ActiveRecord::Base belongs_to :person belongs_to :job - has_many :agents_posts_authors, :through => :person + has_many :agents_posts_authors, through: :person class << self; attr_accessor :make_comments; end self.make_comments = false @@ -17,6 +17,6 @@ class Reference < ActiveRecord::Base end class BadReference < ActiveRecord::Base - self.table_name = 'references' - default_scope { where(:favourite => false) } + self.table_name = "references" + default_scope { where(favourite: false) } end diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb index 3e82e55d89..a2d169292a 100644 --- a/activerecord/test/models/reply.rb +++ b/activerecord/test/models/reply.rb @@ -1,14 +1,14 @@ -require 'models/topic' +require "models/topic" class Reply < Topic - belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true - belongs_to :topic_with_primary_key, :class_name => "Topic", :primary_key => "title", :foreign_key => "parent_title", :counter_cache => "replies_count" - has_many :replies, :class_name => "SillyReply", :dependent => :destroy, :foreign_key => "parent_id" + belongs_to :topic, foreign_key: "parent_id", counter_cache: true + belongs_to :topic_with_primary_key, class_name: "Topic", primary_key: "title", foreign_key: "parent_title", counter_cache: "replies_count" + has_many :replies, class_name: "SillyReply", dependent: :destroy, foreign_key: "parent_id" end class UniqueReply < Reply - belongs_to :topic, :foreign_key => 'parent_id', :counter_cache => true - validates_uniqueness_of :content, :scope => 'parent_id' + belongs_to :topic, foreign_key: "parent_id", counter_cache: true + validates_uniqueness_of :content, scope: "parent_id" end class SillyUniqueReply < UniqueReply @@ -16,12 +16,12 @@ end class WrongReply < Reply validate :errors_on_empty_content - validate :title_is_wrong_create, :on => :create + validate :title_is_wrong_create, on: :create validate :check_empty_title - validate :check_content_mismatch, :on => :create - validate :check_wrong_update, :on => :update - validate :check_author_name_is_secret, :on => :special_case + validate :check_content_mismatch, on: :create + validate :check_wrong_update, on: :update + validate :check_author_name_is_secret, on: :special_case def check_empty_title errors[:title] << "Empty" unless attribute_present?("title") @@ -51,11 +51,11 @@ class WrongReply < Reply end class SillyReply < Reply - belongs_to :reply, :foreign_key => "parent_id", :counter_cache => :replies_count + belongs_to :reply, foreign_key: "parent_id", counter_cache: :replies_count end module Web class Reply < Web::Topic - belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true, :class_name => 'Web::Topic' + belongs_to :topic, foreign_key: "parent_id", counter_cache: true, class_name: "Web::Topic" end end diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb index e333b964ab..77a7b22315 100644 --- a/activerecord/test/models/ship.rb +++ b/activerecord/test/models/ship.rb @@ -2,19 +2,19 @@ class Ship < ActiveRecord::Base self.record_timestamps = false belongs_to :pirate - belongs_to :update_only_pirate, :class_name => 'Pirate' + belongs_to :update_only_pirate, class_name: "Pirate" belongs_to :developer, dependent: :destroy - has_many :parts, :class_name => 'ShipPart' + has_many :parts, class_name: "ShipPart" has_many :treasures - accepts_nested_attributes_for :parts, :allow_destroy => true - accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc(&:empty?) - accepts_nested_attributes_for :update_only_pirate, :update_only => true + accepts_nested_attributes_for :parts, allow_destroy: true + accepts_nested_attributes_for :pirate, allow_destroy: true, reject_if: proc(&:empty?) + accepts_nested_attributes_for :update_only_pirate, update_only: true validates_presence_of :name attr_accessor :cancel_save_from_callback - before_save :cancel_save_callback_method, :if => :cancel_save_from_callback + before_save :cancel_save_callback_method, if: :cancel_save_from_callback def cancel_save_callback_method throw(:abort) end @@ -33,7 +33,7 @@ class Prisoner < ActiveRecord::Base end class FamousShip < ActiveRecord::Base - self.table_name = 'ships' + self.table_name = "ships" belongs_to :famous_pirate validates_presence_of :name, on: :conference end diff --git a/activerecord/test/models/ship_part.rb b/activerecord/test/models/ship_part.rb index 05c65f8a4a..1a633b8d77 100644 --- a/activerecord/test/models/ship_part.rb +++ b/activerecord/test/models/ship_part.rb @@ -1,7 +1,7 @@ class ShipPart < ActiveRecord::Base belongs_to :ship - has_many :trinkets, :class_name => "Treasure", :as => :looter - accepts_nested_attributes_for :trinkets, :allow_destroy => true + has_many :trinkets, class_name: "Treasure", as: :looter + accepts_nested_attributes_for :trinkets, allow_destroy: true accepts_nested_attributes_for :ship validates_presence_of :name diff --git a/activerecord/test/models/shop.rb b/activerecord/test/models/shop.rb index 607a0a5b41..f9d23d13b0 100644 --- a/activerecord/test/models/shop.rb +++ b/activerecord/test/models/shop.rb @@ -1,10 +1,10 @@ module Shop class Collection < ActiveRecord::Base - has_many :products, :dependent => :nullify + has_many :products, dependent: :nullify end class Product < ActiveRecord::Base - has_many :variants, :dependent => :delete_all + has_many :variants, dependent: :delete_all belongs_to :type class Type < ActiveRecord::Base diff --git a/activerecord/test/models/sponsor.rb b/activerecord/test/models/sponsor.rb index ec3dcf8a97..3f142b25fe 100644 --- a/activerecord/test/models/sponsor.rb +++ b/activerecord/test/models/sponsor.rb @@ -1,7 +1,7 @@ class Sponsor < ActiveRecord::Base - belongs_to :sponsor_club, :class_name => "Club", :foreign_key => "club_id" - belongs_to :sponsorable, :polymorphic => true - belongs_to :thing, :polymorphic => true, :foreign_type => :sponsorable_type, :foreign_key => :sponsorable_id - belongs_to :sponsorable_with_conditions, -> { where :name => 'Ernie'}, :polymorphic => true, - :foreign_type => 'sponsorable_type', :foreign_key => 'sponsorable_id' + belongs_to :sponsor_club, class_name: "Club", foreign_key: "club_id" + belongs_to :sponsorable, polymorphic: true + belongs_to :thing, polymorphic: true, foreign_type: :sponsorable_type, foreign_key: :sponsorable_id + belongs_to :sponsorable_with_conditions, -> { where name: "Ernie" }, polymorphic: true, + foreign_type: "sponsorable_type", foreign_key: "sponsorable_id" end diff --git a/activerecord/test/models/subject.rb b/activerecord/test/models/subject.rb index 8e28f8b86b..29e290825e 100644 --- a/activerecord/test/models/subject.rb +++ b/activerecord/test/models/subject.rb @@ -1,16 +1,14 @@ # used for OracleSynonymTest, see test/synonym_test_oracle.rb # class Subject < ActiveRecord::Base - # added initialization of author_email_address in the same way as in Topic class # as otherwise synonym test was failing after_initialize :set_email_address protected def set_email_address - unless self.persisted? - self.author_email_address = 'test@test.com' + unless persisted? + self.author_email_address = "test@test.com" end end - end diff --git a/activerecord/test/models/subscriber.rb b/activerecord/test/models/subscriber.rb index 76e85a0cd3..a820329003 100644 --- a/activerecord/test/models/subscriber.rb +++ b/activerecord/test/models/subscriber.rb @@ -1,7 +1,7 @@ class Subscriber < ActiveRecord::Base - self.primary_key = 'nick' + self.primary_key = "nick" has_many :subscriptions - has_many :books, :through => :subscriptions + has_many :books, through: :subscriptions end class SpecialSubscriber < Subscriber diff --git a/activerecord/test/models/subscription.rb b/activerecord/test/models/subscription.rb index bcac4738a3..1cedf6deae 100644 --- a/activerecord/test/models/subscription.rb +++ b/activerecord/test/models/subscription.rb @@ -1,4 +1,4 @@ class Subscription < ActiveRecord::Base - belongs_to :subscriber, :counter_cache => :books_count + belongs_to :subscriber, counter_cache: :books_count belongs_to :book end diff --git a/activerecord/test/models/tag.rb b/activerecord/test/models/tag.rb index b48b9a2155..c907aea10f 100644 --- a/activerecord/test/models/tag.rb +++ b/activerecord/test/models/tag.rb @@ -1,13 +1,13 @@ class Tag < ActiveRecord::Base has_many :taggings - has_many :taggables, :through => :taggings + has_many :taggables, through: :taggings has_one :tagging - has_many :tagged_posts, :through => :taggings, :source => 'taggable', :source_type => 'Post' + has_many :tagged_posts, through: :taggings, source: "taggable", source_type: "Post" end class OrderedTag < Tag self.table_name = "tags" - has_many :taggings, -> { order('taggings.id DESC') }, foreign_key: 'tag_id' + has_many :taggings, -> { order("taggings.id DESC") }, foreign_key: "tag_id" end diff --git a/activerecord/test/models/tagging.rb b/activerecord/test/models/tagging.rb index a6c05da26a..f739b4a197 100644 --- a/activerecord/test/models/tagging.rb +++ b/activerecord/test/models/tagging.rb @@ -4,10 +4,10 @@ end class Tagging < ActiveRecord::Base belongs_to :tag, -> { includes(:tagging) } - belongs_to :super_tag, :class_name => 'Tag', :foreign_key => 'super_tag_id' - belongs_to :invalid_tag, :class_name => 'Tag', :foreign_key => 'tag_id' - belongs_to :blue_tag, -> { where :tags => { :name => 'Blue' } }, :class_name => 'Tag', :foreign_key => :tag_id - belongs_to :tag_with_primary_key, :class_name => 'Tag', :foreign_key => :tag_id, :primary_key => :custom_primary_key - belongs_to :taggable, :polymorphic => true, :counter_cache => :tags_count - has_many :things, :through => :taggable + belongs_to :super_tag, class_name: "Tag", foreign_key: "super_tag_id" + belongs_to :invalid_tag, class_name: "Tag", foreign_key: "tag_id" + belongs_to :blue_tag, -> { where tags: { name: "Blue" } }, class_name: "Tag", foreign_key: :tag_id + belongs_to :tag_with_primary_key, class_name: "Tag", foreign_key: :tag_id, primary_key: :custom_primary_key + belongs_to :taggable, polymorphic: true, counter_cache: :tags_count + has_many :things, through: :taggable end diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 176bc79dc7..db04735d01 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -2,18 +2,18 @@ class Topic < ActiveRecord::Base scope :base, -> { all } scope :written_before, lambda { |time| if time - where 'written_on < ?', time + where "written_on < ?", time end } - scope :approved, -> { where(:approved => true) } - scope :rejected, -> { where(:approved => false) } + scope :approved, -> { where(approved: true) } + scope :rejected, -> { where(approved: false) } scope :scope_with_lambda, lambda { all } - scope :by_lifo, -> { where(:author_name => 'lifo') } - scope :replied, -> { where 'replies_count > 0' } + scope :by_lifo, -> { where(author_name: "lifo") } + scope :replied, -> { where "replies_count > 0" } - scope 'approved_as_string', -> { where(:approved => true) } + scope "approved_as_string", -> { where(approved: true) } scope :anonymous_extension, -> { all } do def one 1 @@ -22,7 +22,7 @@ class Topic < ActiveRecord::Base scope :with_object, Class.new(Struct.new(:klass)) { def call - klass.where(:approved => true) + klass.where(approved: true) end }.new(self) @@ -33,22 +33,16 @@ class Topic < ActiveRecord::Base end has_many :replies, dependent: :destroy, foreign_key: "parent_id", autosave: true - has_many :approved_replies, -> { approved }, class_name: 'Reply', foreign_key: "parent_id", counter_cache: 'replies_count' + has_many :approved_replies, -> { approved }, class_name: "Reply", foreign_key: "parent_id", counter_cache: "replies_count" - has_many :unique_replies, :dependent => :destroy, :foreign_key => "parent_id" - has_many :silly_unique_replies, :dependent => :destroy, :foreign_key => "parent_id" + has_many :unique_replies, dependent: :destroy, foreign_key: "parent_id" + has_many :silly_unique_replies, dependent: :destroy, foreign_key: "parent_id" serialize :content before_create :default_written_on before_destroy :destroy_children - # Explicitly define as :date column so that returned Oracle DATE values would be typecasted to Date and not Time. - # Some tests depend on assumption that this attribute will have Date values. - if current_adapter?(:OracleEnhancedAdapter) - set_date_columns :last_read - end - def parent Topic.find(parent_id) end @@ -90,8 +84,8 @@ class Topic < ActiveRecord::Base end def set_email_address - unless self.persisted? - self.author_email_address = 'test@test.com' + unless persisted? + self.author_email_address = "test@test.com" end end @@ -119,6 +113,6 @@ end module Web class Topic < ActiveRecord::Base - has_many :replies, :dependent => :destroy, :foreign_key => "parent_id", :class_name => 'Web::Reply' + has_many :replies, dependent: :destroy, foreign_key: "parent_id", class_name: "Web::Reply" end end diff --git a/activerecord/test/models/treasure.rb b/activerecord/test/models/treasure.rb index 63ff0c23ec..fb2a5d44e2 100644 --- a/activerecord/test/models/treasure.rb +++ b/activerecord/test/models/treasure.rb @@ -1,11 +1,11 @@ class Treasure < ActiveRecord::Base has_and_belongs_to_many :parrots - belongs_to :looter, :polymorphic => true + belongs_to :looter, polymorphic: true # No counter_cache option given belongs_to :ship - has_many :price_estimates, :as => :estimate_of - has_and_belongs_to_many :rich_people, join_table: 'peoples_treasures', validate: false + has_many :price_estimates, as: :estimate_of + has_and_belongs_to_many :rich_people, join_table: "peoples_treasures", validate: false accepts_nested_attributes_for :looter end diff --git a/activerecord/test/models/treaty.rb b/activerecord/test/models/treaty.rb index 41fd1350f3..373cd48f71 100644 --- a/activerecord/test/models/treaty.rb +++ b/activerecord/test/models/treaty.rb @@ -1,7 +1,5 @@ class Treaty < ActiveRecord::Base - self.primary_key = :treaty_id has_and_belongs_to_many :countries - end diff --git a/activerecord/test/models/user.rb b/activerecord/test/models/user.rb index f5dc93e994..47649e0a77 100644 --- a/activerecord/test/models/user.rb +++ b/activerecord/test/models/user.rb @@ -1,6 +1,12 @@ +require "models/job" + class User < ActiveRecord::Base has_secure_token has_secure_token :auth_token + + has_and_belongs_to_many :jobs_pool, + class_name: Job, + join_table: "jobs_pool" end class UserWithNotification < User diff --git a/activerecord/test/models/vegetables.rb b/activerecord/test/models/vegetables.rb index 1f41cde3a5..a4590d06e0 100644 --- a/activerecord/test/models/vegetables.rb +++ b/activerecord/test/models/vegetables.rb @@ -1,9 +1,8 @@ class Vegetable < ActiveRecord::Base - validates_presence_of :name def self.inheritance_column - 'custom_type' + "custom_type" end end @@ -20,5 +19,5 @@ class KingCole < GreenCabbage end class RedCabbage < Cabbage - belongs_to :seller, :class_name => 'Company' + belongs_to :seller, class_name: "Company" end diff --git a/activerecord/test/models/vehicle.rb b/activerecord/test/models/vehicle.rb index ef26170f1f..855bc4e325 100644 --- a/activerecord/test/models/vehicle.rb +++ b/activerecord/test/models/vehicle.rb @@ -4,4 +4,4 @@ class Vehicle < ActiveRecord::Base end class Bus < Vehicle -end
\ No newline at end of file +end diff --git a/activerecord/test/models/vertex.rb b/activerecord/test/models/vertex.rb index 48bb851e62..3d19433b6f 100644 --- a/activerecord/test/models/vertex.rb +++ b/activerecord/test/models/vertex.rb @@ -1,9 +1,9 @@ # This class models a vertex in a directed graph. class Vertex < ActiveRecord::Base - has_many :sink_edges, :class_name => 'Edge', :foreign_key => 'source_id' - has_many :sinks, :through => :sink_edges + has_many :sink_edges, class_name: "Edge", foreign_key: "source_id" + has_many :sinks, through: :sink_edges has_and_belongs_to_many :sources, - :class_name => 'Vertex', :join_table => 'edges', - :foreign_key => 'sink_id', :association_foreign_key => 'source_id' + class_name: "Vertex", join_table: "edges", + foreign_key: "sink_id", association_foreign_key: "source_id" end diff --git a/activerecord/test/models/wheel.rb b/activerecord/test/models/wheel.rb index 26868bce5e..cba2b3e518 100644 --- a/activerecord/test/models/wheel.rb +++ b/activerecord/test/models/wheel.rb @@ -1,3 +1,3 @@ class Wheel < ActiveRecord::Base - belongs_to :wheelable, :polymorphic => true, :counter_cache => true + belongs_to :wheelable, polymorphic: true, counter_cache: true end diff --git a/activerecord/test/models/without_table.rb b/activerecord/test/models/without_table.rb index 50c824e4ac..7c0fc286e1 100644 --- a/activerecord/test/models/without_table.rb +++ b/activerecord/test/models/without_table.rb @@ -1,3 +1,3 @@ class WithoutTable < ActiveRecord::Base - default_scope -> { where(:published => true) } + default_scope -> { where(published: true) } end diff --git a/activerecord/test/models/zine.rb b/activerecord/test/models/zine.rb index c2d0fdaf25..3f2b348b46 100644 --- a/activerecord/test/models/zine.rb +++ b/activerecord/test/models/zine.rb @@ -1,3 +1,3 @@ class Zine < ActiveRecord::Base - has_many :interests, :inverse_of => :zine + has_many :interests, inverse_of: :zine end diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb index 5a49b38457..9a203a7293 100644 --- a/activerecord/test/schema/mysql2_specific_schema.rb +++ b/activerecord/test/schema/mysql2_specific_schema.rb @@ -1,8 +1,8 @@ ActiveRecord::Schema.define do - if ActiveRecord::Base.connection.version >= '5.6.0' + if ActiveRecord::Base.connection.version >= "5.6.0" create_table :datetime_defaults, force: true do |t| - t.datetime :modified_datetime, default: -> { 'CURRENT_TIMESTAMP' } + t.datetime :modified_datetime, default: -> { "CURRENT_TIMESTAMP" } end end @@ -21,18 +21,18 @@ ActiveRecord::Schema.define do t.index :var_binary end - create_table :key_tests, force: true, options: 'ENGINE=MyISAM' do |t| + create_table :key_tests, force: true, options: "ENGINE=MyISAM" do |t| t.string :awesome t.string :pizza t.string :snacks - t.index :awesome, type: :fulltext, name: 'index_key_tests_on_awesome' - t.index :pizza, using: :btree, name: 'index_key_tests_on_pizza' - t.index :snacks, name: 'index_key_tests_on_snack' + t.index :awesome, type: :fulltext, name: "index_key_tests_on_awesome" + t.index :pizza, using: :btree, name: "index_key_tests_on_pizza" + t.index :snacks, name: "index_key_tests_on_snack" end create_table :collation_tests, id: false, force: true do |t| - t.string :string_cs_column, limit: 1, collation: 'utf8_bin' - t.string :string_ci_column, limit: 1, collation: 'utf8_general_ci' + t.string :string_cs_column, limit: 1, collation: "utf8_bin" + t.string :string_ci_column, limit: 1, collation: "utf8_general_ci" t.binary :binary_column, limit: 1 end diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb index 24713f722a..f00b858ea6 100644 --- a/activerecord/test/schema/postgresql_specific_schema.rb +++ b/activerecord/test/schema/postgresql_specific_schema.rb @@ -1,6 +1,6 @@ ActiveRecord::Schema.define do - enable_extension!('uuid-ossp', ActiveRecord::Base.connection) + enable_extension!("uuid-ossp", ActiveRecord::Base.connection) create_table :uuid_parents, id: :uuid, force: true do |t| t.string :name @@ -12,16 +12,16 @@ ActiveRecord::Schema.define do end create_table :defaults, force: true do |t| - t.date :modified_date, default: -> { 'CURRENT_DATE' } - t.date :modified_date_function, default: -> { 'now()' } - t.date :fixed_date, default: '2004-01-01' - t.datetime :modified_time, default: -> { 'CURRENT_TIMESTAMP' } - t.datetime :modified_time_function, default: -> { 'now()' } - t.datetime :fixed_time, default: '2004-01-01 00:00:00.000000-00' - t.column :char1, 'char(1)', default: 'Y' - t.string :char2, limit: 50, default: 'a varchar field' - t.text :char3, default: 'a text field' - t.bigint :bigint_default, default: -> { '0::bigint' } + t.date :modified_date, default: -> { "CURRENT_DATE" } + t.date :modified_date_function, default: -> { "now()" } + t.date :fixed_date, default: "2004-01-01" + t.datetime :modified_time, default: -> { "CURRENT_TIMESTAMP" } + t.datetime :modified_time_function, default: -> { "now()" } + t.datetime :fixed_time, default: "2004-01-01 00:00:00.000000-00" + t.column :char1, "char(1)", default: "Y" + t.string :char2, limit: 50, default: "a varchar field" + t.text :char3, default: "a text field" + t.bigint :bigint_default, default: -> { "0::bigint" } t.text :multiline_default, default: '--- [] ' @@ -32,12 +32,12 @@ ActiveRecord::Schema.define do drop_table table_name, if_exists: true end - execute 'DROP SEQUENCE IF EXISTS companies_nonstd_seq CASCADE' - execute 'CREATE SEQUENCE companies_nonstd_seq START 101 OWNED BY companies.id' + execute "DROP SEQUENCE IF EXISTS companies_nonstd_seq CASCADE" + execute "CREATE SEQUENCE companies_nonstd_seq START 101 OWNED BY companies.id" execute "ALTER TABLE companies ALTER COLUMN id SET DEFAULT nextval('companies_nonstd_seq')" - execute 'DROP SEQUENCE IF EXISTS companies_id_seq' + execute "DROP SEQUENCE IF EXISTS companies_id_seq" - execute 'DROP FUNCTION IF EXISTS partitioned_insert_trigger()' + execute "DROP FUNCTION IF EXISTS partitioned_insert_trigger()" %w(accounts_id_seq developers_id_seq projects_id_seq topics_id_seq customers_id_seq orders_id_seq).each do |seq_name| execute "SELECT setval('#{seq_name}', 100)" @@ -88,7 +88,7 @@ _SQL FOR EACH ROW EXECUTE PROCEDURE partitioned_insert_trigger(); _SQL rescue ActiveRecord::StatementInvalid => e - if e.message =~ /language "plpgsql" does not exist/ + if e.message.include?('language "plpgsql" does not exist') execute "CREATE LANGUAGE 'plpgsql';" retry else diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 628a59c2e3..983ac076a9 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -21,7 +21,7 @@ ActiveRecord::Schema.define do t.string :settings, null: true, limit: 1024 # MySQL does not allow default values for blobs. Fake it out with a # big varchar below. - t.string :preferences, null: true, default: '', limit: 1024 + t.string :preferences, null: true, default: "", limit: 1024 t.string :json_data, null: true, limit: 1024 t.string :json_data_empty, null: true, default: "", limit: 1024 t.text :params @@ -98,7 +98,8 @@ ActiveRecord::Schema.define do t.column :author_visibility, :integer, default: 0 t.column :illustrator_visibility, :integer, default: 0 t.column :font_size, :integer, default: 0 - t.column :cover, :string, default: 'hard' + t.column :difficulty, :integer, default: 0 + t.column :cover, :string, default: "hard" end create_table :booleans, force: true do |t| @@ -196,10 +197,10 @@ ActiveRecord::Schema.define do t.integer :rating, default: 1 t.integer :account_id t.string :description, default: "" - t.index [:firm_id, :type, :rating], name: "company_index" + t.index [:firm_id, :type, :rating], name: "company_index", length: { type: 10 }, order: { rating: :desc } t.index [:firm_id, :type], name: "company_partial_index", where: "rating > 10" - t.index :name, name: 'company_name_index', using: :btree - t.index 'lower(name)', name: "company_expression_index" if supports_expression_index? + t.index :name, name: "company_name_index", using: :btree + t.index "lower(name)", name: "company_expression_index" if supports_expression_index? end create_table :content, force: true do |t| @@ -298,7 +299,7 @@ ActiveRecord::Schema.define do create_table :edges, force: true, id: false do |t| t.column :source_id, :integer, null: false t.column :sink_id, :integer, null: false - t.index [:source_id, :sink_id], unique: true, name: 'unique_edge_index' + t.index [:source_id, :sink_id], unique: true, name: "unique_edge_index" end create_table :engines, force: true do |t| @@ -390,6 +391,11 @@ ActiveRecord::Schema.define do t.integer :ideal_reference_id end + create_table :jobs_pool, force: true, id: false do |t| + t.references :job, null: false, index: true + t.references :user, null: false, index: true + end + create_table :keyboards, force: true, id: false do |t| t.primary_key :key_number t.string :name @@ -409,6 +415,14 @@ ActiveRecord::Schema.define do t.references :student end + create_table :students, force: true do |t| + t.string :name + t.boolean :active + t.integer :college_id + end + + add_foreign_key :lessons_students, :students, on_delete: :cascade + create_table :lint_models, force: true create_table :line_items, force: true do |t| @@ -422,10 +436,12 @@ ActiveRecord::Schema.define do end create_table :lock_without_defaults, force: true do |t| + t.column :title, :string t.column :lock_version, :integer end create_table :lock_without_defaults_cust, force: true do |t| + t.column :title, :string t.column :custom_lock_version, :integer end @@ -777,12 +793,6 @@ ActiveRecord::Schema.define do t.integer :lock_version, null: false, default: 0 end - create_table :students, force: true do |t| - t.string :name - t.boolean :active - t.integer :college_id - end - create_table :subscribers, force: true, id: false do |t| t.string :nick, null: false t.string :name @@ -887,12 +897,12 @@ ActiveRecord::Schema.define do t.column :label, :string end - create_table 'warehouse-things', force: true do |t| + create_table "warehouse-things", force: true do |t| t.integer :value end [:circles, :squares, :triangles, :non_poly_ones, :non_poly_twos].each do |t| - create_table(t, force: true) { } + create_table(t, force: true) {} end # NOTE - the following 4 tables are used by models that have :inverse_of options on the associations @@ -927,11 +937,11 @@ ActiveRecord::Schema.define do t.string :title end - create_table :countries, force: true, id: false, primary_key: 'country_id' do |t| + create_table :countries, force: true, id: false, primary_key: "country_id" do |t| t.string :country_id t.string :name end - create_table :treaties, force: true, id: false, primary_key: 'treaty_id' do |t| + create_table :treaties, force: true, id: false, primary_key: "treaty_id" do |t| t.string :treaty_id t.string :name end @@ -952,9 +962,9 @@ ActiveRecord::Schema.define do t.string :name end create_table :weirds, force: true do |t| - t.string 'a$b' - t.string 'ãªã¾ãˆ' - t.string 'from' + t.string "a$b" + t.string "ãªã¾ãˆ" + t.string "from" end create_table :nodes, force: true do |t| @@ -1002,14 +1012,13 @@ ActiveRecord::Schema.define do end add_foreign_key :fk_test_has_fk, :fk_test_has_pk, column: "fk_id", name: "fk_name", primary_key: "pk_id" - add_foreign_key :lessons_students, :students end create_table :overloaded_types, force: true do |t| t.float :overloaded_float, default: 500 t.float :unoverloaded_float t.string :overloaded_string_with_limit, limit: 255 - t.string :string_with_default, default: 'the original default' + t.string :string_with_default, default: "the original default" end create_table :users, force: true do |t| diff --git a/activerecord/test/support/config.rb b/activerecord/test/support/config.rb index 6d123688a3..d0717f7b34 100644 --- a/activerecord/test/support/config.rb +++ b/activerecord/test/support/config.rb @@ -1,7 +1,7 @@ -require 'yaml' -require 'erubis' -require 'fileutils' -require 'pathname' +require "yaml" +require "erubis" +require "fileutils" +require "pathname" module ARTest class << self @@ -12,12 +12,12 @@ module ARTest private def config_file - Pathname.new(ENV['ARCONFIG'] || TEST_ROOT + '/config.yml') + Pathname.new(ENV["ARCONFIG"] || TEST_ROOT + "/config.yml") end def read_config unless config_file.exist? - FileUtils.cp TEST_ROOT + '/config.example.yml', config_file + FileUtils.cp TEST_ROOT + "/config.example.yml", config_file end erb = Erubis::Eruby.new(config_file.read) @@ -25,15 +25,15 @@ module ARTest end def expand_config(config) - config['connections'].each do |adapter, connection| - dbs = [['arunit', 'activerecord_unittest'], ['arunit2', 'activerecord_unittest2']] + config["connections"].each do |adapter, connection| + dbs = [["arunit", "activerecord_unittest"], ["arunit2", "activerecord_unittest2"]] dbs.each do |name, dbname| unless connection[name].is_a?(Hash) - connection[name] = { 'database' => connection[name] } + connection[name] = { "database" => connection[name] } end - connection[name]['database'] ||= dbname - connection[name]['adapter'] ||= adapter + connection[name]["database"] ||= dbname + connection[name]["adapter"] ||= adapter end end diff --git a/activerecord/test/support/connection.rb b/activerecord/test/support/connection.rb index c5334e8596..c9260398e2 100644 --- a/activerecord/test/support/connection.rb +++ b/activerecord/test/support/connection.rb @@ -1,15 +1,15 @@ -require 'active_support/logger' -require 'models/college' -require 'models/course' -require 'models/professor' +require "active_support/logger" +require "models/college" +require "models/course" +require "models/professor" module ARTest def self.connection_name - ENV['ARCONN'] || config['default_connection'] + ENV["ARCONN"] || config["default_connection"] end def self.connection_config - config['connections'][connection_name] + config["connections"][connection_name] end def self.connect diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index d9f23c55ba..83ff80e31a 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,184 @@ +* Use `Hash#compact` and `Hash#compact!` from Ruby 2.4. Old Ruby versions + will continue to get these methods from Active Support as before. + + *Prathamesh Sonpatki* + +* Fix `ActiveSupport::TimeZone#strptime`. + Support for timestamps in format of seconds (%s) and milliseconds (%Q). + + Fixes #26840. + + *Lev Denisov* + +* Fix `DateAndTime::Calculations#copy_time_to`. Copy `nsec` instead of `usec`. + + Jumping forward or backward between weeks now preserves nanosecond digits. + + *Josua Schmid* + +* Fix `ActiveSupport::TimeWithZone#in` across DST boundaries. + + Previously calls to `in` were being sent to the non-DST aware + method `Time#since` via `method_missing`. It is now aliased to + the DST aware `ActiveSupport::TimeWithZone#+` which handles + transitions across DST boundaries, e.g: + + Time.zone = "US/Eastern" + + t = Time.zone.local(2016,11,6,1) + # => Sun, 06 Nov 2016 01:00:00 EDT -05:00 + + t.in(1.hour) + # => Sun, 06 Nov 2016 01:00:00 EST -05:00 + + Fixes #26580. + + *Thomas Balthazar* + +* Remove unused parameter `options = nil` for `#clear` of + `ActiveSupport::Cache::Strategy::LocalCache::LocalStore` and + `ActiveSupport::Cache::Strategy::LocalCache`. + + *Yosuke Kabuto* + +* Fix `thread_mattr_accessor` subclass no longer overwrites parent. + + Assigning a value to a subclass using `thread_mattr_accessor` no + longer changes the value of the parent class. This brings the + behavior inline with the documentation. + + Given: + + class Account + thread_mattr_accessor :user + end + + class Customer < Account + end + + Account.user = "DHH" + Customer.user = "Rafael" + + Before: + + Account.user # => "Rafael" + + After: + + Account.user # => "DHH" + + *Shinichi Maeshima* + +* Since weeks are no longer converted to days, add `:weeks` to the list of + parts that `ActiveSupport::TimeWithZone` will recognize as possibly being + of variable duration to take account of DST transitions. + + Fixes #26039. + + *Andrew White* + +* Defines `Regexp.match?` for Ruby versions prior to 2.4. The predicate + has the same interface, but it does not have the performance boost. Its + purpose is to be able to write 2.4 compatible code. + + *Xavier Noria* + +* Allow `MessageEncryptor` to take advantage of authenticated encryption modes. + + AEAD modes like `aes-256-gcm` provide both confidentiality and data + authenticity, eliminating the need to use `MessageVerifier` to check if the + encrypted data has been tampered with. This speeds up encryption/decryption + and results in shorter cipher text. + + *Bart de Water* + +* Introduce `assert_changes` and `assert_no_changes`. + + `assert_changes` is a more general `assert_difference` that works with any + value. + + assert_changes 'Error.current', from: nil, to: 'ERR' do + expected_bad_operation + end + + Can be called with strings, to be evaluated in the binding (context) of + the block given to the assertion, or a lambda. + + assert_changes -> { Error.current }, from: nil, to: 'ERR' do + expected_bad_operation + end + + The `from` and `to` arguments are compared with the case operator (`===`). + + assert_changes 'Error.current', from: nil, to: Error do + expected_bad_operation + end + + This is pretty useful, if you need to loosely compare a value. For example, + you need to test a token has been generated and it has that many random + characters. + + user = User.start_registration + assert_changes 'user.token', to: /\w{32}/ do + user.finish_registration + end + + *Genadi Samokovarov* + +* Add `:fallback_string` option to `Array#to_sentence`. If an empty array + calls the function and a fallback string option is set then it returns the + fallback string other than an empty string. + + *Mohamed Osama* + +* Fix `ActiveSupport::TimeZone#strptime`. Now raises `ArgumentError` when the + given time doesn't match the format. The error is the same as the one given + by Ruby's `Date.strptime`. Previously it raised + `NoMethodError: undefined method empty? for nil:NilClass.` due to a bug. + + Fixes #25701. + + *John Gesimondo* + +* `travel/travel_to` travel time helpers, now raise on nested calls, + as this can lead to confusing time stubbing. + + Instead of: + + travel_to 2.days.from_now do + # 2 days from today + travel_to 3.days.from_now do + # 5 days from today + end + end + + preferred way to achieve above is: + + travel 2.days do + # 2 days from today + end + + travel 5.days do + # 5 days from today + end + + *Vipul A M* + +* Support parsing JSON time in ISO8601 local time strings in + `ActiveSupport::JSON.decode` when `parse_json_times` is enabled. + Strings in the format of `YYYY-MM-DD hh:mm:ss` (without a `Z` at + the end) will be parsed in the local timezone (`Time.zone`). In + addition, date strings (`YYYY-MM-DD`) are now parsed into `Date` + objects. + + *Grzegorz Witek* + +* Fixed `ActiveSupport::Logger.broadcast` so that calls to `#silence` now + properly delegate to all loggers. Silencing now properly suppresses logging + to both the log and the console. + + *Kevin McPhillips* + * Remove deprecated arguments in `assert_nothing_raised`. *Rafel Mendonça França* @@ -9,7 +190,7 @@ *Sean Griffin* -* Introduce Module#delegate_missing_to. +* Introduce `Module#delegate_missing_to`. When building a decorator, a common pattern emerges: diff --git a/activesupport/Rakefile b/activesupport/Rakefile index 7b56e36abf..2e1c50cc3d 100644 --- a/activesupport/Rakefile +++ b/activesupport/Rakefile @@ -1,12 +1,12 @@ -require 'rake/testtask' +require "rake/testtask" -task :default => :test +task default: :test task :package Rake::TestTask.new do |t| - t.libs << 'test' - t.pattern = 'test/**/*_test.rb' + t.libs << "test" + t.pattern = "test/**/*_test.rb" t.warning = true t.verbose = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) @@ -15,7 +15,7 @@ end namespace :test do task :isolated do Dir.glob("test/**/*_test.rb").all? do |file| - sh(Gem.ruby, '-w', '-Ilib:test', file) - end or raise "Failures" + sh(Gem.ruby, "-w", "-Ilib:test", file) + end || raise("Failures") end end diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index c6ca969844..08370cba85 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -1,27 +1,27 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'activesupport' + s.name = "activesupport" s.version = version - s.summary = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework.' - s.description = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing.' + s.summary = "A toolkit of support libraries and Ruby core extensions extracted from the Rails framework." + s.description = "A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*'] - s.require_path = 'lib' + s.files = Dir["CHANGELOG.md", "MIT-LICENSE", "README.rdoc", "lib/**/*"] + s.require_path = "lib" - s.rdoc_options.concat ['--encoding', 'UTF-8'] + s.rdoc_options.concat ["--encoding", "UTF-8"] - s.add_dependency 'i18n', '~> 0.7' - s.add_dependency 'tzinfo', '~> 1.1' - s.add_dependency 'minitest', '~> 5.1' - s.add_dependency 'concurrent-ruby', '~> 1.0', '>= 1.0.2' + s.add_dependency "i18n", "~> 0.7" + s.add_dependency "tzinfo", "~> 1.1" + s.add_dependency "minitest", "~> 5.1" + s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" end diff --git a/activesupport/bin/generate_tables b/activesupport/bin/generate_tables index 2193533588..ef220e0329 100755 --- a/activesupport/bin/generate_tables +++ b/activesupport/bin/generate_tables @@ -1,18 +1,17 @@ #!/usr/bin/env ruby begin - $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib')) - require 'active_support' + $:.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib")) + require "active_support" rescue IOError end -require 'open-uri' -require 'tmpdir' +require "open-uri" +require "tmpdir" module ActiveSupport module Multibyte module Unicode - class UnicodeDatabase def load; end end @@ -20,10 +19,10 @@ module ActiveSupport class DatabaseGenerator BASE_URI = "http://www.unicode.org/Public/#{UNICODE_VERSION}/ucd/" SOURCES = { - :codepoints => BASE_URI + 'UnicodeData.txt', - :composition_exclusion => BASE_URI + 'CompositionExclusions.txt', - :grapheme_break_property => BASE_URI + 'auxiliary/GraphemeBreakProperty.txt', - :cp1252 => 'http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT' + codepoints: BASE_URI + "UnicodeData.txt", + composition_exclusion: BASE_URI + "CompositionExclusions.txt", + grapheme_break_property: BASE_URI + "auxiliary/GraphemeBreakProperty.txt", + cp1252: "http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT" } def initialize @@ -52,9 +51,9 @@ module ActiveSupport codepoint.code = $1.hex codepoint.combining_class = Integer($4) codepoint.decomp_type = $7 - codepoint.decomp_mapping = ($8=='') ? nil : $8.split.collect(&:hex) - codepoint.uppercase_mapping = ($16=='') ? 0 : $16.hex - codepoint.lowercase_mapping = ($17=='') ? 0 : $17.hex + codepoint.decomp_mapping = ($8=="") ? nil : $8.split.collect(&:hex) + codepoint.uppercase_mapping = ($16=="") ? 0 : $16.hex + codepoint.lowercase_mapping = ($17=="") ? 0 : $17.hex @ucd.codepoints[codepoint.code] = codepoint end @@ -62,8 +61,8 @@ module ActiveSupport if line =~ /^([0-9A-F.]+)\s*;\s*([\w]+)\s*#/ type = $2.downcase.intern @ucd.boundary[type] ||= [] - if $1.include? '..' - parts = $1.split '..' + if $1.include? ".." + parts = $1.split ".." @ucd.boundary[type] << (parts[0].hex..parts[1].hex) else @ucd.boundary[type] << $1.hex @@ -85,7 +84,7 @@ module ActiveSupport def create_composition_map @ucd.codepoints.each do |_, cp| - if !cp.nil? and cp.combining_class == 0 and cp.decomp_type.nil? and !cp.decomp_mapping.nil? and cp.decomp_mapping.length == 2 and @ucd.codepoints[cp.decomp_mapping[0]].combining_class == 0 and !@ucd.composition_exclusion.include?(cp.code) + if !cp.nil? && cp.combining_class == 0 && cp.decomp_type.nil? && !cp.decomp_mapping.nil? && cp.decomp_mapping.length == 2 && @ucd.codepoints[cp.decomp_mapping[0]].combining_class == 0 && !@ucd.composition_exclusion.include?(cp.code) @ucd.composition_map[cp.decomp_mapping[0]] ||= {} @ucd.composition_map[cp.decomp_mapping[0]][cp.decomp_mapping[1]] = cp.code end @@ -105,7 +104,7 @@ module ActiveSupport filename = File.join(Dir.tmpdir, "#{url.split('/').last}") unless File.exist?(filename) $stderr.puts "Downloading #{url.split('/').last}" - File.open(filename, 'wb') do |target| + File.open(filename, "wb") do |target| open(url) do |source| source.each_line { |line| target.write line } end @@ -120,7 +119,7 @@ module ActiveSupport end def dump_to(filename) - File.open(filename, 'wb') do |f| + File.open(filename, "wb") do |f| f.write Marshal.dump([@ucd.codepoints, @ucd.composition_exclusion, @ucd.composition_map, @ucd.boundary, @ucd.cp1252]) end end diff --git a/activesupport/bin/test b/activesupport/bin/test index 404cabba51..84a05bba08 100755 --- a/activesupport/bin/test +++ b/activesupport/bin/test @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -COMPONENT_ROOT = File.expand_path("../../", __FILE__) + +COMPONENT_ROOT = File.expand_path("..", __dir__) require File.expand_path("../tools/test", COMPONENT_ROOT) + exit Minitest.run(ARGV) diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 11569add37..2fc42e1975 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ -require 'securerandom' +require "securerandom" require "active_support/dependencies/autoload" require "active_support/version" require "active_support/logger" diff --git a/activesupport/lib/active_support/all.rb b/activesupport/lib/active_support/all.rb index f537818300..72a23075af 100644 --- a/activesupport/lib/active_support/all.rb +++ b/activesupport/lib/active_support/all.rb @@ -1,3 +1,3 @@ -require 'active_support' -require 'active_support/time' -require 'active_support/core_ext' +require "active_support" +require "active_support/time" +require "active_support/core_ext" diff --git a/activesupport/lib/active_support/array_inquirer.rb b/activesupport/lib/active_support/array_inquirer.rb index ea328f603e..85122e39b2 100644 --- a/activesupport/lib/active_support/array_inquirer.rb +++ b/activesupport/lib/active_support/array_inquirer.rb @@ -32,11 +32,11 @@ module ActiveSupport private def respond_to_missing?(name, include_private = false) - name[-1] == '?' + name[-1] == "?" end def method_missing(name, *args) - if name[-1] == '?' + if name[-1] == "?" any?(name[0..-2]) else super diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb index e161ec4cca..169a58ecd1 100644 --- a/activesupport/lib/active_support/backtrace_cleaner.rb +++ b/activesupport/lib/active_support/backtrace_cleaner.rb @@ -14,7 +14,7 @@ module ActiveSupport # # bc = BacktraceCleaner.new # bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix - # bc.add_silencer { |line| line =~ /mongrel|rubygems/ } # skip any lines from mongrel or rubygems + # bc.add_silencer { |line| line =~ /puma|rubygems/ } # skip any lines from puma or rubygems # bc.clean(exception.backtrace) # perform the cleanup # # To reconfigure an existing BacktraceCleaner (like the default one in Rails) @@ -59,8 +59,8 @@ module ActiveSupport # Adds a silencer from the block provided. If the silencer returns +true+ # for a given line, it will be excluded from the clean backtrace. # - # # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb" - # backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ } + # # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb" + # backtrace_cleaner.add_silencer { |line| line =~ /puma/ } def add_silencer(&block) @silencers << block end diff --git a/activesupport/lib/active_support/benchmarkable.rb b/activesupport/lib/active_support/benchmarkable.rb index 3988b147ac..70493c8da7 100644 --- a/activesupport/lib/active_support/benchmarkable.rb +++ b/activesupport/lib/active_support/benchmarkable.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/benchmark' -require 'active_support/core_ext/hash/keys' +require "active_support/core_ext/benchmark" +require "active_support/core_ext/hash/keys" module ActiveSupport module Benchmarkable @@ -39,7 +39,7 @@ module ActiveSupport result = nil ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield } - logger.send(options[:level], '%s (%.1fms)' % [ message, ms ]) + logger.send(options[:level], "%s (%.1fms)" % [ message, ms ]) result else yield diff --git a/activesupport/lib/active_support/builder.rb b/activesupport/lib/active_support/builder.rb index 321e462acd..0f010c5d96 100644 --- a/activesupport/lib/active_support/builder.rb +++ b/activesupport/lib/active_support/builder.rb @@ -1,5 +1,5 @@ begin - require 'builder' + require "builder" rescue LoadError => e $stderr.puts "You don't have builder installed in your application. Please add it to your Gemfile and run bundle install" raise e diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 179ca13b49..ad02546755 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -1,29 +1,27 @@ -require 'benchmark' -require 'zlib' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/benchmark' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/numeric/bytes' -require 'active_support/core_ext/numeric/time' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/string/strip' +require "zlib" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/numeric/bytes" +require "active_support/core_ext/numeric/time" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/string/strip" module ActiveSupport # See ActiveSupport::Cache::Store for documentation. module Cache - autoload :FileStore, 'active_support/cache/file_store' - autoload :MemoryStore, 'active_support/cache/memory_store' - autoload :MemCacheStore, 'active_support/cache/mem_cache_store' - autoload :NullStore, 'active_support/cache/null_store' + autoload :FileStore, "active_support/cache/file_store" + autoload :MemoryStore, "active_support/cache/memory_store" + autoload :MemCacheStore, "active_support/cache/mem_cache_store" + autoload :NullStore, "active_support/cache/null_store" # These options mean something to all cache implementations. Individual cache # implementations may support additional options. UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl] module Strategy - autoload :LocalCache, 'active_support/cache/strategy/local_cache' + autoload :LocalCache, "active_support/cache/strategy/local_cache" end class << self @@ -153,7 +151,7 @@ module ActiveSupport # or +write+. To specify the threshold at which to compress values, set the # <tt>:compress_threshold</tt> option. The default threshold is 16K. class Store - cattr_accessor :logger, :instance_writer => true + cattr_accessor :logger, instance_writer: true attr_reader :silence, :options alias :silence? :silence @@ -200,15 +198,15 @@ module ActiveSupport # You may also specify additional options via the +options+ argument. # Setting <tt>force: true</tt> forces a cache "miss," meaning we treat # the cache value as missing even if it's present. Passing a block is - # required when `force` is true so this always results in a cache write. + # required when +force+ is true so this always results in a cache write. # # cache.write('today', 'Monday') # cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday' # cache.fetch('today', force: true) # => ArgumentError # - # The `:force` option is useful when you're calling some other method to + # The +:force+ option is useful when you're calling some other method to # ask whether you should force a cache write. Otherwise, it's clearer to - # just call `Cache#write`. + # just call <tt>Cache#write</tt>. # # Setting <tt>:compress</tt> will store a large cache entry set by the call # in a compressed format. @@ -300,7 +298,7 @@ module ActiveSupport save_block_result_to_cache(name, options) { |_name| yield _name } end elsif options && options[:force] - raise ArgumentError, 'Missing block: Calling `Cache#fetch` with `force: true` requires a block.' + raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block." else read(name, options) end @@ -361,6 +359,9 @@ module ActiveSupport # the cache with the given keys, then that data is returned. Otherwise, # the supplied block is called for each key for which there was no data, # and the result will be written to the cache and returned. + # Therefore, you need to pass a block that returns the data to be written + # to the cache. If you do not want to write the cache when the cache is + # not found, use #read_multi. # # Options are passed to the underlying cache implementation. # @@ -374,6 +375,8 @@ module ActiveSupport # # "unknown_key" => "Fallback value for key: unknown_key" } # def fetch_multi(*names) + raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given? + options = names.extract_options! options = merged_options(options) results = read_multi(*names, options) @@ -464,7 +467,7 @@ module ActiveSupport # The options hash is passed to the underlying cache implementation. # # All implementations may not support this method. - def clear(options = nil) + def clear raise NotImplementedError.new("#{self.class.name} does not support clear") end @@ -477,7 +480,7 @@ module ActiveSupport prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace] if prefix source = pattern.source - if source.start_with?('^') + if source.start_with?("^") source = source[1, source.length] else source = ".*#{source[0, source.length]}" @@ -525,12 +528,12 @@ module ActiveSupport case key when Array if key.size > 1 - key = key.collect{|element| expanded_key(element)} + key = key.collect { |element| expanded_key(element) } else key = key.first end when Hash - key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"} + key = key.sort_by { |k,_| k.to_s }.collect { |k,v| "#{k}=#{v}" } end key.to_param @@ -557,9 +560,9 @@ module ActiveSupport def instrument(operation, key, options = nil) log { "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" } - payload = { :key => key } + payload = { key: key } payload.merge!(options) if options.is_a?(Hash) - ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) } + ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) } end def log @@ -574,7 +577,7 @@ module ActiveSupport # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache # for a brief period while the entry is being recalculated. entry.expires_at = Time.now + race_ttl - write_entry(key, entry, :expires_in => race_ttl * 2) + write_entry(key, entry, expires_in: race_ttl * 2) else delete_entry(key, options) end @@ -584,7 +587,7 @@ module ActiveSupport end def get_entry_value(entry, name, options) - instrument(:fetch_hit, name, options) { } + instrument(:fetch_hit, name, options) {} entry.value end diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 99c55b1aa4..1971ff182e 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/marshal' -require 'active_support/core_ext/file/atomic' -require 'active_support/core_ext/string/conversions' -require 'uri/common' +require "active_support/core_ext/marshal" +require "active_support/core_ext/file/atomic" +require "active_support/core_ext/string/conversions" +require "uri/common" module ActiveSupport module Cache @@ -16,8 +16,8 @@ module ActiveSupport DIR_FORMATTER = "%03X" FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write) FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room - EXCLUDED_DIRS = ['.', '..'].freeze - GITKEEP_FILES = ['.gitkeep', '.keep'].freeze + EXCLUDED_DIRS = [".", ".."].freeze + GITKEEP_FILES = [".gitkeep", ".keep"].freeze def initialize(cache_path, options = nil) super(options) @@ -27,9 +27,9 @@ module ActiveSupport # Deletes all items from the cache. In this case it deletes all the entries in the specified # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your # config file when using +FileStore+ because everything in that directory will be deleted. - def clear(options = nil) + def clear root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES) - FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)}) + FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) }) rescue Errno::ENOENT end @@ -80,7 +80,7 @@ module ActiveSupport def write_entry(key, entry, options) return false if options[:unless_exist] && File.exist?(key) ensure_cache_path(File.dirname(key)) - File.atomic_write(key, cache_path) {|f| Marshal.dump(entry, f)} + File.atomic_write(key, cache_path) { |f| Marshal.dump(entry, f) } true end @@ -102,7 +102,7 @@ module ActiveSupport # Lock a file for a block so only one process can modify it at a time. def lock_file(file_name, &block) # :nodoc: if File.exist?(file_name) - File.open(file_name, 'r+') do |f| + File.open(file_name, "r+") do |f| begin f.flock File::LOCK_EX yield diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 2ca4b51efa..cfd5e39bc4 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -1,13 +1,13 @@ begin - require 'dalli' + require "dalli" rescue LoadError => e $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require 'digest/md5' -require 'active_support/core_ext/marshal' -require 'active_support/core_ext/array/extract_options' +require "digest/md5" +require "active_support/core_ext/marshal" +require "active_support/core_ext/array/extract_options" module ActiveSupport module Cache @@ -27,23 +27,23 @@ module ActiveSupport # Provide support for raw values in the local cache strategy. module LocalCacheWithRaw # :nodoc: protected - def read_entry(key, options) - entry = super - if options[:raw] && local_cache && entry - entry = deserialize_entry(entry.value) + def read_entry(key, options) + entry = super + if options[:raw] && local_cache && entry + entry = deserialize_entry(entry.value) + end + entry end - entry - end - def write_entry(key, entry, options) # :nodoc: - if options[:raw] && local_cache - raw_entry = Entry.new(entry.value.to_s) - raw_entry.expires_at = entry.expires_at - super(key, raw_entry, options) - else - super + def write_entry(key, entry, options) # :nodoc: + if options[:raw] && local_cache + raw_entry = Entry.new(entry.value.to_s) + raw_entry.expires_at = entry.expires_at + super(key, raw_entry, options) + else + super + end end - end end prepend Strategy::LocalCache @@ -85,7 +85,7 @@ module ActiveSupport @data = addresses.first else mem_cache_options = options.dup - UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)} + UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) } @data = self.class.build_mem_cache(*(addresses + [mem_cache_options])) end end @@ -96,8 +96,8 @@ module ActiveSupport options = names.extract_options! options = merged_options(options) - keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}] - raw_values = @data.get_multi(keys_to_names.keys, :raw => true) + keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }] + raw_values = @data.get_multi(keys_to_names.keys, raw: true) values = {} raw_values.each do |key, value| entry = deserialize_entry(value) @@ -112,7 +112,7 @@ module ActiveSupport # to zero. def increment(name, amount = 1, options = nil) # :nodoc: options = merged_options(options) - instrument(:increment, name, :amount => amount) do + instrument(:increment, name, amount: amount) do rescue_error_with nil do @data.incr(normalize_key(name, options), amount) end @@ -125,7 +125,7 @@ module ActiveSupport # to zero. def decrement(name, amount = 1, options = nil) # :nodoc: options = merged_options(options) - instrument(:decrement, name, :amount => amount) do + instrument(:decrement, name, amount: amount) do rescue_error_with nil do @data.decr(normalize_key(name, options), amount) end @@ -176,7 +176,7 @@ module ActiveSupport def normalize_key(key, options) key = super.dup key = key.force_encoding(Encoding::ASCII_8BIT) - key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" } + key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" } key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250 key end diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 896c28ad8b..1a8477f9fe 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -1,10 +1,10 @@ -require 'monitor' +require "monitor" module ActiveSupport module Cache # A cache store implementation which stores everything into memory in the # same process. If you're running multiple Ruby on Rails server processes - # (which is the case if you're using mongrel_cluster or Phusion Passenger), + # (which is the case if you're using Phusion Passenger or puma clustered mode), # then this means that Rails server process instances won't be able # to share cache data with each other and this may not be the most # appropriate cache in that scenario. @@ -39,8 +39,8 @@ module ActiveSupport # Preemptively iterates through all stored keys and removes the ones which have expired. def cleanup(options = nil) options = merged_options(options) - instrument(:cleanup, :size => @data.size) do - keys = synchronize{ @data.keys } + instrument(:cleanup, size: @data.size) do + keys = synchronize { @data.keys } keys.each do |key| entry = @data[key] delete_entry(key, options) if entry && entry.expired? @@ -56,8 +56,8 @@ module ActiveSupport begin start_time = Time.now cleanup - instrument(:prune, target_size, :from => @cache_size) do - keys = synchronize{ @key_access.keys.sort{|a,b| @key_access[a].to_f <=> @key_access[b].to_f} } + instrument(:prune, target_size, from: @cache_size) do + keys = synchronize { @key_access.keys.sort { |a,b| @key_access[a].to_f <=> @key_access[b].to_f } } keys.each do |key| delete_entry(key, options) return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time) diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb index 1c678dc2af..f41cc23eb0 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/string/inflections' -require 'active_support/per_thread_registry' +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/string/inflections" +require "active_support/per_thread_registry" module ActiveSupport module Cache @@ -9,7 +9,7 @@ module ActiveSupport # duration of a block. Repeated calls to the cache for the same key will hit the # in-memory cache for faster access. module LocalCache - autoload :Middleware, 'active_support/cache/strategy/local_cache_middleware' + autoload :Middleware, "active_support/cache/strategy/local_cache_middleware" # Class for storing and registering the local caches. class LocalCacheRegistry # :nodoc: @@ -44,7 +44,7 @@ module ActiveSupport yield end - def clear(options = nil) + def clear @data.clear end @@ -70,6 +70,7 @@ module ActiveSupport def with_local_cache use_temporary_local_cache(LocalStore.new) { yield } end + # Middleware class can be inserted as a Rack handler to be local cache for the # duration of request. def middleware @@ -78,9 +79,9 @@ module ActiveSupport local_cache_key) end - def clear(options = nil) # :nodoc: + def clear # :nodoc: return super unless cache = local_cache - cache.clear(options) + cache.clear super end @@ -92,14 +93,14 @@ module ActiveSupport def increment(name, amount = 1, options = nil) # :nodoc: return super unless local_cache - value = bypass_local_cache{super} + value = bypass_local_cache { super } write_cache_value(name, value, options) value end def decrement(name, amount = 1, options = nil) # :nodoc: return super unless local_cache - value = bypass_local_cache{super} + value = bypass_local_cache { super } write_cache_value(name, value, options) value end @@ -146,7 +147,7 @@ module ActiveSupport private def local_cache_key - @local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym + @local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, "_").to_sym end def local_cache diff --git a/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb b/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb index a6f24b1a3c..af51f66dda 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb @@ -1,11 +1,10 @@ -require 'rack/body_proxy' -require 'rack/utils' +require "rack/body_proxy" +require "rack/utils" module ActiveSupport module Cache module Strategy module LocalCache - #-- # This class wraps up local storage for middlewares. Only the middleware method should # construct them. diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 557a4695a6..2ad1145fae 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -1,13 +1,13 @@ -require 'active_support/concern' -require 'active_support/descendants_tracker' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/string/filters' -require 'active_support/deprecation' -require 'thread' +require "active_support/concern" +require "active_support/descendants_tracker" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/string/filters" +require "active_support/deprecation" +require "thread" module ActiveSupport # Callbacks are code hooks that are run at key points in an object's life cycle. @@ -63,6 +63,8 @@ module ActiveSupport included do extend ActiveSupport::DescendantsTracker + class_attribute :__callbacks, instance_writer: false + self.__callbacks ||= {} end CALLBACK_FILTER_TYPES = [:before, :after, :around] @@ -86,711 +88,777 @@ module ActiveSupport # run_callbacks :save do # save # end - def run_callbacks(kind, &block) - send "_run_#{kind}_callbacks", &block - end - - private + # + #-- + # + # As this method is used in many places, and often wraps large portions of + # user code, it has an additional design goal of minimizing its impact on + # the visible call stack. An exception from inside a :before or :after + # callback can be as noisy as it likes -- but when control has passed + # smoothly through and into the supplied block, we want as little evidence + # as possible that we were here. + def run_callbacks(kind) + callbacks = __callbacks[kind.to_sym] - def __run_callbacks__(callbacks, &block) if callbacks.empty? yield if block_given? else - runner = callbacks.compile - e = Filters::Environment.new(self, false, nil, block) - runner.call(e).value - end - end - - # A hook invoked every time a before callback is halted. - # This can be overridden in ActiveSupport::Callbacks implementors in order - # to provide better debugging/logging. - def halted_callback_hook(filter) - end + env = Filters::Environment.new(self, false, nil) + next_sequence = callbacks.compile + + invoke_sequence = Proc.new do + skipped = nil + while true + current, next_sequence = next_sequence, next_sequence.nested + current.invoke_before(env) + if current.final? + env.value = !env.halted && (!block_given? || yield) + elsif current.skip?(env) + (skipped ||= []) << current + next + else + target, block, method, *arguments = current.expand_call_template(env, invoke_sequence) + target.send(method, *arguments, &block) + end + current.invoke_after(env) + skipped.pop.invoke_after(env) while skipped && skipped.first + break env.value + end + end - module Conditionals # :nodoc: - class Value - def initialize(&block) - @block = block + # Common case: no 'around' callbacks defined + if next_sequence.final? + next_sequence.invoke_before(env) + env.value = !env.halted && (!block_given? || yield) + next_sequence.invoke_after(env) + env.value + else + invoke_sequence.call end - def call(target, value); @block.call(value); end end end - module Filters - Environment = Struct.new(:target, :halted, :value, :run_block) + private - class End - def call(env) - block = env.run_block - env.value = !env.halted && (!block || block.call) - env - end + # A hook invoked every time a before callback is halted. + # This can be overridden in ActiveSupport::Callbacks implementors in order + # to provide better debugging/logging. + def halted_callback_hook(filter) end - ENDING = End.new - - class Before - def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter) - halted_lambda = chain_config[:terminator] - if user_conditions.any? - halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) - else - halting(callback_sequence, user_callback, halted_lambda, filter) + module Conditionals # :nodoc: + class Value + def initialize(&block) + @block = block end + def call(target, value); @block.call(value); end end + end - def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) - callback_sequence.before do |env| - target = env.target - value = env.value - halted = env.halted + module Filters + Environment = Struct.new(:target, :halted, :value) - if !halted && user_conditions.all? { |c| c.call(target, value) } - result_lambda = -> { user_callback.call target, value } - env.halted = halted_lambda.call(target, result_lambda) - if env.halted - target.send :halted_callback_hook, filter - end + class Before + def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter) + halted_lambda = chain_config[:terminator] + + if user_conditions.any? + halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) + else + halting(callback_sequence, user_callback, halted_lambda, filter) end + end + + def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter) + callback_sequence.before do |env| + target = env.target + value = env.value + halted = env.halted + + if !halted && user_conditions.all? { |c| c.call(target, value) } + result_lambda = -> { user_callback.call target, value } + env.halted = halted_lambda.call(target, result_lambda) + if env.halted + target.send :halted_callback_hook, filter + end + end - env + env + end end - end - private_class_method :halting_and_conditional + private_class_method :halting_and_conditional - def self.halting(callback_sequence, user_callback, halted_lambda, filter) - callback_sequence.before do |env| - target = env.target - value = env.value - halted = env.halted + def self.halting(callback_sequence, user_callback, halted_lambda, filter) + callback_sequence.before do |env| + target = env.target + value = env.value + halted = env.halted - unless halted - result_lambda = -> { user_callback.call target, value } - env.halted = halted_lambda.call(target, result_lambda) + unless halted + result_lambda = -> { user_callback.call target, value } + env.halted = halted_lambda.call(target, result_lambda) - if env.halted - target.send :halted_callback_hook, filter + if env.halted + target.send :halted_callback_hook, filter + end end - end - env + env + end end + private_class_method :halting end - private_class_method :halting - end - class After - def self.build(callback_sequence, user_callback, user_conditions, chain_config) - if chain_config[:skip_after_callbacks_if_terminated] - if user_conditions.any? - halting_and_conditional(callback_sequence, user_callback, user_conditions) + class After + def self.build(callback_sequence, user_callback, user_conditions, chain_config) + if chain_config[:skip_after_callbacks_if_terminated] + if user_conditions.any? + halting_and_conditional(callback_sequence, user_callback, user_conditions) + else + halting(callback_sequence, user_callback) + end else - halting(callback_sequence, user_callback) + if user_conditions.any? + conditional callback_sequence, user_callback, user_conditions + else + simple callback_sequence, user_callback + end end - else - if user_conditions.any? - conditional callback_sequence, user_callback, user_conditions - else - simple callback_sequence, user_callback + end + + def self.halting_and_conditional(callback_sequence, user_callback, user_conditions) + callback_sequence.after do |env| + target = env.target + value = env.value + halted = env.halted + + if !halted && user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end + + env end end - end + private_class_method :halting_and_conditional - def self.halting_and_conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.after do |env| - target = env.target - value = env.value - halted = env.halted + def self.halting(callback_sequence, user_callback) + callback_sequence.after do |env| + unless env.halted + user_callback.call env.target, env.value + end - if !halted && user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value + env end + end + private_class_method :halting + + def self.conditional(callback_sequence, user_callback, user_conditions) + callback_sequence.after do |env| + target = env.target + value = env.value + + if user_conditions.all? { |c| c.call(target, value) } + user_callback.call target, value + end - env + env + end end - end - private_class_method :halting_and_conditional + private_class_method :conditional - def self.halting(callback_sequence, user_callback) - callback_sequence.after do |env| - unless env.halted + def self.simple(callback_sequence, user_callback) + callback_sequence.after do |env| user_callback.call env.target, env.value - end - env + env + end end + private_class_method :simple end - private_class_method :halting + end - def self.conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.after do |env| - target = env.target - value = env.value + class Callback #:nodoc:# + def self.build(chain, filter, kind, options) + if filter.is_a?(String) + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Passing string to define callback is deprecated and will be removed + in Rails 5.1 without replacement. + MSG + end - if user_conditions.all? { |c| c.call(target, value) } - user_callback.call target, value - end + new chain.name, filter, kind, options, chain.config + end - env - end + attr_accessor :kind, :name + attr_reader :chain_config + + def initialize(name, filter, kind, options, chain_config) + @chain_config = chain_config + @name = name + @kind = kind + @filter = filter + @key = compute_identifier filter + @if = Array(options[:if]) + @unless = Array(options[:unless]) end - private_class_method :conditional - def self.simple(callback_sequence, user_callback) - callback_sequence.after do |env| - user_callback.call env.target, env.value + def filter; @key; end + def raw_filter; @filter; end - env - end + def merge_conditional_options(chain, if_option:, unless_option:) + options = { + if: @if.dup, + unless: @unless.dup + } + + options[:if].concat Array(unless_option) + options[:unless].concat Array(if_option) + + self.class.build chain, @filter, @kind, options + end + + def matches?(_kind, _filter) + @kind == _kind && filter == _filter end - private_class_method :simple - end - class Around - def self.build(callback_sequence, user_callback, user_conditions, chain_config) - if user_conditions.any? - halting_and_conditional(callback_sequence, user_callback, user_conditions) + def duplicates?(other) + case @filter + when Symbol, String + matches?(other.kind, other.filter) else - halting(callback_sequence, user_callback) + false end end - def self.halting_and_conditional(callback_sequence, user_callback, user_conditions) - callback_sequence.around do |env, &run| - target = env.target - value = env.value - halted = env.halted - - if !halted && user_conditions.all? { |c| c.call(target, value) } - user_callback.call(target, value) { - run.call.value - } - env - else - run.call - end + # Wraps code with filter + def apply(callback_sequence) + user_conditions = conditions_lambdas + user_callback = CallTemplate.build(@filter, self) + + case kind + when :before + Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter) + when :after + Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config) + when :around + callback_sequence.around(user_callback, user_conditions) end end - private_class_method :halting_and_conditional - def self.halting(callback_sequence, user_callback) - callback_sequence.around do |env, &run| - target = env.target - value = env.value + def current_scopes + Array(chain_config[:scope]).map { |s| public_send(s) } + end - if env.halted - run.call + private + def compute_identifier(filter) + case filter + when String, ::Proc + filter.object_id else - user_callback.call(target, value) { - run.call.value - } - env + filter end end - end - private_class_method :halting + + def conditions_lambdas + @if.map { |c| CallTemplate.build(c, self).make_lambda } + + @unless.map { |c| CallTemplate.build(c, self).inverted_lambda } + end end - end - class Callback #:nodoc:# - def self.build(chain, filter, kind, options) - if filter.is_a?(String) - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Passing string to define callback is deprecated and will be removed - in Rails 5.1 without replacement. - MSG + # A future invocation of user-supplied code (either as a callback, + # or a condition filter). + class CallTemplate # :nodoc: + def initialize(target, method, arguments, block) + @override_target = target + @method_name = method + @arguments = arguments + @override_block = block end - new chain.name, filter, kind, options, chain.config - end + # Return the parts needed to make this call, with the given + # input values. + # + # Returns an array of the form: + # + # [target, block, method, *arguments] + # + # This array can be used as such: + # + # target.send(method, *arguments, &block) + # + # The actual invocation is left up to the caller to minimize + # call stack pollution. + def expand(target, value, block) + result = @arguments.map { |arg| + case arg + when :value; value + when :target; target + when :block; block || raise(ArgumentError) + end + } - attr_accessor :kind, :name - attr_reader :chain_config - - def initialize(name, filter, kind, options, chain_config) - @chain_config = chain_config - @name = name - @kind = kind - @filter = filter - @key = compute_identifier filter - @if = Array(options[:if]) - @unless = Array(options[:unless]) - end + result.unshift @method_name + result.unshift @override_block || block + result.unshift @override_target || target - def filter; @key; end - def raw_filter; @filter; end + # target, block, method, *arguments = result + # target.send(method, *arguments, &block) + result + end - def merge_conditional_options(chain, if_option:, unless_option:) - options = { - :if => @if.dup, - :unless => @unless.dup - } + # Return a lambda that will make this call when given the input + # values. + def make_lambda + lambda do |target, value, &block| + target, block, method, *arguments = expand(target, value, block) + target.send(method, *arguments, &block) + end + end - options[:if].concat Array(unless_option) - options[:unless].concat Array(if_option) + # Return a lambda that will make this call when given the input + # values, but then return the boolean inverse of that result. + def inverted_lambda + lambda do |target, value, &block| + target, block, method, *arguments = expand(target, value, block) + ! target.send(method, *arguments, &block) + end + end - self.class.build chain, @filter, @kind, options - end + # Filters support: + # + # Symbols:: A method to call. + # Strings:: Some content to evaluate. + # Procs:: A proc to call with the object. + # Objects:: An object with a <tt>before_foo</tt> method on it to call. + # + # All of these objects are converted into a CallTemplate and handled + # the same after this point. + def self.build(filter, callback) + case filter + when Symbol + new(nil, filter, [], nil) + when String + new(nil, :instance_exec, [:value], compile_lambda(filter)) + when Conditionals::Value + new(filter, :call, [:target, :value], nil) + when ::Proc + if filter.arity > 1 + new(nil, :instance_exec, [:target, :block], filter) + elsif filter.arity > 0 + new(nil, :instance_exec, [:target], filter) + else + new(nil, :instance_exec, [], filter) + end + else + method_to_call = callback.current_scopes.join("_") - def matches?(_kind, _filter) - @kind == _kind && filter == _filter - end + new(filter, method_to_call, [:target], nil) + end + end - def duplicates?(other) - case @filter - when Symbol, String - matches?(other.kind, other.filter) - else - false + def self.compile_lambda(filter) + eval("lambda { |value| #{filter} }") end end - # Wraps code with filter - def apply(callback_sequence) - user_conditions = conditions_lambdas - user_callback = make_lambda @filter + # Execute before and after filters in a sequence instead of + # chaining them with nested lambda calls, see: + # https://github.com/rails/rails/issues/18011 + class CallbackSequence # :nodoc: + def initialize(nested = nil, call_template = nil, user_conditions = nil) + @nested = nested + @call_template = call_template + @user_conditions = user_conditions - case kind - when :before - Filters::Before.build(callback_sequence, user_callback, user_conditions, chain_config, @filter) - when :after - Filters::After.build(callback_sequence, user_callback, user_conditions, chain_config) - when :around - Filters::Around.build(callback_sequence, user_callback, user_conditions, chain_config) + @before = [] + @after = [] end - end - private - - def invert_lambda(l) - lambda { |*args, &blk| !l.call(*args, &blk) } - end + def before(&before) + @before.unshift(before) + self + end - # Filters support: - # - # Symbols:: A method to call. - # Strings:: Some content to evaluate. - # Procs:: A proc to call with the object. - # Objects:: An object with a <tt>before_foo</tt> method on it to call. - # - # All of these objects are converted into a lambda and handled - # the same after this point. - def make_lambda(filter) - case filter - when Symbol - lambda { |target, _, &blk| target.send filter, &blk } - when String - l = eval "lambda { |value| #{filter} }" - lambda { |target, value| target.instance_exec(value, &l) } - when Conditionals::Value then filter - when ::Proc - if filter.arity > 1 - return lambda { |target, _, &block| - raise ArgumentError unless block - target.instance_exec(target, block, &filter) - } - end - - if filter.arity <= 0 - lambda { |target, _| target.instance_exec(&filter) } - else - lambda { |target, _| target.instance_exec(target, &filter) } - end - else - scopes = Array(chain_config[:scope]) - method_to_call = scopes.map{ |s| public_send(s) }.join("_") + def after(&after) + @after.push(after) + self + end - lambda { |target, _, &blk| - filter.public_send method_to_call, target, &blk - } + def around(call_template, user_conditions) + CallbackSequence.new(self, call_template, user_conditions) end - end - def compute_identifier(filter) - case filter - when String, ::Proc - filter.object_id - else - filter + def skip?(arg) + arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) } end - end - def conditions_lambdas - @if.map { |c| make_lambda c } + - @unless.map { |c| invert_lambda make_lambda c } - end - end + def nested + @nested + end - # Execute before and after filters in a sequence instead of - # chaining them with nested lambda calls, see: - # https://github.com/rails/rails/issues/18011 - class CallbackSequence - def initialize(&call) - @call = call - @before = [] - @after = [] - end + def final? + !@call_template + end - def before(&before) - @before.unshift(before) - self - end + def expand_call_template(arg, block) + @call_template.expand(arg.target, arg.value, block) + end - def after(&after) - @after.push(after) - self - end + def invoke_before(arg) + @before.each { |b| b.call(arg) } + end - def around(&around) - CallbackSequence.new do |arg| - around.call(arg) { - self.call(arg) - } + def invoke_after(arg) + @after.each { |a| a.call(arg) } end end - def call(arg) - @before.each { |b| b.call(arg) } - value = @call.call(arg) - @after.each { |a| a.call(arg) } - value - end - end + # An Array with a compile method. + class CallbackChain #:nodoc:# + include Enumerable - # An Array with a compile method. - class CallbackChain #:nodoc:# - include Enumerable - - attr_reader :name, :config - - def initialize(name, config) - @name = name - @config = { - scope: [:kind], - terminator: default_terminator - }.merge!(config) - @chain = [] - @callbacks = nil - @mutex = Mutex.new - end + attr_reader :name, :config - def each(&block); @chain.each(&block); end - def index(o); @chain.index(o); end - def empty?; @chain.empty?; end + def initialize(name, config) + @name = name + @config = { + scope: [:kind], + terminator: default_terminator + }.merge!(config) + @chain = [] + @callbacks = nil + @mutex = Mutex.new + end - def insert(index, o) - @callbacks = nil - @chain.insert(index, o) - end + def each(&block); @chain.each(&block); end + def index(o); @chain.index(o); end + def empty?; @chain.empty?; end - def delete(o) - @callbacks = nil - @chain.delete(o) - end + def insert(index, o) + @callbacks = nil + @chain.insert(index, o) + end - def clear - @callbacks = nil - @chain.clear - self - end + def delete(o) + @callbacks = nil + @chain.delete(o) + end - def initialize_copy(other) - @callbacks = nil - @chain = other.chain.dup - @mutex = Mutex.new - end + def clear + @callbacks = nil + @chain.clear + self + end - def compile - @callbacks || @mutex.synchronize do - final_sequence = CallbackSequence.new { |env| Filters::ENDING.call(env) } - @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback| - callback.apply callback_sequence + def initialize_copy(other) + @callbacks = nil + @chain = other.chain.dup + @mutex = Mutex.new + end + + def compile + @callbacks || @mutex.synchronize do + final_sequence = CallbackSequence.new + @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback| + callback.apply callback_sequence + end end end - end - def append(*callbacks) - callbacks.each { |c| append_one(c) } - end + def append(*callbacks) + callbacks.each { |c| append_one(c) } + end - def prepend(*callbacks) - callbacks.each { |c| prepend_one(c) } - end + def prepend(*callbacks) + callbacks.each { |c| prepend_one(c) } + end - protected - def chain; @chain; end + protected + def chain; @chain; end - private + private - def append_one(callback) - @callbacks = nil - remove_duplicates(callback) - @chain.push(callback) - end + def append_one(callback) + @callbacks = nil + remove_duplicates(callback) + @chain.push(callback) + end - def prepend_one(callback) - @callbacks = nil - remove_duplicates(callback) - @chain.unshift(callback) - end + def prepend_one(callback) + @callbacks = nil + remove_duplicates(callback) + @chain.unshift(callback) + end - def remove_duplicates(callback) - @callbacks = nil - @chain.delete_if { |c| callback.duplicates?(c) } - end + def remove_duplicates(callback) + @callbacks = nil + @chain.delete_if { |c| callback.duplicates?(c) } + end - def default_terminator - Proc.new do |target, result_lambda| - terminate = true - catch(:abort) do - result_lambda.call if result_lambda.is_a?(Proc) - terminate = false + def default_terminator + Proc.new do |target, result_lambda| + terminate = true + catch(:abort) do + result_lambda.call if result_lambda.is_a?(Proc) + terminate = false + end + terminate + end end - terminate - end end - end - module ClassMethods - def normalize_callback_params(filters, block) # :nodoc: - type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before - options = filters.extract_options! - filters.unshift(block) if block - [type, filters, options.dup] - end + module ClassMethods + def normalize_callback_params(filters, block) # :nodoc: + type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before + options = filters.extract_options! + filters.unshift(block) if block + [type, filters, options.dup] + end - # This is used internally to append, prepend and skip callbacks to the - # CallbackChain. - def __update_callbacks(name) #:nodoc: - ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target| - chain = target.get_callbacks name - yield target, chain.dup + # This is used internally to append, prepend and skip callbacks to the + # CallbackChain. + def __update_callbacks(name) #:nodoc: + ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target| + chain = target.get_callbacks name + yield target, chain.dup + end end - end - # Install a callback for the given event. - # - # set_callback :save, :before, :before_method - # set_callback :save, :after, :after_method, if: :condition - # set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff } - # - # The second argument indicates whether the callback is to be run +:before+, - # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This - # means the first example above can also be written as: - # - # set_callback :save, :before_method - # - # The callback can be specified as a symbol naming an instance method; as a - # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an - # object that responds to a certain method determined by the <tt>:scope</tt> - # argument to +define_callbacks+. - # - # If a proc, lambda, or block is given, its body is evaluated in the context - # of the current object. It can also optionally accept the current object as - # an argument. - # - # Before and around callbacks are called in the order that they are set; - # after callbacks are called in the reverse order. - # - # Around callbacks can access the return value from the event, if it - # wasn't halted, from the +yield+ call. - # - # ===== Options - # - # * <tt>:if</tt> - A symbol, a string or an array of symbols and strings, - # each naming an instance method or a proc; the callback will be called - # only when they all return a true value. - # * <tt>:unless</tt> - A symbol, a string or an array of symbols and - # strings, each naming an instance method or a proc; the callback will - # be called only when they all return a false value. - # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the - # existing chain rather than appended. - def set_callback(name, *filter_list, &block) - type, filters, options = normalize_callback_params(filter_list, block) - self_chain = get_callbacks name - mapped = filters.map do |filter| - Callback.build(self_chain, filter, type, options) - end - - __update_callbacks(name) do |target, chain| - options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) - target.set_callbacks name, chain + # Install a callback for the given event. + # + # set_callback :save, :before, :before_method + # set_callback :save, :after, :after_method, if: :condition + # set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff } + # + # The second argument indicates whether the callback is to be run +:before+, + # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This + # means the first example above can also be written as: + # + # set_callback :save, :before_method + # + # The callback can be specified as a symbol naming an instance method; as a + # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an + # object that responds to a certain method determined by the <tt>:scope</tt> + # argument to +define_callbacks+. + # + # If a proc, lambda, or block is given, its body is evaluated in the context + # of the current object. It can also optionally accept the current object as + # an argument. + # + # Before and around callbacks are called in the order that they are set; + # after callbacks are called in the reverse order. + # + # Around callbacks can access the return value from the event, if it + # wasn't halted, from the +yield+ call. + # + # ===== Options + # + # * <tt>:if</tt> - A symbol, a string or an array of symbols and strings, + # each naming an instance method or a proc; the callback will be called + # only when they all return a true value. + # * <tt>:unless</tt> - A symbol, a string or an array of symbols and + # strings, each naming an instance method or a proc; the callback will + # be called only when they all return a false value. + # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the + # existing chain rather than appended. + def set_callback(name, *filter_list, &block) + type, filters, options = normalize_callback_params(filter_list, block) + self_chain = get_callbacks name + mapped = filters.map do |filter| + Callback.build(self_chain, filter, type, options) + end + + __update_callbacks(name) do |target, chain| + options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) + target.set_callbacks name, chain + end end - end - # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or - # <tt>:unless</tt> options may be passed in order to control when the - # callback is skipped. - # - # class Writer < Person - # skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 } - # end - # - # An <tt>ArgumentError</tt> will be raised if the callback has not - # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>). - def skip_callback(name, *filter_list, &block) - type, filters, options = normalize_callback_params(filter_list, block) - options[:raise] = true unless options.key?(:raise) - - __update_callbacks(name) do |target, chain| - filters.each do |filter| - callback = chain.find {|c| c.matches?(type, filter) } - - if !callback && options[:raise] - raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined" - end + # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or + # <tt>:unless</tt> options may be passed in order to control when the + # callback is skipped. + # + # class Writer < Person + # skip_callback :validate, :before, :check_membership, if: -> { age > 18 } + # end + # + # An <tt>ArgumentError</tt> will be raised if the callback has not + # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>). + def skip_callback(name, *filter_list, &block) + type, filters, options = normalize_callback_params(filter_list, block) + options[:raise] = true unless options.key?(:raise) + + __update_callbacks(name) do |target, chain| + filters.each do |filter| + callback = chain.find { |c| c.matches?(type, filter) } + + if !callback && options[:raise] + raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined" + end - if callback && (options.key?(:if) || options.key?(:unless)) - new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless]) - chain.insert(chain.index(callback), new_callback) - end + if callback && (options.key?(:if) || options.key?(:unless)) + new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless]) + chain.insert(chain.index(callback), new_callback) + end - chain.delete(callback) + chain.delete(callback) + end + target.set_callbacks name, chain end - target.set_callbacks name, chain end - end - # Remove all set callbacks for the given event. - def reset_callbacks(name) - callbacks = get_callbacks name + # Remove all set callbacks for the given event. + def reset_callbacks(name) + callbacks = get_callbacks name + + ActiveSupport::DescendantsTracker.descendants(self).each do |target| + chain = target.get_callbacks(name).dup + callbacks.each { |c| chain.delete(c) } + target.set_callbacks name, chain + end - ActiveSupport::DescendantsTracker.descendants(self).each do |target| - chain = target.get_callbacks(name).dup - callbacks.each { |c| chain.delete(c) } - target.set_callbacks name, chain + set_callbacks(name, callbacks.dup.clear) end - self.set_callbacks name, callbacks.dup.clear - end + # Define sets of events in the object life cycle that support callbacks. + # + # define_callbacks :validate + # define_callbacks :initialize, :save, :destroy + # + # ===== Options + # + # * <tt>:terminator</tt> - Determines when a before filter will halt the + # callback chain, preventing following before and around callbacks from + # being called and the event from being triggered. + # This should be a lambda to be executed. + # The current object and the result lambda of the callback will be provided + # to the terminator lambda. + # + # define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false } + # + # In this example, if any before validate callbacks returns +false+, + # any successive before and around callback is not executed. + # + # The default terminator halts the chain when a callback throws +:abort+. + # + # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after + # callbacks should be terminated by the <tt>:terminator</tt> option. By + # default after callbacks are executed no matter if callback chain was + # terminated or not. This option makes sense only when <tt>:terminator</tt> + # option is specified. + # + # * <tt>:scope</tt> - Indicates which methods should be executed when an + # object is used as a callback. + # + # class Audit + # def before(caller) + # puts 'Audit: before is called' + # end + # + # def before_save(caller) + # puts 'Audit: before_save is called' + # end + # end + # + # class Account + # include ActiveSupport::Callbacks + # + # define_callbacks :save + # set_callback :save, :before, Audit.new + # + # def save + # run_callbacks :save do + # puts 'save in main' + # end + # end + # end + # + # In the above case whenever you save an account the method + # <tt>Audit#before</tt> will be called. On the other hand + # + # define_callbacks :save, scope: [:kind, :name] + # + # would trigger <tt>Audit#before_save</tt> instead. That's constructed + # by calling <tt>#{kind}_#{name}</tt> on the given instance. In this + # case "kind" is "before" and "name" is "save". In this context +:kind+ + # and +:name+ have special meanings: +:kind+ refers to the kind of + # callback (before/after/around) and +:name+ refers to the method on + # which callbacks are being defined. + # + # A declaration like + # + # define_callbacks :save, scope: [:name] + # + # would call <tt>Audit#save</tt>. + # + # ===== Notes + # + # +names+ passed to +define_callbacks+ must not end with + # <tt>!</tt>, <tt>?</tt> or <tt>=</tt>. + # + # Calling +define_callbacks+ multiple times with the same +names+ will + # overwrite previous callbacks registered with +set_callback+. + def define_callbacks(*names) + options = names.extract_options! + + names.each do |name| + name = name.to_sym + + set_callbacks name, CallbackChain.new(name, options) + + module_eval <<-RUBY, __FILE__, __LINE__ + 1 + def _run_#{name}_callbacks(&block) + run_callbacks #{name.inspect}, &block + end - # Define sets of events in the object life cycle that support callbacks. - # - # define_callbacks :validate - # define_callbacks :initialize, :save, :destroy - # - # ===== Options - # - # * <tt>:terminator</tt> - Determines when a before filter will halt the - # callback chain, preventing following before and around callbacks from - # being called and the event from being triggered. - # This should be a lambda to be executed. - # The current object and the result lambda of the callback will be provided - # to the terminator lambda. - # - # define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false } - # - # In this example, if any before validate callbacks returns +false+, - # any successive before and around callback is not executed. - # - # The default terminator halts the chain when a callback throws +:abort+. - # - # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after - # callbacks should be terminated by the <tt>:terminator</tt> option. By - # default after callbacks are executed no matter if callback chain was - # terminated or not. This option makes sense only when <tt>:terminator</tt> - # option is specified. - # - # * <tt>:scope</tt> - Indicates which methods should be executed when an - # object is used as a callback. - # - # class Audit - # def before(caller) - # puts 'Audit: before is called' - # end - # - # def before_save(caller) - # puts 'Audit: before_save is called' - # end - # end - # - # class Account - # include ActiveSupport::Callbacks - # - # define_callbacks :save - # set_callback :save, :before, Audit.new - # - # def save - # run_callbacks :save do - # puts 'save in main' - # end - # end - # end - # - # In the above case whenever you save an account the method - # <tt>Audit#before</tt> will be called. On the other hand - # - # define_callbacks :save, scope: [:kind, :name] - # - # would trigger <tt>Audit#before_save</tt> instead. That's constructed - # by calling <tt>#{kind}_#{name}</tt> on the given instance. In this - # case "kind" is "before" and "name" is "save". In this context +:kind+ - # and +:name+ have special meanings: +:kind+ refers to the kind of - # callback (before/after/around) and +:name+ refers to the method on - # which callbacks are being defined. - # - # A declaration like - # - # define_callbacks :save, scope: [:name] - # - # would call <tt>Audit#save</tt>. - # - # ===== Notes - # - # +names+ passed to `define_callbacks` must not end with - # `!`, `?` or `=`. - # - # Calling `define_callbacks` multiple times with the same +names+ will - # overwrite previous callbacks registered with `set_callback`. - def define_callbacks(*names) - options = names.extract_options! - - names.each do |name| - class_attribute "_#{name}_callbacks", instance_writer: false - set_callbacks name, CallbackChain.new(name, options) - - module_eval <<-RUBY, __FILE__, __LINE__ + 1 - def _run_#{name}_callbacks(&block) - __run_callbacks__(_#{name}_callbacks, &block) - end - RUBY + def self._#{name}_callbacks + get_callbacks(#{name.inspect}) + end + + def self._#{name}_callbacks=(value) + set_callbacks(#{name.inspect}, value) + end + + def _#{name}_callbacks + __callbacks[#{name.inspect}] + end + RUBY + end end - end - protected + protected - def get_callbacks(name) # :nodoc: - send "_#{name}_callbacks" - end + def get_callbacks(name) # :nodoc: + __callbacks[name.to_sym] + end - def set_callbacks(name, callbacks) # :nodoc: - send "_#{name}_callbacks=", callbacks - end + def set_callbacks(name, callbacks) # :nodoc: + self.__callbacks = __callbacks.merge(name.to_sym => callbacks) + end - def deprecated_false_terminator # :nodoc: - Proc.new do |target, result_lambda| - terminate = true - catch(:abort) do - result = result_lambda.call if result_lambda.is_a?(Proc) - if Callbacks.halt_and_display_warning_on_return_false && result == false - display_deprecation_warning_for_false_terminator - else - terminate = false + def deprecated_false_terminator # :nodoc: + Proc.new do |target, result_lambda| + terminate = true + catch(:abort) do + result = result_lambda.call if result_lambda.is_a?(Proc) + if Callbacks.halt_and_display_warning_on_return_false && result == false + display_deprecation_warning_for_false_terminator + else + terminate = false + end + end + terminate end end - terminate - end - end - private + private - def display_deprecation_warning_for_false_terminator - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1. - To explicitly halt the callback chain, please use `throw :abort` instead. - MSG + def display_deprecation_warning_for_false_terminator + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1. + To explicitly halt the callback chain, please use `throw :abort` instead. + MSG + end end - end end end diff --git a/activesupport/lib/active_support/concurrency/latch.rb b/activesupport/lib/active_support/concurrency/latch.rb index 4abe5ece6f..53e09b685c 100644 --- a/activesupport/lib/active_support/concurrency/latch.rb +++ b/activesupport/lib/active_support/concurrency/latch.rb @@ -1,18 +1,24 @@ -require 'concurrent/atomic/count_down_latch' +require "concurrent/atomic/count_down_latch" module ActiveSupport module Concurrency - class Latch < Concurrent::CountDownLatch - + class Latch def initialize(count = 1) - ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::CountDownLatch instead.") - super(count) + if count == 1 + ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::Event instead.") + else + ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::CountDownLatch instead.") + end + + @inner = Concurrent::CountDownLatch.new(count) end - alias_method :release, :count_down + def release + @inner.count_down + end def await - wait(nil) + @inner.wait(nil) end end end diff --git a/activesupport/lib/active_support/concurrency/share_lock.rb b/activesupport/lib/active_support/concurrency/share_lock.rb index 89e63aefd4..4318523b07 100644 --- a/activesupport/lib/active_support/concurrency/share_lock.rb +++ b/activesupport/lib/active_support/concurrency/share_lock.rb @@ -1,5 +1,5 @@ -require 'thread' -require 'monitor' +require "thread" +require "monitor" module ActiveSupport module Concurrency @@ -13,6 +13,37 @@ module ActiveSupport # we need exclusive locks to be reentrant, and we need to be able # to upgrade share locks to exclusive. + def raw_state # :nodoc: + synchronize do + threads = @sleeping.keys | @sharing.keys | @waiting.keys + threads |= [@exclusive_thread] if @exclusive_thread + + data = {} + + threads.each do |thread| + purpose, compatible = @waiting[thread] + + data[thread] = { + thread: thread, + sharing: @sharing[thread], + exclusive: @exclusive_thread == thread, + purpose: purpose, + compatible: compatible, + waiting: !!@waiting[thread], + sleeper: @sleeping[thread], + } + end + + # NB: Yields while holding our *internal* synchronize lock, + # which is supposed to be used only for a few instructions at + # a time. This allows the caller to inspect additional state + # without things changing out from underneath, but would have + # disastrous effects upon normal operation. Fortunately, this + # method is only intended to be called when things have + # already gone wrong. + yield data + end + end def initialize super() @@ -21,6 +52,7 @@ module ActiveSupport @sharing = Hash.new(0) @waiting = {} + @sleeping = {} @exclusive_thread = nil @exclusive_depth = 0 end @@ -46,7 +78,7 @@ module ActiveSupport return false if no_wait yield_shares(purpose: purpose, compatible: compatible, block_share: true) do - @cv.wait_while { busy_for_exclusive?(purpose) } + wait_for(:start_exclusive) { busy_for_exclusive?(purpose) } end end @exclusive_thread = Thread.current @@ -69,7 +101,7 @@ module ActiveSupport if eligible_waiters?(compatible) yield_shares(compatible: compatible, block_share: true) do - @cv.wait_while { @exclusive_thread || eligible_waiters?(compatible) } + wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) } end end @cv.broadcast @@ -84,11 +116,11 @@ module ActiveSupport elsif @waiting[Thread.current] # We're nested inside a +yield_shares+ call: we'll resume as # soon as there isn't an exclusive lock in our way - @cv.wait_while { @exclusive_thread } + wait_for(:start_sharing) { @exclusive_thread } else # This is an initial / outermost share call: any outstanding # requests for an exclusive lock get to go first - @cv.wait_while { busy_for_sharing?(false) } + wait_for(:start_sharing) { busy_for_sharing?(false) } end @sharing[Thread.current] += 1 end @@ -153,7 +185,7 @@ module ActiveSupport yield ensure synchronize do - @cv.wait_while { @exclusive_thread && @exclusive_thread != Thread.current } + wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current } if previous_wait @waiting[Thread.current] = previous_wait @@ -167,20 +199,27 @@ module ActiveSupport private - # Must be called within synchronize - def busy_for_exclusive?(purpose) - busy_for_sharing?(purpose) || - @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0) - end + # Must be called within synchronize + def busy_for_exclusive?(purpose) + busy_for_sharing?(purpose) || + @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0) + end - def busy_for_sharing?(purpose) - (@exclusive_thread && @exclusive_thread != Thread.current) || - @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) } - end + def busy_for_sharing?(purpose) + (@exclusive_thread && @exclusive_thread != Thread.current) || + @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) } + end - def eligible_waiters?(compatible) - @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } } - end + def eligible_waiters?(compatible) + @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } } + end + + def wait_for(method) + @sleeping[Thread.current] = method + @cv.wait_while { yield } + ensure + @sleeping.delete Thread.current + end end end end diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb index 8256c325af..f72a893bcc 100644 --- a/activesupport/lib/active_support/configurable.rb +++ b/activesupport/lib/active_support/configurable.rb @@ -1,6 +1,7 @@ -require 'active_support/concern' -require 'active_support/ordered_options' -require 'active_support/core_ext/array/extract_options' +require "active_support/concern" +require "active_support/ordered_options" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" module ActiveSupport # Configurable provides a <tt>config</tt> method to store and retrieve @@ -107,7 +108,7 @@ module ActiveSupport options = names.extract_options! names.each do |name| - raise NameError.new('invalid config attribute name') unless name =~ /\A[_A-Za-z]\w*\z/ + raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name) reader, reader_line = "def #{name}; config.#{name}; end", __LINE__ writer, writer_line = "def #{name}=(value); config.#{name} = value; end", __LINE__ @@ -145,4 +146,3 @@ module ActiveSupport end end end - diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb index 7551551bd7..e908386a1c 100644 --- a/activesupport/lib/active_support/core_ext/array.rb +++ b/activesupport/lib/active_support/core_ext/array.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/array/access' -require 'active_support/core_ext/array/conversions' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/array/grouping' -require 'active_support/core_ext/array/prepend_and_append' -require 'active_support/core_ext/array/inquiry' +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/array/access" +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/array/grouping" +require "active_support/core_ext/array/prepend_and_append" +require "active_support/core_ext/array/inquiry" diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 8718b7e1e5..1d4c83ae52 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -1,8 +1,8 @@ -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' +require "active_support/xml_mini" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" class Array # Converts the array to a comma-separated sentence where the last element is @@ -40,6 +40,12 @@ class Array # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ') # # => "one or two or at least three" # + # [].to_sentence(fallback_string: 'none') + # # => "none" + # + # ['one', 'two'].to_sentence(fallback_string: 'none') + # # => "one and two" + # # Using <tt>:locale</tt> option: # # # Given this locale dictionary: @@ -57,12 +63,12 @@ class Array # ['uno', 'dos', 'tres'].to_sentence(locale: :es) # # => "uno o dos o al menos tres" def to_sentence(options = {}) - options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) + options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale, :fallback_string) default_connectors = { - :words_connector => ', ', - :two_words_connector => ' and ', - :last_word_connector => ', and ' + words_connector: ", ", + two_words_connector: " and ", + last_word_connector: ", and " } if defined?(I18n) i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {}) @@ -72,7 +78,7 @@ class Array case length when 0 - '' + "#{options[:fallback_string] || ''}" when 1 "#{self[0]}" when 2 @@ -92,9 +98,9 @@ class Array case format when :db if empty? - 'null' + "null" else - collect(&:id).join(',') + collect(&:id).join(",") end else to_default_s @@ -179,7 +185,7 @@ class Array # </messages> # def to_xml(options = {}) - require 'active_support/builder' unless defined?(Builder) + require "active_support/builder" unless defined?(Builder) options = options.dup options[:indent] ||= 2 @@ -187,9 +193,9 @@ class Array options[:root] ||= \ if first.class != Hash && all? { |e| e.is_a?(first.class) } underscored = ActiveSupport::Inflector.underscore(first.class.name) - ActiveSupport::Inflector.pluralize(underscored).tr('/', '_') + ActiveSupport::Inflector.pluralize(underscored).tr("/", "_") else - 'objects' + "objects" end builder = options[:builder] @@ -197,7 +203,7 @@ class Array root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options) children = options.delete(:children) || root.singularize - attributes = options[:skip_types] ? {} : { type: 'array' } + attributes = options[:skip_types] ? {} : { type: "array" } if empty? builder.tag!(root, attributes) diff --git a/activesupport/lib/active_support/core_ext/array/inquiry.rb b/activesupport/lib/active_support/core_ext/array/inquiry.rb index e8f44cc378..66fa5fcd0c 100644 --- a/activesupport/lib/active_support/core_ext/array/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/array/inquiry.rb @@ -1,4 +1,4 @@ -require 'active_support/array_inquirer' +require "active_support/array_inquirer" class Array # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way diff --git a/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb index f8d48b69df..16a6789f8d 100644 --- a/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb +++ b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb @@ -4,4 +4,4 @@ class Array # The human way of thinking about adding stuff to the beginning of a list is with prepend. alias_method :prepend, :unshift -end
\ No newline at end of file +end diff --git a/activesupport/lib/active_support/core_ext/benchmark.rb b/activesupport/lib/active_support/core_ext/benchmark.rb index eb25b2bc44..2300953860 100644 --- a/activesupport/lib/active_support/core_ext/benchmark.rb +++ b/activesupport/lib/active_support/core_ext/benchmark.rb @@ -1,4 +1,4 @@ -require 'benchmark' +require "benchmark" class << Benchmark # Benchmark realtime in milliseconds. diff --git a/activesupport/lib/active_support/core_ext/big_decimal.rb b/activesupport/lib/active_support/core_ext/big_decimal.rb index 8143113cfa..7b4f87f10e 100644 --- a/activesupport/lib/active_support/core_ext/big_decimal.rb +++ b/activesupport/lib/active_support/core_ext/big_decimal.rb @@ -1 +1 @@ -require 'active_support/core_ext/big_decimal/conversions' +require "active_support/core_ext/big_decimal/conversions" diff --git a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb index 074e2eabf8..decd4e1699 100644 --- a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb +++ b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb @@ -1,9 +1,9 @@ -require 'bigdecimal' -require 'bigdecimal/util' +require "bigdecimal" +require "bigdecimal/util" module ActiveSupport module BigDecimalWithDefaultFormat #:nodoc: - def to_s(format = 'F') + def to_s(format = "F") super(format) end end diff --git a/activesupport/lib/active_support/core_ext/class.rb b/activesupport/lib/active_support/core_ext/class.rb index ef903d59b5..6a19e862d0 100644 --- a/activesupport/lib/active_support/core_ext/class.rb +++ b/activesupport/lib/active_support/core_ext/class.rb @@ -1,2 +1,2 @@ -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/class/subclasses' +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/class/subclasses" diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb index 802d988af2..ba422f9071 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/remove_method' -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/array/extract_options" class Class # Declare a class-level attribute whose value is inheritable by subclasses. @@ -20,14 +20,14 @@ class Class # Base.setting # => true # # In the above case as long as Subclass does not assign a value to setting - # by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt> + # by performing <tt>Subclass.setting = _something_</tt>, <tt>Subclass.setting</tt> # would read value assigned to parent class. Once Subclass assigns a value then # the value assigned by Subclass would be returned. # # This matches normal Ruby method inheritance: think of writing an attribute # on a subclass as overriding the reader method. However, you need to be aware # when using +class_attribute+ with mutable structures as +Array+ or +Hash+. - # In such cases, you don't want to do changes in places but use setters: + # In such cases, you don't want to do changes in place. Instead use setters: # # Base.setting = [] # Base.setting # => [] diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb index 84d5e95e7a..0f767925ed 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb @@ -1,4 +1,4 @@ # cattr_* became mattr_* aliases in 7dfbd91b0780fbd6a1dd9bfbc176e10894871d2d, # but we keep this around for libraries that directly require it knowing they # want cattr_*. No need to deprecate. -require 'active_support/core_ext/module/attribute_accessors' +require "active_support/core_ext/module/attribute_accessors" diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb index 1d8c33b43e..10a7c787f6 100644 --- a/activesupport/lib/active_support/core_ext/class/subclasses.rb +++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb @@ -1,12 +1,25 @@ -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/module/reachable' +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/reachable" class Class begin # Test if this Ruby supports each_object against singleton_class ObjectSpace.each_object(Numeric.singleton_class) {} - def descendants # :nodoc: + # Returns an array with all classes that are < than its receiver. + # + # class C; end + # C.descendants # => [] + # + # class B < C; end + # C.descendants # => [B] + # + # class A < B; end + # C.descendants # => [B, A] + # + # class D < C; end + # C.descendants # => [B, A, D] + def descendants descendants = [] ObjectSpace.each_object(singleton_class) do |k| descendants.unshift k unless k == self @@ -14,7 +27,7 @@ class Class descendants end rescue StandardError # JRuby 9.0.4.0 and earlier - def descendants # :nodoc: + def descendants descendants = [] ObjectSpace.each_object(Class) do |k| descendants.unshift k if k < self diff --git a/activesupport/lib/active_support/core_ext/date.rb b/activesupport/lib/active_support/core_ext/date.rb index 7f0f4639a2..4f66804da2 100644 --- a/activesupport/lib/active_support/core_ext/date.rb +++ b/activesupport/lib/active_support/core_ext/date.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/date/acts_like' -require 'active_support/core_ext/date/blank' -require 'active_support/core_ext/date/calculations' -require 'active_support/core_ext/date/conversions' -require 'active_support/core_ext/date/zones' +require "active_support/core_ext/date/acts_like" +require "active_support/core_ext/date/blank" +require "active_support/core_ext/date/calculations" +require "active_support/core_ext/date/conversions" +require "active_support/core_ext/date/zones" diff --git a/activesupport/lib/active_support/core_ext/date/acts_like.rb b/activesupport/lib/active_support/core_ext/date/acts_like.rb index cd90cee236..46fe99ad47 100644 --- a/activesupport/lib/active_support/core_ext/date/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/date/acts_like.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/acts_like' +require "active_support/core_ext/object/acts_like" class Date # Duck-types as a Date-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/date/blank.rb b/activesupport/lib/active_support/core_ext/date/blank.rb index 71627b6a6f..edd2847126 100644 --- a/activesupport/lib/active_support/core_ext/date/blank.rb +++ b/activesupport/lib/active_support/core_ext/date/blank.rb @@ -1,4 +1,4 @@ -require 'date' +require "date" class Date #:nodoc: # No Date is blank: diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index d589b67bf7..2e64097933 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -1,9 +1,9 @@ -require 'date' -require 'active_support/duration' -require 'active_support/core_ext/object/acts_like' -require 'active_support/core_ext/date/zones' -require 'active_support/core_ext/time/zones' -require 'active_support/core_ext/date_and_time/calculations' +require "date" +require "active_support/duration" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/date/zones" +require "active_support/core_ext/time/zones" +require "active_support/core_ext/date_and_time/calculations" class Date include DateAndTime::Calculations @@ -129,7 +129,7 @@ class Date options.fetch(:day, day) ) end - + # Allow Date to be compared with Time by converting to DateTime and relying on the <=> from there. def compare_with_coercion(other) if other.is_a?(Time) diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb index 6e3b4a89ce..d553406dff 100644 --- a/activesupport/lib/active_support/core_ext/date/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date/conversions.rb @@ -1,20 +1,20 @@ -require 'date' -require 'active_support/inflector/methods' -require 'active_support/core_ext/date/zones' -require 'active_support/core_ext/module/remove_method' +require "date" +require "active_support/inflector/methods" +require "active_support/core_ext/date/zones" +require "active_support/core_ext/module/remove_method" class Date DATE_FORMATS = { - :short => '%d %b', - :long => '%B %d, %Y', - :db => '%Y-%m-%d', - :number => '%Y%m%d', - :long_ordinal => lambda { |date| + short: "%d %b", + long: "%B %d, %Y", + db: "%Y-%m-%d", + number: "%Y%m%d", + long_ordinal: lambda { |date| day_format = ActiveSupport::Inflector.ordinalize(date.day) date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007" }, - :rfc822 => '%d %b %Y', - :iso8601 => lambda { |date| date.iso8601 } + rfc822: "%d %b %Y", + iso8601: lambda { |date| date.iso8601 } } # Ruby 1.9 has Date#to_time which converts to localtime only. @@ -65,7 +65,7 @@ class Date # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005" def readable_inspect - strftime('%a, %d %b %Y') + strftime("%a, %d %b %Y") end alias_method :default_inspect, :inspect alias_method :inspect, :readable_inspect diff --git a/activesupport/lib/active_support/core_ext/date/zones.rb b/activesupport/lib/active_support/core_ext/date/zones.rb index d109b430db..da23fe4892 100644 --- a/activesupport/lib/active_support/core_ext/date/zones.rb +++ b/activesupport/lib/active_support/core_ext/date/zones.rb @@ -1,5 +1,5 @@ -require 'date' -require 'active_support/core_ext/date_and_time/zones' +require "date" +require "active_support/core_ext/date_and_time/zones" class Date include DateAndTime::Zones diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb index 6206546672..f2ba7fdda5 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb @@ -1,15 +1,15 @@ -require 'active_support/core_ext/object/try' +require "active_support/core_ext/object/try" module DateAndTime module Calculations DAYS_INTO_WEEK = { - :monday => 0, - :tuesday => 1, - :wednesday => 2, - :thursday => 3, - :friday => 4, - :saturday => 5, - :sunday => 6 + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6 } WEEKEND_DAYS = [ 6, 0 ] @@ -60,42 +60,42 @@ module DateAndTime # Returns a new date/time the specified number of days ago. def days_ago(days) - advance(:days => -days) + advance(days: -days) end # Returns a new date/time the specified number of days in the future. def days_since(days) - advance(:days => days) + advance(days: days) end # Returns a new date/time the specified number of weeks ago. def weeks_ago(weeks) - advance(:weeks => -weeks) + advance(weeks: -weeks) end # Returns a new date/time the specified number of weeks in the future. def weeks_since(weeks) - advance(:weeks => weeks) + advance(weeks: weeks) end # Returns a new date/time the specified number of months ago. def months_ago(months) - advance(:months => -months) + advance(months: -months) end # Returns a new date/time the specified number of months in the future. def months_since(months) - advance(:months => months) + advance(months: months) end # Returns a new date/time the specified number of years ago. def years_ago(years) - advance(:years => -years) + advance(years: -years) end # Returns a new date/time the specified number of years in the future. def years_since(years) - advance(:years => years) + advance(years: years) end # Returns a new date/time at the start of the month. @@ -108,7 +108,7 @@ module DateAndTime # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000 # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000 def beginning_of_month - first_hour(change(:day => 1)) + first_hour(change(day: 1)) end alias :at_beginning_of_month :beginning_of_month @@ -123,7 +123,7 @@ module DateAndTime # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000 def beginning_of_quarter first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month } - beginning_of_month.change(:month => first_quarter_month) + beginning_of_month.change(month: first_quarter_month) end alias :at_beginning_of_quarter :beginning_of_quarter @@ -138,7 +138,7 @@ module DateAndTime # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000 def end_of_quarter last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month } - beginning_of_month.change(:month => last_quarter_month).end_of_month + beginning_of_month.change(month: last_quarter_month).end_of_month end alias :at_end_of_quarter :end_of_quarter @@ -152,7 +152,7 @@ module DateAndTime # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000 # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000 def beginning_of_year - change(:month => 1).beginning_of_month + change(month: 1).beginning_of_month end alias :at_beginning_of_year :beginning_of_year @@ -290,7 +290,7 @@ module DateAndTime # Returns a new date/time representing the end of the year. # DateTime objects will have a time set to 23:59:59. def end_of_year - change(:month => 12).end_of_month + change(month: 12).end_of_month end alias :at_end_of_year :end_of_year @@ -300,7 +300,7 @@ module DateAndTime end # Returns a Range representing the whole week of the current date/time. - # Week starts on start_day, default is <tt>Date.week_start</tt> or <tt>config.week_start</tt> when set. + # Week starts on start_day, default is <tt>Date.beginning_of_week</tt> or <tt>config.beginning_of_week</tt> when set. def all_week(start_day = Date.beginning_of_week) beginning_of_week(start_day)..end_of_week(start_day) end @@ -334,7 +334,7 @@ module DateAndTime end def copy_time_to(other) - other.change(hour: hour, min: min, sec: sec, usec: try(:usec)) + other.change(hour: hour, min: min, sec: sec, nsec: try(:nsec)) end end end diff --git a/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb b/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb index 19e596a144..db95ae0db5 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/module/attribute_accessors' +require "active_support/core_ext/module/attribute_accessors" module DateAndTime module Compatibility @@ -12,7 +12,11 @@ module DateAndTime mattr_accessor(:preserve_timezone, instance_writer: false) { false } def to_time - preserve_timezone ? getlocal(utc_offset) : getlocal + if preserve_timezone + @_to_time_with_instance_offset ||= getlocal(utc_offset) + else + @_to_time_with_system_offset ||= getlocal + end end end end diff --git a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb index e2432c8f8a..edd724f1d0 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb @@ -22,19 +22,18 @@ module DateAndTime if time_zone time_with_zone(time, time_zone) else - time || self.to_time + time || to_time end end private - def time_with_zone(time, zone) - if time - ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone) - else - ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc)) + def time_with_zone(time, zone) + if time + ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone) + else + ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc)) + end end - end end end - diff --git a/activesupport/lib/active_support/core_ext/date_time.rb b/activesupport/lib/active_support/core_ext/date_time.rb index 86177488c0..6fd498f864 100644 --- a/activesupport/lib/active_support/core_ext/date_time.rb +++ b/activesupport/lib/active_support/core_ext/date_time.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/date_time/acts_like' -require 'active_support/core_ext/date_time/blank' -require 'active_support/core_ext/date_time/calculations' -require 'active_support/core_ext/date_time/compatibility' -require 'active_support/core_ext/date_time/conversions' +require "active_support/core_ext/date_time/acts_like" +require "active_support/core_ext/date_time/blank" +require "active_support/core_ext/date_time/calculations" +require "active_support/core_ext/date_time/compatibility" +require "active_support/core_ext/date_time/conversions" diff --git a/activesupport/lib/active_support/core_ext/date_time/acts_like.rb b/activesupport/lib/active_support/core_ext/date_time/acts_like.rb index 8fbbe0d3e9..6f50f55a53 100644 --- a/activesupport/lib/active_support/core_ext/date_time/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/date_time/acts_like.rb @@ -1,5 +1,5 @@ -require 'date' -require 'active_support/core_ext/object/acts_like' +require "date" +require "active_support/core_ext/object/acts_like" class DateTime # Duck-types as a Date-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/date_time/blank.rb b/activesupport/lib/active_support/core_ext/date_time/blank.rb index 56981b75fb..b475fd926d 100644 --- a/activesupport/lib/active_support/core_ext/date_time/blank.rb +++ b/activesupport/lib/active_support/core_ext/date_time/blank.rb @@ -1,4 +1,4 @@ -require 'date' +require "date" class DateTime #:nodoc: # No DateTime is ever blank: diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb index 9e89a33491..70d5c9af8e 100644 --- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb @@ -1,4 +1,4 @@ -require 'date' +require "date" class DateTime class << self @@ -75,7 +75,7 @@ class DateTime end d = to_date.advance(options) - datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) + datetime_advanced_by_date = change(year: d.year, month: d.month, day: d.day) seconds_to_advance = \ options.fetch(:seconds, 0) + options.fetch(:minutes, 0) * 60 + @@ -104,7 +104,7 @@ class DateTime # Returns a new DateTime representing the start of the day (0:00). def beginning_of_day - change(:hour => 0) + change(hour: 0) end alias :midnight :beginning_of_day alias :at_midnight :beginning_of_day @@ -112,7 +112,7 @@ class DateTime # Returns a new DateTime representing the middle of the day (12:00) def middle_of_day - change(:hour => 12) + change(hour: 12) end alias :midday :middle_of_day alias :noon :middle_of_day @@ -122,31 +122,31 @@ class DateTime # Returns a new DateTime representing the end of the day (23:59:59). def end_of_day - change(:hour => 23, :min => 59, :sec => 59) + change(hour: 23, min: 59, sec: 59) end alias :at_end_of_day :end_of_day # Returns a new DateTime representing the start of the hour (hh:00:00). def beginning_of_hour - change(:min => 0) + change(min: 0) end alias :at_beginning_of_hour :beginning_of_hour # Returns a new DateTime representing the end of the hour (hh:59:59). def end_of_hour - change(:min => 59, :sec => 59) + change(min: 59, sec: 59) end alias :at_end_of_hour :end_of_hour # Returns a new DateTime representing the start of the minute (hh:mm:00). def beginning_of_minute - change(:sec => 0) + change(sec: 0) end alias :at_beginning_of_minute :beginning_of_minute # Returns a new DateTime representing the end of the minute (hh:mm:59). def end_of_minute - change(:sec => 59) + change(sec: 59) end alias :at_end_of_minute :end_of_minute diff --git a/activesupport/lib/active_support/core_ext/date_time/compatibility.rb b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb index 03e4a2adfa..30bb7f4a60 100644 --- a/activesupport/lib/active_support/core_ext/date_time/compatibility.rb +++ b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/date_and_time/compatibility' +require "active_support/core_ext/date_and_time/compatibility" class DateTime prepend DateAndTime::Compatibility diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb index f59d05b214..44ae96dbe8 100644 --- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb @@ -1,8 +1,8 @@ -require 'date' -require 'active_support/inflector/methods' -require 'active_support/core_ext/time/conversions' -require 'active_support/core_ext/date_time/calculations' -require 'active_support/values/time_zone' +require "date" +require "active_support/inflector/methods" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/date_time/calculations" +require "active_support/values/time_zone" class DateTime # Convert to a formatted string. See Time::DATE_FORMATS for predefined formats. @@ -95,11 +95,11 @@ class DateTime private - def offset_in_seconds - (offset * 86400).to_i - end + def offset_in_seconds + (offset * 86400).to_i + end - def seconds_since_unix_epoch - (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight - end + def seconds_since_unix_epoch + (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight + end end diff --git a/activesupport/lib/active_support/core_ext/digest/uuid.rb b/activesupport/lib/active_support/core_ext/digest/uuid.rb index 593c51bba2..e6d60e3267 100644 --- a/activesupport/lib/active_support/core_ext/digest/uuid.rb +++ b/activesupport/lib/active_support/core_ext/digest/uuid.rb @@ -1,4 +1,4 @@ -require 'securerandom' +require "securerandom" module Digest module UUID @@ -26,7 +26,7 @@ module Digest hash.update(uuid_namespace) hash.update(name) - ary = hash.digest.unpack('NnnnnN') + ary = hash.digest.unpack("NnnnnN") ary[2] = (ary[2] & 0x0FFF) | (version << 12) ary[3] = (ary[3] & 0x3FFF) | 0x8000 @@ -35,12 +35,12 @@ module Digest # Convenience method for uuid_from_hash using Digest::MD5. def self.uuid_v3(uuid_namespace, name) - self.uuid_from_hash(Digest::MD5, uuid_namespace, name) + uuid_from_hash(Digest::MD5, uuid_namespace, name) end # Convenience method for uuid_from_hash using Digest::SHA1. def self.uuid_v5(uuid_namespace, name) - self.uuid_from_hash(Digest::SHA1, uuid_namespace, name) + uuid_from_hash(Digest::SHA1, uuid_namespace, name) end # Convenience method for SecureRandom.uuid. diff --git a/activesupport/lib/active_support/core_ext/file.rb b/activesupport/lib/active_support/core_ext/file.rb index dc24afbe7f..6d99bad2af 100644 --- a/activesupport/lib/active_support/core_ext/file.rb +++ b/activesupport/lib/active_support/core_ext/file.rb @@ -1 +1 @@ -require 'active_support/core_ext/file/atomic' +require "active_support/core_ext/file/atomic" diff --git a/activesupport/lib/active_support/core_ext/file/atomic.rb b/activesupport/lib/active_support/core_ext/file/atomic.rb index 463fd78412..8d6c0d3685 100644 --- a/activesupport/lib/active_support/core_ext/file/atomic.rb +++ b/activesupport/lib/active_support/core_ext/file/atomic.rb @@ -1,4 +1,4 @@ -require 'fileutils' +require "fileutils" class File # Write to a file atomically. Useful for situations where you don't @@ -17,7 +17,7 @@ class File # file.write('hello') # end def self.atomic_write(file_name, temp_dir = dirname(file_name)) - require 'tempfile' unless defined?(Tempfile) + require "tempfile" unless defined?(Tempfile) Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file| temp_file.binmode @@ -53,11 +53,11 @@ class File # Private utility method. def self.probe_stat_in(dir) #:nodoc: basename = [ - '.permissions_check', + ".permissions_check", Thread.current.object_id, Process.pid, rand(1000000) - ].join('.') + ].join(".") file_name = join(dir, basename) FileUtils.touch(file_name) diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb index af4d1da0eb..c819307e8a 100644 --- a/activesupport/lib/active_support/core_ext/hash.rb +++ b/activesupport/lib/active_support/core_ext/hash.rb @@ -1,9 +1,9 @@ -require 'active_support/core_ext/hash/compact' -require 'active_support/core_ext/hash/conversions' -require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/hash/transform_values' +require "active_support/core_ext/hash/compact" +require "active_support/core_ext/hash/conversions" +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/hash/transform_values" diff --git a/activesupport/lib/active_support/core_ext/hash/compact.rb b/activesupport/lib/active_support/core_ext/hash/compact.rb index f072530e04..5cae495bda 100644 --- a/activesupport/lib/active_support/core_ext/hash/compact.rb +++ b/activesupport/lib/active_support/core_ext/hash/compact.rb @@ -1,23 +1,27 @@ class Hash - # Returns a hash with non +nil+ values. - # - # hash = { a: true, b: false, c: nil } - # hash.compact # => { a: true, b: false } - # hash # => { a: true, b: false, c: nil } - # { c: nil }.compact # => {} - # { c: true }.compact # => { c: true } - def compact - self.select { |_, value| !value.nil? } + unless Hash.instance_methods(false).include?(:compact) + # Returns a hash with non +nil+ values. + # + # hash = { a: true, b: false, c: nil } + # hash.compact # => { a: true, b: false } + # hash # => { a: true, b: false, c: nil } + # { c: nil }.compact # => {} + # { c: true }.compact # => { c: true } + def compact + select { |_, value| !value.nil? } + end end - # Replaces current hash with non +nil+ values. - # Returns nil if no changes were made, otherwise returns the hash. - # - # hash = { a: true, b: false, c: nil } - # hash.compact! # => { a: true, b: false } - # hash # => { a: true, b: false } - # { c: true }.compact! # => nil - def compact! - self.reject! { |_, value| value.nil? } + unless Hash.instance_methods(false).include?(:compact!) + # Replaces current hash with non +nil+ values. + # Returns nil if no changes were made, otherwise returns the hash. + # + # hash = { a: true, b: false, c: nil } + # hash.compact! # => { a: true, b: false } + # hash # => { a: true, b: false } + # { c: true }.compact! # => nil + def compact! + reject! { |_, value| value.nil? } + end end end diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 2fc514cfce..3cd96ccb9a 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -1,11 +1,11 @@ -require 'active_support/xml_mini' -require 'active_support/time' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/string/inflections' +require "active_support/xml_mini" +require "active_support/time" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/string/inflections" class Hash # Returns a string containing an XML representation of its receiver: @@ -71,11 +71,11 @@ class Hash # configure your own builder with the <tt>:builder</tt> option. The method also accepts # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder. def to_xml(options = {}) - require 'active_support/builder' unless defined?(Builder) + require "active_support/builder" unless defined?(Builder) options = options.dup options[:indent] ||= 2 - options[:root] ||= 'hash' + options[:root] ||= "hash" options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent]) builder = options[:builder] @@ -159,36 +159,36 @@ module ActiveSupport private def normalize_keys(params) case params - when Hash - Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ] - when Array - params.map { |v| normalize_keys(v) } + when Hash + Hash[params.map { |k,v| [k.to_s.tr("-", "_"), normalize_keys(v)] } ] + when Array + params.map { |v| normalize_keys(v) } else - params + params end end def deep_to_h(value) case value - when Hash - process_hash(value) - when Array - process_array(value) - when String - value + when Hash + process_hash(value) + when Array + process_array(value) + when String + value else - raise "can't typecast #{value.class.name} - #{value.inspect}" + raise "can't typecast #{value.class.name} - #{value.inspect}" end end def process_hash(value) - if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type']) - raise DisallowedType, value['type'] + if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"]) + raise DisallowedType, value["type"] end if become_array?(value) _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) }) - if entries.nil? || value['__content__'].try(:empty?) + if entries.nil? || value["__content__"].try(:empty?) [] else case entries @@ -204,28 +204,28 @@ module ActiveSupport process_content(value) elsif become_empty_string?(value) - '' + "" elsif become_hash?(value) xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }] # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with # how multipart uploaded files from HTML appear - xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value + xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value end end def become_content?(value) - value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?)) + value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?)) end def become_array?(value) - value['type'] == 'array' + value["type"] == "array" end def become_empty_string?(value) # { "string" => true } # No tests fail when the second term is removed. - value['type'] == 'string' && value['nil'] != 'true' + value["type"] == "string" && value["nil"] != "true" end def become_hash?(value) @@ -234,19 +234,19 @@ module ActiveSupport def nothing?(value) # blank or nil parsed values are represented by nil - value.blank? || value['nil'] == 'true' + value.blank? || value["nil"] == "true" end def garbage?(value) # If the type is the only element which makes it then # this still makes the value nil, except if type is # an XML node(where type['value'] is a Hash) - value['type'] && !value['type'].is_a?(::Hash) && value.size == 1 + value["type"] && !value["type"].is_a?(::Hash) && value.size == 1 end def process_content(value) - content = value['__content__'] - if parser = ActiveSupport::XmlMini::PARSING[value['type']] + content = value["__content__"] + if parser = ActiveSupport::XmlMini::PARSING[value["type"]] parser.arity == 1 ? parser.call(content) : parser.call(content, value) else content @@ -257,6 +257,5 @@ module ActiveSupport value.map! { |i| deep_to_h(i) } value.length > 1 ? value : value.first end - end end diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb index 6df7b4121b..3e1ccecb6c 100644 --- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb +++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb @@ -1,7 +1,6 @@ -require 'active_support/hash_with_indifferent_access' +require "active_support/hash_with_indifferent_access" class Hash - # Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver: # # { a: 1 }.with_indifferent_access['a'] # => 1 diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index 1bfa18aeee..b7089357a8 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -52,14 +52,14 @@ class Hash # hash.symbolize_keys # # => {:name=>"Rob", :age=>"28"} def symbolize_keys - transform_keys{ |key| key.to_sym rescue key } + transform_keys { |key| key.to_sym rescue key } end alias_method :to_options, :symbolize_keys # Destructively converts all keys to symbols, as long as they respond # to +to_sym+. Same as +symbolize_keys+, but modifies +self+. def symbolize_keys! - transform_keys!{ |key| key.to_sym rescue key } + transform_keys! { |key| key.to_sym rescue key } end alias_method :to_options!, :symbolize_keys! @@ -128,14 +128,14 @@ class Hash # hash.deep_symbolize_keys # # => {:person=>{:name=>"Rob", :age=>"28"}} def deep_symbolize_keys - deep_transform_keys{ |key| key.to_sym rescue key } + deep_transform_keys { |key| key.to_sym rescue key } end # Destructively converts all keys to symbols, as long as they respond # to +to_sym+. This includes the keys from the root hash and from all # nested hashes and arrays. def deep_symbolize_keys! - deep_transform_keys!{ |key| key.to_sym rescue key } + deep_transform_keys! { |key| key.to_sym rescue key } end private @@ -147,7 +147,7 @@ class Hash result[yield(key)] = _deep_transform_keys_in_object(value, &block) end when Array - object.map {|e| _deep_transform_keys_in_object(e, &block) } + object.map { |e| _deep_transform_keys_in_object(e, &block) } else object end @@ -162,7 +162,7 @@ class Hash end object when Array - object.map! {|e| _deep_transform_keys_in_object!(e, &block)} + object.map! { |e| _deep_transform_keys_in_object!(e, &block) } else object end diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb index fbb482435d..db3e7508e7 100644 --- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb @@ -16,7 +16,7 @@ class Hash # Destructive +reverse_merge+. def reverse_merge!(other_hash) # right wins if there is no left - merge!( other_hash ){|key,left,right| left } + merge!( other_hash ) { |key,left,right| left } end alias_method :reverse_update, :reverse_merge! end diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index 1d5f38231a..161b00dfb3 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -1,11 +1,11 @@ class Hash - # Slices a hash to include only the given keys. Returns a hash containing + # Slices a hash to include only the given keys. Returns a hash containing # the given keys. - # + # # { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b) # # => {:a=>1, :b=>2} - # - # This is useful for limiting an options hash to valid keys before + # + # This is useful for limiting an options hash to valid keys before # passing to a method: # # def search(criteria = {}) diff --git a/activesupport/lib/active_support/core_ext/hash/transform_values.rb b/activesupport/lib/active_support/core_ext/hash/transform_values.rb index 7d507ac998..2f693bff0c 100644 --- a/activesupport/lib/active_support/core_ext/hash/transform_values.rb +++ b/activesupport/lib/active_support/core_ext/hash/transform_values.rb @@ -16,7 +16,7 @@ class Hash result[key] = yield(value) end result - end + end unless method_defined? :transform_values # Destructively converts all values using the +block+ operations. # Same as +transform_values+ but modifies +self+. @@ -25,5 +25,6 @@ class Hash each do |key, value| self[key] = yield(value) end - end + end unless method_defined? :transform_values! + # TODO: Remove this file when supporting only Ruby 2.4+. end diff --git a/activesupport/lib/active_support/core_ext/integer.rb b/activesupport/lib/active_support/core_ext/integer.rb index a44a1b4c74..8f0c55f9d3 100644 --- a/activesupport/lib/active_support/core_ext/integer.rb +++ b/activesupport/lib/active_support/core_ext/integer.rb @@ -1,3 +1,3 @@ -require 'active_support/core_ext/integer/multiple' -require 'active_support/core_ext/integer/inflections' -require 'active_support/core_ext/integer/time' +require "active_support/core_ext/integer/multiple" +require "active_support/core_ext/integer/inflections" +require "active_support/core_ext/integer/time" diff --git a/activesupport/lib/active_support/core_ext/integer/inflections.rb b/activesupport/lib/active_support/core_ext/integer/inflections.rb index 56f2ed5985..bc21b65533 100644 --- a/activesupport/lib/active_support/core_ext/integer/inflections.rb +++ b/activesupport/lib/active_support/core_ext/integer/inflections.rb @@ -1,4 +1,4 @@ -require 'active_support/inflector' +require "active_support/inflector" class Integer # Ordinalize turns a number into an ordinal string used to denote the diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb index 87185b024f..4a64872392 100644 --- a/activesupport/lib/active_support/core_ext/integer/time.rb +++ b/activesupport/lib/active_support/core_ext/integer/time.rb @@ -1,5 +1,5 @@ -require 'active_support/duration' -require 'active_support/core_ext/numeric/time' +require "active_support/duration" +require "active_support/core_ext/numeric/time" class Integer # Enables the use of time calculations and declarations, like <tt>45.minutes + diff --git a/activesupport/lib/active_support/core_ext/kernel.rb b/activesupport/lib/active_support/core_ext/kernel.rb index 364ed9d65f..3d41ff7876 100644 --- a/activesupport/lib/active_support/core_ext/kernel.rb +++ b/activesupport/lib/active_support/core_ext/kernel.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/kernel/agnostics' -require 'active_support/core_ext/kernel/concern' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/kernel/singleton_class' +require "active_support/core_ext/kernel/agnostics" +require "active_support/core_ext/kernel/concern" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/kernel/singleton_class" diff --git a/activesupport/lib/active_support/core_ext/kernel/concern.rb b/activesupport/lib/active_support/core_ext/kernel/concern.rb index 18bcc01fa4..307a7f7a63 100644 --- a/activesupport/lib/active_support/core_ext/kernel/concern.rb +++ b/activesupport/lib/active_support/core_ext/kernel/concern.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/module/concerning' +require "active_support/core_ext/module/concerning" module Kernel module_function diff --git a/activesupport/lib/active_support/core_ext/kernel/debugger.rb b/activesupport/lib/active_support/core_ext/kernel/debugger.rb index 1fde3db070..dccfa3e9bb 100644 --- a/activesupport/lib/active_support/core_ext/kernel/debugger.rb +++ b/activesupport/lib/active_support/core_ext/kernel/debugger.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/load_error.rb b/activesupport/lib/active_support/core_ext/load_error.rb index 60732eb41a..cd00d1b662 100644 --- a/activesupport/lib/active_support/core_ext/load_error.rb +++ b/activesupport/lib/active_support/core_ext/load_error.rb @@ -1,4 +1,5 @@ -require 'active_support/deprecation/proxy_wrappers' +require "active_support/deprecation" +require "active_support/deprecation/proxy_wrappers" class LoadError REGEXPS = [ @@ -23,8 +24,8 @@ class LoadError # Returns true if the given path name (except perhaps for the ".rb" # extension) is the missing file which caused the exception to be raised. def is_missing?(location) - location.sub(/\.rb$/, ''.freeze) == path.sub(/\.rb$/, ''.freeze) + location.sub(/\.rb$/, "".freeze) == path.sub(/\.rb$/, "".freeze) end end -MissingSourceFile = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('MissingSourceFile', 'LoadError') +MissingSourceFile = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("MissingSourceFile", "LoadError") diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb index ef038331c2..57feea69a5 100644 --- a/activesupport/lib/active_support/core_ext/module.rb +++ b/activesupport/lib/active_support/core_ext/module.rb @@ -1,12 +1,12 @@ -require 'active_support/core_ext/module/aliasing' -require 'active_support/core_ext/module/introspection' -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/module/reachable' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/module/attribute_accessors_per_thread' -require 'active_support/core_ext/module/attr_internal' -require 'active_support/core_ext/module/concerning' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/module/deprecation' -require 'active_support/core_ext/module/remove_method' -require 'active_support/core_ext/module/qualified_const' +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/reachable" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/attribute_accessors_per_thread" +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/module/concerning" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/module/deprecation" +require "active_support/core_ext/module/remove_method" +require "active_support/core_ext/module/qualified_const" diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index b6934b9c54..4a04bdd446 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -28,7 +28,7 @@ class Module # Strip out punctuation on predicates, bang or writer methods since # e.g. target?_without_feature is not a valid method name. - aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 + aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ""), $1 yield(aliased_target, punctuation) if block_given? with_method = "#{aliased_target}_with_#{feature}#{punctuation}" @@ -65,6 +65,9 @@ class Module # e.subject = "Megastars" # e.title # => "Megastars" def alias_attribute(new_name, old_name) + # The following reader methods use an explicit `self` receiver in order to + # support aliases that start with an uppercase letter. Otherwise, they would + # be resolved as constants instead. module_eval <<-STR, __FILE__, __LINE__ + 1 def #{new_name}; self.#{old_name}; end # def subject; self.title; end def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end diff --git a/activesupport/lib/active_support/core_ext/module/attr_internal.rb b/activesupport/lib/active_support/core_ext/module/attr_internal.rb index 93fb598650..5081d5f7a3 100644 --- a/activesupport/lib/active_support/core_ext/module/attr_internal.rb +++ b/activesupport/lib/active_support/core_ext/module/attr_internal.rb @@ -1,12 +1,12 @@ class Module # Declares an attribute reader backed by an internally-named instance variable. def attr_internal_reader(*attrs) - attrs.each {|attr_name| attr_internal_define(attr_name, :reader)} + attrs.each { |attr_name| attr_internal_define(attr_name, :reader) } end # Declares an attribute writer backed by an internally-named instance variable. def attr_internal_writer(*attrs) - attrs.each {|attr_name| attr_internal_define(attr_name, :writer)} + attrs.each { |attr_name| attr_internal_define(attr_name, :writer) } end # Declares an attribute reader and writer backed by an internally-named instance @@ -18,7 +18,7 @@ class Module alias_method :attr_internal, :attr_internal_accessor class << self; attr_accessor :attr_internal_naming_format end - self.attr_internal_naming_format = '@_%s' + self.attr_internal_naming_format = "@_%s" private def attr_internal_ivar_name(attr) @@ -26,7 +26,7 @@ class Module end def attr_internal_define(attr_name, type) - internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '') + internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, "") # use native attr_* methods as they are faster on some Ruby implementations send("attr_#{type}", internal_name) attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index 567ac825e9..90989f4f3d 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,4 +1,5 @@ -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance @@ -53,7 +54,7 @@ class Module def mattr_reader(*syms) options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /\A[_A-Za-z]\w*\z/ + raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@#{sym} = nil unless defined? @@#{sym} @@ -119,7 +120,7 @@ class Module def mattr_writer(*syms) options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /\A[_A-Za-z]\w*\z/ + raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@#{sym} = nil unless defined? @@#{sym} diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb index 045668c207..1e82b4acc2 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb @@ -1,9 +1,10 @@ -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance # attributes, but does so on a per-thread basis. -# +# # So the values are scoped within the Thread.current space under the class name # of the module. class Module @@ -33,21 +34,24 @@ class Module # end # # Current.new.user # => NoMethodError - def thread_mattr_reader(*syms) + def thread_mattr_reader(*syms) # :nodoc: options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ + raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym) + + # The following generated method concatenates `name` because we want it + # to work with inheritance via polymorphism. class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym} - Thread.current[:"attr_#{name}_#{sym}"] + Thread.current["attr_" + name + "_#{sym}"] end EOS unless options[:instance_reader] == false || options[:instance_accessor] == false class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym} - Thread.current[:"attr_#{name}_#{sym}"] + self.class.#{sym} end EOS end @@ -73,20 +77,23 @@ class Module # end # # Current.new.user = "DHH" # => NoMethodError - def thread_mattr_writer(*syms) + def thread_mattr_writer(*syms) # :nodoc: options = syms.extract_options! syms.each do |sym| - raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/ + raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym) + + # The following generated method concatenates `name` because we want it + # to work with inheritance via polymorphism. class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym}=(obj) - Thread.current[:"attr_#{name}_#{sym}"] = obj + Thread.current["attr_" + name + "_#{sym}"] = obj end EOS unless options[:instance_writer] == false || options[:instance_accessor] == false class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym}=(obj) - Thread.current[:"attr_#{name}_#{sym}"] = obj + self.class.#{sym} = obj end EOS end @@ -133,9 +140,9 @@ class Module # # Current.new.user = "DHH" # => NoMethodError # Current.new.user # => NoMethodError - def thread_mattr_accessor(*syms, &blk) - thread_mattr_reader(*syms, &blk) - thread_mattr_writer(*syms, &blk) + def thread_mattr_accessor(*syms) + thread_mattr_reader(*syms) + thread_mattr_writer(*syms) end alias :thread_cattr_accessor :thread_mattr_accessor end diff --git a/activesupport/lib/active_support/core_ext/module/concerning.rb b/activesupport/lib/active_support/core_ext/module/concerning.rb index 65b88b9bbd..97b0a382ce 100644 --- a/activesupport/lib/active_support/core_ext/module/concerning.rb +++ b/activesupport/lib/active_support/core_ext/module/concerning.rb @@ -1,4 +1,4 @@ -require 'active_support/concern' +require "active_support/concern" class Module # = Bite-sized separation of concerns diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 3f6e8bd26c..f5f4ba61b7 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,4 +1,5 @@ -require 'set' +require "set" +require "active_support/core_ext/regexp" class Module # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+ @@ -150,18 +151,18 @@ class Module # The target method must be public, otherwise it will raise +NoMethodError+. def delegate(*methods, to: nil, prefix: nil, allow_nil: nil) unless to - raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).' + raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)." end - if prefix == true && to =~ /^[^a-z_]/ - raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.' + if prefix == true && /^[^a-z_]/.match?(to) + raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method." end method_prefix = \ if prefix "#{prefix == true ? to : prefix}_" else - '' + "" end location = caller_locations(1, 1).first @@ -173,7 +174,7 @@ class Module methods.each do |method| # Attribute writer methods only accept one argument. Makes sure []= # methods still accept two arguments. - definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block' + definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block" # The following generated method calls the target exactly once, storing # the returned value in a dummy variable. @@ -190,7 +191,7 @@ class Module " _.#{method}(#{definition})", "end", "end" - ].join ';' + ].join ";" else exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") @@ -205,7 +206,7 @@ class Module " raise", " end", "end" - ].join ';' + ].join ";" end module_eval(method_def, file, line) @@ -255,7 +256,7 @@ class Module # end # end # - # The target can be anything callable withing the object. E.g. instance + # The target can be anything callable within the object. E.g. instance # variables, methods, constants ant the likes. def delegate_missing_to(target) target = target.to_s diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb index fa692e1b0e..4f854a718b 100644 --- a/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -1,4 +1,4 @@ -require 'active_support/inflector' +require "active_support/inflector" class Module # Returns the name of the module containing this one. @@ -46,9 +46,9 @@ class Module def parents parents = [] if parent_name - parts = parent_name.split('::') + parts = parent_name.split("::") until parts.empty? - parents << ActiveSupport::Inflector.constantize(parts * '::') + parents << ActiveSupport::Inflector.constantize(parts * "::") parts.pop end end diff --git a/activesupport/lib/active_support/core_ext/module/method_transplanting.rb b/activesupport/lib/active_support/core_ext/module/method_transplanting.rb index 1fde3db070..dccfa3e9bb 100644 --- a/activesupport/lib/active_support/core_ext/module/method_transplanting.rb +++ b/activesupport/lib/active_support/core_ext/module/method_transplanting.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/module/qualified_const.rb b/activesupport/lib/active_support/core_ext/module/qualified_const.rb index 3ea39d4267..62f0687ae9 100644 --- a/activesupport/lib/active_support/core_ext/module/qualified_const.rb +++ b/activesupport/lib/active_support/core_ext/module/qualified_const.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/string/inflections' +require "active_support/core_ext/string/inflections" #-- # Allows code reuse in the methods below without polluting Module. @@ -11,7 +11,7 @@ module ActiveSupport end def self.names(path) - path.split('::') + path.split("::") end end end diff --git a/activesupport/lib/active_support/core_ext/module/reachable.rb b/activesupport/lib/active_support/core_ext/module/reachable.rb index 5d3d0e9851..b89a38f26c 100644 --- a/activesupport/lib/active_support/core_ext/module/reachable.rb +++ b/activesupport/lib/active_support/core_ext/module/reachable.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/string/inflections' +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/string/inflections" class Module def reachable? #:nodoc: diff --git a/activesupport/lib/active_support/core_ext/numeric.rb b/activesupport/lib/active_support/core_ext/numeric.rb index bcdc3eace2..6062f9e3a8 100644 --- a/activesupport/lib/active_support/core_ext/numeric.rb +++ b/activesupport/lib/active_support/core_ext/numeric.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/numeric/bytes' -require 'active_support/core_ext/numeric/time' -require 'active_support/core_ext/numeric/inquiry' -require 'active_support/core_ext/numeric/conversions' +require "active_support/core_ext/numeric/bytes" +require "active_support/core_ext/numeric/time" +require "active_support/core_ext/numeric/inquiry" +require "active_support/core_ext/numeric/conversions" diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb index 6586a351f8..cebfda8d31 100644 --- a/activesupport/lib/active_support/core_ext/numeric/conversions.rb +++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb @@ -1,9 +1,8 @@ -require 'active_support/core_ext/big_decimal/conversions' -require 'active_support/number_helper' -require 'active_support/core_ext/module/deprecation' +require "active_support/core_ext/big_decimal/conversions" +require "active_support/number_helper" +require "active_support/core_ext/module/deprecation" module ActiveSupport::NumericWithFormat - # Provides options for converting numbers into formatted strings. # Options are provided for phone numbers, currency, percentage, # precision, positional notation, file size and pretty printing. @@ -135,7 +134,7 @@ module ActiveSupport::NumericWithFormat end # Ruby 2.4+ unifies Fixnum & Bignum into Integer. -if Integer == Fixnum +if 0.class == Integer Integer.prepend ActiveSupport::NumericWithFormat else Fixnum.prepend ActiveSupport::NumericWithFormat diff --git a/activesupport/lib/active_support/core_ext/numeric/inquiry.rb b/activesupport/lib/active_support/core_ext/numeric/inquiry.rb index 7e7ac1b0b2..ec79701189 100644 --- a/activesupport/lib/active_support/core_ext/numeric/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/numeric/inquiry.rb @@ -1,26 +1,26 @@ unless 1.respond_to?(:positive?) # TODO: Remove this file when we drop support to ruby < 2.3 -class Numeric - # Returns true if the number is positive. - # - # 1.positive? # => true - # 0.positive? # => false - # -1.positive? # => false - def positive? - self > 0 - end + class Numeric + # Returns true if the number is positive. + # + # 1.positive? # => true + # 0.positive? # => false + # -1.positive? # => false + def positive? + self > 0 + end - # Returns true if the number is negative. - # - # -1.negative? # => true - # 0.negative? # => false - # 1.negative? # => false - def negative? - self < 0 + # Returns true if the number is negative. + # + # -1.negative? # => true + # 0.negative? # => false + # 1.negative? # => false + def negative? + self < 0 + end end -end -class Complex - undef :positive? - undef :negative? -end + class Complex + undef :positive? + undef :negative? + end end diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb index c6ece22f8d..809dfd4e07 100644 --- a/activesupport/lib/active_support/core_ext/numeric/time.rb +++ b/activesupport/lib/active_support/core_ext/numeric/time.rb @@ -1,8 +1,8 @@ -require 'active_support/duration' -require 'active_support/core_ext/time/calculations' -require 'active_support/core_ext/time/acts_like' -require 'active_support/core_ext/date/calculations' -require 'active_support/core_ext/date/acts_like' +require "active_support/duration" +require "active_support/core_ext/time/calculations" +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/date/calculations" +require "active_support/core_ext/date/acts_like" class Numeric # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb index f4f9152d6a..58bbf78601 100644 --- a/activesupport/lib/active_support/core_ext/object.rb +++ b/activesupport/lib/active_support/core_ext/object.rb @@ -1,14 +1,14 @@ -require 'active_support/core_ext/object/acts_like' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/object/deep_dup' -require 'active_support/core_ext/object/try' -require 'active_support/core_ext/object/inclusion' +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/object/deep_dup" +require "active_support/core_ext/object/try" +require "active_support/core_ext/object/inclusion" -require 'active_support/core_ext/object/conversions' -require 'active_support/core_ext/object/instance_variables' +require "active_support/core_ext/object/conversions" +require "active_support/core_ext/object/instance_variables" -require 'active_support/core_ext/object/json' -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/object/with_options' +require "active_support/core_ext/object/json" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/object/with_options" diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb index cb74bad73e..bdb50ee291 100644 --- a/activesupport/lib/active_support/core_ext/object/blank.rb +++ b/activesupport/lib/active_support/core_ext/object/blank.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/regexp" + class Object # An object is blank if it's false, empty, or a whitespace string. # For example, +false+, '', ' ', +nil+, [], and {} are all blank. @@ -115,7 +117,7 @@ class String # The regexp that matches blank strings is expensive. For the case of empty # strings we can speed up this method (~3.5x) with an empty? call. The # penalty for the rest of strings is marginal. - empty? || BLANK_RE === self + empty? || BLANK_RE.match?(self) end end diff --git a/activesupport/lib/active_support/core_ext/object/conversions.rb b/activesupport/lib/active_support/core_ext/object/conversions.rb index 540f7aadb0..918ebcdc9f 100644 --- a/activesupport/lib/active_support/core_ext/object/conversions.rb +++ b/activesupport/lib/active_support/core_ext/object/conversions.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/to_param' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/array/conversions' -require 'active_support/core_ext/hash/conversions' +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/hash/conversions" diff --git a/activesupport/lib/active_support/core_ext/object/deep_dup.rb b/activesupport/lib/active_support/core_ext/object/deep_dup.rb index 8dfeed0066..5ac649e552 100644 --- a/activesupport/lib/active_support/core_ext/object/deep_dup.rb +++ b/activesupport/lib/active_support/core_ext/object/deep_dup.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/duplicable' +require "active_support/core_ext/object/duplicable" class Object # Returns a deep copy of object if it's duplicable. If it's diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb index 9bc5ee65ba..aa2282cb7e 100644 --- a/activesupport/lib/active_support/core_ext/object/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb @@ -76,7 +76,7 @@ class Numeric end end -require 'bigdecimal' +require "bigdecimal" class BigDecimal # BigDecimals are duplicable: # diff --git a/activesupport/lib/active_support/core_ext/object/inclusion.rb b/activesupport/lib/active_support/core_ext/object/inclusion.rb index d4c17dfb07..98bf820d36 100644 --- a/activesupport/lib/active_support/core_ext/object/inclusion.rb +++ b/activesupport/lib/active_support/core_ext/object/inclusion.rb @@ -22,6 +22,6 @@ class Object # # @return [Object] def presence_in(another_object) - self.in?(another_object) ? self : nil + in?(another_object) ? self : nil end end diff --git a/activesupport/lib/active_support/core_ext/object/json.rb b/activesupport/lib/active_support/core_ext/object/json.rb index d49b2fbe54..1c4d181443 100644 --- a/activesupport/lib/active_support/core_ext/object/json.rb +++ b/activesupport/lib/active_support/core_ext/object/json.rb @@ -1,14 +1,16 @@ # Hack to load json gem first so we can overwrite its to_json. -require 'json' -require 'bigdecimal' -require 'active_support/core_ext/big_decimal/conversions' # for #to_s -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/object/instance_variables' -require 'time' -require 'active_support/core_ext/time/conversions' -require 'active_support/core_ext/date_time/conversions' -require 'active_support/core_ext/date/conversions' +require "json" +require "bigdecimal" +require "uri/generic" +require "pathname" +require "active_support/core_ext/big_decimal/conversions" # for #to_s +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/object/instance_variables" +require "time" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/date_time/conversions" +require "active_support/core_ext/date/conversions" # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting # their default behavior. That said, we need to define the basic to_json method in all of them, @@ -187,14 +189,26 @@ class DateTime if ActiveSupport::JSON::Encoding.use_standard_json_time_format xmlschema(ActiveSupport::JSON::Encoding.time_precision) else - strftime('%Y/%m/%d %H:%M:%S %z') + strftime("%Y/%m/%d %H:%M:%S %z") end end end +class URI::Generic #:nodoc: + def as_json(options = nil) + to_s + end +end + +class Pathname #:nodoc: + def as_json(options = nil) + to_s + end +end + class Process::Status #:nodoc: def as_json(options = nil) - { :exitstatus => exitstatus, :pid => pid } + { exitstatus: exitstatus, pid: pid } end end diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb index 684d4ef57e..5eeaf03163 100644 --- a/activesupport/lib/active_support/core_ext/object/to_param.rb +++ b/activesupport/lib/active_support/core_ext/object/to_param.rb @@ -1 +1 @@ -require 'active_support/core_ext/object/to_query' +require "active_support/core_ext/object/to_query" diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb index ec5ace4e16..a3a3abacbb 100644 --- a/activesupport/lib/active_support/core_ext/object/to_query.rb +++ b/activesupport/lib/active_support/core_ext/object/to_query.rb @@ -1,4 +1,4 @@ -require 'cgi' +require "cgi" class Object # Alias of <tt>to_s</tt>. @@ -38,7 +38,7 @@ class Array # Calls <tt>to_param</tt> on all its elements and joins the result with # slashes. This is used by <tt>url_for</tt> in Action Pack. def to_param - collect(&:to_param).join '/' + collect(&:to_param).join "/" end # Converts an array into a string suitable for use as a URL query string, @@ -51,7 +51,7 @@ class Array if empty? nil.to_query(prefix) else - collect { |value| value.to_query(prefix) }.join '&' + collect { |value| value.to_query(prefix) }.join "&" end end end @@ -77,7 +77,7 @@ class Hash unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty? value.to_query(namespace ? "#{namespace}[#{key}]" : key) end - end.compact.sort! * '&' + end.compact.sort! * "&" end alias_method :to_param, :to_query diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index 3b6d9da216..b2be619b2d 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -1,4 +1,4 @@ -require 'delegate' +require "delegate" module ActiveSupport module Tryable #:nodoc: diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb index 513c8b1d55..cf39b1d312 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -1,4 +1,4 @@ -require 'active_support/option_merger' +require "active_support/option_merger" class Object # An elegant way to factor duplication out of options passed to a series of diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb index 9368e81235..3190e3ff76 100644 --- a/activesupport/lib/active_support/core_ext/range.rb +++ b/activesupport/lib/active_support/core_ext/range.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/range/conversions' -require 'active_support/core_ext/range/include_range' -require 'active_support/core_ext/range/overlaps' -require 'active_support/core_ext/range/each' +require "active_support/core_ext/range/conversions" +require "active_support/core_ext/range/include_range" +require "active_support/core_ext/range/overlaps" +require "active_support/core_ext/range/each" diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb index 965436c23a..69ea046cb6 100644 --- a/activesupport/lib/active_support/core_ext/range/conversions.rb +++ b/activesupport/lib/active_support/core_ext/range/conversions.rb @@ -1,6 +1,6 @@ module ActiveSupport::RangeWithFormat RANGE_FORMATS = { - :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" } + db: Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" } } # Convert range to a formatted string. See RANGE_FORMATS for predefined formats. diff --git a/activesupport/lib/active_support/core_ext/regexp.rb b/activesupport/lib/active_support/core_ext/regexp.rb index 784145f5fb..062d568228 100644 --- a/activesupport/lib/active_support/core_ext/regexp.rb +++ b/activesupport/lib/active_support/core_ext/regexp.rb @@ -2,4 +2,8 @@ class Regexp #:nodoc: def multiline? options & MULTILINE == MULTILINE end + + def match?(string, pos=0) + !!match(string, pos) + end unless //.respond_to?(:match?) end diff --git a/activesupport/lib/active_support/core_ext/securerandom.rb b/activesupport/lib/active_support/core_ext/securerandom.rb index 98cf7430f7..92392d1a92 100644 --- a/activesupport/lib/active_support/core_ext/securerandom.rb +++ b/activesupport/lib/active_support/core_ext/securerandom.rb @@ -1,7 +1,7 @@ -require 'securerandom' +require "securerandom" module SecureRandom - BASE58_ALPHABET = ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a - ['0', 'O', 'I', 'l'] + BASE58_ALPHABET = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - ["0", "O", "I", "l"] # SecureRandom.base58 generates a random base58 string. # # The argument _n_ specifies the length, of the random string to be generated. diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb index c656db2c6c..4cb3200875 100644 --- a/activesupport/lib/active_support/core_ext/string.rb +++ b/activesupport/lib/active_support/core_ext/string.rb @@ -1,13 +1,13 @@ -require 'active_support/core_ext/string/conversions' -require 'active_support/core_ext/string/filters' -require 'active_support/core_ext/string/multibyte' -require 'active_support/core_ext/string/starts_ends_with' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/string/access' -require 'active_support/core_ext/string/behavior' -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/string/exclude' -require 'active_support/core_ext/string/strip' -require 'active_support/core_ext/string/inquiry' -require 'active_support/core_ext/string/indent' -require 'active_support/core_ext/string/zones' +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/string/filters" +require "active_support/core_ext/string/multibyte" +require "active_support/core_ext/string/starts_ends_with" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/string/access" +require "active_support/core_ext/string/behavior" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/string/exclude" +require "active_support/core_ext/string/strip" +require "active_support/core_ext/string/inquiry" +require "active_support/core_ext/string/indent" +require "active_support/core_ext/string/zones" diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb index 213a91aa7a..caa48e34c5 100644 --- a/activesupport/lib/active_support/core_ext/string/access.rb +++ b/activesupport/lib/active_support/core_ext/string/access.rb @@ -74,9 +74,9 @@ class String # str.first(6) # => "hello" def first(limit = 1) if limit == 0 - '' + "" elsif limit >= size - self.dup + dup else to(limit - 1) end @@ -94,9 +94,9 @@ class String # str.last(6) # => "hello" def last(limit = 1) if limit == 0 - '' + "" elsif limit >= size - self.dup + dup else from(-limit) end diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb index 946976c5e9..221b4969cc 100644 --- a/activesupport/lib/active_support/core_ext/string/conversions.rb +++ b/activesupport/lib/active_support/core_ext/string/conversions.rb @@ -1,5 +1,5 @@ -require 'date' -require 'active_support/core_ext/time/calculations' +require "date" +require "active_support/core_ext/time/calculations" class String # Converts a string to a Time value. diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb index 375ec1aef8..a9ec2eb842 100644 --- a/activesupport/lib/active_support/core_ext/string/filters.rb +++ b/activesupport/lib/active_support/core_ext/string/filters.rb @@ -17,7 +17,7 @@ class String # str.squish! # => "foo bar boo" # str # => "foo bar boo" def squish! - gsub!(/[[:space:]]+/, ' ') + gsub!(/[[:space:]]+/, " ") strip! self end @@ -64,7 +64,7 @@ class String def truncate(truncate_at, options = {}) return dup unless length > truncate_at - omission = options[:omission] || '...' + omission = options[:omission] || "..." length_with_room_for_omission = truncate_at - omission.length stop = \ if options[:separator] @@ -94,7 +94,7 @@ class String sep = options[:separator] || /\s+/ sep = Regexp.escape(sep.to_s) unless Regexp === sep if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m - $1 + (options[:omission] || '...') + $1 + (options[:omission] || "...") else dup end diff --git a/activesupport/lib/active_support/core_ext/string/indent.rb b/activesupport/lib/active_support/core_ext/string/indent.rb index ce3a69cf5f..e87f72fdbd 100644 --- a/activesupport/lib/active_support/core_ext/string/indent.rb +++ b/activesupport/lib/active_support/core_ext/string/indent.rb @@ -3,7 +3,7 @@ class String # # Returns the indented string, or +nil+ if there was nothing to indent. def indent!(amount, indent_string=nil, indent_empty_lines=false) - indent_string = indent_string || self[/^[ \t]/] || ' ' + indent_string = indent_string || self[/^[ \t]/] || " " re = indent_empty_lines ? /^/ : /^(?!$)/ gsub!(re, indent_string * amount) end @@ -38,6 +38,6 @@ class String # "foo\n\nbar".indent(2, nil, true) # => " foo\n \n bar" # def indent(amount, indent_string=nil, indent_empty_lines=false) - dup.tap {|_| _.indent!(amount, indent_string, indent_empty_lines)} + dup.tap { |_| _.indent!(amount, indent_string, indent_empty_lines) } end end diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 7277f51076..7e12700c8c 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -1,5 +1,5 @@ -require 'active_support/inflector/methods' -require 'active_support/inflector/transliterate' +require "active_support/inflector/methods" +require "active_support/inflector/transliterate" # String inflections define new methods on the String class to transform names for different purposes. # For instance, you can figure out the name of a table from the name of a class. @@ -31,7 +31,7 @@ class String def pluralize(count = nil, locale = :en) locale = count if count.is_a?(Symbol) if count == 1 - self.dup + dup else ActiveSupport::Inflector.pluralize(self, locale) end @@ -164,7 +164,7 @@ class String # # <%= link_to(@person.name, person_path) %> # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a> - # + # # To preserve the case of the characters in a string, use the `preserve_case` argument. # # class Person @@ -178,7 +178,7 @@ class String # # <%= link_to(@person.name, person_path) %> # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a> - def parameterize(sep = :unused, separator: '-', preserve_case: false) + def parameterize(sep = :unused, separator: "-", preserve_case: false) unless sep == :unused ActiveSupport::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.") separator = sep diff --git a/activesupport/lib/active_support/core_ext/string/inquiry.rb b/activesupport/lib/active_support/core_ext/string/inquiry.rb index 1dcd949536..c95d83beae 100644 --- a/activesupport/lib/active_support/core_ext/string/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/string/inquiry.rb @@ -1,4 +1,4 @@ -require 'active_support/string_inquirer' +require "active_support/string_inquirer" class String # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class, diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb index cc6f2158e7..1c73182259 100644 --- a/activesupport/lib/active_support/core_ext/string/multibyte.rb +++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb @@ -1,4 +1,4 @@ -require 'active_support/multibyte' +require "active_support/multibyte" class String # == Multibyte proxy diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 005ad93b08..2b7e556ced 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -1,10 +1,11 @@ -require 'erb' -require 'active_support/core_ext/kernel/singleton_class' +require "erb" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/multibyte/unicode" class ERB module Util - HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' } - JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' } + HTML_ESCAPE = { "&" => "&", ">" => ">", "<" => "<", '"' => """, "'" => "'" } + JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' } HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/ JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u @@ -144,7 +145,7 @@ module ActiveSupport #:nodoc: # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers. class SafeConcatError < StandardError def initialize - super 'Could not concatenate to the buffer because it is not html safe.' + super "Could not concatenate to the buffer because it is not html safe." end end @@ -171,7 +172,7 @@ module ActiveSupport #:nodoc: original_concat(value) end - def initialize(str = '') + def initialize(str = "") @html_safe = true super end @@ -242,9 +243,9 @@ module ActiveSupport #:nodoc: private - def html_escape_interpolated_argument(arg) - (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s) - end + def html_escape_interpolated_argument(arg) + (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s) + end end end diff --git a/activesupport/lib/active_support/core_ext/string/strip.rb b/activesupport/lib/active_support/core_ext/string/strip.rb index 55b9b87352..bb62e6c0ba 100644 --- a/activesupport/lib/active_support/core_ext/string/strip.rb +++ b/activesupport/lib/active_support/core_ext/string/strip.rb @@ -18,6 +18,6 @@ class String # Technically, it looks for the least indented non-empty line # in the whole string, and removes that amount of leading whitespace. def strip_heredoc - gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze) + gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze) end end diff --git a/activesupport/lib/active_support/core_ext/string/zones.rb b/activesupport/lib/active_support/core_ext/string/zones.rb index 510c884c18..de5a28e4f7 100644 --- a/activesupport/lib/active_support/core_ext/string/zones.rb +++ b/activesupport/lib/active_support/core_ext/string/zones.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/string/conversions' -require 'active_support/core_ext/time/zones' +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/time/zones" class String # Converts String to a TimeWithZone in the current zone if Time.zone or Time.zone_default diff --git a/activesupport/lib/active_support/core_ext/struct.rb b/activesupport/lib/active_support/core_ext/struct.rb index 1fde3db070..dccfa3e9bb 100644 --- a/activesupport/lib/active_support/core_ext/struct.rb +++ b/activesupport/lib/active_support/core_ext/struct.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/time.rb b/activesupport/lib/active_support/core_ext/time.rb index 0bce632222..b1ae4a45d9 100644 --- a/activesupport/lib/active_support/core_ext/time.rb +++ b/activesupport/lib/active_support/core_ext/time.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/time/acts_like' -require 'active_support/core_ext/time/calculations' -require 'active_support/core_ext/time/compatibility' -require 'active_support/core_ext/time/conversions' -require 'active_support/core_ext/time/zones' +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/time/calculations" +require "active_support/core_ext/time/compatibility" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/time/zones" diff --git a/activesupport/lib/active_support/core_ext/time/acts_like.rb b/activesupport/lib/active_support/core_ext/time/acts_like.rb index 3f853b7893..cf4b2539c5 100644 --- a/activesupport/lib/active_support/core_ext/time/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/time/acts_like.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/acts_like' +require "active_support/core_ext/object/acts_like" class Time # Duck-types as a Time-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index e81b48ab26..2cbfa14772 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -1,9 +1,9 @@ -require 'active_support/duration' -require 'active_support/core_ext/time/conversions' -require 'active_support/time_with_zone' -require 'active_support/core_ext/time/zones' -require 'active_support/core_ext/date_and_time/calculations' -require 'active_support/core_ext/date/calculations' +require "active_support/duration" +require "active_support/core_ext/time/conversions" +require "active_support/time_with_zone" +require "active_support/core_ext/time/zones" +require "active_support/core_ext/date_and_time/calculations" +require "active_support/core_ext/date/calculations" class Time include DateAndTime::Calculations @@ -61,7 +61,7 @@ class Time # Time.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296.0 # Time.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399.0 def seconds_since_midnight - to_i - change(:hour => 0).to_i + (usec / 1.0e+6) + to_i - change(hour: 0).to_i + (usec / 1.0e+6) end # Returns the number of seconds until 23:59:59. @@ -112,7 +112,7 @@ class Time elsif zone ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec) else - raise ArgumentError, 'argument out of range' if new_usec >= 1000000 + raise ArgumentError, "argument out of range" if new_usec >= 1000000 ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset) end end @@ -141,7 +141,7 @@ class Time d = to_date.advance(options) d = d.gregorian if d.julian? - time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) + time_advanced_by_date = change(year: d.year, month: d.month, day: d.day) seconds_to_advance = \ options.fetch(:seconds, 0) + options.fetch(:minutes, 0) * 60 + @@ -169,7 +169,7 @@ class Time # Returns a new Time representing the start of the day (0:00) def beginning_of_day - change(:hour => 0) + change(hour: 0) end alias :midnight :beginning_of_day alias :at_midnight :beginning_of_day @@ -177,7 +177,7 @@ class Time # Returns a new Time representing the middle of the day (12:00) def middle_of_day - change(:hour => 12) + change(hour: 12) end alias :midday :middle_of_day alias :noon :middle_of_day @@ -188,41 +188,41 @@ class Time # Returns a new Time representing the end of the day, 23:59:59.999999 def end_of_day change( - :hour => 23, - :min => 59, - :sec => 59, - :usec => Rational(999999999, 1000) + hour: 23, + min: 59, + sec: 59, + usec: Rational(999999999, 1000) ) end alias :at_end_of_day :end_of_day # Returns a new Time representing the start of the hour (x:00) def beginning_of_hour - change(:min => 0) + change(min: 0) end alias :at_beginning_of_hour :beginning_of_hour # Returns a new Time representing the end of the hour, x:59:59.999999 def end_of_hour change( - :min => 59, - :sec => 59, - :usec => Rational(999999999, 1000) + min: 59, + sec: 59, + usec: Rational(999999999, 1000) ) end alias :at_end_of_hour :end_of_hour # Returns a new Time representing the start of the minute (x:xx:00) def beginning_of_minute - change(:sec => 0) + change(sec: 0) end alias :at_beginning_of_minute :beginning_of_minute # Returns a new Time representing the end of the minute, x:xx:59.999999 def end_of_minute change( - :sec => 59, - :usec => Rational(999999999, 1000) + sec: 59, + usec: Rational(999999999, 1000) ) end alias :at_end_of_minute :end_of_minute @@ -281,5 +281,4 @@ class Time end alias_method :eql_without_coercion, :eql? alias_method :eql?, :eql_with_coercion - end diff --git a/activesupport/lib/active_support/core_ext/time/compatibility.rb b/activesupport/lib/active_support/core_ext/time/compatibility.rb index 945319461b..ca4b9574d5 100644 --- a/activesupport/lib/active_support/core_ext/time/compatibility.rb +++ b/activesupport/lib/active_support/core_ext/time/compatibility.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/date_and_time/compatibility' +require "active_support/core_ext/date_and_time/compatibility" class Time prepend DateAndTime::Compatibility diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index 536c4bf525..f2bbe55aa6 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -1,24 +1,24 @@ -require 'active_support/inflector/methods' -require 'active_support/values/time_zone' +require "active_support/inflector/methods" +require "active_support/values/time_zone" class Time DATE_FORMATS = { - :db => '%Y-%m-%d %H:%M:%S', - :number => '%Y%m%d%H%M%S', - :nsec => '%Y%m%d%H%M%S%9N', - :usec => '%Y%m%d%H%M%S%6N', - :time => '%H:%M', - :short => '%d %b %H:%M', - :long => '%B %d, %Y %H:%M', - :long_ordinal => lambda { |time| + db: "%Y-%m-%d %H:%M:%S", + number: "%Y%m%d%H%M%S", + nsec: "%Y%m%d%H%M%S%9N", + usec: "%Y%m%d%H%M%S%6N", + time: "%H:%M", + short: "%d %b %H:%M", + long: "%B %d, %Y %H:%M", + long_ordinal: lambda { |time| day_format = ActiveSupport::Inflector.ordinalize(time.day) time.strftime("%B #{day_format}, %Y %H:%M") }, - :rfc822 => lambda { |time| + rfc822: lambda { |time| offset_format = time.formatted_offset(false) time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}") }, - :iso8601 => lambda { |time| time.iso8601 } + iso8601: lambda { |time| time.iso8601 } } # Converts to a formatted string. See DATE_FORMATS for built-in formats. diff --git a/activesupport/lib/active_support/core_ext/time/marshal.rb b/activesupport/lib/active_support/core_ext/time/marshal.rb index 467bad1726..d095d76ebb 100644 --- a/activesupport/lib/active_support/core_ext/time/marshal.rb +++ b/activesupport/lib/active_support/core_ext/time/marshal.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index 7a60f94996..87b5ad903a 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -1,6 +1,6 @@ -require 'active_support/time_with_zone' -require 'active_support/core_ext/time/acts_like' -require 'active_support/core_ext/date_and_time/zones' +require "active_support/time_with_zone" +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/date_and_time/zones" class Time include DateAndTime::Zones diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb index c6c183edd9..342a5fcd52 100644 --- a/activesupport/lib/active_support/core_ext/uri.rb +++ b/activesupport/lib/active_support/core_ext/uri.rb @@ -1,4 +1,4 @@ -require 'uri' +require "uri" str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese. parser = URI::Parser.new @@ -10,7 +10,7 @@ unless str == parser.unescape(parser.escape(str)) # YK: My initial experiments say yes, but let's be sure please enc = str.encoding enc = Encoding::UTF_8 if enc == Encoding::US_ASCII - str.gsub(escaped) { |match| [match[1, 2].hex].pack('C') }.force_encoding(enc) + str.gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc) end end end diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 57f6286de3..216d52164e 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -1,19 +1,19 @@ -require 'set' -require 'thread' -require 'concurrent/map' -require 'pathname' -require 'active_support/core_ext/module/aliasing' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/module/introspection' -require 'active_support/core_ext/module/anonymous' -require 'active_support/core_ext/module/qualified_const' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/load_error' -require 'active_support/core_ext/name_error' -require 'active_support/core_ext/string/starts_ends_with' +require "set" +require "thread" +require "concurrent/map" +require "pathname" +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/qualified_const" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/load_error" +require "active_support/core_ext/name_error" +require "active_support/core_ext/string/starts_ends_with" require "active_support/dependencies/interlock" -require 'active_support/inflector' +require "active_support/inflector" module ActiveSupport #:nodoc: module Dependencies #:nodoc: @@ -64,7 +64,7 @@ module ActiveSupport #:nodoc: # Should we load files or require them? mattr_accessor :mechanism - self.mechanism = ENV['NO_RELOAD'] ? :require : :load + self.mechanism = ENV["NO_RELOAD"] ? :require : :load # The set of directories from which we may automatically load files. Files # under these directories will be reloaded on each request in development mode, @@ -170,9 +170,9 @@ module ActiveSupport #:nodoc: end private - def pop_modules(modules) - modules.each { |mod| @stack[mod].pop } - end + def pop_modules(modules) + modules.each { |mod| @stack[mod].pop } + end end # An internal stack used to record which constants are loaded by any block. @@ -282,17 +282,17 @@ module ActiveSupport #:nodoc: private - def load(file, wrap = false) - result = false - load_dependency(file) { result = super } - result - end + def load(file, wrap = false) + result = false + load_dependency(file) { result = super } + result + end - def require(file) - result = false - load_dependency(file) { result = super } - result - end + def require(file) + result = false + load_dependency(file) { result = super } + result + end end # Exception file-blaming. @@ -371,7 +371,7 @@ module ActiveSupport #:nodoc: load_args = ["#{file_name}.rb"] load_args << const_path unless const_path.nil? - if !warnings_on_first_load or history.include?(expanded) + if !warnings_on_first_load || history.include?(expanded) result = load_file(*load_args) else enable_warnings { result = load_file(*load_args) } @@ -503,7 +503,7 @@ module ActiveSupport #:nodoc: if file_path expanded = File.expand_path(file_path) - expanded.sub!(/\.rb\z/, ''.freeze) + expanded.sub!(/\.rb\z/, "".freeze) if loading.include?(expanded) raise "Circular dependency detected while autoloading constant #{qualified_name}" @@ -547,7 +547,7 @@ module ActiveSupport #:nodoc: end name_error = NameError.new("uninitialized constant #{qualified_name}", const_name) - name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ }) + name_error.set_backtrace(caller.reject { |l| l.starts_with? __FILE__ }) raise name_error end @@ -591,7 +591,7 @@ module ActiveSupport #:nodoc: def store(klass) return self unless klass.respond_to?(:name) - raise(ArgumentError, 'anonymous classes cannot be cached') if klass.name.empty? + raise(ArgumentError, "anonymous classes cannot be cached") if klass.name.empty? @store[klass.name] = klass self end @@ -675,29 +675,29 @@ module ActiveSupport #:nodoc: # A module, class, symbol, or string may be provided. def to_constant_name(desc) #:nodoc: case desc - when String then desc.sub(/^::/, '') - when Symbol then desc.to_s - when Module - desc.name || - raise(ArgumentError, "Anonymous modules have no name to be referenced by") + when String then desc.sub(/^::/, "") + when Symbol then desc.to_s + when Module + desc.name || + raise(ArgumentError, "Anonymous modules have no name to be referenced by") else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}" end end def remove_constant(const) #:nodoc: # Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo. - normalized = const.to_s.sub(/\A::/, '') - normalized.sub!(/\A(Object::)+/, '') + normalized = const.to_s.sub(/\A::/, "") + normalized.sub!(/\A(Object::)+/, "") - constants = normalized.split('::') + constants = normalized.split("::") to_remove = constants.pop # Remove the file path from the loaded list. file_path = search_for_file(const.underscore) if file_path expanded = File.expand_path(file_path) - expanded.sub!(/\.rb\z/, '') - self.loaded.delete(expanded) + expanded.sub!(/\.rb\z/, "") + loaded.delete(expanded) end if constants.empty? @@ -710,7 +710,7 @@ module ActiveSupport #:nodoc: # here than require the caller to be clever. We check the parent # rather than the very const argument because we do not want to # trigger Kernel#autoloads, see the comment below. - parent_name = constants.join('::') + parent_name = constants.join("::") return unless qualified_const_defined?(parent_name) parent = constantize(parent_name) end diff --git a/activesupport/lib/active_support/dependencies/interlock.rb b/activesupport/lib/active_support/dependencies/interlock.rb index f1865ca2f8..e4e18439c5 100644 --- a/activesupport/lib/active_support/dependencies/interlock.rb +++ b/activesupport/lib/active_support/dependencies/interlock.rb @@ -1,4 +1,4 @@ -require 'active_support/concurrency/share_lock' +require "active_support/concurrency/share_lock" module ActiveSupport #:nodoc: module Dependencies #:nodoc: @@ -46,6 +46,10 @@ module ActiveSupport #:nodoc: yield end end + + def raw_state(&block) # :nodoc: + @lock.raw_state(&block) + end end end end diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index b581710067..191e582de8 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -1,4 +1,4 @@ -require 'singleton' +require "singleton" module ActiveSupport # \Deprecation specifies the API used by Rails to deprecate methods, instance @@ -12,12 +12,12 @@ module ActiveSupport # a circular require warning for active_support/deprecation.rb. # # So, we define the constant first, and load dependencies later. - require 'active_support/deprecation/instance_delegator' - require 'active_support/deprecation/behaviors' - require 'active_support/deprecation/reporting' - require 'active_support/deprecation/method_wrappers' - require 'active_support/deprecation/proxy_wrappers' - require 'active_support/core_ext/module/deprecation' + require "active_support/deprecation/instance_delegator" + require "active_support/deprecation/behaviors" + require "active_support/deprecation/reporting" + require "active_support/deprecation/method_wrappers" + require "active_support/deprecation/proxy_wrappers" + require "active_support/core_ext/module/deprecation" include Singleton include InstanceDelegator @@ -32,7 +32,7 @@ module ActiveSupport # and the second is a library name # # ActiveSupport::Deprecation.new('2.0', 'MyLibrary') - def initialize(deprecation_horizon = '5.2', gem_name = 'Rails') + def initialize(deprecation_horizon = "5.2", gem_name = "Rails") self.gem_name = gem_name self.deprecation_horizon = deprecation_horizon # By default, warnings are not silenced and debugging is off. diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb index 35a9e5f8b8..1d1354c23e 100644 --- a/activesupport/lib/active_support/deprecation/behaviors.rb +++ b/activesupport/lib/active_support/deprecation/behaviors.rb @@ -25,7 +25,7 @@ module ActiveSupport if defined?(Rails.logger) && Rails.logger Rails.logger else - require 'active_support/logger' + require "active_support/logger" ActiveSupport::Logger.new($stderr) end logger.warn message @@ -34,7 +34,7 @@ module ActiveSupport notify: ->(message, callstack) { ActiveSupport::Notifications.instrument("deprecation.rails", - :message => message, :callstack => callstack) + message: message, callstack: callstack) }, silence: ->(message, callstack) {}, diff --git a/activesupport/lib/active_support/deprecation/instance_delegator.rb b/activesupport/lib/active_support/deprecation/instance_delegator.rb index 8472a58add..6d390f3b37 100644 --- a/activesupport/lib/active_support/deprecation/instance_delegator.rb +++ b/activesupport/lib/active_support/deprecation/instance_delegator.rb @@ -1,11 +1,12 @@ -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/delegation" module ActiveSupport class Deprecation module InstanceDelegator # :nodoc: def self.included(base) base.extend(ClassMethods) + base.singleton_class.prepend(OverrideDelegators) base.public_class_method :new end @@ -19,6 +20,18 @@ module ActiveSupport singleton_class.delegate(method_name, to: :instance) end end + + module OverrideDelegators # :nodoc: + def warn(message = nil, callstack = nil) + callstack ||= caller_locations(2) + super + end + + def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil) + caller_backtrace ||= caller_locations(2) + super + end + end end end end diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb index f5ea6669ce..7655fa4f99 100644 --- a/activesupport/lib/active_support/deprecation/method_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/module/aliasing' -require 'active_support/core_ext/array/extract_options' +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/array/extract_options" module ActiveSupport class Deprecation diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb index 0cb2d4d22e..1c6618b19a 100644 --- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb @@ -1,4 +1,5 @@ -require 'active_support/inflector/methods' +require "active_support/inflector/methods" +require "active_support/core_ext/regexp" module ActiveSupport class Deprecation @@ -10,7 +11,7 @@ module ActiveSupport super end - instance_methods.each { |m| undef_method m unless m =~ /^__|^object_id$/ } + instance_methods.each { |m| undef_method m unless /^__|^object_id$/.match?(m) } # Don't give a deprecation warning on inspect since test/unit and error # logs rely on it for diagnostics. diff --git a/activesupport/lib/active_support/deprecation/reporting.rb b/activesupport/lib/active_support/deprecation/reporting.rb index de5b233679..b8d200ba94 100644 --- a/activesupport/lib/active_support/deprecation/reporting.rb +++ b/activesupport/lib/active_support/deprecation/reporting.rb @@ -1,4 +1,4 @@ -require 'rbconfig' +require "rbconfig" module ActiveSupport class Deprecation @@ -57,8 +57,8 @@ module ActiveSupport def deprecated_method_warning(method_name, message = nil) warning = "#{method_name} is deprecated and will be removed from #{gem_name} #{deprecation_horizon}" case message - when Symbol then "#{warning} (use #{message} instead)" - when String then "#{warning} (#{message})" + when Symbol then "#{warning} (use #{message} instead)" + when String then "#{warning} (#{message})" else warning end end @@ -105,7 +105,7 @@ module ActiveSupport RAILS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/" def ignored_callstack(path) - path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG['rubylibdir']) + path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"]) end end end diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index 47d09f4f5a..6ec0c3a70a 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/array/conversions' -require 'active_support/core_ext/object/acts_like' +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/object/acts_like" module ActiveSupport # Provides accurate date and time measurements using Date#advance and @@ -9,8 +9,8 @@ module ActiveSupport class Duration attr_accessor :value, :parts - autoload :ISO8601Parser, 'active_support/duration/iso8601_parser' - autoload :ISO8601Serializer, 'active_support/duration/iso8601_serializer' + autoload :ISO8601Parser, "active_support/duration/iso8601_parser" + autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer" def initialize(value, parts) #:nodoc: @value, @parts = value, parts @@ -120,8 +120,8 @@ module ActiveSupport def inspect #:nodoc: parts. reduce(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }. - sort_by {|unit, _ | [:years, :months, :weeks, :days, :hours, :minutes, :seconds].index(unit)}. - map {|unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}"}. + sort_by { |unit, _ | [:years, :months, :weeks, :days, :hours, :minutes, :seconds].index(unit) }. + map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }. to_sentence(locale: ::I18n.default_locale) end diff --git a/activesupport/lib/active_support/duration/iso8601_parser.rb b/activesupport/lib/active_support/duration/iso8601_parser.rb index 07af58ad99..e96cb8e883 100644 --- a/activesupport/lib/active_support/duration/iso8601_parser.rb +++ b/activesupport/lib/active_support/duration/iso8601_parser.rb @@ -1,4 +1,5 @@ -require 'strscan' +require "strscan" +require "active_support/core_ext/regexp" module ActiveSupport class Duration @@ -11,8 +12,8 @@ module ActiveSupport class ParsingError < ::ArgumentError; end PERIOD_OR_COMMA = /\.|,/ - PERIOD = '.'.freeze - COMMA = ','.freeze + PERIOD = ".".freeze + COMMA = ",".freeze SIGN_MARKER = /\A\-|\+|/ DATE_MARKER = /P/ @@ -20,8 +21,8 @@ module ActiveSupport DATE_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(Y|M|D|W)/ TIME_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(H|M|S)/ - DATE_TO_PART = { 'Y' => :years, 'M' => :months, 'W' => :weeks, 'D' => :days } - TIME_TO_PART = { 'H' => :hours, 'M' => :minutes, 'S' => :seconds } + DATE_TO_PART = { "Y" => :years, "M" => :months, "W" => :weeks, "D" => :days } + TIME_TO_PART = { "H" => :hours, "M" => :minutes, "S" => :seconds } DATE_COMPONENTS = [:years, :months, :days] TIME_COMPONENTS = [:hours, :minutes, :seconds] @@ -39,36 +40,36 @@ module ActiveSupport def parse! while !finished? case mode - when :start - if scan(SIGN_MARKER) - self.sign = (scanner.matched == '-') ? -1 : 1 - self.mode = :sign - else - raise_parsing_error - end - - when :sign - if scan(DATE_MARKER) - self.mode = :date - else - raise_parsing_error - end - - when :date - if scan(TIME_MARKER) - self.mode = :time - elsif scan(DATE_COMPONENT) - parts[DATE_TO_PART[scanner[2]]] = number * sign - else - raise_parsing_error - end - - when :time - if scan(TIME_COMPONENT) - parts[TIME_TO_PART[scanner[2]]] = number * sign - else - raise_parsing_error - end + when :start + if scan(SIGN_MARKER) + self.sign = (scanner.matched == "-") ? -1 : 1 + self.mode = :sign + else + raise_parsing_error + end + + when :sign + if scan(DATE_MARKER) + self.mode = :date + else + raise_parsing_error + end + + when :date + if scan(TIME_MARKER) + self.mode = :time + elsif scan(DATE_COMPONENT) + parts[DATE_TO_PART[scanner[2]]] = number * sign + else + raise_parsing_error + end + + when :time + if scan(TIME_COMPONENT) + parts[TIME_TO_PART[scanner[2]]] = number * sign + else + raise_parsing_error + end end end @@ -79,44 +80,44 @@ module ActiveSupport private - def finished? - scanner.eos? - end + def finished? + scanner.eos? + end - # Parses number which can be a float with either comma or period. - def number - scanner[1] =~ PERIOD_OR_COMMA ? scanner[1].tr(COMMA, PERIOD).to_f : scanner[1].to_i - end + # Parses number which can be a float with either comma or period. + def number + PERIOD_OR_COMMA.match?(scanner[1]) ? scanner[1].tr(COMMA, PERIOD).to_f : scanner[1].to_i + end - def scan(pattern) - scanner.scan(pattern) - end + def scan(pattern) + scanner.scan(pattern) + end - def raise_parsing_error(reason = nil) - raise ParsingError, "Invalid ISO 8601 duration: #{scanner.string.inspect} #{reason}".strip - end + def raise_parsing_error(reason = nil) + raise ParsingError, "Invalid ISO 8601 duration: #{scanner.string.inspect} #{reason}".strip + end - # Checks for various semantic errors as stated in ISO 8601 standard. - def validate! - raise_parsing_error('is empty duration') if parts.empty? + # Checks for various semantic errors as stated in ISO 8601 standard. + def validate! + raise_parsing_error("is empty duration") if parts.empty? - # Mixing any of Y, M, D with W is invalid. - if parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any? - raise_parsing_error('mixing weeks with other date parts not allowed') - end + # Mixing any of Y, M, D with W is invalid. + if parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any? + raise_parsing_error("mixing weeks with other date parts not allowed") + end - # Specifying an empty T part is invalid. - if mode == :time && (parts.keys & TIME_COMPONENTS).empty? - raise_parsing_error('time part marker is present but time part is empty') - end + # Specifying an empty T part is invalid. + if mode == :time && (parts.keys & TIME_COMPONENTS).empty? + raise_parsing_error("time part marker is present but time part is empty") + end - fractions = parts.values.reject(&:zero?).select { |a| (a % 1) != 0 } - unless fractions.empty? || (fractions.size == 1 && fractions.last == @parts.values.reject(&:zero?).last) - raise_parsing_error '(only last part can be fractional)' - end + fractions = parts.values.reject(&:zero?).select { |a| (a % 1) != 0 } + unless fractions.empty? || (fractions.size == 1 && fractions.last == @parts.values.reject(&:zero?).last) + raise_parsing_error "(only last part can be fractional)" + end - return true - end + return true + end end end end diff --git a/activesupport/lib/active_support/duration/iso8601_serializer.rb b/activesupport/lib/active_support/duration/iso8601_serializer.rb index 05c6a083a9..542630b950 100644 --- a/activesupport/lib/active_support/duration/iso8601_serializer.rb +++ b/activesupport/lib/active_support/duration/iso8601_serializer.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/hash/transform_values' +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/transform_values" module ActiveSupport class Duration @@ -12,13 +12,15 @@ module ActiveSupport # Builds and returns output string. def serialize - output = 'P' parts, sign = normalize + return "PT0S".freeze if parts.empty? + + output = "P" output << "#{parts[:years]}Y" if parts.key?(:years) output << "#{parts[:months]}M" if parts.key?(:months) output << "#{parts[:weeks]}W" if parts.key?(:weeks) output << "#{parts[:days]}D" if parts.key?(:days) - time = '' + time = "" time << "#{parts[:hours]}H" if parts.key?(:hours) time << "#{parts[:minutes]}M" if parts.key?(:minutes) if parts.key?(:seconds) @@ -39,9 +41,9 @@ module ActiveSupport p[k] += v unless v.zero? end # If all parts are negative - let's make a negative duration - sign = '' + sign = "" if parts.values.all? { |v| v < 0 } - sign = '-' + sign = "-" parts.transform_values!(&:-@) end [parts, sign] diff --git a/activesupport/lib/active_support/evented_file_update_checker.rb b/activesupport/lib/active_support/evented_file_update_checker.rb index a2dcf31132..f54f88eb0a 100644 --- a/activesupport/lib/active_support/evented_file_update_checker.rb +++ b/activesupport/lib/active_support/evented_file_update_checker.rb @@ -1,6 +1,6 @@ -require 'set' -require 'pathname' -require 'concurrent/atomic/atomic_boolean' +require "set" +require "pathname" +require "concurrent/atomic/atomic_boolean" module ActiveSupport # Allows you to "listen" to changes in a file system. @@ -52,7 +52,7 @@ module ActiveSupport # to our test suite. Thus, we lazy load it and disable warnings locally. silence_warnings do begin - require 'listen' + require "listen" rescue LoadError => e raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace end @@ -124,71 +124,71 @@ module ActiveSupport @ph.filter_out_descendants(dtw) end - class PathHelper - def xpath(path) - Pathname.new(path).expand_path - end + class PathHelper + def xpath(path) + Pathname.new(path).expand_path + end - def normalize_extension(ext) - ext.to_s.sub(/\A\./, '') - end + def normalize_extension(ext) + ext.to_s.sub(/\A\./, "") + end - # Given a collection of Pathname objects returns the longest subpath - # common to all of them, or +nil+ if there is none. - def longest_common_subpath(paths) - return if paths.empty? - - lcsp = Pathname.new(paths[0]) - - paths[1..-1].each do |path| - until ascendant_of?(lcsp, path) - if lcsp.root? - # If we get here a root directory is not an ascendant of path. - # This may happen if there are paths in different drives on - # Windows. - return - else - lcsp = lcsp.parent + # Given a collection of Pathname objects returns the longest subpath + # common to all of them, or +nil+ if there is none. + def longest_common_subpath(paths) + return if paths.empty? + + lcsp = Pathname.new(paths[0]) + + paths[1..-1].each do |path| + until ascendant_of?(lcsp, path) + if lcsp.root? + # If we get here a root directory is not an ascendant of path. + # This may happen if there are paths in different drives on + # Windows. + return + else + lcsp = lcsp.parent + end end end - end - lcsp - end + lcsp + end - # Returns the deepest existing ascendant, which could be the argument itself. - def existing_parent(dir) - dir.ascend do |ascendant| - break ascendant if ascendant.directory? + # Returns the deepest existing ascendant, which could be the argument itself. + def existing_parent(dir) + dir.ascend do |ascendant| + break ascendant if ascendant.directory? + end end - end - # Filters out directories which are descendants of others in the collection (stable). - def filter_out_descendants(dirs) - return dirs if dirs.length < 2 + # Filters out directories which are descendants of others in the collection (stable). + def filter_out_descendants(dirs) + return dirs if dirs.length < 2 - dirs_sorted_by_nparts = dirs.sort_by { |dir| dir.each_filename.to_a.length } - descendants = [] + dirs_sorted_by_nparts = dirs.sort_by { |dir| dir.each_filename.to_a.length } + descendants = [] - until dirs_sorted_by_nparts.empty? - dir = dirs_sorted_by_nparts.shift + until dirs_sorted_by_nparts.empty? + dir = dirs_sorted_by_nparts.shift - dirs_sorted_by_nparts.reject! do |possible_descendant| - ascendant_of?(dir, possible_descendant) && descendants << possible_descendant + dirs_sorted_by_nparts.reject! do |possible_descendant| + ascendant_of?(dir, possible_descendant) && descendants << possible_descendant + end end - end - # Array#- preserves order. - dirs - descendants - end + # Array#- preserves order. + dirs - descendants + end - private + private - def ascendant_of?(base, other) - base != other && other.ascend do |ascendant| - break true if base == ascendant + def ascendant_of?(base, other) + base != other && other.ascend do |ascendant| + break true if base == ascendant + end end - end - end + end end end diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb index 00c5745a25..3384d12d5b 100644 --- a/activesupport/lib/active_support/execution_wrapper.rb +++ b/activesupport/lib/active_support/execution_wrapper.rb @@ -1,4 +1,4 @@ -require 'active_support/callbacks' +require "active_support/callbacks" module ActiveSupport class ExecutionWrapper @@ -19,6 +19,23 @@ module ActiveSupport set_callback(:complete, *args, &block) end + class RunHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + hook_state[hook] = hook.run + end + end + + class CompleteHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + if hook_state.key?(hook) + hook.complete hook_state[hook] + end + end + alias after before + end + # Register an object to be invoked during both the +run+ and # +complete+ steps. # @@ -29,19 +46,11 @@ module ActiveSupport # invoked in that situation.) def self.register_hook(hook, outer: false) if outer - run_args = [prepend: true] - complete_args = [:after] + to_run RunHook.new(hook), prepend: true + to_complete :after, CompleteHook.new(hook) else - run_args = complete_args = [] - end - - to_run(*run_args) do - hook_state[hook] = hook.run - end - to_complete(*complete_args) do - if hook_state.key?(hook) - hook.complete hook_state[hook] - end + to_run RunHook.new(hook) + to_complete CompleteHook.new(hook) end end diff --git a/activesupport/lib/active_support/executor.rb b/activesupport/lib/active_support/executor.rb index 602fb11a44..a6400cae0a 100644 --- a/activesupport/lib/active_support/executor.rb +++ b/activesupport/lib/active_support/executor.rb @@ -1,4 +1,4 @@ -require 'active_support/execution_wrapper' +require "active_support/execution_wrapper" module ActiveSupport class Executor < ExecutionWrapper diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb index b5667b6ac8..98aceabe21 100644 --- a/activesupport/lib/active_support/file_update_checker.rb +++ b/activesupport/lib/active_support/file_update_checker.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/time/calculations' +require "active_support/core_ext/time/calculations" module ActiveSupport # FileUpdateChecker specifies the API used by Rails to watch files @@ -93,65 +93,65 @@ module ActiveSupport private - def watched - @watched || begin - all = @files.select { |f| File.exist?(f) } - all.concat(Dir[@glob]) if @glob - all + def watched + @watched || begin + all = @files.select { |f| File.exist?(f) } + all.concat(Dir[@glob]) if @glob + all + end end - end - def updated_at(paths) - @updated_at || max_mtime(paths) || Time.at(0) - end + def updated_at(paths) + @updated_at || max_mtime(paths) || Time.at(0) + end - # This method returns the maximum mtime of the files in +paths+, or +nil+ - # if the array is empty. - # - # Files with a mtime in the future are ignored. Such abnormal situation - # can happen for example if the user changes the clock by hand. It is - # healthy to consider this edge case because with mtimes in the future - # reloading is not triggered. - def max_mtime(paths) - time_now = Time.now - max_mtime = nil - - # Time comparisons are performed with #compare_without_coercion because - # AS redefines these operators in a way that is much slower and does not - # bring any benefit in this particular code. + # This method returns the maximum mtime of the files in +paths+, or +nil+ + # if the array is empty. # - # Read t1.compare_without_coercion(t2) < 0 as t1 < t2. - paths.each do |path| - mtime = File.mtime(path) - - next if time_now.compare_without_coercion(mtime) < 0 - - if max_mtime.nil? || max_mtime.compare_without_coercion(mtime) < 0 - max_mtime = mtime + # Files with a mtime in the future are ignored. Such abnormal situation + # can happen for example if the user changes the clock by hand. It is + # healthy to consider this edge case because with mtimes in the future + # reloading is not triggered. + def max_mtime(paths) + time_now = Time.now + max_mtime = nil + + # Time comparisons are performed with #compare_without_coercion because + # AS redefines these operators in a way that is much slower and does not + # bring any benefit in this particular code. + # + # Read t1.compare_without_coercion(t2) < 0 as t1 < t2. + paths.each do |path| + mtime = File.mtime(path) + + next if time_now.compare_without_coercion(mtime) < 0 + + if max_mtime.nil? || max_mtime.compare_without_coercion(mtime) < 0 + max_mtime = mtime + end end - end - max_mtime - end + max_mtime + end - def compile_glob(hash) - hash.freeze # Freeze so changes aren't accidentally pushed - return if hash.empty? + def compile_glob(hash) + hash.freeze # Freeze so changes aren't accidentally pushed + return if hash.empty? - globs = hash.map do |key, value| - "#{escape(key)}/**/*#{compile_ext(value)}" + globs = hash.map do |key, value| + "#{escape(key)}/**/*#{compile_ext(value)}" + end + "{#{globs.join(",")}}" end - "{#{globs.join(",")}}" - end - def escape(key) - key.gsub(',','\,') - end + def escape(key) + key.gsub(",",'\,') + end - def compile_ext(array) - array = Array(array) - return if array.empty? - ".{#{array.join(",")}}" - end + def compile_ext(array) + array = Array(array) + return if array.empty? + ".{#{array.join(",")}}" + end end end diff --git a/activesupport/lib/active_support/gzip.rb b/activesupport/lib/active_support/gzip.rb index b837c879bb..4aee8dddba 100644 --- a/activesupport/lib/active_support/gzip.rb +++ b/activesupport/lib/active_support/gzip.rb @@ -1,5 +1,5 @@ -require 'zlib' -require 'stringio' +require "zlib" +require "stringio" module ActiveSupport # A convenient wrapper for the zlib standard library that allows @@ -9,7 +9,7 @@ module ActiveSupport # # => "\x1F\x8B\b\x00o\x8D\xCDO\x00\x03K\xCE\xCF-(J-.V\xC8MU\x04\x00R>n\x83\f\x00\x00\x00" # # ActiveSupport::Gzip.decompress(gzip) - # # => "compress me!" + # # => "compress me!" module Gzip class Stream < StringIO def initialize(*) diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 03770a197c..7ecc5c19bd 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/hash/reverse_merge' +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/hash/reverse_merge" module ActiveSupport # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered @@ -40,6 +40,12 @@ module ActiveSupport # rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access # # which may be handy. + # + # To access this class outside of Rails, require the core extension with: + # + # require "active_support/core_ext/hash/indifferent_access" + # + # which will, in turn, require this file. class HashWithIndifferentAccess < Hash # Returns +true+ so that <tt>Array#extract_options!</tt> finds members of # this class. @@ -161,7 +167,6 @@ module ActiveSupport alias_method :has_key?, :key? alias_method :member?, :key? - # Same as <tt>Hash#[]</tt> where the key passed as argument can be # either a string or a symbol: # @@ -217,7 +222,7 @@ module ActiveSupport # modify the receiver but rather returns a new hash with indifferent # access with the result of the merge. def merge(hash, &block) - self.dup.update(hash, &block) + dup.update(hash, &block) end # Like +merge+ but the other way around: Merges the receiver into the diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 6cc98191d4..f0408f429c 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -1,13 +1,13 @@ -require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/hash/slice' +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" begin - require 'i18n' + require "i18n" rescue LoadError => e $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install" raise e end -require 'active_support/lazy_load_hooks' +require "active_support/lazy_load_hooks" ActiveSupport.run_load_hooks(:i18n) I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml" diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb index 6cc7c90c12..08c9ef8f02 100644 --- a/activesupport/lib/active_support/i18n_railtie.rb +++ b/activesupport/lib/active_support/i18n_railtie.rb @@ -83,14 +83,15 @@ module I18n def self.init_fallbacks(fallbacks) include_fallbacks_module - args = case fallbacks - when ActiveSupport::OrderedOptions - [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact - when Hash, Array - Array.wrap(fallbacks) - else # TrueClass - [] - end + args = \ + case fallbacks + when ActiveSupport::OrderedOptions + [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact + when Hash, Array + Array.wrap(fallbacks) + else # TrueClass + [] + end I18n.fallbacks = I18n::Locale::Fallbacks.new(*args) end diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb index 2ca1124e76..afa7d1f325 100644 --- a/activesupport/lib/active_support/inflections.rb +++ b/activesupport/lib/active_support/inflections.rb @@ -1,4 +1,4 @@ -require 'active_support/inflector/inflections' +require "active_support/inflector/inflections" #-- # Defines the standard inflection rules. These are the starting point for @@ -8,8 +8,8 @@ require 'active_support/inflector/inflections' #++ module ActiveSupport Inflector.inflections(:en) do |inflect| - inflect.plural(/$/, 's') - inflect.plural(/s$/i, 's') + inflect.plural(/$/, "s") + inflect.plural(/s$/i, "s") inflect.plural(/^(ax|test)is$/i, '\1es') inflect.plural(/(octop|vir)us$/i, '\1i') inflect.plural(/(octop|vir)i$/i, '\1i') @@ -18,7 +18,7 @@ module ActiveSupport inflect.plural(/(buffal|tomat)o$/i, '\1oes') inflect.plural(/([ti])um$/i, '\1a') inflect.plural(/([ti])a$/i, '\1a') - inflect.plural(/sis$/i, 'ses') + inflect.plural(/sis$/i, "ses") inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves') inflect.plural(/(hive)$/i, '\1s') inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies') @@ -30,7 +30,7 @@ module ActiveSupport inflect.plural(/^(oxen)$/i, '\1') inflect.plural(/(quiz)$/i, '\1zes') - inflect.singular(/s$/i, '') + inflect.singular(/s$/i, "") inflect.singular(/(ss)$/i, '\1') inflect.singular(/(n)ews$/i, '\1ews') inflect.singular(/([ti])a$/i, '\1um') @@ -58,12 +58,12 @@ module ActiveSupport inflect.singular(/(quiz)zes$/i, '\1') inflect.singular(/(database)s$/i, '\1') - inflect.irregular('person', 'people') - inflect.irregular('man', 'men') - inflect.irregular('child', 'children') - inflect.irregular('sex', 'sexes') - inflect.irregular('move', 'moves') - inflect.irregular('zombie', 'zombies') + inflect.irregular("person", "people") + inflect.irregular("man", "men") + inflect.irregular("child", "children") + inflect.irregular("sex", "sexes") + inflect.irregular("move", "moves") + inflect.irregular("zombie", "zombies") inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police)) end diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 215a60eba7..48631b16a8 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -1,7 +1,7 @@ # in case active_support/inflector is required without the rest of active_support -require 'active_support/inflector/inflections' -require 'active_support/inflector/transliterate' -require 'active_support/inflector/methods' +require "active_support/inflector/inflections" +require "active_support/inflector/transliterate" +require "active_support/inflector/methods" -require 'active_support/inflections' -require 'active_support/core_ext/string/inflections' +require "active_support/inflections" +require "active_support/core_ext/string/inflections" diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb index f3e52b48ac..aa68f9ec9e 100644 --- a/activesupport/lib/active_support/inflector/inflections.rb +++ b/activesupport/lib/active_support/inflector/inflections.rb @@ -1,6 +1,6 @@ -require 'concurrent/map' -require 'active_support/core_ext/array/prepend_and_append' -require 'active_support/i18n' +require "concurrent/map" +require "active_support/core_ext/array/prepend_and_append" +require "active_support/i18n" module ActiveSupport module Inflector @@ -43,8 +43,8 @@ module ActiveSupport end def add(words) - self.concat(words.flatten.map(&:downcase)) - @regex_array += self.map {|word| to_regex(word) } + concat(words.flatten.map(&:downcase)) + @regex_array += map { |word| to_regex(word) } self end @@ -215,10 +215,10 @@ module ActiveSupport # clear :plurals def clear(scope = :all) case scope - when :all - @plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, [] + when :all + @plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, [] else - instance_variable_set "@#{scope}", [] + instance_variable_set "@#{scope}", [] end end end diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index f94e12e14f..c80243c40a 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -1,4 +1,5 @@ -require 'active_support/inflections' +require "active_support/inflections" +require "active_support/core_ext/regexp" module ActiveSupport # The Inflector transforms words from singular to plural, class names to table @@ -71,7 +72,7 @@ module ActiveSupport string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase } end string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" } - string.gsub!('/'.freeze, '::'.freeze) + string.gsub!("/".freeze, "::".freeze) string end @@ -87,8 +88,8 @@ module ActiveSupport # # camelize(underscore('SSLError')) # => "SslError" def underscore(camel_cased_word) - return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/ - word = camel_cased_word.to_s.gsub('::'.freeze, '/'.freeze) + return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word) + word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze) word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'.freeze }#{$2.downcase}" } word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze) word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze) @@ -125,9 +126,9 @@ module ActiveSupport inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) } - result.sub!(/\A_+/, ''.freeze) - result.sub!(/_id\z/, ''.freeze) - result.tr!('_'.freeze, ' '.freeze) + result.sub!(/\A_+/, "".freeze) + result.sub!(/_id\z/, "".freeze) + result.tr!("_".freeze, " ".freeze) result.gsub!(/([a-z\d]*)/i) do |match| "#{inflections.acronyms[match] || match.downcase}" @@ -146,7 +147,7 @@ module ActiveSupport # upcase_first('w') # => "W" # upcase_first('') # => "" def upcase_first(string) - string.length > 0 ? string[0].upcase.concat(string[1..-1]) : '' + string.length > 0 ? string[0].upcase.concat(string[1..-1]) : "" end # Capitalizes all the words and replaces some characters in the string to @@ -185,14 +186,14 @@ module ActiveSupport # classify('calculus') # => "Calculus" def classify(table_name) # strip out any leading schema name - camelize(singularize(table_name.to_s.sub(/.*\./, ''.freeze))) + camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze))) end # Replaces underscores with dashes in the string. # # dasherize('puni_puni') # => "puni-puni" def dasherize(underscored_word) - underscored_word.tr('_'.freeze, '-'.freeze) + underscored_word.tr("_".freeze, "-".freeze) end # Removes the module part from the expression in the string. @@ -205,7 +206,7 @@ module ActiveSupport # See also #deconstantize. def demodulize(path) path = path.to_s - if i = path.rindex('::') + if i = path.rindex("::") path[(i+2)..-1] else path @@ -222,7 +223,7 @@ module ActiveSupport # # See also #demodulize. def deconstantize(path) - path.to_s[0, path.rindex('::') || 0] # implementation based on the one in facets' Module#spacename + path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename end # Creates a foreign key name from a class name. @@ -238,8 +239,8 @@ module ActiveSupport # Tries to find a constant with the name specified in the argument string. # - # 'Module'.constantize # => Module - # 'Foo::Bar'.constantize # => Foo::Bar + # constantize('Module') # => Module + # constantize('Foo::Bar') # => Foo::Bar # # The name is assumed to be the one of a top-level constant, no matter # whether it starts with "::" or not. No lexical context is taken into @@ -248,14 +249,14 @@ module ActiveSupport # C = 'outside' # module M # C = 'inside' - # C # => 'inside' - # 'C'.constantize # => 'outside', same as ::C + # C # => 'inside' + # constantize('C') # => 'outside', same as ::C # end # # NameError is raised when the name is not in CamelCase or the constant is # unknown. def constantize(camel_cased_word) - names = camel_cased_word.split('::'.freeze) + names = camel_cased_word.split("::".freeze) # Trigger a built-in NameError exception including the ill-formed constant in the message. Object.const_get(camel_cased_word) if names.empty? @@ -313,7 +314,7 @@ module ActiveSupport raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) || e.name.to_s == camel_cased_word.to_s) rescue ArgumentError => e - raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/ + raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message) end # Returns the suffix that should be added to a number to denote the position @@ -332,9 +333,9 @@ module ActiveSupport "th" else case abs_number % 10 - when 1; "st" - when 2; "nd" - when 3; "rd" + when 1; "st" + when 2; "nd" + when 3; "rd" else "th" end end @@ -355,36 +356,36 @@ module ActiveSupport private - # Mounts a regular expression, returned as a string to ease interpolation, - # that will match part by part the given constant. - # - # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?" - # const_regexp("::") # => "::" - def const_regexp(camel_cased_word) #:nodoc: - parts = camel_cased_word.split("::".freeze) + # Mounts a regular expression, returned as a string to ease interpolation, + # that will match part by part the given constant. + # + # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?" + # const_regexp("::") # => "::" + def const_regexp(camel_cased_word) #:nodoc: + parts = camel_cased_word.split("::".freeze) - return Regexp.escape(camel_cased_word) if parts.blank? + return Regexp.escape(camel_cased_word) if parts.blank? - last = parts.pop + last = parts.pop - parts.reverse.inject(last) do |acc, part| - part.empty? ? acc : "#{part}(::#{acc})?" + parts.reverse.inject(last) do |acc, part| + part.empty? ? acc : "#{part}(::#{acc})?" + end end - end - # Applies inflection rules for +singularize+ and +pluralize+. - # - # apply_inflections('post', inflections.plurals) # => "posts" - # apply_inflections('posts', inflections.singulars) # => "post" - def apply_inflections(word, rules) - result = word.to_s.dup + # Applies inflection rules for +singularize+ and +pluralize+. + # + # apply_inflections('post', inflections.plurals) # => "posts" + # apply_inflections('posts', inflections.singulars) # => "post" + def apply_inflections(word, rules) + result = word.to_s.dup - if word.empty? || inflections.uncountables.uncountable?(result) - result - else - rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) } - result + if word.empty? || inflections.uncountables.uncountable?(result) + result + else + rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) } + result + end end - end end end diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb index 871cfb8a72..85fa83c803 100644 --- a/activesupport/lib/active_support/inflector/transliterate.rb +++ b/activesupport/lib/active_support/inflector/transliterate.rb @@ -1,9 +1,8 @@ -require 'active_support/core_ext/string/multibyte' -require 'active_support/i18n' +require "active_support/core_ext/string/multibyte" +require "active_support/i18n" module ActiveSupport module Inflector - # Replaces non-ASCII characters with an ASCII approximation, or if none # exists, a replacement character which defaults to "?". # @@ -60,7 +59,7 @@ module ActiveSupport def transliterate(string, replacement = "?".freeze) I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize( ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c), - :replacement => replacement) + replacement: replacement) end # Replaces special characters in a string so that it may be used as part of @@ -79,7 +78,7 @@ module ActiveSupport # parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth" # parameterize("^trés|Jolie-- ", preserve_case: true) # => "tres-Jolie" # - def parameterize(string, sep = :unused, separator: '-', preserve_case: false) + def parameterize(string, sep = :unused, separator: "-", preserve_case: false) unless sep == :unused ActiveSupport::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.") separator = sep @@ -102,9 +101,9 @@ module ActiveSupport # No more than one of the separator in a row. parameterized_string.gsub!(re_duplicate_separator, separator) # Remove leading/trailing separator. - parameterized_string.gsub!(re_leading_trailing_separator, ''.freeze) + parameterized_string.gsub!(re_leading_trailing_separator, "".freeze) end - + parameterized_string.downcase! unless preserve_case parameterized_string end diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index 3e1d9b1d33..da938d1555 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,2 +1,2 @@ -require 'active_support/json/decoding' -require 'active_support/json/encoding' +require "active_support/json/decoding" +require "active_support/json/encoding" diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index 2932954f03..f487fa0c65 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/module/delegation' -require 'json' +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/delegation" +require "json" module ActiveSupport # Look for and parse json strings that look like ISO 8601 times. @@ -8,7 +8,8 @@ module ActiveSupport module JSON # matches YAML-formatted dates - DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/ + DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/ + DATETIME_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)$/ class << self # Parses a JSON string (JavaScript Object Notation) into a hash. @@ -48,7 +49,13 @@ module ActiveSupport nil when DATE_REGEX begin - DateTime.parse(data) + Date.parse(data) + rescue ArgumentError + data + end + when DATETIME_REGEX + begin + Time.zone.parse(data) rescue ArgumentError data end diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 031c5e9339..cee731417f 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/object/json' -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/object/json" +require "active_support/core_ext/module/delegation" module ActiveSupport class << self @@ -7,7 +7,7 @@ module ActiveSupport :time_precision, :time_precision=, :escape_html_entities_in_json, :escape_html_entities_in_json=, :json_encoder, :json_encoder=, - :to => :'ActiveSupport::JSON::Encoding' + to: :'ActiveSupport::JSON::Encoding' end module JSON @@ -40,9 +40,9 @@ module ActiveSupport ESCAPED_CHARS = { "\u2028" => '\u2028', "\u2029" => '\u2029', - '>' => '\u003e', - '<' => '\u003c', - '&' => '\u0026', + ">" => '\u003e', + "<" => '\u003c', + "&" => '\u0026', } ESCAPE_REGEX_WITH_HTML_ENTITIES = /[\u2028\u2029><&]/u diff --git a/activesupport/lib/active_support/key_generator.rb b/activesupport/lib/active_support/key_generator.rb index 7f73f9ddfc..1064398d8c 100644 --- a/activesupport/lib/active_support/key_generator.rb +++ b/activesupport/lib/active_support/key_generator.rb @@ -1,5 +1,5 @@ -require 'concurrent/map' -require 'openssl' +require "concurrent/map" +require "openssl" module ActiveSupport # KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2. @@ -31,11 +31,9 @@ module ActiveSupport @cache_keys = Concurrent::Map.new end - # Returns a derived key suitable for use. The default key_size is chosen - # to be compatible with the default settings of ActiveSupport::MessageVerifier. - # i.e. OpenSSL::Digest::SHA1#block_length - def generate_key(salt, key_size=64) - @cache_keys["#{salt}#{key_size}"] ||= @key_generator.generate_key(salt, key_size) + # Returns a derived key suitable for use. + def generate_key(*args) + @cache_keys[args.join] ||= @key_generator.generate_key(*args) end end @@ -53,21 +51,21 @@ module ActiveSupport private - # To prevent users from using something insecure like "Password" we make sure that the - # secret they've provided is at least 30 characters in length. - def ensure_secret_secure(secret) - if secret.blank? - raise ArgumentError, "A secret is required to generate an integrity hash " \ - "for cookie session data. Set a secret_key_base of at least " \ - "#{SECRET_MIN_LENGTH} characters in config/secrets.yml." - end + # To prevent users from using something insecure like "Password" we make sure that the + # secret they've provided is at least 30 characters in length. + def ensure_secret_secure(secret) + if secret.blank? + raise ArgumentError, "A secret is required to generate an integrity hash " \ + "for cookie session data. Set a secret_key_base of at least " \ + "#{SECRET_MIN_LENGTH} characters in config/secrets.yml." + end - if secret.length < SECRET_MIN_LENGTH - raise ArgumentError, "Secret should be something secure, " \ - "like \"#{SecureRandom.hex(16)}\". The value you " \ - "provided, \"#{secret}\", is shorter than the minimum length " \ - "of #{SECRET_MIN_LENGTH} characters." + if secret.length < SECRET_MIN_LENGTH + raise ArgumentError, "Secret should be something secure, " \ + "like \"#{SecureRandom.hex(16)}\". The value you " \ + "provided, \"#{secret}\", is shorter than the minimum length " \ + "of #{SECRET_MIN_LENGTH} characters." + end end - end end end diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb index e2b8f0f648..ae1897b886 100644 --- a/activesupport/lib/active_support/lazy_load_hooks.rb +++ b/activesupport/lib/active_support/lazy_load_hooks.rb @@ -15,34 +15,44 @@ module ActiveSupport # end # end # - # When the entirety of +activerecord/lib/active_record/base.rb+ has been + # When the entirety of +ActiveRecord::Base+ has been # evaluated then +run_load_hooks+ is invoked. The very last line of - # +activerecord/lib/active_record/base.rb+ is: + # +ActiveRecord::Base+ is: # # ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base) - @load_hooks = Hash.new { |h,k| h[k] = [] } - @loaded = Hash.new { |h,k| h[k] = [] } - - def self.on_load(name, options = {}, &block) - @loaded[name].each do |base| - execute_hook(base, options, block) + module LazyLoadHooks + def self.extended(base) # :nodoc: + base.class_eval do + @load_hooks = Hash.new { |h,k| h[k] = [] } + @loaded = Hash.new { |h,k| h[k] = [] } + end end - @load_hooks[name] << [block, options] - end + # Declares a block that will be executed when a Rails component is fully + # loaded. + def on_load(name, options = {}, &block) + @loaded[name].each do |base| + execute_hook(base, options, block) + end - def self.execute_hook(base, options, block) - if options[:yield] - block.call(base) - else - base.instance_eval(&block) + @load_hooks[name] << [block, options] end - end - def self.run_load_hooks(name, base = Object) - @loaded[name] << base - @load_hooks[name].each do |hook, options| - execute_hook(base, options, hook) + def execute_hook(base, options, block) + if options[:yield] + block.call(base) + else + base.instance_eval(&block) + end + end + + def run_load_hooks(name, base = Object) + @loaded[name] << base + @load_hooks[name].each do |hook, options| + execute_hook(base, options, hook) + end end end + + extend LazyLoadHooks end diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb index e782cd2d4b..e5812d75d0 100644 --- a/activesupport/lib/active_support/log_subscriber.rb +++ b/activesupport/lib/active_support/log_subscriber.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/class/attribute' -require 'active_support/subscriber' +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/class/attribute" +require "active_support/subscriber" module ActiveSupport # ActiveSupport::LogSubscriber is an object set to consume diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb index 588ed67c81..a7e30632f6 100644 --- a/activesupport/lib/active_support/log_subscriber/test_helper.rb +++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb @@ -1,6 +1,6 @@ -require 'active_support/log_subscriber' -require 'active_support/logger' -require 'active_support/notifications' +require "active_support/log_subscriber" +require "active_support/logger" +require "active_support/notifications" module ActiveSupport class LogSubscriber @@ -62,11 +62,11 @@ module ActiveSupport end def method_missing(level, message = nil) - if block_given? - @logged[level] << yield - else - @logged[level] << message - end + if block_given? + @logged[level] << yield + else + @logged[level] << message + end end def logged(level) diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb index 92b890dbb0..3ba6461b57 100644 --- a/activesupport/lib/active_support/logger.rb +++ b/activesupport/lib/active_support/logger.rb @@ -1,6 +1,6 @@ -require 'active_support/logger_silence' -require 'active_support/logger_thread_safe_level' -require 'logger' +require "active_support/logger_silence" +require "active_support/logger_thread_safe_level" +require "logger" module ActiveSupport class Logger < ::Logger diff --git a/activesupport/lib/active_support/logger_silence.rb b/activesupport/lib/active_support/logger_silence.rb index 3eb8098c77..632994cf50 100644 --- a/activesupport/lib/active_support/logger_silence.rb +++ b/activesupport/lib/active_support/logger_silence.rb @@ -1,6 +1,6 @@ -require 'active_support/concern' -require 'active_support/core_ext/module/attribute_accessors' -require 'concurrent' +require "active_support/concern" +require "active_support/core_ext/module/attribute_accessors" +require "concurrent" module LoggerSilence extend ActiveSupport::Concern diff --git a/activesupport/lib/active_support/logger_thread_safe_level.rb b/activesupport/lib/active_support/logger_thread_safe_level.rb index 5fedb5e689..7fb175dea6 100644 --- a/activesupport/lib/active_support/logger_thread_safe_level.rb +++ b/activesupport/lib/active_support/logger_thread_safe_level.rb @@ -1,4 +1,4 @@ -require 'active_support/concern' +require "active_support/concern" module ActiveSupport module LoggerThreadSafeLevel # :nodoc: diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb index 721efea789..7b33dc3481 100644 --- a/activesupport/lib/active_support/message_encryptor.rb +++ b/activesupport/lib/active_support/message_encryptor.rb @@ -1,6 +1,7 @@ -require 'openssl' -require 'base64' -require 'active_support/core_ext/array/extract_options' +require "openssl" +require "base64" +require "active_support/core_ext/array/extract_options" +require "active_support/message_verifier" module ActiveSupport # MessageEncryptor is a simple way to encrypt values which get stored @@ -18,6 +19,8 @@ module ActiveSupport # encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..." # crypt.decrypt_and_verify(encrypted_data) # => "my secret data" class MessageEncryptor + DEFAULT_CIPHER = "aes-256-cbc" + module NullSerializer #:nodoc: def self.load(value) value @@ -28,6 +31,16 @@ module ActiveSupport end end + module NullVerifier #:nodoc: + def self.verify(value) + value + end + + def self.generate(value) + value + end + end + class InvalidMessage < StandardError; end OpenSSLCipherError = OpenSSL::Cipher::CipherError @@ -40,15 +53,17 @@ module ActiveSupport # Options: # * <tt>:cipher</tt> - Cipher to use. Can be any cipher returned by # <tt>OpenSSL::Cipher.ciphers</tt>. Default is 'aes-256-cbc'. - # * <tt>:digest</tt> - String of digest to use for signing. Default is +SHA1+. + # * <tt>:digest</tt> - String of digest to use for signing. Default is + # +SHA1+. Ignored when using an AEAD cipher like 'aes-256-gcm'. # * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+. def initialize(secret, *signature_key_or_options) options = signature_key_or_options.extract_options! sign_secret = signature_key_or_options.first @secret = secret @sign_secret = sign_secret - @cipher = options[:cipher] || 'aes-256-cbc' - @verifier = MessageVerifier.new(@sign_secret || @secret, digest: options[:digest] || 'SHA1', serializer: NullSerializer) + @cipher = options[:cipher] || "aes-256-cbc" + @digest = options[:digest] || "SHA1" unless aead_mode? + @verifier = resolve_verifier @serializer = options[:serializer] || Marshal end @@ -64,44 +79,73 @@ module ActiveSupport _decrypt(verifier.verify(value)) end + # Given a cipher, returns the key length of the cipher to help generate the key of desired size + def self.key_len(cipher = DEFAULT_CIPHER) + OpenSSL::Cipher.new(cipher).key_len + end + private - def _encrypt(value) - cipher = new_cipher - cipher.encrypt - cipher.key = @secret + def _encrypt(value) + cipher = new_cipher + cipher.encrypt + cipher.key = @secret - # Rely on OpenSSL for the initialization vector - iv = cipher.random_iv + # Rely on OpenSSL for the initialization vector + iv = cipher.random_iv + cipher.auth_data = "" if aead_mode? - encrypted_data = cipher.update(@serializer.dump(value)) - encrypted_data << cipher.final + encrypted_data = cipher.update(@serializer.dump(value)) + encrypted_data << cipher.final - "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" - end - - def _decrypt(encrypted_message) - cipher = new_cipher - encrypted_data, iv = encrypted_message.split("--".freeze).map {|v| ::Base64.strict_decode64(v)} + blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" + blob << "--#{::Base64.strict_encode64 cipher.auth_tag}" if aead_mode? + blob + end - cipher.decrypt - cipher.key = @secret - cipher.iv = iv + def _decrypt(encrypted_message) + cipher = new_cipher + encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map { |v| ::Base64.strict_decode64(v) } + + # Currently the OpenSSL bindings do not raise an error if auth_tag is + # truncated, which would allow an attacker to easily forge it. See + # https://github.com/ruby/openssl/issues/63 + raise InvalidMessage if aead_mode? && auth_tag.bytes.length != 16 + + cipher.decrypt + cipher.key = @secret + cipher.iv = iv + if aead_mode? + cipher.auth_tag = auth_tag + cipher.auth_data = "" + end + + decrypted_data = cipher.update(encrypted_data) + decrypted_data << cipher.final + + @serializer.load(decrypted_data) + rescue OpenSSLCipherError, TypeError, ArgumentError + raise InvalidMessage + end - decrypted_data = cipher.update(encrypted_data) - decrypted_data << cipher.final + def new_cipher + OpenSSL::Cipher.new(@cipher) + end - @serializer.load(decrypted_data) - rescue OpenSSLCipherError, TypeError, ArgumentError - raise InvalidMessage - end + def verifier + @verifier + end - def new_cipher - OpenSSL::Cipher.new(@cipher) - end + def aead_mode? + @aead_mode ||= new_cipher.authenticated? + end - def verifier - @verifier - end + def resolve_verifier + if aead_mode? + NullVerifier + else + MessageVerifier.new(@sign_secret || @secret, digest: @digest, serializer: NullSerializer) + end + end end end diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index 4c3deffe6e..8419e858c6 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -1,6 +1,6 @@ -require 'base64' -require 'active_support/core_ext/object/blank' -require 'active_support/security_utils' +require "base64" +require "active_support/core_ext/object/blank" +require "active_support/security_utils" module ActiveSupport # +MessageVerifier+ makes it easy to generate and verify messages which are @@ -34,9 +34,9 @@ module ActiveSupport class InvalidSignature < StandardError; end def initialize(secret, options = {}) - raise ArgumentError, 'Secret should not be nil.' unless secret + raise ArgumentError, "Secret should not be nil." unless secret @secret = secret - @digest = options[:digest] || 'SHA1' + @digest = options[:digest] || "SHA1" @serializer = options[:serializer] || Marshal end @@ -83,7 +83,7 @@ module ActiveSupport data = signed_message.split("--".freeze)[0] @serializer.load(decode(data)) rescue ArgumentError => argument_error - return if argument_error.message =~ %r{invalid base64} + return if argument_error.message.include?("invalid base64") raise end end @@ -127,7 +127,7 @@ module ActiveSupport end def generate_digest(data) - require 'openssl' unless defined?(OpenSSL) + require "openssl" unless defined?(OpenSSL) OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data) end end diff --git a/activesupport/lib/active_support/multibyte.rb b/activesupport/lib/active_support/multibyte.rb index ffebd9a60b..f7c7befee0 100644 --- a/activesupport/lib/active_support/multibyte.rb +++ b/activesupport/lib/active_support/multibyte.rb @@ -1,7 +1,7 @@ module ActiveSupport #:nodoc: module Multibyte - autoload :Chars, 'active_support/multibyte/chars' - autoload :Unicode, 'active_support/multibyte/unicode' + autoload :Chars, "active_support/multibyte/chars" + autoload :Unicode, "active_support/multibyte/unicode" # The proxy class returned when calling mb_chars. You can use this accessor # to configure your own proxy class so you can support other encodings. See diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 707cf200b5..938e4ebb72 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -1,7 +1,8 @@ -require 'active_support/json' -require 'active_support/core_ext/string/access' -require 'active_support/core_ext/string/behavior' -require 'active_support/core_ext/module/delegation' +require "active_support/json" +require "active_support/core_ext/string/access" +require "active_support/core_ext/string/behavior" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/regexp" module ActiveSupport #:nodoc: module Multibyte #:nodoc: @@ -45,7 +46,7 @@ module ActiveSupport #:nodoc: alias to_s wrapped_string alias to_str wrapped_string - delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string + delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string # Creates a new Chars instance by wrapping _string_. def initialize(string) @@ -56,7 +57,7 @@ module ActiveSupport #:nodoc: # Forward all undefined methods to the wrapped string. def method_missing(method, *args, &block) result = @wrapped_string.__send__(method, *args, &block) - if method.to_s =~ /!$/ + if /!$/.match?(method) self if result else result.kind_of?(String) ? chars(result) : result @@ -105,7 +106,7 @@ module ActiveSupport #:nodoc: # # 'Café'.mb_chars.reverse.to_s # => 'éfaC' def reverse - chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*')) + chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack("U*")) end # Limits the byte size of the string to a number of bytes without breaking @@ -142,7 +143,7 @@ module ActiveSupport #:nodoc: # # 'über'.mb_chars.capitalize.to_s # => "Über" def capitalize - (slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase + (slice(0) || chars("")).upcase + (slice(1..-1) || chars("")).downcase end # Capitalizes the first letter of every word, when possible. @@ -150,7 +151,7 @@ module ActiveSupport #:nodoc: # "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró" # "日本語".mb_chars.titleize # => "日本語" def titleize - chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1)}) + chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1) }) end alias_method :titlecase, :titleize @@ -170,7 +171,7 @@ module ActiveSupport #:nodoc: # 'é'.length # => 2 # 'é'.mb_chars.decompose.to_s.length # => 3 def decompose - chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack('U*')) + chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*")) end # Performs composition on all the characters. @@ -178,7 +179,7 @@ module ActiveSupport #:nodoc: # 'é'.length # => 3 # 'é'.mb_chars.compose.to_s.length # => 2 def compose - chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack('U*')) + chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*")) end # Returns the number of grapheme clusters in the string. @@ -213,10 +214,10 @@ module ActiveSupport #:nodoc: def translate_offset(byte_offset) #:nodoc: return nil if byte_offset.nil? - return 0 if @wrapped_string == '' + return 0 if @wrapped_string == "" begin - @wrapped_string.byteslice(0...byte_offset).unpack('U*').length + @wrapped_string.byteslice(0...byte_offset).unpack("U*").length rescue ArgumentError byte_offset -= 1 retry diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb index 72b20fff06..217919ccb8 100644 --- a/activesupport/lib/active_support/multibyte/unicode.rb +++ b/activesupport/lib/active_support/multibyte/unicode.rb @@ -1,7 +1,6 @@ module ActiveSupport module Multibyte module Unicode - extend self # A list of all available normalization forms. @@ -10,7 +9,7 @@ module ActiveSupport NORMALIZATION_FORMS = [:c, :kc, :d, :kd] # The Unicode version that is supported by the implementation - UNICODE_VERSION = '8.0.0' + UNICODE_VERSION = "8.0.0" # The default normalization used for operations that require # normalization. It can be set to any of the normalizations @@ -31,36 +30,6 @@ module ActiveSupport HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT HANGUL_SCOUNT = 11172 HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT - HANGUL_JAMO_FIRST = 0x1100 - HANGUL_JAMO_LAST = 0x11FF - - # All the unicode whitespace - WHITESPACE = [ - (0x0009..0x000D).to_a, # White_Space # Cc [5] <control-0009>..<control-000D> - 0x0020, # White_Space # Zs SPACE - 0x0085, # White_Space # Cc <control-0085> - 0x00A0, # White_Space # Zs NO-BREAK SPACE - 0x1680, # White_Space # Zs OGHAM SPACE MARK - (0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE - 0x2028, # White_Space # Zl LINE SEPARATOR - 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR - 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE - 0x205F, # White_Space # Zs MEDIUM MATHEMATICAL SPACE - 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE - ].flatten.freeze - - # BOM (byte order mark) can also be seen as whitespace, it's a - # non-rendering character used to distinguish between little and big - # endian. This is not an issue in utf-8, so it must be ignored. - LEADERS_AND_TRAILERS = WHITESPACE + [65279] # ZERO-WIDTH NO-BREAK SPACE aka BOM - - # Returns a regular expression pattern that matches the passed Unicode - # codepoints. - def self.codepoints_to_pattern(array_of_codepoints) #:nodoc: - array_of_codepoints.collect{ |e| [e].pack 'U*'.freeze }.join('|'.freeze) - end - TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u - LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u # Detect whether the codepoint is in a certain character class. Returns # +true+ when it's in the specified character class and +false+ otherwise. @@ -90,25 +59,25 @@ module ActiveSupport should_break = # GB3. CR X LF - if previous == database.boundary[:cr] and current == database.boundary[:lf] + if previous == database.boundary[:cr] && current == database.boundary[:lf] false # GB4. (Control|CR|LF) ÷ - elsif previous and in_char_class?(previous, [:control,:cr,:lf]) + elsif previous && in_char_class?(previous, [:control,:cr,:lf]) true # GB5. ÷ (Control|CR|LF) elsif in_char_class?(current, [:control,:cr,:lf]) true # GB6. L X (L|V|LV|LVT) - elsif database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) + elsif database.boundary[:l] === previous && in_char_class?(current, [:l,:v,:lv,:lvt]) false # GB7. (LV|V) X (V|T) - elsif in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) + elsif in_char_class?(previous, [:lv,:v]) && in_char_class?(current, [:v,:t]) false # GB8. (LVT|T) X (T) - elsif in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current + elsif in_char_class?(previous, [:lvt,:t]) && database.boundary[:t] === current false # GB8a. Regional_Indicator X Regional_Indicator - elsif database.boundary[:regional_indicator] === previous and database.boundary[:regional_indicator] === current + elsif database.boundary[:regional_indicator] === previous && database.boundary[:regional_indicator] === current false # GB9. X Extend elsif database.boundary[:extend] === current @@ -136,7 +105,7 @@ module ActiveSupport # # Unicode.pack_graphemes(Unicode.unpack_graphemes('कà¥à¤·à¤¿')) # => 'कà¥à¤·à¤¿' def pack_graphemes(unpacked) - unpacked.flatten.pack('U*') + unpacked.flatten.pack("U*") end # Re-order codepoints so the string becomes canonical. @@ -159,7 +128,7 @@ module ActiveSupport def decompose(type, codepoints) codepoints.inject([]) do |decomposed, cp| # if it's a hangul syllable starter character - if HANGUL_SBASE <= cp and cp < HANGUL_SLAST + if HANGUL_SBASE <= cp && cp < HANGUL_SLAST sindex = cp - HANGUL_SBASE ncp = [] # new codepoints ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT @@ -168,7 +137,7 @@ module ActiveSupport ncp << (HANGUL_TBASE + tindex) unless tindex == 0 decomposed.concat ncp # if the codepoint is decomposable in with the current decomposition type - elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :compatibility) + elsif (ncp = database.codepoints[cp].decomp_mapping) && (!database.codepoints[cp].decomp_type || type == :compatibility) decomposed.concat decompose(type, ncp.dup) else decomposed << cp @@ -187,11 +156,11 @@ module ActiveSupport pos += 1 lindex = starter_char - HANGUL_LBASE # -- Hangul - if 0 <= lindex and lindex < HANGUL_LCOUNT + if 0 <= lindex && lindex < HANGUL_LCOUNT vindex = codepoints[starter_pos+1] - HANGUL_VBASE rescue vindex = -1 - if 0 <= vindex and vindex < HANGUL_VCOUNT + if 0 <= vindex && vindex < HANGUL_VCOUNT tindex = codepoints[starter_pos+2] - HANGUL_TBASE rescue tindex = -1 - if 0 <= tindex and tindex < HANGUL_TCOUNT + if 0 <= tindex && tindex < HANGUL_TCOUNT j = starter_pos + 2 eoa -= 2 else @@ -259,7 +228,7 @@ module ActiveSupport reader = Encoding::Converter.new(Encoding::UTF_8, Encoding::UTF_16LE) source = string.dup - out = ''.force_encoding(Encoding::UTF_16LE) + out = "".force_encoding(Encoding::UTF_16LE) loop do reader.primitive_convert(source, out) @@ -287,17 +256,17 @@ module ActiveSupport # See http://www.unicode.org/reports/tr15, Table 1 codepoints = string.codepoints.to_a case form - when :d - reorder_characters(decompose(:canonical, codepoints)) - when :c - compose(reorder_characters(decompose(:canonical, codepoints))) - when :kd - reorder_characters(decompose(:compatibility, codepoints)) - when :kc - compose(reorder_characters(decompose(:compatibility, codepoints))) + when :d + reorder_characters(decompose(:canonical, codepoints)) + when :c + compose(reorder_characters(decompose(:canonical, codepoints))) + when :kd + reorder_characters(decompose(:compatibility, codepoints)) + when :kc + compose(reorder_characters(decompose(:compatibility, codepoints))) else - raise ArgumentError, "#{form} is not a valid normalization variant", caller - end.pack('U*'.freeze) + raise ArgumentError, "#{form} is not a valid normalization variant", caller + end.pack("U*".freeze) end def downcase(string) @@ -356,7 +325,7 @@ module ActiveSupport # UnicodeDatabase. def load begin - @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read } + @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, "rb") { |f| Marshal.load f.read } rescue => e raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable") end @@ -378,7 +347,7 @@ module ActiveSupport # Returns the directory in which the data files are stored. def self.dirname - File.dirname(__FILE__) + '/../values/' + File.dirname(__FILE__) + "/../values/" end # Returns the filename for the data file for this version. @@ -389,25 +358,25 @@ module ActiveSupport private - def apply_mapping(string, mapping) #:nodoc: - database.codepoints - string.each_codepoint.map do |codepoint| - cp = database.codepoints[codepoint] - if cp and (ncp = cp.send(mapping)) and ncp > 0 - ncp - else - codepoint - end - end.pack('U*') - end + def apply_mapping(string, mapping) #:nodoc: + database.codepoints + string.each_codepoint.map do |codepoint| + cp = database.codepoints[codepoint] + if cp && (ncp = cp.send(mapping)) && ncp > 0 + ncp + else + codepoint + end + end.pack("U*") + end - def recode_windows1252_chars(string) - string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace) - end + def recode_windows1252_chars(string) + string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace) + end - def database - @database ||= UnicodeDatabase.new - end + def database + @database ||= UnicodeDatabase.new + end end end end diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 823d68e507..bae5f067ae 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -1,6 +1,6 @@ -require 'active_support/notifications/instrumenter' -require 'active_support/notifications/fanout' -require 'active_support/per_thread_registry' +require "active_support/notifications/instrumenter" +require "active_support/notifications/fanout" +require "active_support/per_thread_registry" module ActiveSupport # = Notifications diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index c53f9c1039..9da115f552 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -1,5 +1,5 @@ -require 'mutex_m' -require 'concurrent/map' +require "mutex_m" +require "concurrent/map" module ActiveSupport module Notifications @@ -68,7 +68,7 @@ module ActiveSupport module Subscribers # :nodoc: def self.new(pattern, listener) - if listener.respond_to?(:start) and listener.respond_to?(:finish) + if listener.respond_to?(:start) && listener.respond_to?(:finish) subscriber = Evented.new pattern, listener else subscriber = Timed.new pattern, listener diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb index 91f94cb2d7..23262d5398 100644 --- a/activesupport/lib/active_support/notifications/instrumenter.rb +++ b/activesupport/lib/active_support/notifications/instrumenter.rb @@ -1,4 +1,4 @@ -require 'securerandom' +require "securerandom" module ActiveSupport module Notifications @@ -44,9 +44,9 @@ module ActiveSupport private - def unique_id - SecureRandom.hex(10) - end + def unique_id + SecureRandom.hex(10) + end end class Event diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index 9d976f1831..c485a6af63 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -1,8 +1,8 @@ -require 'active_support/core_ext/big_decimal/conversions' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/hash/keys' -require 'active_support/i18n' -require 'active_support/core_ext/class/attribute' +require "active_support/core_ext/big_decimal/conversions" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/keys" +require "active_support/i18n" +require "active_support/core_ext/class/attribute" module ActiveSupport module NumberHelper @@ -169,7 +169,7 @@ module ActiveSupport end def default_value(key) - key.split('.').reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] } + key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] } end def valid_float? #:nodoc: diff --git a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb index 57f40f33bf..0f9dce722f 100644 --- a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/numeric/inquiry' +require "active_support/core_ext/numeric/inquiry" module ActiveSupport module NumberHelper @@ -15,13 +15,13 @@ module ActiveSupport end rounded_number = NumberToRoundedConverter.convert(number, options) - format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, options[:unit]) + format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, options[:unit]) end private def absolute_value(number) - number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, '') + number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "") end def options diff --git a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb index 43c5540b6f..e3b35531b1 100644 --- a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb @@ -12,7 +12,7 @@ module ActiveSupport private def parts - left, right = number.to_s.split('.'.freeze) + left, right = number.to_s.split(".".freeze) left.gsub!(delimiter_pattern) do |digit_to_delimit| "#{digit_to_delimit}#{options[:delimiter]}" end @@ -22,7 +22,6 @@ module ActiveSupport def delimiter_pattern options.fetch(:delimiter_pattern, DEFAULT_DELIMITER_REGEX) end - end end end diff --git a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb index 7a1f8171c0..695ee1dad3 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb @@ -25,22 +25,22 @@ module ActiveSupport exponent += 3 end unit = determine_unit(units, exponent) - format.gsub('%n'.freeze, rounded_number).gsub('%u'.freeze, unit).strip + format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, unit).strip end private def format - options[:format] || translate_in_locale('human.decimal_units.format') + options[:format] || translate_in_locale("human.decimal_units.format") end def determine_unit(units, exponent) exp = DECIMAL_UNITS[exponent] case units when Hash - units[exp] || '' + units[exp] || "" when String, Symbol - I18n.translate("#{units}.#{exp}", :locale => options[:locale], :count => number.to_i) + I18n.translate("#{units}.#{exp}", locale: options[:locale], count: number.to_i) else translate_in_locale("human.decimal_units.units.#{exp}", count: number.to_i) end @@ -56,7 +56,7 @@ module ActiveSupport when Hash units when String, Symbol - I18n.translate(units.to_s, :locale => options[:locale], :raise => true) + I18n.translate(units.to_s, locale: options[:locale], raise: true) when nil translate_in_locale("human.decimal_units.units", raise: true) else diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb index a83b368b7f..78cb33aa62 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb @@ -8,7 +8,7 @@ module ActiveSupport def convert if opts.key?(:prefix) - ActiveSupport::Deprecation.warn('The :prefix option of `number_to_human_size` is deprecated and will be removed in Rails 5.1 with no replacement.') + ActiveSupport::Deprecation.warn("The :prefix option of `number_to_human_size` is deprecated and will be removed in Rails 5.1 with no replacement.") end @number = Float(number) @@ -24,21 +24,21 @@ module ActiveSupport human_size = number / (base ** exponent) number_to_format = NumberToRoundedConverter.convert(human_size, options) end - conversion_format.gsub('%n'.freeze, number_to_format).gsub('%u'.freeze, unit) + conversion_format.gsub("%n".freeze, number_to_format).gsub("%u".freeze, unit) end private def conversion_format - translate_number_value_with_default('human.storage_units.format', :locale => options[:locale], :raise => true) + translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true) end def unit - translate_number_value_with_default(storage_unit_key, :locale => options[:locale], :count => number.to_i, :raise => true) + translate_number_value_with_default(storage_unit_key, locale: options[:locale], count: number.to_i, raise: true) end def storage_unit_key - key_end = smaller_than_base? ? 'byte' : STORAGE_UNITS[exponent] + key_end = smaller_than_base? ? "byte" : STORAGE_UNITS[exponent] "human.storage_units.units.#{key_end}" end @@ -59,4 +59,3 @@ module ActiveSupport end end end - diff --git a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb index 4c04d40c19..ac647ca9b7 100644 --- a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb @@ -5,7 +5,7 @@ module ActiveSupport def convert rounded_number = NumberToRoundedConverter.convert(number, options) - options[:format].gsub('%n'.freeze, rounded_number) + options[:format].gsub("%n".freeze, rounded_number) end end end diff --git a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb index dee74fa7a6..c2612f9a9b 100644 --- a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb @@ -51,8 +51,6 @@ module ActiveSupport def regexp_pattern(default_pattern) opts.fetch :pattern, default_pattern end - end end end - diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb index 9fb7dfb779..cfcb0045fb 100644 --- a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb @@ -29,10 +29,10 @@ module ActiveSupport formatted_string = if BigDecimal === rounded_number && rounded_number.finite? - s = rounded_number.to_s('F') - s << '0'.freeze * precision - a, b = s.split('.'.freeze, 2) - a << '.'.freeze + s = rounded_number.to_s("F") + s << "0".freeze * precision + a, b = s.split(".".freeze, 2) + a << ".".freeze a << b[0, precision] else "%00.#{precision}f" % rounded_number @@ -74,7 +74,7 @@ module ActiveSupport def format_number(number) if strip_insignificant_zeros escaped_separator = Regexp.escape(options[:separator]) - number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') + number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, "") else number end diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb index dea84e437f..0f2caa98f2 100644 --- a/activesupport/lib/active_support/option_merger.rb +++ b/activesupport/lib/active_support/option_merger.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/hash/deep_merge' +require "active_support/core_ext/hash/deep_merge" module ActiveSupport class OptionMerger #:nodoc: diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index b1658f0f27..793bc9e22d 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -1,7 +1,7 @@ -require 'yaml' +require "yaml" YAML.add_builtin_type("omap") do |type, val| - ActiveSupport::OrderedHash[val.map{ |v| v.to_a.first }] + ActiveSupport::OrderedHash[val.map { |v| v.to_a.first }] end module ActiveSupport @@ -25,7 +25,7 @@ module ActiveSupport end def encode_with(coder) - coder.represent_seq '!omap', map { |k,v| { k => v } } + coder.represent_seq "!omap", map { |k,v| { k => v } } end def select(*args, &block) diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index 501ba7fc76..14ed9049be 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/blank' +require "active_support/core_ext/object/blank" module ActiveSupport # Usually key value pairs are handled something like this: @@ -38,10 +38,10 @@ module ActiveSupport def method_missing(name, *args) name_string = name.to_s - if name_string.chomp!('=') + if name_string.chomp!("=") self[name_string] = args.first else - bangs = name_string.chomp!('!') + bangs = name_string.chomp!("!") if bangs fetch(name_string.to_sym).presence || raise(KeyError.new("#{name_string} is blank.")) diff --git a/activesupport/lib/active_support/per_thread_registry.rb b/activesupport/lib/active_support/per_thread_registry.rb index 88e2b12cc7..9e6d8d4fd8 100644 --- a/activesupport/lib/active_support/per_thread_registry.rb +++ b/activesupport/lib/active_support/per_thread_registry.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/module/delegation" module ActiveSupport - # NOTE: This approach has been deprecated for end-user code in favor of thread_mattr_accessor and friends. + # NOTE: This approach has been deprecated for end-user code in favor of {thread_mattr_accessor}[rdoc-ref:Module#thread_mattr_accessor] and friends. # Please use that approach instead. # # This module is used to encapsulate access to thread local variables. @@ -38,7 +38,7 @@ module ActiveSupport # If the class has an initializer, it must accept no arguments. module PerThreadRegistry def self.extended(object) - object.instance_variable_set '@per_thread_registry_key', object.name.freeze + object.instance_variable_set "@per_thread_registry_key", object.name.freeze end def instance diff --git a/activesupport/lib/active_support/rails.rb b/activesupport/lib/active_support/rails.rb index c8e3a4bf53..57380061f7 100644 --- a/activesupport/lib/active_support/rails.rb +++ b/activesupport/lib/active_support/rails.rb @@ -9,19 +9,19 @@ # Rails and can change anytime. # Defines Object#blank? and Object#present?. -require 'active_support/core_ext/object/blank' +require "active_support/core_ext/object/blank" # Rails own autoload, eager_load, etc. -require 'active_support/dependencies/autoload' +require "active_support/dependencies/autoload" # Support for ClassMethods and the included macro. -require 'active_support/concern' +require "active_support/concern" # Defines Class#class_attribute. -require 'active_support/core_ext/class/attribute' +require "active_support/core_ext/class/attribute" # Defines Module#delegate. -require 'active_support/core_ext/module/delegation' +require "active_support/core_ext/module/delegation" # Defines ActiveSupport::Deprecation. -require 'active_support/deprecation' +require "active_support/deprecation" diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 845788b669..b875875afe 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -21,11 +21,11 @@ module ActiveSupport rescue TZInfo::DataSourceNotFound => e raise e.exception "tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install" end - require 'active_support/core_ext/time/zones' + require "active_support/core_ext/time/zones" zone_default = Time.find_zone!(app.config.time_zone) unless zone_default - raise 'Value assigned to config.time_zone not recognized. ' \ + raise "Value assigned to config.time_zone not recognized. " \ 'Run "rake time:zones:all" for a time zone names list.' end @@ -35,7 +35,7 @@ module ActiveSupport # Sets the default week start # If assigned value is not a valid day symbol (e.g. :sunday, :monday, ...), an exception will be raised. initializer "active_support.initialize_beginning_of_week" do |app| - require 'active_support/core_ext/date/calculations' + require "active_support/core_ext/date/calculations" beginning_of_week_default = Date.find_beginning_of_week!(app.config.beginning_of_week) Date.beginning_of_week_default = beginning_of_week_default diff --git a/activesupport/lib/active_support/reloader.rb b/activesupport/lib/active_support/reloader.rb index 5623bdd349..121c621751 100644 --- a/activesupport/lib/active_support/reloader.rb +++ b/activesupport/lib/active_support/reloader.rb @@ -1,4 +1,4 @@ -require 'active_support/execution_wrapper' +require "active_support/execution_wrapper" module ActiveSupport #-- diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index 2c05deee41..dc3f27a16d 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -1,6 +1,6 @@ -require 'active_support/concern' -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/string/inflections' +require "active_support/concern" +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/string/inflections" module ActiveSupport # Rescuable module adds support for easier exception handling. @@ -52,7 +52,7 @@ module ActiveSupport if block_given? with = block else - raise ArgumentError, 'Need a handler. Pass the with: keyword argument or provide a block.' + raise ArgumentError, "Need a handler. Pass the with: keyword argument or provide a block." end end diff --git a/activesupport/lib/active_support/security_utils.rb b/activesupport/lib/active_support/security_utils.rb index 9be8613ada..b655d64449 100644 --- a/activesupport/lib/active_support/security_utils.rb +++ b/activesupport/lib/active_support/security_utils.rb @@ -1,4 +1,4 @@ -require 'digest' +require "digest" module ActiveSupport module SecurityUtils diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb index bc673150d0..09e1cbb28d 100644 --- a/activesupport/lib/active_support/string_inquirer.rb +++ b/activesupport/lib/active_support/string_inquirer.rb @@ -8,15 +8,21 @@ module ActiveSupport # you can call this: # # Rails.env.production? + # + # == Instantiating a new StringInquirer + # + # vehicle = ActiveSupport::StringInquirer.new('car') + # vehicle.car? # => true + # vehicle.bike? # => false class StringInquirer < String private def respond_to_missing?(method_name, include_private = false) - method_name[-1] == '?' + method_name[-1] == "?" end def method_missing(method_name, *arguments) - if method_name[-1] == '?' + if method_name[-1] == "?" self == method_name[0..-2] else super diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb index 1cd4b807ad..0f09f1eb63 100644 --- a/activesupport/lib/active_support/subscriber.rb +++ b/activesupport/lib/active_support/subscriber.rb @@ -1,4 +1,4 @@ -require 'active_support/per_thread_registry' +require "active_support/per_thread_registry" module ActiveSupport # ActiveSupport::Subscriber is an object set to consume @@ -23,7 +23,6 @@ module ActiveSupport # the +sql+ method. class Subscriber class << self - # Attach the subscriber to a namespace. def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications) @namespace = namespace @@ -91,7 +90,7 @@ module ActiveSupport event.end = finished event.payload.merge!(payload) - method = name.split('.'.freeze).first + method = name.split(".".freeze).first send(method, event) end diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb index bcd7bf74c0..6836378943 100644 --- a/activesupport/lib/active_support/tagged_logging.rb +++ b/activesupport/lib/active_support/tagged_logging.rb @@ -1,7 +1,7 @@ -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/object/blank' -require 'logger' -require 'active_support/logger' +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/object/blank" +require "logger" +require "active_support/logger" module ActiveSupport # Wraps any standard Logger object to provide tagging capabilities. diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index 221e1171e7..3de4ccc1da 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -1,15 +1,15 @@ -gem 'minitest' # make sure we get the gem, not stdlib -require 'minitest' -require 'active_support/testing/tagged_logging' -require 'active_support/testing/setup_and_teardown' -require 'active_support/testing/assertions' -require 'active_support/testing/deprecation' -require 'active_support/testing/declarative' -require 'active_support/testing/isolation' -require 'active_support/testing/constant_lookup' -require 'active_support/testing/time_helpers' -require 'active_support/testing/file_fixtures' -require 'active_support/core_ext/kernel/reporting' +gem "minitest" # make sure we get the gem, not stdlib +require "minitest" +require "active_support/testing/tagged_logging" +require "active_support/testing/setup_and_teardown" +require "active_support/testing/assertions" +require "active_support/testing/deprecation" +require "active_support/testing/declarative" +require "active_support/testing/isolation" +require "active_support/testing/constant_lookup" +require "active_support/testing/time_helpers" +require "active_support/testing/file_fixtures" +require "active_support/core_ext/kernel/reporting" module ActiveSupport class TestCase < ::Minitest::Test @@ -66,16 +66,6 @@ module ActiveSupport alias :assert_not_respond_to :refute_respond_to alias :assert_not_same :refute_same - - # Assertion that the block should not raise an exception. - # - # Passes if evaluated code in the yielded block raises no exception. - # - # assert_nothing_raised do - # perform_service(param: 'no_exception') - # end - def assert_nothing_raised - yield - end + ActiveSupport.run_load_hooks(:active_support_test_case, self) end end diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index ad83638572..28cf2953bf 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -1,6 +1,8 @@ module ActiveSupport module Testing module Assertions + UNTRACKED = Object.new # :nodoc: + # Asserts that an expression is not truthy. Passes if <tt>object</tt> is # +nil+ or +false+. "Truthy" means "considered true in a conditional" # like <tt>if foo</tt>. @@ -17,6 +19,17 @@ module ActiveSupport assert !object, message end + # Assertion that the block should not raise an exception. + # + # Passes if evaluated code in the yielded block raises no exception. + # + # assert_nothing_raised do + # perform_service(param: 'no_exception') + # end + def assert_nothing_raised + yield + end + # Test numeric difference between the return value of an expression as a # result of what is evaluated in the yielded block. # @@ -92,6 +105,93 @@ module ActiveSupport def assert_no_difference(expression, message = nil, &block) assert_difference expression, 0, message, &block end + + # Assertion that the result of evaluating an expression is changed before + # and after invoking the passed in block. + # + # assert_changes 'Status.all_good?' do + # post :create, params: { status: { ok: false } } + # end + # + # You can pass the block as a string to be evaluated in the context of + # the block. A lambda can be passed for the block as well. + # + # assert_changes -> { Status.all_good? } do + # post :create, params: { status: { ok: false } } + # end + # + # The assertion is useful to test side effects. The passed block can be + # anything that can be converted to string with #to_s. + # + # assert_changes :@object do + # @object = 42 + # end + # + # The keyword arguments :from and :to can be given to specify the + # expected initial value and the expected value after the block was + # executed. + # + # assert_changes :@object, from: nil, to: :foo do + # @object = :foo + # end + # + # An error message can be specified. + # + # assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do + # post :create, params: { status: { incident: true } } + # end + def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block) + exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } + + before = exp.call + retval = yield + + unless from == UNTRACKED + error = "#{expression.inspect} isn't #{from.inspect}" + error = "#{message}.\n#{error}" if message + assert from === before, error + end + + after = exp.call + + if to == UNTRACKED + error = "#{expression.inspect} didn't changed" + error = "#{message}.\n#{error}" if message + assert_not_equal before, after, error + else + error = "#{expression.inspect} didn't change to #{to}" + error = "#{message}.\n#{error}" if message + assert to === after, error + end + + retval + end + + # Assertion that the result of evaluating an expression is changed before + # and after invoking the passed in block. + # + # assert_no_changes 'Status.all_good?' do + # post :create, params: { status: { ok: true } } + # end + # + # An error message can be specified. + # + # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do + # post :create, params: { status: { ok: false } } + # end + def assert_no_changes(expression, message = nil, &block) + exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } + + before = exp.call + retval = yield + after = exp.call + + error = "#{expression.inspect} did change to #{after}" + error = "#{message}.\n#{error}" if message + assert_equal before, after, error + + retval + end end end end diff --git a/activesupport/lib/active_support/testing/autorun.rb b/activesupport/lib/active_support/testing/autorun.rb index 84c6b89340..3108e3e549 100644 --- a/activesupport/lib/active_support/testing/autorun.rb +++ b/activesupport/lib/active_support/testing/autorun.rb @@ -1,12 +1,9 @@ -gem 'minitest' +gem "minitest" -require 'minitest' +require "minitest" -if Minitest.respond_to?(:run_with_rails_extension) - unless Minitest.run_with_rails_extension - Minitest.run_with_autorun = true - Minitest.autorun - end -else - Minitest.autorun +if Minitest.respond_to?(:run_via) && !Minitest.run_via[:rails] + Minitest.run_via[:ruby] = true end + +Minitest.autorun diff --git a/activesupport/lib/active_support/testing/constant_lookup.rb b/activesupport/lib/active_support/testing/constant_lookup.rb index 07d477c0db..647395d2b3 100644 --- a/activesupport/lib/active_support/testing/constant_lookup.rb +++ b/activesupport/lib/active_support/testing/constant_lookup.rb @@ -44,7 +44,6 @@ module ActiveSupport end end end - end end end diff --git a/activesupport/lib/active_support/testing/deprecation.rb b/activesupport/lib/active_support/testing/deprecation.rb index 5dfa14eeba..58911570e8 100644 --- a/activesupport/lib/active_support/testing/deprecation.rb +++ b/activesupport/lib/active_support/testing/deprecation.rb @@ -1,4 +1,5 @@ -require 'active_support/deprecation' +require "active_support/deprecation" +require "active_support/core_ext/regexp" module ActiveSupport module Testing @@ -8,7 +9,7 @@ module ActiveSupport assert !warnings.empty?, "Expected a deprecation warning within the block but received none" if match match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp) - assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}" + assert warnings.any? { |w| match.match?(w) }, "No deprecation warning matched #{match}: #{warnings.join(', ')}" end result end diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index 7dd03ce65d..d30b34ecd6 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -1,7 +1,7 @@ module ActiveSupport module Testing module Isolation - require 'thread' + require "thread" def self.included(klass) #:nodoc: klass.class_eval do @@ -68,17 +68,17 @@ module ActiveSupport if ENV["ISOLATION_TEST"] yield File.open(ENV["ISOLATION_OUTPUT"], "w") do |file| - file.puts [Marshal.dump(self.dup)].pack("m") + file.puts [Marshal.dump(dup)].pack("m") end exit! else Tempfile.open("isolation") do |tmpfile| env = { - 'ISOLATION_TEST' => self.class.name, - 'ISOLATION_OUTPUT' => tmpfile.path + "ISOLATION_TEST" => self.class.name, + "ISOLATION_OUTPUT" => tmpfile.path } - load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ") + load_paths = $-I.map { |p| "-I\"#{File.expand_path(p)}\"" }.join(" ") orig_args = ORIG_ARGV.join(" ") test_opts = "-n#{self.class.name}##{self.name}" command = "#{Gem.ruby} #{load_paths} #{$0} '#{orig_args}' #{test_opts}" diff --git a/activesupport/lib/active_support/testing/method_call_assertions.rb b/activesupport/lib/active_support/testing/method_call_assertions.rb index fccaa54f40..6b07416fdc 100644 --- a/activesupport/lib/active_support/testing/method_call_assertions.rb +++ b/activesupport/lib/active_support/testing/method_call_assertions.rb @@ -1,4 +1,4 @@ -require 'minitest/mock' +require "minitest/mock" module ActiveSupport module Testing diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index 33f2b8dc9b..358c79c321 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,5 +1,5 @@ -require 'active_support/concern' -require 'active_support/callbacks' +require "active_support/concern" +require "active_support/callbacks" module ActiveSupport module Testing diff --git a/activesupport/lib/active_support/testing/stream.rb b/activesupport/lib/active_support/testing/stream.rb index 895192ad05..1d06b94559 100644 --- a/activesupport/lib/active_support/testing/stream.rb +++ b/activesupport/lib/active_support/testing/stream.rb @@ -3,40 +3,40 @@ module ActiveSupport module Stream #:nodoc: private - def silence_stream(stream) - old_stream = stream.dup - stream.reopen(IO::NULL) - stream.sync = true - yield - ensure - stream.reopen(old_stream) - old_stream.close - end + def silence_stream(stream) + old_stream = stream.dup + stream.reopen(IO::NULL) + stream.sync = true + yield + ensure + stream.reopen(old_stream) + old_stream.close + end - def quietly - silence_stream(STDOUT) do - silence_stream(STDERR) do - yield + def quietly + silence_stream(STDOUT) do + silence_stream(STDERR) do + yield + end end end - end - def capture(stream) - stream = stream.to_s - captured_stream = Tempfile.new(stream) - stream_io = eval("$#{stream}") - origin_stream = stream_io.dup - stream_io.reopen(captured_stream) + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) - yield + yield - stream_io.rewind - return captured_stream.read - ensure - captured_stream.close - captured_stream.unlink - stream_io.reopen(origin_stream) - end + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) + end end end end diff --git a/activesupport/lib/active_support/testing/tagged_logging.rb b/activesupport/lib/active_support/testing/tagged_logging.rb index 843ce4a867..afdff87b45 100644 --- a/activesupport/lib/active_support/testing/tagged_logging.rb +++ b/activesupport/lib/active_support/testing/tagged_logging.rb @@ -8,7 +8,7 @@ module ActiveSupport def before_setup if tagged_logger && tagged_logger.info? heading = "#{self.class}: #{name}" - divider = '-' * heading.size + divider = "-" * heading.size tagged_logger.info divider tagged_logger.info heading tagged_logger.info divider diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb index fca0947c5b..e2f008b4b7 100644 --- a/activesupport/lib/active_support/testing/time_helpers.rb +++ b/activesupport/lib/active_support/testing/time_helpers.rb @@ -1,32 +1,39 @@ +require "active_support/core_ext/string/strip" # for strip_heredoc +require "concurrent/map" + module ActiveSupport module Testing class SimpleStubs # :nodoc: Stub = Struct.new(:object, :method_name, :original_method) def initialize - @stubs = {} + @stubs = Concurrent::Map.new { |h, k| h[k] = {} } end def stub_object(object, method_name, return_value) - key = [object.object_id, method_name] - - if stub = @stubs[key] + if stub = stubbing(object, method_name) unstub_object(stub) end new_name = "__simple_stub__#{method_name}" - @stubs[key] = Stub.new(object, method_name, new_name) + @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name) object.singleton_class.send :alias_method, new_name, method_name object.define_singleton_method(method_name) { return_value } end def unstub_all! - @stubs.each_value do |stub| - unstub_object(stub) + @stubs.each_value do |object_stubs| + object_stubs.each_value do |stub| + unstub_object(stub) + end end - @stubs = {} + @stubs.clear + end + + def stubbing(object, method_name) + @stubs[object.object_id][method_name] end private @@ -66,7 +73,7 @@ module ActiveSupport # +Date.today+, and +DateTime.now+ to return the time or date passed into this method. # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 - # travel_to Time.new(2004, 11, 24, 01, 04, 44) + # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 # Date.current # => Wed, 24 Nov 2004 # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500 @@ -88,11 +95,39 @@ module ActiveSupport # state at the end of the block: # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 - # travel_to Time.new(2004, 11, 24, 01, 04, 44) do + # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 # end # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 def travel_to(date_or_time) + if block_given? && simple_stubs.stubbing(Time, :now) + travel_to_nested_block_call = <<-MSG.strip_heredoc + + Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing. + + Instead of: + + travel_to 2.days.from_now do + # 2 days from today + travel_to 3.days.from_now do + # 5 days from today + end + end + + preferred way to achieve above is: + + travel 2.days do + # 2 days from today + end + + travel 5.days do + # 5 days from today + end + + MSG + raise travel_to_nested_block_call + end + if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime) now = date_or_time.midnight.to_time else @@ -116,7 +151,7 @@ module ActiveSupport # `travel` and `travel_to`. # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 - # travel_to Time.new(2004, 11, 24, 01, 04, 44) + # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00 # travel_back # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 diff --git a/activesupport/lib/active_support/time.rb b/activesupport/lib/active_support/time.rb index ea2d3391bd..7658228ca6 100644 --- a/activesupport/lib/active_support/time.rb +++ b/activesupport/lib/active_support/time.rb @@ -1,18 +1,18 @@ module ActiveSupport - autoload :Duration, 'active_support/duration' - autoload :TimeWithZone, 'active_support/time_with_zone' - autoload :TimeZone, 'active_support/values/time_zone' + autoload :Duration, "active_support/duration" + autoload :TimeWithZone, "active_support/time_with_zone" + autoload :TimeZone, "active_support/values/time_zone" end -require 'date' -require 'time' +require "date" +require "time" -require 'active_support/core_ext/time' -require 'active_support/core_ext/date' -require 'active_support/core_ext/date_time' +require "active_support/core_ext/time" +require "active_support/core_ext/date" +require "active_support/core_ext/date_time" -require 'active_support/core_ext/integer/time' -require 'active_support/core_ext/numeric/time' +require "active_support/core_ext/integer/time" +require "active_support/core_ext/numeric/time" -require 'active_support/core_ext/string/conversions' -require 'active_support/core_ext/string/zones' +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/string/zones" diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index b1cec43124..889f71c4f3 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -1,7 +1,7 @@ -require 'active_support/duration' -require 'active_support/values/time_zone' -require 'active_support/core_ext/object/acts_like' -require 'active_support/core_ext/date_and_time/compatibility' +require "active_support/duration" +require "active_support/values/time_zone" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/date_and_time/compatibility" module ActiveSupport # A Time-like class that can represent a time in any time zone. Necessary @@ -36,14 +36,13 @@ module ActiveSupport # t.is_a?(Time) # => true # t.is_a?(ActiveSupport::TimeWithZone) # => true class TimeWithZone - # Report class name as 'Time' to thwart type checking. def self.name - 'Time' + "Time" end PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N".freeze } - PRECISIONS[0] = '%FT%T'.freeze + PRECISIONS[0] = "%FT%T".freeze include Comparable, DateAndTime::Compatibility attr_reader :time_zone @@ -134,7 +133,7 @@ module ActiveSupport period.zone_identifier.to_s end - # Returns a string of the object's date, time, zone and offset from UTC. + # Returns a string of the object's date, time, zone, and offset from UTC. # # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00" def inspect @@ -171,12 +170,12 @@ module ActiveSupport end def init_with(coder) #:nodoc: - initialize(coder['utc'], coder['zone'], coder['time']) + initialize(coder["utc"], coder["zone"], coder["time"]) end def encode_with(coder) #:nodoc: - coder.tag = '!ruby/object:ActiveSupport::TimeWithZone' - coder.map = { 'utc' => utc, 'zone' => time_zone, 'time' => time } + coder.tag = "!ruby/object:ActiveSupport::TimeWithZone" + coder.map = { "utc" => utc, "zone" => time_zone, "time" => time } end # Returns a string of the object's date and time in the format used by @@ -280,6 +279,7 @@ module ActiveSupport end end alias_method :since, :+ + alias_method :in, :+ # Returns a new TimeWithZone object that represents the difference between # the current object's time and the +other+ time. @@ -407,7 +407,7 @@ module ActiveSupport # Time.zone.now.to_datetime # => Tue, 18 Aug 2015 02:32:20 +0000 # Time.current.in_time_zone('Hawaii').to_datetime # => Mon, 17 Aug 2015 16:32:20 -1000 def to_datetime - utc.to_datetime.new_offset(Rational(utc_offset, 86_400)) + @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400)) end # So that +self+ <tt>acts_like?(:time)</tt>. @@ -459,7 +459,7 @@ module ActiveSupport def method_missing(sym, *args, &block) wrap_with_time_zone time.__send__(sym, *args, &block) rescue NoMethodError => e - raise e, e.message.sub(time.inspect, self.inspect), e.backtrace + raise e, e.message.sub(time.inspect, inspect), e.backtrace end private @@ -477,11 +477,13 @@ module ActiveSupport end def transfer_time_values_to_utc_constructor(time) + # avoid creating another Time object if possible + return time if time.instance_of?(::Time) && time.utc? ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec) end def duration_of_variable_length?(obj) - ActiveSupport::Duration === obj && obj.parts.any? {|p| [:years, :months, :days].include?(p[0]) } + ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) } end def wrap_with_time_zone(time) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 19420cee5e..a562f33420 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,6 +1,6 @@ -require 'tzinfo' -require 'concurrent/map' -require 'active_support/core_ext/object/blank' +require "tzinfo" +require "concurrent/map" +require "active_support/core_ext/object/blank" module ActiveSupport # The TimeZone class serves as a wrapper around TZInfo::Timezone instances. @@ -180,8 +180,8 @@ module ActiveSupport "Samoa" => "Pacific/Apia" } - UTC_OFFSET_WITH_COLON = '%s%02d:%02d' - UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(':', '') + UTC_OFFSET_WITH_COLON = "%s%02d:%02d" + UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(":", "") @lazy_zones_map = Concurrent::Map.new @country_zones = Concurrent::Map.new @@ -193,7 +193,7 @@ module ActiveSupport # ActiveSupport::TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00" def seconds_to_utc_offset(seconds, colon = true) format = colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON - sign = (seconds < 0 ? '-' : '+') + sign = (seconds < 0 ? "-" : "+") hours = seconds.abs / 3600 minutes = (seconds.abs % 3600) / 60 format % [sign, hours, minutes] @@ -226,17 +226,17 @@ module ActiveSupport # Returns +nil+ if no such time zone is known to the system. def [](arg) case arg - when String + when String begin @lazy_zones_map[arg] ||= create(arg) rescue TZInfo::InvalidTimezoneIdentifier nil end - when Numeric, ActiveSupport::Duration - arg *= 3600 if arg.abs <= 13 - all.find { |z| z.utc_offset == arg.to_i } + when Numeric, ActiveSupport::Duration + arg *= 3600 if arg.abs <= 13 + all.find { |z| z.utc_offset == arg.to_i } else - raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}" + raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}" end end @@ -260,7 +260,7 @@ module ActiveSupport private def zones_map @zones_map ||= begin - MAPPING.each_key {|place| self[place]} # load all the zones + MAPPING.each_key { |place| self[place] } # load all the zones @lazy_zones_map end end @@ -437,29 +437,34 @@ module ActiveSupport end def init_with(coder) #:nodoc: - initialize(coder['name']) + initialize(coder["name"]) end def encode_with(coder) #:nodoc: coder.tag ="!ruby/object:#{self.class}" - coder.map = { 'name' => tzinfo.name } + coder.map = { "name" => tzinfo.name } end private def parts_to_time(parts, now) + raise ArgumentError, "invalid date" if parts.nil? return if parts.empty? - time = Time.new( - parts.fetch(:year, now.year), - parts.fetch(:mon, now.month), - parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day), - parts.fetch(:hour, 0), - parts.fetch(:min, 0), - parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0), - parts.fetch(:offset, 0) - ) - - if parts[:offset] + if parts[:seconds] + time = Time.at(parts[:seconds]) + else + time = Time.new( + parts.fetch(:year, now.year), + parts.fetch(:mon, now.month), + parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day), + parts.fetch(:hour, 0), + parts.fetch(:min, 0), + parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0), + parts.fetch(:offset, 0) + ) + end + + if parts[:offset] || parts[:seconds] TimeWithZone.new(time.utc, self) else TimeWithZone.new(nil, self, time) diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb index fe03984546..20b91ac911 100644 --- a/activesupport/lib/active_support/version.rb +++ b/activesupport/lib/active_support/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module ActiveSupport # Returns the version of the currently loaded ActiveSupport as a <tt>Gem::Version</tt> diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index 99fc26549e..921a3447d0 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -1,9 +1,9 @@ -require 'time' -require 'base64' -require 'bigdecimal' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/string/inflections' -require 'active_support/core_ext/date_time/calculations' +require "time" +require "base64" +require "bigdecimal" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/date_time/calculations" module ActiveSupport # = XmlMini @@ -20,11 +20,11 @@ module ActiveSupport attr_writer :original_filename, :content_type def original_filename - @original_filename || 'untitled' + @original_filename || "untitled" end def content_type - @content_type || 'application/octet-stream' + @content_type || "application/octet-stream" end end @@ -48,8 +48,8 @@ module ActiveSupport } # No need to map these on Ruby 2.4+ - TYPE_NAMES["Fixnum"] = "integer" unless Fixnum == Integer - TYPE_NAMES["Bignum"] = "integer" unless Bignum == Integer + TYPE_NAMES["Fixnum"] = "integer" unless 0.class == Integer + TYPE_NAMES["Bignum"] = "integer" unless 0.class == Integer end FORMATTING = { @@ -86,7 +86,7 @@ module ActiveSupport attr_accessor :depth self.depth = 100 - delegate :parse, :to => :backend + delegate :parse, to: :backend def backend current_thread_backend || @backend @@ -108,7 +108,7 @@ module ActiveSupport def to_tag(key, value, options) type_name = options.delete(:type) - merged_options = options.merge(:root => key, :skip_instruct => true) + merged_options = options.merge(root: key, skip_instruct: true) if value.is_a?(::Method) || value.is_a?(::Proc) if value.arity == 1 @@ -126,7 +126,7 @@ module ActiveSupport key = rename_key(key.to_s, options) - attributes = options[:skip_types] || type_name.nil? ? { } : { :type => type_name } + attributes = options[:skip_types] || type_name.nil? ? {} : { type: type_name } attributes[:nil] = true if value.nil? encoding = options[:encoding] || DEFAULT_ENCODINGS[type_name] @@ -151,29 +151,29 @@ module ActiveSupport protected - def _dasherize(key) - # $2 must be a non-greedy regex for this to work - left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1,3] - "#{left}#{middle.tr('_ ', '--')}#{right}" - end + def _dasherize(key) + # $2 must be a non-greedy regex for this to work + left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1,3] + "#{left}#{middle.tr('_ ', '--')}#{right}" + end - # TODO: Add support for other encodings - def _parse_binary(bin, entity) #:nodoc: - case entity['encoding'] - when 'base64' - ::Base64.decode64(bin) - else - bin + # TODO: Add support for other encodings + def _parse_binary(bin, entity) #:nodoc: + case entity["encoding"] + when "base64" + ::Base64.decode64(bin) + else + bin + end end - end - def _parse_file(file, entity) - f = StringIO.new(::Base64.decode64(file)) - f.extend(FileLike) - f.original_filename = entity['name'] - f.content_type = entity['content_type'] - f - end + def _parse_file(file, entity) + f = StringIO.new(::Base64.decode64(file)) + f.extend(FileLike) + f.original_filename = entity["name"] + f.content_type = entity["content_type"] + f + end private @@ -195,5 +195,5 @@ module ActiveSupport end end - XmlMini.backend = 'REXML' + XmlMini.backend = "REXML" end diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb index 94751bbc04..10498c9be0 100644 --- a/activesupport/lib/active_support/xml_mini/jdom.rb +++ b/activesupport/lib/active_support/xml_mini/jdom.rb @@ -1,9 +1,9 @@ -raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM =~ /java/ +raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM.include?("java") -require 'jruby' +require "jruby" include Java -require 'active_support/core_ext/object/blank' +require "active_support/core_ext/object/blank" java_import javax.xml.parsers.DocumentBuilder unless defined? DocumentBuilder java_import javax.xml.parsers.DocumentBuilderFactory unless defined? DocumentBuilderFactory @@ -16,7 +16,7 @@ module ActiveSupport module XmlMini_JDOM #:nodoc: extend self - CONTENT_KEY = '__content__'.freeze + CONTENT_KEY = "__content__".freeze NODE_TYPE_NAMES = %w{ATTRIBUTE_NODE CDATA_SECTION_NODE COMMENT_NODE DOCUMENT_FRAGMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE ELEMENT_NODE ENTITY_NODE ENTITY_REFERENCE_NODE NOTATION_NODE @@ -46,136 +46,136 @@ module ActiveSupport xml_string_reader = StringReader.new(data) xml_input_source = InputSource.new(xml_string_reader) doc = @dbf.new_document_builder.parse(xml_input_source) - merge_element!({CONTENT_KEY => ''}, doc.document_element, XmlMini.depth) + merge_element!({ CONTENT_KEY => "" }, doc.document_element, XmlMini.depth) end end private - # Convert an XML element and merge into the hash - # - # hash:: - # Hash to merge the converted element into. - # element:: - # XML element to merge into hash - def merge_element!(hash, element, depth) - raise 'Document too deep!' if depth == 0 - delete_empty(hash) - merge!(hash, element.tag_name, collapse(element, depth)) - end - - def delete_empty(hash) - hash.delete(CONTENT_KEY) if hash[CONTENT_KEY] == '' - end + # Convert an XML element and merge into the hash + # + # hash:: + # Hash to merge the converted element into. + # element:: + # XML element to merge into hash + def merge_element!(hash, element, depth) + raise "Document too deep!" if depth == 0 + delete_empty(hash) + merge!(hash, element.tag_name, collapse(element, depth)) + end - # Actually converts an XML document element into a data structure. - # - # element:: - # The document element to be collapsed. - def collapse(element, depth) - hash = get_attributes(element) + def delete_empty(hash) + hash.delete(CONTENT_KEY) if hash[CONTENT_KEY] == "" + end - child_nodes = element.child_nodes - if child_nodes.length > 0 - (0...child_nodes.length).each do |i| - child = child_nodes.item(i) - merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE + # Actually converts an XML document element into a data structure. + # + # element:: + # The document element to be collapsed. + def collapse(element, depth) + hash = get_attributes(element) + + child_nodes = element.child_nodes + if child_nodes.length > 0 + (0...child_nodes.length).each do |i| + child = child_nodes.item(i) + merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE + end + merge_texts!(hash, element) unless empty_content?(element) + hash + else + merge_texts!(hash, element) end - merge_texts!(hash, element) unless empty_content?(element) - hash - else - merge_texts!(hash, element) end - end - # Merge all the texts of an element into the hash - # - # hash:: - # Hash to add the converted element to. - # element:: - # XML element whose texts are to me merged into the hash - def merge_texts!(hash, element) - delete_empty(hash) - text_children = texts(element) - if text_children.join.empty? - hash - else - # must use value to prevent double-escaping - merge!(hash, CONTENT_KEY, text_children.join) + # Merge all the texts of an element into the hash + # + # hash:: + # Hash to add the converted element to. + # element:: + # XML element whose texts are to me merged into the hash + def merge_texts!(hash, element) + delete_empty(hash) + text_children = texts(element) + if text_children.join.empty? + hash + else + # must use value to prevent double-escaping + merge!(hash, CONTENT_KEY, text_children.join) + end end - end - # Adds a new key/value pair to an existing Hash. If the key to be added - # already exists and the existing value associated with key is not - # an Array, it will be wrapped in an Array. Then the new value is - # appended to that Array. - # - # hash:: - # Hash to add key/value pair to. - # key:: - # Key to be added. - # value:: - # Value to be associated with key. - def merge!(hash, key, value) - if hash.has_key?(key) - if hash[key].instance_of?(Array) - hash[key] << value + # Adds a new key/value pair to an existing Hash. If the key to be added + # already exists and the existing value associated with key is not + # an Array, it will be wrapped in an Array. Then the new value is + # appended to that Array. + # + # hash:: + # Hash to add key/value pair to. + # key:: + # Key to be added. + # value:: + # Value to be associated with key. + def merge!(hash, key, value) + if hash.has_key?(key) + if hash[key].instance_of?(Array) + hash[key] << value + else + hash[key] = [hash[key], value] + end + elsif value.instance_of?(Array) + hash[key] = [value] else - hash[key] = [hash[key], value] + hash[key] = value end - elsif value.instance_of?(Array) - hash[key] = [value] - else - hash[key] = value + hash end - hash - end - # Converts the attributes array of an XML element into a hash. - # Returns an empty Hash if node has no attributes. - # - # element:: - # XML element to extract attributes from. - def get_attributes(element) - attribute_hash = {} - attributes = element.attributes - (0...attributes.length).each do |i| - attribute_hash[CONTENT_KEY] ||= '' - attribute_hash[attributes.item(i).name] = attributes.item(i).value + # Converts the attributes array of an XML element into a hash. + # Returns an empty Hash if node has no attributes. + # + # element:: + # XML element to extract attributes from. + def get_attributes(element) + attribute_hash = {} + attributes = element.attributes + (0...attributes.length).each do |i| + attribute_hash[CONTENT_KEY] ||= "" + attribute_hash[attributes.item(i).name] = attributes.item(i).value + end + attribute_hash end - attribute_hash - end - # Determines if a document element has text content - # - # element:: - # XML element to be checked. - def texts(element) - texts = [] - child_nodes = element.child_nodes - (0...child_nodes.length).each do |i| - item = child_nodes.item(i) - if item.node_type == Node.TEXT_NODE - texts << item.get_data + # Determines if a document element has text content + # + # element:: + # XML element to be checked. + def texts(element) + texts = [] + child_nodes = element.child_nodes + (0...child_nodes.length).each do |i| + item = child_nodes.item(i) + if item.node_type == Node.TEXT_NODE + texts << item.get_data + end end + texts end - texts - end - # Determines if a document element has text content - # - # element:: - # XML element to be checked. - def empty_content?(element) - text = '' - child_nodes = element.child_nodes - (0...child_nodes.length).each do |i| - item = child_nodes.item(i) - if item.node_type == Node.TEXT_NODE - text << item.get_data.strip + # Determines if a document element has text content + # + # element:: + # XML element to be checked. + def empty_content?(element) + text = "" + child_nodes = element.child_nodes + (0...child_nodes.length).each do |i| + item = child_nodes.item(i) + if item.node_type == Node.TEXT_NODE + text << item.get_data.strip + end end + text.strip.length == 0 end - text.strip.length == 0 - end end end diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb index bb0ea9c582..8a4aa03963 100644 --- a/activesupport/lib/active_support/xml_mini/libxml.rb +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -1,6 +1,6 @@ -require 'libxml' -require 'active_support/core_ext/object/blank' -require 'stringio' +require "libxml" +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_LibXML #:nodoc: @@ -11,7 +11,7 @@ module ActiveSupport # XML Document string or IO to parse def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc @@ -22,7 +22,6 @@ module ActiveSupport LibXML::XML::Parser.io(data).parse.to_hash end end - end end @@ -35,7 +34,7 @@ module LibXML #:nodoc: end module Node #:nodoc: - CONTENT_ROOT = '__content__'.freeze + CONTENT_ROOT = "__content__".freeze # Convert XML document to hash. # @@ -46,9 +45,9 @@ module LibXML #:nodoc: # Insert node hash into parent hash correctly. case hash[name] - when Array then hash[name] << node_hash - when Hash then hash[name] = [hash[name], node_hash] - when nil then hash[name] = node_hash + when Array then hash[name] << node_hash + when Hash then hash[name] = [hash[name], node_hash] + when nil then hash[name] = node_hash end # Handle child elements @@ -56,7 +55,7 @@ module LibXML #:nodoc: if c.element? c.to_hash(node_hash) elsif c.text? || c.cdata? - node_hash[CONTENT_ROOT] ||= '' + node_hash[CONTENT_ROOT] ||= "" node_hash[CONTENT_ROOT] << c.content end end diff --git a/activesupport/lib/active_support/xml_mini/libxmlsax.rb b/activesupport/lib/active_support/xml_mini/libxmlsax.rb index 70a95299ec..4edb0bd2b1 100644 --- a/activesupport/lib/active_support/xml_mini/libxmlsax.rb +++ b/activesupport/lib/active_support/xml_mini/libxmlsax.rb @@ -1,6 +1,6 @@ -require 'libxml' -require 'active_support/core_ext/object/blank' -require 'stringio' +require "libxml" +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_LibXMLSAX #:nodoc: @@ -9,11 +9,10 @@ module ActiveSupport # Class that will build the hash while the XML document # is being parsed using SAX events. class HashBuilder - include LibXML::XML::SaxParser::Callbacks - CONTENT_KEY = '__content__'.freeze - HASH_SIZE_KEY = '__hash_size__'.freeze + CONTENT_KEY = "__content__".freeze + HASH_SIZE_KEY = "__hash_size__".freeze attr_reader :hash @@ -22,7 +21,7 @@ module ActiveSupport end def on_start_document - @hash = { CONTENT_KEY => '' } + @hash = { CONTENT_KEY => "" } @hash_stack = [@hash] end @@ -32,20 +31,20 @@ module ActiveSupport end def on_start_element(name, attrs = {}) - new_hash = { CONTENT_KEY => '' }.merge!(attrs) + new_hash = { CONTENT_KEY => "" }.merge!(attrs) new_hash[HASH_SIZE_KEY] = new_hash.size + 1 case current_hash[name] - when Array then current_hash[name] << new_hash - when Hash then current_hash[name] = [current_hash[name], new_hash] - when nil then current_hash[name] = new_hash + when Array then current_hash[name] << new_hash + when Hash then current_hash[name] = [current_hash[name], new_hash] + when nil then current_hash[name] = new_hash end @hash_stack.push(new_hash) end def on_end_element(name) - if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == '' + if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == "" current_hash.delete(CONTENT_KEY) end @hash_stack.pop @@ -63,7 +62,7 @@ module ActiveSupport def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc diff --git a/activesupport/lib/active_support/xml_mini/nokogiri.rb b/activesupport/lib/active_support/xml_mini/nokogiri.rb index 619cc7522d..b92fa7ea7c 100644 --- a/activesupport/lib/active_support/xml_mini/nokogiri.rb +++ b/activesupport/lib/active_support/xml_mini/nokogiri.rb @@ -1,11 +1,11 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError => e $stderr.puts "You don't have nokogiri installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require 'active_support/core_ext/object/blank' -require 'stringio' +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_Nokogiri #:nodoc: @@ -16,7 +16,7 @@ module ActiveSupport # XML Document string or IO to parse def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc @@ -38,7 +38,7 @@ module ActiveSupport end module Node #:nodoc: - CONTENT_ROOT = '__content__'.freeze + CONTENT_ROOT = "__content__".freeze # Convert XML document to hash. # @@ -49,9 +49,9 @@ module ActiveSupport # Insert node hash into parent hash correctly. case hash[name] - when Array then hash[name] << node_hash - when Hash then hash[name] = [hash[name], node_hash] - when nil then hash[name] = node_hash + when Array then hash[name] << node_hash + when Hash then hash[name] = [hash[name], node_hash] + when nil then hash[name] = node_hash end # Handle child elements @@ -59,7 +59,7 @@ module ActiveSupport if c.element? c.to_hash(node_hash) elsif c.text? || c.cdata? - node_hash[CONTENT_ROOT] ||= '' + node_hash[CONTENT_ROOT] ||= "" node_hash[CONTENT_ROOT] << c.content end end diff --git a/activesupport/lib/active_support/xml_mini/nokogirisax.rb b/activesupport/lib/active_support/xml_mini/nokogirisax.rb index be2d6a4cb1..b8b85146c5 100644 --- a/activesupport/lib/active_support/xml_mini/nokogirisax.rb +++ b/activesupport/lib/active_support/xml_mini/nokogirisax.rb @@ -1,11 +1,11 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError => e $stderr.puts "You don't have nokogiri installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require 'active_support/core_ext/object/blank' -require 'stringio' +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_NokogiriSAX #:nodoc: @@ -14,9 +14,8 @@ module ActiveSupport # Class that will build the hash while the XML document # is being parsed using SAX events. class HashBuilder < Nokogiri::XML::SAX::Document - - CONTENT_KEY = '__content__'.freeze - HASH_SIZE_KEY = '__hash_size__'.freeze + CONTENT_KEY = "__content__".freeze + HASH_SIZE_KEY = "__hash_size__".freeze attr_reader :hash @@ -38,20 +37,20 @@ module ActiveSupport end def start_element(name, attrs = []) - new_hash = { CONTENT_KEY => '' }.merge!(Hash[attrs]) + new_hash = { CONTENT_KEY => "" }.merge!(Hash[attrs]) new_hash[HASH_SIZE_KEY] = new_hash.size + 1 case current_hash[name] - when Array then current_hash[name] << new_hash - when Hash then current_hash[name] = [current_hash[name], new_hash] - when nil then current_hash[name] = new_hash + when Array then current_hash[name] << new_hash + when Hash then current_hash[name] = [current_hash[name], new_hash] + when nil then current_hash[name] = new_hash end @hash_stack.push(new_hash) end def end_element(name) - if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == '' + if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == "" current_hash.delete(CONTENT_KEY) end @hash_stack.pop @@ -69,7 +68,7 @@ module ActiveSupport def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end char = data.getc diff --git a/activesupport/lib/active_support/xml_mini/rexml.rb b/activesupport/lib/active_support/xml_mini/rexml.rb index 95af5af2c0..091a15294c 100644 --- a/activesupport/lib/active_support/xml_mini/rexml.rb +++ b/activesupport/lib/active_support/xml_mini/rexml.rb @@ -1,12 +1,12 @@ -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/object/blank' -require 'stringio' +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/object/blank" +require "stringio" module ActiveSupport module XmlMini_REXML #:nodoc: extend self - CONTENT_KEY = '__content__'.freeze + CONTENT_KEY = "__content__".freeze # Parse an XML Document string or IO into a simple hash. # @@ -17,13 +17,13 @@ module ActiveSupport # XML Document string or IO to parse def parse(data) if !data.respond_to?(:read) - data = StringIO.new(data || '') + data = StringIO.new(data || "") end if data.eof? {} else - silence_warnings { require 'rexml/document' } unless defined?(REXML::Document) + silence_warnings { require "rexml/document" } unless defined?(REXML::Document) doc = REXML::Document.new(data) if doc.root @@ -55,7 +55,7 @@ module ActiveSupport hash = get_attributes(element) if element.has_elements? - element.each_element {|child| merge_element!(hash, child, depth - 1) } + element.each_element { |child| merge_element!(hash, child, depth - 1) } merge_texts!(hash, element) unless empty_content?(element) hash else @@ -74,7 +74,7 @@ module ActiveSupport hash else # must use value to prevent double-escaping - texts = '' + texts = "" element.texts.each { |t| texts << t.value } merge!(hash, CONTENT_KEY, texts) end diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index bab7440397..4e564591b4 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -1,17 +1,17 @@ ORIG_ARGV = ARGV.dup -require 'active_support/core_ext/kernel/reporting' +require "active_support/core_ext/kernel/reporting" silence_warnings do Encoding.default_internal = "UTF-8" Encoding.default_external = "UTF-8" end -require 'active_support/testing/autorun' -require 'active_support/testing/method_call_assertions' +require "active_support/testing/autorun" +require "active_support/testing/method_call_assertions" -ENV['NO_RELOAD'] = '1' -require 'active_support' +ENV["NO_RELOAD"] = "1" +require "active_support" Thread.abort_on_exception = true @@ -19,18 +19,18 @@ Thread.abort_on_exception = true ActiveSupport::Deprecation.debug = true # Default to old to_time behavior but allow running tests with new behavior -ActiveSupport.to_time_preserves_timezone = ENV['PRESERVE_TIMEZONES'] == '1' +ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1" # Disable available locale checks to avoid warnings running the test suite. I18n.enforce_available_locales = false # Skips the current run on Rubinius using Minitest::Assertions#skip -def rubinius_skip(message = '') - skip message if RUBY_ENGINE == 'rbx' +def rubinius_skip(message = "") + skip message if RUBY_ENGINE == "rbx" end # Skips the current run on JRuby using Minitest::Assertions#skip -def jruby_skip(message = '') +def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end diff --git a/activesupport/test/array_inquirer_test.rb b/activesupport/test/array_inquirer_test.rb index 263ab3802b..4d3f5b001c 100644 --- a/activesupport/test/array_inquirer_test.rb +++ b/activesupport/test/array_inquirer_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class ArrayInquirerTest < ActiveSupport::TestCase def setup - @array_inquirer = ActiveSupport::ArrayInquirer.new([:mobile, :tablet, 'api']) + @array_inquirer = ActiveSupport::ArrayInquirer.new([:mobile, :tablet, "api"]) end def test_individual @@ -19,7 +19,7 @@ class ArrayInquirerTest < ActiveSupport::TestCase end def test_any_string_symbol_mismatch - assert @array_inquirer.any?('mobile') + assert @array_inquirer.any?("mobile") assert @array_inquirer.any?(:api) end @@ -33,7 +33,7 @@ class ArrayInquirerTest < ActiveSupport::TestCase end def test_inquiry - result = [:mobile, :tablet, 'api'].inquiry + result = [:mobile, :tablet, "api"].inquiry assert_instance_of ActiveSupport::ArrayInquirer, result assert_equal @array_inquirer, result diff --git a/activesupport/test/autoload_test.rb b/activesupport/test/autoload_test.rb index c18b007612..6c8aa3e055 100644 --- a/activesupport/test/autoload_test.rb +++ b/activesupport/test/autoload_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class TestAutoloadModule < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -31,7 +31,7 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@some_class_path) + assert_not_includes $LOADED_FEATURES, @some_class_path assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end @@ -40,7 +40,7 @@ class TestAutoloadModule < ActiveSupport::TestCase autoload :SomeClass end - assert !$LOADED_FEATURES.include?(@some_class_path) + assert_not_includes $LOADED_FEATURES, @some_class_path assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end @@ -51,9 +51,9 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@some_class_path) + assert_not_includes $LOADED_FEATURES, @some_class_path ::Fixtures::Autoload.eager_load! - assert $LOADED_FEATURES.include?(@some_class_path) + assert_includes $LOADED_FEATURES, @some_class_path assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end @@ -64,7 +64,7 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@another_class_path) + assert_not_includes $LOADED_FEATURES, @another_class_path assert_nothing_raised { ::Fixtures::AnotherClass } end @@ -75,7 +75,7 @@ class TestAutoloadModule < ActiveSupport::TestCase end end - assert !$LOADED_FEATURES.include?(@another_class_path) + assert_not_includes $LOADED_FEATURES, @another_class_path assert_nothing_raised { ::Fixtures::AnotherClass } end -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/a/b.rb b/activesupport/test/autoloading_fixtures/a/b.rb index 9c9e6454cf..0dbbbbd181 100644 --- a/activesupport/test/autoloading_fixtures/a/b.rb +++ b/activesupport/test/autoloading_fixtures/a/b.rb @@ -1,2 +1,2 @@ class A::B -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/a/c/d.rb b/activesupport/test/autoloading_fixtures/a/c/d.rb index 0f40d6fbc4..2c0ec5f182 100644 --- a/activesupport/test/autoloading_fixtures/a/c/d.rb +++ b/activesupport/test/autoloading_fixtures/a/c/d.rb @@ -1,2 +1,2 @@ class A::C::D -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/a/c/em/f.rb b/activesupport/test/autoloading_fixtures/a/c/em/f.rb index 8b28e19148..3ff1b7efa0 100644 --- a/activesupport/test/autoloading_fixtures/a/c/em/f.rb +++ b/activesupport/test/autoloading_fixtures/a/c/em/f.rb @@ -1,2 +1,2 @@ class A::C::EM::F -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/class_folder.rb b/activesupport/test/autoloading_fixtures/class_folder.rb index ad2b27be61..6ee8182214 100644 --- a/activesupport/test/autoloading_fixtures/class_folder.rb +++ b/activesupport/test/autoloading_fixtures/class_folder.rb @@ -1,3 +1,3 @@ class ClassFolder - ConstantInClassFolder = 'indeed' + ConstantInClassFolder = "indeed" end diff --git a/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb b/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb index 402609c583..4df069cab6 100644 --- a/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb +++ b/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb @@ -1,3 +1,3 @@ class ClassFolder::ClassFolderSubclass < ClassFolder - ConstantInClassFolder = 'indeed' + ConstantInClassFolder = "indeed" end diff --git a/activesupport/test/autoloading_fixtures/conflict.rb b/activesupport/test/autoloading_fixtures/conflict.rb index 4ac6201902..d7f42b5d5f 100644 --- a/activesupport/test/autoloading_fixtures/conflict.rb +++ b/activesupport/test/autoloading_fixtures/conflict.rb @@ -1 +1 @@ -Conflict = 2
\ No newline at end of file +Conflict = 2 diff --git a/activesupport/test/autoloading_fixtures/cross_site_dependency.rb b/activesupport/test/autoloading_fixtures/cross_site_dependency.rb index 21ee554e92..de941bf271 100644 --- a/activesupport/test/autoloading_fixtures/cross_site_dependency.rb +++ b/activesupport/test/autoloading_fixtures/cross_site_dependency.rb @@ -1,2 +1,2 @@ class CrossSiteDependency -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/d.rb b/activesupport/test/autoloading_fixtures/d.rb index 45c794d4ca..52850e1e1a 100644 --- a/activesupport/test/autoloading_fixtures/d.rb +++ b/activesupport/test/autoloading_fixtures/d.rb @@ -1,2 +1,2 @@ class D -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/em.rb b/activesupport/test/autoloading_fixtures/em.rb index 16a1838667..e47024999e 100644 --- a/activesupport/test/autoloading_fixtures/em.rb +++ b/activesupport/test/autoloading_fixtures/em.rb @@ -1,2 +1,2 @@ class EM -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb b/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb index e3d1218c96..d2c4f6b0c5 100644 --- a/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb +++ b/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb @@ -1,3 +1,2 @@ module LoadedConstant end - diff --git a/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb b/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb index 80244b8bab..04c426833e 100644 --- a/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb +++ b/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb @@ -1,2 +1,2 @@ class ModuleFolder::NestedSibling -end
\ No newline at end of file +end diff --git a/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb b/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb index d12d02f3aa..4f2020c503 100644 --- a/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb +++ b/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb @@ -1 +1 @@ -ModuleWithCustomConstMissing::A::B = "10"
\ No newline at end of file +ModuleWithCustomConstMissing::A::B = "10" diff --git a/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb index 3ca4213c71..829ee917d2 100644 --- a/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb +++ b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb @@ -1,4 +1,4 @@ RaisesArbitraryException = 1 _ = A::B # Autoloading recursion, also expected to be watched and discarded. -raise Exception, 'arbitray exception message' +raise Exception, "arbitray exception message" diff --git a/activesupport/test/autoloading_fixtures/requires_constant.rb b/activesupport/test/autoloading_fixtures/requires_constant.rb index 14804a0de0..f04dcc4091 100644 --- a/activesupport/test/autoloading_fixtures/requires_constant.rb +++ b/activesupport/test/autoloading_fixtures/requires_constant.rb @@ -2,4 +2,3 @@ require "loaded_constant" module RequiresConstant end - diff --git a/activesupport/test/autoloading_fixtures/typo.rb b/activesupport/test/autoloading_fixtures/typo.rb index 8e047f5fd4..0ffe07c2b3 100644 --- a/activesupport/test/autoloading_fixtures/typo.rb +++ b/activesupport/test/autoloading_fixtures/typo.rb @@ -1,2 +1 @@ TypO = 1 - diff --git a/activesupport/test/benchmarkable_test.rb b/activesupport/test/benchmarkable_test.rb index 5af041f458..210b9cb9fd 100644 --- a/activesupport/test/benchmarkable_test.rb +++ b/activesupport/test/benchmarkable_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class BenchmarkableTest < ActiveSupport::TestCase include ActiveSupport::Benchmarkable @@ -36,20 +36,20 @@ class BenchmarkableTest < ActiveSupport::TestCase def test_with_message i_was_run = false - benchmark('test_run') { i_was_run = true } + benchmark("test_run") { i_was_run = true } assert i_was_run - assert_last_logged 'test_run' + assert_last_logged "test_run" end def test_with_silence - assert_difference 'buffer.count', +2 do - benchmark('test_run') do + assert_difference "buffer.count", +2 do + benchmark("test_run") do logger.info "SOMETHING" end end - assert_difference 'buffer.count', +1 do - benchmark('test_run', silence: true) do + assert_difference "buffer.count", +1 do + benchmark("test_run", silence: true) do logger.info "NOTHING" end end @@ -57,20 +57,20 @@ class BenchmarkableTest < ActiveSupport::TestCase def test_within_level logger.level = ActiveSupport::Logger::DEBUG - benchmark('included_debug_run', :level => :debug) { } - assert_last_logged 'included_debug_run' + benchmark("included_debug_run", level: :debug) {} + assert_last_logged "included_debug_run" end def test_outside_level logger.level = ActiveSupport::Logger::ERROR - benchmark('skipped_debug_run', :level => :debug) { } + benchmark("skipped_debug_run", level: :debug) {} assert_no_match(/skipped_debug_run/, buffer.last) ensure logger.level = ActiveSupport::Logger::DEBUG end private - def assert_last_logged(message = 'Benchmarking') + def assert_last_logged(message = "Benchmarking") assert_match(/^#{message} \(.*\)$/, buffer.last) end end diff --git a/activesupport/test/broadcast_logger_test.rb b/activesupport/test/broadcast_logger_test.rb index f95b3e5ad3..4b74f1313e 100644 --- a/activesupport/test/broadcast_logger_test.rb +++ b/activesupport/test/broadcast_logger_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActiveSupport class BroadcastLoggerTest < TestCase @@ -26,8 +26,8 @@ module ActiveSupport test "#close broadcasts to all loggers" do logger.close - assert log1.closed, 'should be closed' - assert log2.closed, 'should be closed' + assert log1.closed, "should be closed" + assert log2.closed, "should be closed" end test "#<< shovels the value into all loggers" do @@ -138,7 +138,7 @@ module ActiveSupport add(::Logger::UNKNOWN, message, &block) end - def << x + def <<(x) @chevrons << x end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index ec7d028d7e..0df4173a1a 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -1,7 +1,9 @@ -require 'logger' -require 'abstract_unit' -require 'active_support/cache' -require 'dependencies_test_helpers' +require "logger" +require "abstract_unit" +require "active_support/cache" +require "dependencies_test_helpers" + +require "pathname" module ActiveSupport module Cache @@ -11,23 +13,35 @@ module ActiveSupport def test_local_cache_cleared_on_close key = "super awesome key" assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new('<3', key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), 'should have a cache' + middleware = Middleware.new("<3", key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), "should have a cache" [200, {}, []] }) _, _, body = middleware.call({}) - assert LocalCacheRegistry.cache_for(key), 'should still have a cache' - body.each { } - assert LocalCacheRegistry.cache_for(key), 'should still have a cache' + assert LocalCacheRegistry.cache_for(key), "should still have a cache" + body.each {} + assert LocalCacheRegistry.cache_for(key), "should still have a cache" body.close assert_nil LocalCacheRegistry.cache_for(key) end + def test_local_cache_cleared_and_response_should_be_present_on_invalid_parameters_error + key = "super awesome key" + assert_nil LocalCacheRegistry.cache_for key + middleware = Middleware.new("<3", key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), "should have a cache" + raise Rack::Utils::InvalidParameterError + }) + response = middleware.call({}) + assert response, "response should exist" + assert_nil LocalCacheRegistry.cache_for(key) + end + def test_local_cache_cleared_on_exception key = "super awesome key" assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new('<3', key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), 'should have a cache' + middleware = Middleware.new("<3", key).new(->(env) { + assert LocalCacheRegistry.cache_for(key), "should have a cache" raise }) assert_raises(RuntimeError) { middleware.call({}) } @@ -50,82 +64,92 @@ class CacheKeyTest < ActiveSupport::TestCase end end - entry = legacy.new 'foo' - assert_equal 'foo', entry.value + entry = legacy.new "foo" + assert_equal "foo", entry.value end def test_expand_cache_key - assert_equal '1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true]) - assert_equal 'name/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true], :name) + assert_equal "1/2/true", ActiveSupport::Cache.expand_cache_key([1, "2", true]) + assert_equal "name/1/2/true", ActiveSupport::Cache.expand_cache_key([1, "2", true], :name) end def test_expand_cache_key_with_rails_cache_id - with_env('RAILS_CACHE_ID' => 'c99') do - assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo) - assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key([:foo]) - assert_equal 'c99/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar]) - assert_equal 'nm/c99/foo', ActiveSupport::Cache.expand_cache_key(:foo, :nm) - assert_equal 'nm/c99/foo', ActiveSupport::Cache.expand_cache_key([:foo], :nm) - assert_equal 'nm/c99/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar], :nm) + with_env("RAILS_CACHE_ID" => "c99") do + assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key(:foo) + assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key([:foo]) + assert_equal "c99/foo/bar", ActiveSupport::Cache.expand_cache_key([:foo, :bar]) + assert_equal "nm/c99/foo", ActiveSupport::Cache.expand_cache_key(:foo, :nm) + assert_equal "nm/c99/foo", ActiveSupport::Cache.expand_cache_key([:foo], :nm) + assert_equal "nm/c99/foo/bar", ActiveSupport::Cache.expand_cache_key([:foo, :bar], :nm) end end def test_expand_cache_key_with_rails_app_version - with_env('RAILS_APP_VERSION' => 'rails3') do - assert_equal 'rails3/foo', ActiveSupport::Cache.expand_cache_key(:foo) + with_env("RAILS_APP_VERSION" => "rails3") do + assert_equal "rails3/foo", ActiveSupport::Cache.expand_cache_key(:foo) end end def test_expand_cache_key_rails_cache_id_should_win_over_rails_app_version - with_env('RAILS_CACHE_ID' => 'c99', 'RAILS_APP_VERSION' => 'rails3') do - assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo) + with_env("RAILS_CACHE_ID" => "c99", "RAILS_APP_VERSION" => "rails3") do + assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key(:foo) end end def test_expand_cache_key_respond_to_cache_key - key = 'foo' + key = "foo" def key.cache_key :foo_key end - assert_equal 'foo_key', ActiveSupport::Cache.expand_cache_key(key) + assert_equal "foo_key", ActiveSupport::Cache.expand_cache_key(key) end def test_expand_cache_key_array_with_something_that_responds_to_cache_key - key = 'foo' + key = "foo" def key.cache_key :foo_key end - assert_equal 'foo_key', ActiveSupport::Cache.expand_cache_key([key]) + assert_equal "foo_key", ActiveSupport::Cache.expand_cache_key([key]) end def test_expand_cache_key_of_nil - assert_equal '', ActiveSupport::Cache.expand_cache_key(nil) + assert_equal "", ActiveSupport::Cache.expand_cache_key(nil) end def test_expand_cache_key_of_false - assert_equal 'false', ActiveSupport::Cache.expand_cache_key(false) + assert_equal "false", ActiveSupport::Cache.expand_cache_key(false) end def test_expand_cache_key_of_true - assert_equal 'true', ActiveSupport::Cache.expand_cache_key(true) + assert_equal "true", ActiveSupport::Cache.expand_cache_key(true) end def test_expand_cache_key_of_array_like_object - assert_equal 'foo/bar/baz', ActiveSupport::Cache.expand_cache_key(%w{foo bar baz}.to_enum) + assert_equal "foo/bar/baz", ActiveSupport::Cache.expand_cache_key(%w{foo bar baz}.to_enum) end private - def with_env(kv) - old_values = {} - kv.each { |key, value| old_values[key], ENV[key] = ENV[key], value } - yield - ensure - old_values.each { |key, value| ENV[key] = value} - end + def with_env(kv) + old_values = {} + kv.each { |key, value| old_values[key], ENV[key] = ENV[key], value } + yield + ensure + old_values.each { |key, value| ENV[key] = value } + end end class CacheStoreSettingTest < ActiveSupport::TestCase + def test_memory_store_gets_created_if_no_arguments_passed_to_lookup_store_method + store = ActiveSupport::Cache.lookup_store + assert_kind_of(ActiveSupport::Cache::MemoryStore, store) + end + + def test_memory_store + store = ActiveSupport::Cache.lookup_store :memory_store + assert_kind_of(ActiveSupport::Cache::MemoryStore, store) + end + def test_file_fragment_cache_store store = ActiveSupport::Cache.lookup_store :file_store, "/path/to/cache/directory" assert_kind_of(ActiveSupport::Cache::FileStore, store) @@ -158,16 +182,16 @@ class CacheStoreSettingTest < ActiveSupport::TestCase def test_mem_cache_fragment_cache_store_with_multiple_servers assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], {}]) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1' + store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", "192.168.1.1" assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) end end def test_mem_cache_fragment_cache_store_with_options - assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], { :timeout => 10 }]) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1', :namespace => 'foo', :timeout => 10 + assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], { timeout: 10 }]) do + store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", "192.168.1.1", namespace: "foo", timeout: 10 assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - assert_equal 'foo', store.options[:namespace] + assert_equal "foo", store.options[:namespace] end end @@ -180,7 +204,7 @@ end class CacheStoreNamespaceTest < ActiveSupport::TestCase def test_static_namespace - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => "tester") + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "tester") cache.write("foo", "bar") assert_equal "bar", cache.read("foo") assert_equal "bar", cache.instance_variable_get(:@data)["tester:foo"].value @@ -188,15 +212,15 @@ class CacheStoreNamespaceTest < ActiveSupport::TestCase def test_proc_namespace test_val = "tester" - proc = lambda{test_val} - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => proc) + proc = lambda { test_val } + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: proc) cache.write("foo", "bar") assert_equal "bar", cache.read("foo") assert_equal "bar", cache.instance_variable_get(:@data)["tester:foo"].value end def test_delete_matched_key_start - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => "tester") + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "tester") cache.write("foo", "bar") cache.write("fu", "baz") cache.delete_matched(/^fo/) @@ -205,7 +229,7 @@ class CacheStoreNamespaceTest < ActiveSupport::TestCase end def test_delete_matched_key - cache = ActiveSupport::Cache.lookup_store(:memory_store, :namespace => "foo") + cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "foo") cache.write("foo", "bar") cache.write("fu", "baz") cache.delete_matched(/OO/i) @@ -217,141 +241,147 @@ end # Tests the base functionality that should be identical across all cache stores. module CacheStoreBehavior def test_should_read_and_write_strings - assert @cache.write('foo', 'bar') - assert_equal 'bar', @cache.read('foo') + assert @cache.write("foo", "bar") + assert_equal "bar", @cache.read("foo") end def test_should_overwrite - @cache.write('foo', 'bar') - @cache.write('foo', 'baz') - assert_equal 'baz', @cache.read('foo') + @cache.write("foo", "bar") + @cache.write("foo", "baz") + assert_equal "baz", @cache.read("foo") end def test_fetch_without_cache_miss - @cache.write('foo', 'bar') + @cache.write("foo", "bar") assert_not_called(@cache, :write) do - assert_equal 'bar', @cache.fetch('foo') { 'baz' } + assert_equal "bar", @cache.fetch("foo") { "baz" } end end def test_fetch_with_cache_miss - assert_called_with(@cache, :write, ['foo', 'baz', @cache.options]) do - assert_equal 'baz', @cache.fetch('foo') { 'baz' } + assert_called_with(@cache, :write, ["foo", "baz", @cache.options]) do + assert_equal "baz", @cache.fetch("foo") { "baz" } end end def test_fetch_with_cache_miss_passes_key_to_block cache_miss = false - assert_equal 3, @cache.fetch('foo') { |key| cache_miss = true; key.length } + assert_equal 3, @cache.fetch("foo") { |key| cache_miss = true; key.length } assert cache_miss cache_miss = false - assert_equal 3, @cache.fetch('foo') { |key| cache_miss = true; key.length } + assert_equal 3, @cache.fetch("foo") { |key| cache_miss = true; key.length } assert !cache_miss end def test_fetch_with_forced_cache_miss - @cache.write('foo', 'bar') + @cache.write("foo", "bar") assert_not_called(@cache, :read) do - assert_called_with(@cache, :write, ['foo', 'bar', @cache.options.merge(:force => true)]) do - @cache.fetch('foo', :force => true) { 'bar' } + assert_called_with(@cache, :write, ["foo", "bar", @cache.options.merge(force: true)]) do + @cache.fetch("foo", force: true) { "bar" } end end end def test_fetch_with_cached_nil - @cache.write('foo', nil) + @cache.write("foo", nil) assert_not_called(@cache, :write) do - assert_nil @cache.fetch('foo') { 'baz' } + assert_nil @cache.fetch("foo") { "baz" } end end def test_fetch_with_forced_cache_miss_with_block - @cache.write('foo', 'bar') - assert_equal 'foo_bar', @cache.fetch('foo', force: true) { 'foo_bar' } + @cache.write("foo", "bar") + assert_equal "foo_bar", @cache.fetch("foo", force: true) { "foo_bar" } end def test_fetch_with_forced_cache_miss_without_block - @cache.write('foo', 'bar') + @cache.write("foo", "bar") assert_raises(ArgumentError) do - @cache.fetch('foo', force: true) + @cache.fetch("foo", force: true) end - assert_equal 'bar', @cache.read('foo') + assert_equal "bar", @cache.read("foo") end def test_should_read_and_write_hash - assert @cache.write('foo', {:a => "b"}) - assert_equal({:a => "b"}, @cache.read('foo')) + assert @cache.write("foo", a: "b") + assert_equal({ a: "b" }, @cache.read("foo")) end def test_should_read_and_write_integer - assert @cache.write('foo', 1) - assert_equal 1, @cache.read('foo') + assert @cache.write("foo", 1) + assert_equal 1, @cache.read("foo") end def test_should_read_and_write_nil - assert @cache.write('foo', nil) - assert_equal nil, @cache.read('foo') + assert @cache.write("foo", nil) + assert_equal nil, @cache.read("foo") end def test_should_read_and_write_false - assert @cache.write('foo', false) - assert_equal false, @cache.read('foo') + assert @cache.write("foo", false) + assert_equal false, @cache.read("foo") end def test_read_multi - @cache.write('foo', 'bar') - @cache.write('fu', 'baz') - @cache.write('fud', 'biz') - assert_equal({"foo" => "bar", "fu" => "baz"}, @cache.read_multi('foo', 'fu')) + @cache.write("foo", "bar") + @cache.write("fu", "baz") + @cache.write("fud", "biz") + assert_equal({ "foo" => "bar", "fu" => "baz" }, @cache.read_multi("foo", "fu")) end def test_read_multi_with_expires time = Time.now - @cache.write('foo', 'bar', :expires_in => 10) - @cache.write('fu', 'baz') - @cache.write('fud', 'biz') + @cache.write("foo", "bar", expires_in: 10) + @cache.write("fu", "baz") + @cache.write("fud", "biz") Time.stub(:now, time + 11) do - assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu')) + assert_equal({ "fu" => "baz" }, @cache.read_multi("foo", "fu")) end end def test_fetch_multi - @cache.write('foo', 'bar') - @cache.write('fud', 'biz') + @cache.write("foo", "bar") + @cache.write("fud", "biz") - values = @cache.fetch_multi('foo', 'fu', 'fud') { |value| value * 2 } + values = @cache.fetch_multi("foo", "fu", "fud") { |value| value * 2 } - assert_equal({ 'foo' => 'bar', 'fu' => 'fufu', 'fud' => 'biz' }, values) - assert_equal('fufu', @cache.read('fu')) + assert_equal({ "foo" => "bar", "fu" => "fufu", "fud" => "biz" }, values) + assert_equal("fufu", @cache.read("fu")) end def test_multi_with_objects cache_struct = Struct.new(:cache_key, :title) - foo = cache_struct.new('foo', 'FOO!') - bar = cache_struct.new('bar') + foo = cache_struct.new("foo", "FOO!") + bar = cache_struct.new("bar") - @cache.write('bar', 'BAM!') + @cache.write("bar", "BAM!") values = @cache.fetch_multi(foo, bar) { |object| object.title } - assert_equal({ foo => 'FOO!', bar => 'BAM!' }, values) + assert_equal({ foo => "FOO!", bar => "BAM!" }, values) + end + + def test_fetch_multi_without_block + assert_raises(ArgumentError) do + @cache.fetch_multi("foo") + end end def test_read_and_write_compressed_small_data - @cache.write('foo', 'bar', :compress => true) - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar", compress: true) + assert_equal "bar", @cache.read("foo") end def test_read_and_write_compressed_large_data - @cache.write('foo', 'bar', :compress => true, :compress_threshold => 2) - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar", compress: true, compress_threshold: 2) + assert_equal "bar", @cache.read("foo") end def test_read_and_write_compressed_nil - @cache.write('foo', nil, :compress => true) - assert_nil @cache.read('foo') + @cache.write("foo", nil, compress: true) + assert_nil @cache.read("foo") end def test_cache_key @@ -378,7 +408,7 @@ module CacheStoreBehavior end def test_hash_as_cache_key - @cache.write({:foo => 1, :fu => 2}, "bar") + @cache.write({ foo: 1, fu: 2 }, "bar") assert_equal "bar", @cache.read("foo=1/fu=2") end @@ -388,65 +418,65 @@ module CacheStoreBehavior end def test_exist - @cache.write('foo', 'bar') - assert_equal true, @cache.exist?('foo') - assert_equal false, @cache.exist?('bar') + @cache.write("foo", "bar") + assert_equal true, @cache.exist?("foo") + assert_equal false, @cache.exist?("bar") end def test_nil_exist - @cache.write('foo', nil) - assert @cache.exist?('foo') + @cache.write("foo", nil) + assert @cache.exist?("foo") end def test_delete - @cache.write('foo', 'bar') - assert @cache.exist?('foo') - assert @cache.delete('foo') - assert !@cache.exist?('foo') + @cache.write("foo", "bar") + assert @cache.exist?("foo") + assert @cache.delete("foo") + assert !@cache.exist?("foo") end def test_original_store_objects_should_not_be_immutable - bar = 'bar' - @cache.write('foo', bar) - assert_nothing_raised { bar.gsub!(/.*/, 'baz') } + bar = "bar" + @cache.write("foo", bar) + assert_nothing_raised { bar.gsub!(/.*/, "baz") } end def test_expires_in time = Time.local(2008, 4, 24) Time.stub(:now, time) do - @cache.write('foo', 'bar') - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar") + assert_equal "bar", @cache.read("foo") end Time.stub(:now, time + 30) do - assert_equal 'bar', @cache.read('foo') + assert_equal "bar", @cache.read("foo") end Time.stub(:now, time + 61) do - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end end def test_race_condition_protection_skipped_if_not_defined - @cache.write('foo', 'bar') - time = @cache.send(:read_entry, @cache.send(:normalize_key, 'foo', {}), {}).expires_at + @cache.write("foo", "bar") + time = @cache.send(:read_entry, @cache.send(:normalize_key, "foo", {}), {}).expires_at Time.stub(:now, Time.at(time)) do - result = @cache.fetch('foo') do - assert_equal nil, @cache.read('foo') - 'baz' + result = @cache.fetch("foo") do + assert_equal nil, @cache.read("foo") + "baz" end - assert_equal 'baz', result + assert_equal "baz", result end end def test_race_condition_protection_is_limited time = Time.now - @cache.write('foo', 'bar', :expires_in => 60) + @cache.write("foo", "bar", expires_in: 60) Time.stub(:now, time + 71) do - result = @cache.fetch('foo', :race_condition_ttl => 10) do - assert_equal nil, @cache.read('foo') + result = @cache.fetch("foo", race_condition_ttl: 10) do + assert_equal nil, @cache.read("foo") "baz" end assert_equal "baz", result @@ -455,28 +485,28 @@ module CacheStoreBehavior def test_race_condition_protection_is_safe time = Time.now - @cache.write('foo', 'bar', :expires_in => 60) + @cache.write("foo", "bar", expires_in: 60) Time.stub(:now, time + 61) do begin - @cache.fetch('foo', :race_condition_ttl => 10) do - assert_equal 'bar', @cache.read('foo') + @cache.fetch("foo", race_condition_ttl: 10) do + assert_equal "bar", @cache.read("foo") raise ArgumentError.new end rescue ArgumentError end - assert_equal "bar", @cache.read('foo') + assert_equal "bar", @cache.read("foo") end Time.stub(:now, time + 91) do - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end end def test_race_condition_protection time = Time.now - @cache.write('foo', 'bar', :expires_in => 60) + @cache.write("foo", "bar", expires_in: 60) Time.stub(:now, time + 61) do - result = @cache.fetch('foo', :race_condition_ttl => 10) do - assert_equal 'bar', @cache.read('foo') + result = @cache.fetch("foo", race_condition_ttl: 10) do + assert_equal "bar", @cache.read("foo") "baz" end assert_equal "baz", result @@ -485,23 +515,23 @@ module CacheStoreBehavior def test_crazy_key_characters crazy_key = "#/:*(<+=> )&$%@?;'\"\'`~-" - assert @cache.write(crazy_key, "1", :raw => true) + assert @cache.write(crazy_key, "1", raw: true) assert_equal "1", @cache.read(crazy_key) assert_equal "1", @cache.fetch(crazy_key) assert @cache.delete(crazy_key) - assert_equal "2", @cache.fetch(crazy_key, :raw => true) { "2" } + assert_equal "2", @cache.fetch(crazy_key, raw: true) { "2" } assert_equal 3, @cache.increment(crazy_key) assert_equal 2, @cache.decrement(crazy_key) end def test_really_long_keys key = "" - 900.times{key << "x"} + 900.times { key << "x" } assert @cache.write(key, "bar") assert_equal "bar", @cache.read(key) assert_equal "bar", @cache.fetch(key) assert_nil @cache.read("#{key}x") - assert_equal({key => "bar"}, @cache.read_multi(key)) + assert_equal({ key => "bar" }, @cache.read_multi(key)) assert @cache.delete(key) end @@ -511,10 +541,10 @@ module CacheStoreBehavior ActiveSupport::Notifications.subscribe "cache_read.active_support" do |*args| @events << ActiveSupport::Notifications::Event.new(*args) end - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert @cache.fetch(key) {} assert_equal 1, @events.length - assert_equal 'cache_read.active_support', @events[0].name + assert_equal "cache_read.active_support", @events[0].name assert_equal :fetch, @events[0].payload[:super_operation] assert @events[0].payload[:hit] ensure @@ -528,9 +558,9 @@ module CacheStoreBehavior end assert_not @cache.fetch("bad_key") {} assert_equal 3, @events.length - assert_equal 'cache_read.active_support', @events[0].name - assert_equal 'cache_generate.active_support', @events[1].name - assert_equal 'cache_write.active_support', @events[2].name + assert_equal "cache_read.active_support", @events[0].name + assert_equal "cache_generate.active_support", @events[1].name + assert_equal "cache_write.active_support", @events[2].name assert_equal :fetch, @events[0].payload[:super_operation] assert_not @events[0].payload[:hit] ensure @@ -551,11 +581,11 @@ module EncodedKeyCacheBehavior Encoding.list.each do |encoding| define_method "test_#{encoding.name.underscore}_encoded_values" do key = "foo".force_encoding(encoding) - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert_equal "1", @cache.read(key) assert_equal "1", @cache.fetch(key) assert @cache.delete(key) - assert_equal "2", @cache.fetch(key, :raw => true) { "2" } + assert_equal "2", @cache.fetch(key, raw: true) { "2" } assert_equal 3, @cache.increment(key) assert_equal 2, @cache.decrement(key) end @@ -563,18 +593,18 @@ module EncodedKeyCacheBehavior def test_common_utf8_values key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8) - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert_equal "1", @cache.read(key) assert_equal "1", @cache.fetch(key) assert @cache.delete(key) - assert_equal "2", @cache.fetch(key, :raw => true) { "2" } + assert_equal "2", @cache.fetch(key, raw: true) { "2" } assert_equal 3, @cache.increment(key) assert_equal 2, @cache.decrement(key) end def test_retains_encoding key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8) - assert @cache.write(key, "1", :raw => true) + assert @cache.write(key, "1", raw: true) assert_equal Encoding::UTF_8, key.encoding end end @@ -595,122 +625,122 @@ end module CacheIncrementDecrementBehavior def test_increment - @cache.write('foo', 1, :raw => true) - assert_equal 1, @cache.read('foo').to_i - assert_equal 2, @cache.increment('foo') - assert_equal 2, @cache.read('foo').to_i - assert_equal 3, @cache.increment('foo') - assert_equal 3, @cache.read('foo').to_i - assert_nil @cache.increment('bar') + @cache.write("foo", 1, raw: true) + assert_equal 1, @cache.read("foo").to_i + assert_equal 2, @cache.increment("foo") + assert_equal 2, @cache.read("foo").to_i + assert_equal 3, @cache.increment("foo") + assert_equal 3, @cache.read("foo").to_i + assert_nil @cache.increment("bar") end def test_decrement - @cache.write('foo', 3, :raw => true) - assert_equal 3, @cache.read('foo').to_i - assert_equal 2, @cache.decrement('foo') - assert_equal 2, @cache.read('foo').to_i - assert_equal 1, @cache.decrement('foo') - assert_equal 1, @cache.read('foo').to_i - assert_nil @cache.decrement('bar') + @cache.write("foo", 3, raw: true) + assert_equal 3, @cache.read("foo").to_i + assert_equal 2, @cache.decrement("foo") + assert_equal 2, @cache.read("foo").to_i + assert_equal 1, @cache.decrement("foo") + assert_equal 1, @cache.read("foo").to_i + assert_nil @cache.decrement("bar") end end module LocalCacheBehavior def test_local_writes_are_persistent_on_the_remote_cache retval = @cache.with_local_cache do - @cache.write('foo', 'bar') + @cache.write("foo", "bar") end assert retval - assert_equal 'bar', @cache.read('foo') + assert_equal "bar", @cache.read("foo") end def test_clear_also_clears_local_cache @cache.with_local_cache do - @cache.write('foo', 'bar') + @cache.write("foo", "bar") @cache.clear - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end - assert_nil @cache.read('foo') + assert_nil @cache.read("foo") end def test_local_cache_of_write @cache.with_local_cache do - @cache.write('foo', 'bar') - @peek.delete('foo') - assert_equal 'bar', @cache.read('foo') + @cache.write("foo", "bar") + @peek.delete("foo") + assert_equal "bar", @cache.read("foo") end end def test_local_cache_of_read - @cache.write('foo', 'bar') + @cache.write("foo", "bar") @cache.with_local_cache do - assert_equal 'bar', @cache.read('foo') + assert_equal "bar", @cache.read("foo") end end def test_local_cache_of_read_nil @cache.with_local_cache do - assert_equal nil, @cache.read('foo') - @cache.send(:bypass_local_cache) { @cache.write 'foo', 'bar' } - assert_equal nil, @cache.read('foo') + assert_equal nil, @cache.read("foo") + @cache.send(:bypass_local_cache) { @cache.write "foo", "bar" } + assert_equal nil, @cache.read("foo") end end def test_local_cache_fetch @cache.with_local_cache do - @cache.send(:local_cache).write 'foo', 'bar' - assert_equal 'bar', @cache.send(:local_cache).fetch('foo') + @cache.send(:local_cache).write "foo", "bar" + assert_equal "bar", @cache.send(:local_cache).fetch("foo") end end def test_local_cache_of_write_nil @cache.with_local_cache do - assert @cache.write('foo', nil) - assert_nil @cache.read('foo') - @peek.write('foo', 'bar') - assert_nil @cache.read('foo') + assert @cache.write("foo", nil) + assert_nil @cache.read("foo") + @peek.write("foo", "bar") + assert_nil @cache.read("foo") end end def test_local_cache_of_delete @cache.with_local_cache do - @cache.write('foo', 'bar') - @cache.delete('foo') - assert_nil @cache.read('foo') + @cache.write("foo", "bar") + @cache.delete("foo") + assert_nil @cache.read("foo") end end def test_local_cache_of_exist @cache.with_local_cache do - @cache.write('foo', 'bar') - @peek.delete('foo') - assert @cache.exist?('foo') + @cache.write("foo", "bar") + @peek.delete("foo") + assert @cache.exist?("foo") end end def test_local_cache_of_increment @cache.with_local_cache do - @cache.write('foo', 1, :raw => true) - @peek.write('foo', 2, :raw => true) - @cache.increment('foo') - assert_equal 3, @cache.read('foo') + @cache.write("foo", 1, raw: true) + @peek.write("foo", 2, raw: true) + @cache.increment("foo") + assert_equal 3, @cache.read("foo") end end def test_local_cache_of_decrement @cache.with_local_cache do - @cache.write('foo', 1, :raw => true) - @peek.write('foo', 3, :raw => true) - @cache.decrement('foo') - assert_equal 2, @cache.read('foo') + @cache.write("foo", 1, raw: true) + @peek.write("foo", 3, raw: true) + @cache.decrement("foo") + assert_equal 2, @cache.read("foo") end end def test_middleware app = lambda { |env| - result = @cache.write('foo', 'bar') - assert_equal 'bar', @cache.read('foo') # make sure 'foo' was written + result = @cache.write("foo", "bar") + assert_equal "bar", @cache.read("foo") # make sure 'foo' was written assert result [200, {}, []] } @@ -721,9 +751,9 @@ module LocalCacheBehavior def test_can_call_deprecated_set_cache_value @cache.with_local_cache do assert_deprecated "`set_cache_value` is deprecated" do - @cache.send(:set_cache_value, 1, 'foo', :ignored, {}) + @cache.send(:set_cache_value, 1, "foo", :ignored, {}) end - assert_equal 1, @cache.read('foo') + assert_equal 1, @cache.read("foo") end end end @@ -732,14 +762,14 @@ module AutoloadingCacheBehavior include DependenciesTestHelpers def test_simple_autoloading with_autoloading_fixtures do - @cache.write('foo', EM.new) + @cache.write("foo", EM.new) end remove_constants(:EM) ActiveSupport::Dependencies.clear with_autoloading_fixtures do - assert_kind_of EM, @cache.read('foo') + assert_kind_of EM, @cache.read("foo") end remove_constants(:EM) @@ -748,14 +778,14 @@ module AutoloadingCacheBehavior def test_two_classes_autoloading with_autoloading_fixtures do - @cache.write('foo', [EM.new, ClassFolder.new]) + @cache.write("foo", [EM.new, ClassFolder.new]) end remove_constants(:EM, :ClassFolder) ActiveSupport::Dependencies.clear with_autoloading_fixtures do - loaded = @cache.read('foo') + loaded = @cache.read("foo") assert_kind_of Array, loaded assert_equal 2, loaded.size assert_kind_of EM, loaded[0] @@ -770,9 +800,9 @@ end class FileStoreTest < ActiveSupport::TestCase def setup Dir.mkdir(cache_dir) unless File.exist?(cache_dir) - @cache = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60) - @peek = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60) - @cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), :expires_in => 60) + @cache = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, expires_in: 60) + @peek = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, expires_in: 60) + @cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), expires_in: 60) @buffer = StringIO.new @cache.logger = ActiveSupport::Logger.new(@buffer) @@ -784,7 +814,7 @@ class FileStoreTest < ActiveSupport::TestCase end def cache_dir - File.join(Dir.pwd, 'tmp_cache') + File.join(Dir.pwd, "tmp_cache") end include CacheStoreBehavior @@ -807,11 +837,6 @@ class FileStoreTest < ActiveSupport::TestCase @cache.clear end - def test_long_keys - @cache.write("a"*10000, 1) - assert_equal 1, @cache.read("a"*10000) - end - def test_long_uri_encoded_keys @cache.write("%"*870, 1) assert_equal 1, @cache.read("%"*870) @@ -834,7 +859,7 @@ class FileStoreTest < ActiveSupport::TestCase key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}" path = @cache.send(:normalize_key, key, {}) Dir::Tmpname.create(path) do |tmpname, n, opts| - assert File.basename(tmpname+'.lock').length <= 255, "Temp filename too long: #{File.basename(tmpname+'.lock').length}" + assert File.basename(tmpname+".lock").length <= 255, "Temp filename too long: #{File.basename(tmpname+'.lock').length}" end end @@ -843,28 +868,28 @@ class FileStoreTest < ActiveSupport::TestCase def test_key_transformation_max_filename_size key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}B" path = @cache.send(:normalize_key, key, {}) - assert path.split('/').all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE} - assert_equal 'B', File.basename(path) + assert path.split("/").all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE } + assert_equal "B", File.basename(path) end # If nothing has been stored in the cache, there is a chance the cache directory does not yet exist # Ensure delete_matched gracefully handles this case def test_delete_matched_when_cache_directory_does_not_exist assert_nothing_raised do - ActiveSupport::Cache::FileStore.new('/test/cache/directory').delete_matched(/does_not_exist/) + ActiveSupport::Cache::FileStore.new("/test/cache/directory").delete_matched(/does_not_exist/) end end def test_delete_does_not_delete_empty_parent_dir - sub_cache_dir = File.join(cache_dir, 'subdir/') + sub_cache_dir = File.join(cache_dir, "subdir/") sub_cache_store = ActiveSupport::Cache::FileStore.new(sub_cache_dir) assert_nothing_raised do - assert sub_cache_store.write('foo', 'bar') - assert sub_cache_store.delete('foo') + assert sub_cache_store.write("foo", "bar") + assert sub_cache_store.delete("foo") end assert File.exist?(cache_dir), "Parent of top level cache dir was deleted!" assert File.exist?(sub_cache_dir), "Top level cache dir was deleted!" - assert Dir.entries(sub_cache_dir).reject {|f| ActiveSupport::Cache::FileStore::EXCLUDED_DIRS.include?(f)}.empty? + assert Dir.entries(sub_cache_dir).reject { |f| ActiveSupport::Cache::FileStore::EXCLUDED_DIRS.include?(f) }.empty? end def test_log_exception_when_cache_read_fails @@ -876,14 +901,14 @@ class FileStoreTest < ActiveSupport::TestCase def test_cleanup_removes_all_expired_entries time = Time.now - @cache.write('foo', 'bar', expires_in: 10) - @cache.write('baz', 'qux') - @cache.write('quux', 'corge', expires_in: 20) + @cache.write("foo", "bar", expires_in: 10) + @cache.write("baz", "qux") + @cache.write("quux", "corge", expires_in: 20) Time.stub(:now, time + 15) do @cache.cleanup - assert_not @cache.exist?('foo') - assert @cache.exist?('baz') - assert @cache.exist?('quux') + assert_not @cache.exist?("foo") + assert @cache.exist?("baz") + assert @cache.exist?("quux") end end @@ -904,7 +929,7 @@ end class MemoryStoreTest < ActiveSupport::TestCase def setup @record_size = ActiveSupport::Cache.lookup_store(:memory_store).send(:cached_size, 1, ActiveSupport::Cache::Entry.new("aaaaaaaaaa")) - @cache = ActiveSupport::Cache.lookup_store(:memory_store, :expires_in => 60, :size => @record_size * 10 + 1) + @cache = ActiveSupport::Cache.lookup_store(:memory_store, expires_in: 60, size: @record_size * 10 + 1) end include CacheStoreBehavior @@ -964,7 +989,7 @@ class MemoryStoreTest < ActiveSupport::TestCase @cache.write(7, "gggggggggg") && sleep(0.001) @cache.write(8, "hhhhhhhhhh") && sleep(0.001) @cache.write(9, "iiiiiiiiii") && sleep(0.001) - long_key = '*' * 2 * @record_size + long_key = "*" * 2 * @record_size @cache.write(long_key, "llllllllll") assert @cache.exist?(long_key) assert @cache.exist?(9) @@ -998,18 +1023,18 @@ class MemoryStoreTest < ActiveSupport::TestCase def test_write_with_unless_exist assert_equal true, @cache.write(1, "aaaaaaaaaa") - assert_equal false, @cache.write(1, "aaaaaaaaaa", :unless_exist => true) + assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) @cache.write(1, nil) - assert_equal false, @cache.write(1, "aaaaaaaaaa", :unless_exist => true) + assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) end end class MemCacheStoreTest < ActiveSupport::TestCase - require 'dalli' + require "dalli" begin - ss = Dalli::Client.new('localhost:11211').stats - raise Dalli::DalliError unless ss['localhost:11211'] + ss = Dalli::Client.new("localhost:11211").stats + raise Dalli::DalliError unless ss["localhost:11211"] MEMCACHE_UP = true rescue Dalli::DalliError @@ -1020,7 +1045,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase def setup skip "memcache server is not up" unless MEMCACHE_UP - @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :expires_in => 60) + @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, expires_in: 60) @peek = ActiveSupport::Cache.lookup_store(:mem_cache_store) @data = @cache.instance_variable_get(:@data) @cache.clear @@ -1035,21 +1060,21 @@ class MemCacheStoreTest < ActiveSupport::TestCase include AutoloadingCacheBehavior def test_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.write("foo", 2) assert_equal "2", cache.read("foo") end def test_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.write("foo", Marshal.dump([])) assert_equal [], cache.read("foo") end def test_local_cache_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.with_local_cache do cache.write("foo", 2) @@ -1058,7 +1083,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase end def test_local_cache_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true) + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear cache.with_local_cache do cache.write("foo", Marshal.dump([])) @@ -1067,11 +1092,11 @@ class MemCacheStoreTest < ActiveSupport::TestCase end def test_read_should_return_a_different_object_id_each_time_it_is_called - @cache.write('foo', 'bar') - value = @cache.read('foo') - assert_not_equal value.object_id, @cache.read('foo').object_id - value << 'bingo' - assert_not_equal value, @cache.read('foo') + @cache.write("foo", "bar") + value = @cache.read("foo") + assert_not_equal value.object_id, @cache.read("foo").object_id + value << "bingo" + assert_not_equal value, @cache.read("foo") end def test_can_call_deprecated_escape_key @@ -1109,12 +1134,12 @@ class NullStoreTest < ActiveSupport::TestCase end def test_increment - @cache.write("name", 1, :raw => true) + @cache.write("name", 1, raw: true) assert_nil @cache.increment("name") end def test_decrement - @cache.write("name", 1, :raw => true) + @cache.write("name", 1, raw: true) assert_nil @cache.increment("name") end @@ -1144,12 +1169,12 @@ class CacheStoreLoggerTest < ActiveSupport::TestCase end def test_logging - @cache.fetch('foo') { 'bar' } + @cache.fetch("foo") { "bar" } assert @buffer.string.present? end def test_log_with_string_namespace - @cache.fetch('foo', {namespace: 'string_namespace'}) { 'bar' } + @cache.fetch("foo", namespace: "string_namespace") { "bar" } assert_match %r{string_namespace:foo}, @buffer.string end @@ -1157,12 +1182,12 @@ class CacheStoreLoggerTest < ActiveSupport::TestCase proc = Proc.new do "proc_namespace" end - @cache.fetch('foo', {:namespace => proc}) { 'bar' } + @cache.fetch("foo", namespace: proc) { "bar" } assert_match %r{proc_namespace:foo}, @buffer.string end def test_mute_logging - @cache.mute { @cache.fetch('foo') { 'bar' } } + @cache.mute { @cache.fetch("foo") { "bar" } } assert @buffer.string.blank? end end @@ -1170,17 +1195,17 @@ end class CacheEntryTest < ActiveSupport::TestCase def test_expired entry = ActiveSupport::Cache::Entry.new("value") - assert !entry.expired?, 'entry not expired' - entry = ActiveSupport::Cache::Entry.new("value", :expires_in => 60) - assert !entry.expired?, 'entry not expired' + assert !entry.expired?, "entry not expired" + entry = ActiveSupport::Cache::Entry.new("value", expires_in: 60) + assert !entry.expired?, "entry not expired" Time.stub(:now, Time.now + 61) do - assert entry.expired?, 'entry is expired' + assert entry.expired?, "entry is expired" end end def test_compress_values value = "value" * 100 - entry = ActiveSupport::Cache::Entry.new(value, :compress => true, :compress_threshold => 1) + entry = ActiveSupport::Cache::Entry.new(value, compress: true, compress_threshold: 1) assert_equal value, entry.value assert(value.bytesize > entry.size, "value is compressed") end diff --git a/activesupport/test/callback_inheritance_test.rb b/activesupport/test/callback_inheritance_test.rb index 1adfe4edf4..9e2f7527e0 100644 --- a/activesupport/test/callback_inheritance_test.rb +++ b/activesupport/test/callback_inheritance_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class GrandParent include ActiveSupport::Callbacks @@ -9,8 +9,8 @@ class GrandParent end define_callbacks :dispatch - set_callback :dispatch, :before, :before1, :before2, :if => proc {|c| c.action_name == "index" || c.action_name == "update" } - set_callback :dispatch, :after, :after1, :after2, :if => proc {|c| c.action_name == "update" || c.action_name == "delete" } + set_callback :dispatch, :before, :before1, :before2, if: proc { |c| c.action_name == "index" || c.action_name == "update" } + set_callback :dispatch, :after, :after1, :after2, if: proc { |c| c.action_name == "update" || c.action_name == "delete" } def before1 @log << "before1" @@ -37,12 +37,12 @@ class GrandParent end class Parent < GrandParent - skip_callback :dispatch, :before, :before2, :unless => proc {|c| c.action_name == "update" } - skip_callback :dispatch, :after, :after2, :unless => proc {|c| c.action_name == "delete" } + skip_callback :dispatch, :before, :before2, unless: proc { |c| c.action_name == "update" } + skip_callback :dispatch, :after, :after2, unless: proc { |c| c.action_name == "delete" } end class Child < GrandParent - skip_callback :dispatch, :before, :before2, :unless => proc {|c| c.action_name == "update" }, :if => :state_open? + skip_callback :dispatch, :before, :before2, unless: proc { |c| c.action_name == "update" }, if: :state_open? def state_open? @state == :open diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index a624473f46..783952c8c7 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module CallbacksTest class Record @@ -56,27 +56,31 @@ module CallbacksTest end class Person < Record + attr_accessor :save_fails + [:before_save, :after_save].each do |callback_method| callback_method_sym = callback_method.to_sym send(callback_method, callback_symbol(callback_method_sym)) ActiveSupport::Deprecation.silence { send(callback_method, callback_string(callback_method_sym)) } send(callback_method, callback_proc(callback_method_sym)) - send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, ''))) + send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, ""))) send(callback_method, CallbackClass) send(callback_method) { |model| model.history << [callback_method_sym, :block] } end def save - run_callbacks :save + run_callbacks :save do + raise "inside save" if save_fails + end end end class PersonSkipper < Person - skip_callback :save, :before, :before_save_method, :if => :yes - skip_callback :save, :after, :after_save_method, :unless => :yes - skip_callback :save, :after, :after_save_method, :if => :no - skip_callback :save, :before, :before_save_method, :unless => :no - skip_callback :save, :before, CallbackClass , :if => :yes + skip_callback :save, :before, :before_save_method, if: :yes + skip_callback :save, :after, :after_save_method, unless: :yes + skip_callback :save, :after, :after_save_method, if: :no + skip_callback :save, :before, :before_save_method, unless: :no + skip_callback :save, :before, CallbackClass , if: :yes def yes; true; end def no; false; end end @@ -89,7 +93,7 @@ module CallbacksTest define_callbacks :dispatch - set_callback :dispatch, :before, :log, :unless => proc {|c| c.action_name == :index || c.action_name == :show } + set_callback :dispatch, :before, :log, unless: proc { |c| c.action_name == :index || c.action_name == :show } set_callback :dispatch, :after, :log2 attr_reader :action_name, :logger @@ -114,7 +118,7 @@ module CallbacksTest end class Child < ParentController - skip_callback :dispatch, :before, :log, :if => proc {|c| c.action_name == :update} + skip_callback :dispatch, :before, :log, if: proc { |c| c.action_name == :update } skip_callback :dispatch, :after, :log2 end @@ -125,10 +129,10 @@ module CallbacksTest super end - before_save Proc.new {|r| r.history << [:before_save, :starts_true, :if] }, :if => :starts_true - before_save Proc.new {|r| r.history << [:before_save, :starts_false, :if] }, :if => :starts_false - before_save Proc.new {|r| r.history << [:before_save, :starts_true, :unless] }, :unless => :starts_true - before_save Proc.new {|r| r.history << [:before_save, :starts_false, :unless] }, :unless => :starts_false + before_save Proc.new { |r| r.history << [:before_save, :starts_true, :if] }, if: :starts_true + before_save Proc.new { |r| r.history << [:before_save, :starts_false, :if] }, if: :starts_false + before_save Proc.new { |r| r.history << [:before_save, :starts_true, :unless] }, unless: :starts_true + before_save Proc.new { |r| r.history << [:before_save, :starts_false, :unless] }, unless: :starts_false def starts_true if @@starts_true @@ -181,27 +185,25 @@ module CallbacksTest end end - - class ConditionalPerson < Record # proc - before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true } - before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false } - before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false } - before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true } + before_save Proc.new { |r| r.history << [:before_save, :proc] }, if: Proc.new { |r| true } + before_save Proc.new { |r| r.history << "b00m" }, if: Proc.new { |r| false } + before_save Proc.new { |r| r.history << [:before_save, :proc] }, unless: Proc.new { |r| false } + before_save Proc.new { |r| r.history << "b00m" }, unless: Proc.new { |r| true } # symbol - before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes - before_save Proc.new { |r| r.history << "b00m" }, :if => :no - before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no - before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes + before_save Proc.new { |r| r.history << [:before_save, :symbol] }, if: :yes + before_save Proc.new { |r| r.history << "b00m" }, if: :no + before_save Proc.new { |r| r.history << [:before_save, :symbol] }, unless: :no + before_save Proc.new { |r| r.history << "b00m" }, unless: :yes # string - before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes' - before_save Proc.new { |r| r.history << "b00m" }, :if => 'no' - before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no' - before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes' + before_save Proc.new { |r| r.history << [:before_save, :string] }, if: "yes" + before_save Proc.new { |r| r.history << "b00m" }, if: "no" + before_save Proc.new { |r| r.history << [:before_save, :string] }, unless: "no" + before_save Proc.new { |r| r.history << "b00m" }, unless: "yes" # Combined if and unless - before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no - before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes + before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, if: :yes, unless: :no + before_save Proc.new { |r| r.history << "b00m" }, if: :yes, unless: :yes def yes; true; end def other_yes; true; end @@ -224,19 +226,20 @@ module CallbacksTest class AroundPerson < MySuper attr_reader :history + attr_accessor :save_fails - set_callback :save, :before, :nope, :if => :no - set_callback :save, :before, :nope, :unless => :yes + set_callback :save, :before, :nope, if: :no + set_callback :save, :before, :nope, unless: :yes set_callback :save, :after, :tweedle ActiveSupport::Deprecation.silence { set_callback :save, :before, "tweedle_dee" } - set_callback :save, :before, proc {|m| m.history << "yup" } - set_callback :save, :before, :nope, :if => proc { false } - set_callback :save, :before, :nope, :unless => proc { true } - set_callback :save, :before, :yup, :if => proc { true } - set_callback :save, :before, :yup, :unless => proc { false } + set_callback :save, :before, proc { |m| m.history << "yup" } + set_callback :save, :before, :nope, if: proc { false } + set_callback :save, :before, :nope, unless: proc { true } + set_callback :save, :before, :yup, if: proc { true } + set_callback :save, :before, :yup, unless: proc { false } set_callback :save, :around, :tweedle_dum - set_callback :save, :around, :w0tyes, :if => :yes - set_callback :save, :around, :w0tno, :if => :no + set_callback :save, :around, :w0tyes, if: :yes + set_callback :save, :around, :w0tno, if: :no set_callback :save, :around, :tweedle_deedle def no; false; end @@ -287,6 +290,7 @@ module CallbacksTest def save run_callbacks :save do + raise "inside save" if save_fails @history << "running" end end @@ -323,7 +327,7 @@ module CallbacksTest define_callbacks :save attr_reader :stuff - set_callback :save, :before, :action, :if => :yes + set_callback :save, :before, :action, if: :yes def yes() true end @@ -361,7 +365,6 @@ module CallbacksTest end class ExtendCallbacks - include ActiveSupport::Callbacks define_callbacks :save @@ -405,6 +408,71 @@ module CallbacksTest end end + class CallStackTest < ActiveSupport::TestCase + def test_tidy_call_stack + around = AroundPerson.new + around.save_fails = true + + exception = (around.save rescue $!) + + # Make sure we have the exception we're expecting + assert_equal "inside save", exception.message + + call_stack = exception.backtrace_locations + call_stack.pop caller_locations(0).size + + # Yes, this looks like an implementation test, but it's the least + # obtuse way of asserting that there aren't a load of entries in + # the call stack for each callback. + # + # If you've renamed a method, or squeezed more lines out, go ahead + # and update this assertion. But if you're here because a + # refactoring added new lines, please reconsider. + + # As shown here, our current budget is one line for run_callbacks + # itself, plus N+1 lines where N is the number of :around + # callbacks that have been invoked, if there are any (plus + # whatever the callbacks do themselves, of course). + + assert_equal [ + "block in save", + "block in run_callbacks", + "tweedle_deedle", + "block in run_callbacks", + "w0tyes", + "block in run_callbacks", + "tweedle_dum", + "block in run_callbacks", + ("call" if RUBY_VERSION < "2.3"), + "run_callbacks", + "save" + ].compact, call_stack.map(&:label) + end + + def test_short_call_stack + person = Person.new + person.save_fails = true + + exception = (person.save rescue $!) + + # Make sure we have the exception we're expecting + assert_equal "inside save", exception.message + + call_stack = exception.backtrace_locations + call_stack.pop caller_locations(0).size + + # This budget much simpler: with no :around callbacks invoked, + # there should be just one line. run_callbacks yields directly + # back to its caller. + + assert_equal [ + "block in save", + "run_callbacks", + "save" + ], call_stack.map(&:label) + end + end + class AroundCallbackResultTest < ActiveSupport::TestCase def test_save_around around = AroundPersonResult.new @@ -453,7 +521,6 @@ module CallbacksTest end class CallbacksTest < ActiveSupport::TestCase - def test_save_person person = Person.new assert_equal [], person.history @@ -491,8 +558,6 @@ module CallbacksTest end end - - class ResetCallbackTest < ActiveSupport::TestCase def test_save_conditional_person person = CleanPerson.new @@ -637,7 +702,7 @@ module CallbacksTest class CustomScopeObject include ActiveSupport::Callbacks - define_callbacks :save, :scope => [:kind, :name] + define_callbacks :save, scope: [:kind, :name] set_callback :save, :before, CallbackObject.new attr_accessor :record @@ -810,7 +875,7 @@ module CallbacksTest class WriterSkipper < Person attr_accessor :age - skip_callback :save, :before, :before_save_method, :if => lambda {self.age > 21} + skip_callback :save, :before, :before_save_method, if: -> { age > 21 } end class WriterCallbacksTest < ActiveSupport::TestCase @@ -885,7 +950,7 @@ module CallbacksTest def test_proc_arity_2 assert_raises(ArgumentError) do - klass = build_class(->(x,y) { }) + klass = build_class(->(x,y) {}) klass.new.run end end @@ -903,7 +968,7 @@ module CallbacksTest Class.new { include ActiveSupport::Callbacks define_callbacks :foo - set_callback :foo, :before, :foo, :if => callback + set_callback :foo, :before, :foo, if: callback def foo; end def run; run_callbacks :foo; end } @@ -918,8 +983,8 @@ module CallbacksTest } klass = Class.new { include ActiveSupport::Callbacks - define_callbacks :foo, :scope => [:name] - set_callback :foo, :before, :foo, :if => callback + define_callbacks :foo, scope: [:name] + set_callback :foo, :before, :foo, if: callback def run; run_callbacks :foo; end private def foo; end @@ -964,7 +1029,7 @@ module CallbacksTest def test_proc_arity2 assert_raises(ArgumentError) do - object = build_class(->(a,b) { }).new + object = build_class(->(a,b) {}).new object.run end end diff --git a/activesupport/test/class_cache_test.rb b/activesupport/test/class_cache_test.rb index b96f476ce6..c618fea81a 100644 --- a/activesupport/test/class_cache_test.rb +++ b/activesupport/test/class_cache_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/dependencies' +require "abstract_unit" +require "active_support/dependencies" module ActiveSupport module Dependencies diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb index 05580352a9..5ed518cdb0 100644 --- a/activesupport/test/clean_backtrace_test.rb +++ b/activesupport/test/clean_backtrace_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' +require "abstract_unit" class BacktraceCleanerFilterTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new - @bc.add_filter { |line| line.gsub("/my/prefix", '') } + @bc.add_filter { |line| line.gsub("/my/prefix", "") } end test "backtrace should filter all lines in a backtrace, removing prefixes" do @@ -20,13 +20,12 @@ class BacktraceCleanerFilterTest < ActiveSupport::TestCase test "backtrace should contain unaltered lines if they dont match a filter" do assert_equal "/my/other_prefix/my/class.rb", @bc.clean([ "/my/other_prefix/my/class.rb" ]).first end - end class BacktraceCleanerSilencerTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new - @bc.add_silencer { |line| line =~ /mongrel/ } + @bc.add_silencer { |line| line.include?("mongrel") } end test "backtrace should not contain lines that match the silencer" do @@ -44,8 +43,8 @@ end class BacktraceCleanerMultipleSilencersTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new - @bc.add_silencer { |line| line =~ /mongrel/ } - @bc.add_silencer { |line| line =~ /yolo/ } + @bc.add_silencer { |line| line.include?("mongrel") } + @bc.add_silencer { |line| line.include?("yolo") } end test "backtrace should not contain lines that match the silencers" do @@ -66,7 +65,7 @@ class BacktraceCleanerFilterAndSilencerTest < ActiveSupport::TestCase def setup @bc = ActiveSupport::BacktraceCleaner.new @bc.add_filter { |line| line.gsub("/mongrel", "") } - @bc.add_silencer { |line| line =~ /mongrel/ } + @bc.add_silencer { |line| line.include?("mongrel") } end test "backtrace should not silence lines that has first had their silence hook filtered out" do diff --git a/activesupport/test/clean_logger_test.rb b/activesupport/test/clean_logger_test.rb index 02693a97dc..cf37fc5639 100644 --- a/activesupport/test/clean_logger_test.rb +++ b/activesupport/test/clean_logger_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'stringio' -require 'active_support/logger' +require "abstract_unit" +require "stringio" +require "active_support/logger" class CleanLoggerTest < ActiveSupport::TestCase def setup @@ -9,14 +9,14 @@ class CleanLoggerTest < ActiveSupport::TestCase end def test_format_message - @logger.error 'error' + @logger.error "error" assert_equal "error\n", @out.string end def test_datetime_format @logger.formatter = Logger::Formatter.new @logger.formatter.datetime_format = "%Y-%m-%d" - @logger.debug 'debug' + @logger.debug "debug" assert_equal "%Y-%m-%d", @logger.formatter.datetime_format assert_match(/D, \[\d\d\d\d-\d\d-\d\d#\d+\] DEBUG -- : debug/, @out.string) end diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb index 8ea701cfb7..95507c815d 100644 --- a/activesupport/test/concern_test.rb +++ b/activesupport/test/concern_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/concern' +require "abstract_unit" +require "active_support/concern" class ConcernTest < ActiveSupport::TestCase module Baz @@ -66,13 +66,13 @@ class ConcernTest < ActiveSupport::TestCase def test_module_is_included_normally @klass.include(Baz) assert_equal "baz", @klass.new.baz - assert @klass.included_modules.include?(ConcernTest::Baz) + assert_includes @klass.included_modules, ConcernTest::Baz end def test_class_methods_are_extended @klass.include(Baz) assert_equal "baz", @klass.baz - assert_equal ConcernTest::Baz::ClassMethods, (class << @klass; self.included_modules; end)[0] + assert_equal ConcernTest::Baz::ClassMethods, (class << @klass; included_modules; end)[0] end def test_class_methods_are_extended_only_on_expected_objects @@ -105,7 +105,7 @@ class ConcernTest < ActiveSupport::TestCase assert_equal "bar", @klass.new.bar assert_equal "bar+baz", @klass.new.baz assert_equal "bar's baz + baz", @klass.baz - assert @klass.included_modules.include?(ConcernTest::Bar) + assert_includes @klass.included_modules, ConcernTest::Bar end def test_dependencies_with_multiple_modules diff --git a/activesupport/test/configurable_test.rb b/activesupport/test/configurable_test.rb index 5d22ded2de..3cd6d2d4d0 100644 --- a/activesupport/test/configurable_test.rb +++ b/activesupport/test/configurable_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/configurable' +require "abstract_unit" +require "active_support/configurable" class ConfigurableActiveSupport < ActiveSupport::TestCase class Parent @@ -111,7 +111,7 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase end end - test 'the config_accessor method should not be publicly callable' do + test "the config_accessor method should not be publicly callable" do assert_raises NoMethodError do Class.new { include ActiveSupport::Configurable @@ -121,11 +121,11 @@ class ConfigurableActiveSupport < ActiveSupport::TestCase def assert_method_defined(object, method) methods = object.public_methods.map(&:to_s) - assert methods.include?(method.to_s), "Expected #{methods.inspect} to include #{method.to_s.inspect}" + assert_includes methods, method.to_s, "Expected #{methods.inspect} to include #{method.to_s.inspect}" end def assert_method_not_defined(object, method) methods = object.public_methods.map(&:to_s) - assert !methods.include?(method.to_s), "Expected #{methods.inspect} to not include #{method.to_s.inspect}" + assert_not_includes methods, method.to_s, "Expected #{methods.inspect} to not include #{method.to_s.inspect}" end end diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 1115bc0fd8..af2db8c991 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -1,4 +1,4 @@ -require 'dependencies_test_helpers' +require "dependencies_test_helpers" module Ace module Base @@ -100,10 +100,10 @@ module ConstantizeTestCases assert_nil yield("Ace::Gas::ConstantizeTestCases") assert_nil yield("#<Class:0x7b8b718b>::Nested_1") assert_nil yield("Ace::gas") - assert_nil yield('Object::ABC') - assert_nil yield('Object::Object::Object::ABC') - assert_nil yield('A::Object::B') - assert_nil yield('A::Object::Object::Object::B') + assert_nil yield("Object::ABC") + assert_nil yield("Object::Object::Object::ABC") + assert_nil yield("A::Object::B") + assert_nil yield("A::Object::Object::Object::B") assert_raises(NameError) do with_autoloading_fixtures do diff --git a/activesupport/test/core_ext/array/access_test.rb b/activesupport/test/core_ext/array/access_test.rb index 1d834667f0..a38ea36d00 100644 --- a/activesupport/test/core_ext/array/access_test.rb +++ b/activesupport/test/core_ext/array/access_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class AccessTest < ActiveSupport::TestCase def test_from diff --git a/activesupport/test/core_ext/array/conversions_test.rb b/activesupport/test/core_ext/array/conversions_test.rb index de36e2026d..469efcd934 100644 --- a/activesupport/test/core_ext/array/conversions_test.rb +++ b/activesupport/test/core_ext/array/conversions_test.rb @@ -1,37 +1,42 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' -require 'active_support/core_ext/big_decimal' -require 'active_support/core_ext/hash' -require 'active_support/core_ext/string' +require "abstract_unit" +require "active_support/core_ext/array" +require "active_support/core_ext/big_decimal" +require "active_support/core_ext/hash" +require "active_support/core_ext/string" class ToSentenceTest < ActiveSupport::TestCase def test_plain_array_to_sentence assert_equal "", [].to_sentence - assert_equal "one", ['one'].to_sentence - assert_equal "one and two", ['one', 'two'].to_sentence - assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence + assert_equal "one", ["one"].to_sentence + assert_equal "one and two", ["one", "two"].to_sentence + assert_equal "one, two, and three", ["one", "two", "three"].to_sentence end def test_to_sentence_with_words_connector - assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(words_connector: ' ') - assert_equal "one & two, and three", ['one', 'two', 'three'].to_sentence(words_connector: ' & ') - assert_equal "onetwo, and three", ['one', 'two', 'three'].to_sentence(words_connector: nil) + assert_equal "one two, and three", ["one", "two", "three"].to_sentence(words_connector: " ") + assert_equal "one & two, and three", ["one", "two", "three"].to_sentence(words_connector: " & ") + assert_equal "onetwo, and three", ["one", "two", "three"].to_sentence(words_connector: nil) end def test_to_sentence_with_last_word_connector - assert_equal "one, two, and also three", ['one', 'two', 'three'].to_sentence(last_word_connector: ', and also ') - assert_equal "one, twothree", ['one', 'two', 'three'].to_sentence(last_word_connector: nil) - assert_equal "one, two three", ['one', 'two', 'three'].to_sentence(last_word_connector: ' ') - assert_equal "one, two and three", ['one', 'two', 'three'].to_sentence(last_word_connector: ' and ') + assert_equal "one, two, and also three", ["one", "two", "three"].to_sentence(last_word_connector: ", and also ") + assert_equal "one, twothree", ["one", "two", "three"].to_sentence(last_word_connector: nil) + assert_equal "one, two three", ["one", "two", "three"].to_sentence(last_word_connector: " ") + assert_equal "one, two and three", ["one", "two", "three"].to_sentence(last_word_connector: " and ") + end + + def test_to_sentence_with_fallback_string + assert_equal "none", [].to_sentence(fallback_string: "none") + assert_equal "one, two, and three", ["one", "two", "three"].to_sentence(fallback_string: "none") end def test_two_elements - assert_equal "one and two", ['one', 'two'].to_sentence - assert_equal "one two", ['one', 'two'].to_sentence(two_words_connector: ' ') + assert_equal "one and two", ["one", "two"].to_sentence + assert_equal "one two", ["one", "two"].to_sentence(two_words_connector: " ") end def test_one_element - assert_equal "one", ['one'].to_sentence + assert_equal "one", ["one"].to_sentence end def test_one_element_not_same_object @@ -40,31 +45,31 @@ class ToSentenceTest < ActiveSupport::TestCase end def test_one_non_string_element - assert_equal '1', [1].to_sentence + assert_equal "1", [1].to_sentence end def test_does_not_modify_given_hash - options = { words_connector: ' ' } - assert_equal "one two, and three", ['one', 'two', 'three'].to_sentence(options) - assert_equal({ words_connector: ' ' }, options) + options = { words_connector: " " } + assert_equal "one two, and three", ["one", "two", "three"].to_sentence(options) + assert_equal({ words_connector: " " }, options) end def test_with_blank_elements - assert_equal ", one, , two, and three", [nil, 'one', '', 'two', 'three'].to_sentence + assert_equal ", one, , two, and three", [nil, "one", "", "two", "three"].to_sentence end def test_with_invalid_options exception = assert_raise ArgumentError do - ['one', 'two'].to_sentence(passing: 'invalid option') + ["one", "two"].to_sentence(passing: "invalid option") end - assert_equal exception.message, "Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale" + assert_equal exception.message, "Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale, :fallback_string" end def test_always_returns_string - assert_instance_of String, [ActiveSupport::SafeBuffer.new('one')].to_sentence - assert_instance_of String, [ActiveSupport::SafeBuffer.new('one'), 'two'].to_sentence - assert_instance_of String, [ActiveSupport::SafeBuffer.new('one'), 'two', 'three'].to_sentence + assert_instance_of String, [ActiveSupport::SafeBuffer.new("one")].to_sentence + assert_instance_of String, [ActiveSupport::SafeBuffer.new("one"), "two"].to_sentence + assert_instance_of String, [ActiveSupport::SafeBuffer.new("one"), "two", "three"].to_sentence end end @@ -88,32 +93,32 @@ class ToXmlTest < ActiveSupport::TestCase def test_to_xml_with_hash_elements xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } ].to_xml(skip_instruct: true, indent: 0) assert_equal '<objects type="array"><object>', xml.first(30) - assert xml.include?(%(<age type="integer">26</age>)), xml - assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)), xml - assert xml.include?(%(<name>David</name>)), xml - assert xml.include?(%(<age type="integer">31</age>)), xml - assert xml.include?(%(<age-in-millis type="decimal">1.0</age-in-millis>)), xml - assert xml.include?(%(<name>Jason</name>)), xml + assert_includes xml, %(<age type="integer">26</age>), xml + assert_includes xml, %(<age-in-millis type="integer">820497600000</age-in-millis>), xml + assert_includes xml, %(<name>David</name>), xml + assert_includes xml, %(<age type="integer">31</age>), xml + assert_includes xml, %(<age-in-millis type="decimal">1.0</age-in-millis>), xml + assert_includes xml, %(<name>Jason</name>), xml end def test_to_xml_with_non_hash_elements xml = %w[1 2 3].to_xml(skip_instruct: true, indent: 0) assert_equal '<strings type="array"><string', xml.first(29) - assert xml.include?(%(<string>2</string>)), xml + assert_includes xml, %(<string>2</string>), xml end def test_to_xml_with_non_hash_different_type_elements - xml = [1, 2.0, '3'].to_xml(skip_instruct: true, indent: 0) + xml = [1, 2.0, "3"].to_xml(skip_instruct: true, indent: 0) assert_equal '<objects type="array"><object', xml.first(29) - assert xml.include?(%(<object type="integer">1</object>)), xml - assert xml.include?(%(<object type="float">2.0</object>)), xml - assert xml.include?(%(object>3</object>)), xml + assert_includes xml, %(<object type="integer">1</object>), xml + assert_includes xml, %(<object type="float">2.0</object>), xml + assert_includes xml, %(object>3</object>), xml end def test_to_xml_with_dedicated_name @@ -130,10 +135,10 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 0) assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street-address>Paulina</street-address>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<street-address>Evergreen</street-address>)) - assert xml.include?(%(<name>Jason</name>)) + assert_includes xml, %(<street-address>Paulina</street-address>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<street-address>Evergreen</street-address>) + assert_includes xml, %(<name>Jason</name>) end def test_to_xml_with_indent_set @@ -142,10 +147,10 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 4) assert_equal "<objects>\n <object>", xml.first(22) - assert xml.include?(%(\n <street-address>Paulina</street-address>)) - assert xml.include?(%(\n <name>David</name>)) - assert xml.include?(%(\n <street-address>Evergreen</street-address>)) - assert xml.include?(%(\n <name>Jason</name>)) + assert_includes xml, %(\n <street-address>Paulina</street-address>) + assert_includes xml, %(\n <name>David</name>) + assert_includes xml, %(\n <street-address>Evergreen</street-address>) + assert_includes xml, %(\n <name>Jason</name>) end def test_to_xml_with_dasherize_false @@ -154,8 +159,8 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 0, dasherize: false) assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street_address>Paulina</street_address>)) - assert xml.include?(%(<street_address>Evergreen</street_address>)) + assert_includes xml, %(<street_address>Paulina</street_address>) + assert_includes xml, %(<street_address>Evergreen</street_address>) end def test_to_xml_with_dasherize_true @@ -164,14 +169,14 @@ class ToXmlTest < ActiveSupport::TestCase ].to_xml(skip_instruct: true, skip_types: true, indent: 0, dasherize: true) assert_equal "<objects><object>", xml.first(17) - assert xml.include?(%(<street-address>Paulina</street-address>)) - assert xml.include?(%(<street-address>Evergreen</street-address>)) + assert_includes xml, %(<street-address>Paulina</street-address>) + assert_includes xml, %(<street-address>Evergreen</street-address>) end def test_to_xml_with_instruct xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } ].to_xml(skip_instruct: false, indent: 0) assert_match(/^<\?xml [^>]*/, xml) @@ -181,12 +186,12 @@ class ToXmlTest < ActiveSupport::TestCase def test_to_xml_with_block xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new('1.0') } + { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } ].to_xml(skip_instruct: true, indent: 0) do |builder| builder.count 2 end - assert xml.include?(%(<count>2</count>)), xml + assert_includes xml, %(<count>2</count>), xml end def test_to_xml_with_empty diff --git a/activesupport/test/core_ext/array/extract_options_test.rb b/activesupport/test/core_ext/array/extract_options_test.rb index 0481a507cf..1651bee0f6 100644 --- a/activesupport/test/core_ext/array/extract_options_test.rb +++ b/activesupport/test/core_ext/array/extract_options_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' -require 'active_support/core_ext/hash' +require "abstract_unit" +require "active_support/core_ext/array" +require "active_support/core_ext/hash" class ExtractOptionsTest < ActiveSupport::TestCase class HashSubclass < Hash diff --git a/activesupport/test/core_ext/array/grouping_test.rb b/activesupport/test/core_ext/array/grouping_test.rb index 0682241f0b..b06f87c008 100644 --- a/activesupport/test/core_ext/array/grouping_test.rb +++ b/activesupport/test/core_ext/array/grouping_test.rb @@ -1,39 +1,39 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class GroupingTest < ActiveSupport::TestCase def setup # In Ruby < 2.4, test we avoid Integer#/ (redefined by mathn) - Fixnum.send :private, :/ unless Fixnum == Integer + Fixnum.send :private, :/ unless 0.class == Integer end def teardown - Fixnum.send :public, :/ unless Fixnum == Integer + Fixnum.send :public, :/ unless 0.class == Integer end def test_in_groups_of_with_perfect_fit groups = [] - ('a'..'i').to_a.in_groups_of(3) do |group| + ("a".."i").to_a.in_groups_of(3) do |group| groups << group end assert_equal [%w(a b c), %w(d e f), %w(g h i)], groups - assert_equal [%w(a b c), %w(d e f), %w(g h i)], ('a'..'i').to_a.in_groups_of(3) + assert_equal [%w(a b c), %w(d e f), %w(g h i)], ("a".."i").to_a.in_groups_of(3) end def test_in_groups_of_with_padding groups = [] - ('a'..'g').to_a.in_groups_of(3) do |group| + ("a".."g").to_a.in_groups_of(3) do |group| groups << group end - assert_equal [%w(a b c), %w(d e f), ['g', nil, nil]], groups + assert_equal [%w(a b c), %w(d e f), ["g", nil, nil]], groups end def test_in_groups_of_pads_with_specified_values groups = [] - ('a'..'g').to_a.in_groups_of(3, 'foo') do |group| + ("a".."g").to_a.in_groups_of(3, "foo") do |group| groups << group end @@ -43,7 +43,7 @@ class GroupingTest < ActiveSupport::TestCase def test_in_groups_of_without_padding groups = [] - ('a'..'g').to_a.in_groups_of(3, false) do |group| + ("a".."g").to_a.in_groups_of(3, false) do |group| groups << group end @@ -83,8 +83,8 @@ class GroupingTest < ActiveSupport::TestCase assert_equal [[1, 2, 3], [4, 5, nil], [6, 7, nil]], array.in_groups(3) - assert_equal [[1, 2, 3], [4, 5, 'foo'], [6, 7, 'foo']], - array.in_groups(3, 'foo') + assert_equal [[1, 2, 3], [4, 5, "foo"], [6, 7, "foo"]], + array.in_groups(3, "foo") end def test_in_groups_without_padding diff --git a/activesupport/test/core_ext/array/prepend_append_test.rb b/activesupport/test/core_ext/array/prepend_append_test.rb index 762aa69b2b..763e26191d 100644 --- a/activesupport/test/core_ext/array/prepend_append_test.rb +++ b/activesupport/test/core_ext/array/prepend_append_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class PrependAppendTest < ActiveSupport::TestCase def test_append diff --git a/activesupport/test/core_ext/array/wrap_test.rb b/activesupport/test/core_ext/array/wrap_test.rb index baf426506f..ae846cb3f2 100644 --- a/activesupport/test/core_ext/array/wrap_test.rb +++ b/activesupport/test/core_ext/array/wrap_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' +require "abstract_unit" +require "active_support/core_ext/array" class WrapTest < ActiveSupport::TestCase class FakeCollection diff --git a/activesupport/test/core_ext/bigdecimal_test.rb b/activesupport/test/core_ext/bigdecimal_test.rb index 6e82e3892b..43b659546f 100644 --- a/activesupport/test/core_ext/bigdecimal_test.rb +++ b/activesupport/test/core_ext/bigdecimal_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' -require 'active_support/core_ext/big_decimal' +require "abstract_unit" +require "active_support/core_ext/big_decimal" class BigDecimalTest < ActiveSupport::TestCase def test_to_s - bd = BigDecimal.new '0.01' - assert_equal '0.01', bd.to_s - assert_equal '+0.01', bd.to_s('+F') - assert_equal '+0.0 1', bd.to_s('+1F') + bd = BigDecimal.new "0.01" + assert_equal "0.01", bd.to_s + assert_equal "+0.01", bd.to_s("+F") + assert_equal "+0.0 1", bd.to_s("+1F") end end diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb index e7a1334db3..5a9ec78cc1 100644 --- a/activesupport/test/core_ext/class/attribute_test.rb +++ b/activesupport/test/core_ext/class/attribute_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/class/attribute' +require "abstract_unit" +require "active_support/core_ext/class/attribute" class ClassAttributeTest < ActiveSupport::TestCase def setup @@ -7,17 +7,17 @@ class ClassAttributeTest < ActiveSupport::TestCase @sub = Class.new(@klass) end - test 'defaults to nil' do + test "defaults to nil" do assert_nil @klass.setting assert_nil @sub.setting end - test 'inheritable' do + test "inheritable" do @klass.setting = 1 assert_equal 1, @sub.setting end - test 'overridable' do + test "overridable" do @sub.setting = 1 assert_nil @klass.setting @@ -27,20 +27,20 @@ class ClassAttributeTest < ActiveSupport::TestCase assert_equal 1, Class.new(@sub).setting end - test 'predicate method' do + test "predicate method" do assert_equal false, @klass.setting? @klass.setting = 1 assert_equal true, @klass.setting? end - test 'instance reader delegates to class' do + test "instance reader delegates to class" do assert_nil @klass.new.setting @klass.setting = 1 assert_equal 1, @klass.new.setting end - test 'instance override' do + test "instance override" do object = @klass.new object.setting = 1 assert_nil @klass.setting @@ -48,43 +48,43 @@ class ClassAttributeTest < ActiveSupport::TestCase assert_equal 1, object.setting end - test 'instance predicate' do + test "instance predicate" do object = @klass.new assert_equal false, object.setting? object.setting = 1 assert_equal true, object.setting? end - test 'disabling instance writer' do - object = Class.new { class_attribute :setting, :instance_writer => false }.new - assert_raise(NoMethodError) { object.setting = 'boom' } + test "disabling instance writer" do + object = Class.new { class_attribute :setting, instance_writer: false }.new + assert_raise(NoMethodError) { object.setting = "boom" } end - test 'disabling instance reader' do - object = Class.new { class_attribute :setting, :instance_reader => false }.new + test "disabling instance reader" do + object = Class.new { class_attribute :setting, instance_reader: false }.new assert_raise(NoMethodError) { object.setting } assert_raise(NoMethodError) { object.setting? } end - test 'disabling both instance writer and reader' do - object = Class.new { class_attribute :setting, :instance_accessor => false }.new + test "disabling both instance writer and reader" do + object = Class.new { class_attribute :setting, instance_accessor: false }.new assert_raise(NoMethodError) { object.setting } assert_raise(NoMethodError) { object.setting? } - assert_raise(NoMethodError) { object.setting = 'boom' } + assert_raise(NoMethodError) { object.setting = "boom" } end - test 'disabling instance predicate' do + test "disabling instance predicate" do object = Class.new { class_attribute :setting, instance_predicate: false }.new assert_raise(NoMethodError) { object.setting? } end - test 'works well with singleton classes' do + test "works well with singleton classes" do object = @klass.new - object.singleton_class.setting = 'foo' - assert_equal 'foo', object.setting + object.singleton_class.setting = "foo" + assert_equal "foo", object.setting end - test 'setter returns set value' do + test "setter returns set value" do val = @klass.send(:setting=, 1) assert_equal 1, val end diff --git a/activesupport/test/core_ext/class_test.rb b/activesupport/test/core_ext/class_test.rb index 9c6c579ef7..a9c44907cc 100644 --- a/activesupport/test/core_ext/class_test.rb +++ b/activesupport/test/core_ext/class_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/class' -require 'set' +require "abstract_unit" +require "active_support/core_ext/class" +require "set" class ClassTest < ActiveSupport::TestCase class Parent; end diff --git a/activesupport/test/core_ext/date_and_time_behavior.rb b/activesupport/test/core_ext/date_and_time_behavior.rb index 54df87def8..6cc9781e02 100644 --- a/activesupport/test/core_ext/date_and_time_behavior.rb +++ b/activesupport/test/core_ext/date_and_time_behavior.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module DateAndTimeBehavior def test_yesterday @@ -126,7 +126,9 @@ module DateAndTimeBehavior end def test_next_week_at_same_time - assert_equal date_time_init(2005,2,28,15,15,10), date_time_init(2005,2,22,15,15,10).next_week(:monday, same_time: true) + assert_equal date_time_init(2005,2,28,15,15,10), date_time_init(2005,2,22,15,15,10).next_week(:monday, same_time: true) + assert_equal date_time_init(2005,2,28,15,15,10,999999), date_time_init(2005,2,22,15,15,10,999999).next_week(:monday, same_time: true) + assert_equal date_time_init(2005,2,28,15,15,10,Rational(999999999, 1000)), date_time_init(2005,2,22,15,15,10,Rational(999999999, 1000)).next_week(:monday, same_time: true) assert_equal date_time_init(2005,3,4,15,15,10), date_time_init(2005,2,22,15,15,10).next_week(:friday, same_time: true) assert_equal date_time_init(2006,10,30,0,0,0), date_time_init(2006,10,23,0,0,0).next_week(:monday, same_time: true) assert_equal date_time_init(2006,11,1,0,0,0), date_time_init(2006,10,23,0,0,0).next_week(:wednesday, same_time: true) diff --git a/activesupport/test/core_ext/date_and_time_compatibility_test.rb b/activesupport/test/core_ext/date_and_time_compatibility_test.rb index 11cb1469da..180b3e12aa 100644 --- a/activesupport/test/core_ext/date_and_time_compatibility_test.rb +++ b/activesupport/test/core_ext/date_and_time_compatibility_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/time' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/time" +require "time_zone_test_helpers" class DateAndTimeCompatibilityTest < ActiveSupport::TestCase include TimeZoneTestHelpers @@ -10,12 +10,12 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase @date_time = DateTime.new(2016, 4, 23, 14, 11, 12, 0) @utc_offset = 3600 @system_offset = -14400 - @zone = ActiveSupport::TimeZone['London'] + @zone = ActiveSupport::TimeZone["London"] end def test_time_to_time_preserves_timezone with_preserve_timezone(true) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = Time.new(2016, 4, 23, 15, 11, 12, 3600).to_time assert_instance_of Time, time @@ -27,7 +27,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_time_to_time_does_not_preserve_time_zone with_preserve_timezone(false) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = Time.new(2016, 4, 23, 15, 11, 12, 3600).to_time assert_instance_of Time, time @@ -39,7 +39,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_datetime_to_time_preserves_timezone with_preserve_timezone(true) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1,24)).to_time assert_instance_of Time, time @@ -51,7 +51,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_datetime_to_time_does_not_preserve_time_zone with_preserve_timezone(false) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1,24)).to_time assert_instance_of Time, time @@ -63,7 +63,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_twz_to_time_preserves_timezone with_preserve_timezone(true) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = ActiveSupport::TimeWithZone.new(@utc_time, @zone).to_time assert_instance_of Time, time @@ -83,7 +83,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_twz_to_time_does_not_preserve_time_zone with_preserve_timezone(false) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = ActiveSupport::TimeWithZone.new(@utc_time, @zone).to_time assert_instance_of Time, time @@ -103,7 +103,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_string_to_time_preserves_timezone with_preserve_timezone(true) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = "2016-04-23T15:11:12+01:00".to_time assert_instance_of Time, time @@ -115,7 +115,7 @@ class DateAndTimeCompatibilityTest < ActiveSupport::TestCase def test_string_to_time_does_not_preserve_time_zone with_preserve_timezone(false) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = "2016-04-23T15:11:12+01:00".to_time assert_instance_of Time, time diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index a7219eee31..0655197335 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'core_ext/date_and_time_behavior' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/time" +require "core_ext/date_and_time_behavior" +require "time_zone_test_helpers" class DateExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,*args) @@ -47,7 +47,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_to_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time, Date.new(2005, 2, 21).to_time.class assert_equal Time.local(2005, 2, 21), Date.new(2005, 2, 21).to_time assert_equal Time.local(2005, 2, 21).utc_offset, Date.new(2005, 2, 21).to_time.utc_offset @@ -81,10 +81,10 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_change - assert_equal Date.new(2005, 2, 21), Date.new(2005, 2, 11).change(:day => 21) - assert_equal Date.new(2007, 5, 11), Date.new(2005, 2, 11).change(:year => 2007, :month => 5) - assert_equal Date.new(2006,2,22), Date.new(2005,2,22).change(:year => 2006) - assert_equal Date.new(2005,6,22), Date.new(2005,2,22).change(:month => 6) + assert_equal Date.new(2005, 2, 21), Date.new(2005, 2, 11).change(day: 21) + assert_equal Date.new(2007, 5, 11), Date.new(2005, 2, 11).change(year: 2007, month: 5) + assert_equal Date.new(2006,2,22), Date.new(2005,2,22).change(year: 2006) + assert_equal Date.new(2005,6,22), Date.new(2005,2,22).change(month: 6) end def test_sunday @@ -139,34 +139,34 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_advance - assert_equal Date.new(2006,2,28), Date.new(2005,2,28).advance(:years => 1) - assert_equal Date.new(2005,6,28), Date.new(2005,2,28).advance(:months => 4) - assert_equal Date.new(2005,3,21), Date.new(2005,2,28).advance(:weeks => 3) - assert_equal Date.new(2005,3,5), Date.new(2005,2,28).advance(:days => 5) - assert_equal Date.new(2012,9,28), Date.new(2005,2,28).advance(:years => 7, :months => 7) - assert_equal Date.new(2013,10,3), Date.new(2005,2,28).advance(:years => 7, :months => 19, :days => 5) - assert_equal Date.new(2013,10,17), Date.new(2005,2,28).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Date.new(2005,2,28), Date.new(2004,2,29).advance(:years => 1) #leap day plus one year + assert_equal Date.new(2006,2,28), Date.new(2005,2,28).advance(years: 1) + assert_equal Date.new(2005,6,28), Date.new(2005,2,28).advance(months: 4) + assert_equal Date.new(2005,3,21), Date.new(2005,2,28).advance(weeks: 3) + assert_equal Date.new(2005,3,5), Date.new(2005,2,28).advance(days: 5) + assert_equal Date.new(2012,9,28), Date.new(2005,2,28).advance(years: 7, months: 7) + assert_equal Date.new(2013,10,3), Date.new(2005,2,28).advance(years: 7, months: 19, days: 5) + assert_equal Date.new(2013,10,17), Date.new(2005,2,28).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Date.new(2005,2,28), Date.new(2004,2,29).advance(years: 1) #leap day plus one year end def test_advance_does_first_years_and_then_days - assert_equal Date.new(2012, 2, 29), Date.new(2011, 2, 28).advance(:years => 1, :days => 1) + assert_equal Date.new(2012, 2, 29), Date.new(2011, 2, 28).advance(years: 1, days: 1) # If day was done first we would jump to 2012-03-01 instead. end def test_advance_does_first_months_and_then_days - assert_equal Date.new(2010, 3, 29), Date.new(2010, 2, 28).advance(:months => 1, :days => 1) + assert_equal Date.new(2010, 3, 29), Date.new(2010, 2, 28).advance(months: 1, days: 1) # If day was done first we would jump to 2010-04-01 instead. end def test_advance_in_calendar_reform - assert_equal Date.new(1582,10,15), Date.new(1582,10,4).advance(:days => 1) - assert_equal Date.new(1582,10,4), Date.new(1582,10,15).advance(:days => -1) + assert_equal Date.new(1582,10,15), Date.new(1582,10,4).advance(days: 1) + assert_equal Date.new(1582,10,4), Date.new(1582,10,15).advance(days: -1) 5.upto(14) do |day| - assert_equal Date.new(1582,10,4), Date.new(1582,9,day).advance(:months => 1) - assert_equal Date.new(1582,10,4), Date.new(1582,11,day).advance(:months => -1) - assert_equal Date.new(1582,10,4), Date.new(1581,10,day).advance(:years => 1) - assert_equal Date.new(1582,10,4), Date.new(1583,10,day).advance(:years => -1) + assert_equal Date.new(1582,10,4), Date.new(1582,9,day).advance(months: 1) + assert_equal Date.new(1582,10,4), Date.new(1582,11,day).advance(months: -1) + assert_equal Date.new(1582,10,4), Date.new(1581,10,day).advance(years: 1) + assert_equal Date.new(1582,10,4), Date.new(1583,10,day).advance(years: -1) end end @@ -196,7 +196,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_yesterday_constructor_when_zone_is_not_set - with_env_tz 'UTC' do + with_env_tz "UTC" do with_tz_default do assert_equal(Date.today - 1, Date.yesterday) end @@ -204,8 +204,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_yesterday_constructor_when_zone_is_set - with_env_tz 'UTC' do - with_tz_default ActiveSupport::TimeZone['Eastern Time (US & Canada)'] do # UTC -5 + with_env_tz "UTC" do + with_tz_default ActiveSupport::TimeZone["Eastern Time (US & Canada)"] do # UTC -5 Time.stub(:now, Time.local(2000, 1, 1)) do assert_equal Date.new(1999, 12, 30), Date.yesterday end @@ -218,7 +218,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_tomorrow_constructor_when_zone_is_not_set - with_env_tz 'UTC' do + with_env_tz "UTC" do with_tz_default do assert_equal(Date.today + 1, Date.tomorrow) end @@ -226,8 +226,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_tomorrow_constructor_when_zone_is_set - with_env_tz 'UTC' do - with_tz_default ActiveSupport::TimeZone['Europe/Paris'] do # UTC +1 + with_env_tz "UTC" do + with_tz_default ActiveSupport::TimeZone["Europe/Paris"] do # UTC +1 Time.stub(:now, Time.local(1999, 12, 31, 23)) do assert_equal Date.new(2000, 1, 2), Date.tomorrow end @@ -240,8 +240,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_since_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,21,0,0,45), Date.new(2005,2,21).since(45) assert_equal zone, Date.new(2005,2,21).since(45).time_zone @@ -254,8 +254,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_ago_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,20,23,59,15), Date.new(2005,2,21).ago(45) assert_equal zone, Date.new(2005,2,21).ago(45).time_zone @@ -272,8 +272,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_beginning_of_day_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,21,0,0,0), Date.new(2005,2,21).beginning_of_day assert_equal zone, Date.new(2005,2,21).beginning_of_day.time_zone @@ -286,8 +286,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_end_of_day_when_zone_is_set - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'UTC' do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "UTC" do with_tz_default zone do assert_equal zone.local(2005,2,21,23,59,59,Rational(999999999, 1000)), Date.new(2005,2,21).end_of_day assert_equal zone, Date.new(2005,2,21).end_of_day.time_zone @@ -330,7 +330,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_xmlschema - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema) assert_match(/^1980-06-28T00:00:00-04:?00$/, Date.new(1980, 6, 28).xmlschema) # these tests are only of interest on platforms where older dates #to_time fail over to DateTime @@ -342,8 +342,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_xmlschema_when_zone_is_set - with_env_tz 'UTC' do - with_tz_default ActiveSupport::TimeZone['Eastern Time (US & Canada)'] do # UTC -5 + with_env_tz "UTC" do + with_tz_default ActiveSupport::TimeZone["Eastern Time (US & Canada)"] do # UTC -5 assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema) assert_match(/^1980-06-28T00:00:00-04:?00$/, Date.new(1980, 6, 28).xmlschema) end @@ -367,7 +367,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_date_today_when_zone_not_set - with_env_tz 'US/Central' do + with_env_tz "US/Central" do Time.stub(:now, Time.local(1999, 12, 31, 23)) do assert_equal Date.today, Date.current end @@ -375,8 +375,8 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_time_zone_today_when_zone_is_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Central' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Central" do assert_equal ::Time.zone.today, Date.current end ensure @@ -384,9 +384,9 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_date_advance_should_not_change_passed_options_hash - options = { :years => 3, :months => 11, :days => 2 } + options = { years: 3, months: 11, days: 2 } Date.new(2005,2,28).advance(options) - assert_equal({ :years => 3, :months => 11, :days => 2 }, options) + assert_equal({ years: 3, months: 11, days: 2 }, options) end end @@ -407,4 +407,3 @@ class DateExtBehaviorTest < ActiveSupport::TestCase end end end - diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 306316efcd..f2a50f4693 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'core_ext/date_and_time_behavior' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/time" +require "core_ext/date_and_time_behavior" +require "time_zone_test_helpers" class DateTimeExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,hour,minute,second,*args) @@ -35,13 +35,13 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_custom_date_format - Time::DATE_FORMATS[:custom] = '%Y%m%d%H%M%S' - assert_equal '20050221143000', DateTime.new(2005, 2, 21, 14, 30, 0).to_s(:custom) + Time::DATE_FORMATS[:custom] = "%Y%m%d%H%M%S" + assert_equal "20050221143000", DateTime.new(2005, 2, 21, 14, 30, 0).to_s(:custom) Time::DATE_FORMATS.delete(:custom) end def test_localtime - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_instance_of Time, DateTime.new(2016, 3, 11, 15, 11, 12, 0).localtime assert_equal Time.local(2016, 3, 11, 10, 11, 12), DateTime.new(2016, 3, 11, 15, 11, 12, 0).localtime assert_equal Time.local(2016, 3, 21, 11, 11, 12), DateTime.new(2016, 3, 21, 15, 11, 12, 0).localtime @@ -50,7 +50,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_getlocal - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_instance_of Time, DateTime.new(2016, 3, 11, 15, 11, 12, 0).getlocal assert_equal Time.local(2016, 3, 11, 10, 11, 12), DateTime.new(2016, 3, 11, 15, 11, 12, 0).getlocal assert_equal Time.local(2016, 3, 21, 11, 11, 12), DateTime.new(2016, 3, 21, 15, 11, 12, 0).getlocal @@ -67,7 +67,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_to_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_instance_of Time, DateTime.new(2005, 2, 21, 10, 11, 12, 0).to_time if ActiveSupport.to_time_preserves_timezone @@ -159,47 +159,47 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_change - assert_equal DateTime.civil(2006,2,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:year => 2006) - assert_equal DateTime.civil(2005,6,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:month => 6) - assert_equal DateTime.civil(2012,9,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:year => 2012, :month => 9) - assert_equal DateTime.civil(2005,2,22,16), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16) - assert_equal DateTime.civil(2005,2,22,16,45), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16, :min => 45) - assert_equal DateTime.civil(2005,2,22,15,45), DateTime.civil(2005,2,22,15,15,10).change(:min => 45) + assert_equal DateTime.civil(2006,2,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(year: 2006) + assert_equal DateTime.civil(2005,6,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(month: 6) + assert_equal DateTime.civil(2012,9,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(year: 2012, month: 9) + assert_equal DateTime.civil(2005,2,22,16), DateTime.civil(2005,2,22,15,15,10).change(hour: 16) + assert_equal DateTime.civil(2005,2,22,16,45), DateTime.civil(2005,2,22,15,15,10).change(hour: 16, min: 45) + assert_equal DateTime.civil(2005,2,22,15,45), DateTime.civil(2005,2,22,15,15,10).change(min: 45) # datetime with fractions of a second - assert_equal DateTime.civil(2005,2,1,15,15,10.7), DateTime.civil(2005,2,22,15,15,10.7).change(:day => 1) + assert_equal DateTime.civil(2005,2,1,15,15,10.7), DateTime.civil(2005,2,22,15,15,10.7).change(day: 1) end def test_advance - assert_equal DateTime.civil(2006,2,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 1) - assert_equal DateTime.civil(2005,6,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:months => 4) - assert_equal DateTime.civil(2005,3,21,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:weeks => 3) - assert_equal DateTime.civil(2005,3,5,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:days => 5) - assert_equal DateTime.civil(2012,9,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 7) - assert_equal DateTime.civil(2013,10,3,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :days => 5) - assert_equal DateTime.civil(2013,10,17,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal DateTime.civil(2001,12,27,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1) - assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year - assert_equal DateTime.civil(2005,2,28,20,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:hours => 5) - assert_equal DateTime.civil(2005,2,28,15,22,10), DateTime.civil(2005,2,28,15,15,10).advance(:minutes => 7) - assert_equal DateTime.civil(2005,2,28,15,15,19), DateTime.civil(2005,2,28,15,15,10).advance(:seconds => 9) - assert_equal DateTime.civil(2005,2,28,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal DateTime.civil(2005,2,28,10,8,1), DateTime.civil(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal DateTime.civil(2013,10,17,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal DateTime.civil(2006,2,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 1) + assert_equal DateTime.civil(2005,6,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(months: 4) + assert_equal DateTime.civil(2005,3,21,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(weeks: 3) + assert_equal DateTime.civil(2005,3,5,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(days: 5) + assert_equal DateTime.civil(2012,9,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 7) + assert_equal DateTime.civil(2013,10,3,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 19, days: 5) + assert_equal DateTime.civil(2013,10,17,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal DateTime.civil(2001,12,27,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(years: -3, months: -2, days: -1) + assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10).advance(years: 1) #leap day plus one year + assert_equal DateTime.civil(2005,2,28,20,15,10), DateTime.civil(2005,2,28,15,15,10).advance(hours: 5) + assert_equal DateTime.civil(2005,2,28,15,22,10), DateTime.civil(2005,2,28,15,15,10).advance(minutes: 7) + assert_equal DateTime.civil(2005,2,28,15,15,19), DateTime.civil(2005,2,28,15,15,10).advance(seconds: 9) + assert_equal DateTime.civil(2005,2,28,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(hours: 5, minutes: 7, seconds: 9) + assert_equal DateTime.civil(2005,2,28,10,8,1), DateTime.civil(2005,2,28,15,15,10).advance(hours: -5, minutes: -7, seconds: -9) + assert_equal DateTime.civil(2013,10,17,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_advance_partial_days - assert_equal DateTime.civil(2012,9,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 1.5) - assert_equal DateTime.civil(2012,9,28,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 0.5) - assert_equal DateTime.civil(2012,10,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(:days => 1.5, :months => 1) + assert_equal DateTime.civil(2012,9,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(days: 1.5) + assert_equal DateTime.civil(2012,9,28,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(days: 0.5) + assert_equal DateTime.civil(2012,10,29,13,15,10), DateTime.civil(2012,9,28,1,15,10).advance(days: 1.5, months: 1) end def test_advanced_processes_first_the_date_deltas_and_then_the_time_deltas # If the time deltas were processed first, the following datetimes would be advanced to 2010/04/01 instead. - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59, 59).advance(:months => 1, :seconds => 1) - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59).advance(:months => 1, :minutes => 1) - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23).advance(:months => 1, :hours => 1) - assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 22, 58, 59).advance(:months => 1, :hours => 1, :minutes => 1, :seconds => 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59, 59).advance(months: 1, seconds: 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23, 59).advance(months: 1, minutes: 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 23).advance(months: 1, hours: 1) + assert_equal DateTime.civil(2010, 3, 29), DateTime.civil(2010, 2, 28, 22, 58, 59).advance(months: 1, hours: 1, minutes: 1, seconds: 1) end def test_last_week @@ -282,7 +282,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_date_today_when_zone_is_not_set - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(1999, 12, 31, 23, 59, 59)) do assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current end @@ -290,8 +290,8 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_current_returns_time_zone_today_when_zone_is_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Eastern' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(1999, 12, 31, 23, 59, 59)) do assert_equal DateTime.new(1999, 12, 31, 23, 59, 59, Rational(-18000, 86400)), DateTime.current end @@ -305,7 +305,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_current_with_time_zone - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_kind_of DateTime, DateTime.current end end @@ -343,15 +343,15 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_formatted_offset_with_utc - assert_equal '+00:00', DateTime.civil(2000).formatted_offset - assert_equal '+0000', DateTime.civil(2000).formatted_offset(false) - assert_equal 'UTC', DateTime.civil(2000).formatted_offset(true, 'UTC') + assert_equal "+00:00", DateTime.civil(2000).formatted_offset + assert_equal "+0000", DateTime.civil(2000).formatted_offset(false) + assert_equal "UTC", DateTime.civil(2000).formatted_offset(true, "UTC") end def test_formatted_offset_with_local dt = DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-5, 24)) - assert_equal '-05:00', dt.formatted_offset - assert_equal '-0500', dt.formatted_offset(false) + assert_equal "-05:00", dt.formatted_offset + assert_equal "-0500", dt.formatted_offset(false) end def test_compare_with_time @@ -367,9 +367,9 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end def test_compare_with_time_with_zone - assert_equal 1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] ) - assert_equal 0, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] ) - assert_equal(-1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] )) + assert_equal 1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone["UTC"] ) + assert_equal 0, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"] ) + assert_equal(-1, DateTime.civil(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone["UTC"] )) end def test_compare_with_string diff --git a/activesupport/test/core_ext/digest/uuid_test.rb b/activesupport/test/core_ext/digest/uuid_test.rb index 08e0a1d6e1..866a03259a 100644 --- a/activesupport/test/core_ext/digest/uuid_test.rb +++ b/activesupport/test/core_ext/digest/uuid_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/digest/uuid' +require "abstract_unit" +require "active_support/core_ext/digest/uuid" class DigestUUIDExt < ActiveSupport::TestCase def test_v3_uuids @@ -18,7 +18,7 @@ class DigestUUIDExt < ActiveSupport::TestCase def test_invalid_hash_class assert_raise ArgumentError do - Digest::UUID.uuid_from_hash(Digest::SHA2, Digest::UUID::OID_NAMESPACE, '1.2.3') + Digest::UUID.uuid_from_hash(Digest::SHA2, Digest::UUID::OID_NAMESPACE, "1.2.3") end end end diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index 502e2811fa..a881768470 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' -require 'active_support/inflector' -require 'active_support/time' -require 'active_support/json' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/inflector" +require "active_support/time" +require "active_support/json" +require "time_zone_test_helpers" class DurationTest < ActiveSupport::TestCase include TimeZoneTestHelpers @@ -29,14 +29,14 @@ class DurationTest < ActiveSupport::TestCase def test_threequals assert ActiveSupport::Duration === 1.day assert !(ActiveSupport::Duration === 1.day.to_i) - assert !(ActiveSupport::Duration === 'foo') + assert !(ActiveSupport::Duration === "foo") end def test_equals assert 1.day == 1.day assert 1.day == 1.day.to_i assert 1.day.to_i == 1.day - assert !(1.day == 'foo') + assert !(1.day == "foo") end def test_to_s @@ -54,28 +54,28 @@ class DurationTest < ActiveSupport::TestCase assert !1.eql?(1.second) assert 1.minute.eql?(180.seconds - 2.minutes) assert !1.minute.eql?(60) - assert !1.minute.eql?('foo') + assert !1.minute.eql?("foo") end def test_inspect - assert_equal '0 seconds', 0.seconds.inspect - assert_equal '1 month', 1.month.inspect - assert_equal '1 month and 1 day', (1.month + 1.day).inspect - assert_equal '6 months and -2 days', (6.months - 2.days).inspect - assert_equal '10 seconds', 10.seconds.inspect - assert_equal '10 years, 2 months, and 1 day', (10.years + 2.months + 1.day).inspect - assert_equal '10 years, 2 months, and 1 day', (10.years + 1.month + 1.day + 1.month).inspect - assert_equal '10 years, 2 months, and 1 day', (1.day + 10.years + 2.months).inspect - assert_equal '7 days', 7.days.inspect - assert_equal '1 week', 1.week.inspect - assert_equal '2 weeks', 1.fortnight.inspect + assert_equal "0 seconds", 0.seconds.inspect + assert_equal "1 month", 1.month.inspect + assert_equal "1 month and 1 day", (1.month + 1.day).inspect + assert_equal "6 months and -2 days", (6.months - 2.days).inspect + assert_equal "10 seconds", 10.seconds.inspect + assert_equal "10 years, 2 months, and 1 day", (10.years + 2.months + 1.day).inspect + assert_equal "10 years, 2 months, and 1 day", (10.years + 1.month + 1.day + 1.month).inspect + assert_equal "10 years, 2 months, and 1 day", (1.day + 10.years + 2.months).inspect + assert_equal "7 days", 7.days.inspect + assert_equal "1 week", 1.week.inspect + assert_equal "2 weeks", 1.fortnight.inspect end def test_inspect_locale current_locale = I18n.default_locale I18n.default_locale = :de - I18n.backend.store_translations(:de, { support: { array: { last_word_connector: ' und ' } } }) - assert_equal '10 years, 1 month und 1 day', (10.years + 1.month + 1.day).inspect + I18n.backend.store_translations(:de, support: { array: { last_word_connector: " und " } }) + assert_equal "10 years, 1 month und 1 day", (10.years + 1.month + 1.day).inspect ensure I18n.default_locale = current_locale end @@ -89,7 +89,7 @@ class DurationTest < ActiveSupport::TestCase end def test_time_plus_duration_returns_same_time_datatype - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Moscow'] , Time.utc(2016,4,28,00,45)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Moscow"] , Time.utc(2016,4,28,00,45)) now = Time.now.utc %w( second minute hour day week month year ).each do |unit| assert_equal((now + 1.send(unit)).class, Time, "Time + 1.#{unit} must be Time") @@ -99,7 +99,7 @@ class DurationTest < ActiveSupport::TestCase def test_argument_error e = assert_raise ArgumentError do - 1.second.ago('') + 1.second.ago("") end assert_equal 'expected a time or date, got ""', e.message, "ensure ArgumentError is not being raised by dependencies.rb" end @@ -149,7 +149,7 @@ class DurationTest < ActiveSupport::TestCase def test_since_and_ago_anchored_to_time_now_when_time_zone_is_not_set Time.zone = nil - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do # since assert_not_instance_of ActiveSupport::TimeWithZone, 5.seconds.since @@ -162,17 +162,17 @@ class DurationTest < ActiveSupport::TestCase end def test_since_and_ago_anchored_to_time_zone_now_when_time_zone_is_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Eastern' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do # since assert_instance_of ActiveSupport::TimeWithZone, 5.seconds.since assert_equal Time.utc(2000,1,1,0,0,5), 5.seconds.since.time - assert_equal 'Eastern Time (US & Canada)', 5.seconds.since.time_zone.name + assert_equal "Eastern Time (US & Canada)", 5.seconds.since.time_zone.name # ago assert_instance_of ActiveSupport::TimeWithZone, 5.seconds.ago assert_equal Time.utc(1999,12,31,23,59,55), 5.seconds.ago.time - assert_equal 'Eastern Time (US & Canada)', 5.seconds.ago.time_zone.name + assert_equal "Eastern Time (US & Canada)", 5.seconds.ago.time_zone.name end end ensure @@ -180,13 +180,13 @@ class DurationTest < ActiveSupport::TestCase end def test_adding_hours_across_dst_boundary - with_env_tz 'CET' do + with_env_tz "CET" do assert_equal Time.local(2009,3,29,0,0,0) + 24.hours, Time.local(2009,3,30,1,0,0) end end def test_adding_day_across_dst_boundary - with_env_tz 'CET' do + with_env_tz "CET" do assert_equal Time.local(2009,3,29,0,0,0) + 1.day, Time.local(2009,3,30,0,0,0) end end @@ -194,7 +194,7 @@ class DurationTest < ActiveSupport::TestCase def test_delegation_with_block_works counter = 0 assert_nothing_raised do - 1.minute.times {counter += 1} + 1.minute.times { counter += 1 } end assert_equal counter, 60 end @@ -204,11 +204,15 @@ class DurationTest < ActiveSupport::TestCase end def test_to_json - assert_equal '172800', 2.days.to_json + assert_equal "172800", 2.days.to_json end def test_case_when - cased = case 1.day when 1.day then "ok" end + cased = \ + case 1.day + when 1.day + "ok" + end assert_equal cased, "ok" end @@ -260,7 +264,7 @@ class DurationTest < ActiveSupport::TestCase # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. def test_iso8601_parsing_wrong_patterns_with_raise - invalid_patterns = ['', 'P', 'PT', 'P1YT', 'T', 'PW', 'P1Y1W', '~P1Y', '.P1Y', 'P1.5Y0.5M', 'P1.5Y1M', 'P1.5MT10.5S'] + invalid_patterns = ["", "P", "PT", "P1YT", "T", "PW", "P1Y1W", "~P1Y", ".P1Y", "P1.5Y0.5M", "P1.5Y1M", "P1.5MT10.5S"] invalid_patterns.each do |pattern| assert_raise ActiveSupport::Duration::ISO8601Parser::ParsingError, pattern.inspect do ActiveSupport::Duration.parse(pattern) @@ -270,15 +274,16 @@ class DurationTest < ActiveSupport::TestCase def test_iso8601_output expectations = [ - ['P1Y', 1.year ], - ['P1W', 1.week ], - ['P1Y1M', 1.year + 1.month ], - ['P1Y1M1D', 1.year + 1.month + 1.day ], - ['-P1Y1D', -1.year - 1.day ], - ['P1Y-1DT-1S', 1.year - 1.day - 1.second ], # Parts with different signs are exists in PostgreSQL interval datatype. - ['PT1S', 1.second ], - ['PT1.4S', (1.4).seconds ], - ['P1Y1M1DT1H', 1.year + 1.month + 1.day + 1.hour], + ["P1Y", 1.year ], + ["P1W", 1.week ], + ["P1Y1M", 1.year + 1.month ], + ["P1Y1M1D", 1.year + 1.month + 1.day ], + ["-P1Y1D", -1.year - 1.day ], + ["P1Y-1DT-1S", 1.year - 1.day - 1.second ], # Parts with different signs are exists in PostgreSQL interval datatype. + ["PT1S", 1.second ], + ["PT1.4S", (1.4).seconds ], + ["P1Y1M1DT1H", 1.year + 1.month + 1.day + 1.hour], + ["PT0S", 0.minutes ], ] expectations.each do |expected_output, duration| assert_equal expected_output, duration.iso8601, expected_output.inspect @@ -287,17 +292,17 @@ class DurationTest < ActiveSupport::TestCase def test_iso8601_output_precision expectations = [ - [nil, 'P1Y1MT5.55S', 1.year + 1.month + (5.55).seconds ], - [0, 'P1Y1MT6S', 1.year + 1.month + (5.55).seconds ], - [1, 'P1Y1MT5.5S', 1.year + 1.month + (5.55).seconds ], - [2, 'P1Y1MT5.55S', 1.year + 1.month + (5.55).seconds ], - [3, 'P1Y1MT5.550S', 1.year + 1.month + (5.55).seconds ], - [nil, 'PT1S', 1.second ], - [2, 'PT1.00S', 1.second ], - [nil, 'PT1.4S', (1.4).seconds ], - [0, 'PT1S', (1.4).seconds ], - [1, 'PT1.4S', (1.4).seconds ], - [5, 'PT1.40000S', (1.4).seconds ], + [nil, "P1Y1MT5.55S", 1.year + 1.month + (5.55).seconds ], + [0, "P1Y1MT6S", 1.year + 1.month + (5.55).seconds ], + [1, "P1Y1MT5.5S", 1.year + 1.month + (5.55).seconds ], + [2, "P1Y1MT5.55S", 1.year + 1.month + (5.55).seconds ], + [3, "P1Y1MT5.550S", 1.year + 1.month + (5.55).seconds ], + [nil, "PT1S", 1.second ], + [2, "PT1.00S", 1.second ], + [nil, "PT1.4S", (1.4).seconds ], + [0, "PT1S", (1.4).seconds ], + [1, "PT1.4S", (1.4).seconds ], + [5, "PT1.40000S", (1.4).seconds ], ] expectations.each do |precision, expected_output, duration| assert_equal expected_output, duration.iso8601(precision: precision), expected_output.inspect diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 99c3236c35..9072957e0e 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/array' -require 'active_support/core_ext/enumerable' +require "abstract_unit" +require "active_support/core_ext/array" +require "active_support/core_ext/enumerable" Payment = Struct.new(:price) ExpandedPayment = Struct.new(:dollars, :cents) @@ -33,8 +33,8 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal 60, enum.sum { |i| i * 2 } enum = GenericEnumerable.new(%w(a b c)) - assert_equal 'abc', enum.sum - assert_equal 'aabbcc', enum.sum { |i| i * 2 } + assert_equal "abc", enum.sum + assert_equal "aabbcc", enum.sum { |i| i * 2 } payments = GenericEnumerable.new([ Payment.new(5), Payment.new(15), Payment.new(10) ]) assert_equal 30, payments.sum(&:price) @@ -75,7 +75,7 @@ class EnumerableTests < ActiveSupport::TestCase assert_typed_equal(2.0, sum.real, Float) assert_typed_equal(3.0, sum.imag, Float) - sum = GenericEnumerable.new([1, 2]).sum(10) {|v| v * 2 } + sum = GenericEnumerable.new([1, 2]).sum(10) { |v| v * 2 } assert_typed_equal(16, sum, Integer) end @@ -102,7 +102,7 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal 10, (1..4).sum assert_equal 10, (1..4.5).sum assert_equal 6, (1...4).sum - assert_equal 'abc', ('a'..'c').sum + assert_equal "abc", ("a".."c").sum assert_equal 50_000_005_000_000, (0..10_000_000).sum assert_equal 0, (10..0).sum assert_equal 5, (10..0).sum(5) @@ -120,8 +120,8 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal 60, enum.sum { |i| i * 2 } enum = %w(a b c) - assert_equal 'abc', enum.sum - assert_equal 'aabbcc', enum.sum { |i| i * 2 } + assert_equal "abc", enum.sum + assert_equal "aabbcc", enum.sum { |i| i * 2 } payments = [ Payment.new(5), Payment.new(15), Payment.new(10) ] assert_equal 30, payments.sum(&:price) @@ -162,7 +162,7 @@ class EnumerableTests < ActiveSupport::TestCase assert_typed_equal(2.0, sum.real, Float) assert_typed_equal(3.0, sum.imag, Float) - sum = [1, 2].sum(10) {|v| v * 2 } + sum = [1, 2].sum(10) { |v| v * 2 } assert_typed_equal(16, sum, Integer) end @@ -184,17 +184,17 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal false, GenericEnumerable.new([ 1 ] ).many? assert_equal true, GenericEnumerable.new([ 1, 2 ] ).many? - assert_equal false, GenericEnumerable.new([] ).many? {|x| x > 1 } - assert_equal false, GenericEnumerable.new([ 2 ] ).many? {|x| x > 1 } - assert_equal false, GenericEnumerable.new([ 1, 2 ] ).many? {|x| x > 1 } - assert_equal true, GenericEnumerable.new([ 1, 2, 2 ]).many? {|x| x > 1 } + assert_equal false, GenericEnumerable.new([] ).many? { |x| x > 1 } + assert_equal false, GenericEnumerable.new([ 2 ] ).many? { |x| x > 1 } + assert_equal false, GenericEnumerable.new([ 1, 2 ] ).many? { |x| x > 1 } + assert_equal true, GenericEnumerable.new([ 1, 2, 2 ]).many? { |x| x > 1 } end def test_many_iterates_only_on_what_is_needed infinity = 1.0/0.0 very_long_enum = 0..infinity assert_equal true, very_long_enum.many? - assert_equal true, very_long_enum.many?{|x| x > 100} + assert_equal true, very_long_enum.many? { |x| x > 100 } end def test_exclude? @@ -206,7 +206,7 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal [1, 2, 4], GenericEnumerable.new((1..5).to_a).without(3, 5) assert_equal [1, 2, 4], (1..5).to_a.without(3, 5) assert_equal [1, 2, 4], (1..5).to_set.without(3, 5) - assert_equal({foo: 1, baz: 3}, {foo: 1, bar: 2, baz: 3}.without(:bar)) + assert_equal({ foo: 1, baz: 3 }, { foo: 1, bar: 2, baz: 3 }.without(:bar)) end def test_pluck diff --git a/activesupport/test/core_ext/file_test.rb b/activesupport/test/core_ext/file_test.rb index cde0132b97..df5d09acd0 100644 --- a/activesupport/test/core_ext/file_test.rb +++ b/activesupport/test/core_ext/file_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/file' +require "abstract_unit" +require "active_support/core_ext/file" class AtomicWriteTest < ActiveSupport::TestCase def test_atomic_write_without_errors diff --git a/activesupport/test/core_ext/hash/transform_keys_test.rb b/activesupport/test/core_ext/hash/transform_keys_test.rb index 962d3a30b6..7a11d827f8 100644 --- a/activesupport/test/core_ext/hash/transform_keys_test.rb +++ b/activesupport/test/core_ext/hash/transform_keys_test.rb @@ -1,62 +1,62 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash/keys' +require "abstract_unit" +require "active_support/core_ext/hash/keys" class TransformKeysTest < ActiveSupport::TestCase test "transform_keys returns a new hash with the keys computed from the block" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_keys { |k| "#{k}!".to_sym } - assert_equal({ a: 'a', b: 'b' }, original) - assert_equal({ a!: 'a', b!: 'b' }, mapped) + assert_equal({ a: "a", b: "b" }, original) + assert_equal({ a!: "a", b!: "b" }, mapped) end test "transform_keys! modifies the keys of the original" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_keys! { |k| "#{k}!".to_sym } - assert_equal({ a!: 'a', b!: 'b' }, original) + assert_equal({ a!: "a", b!: "b" }, original) assert_same original, mapped end test "transform_keys returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_keys assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_keys! returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_keys! assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_keys is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_keys.with_index { |k, i| [k, i].join.to_sym } - assert_equal({ a0: 'a', b1: 'b' }, mapped) + assert_equal({ a0: "a", b1: "b" }, mapped) end test "transform_keys! is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } original.transform_keys!.with_index { |k, i| [k, i].join.to_sym } - assert_equal({ a0: 'a', b1: 'b' }, original) + assert_equal({ a0: "a", b1: "b" }, original) end test "transform_keys returns a Hash instance when self is inherited from Hash" do class HashDescendant < ::Hash def initialize(elements = nil) super(elements) - (elements || {}).each_pair{ |key, value| self[key] = value } + (elements || {}).each_pair { |key, value| self[key] = value } end end - original = HashDescendant.new({ a: 'a', b: 'b' }) + original = HashDescendant.new(a: "a", b: "b") mapped = original.transform_keys { |k| "#{k}!".to_sym } - assert_equal({ a: 'a', b: 'b' }, original) - assert_equal({ a!: 'a', b!: 'b' }, mapped) + assert_equal({ a: "a", b: "b" }, original) + assert_equal({ a!: "a", b!: "b" }, mapped) assert_equal(::Hash, mapped.class) end end diff --git a/activesupport/test/core_ext/hash/transform_values_test.rb b/activesupport/test/core_ext/hash/transform_values_test.rb index 114022fbaf..f2ac4ce6ce 100644 --- a/activesupport/test/core_ext/hash/transform_values_test.rb +++ b/activesupport/test/core_ext/hash/transform_values_test.rb @@ -1,75 +1,75 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/hash/transform_values' +require "abstract_unit" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/hash/transform_values" class TransformValuesTest < ActiveSupport::TestCase test "transform_values returns a new hash with the values computed from the block" do - original = { a: 'a', b: 'b' } - mapped = original.transform_values { |v| v + '!' } + original = { a: "a", b: "b" } + mapped = original.transform_values { |v| v + "!" } - assert_equal({ a: 'a', b: 'b' }, original) - assert_equal({ a: 'a!', b: 'b!' }, mapped) + assert_equal({ a: "a", b: "b" }, original) + assert_equal({ a: "a!", b: "b!" }, mapped) end test "transform_values! modifies the values of the original" do - original = { a: 'a', b: 'b' } - mapped = original.transform_values! { |v| v + '!' } + original = { a: "a", b: "b" } + mapped = original.transform_values! { |v| v + "!" } - assert_equal({ a: 'a!', b: 'b!' }, original) + assert_equal({ a: "a!", b: "b!" }, original) assert_same original, mapped end test "indifferent access is still indifferent after mapping values" do - original = { a: 'a', b: 'b' }.with_indifferent_access - mapped = original.transform_values { |v| v + '!' } + original = { a: "a", b: "b" }.with_indifferent_access + mapped = original.transform_values { |v| v + "!" } - assert_equal 'a!', mapped[:a] - assert_equal 'a!', mapped['a'] + assert_equal "a!", mapped[:a] + assert_equal "a!", mapped["a"] end # This is to be consistent with the behavior of Ruby's built in methods # (e.g. #select, #reject) as of 2.2 test "default values do not persist during mapping" do - original = Hash.new('foo') - original[:a] = 'a' - mapped = original.transform_values { |v| v + '!' } + original = Hash.new("foo") + original[:a] = "a" + mapped = original.transform_values { |v| v + "!" } - assert_equal 'a!', mapped[:a] + assert_equal "a!", mapped[:a] assert_nil mapped[:b] end test "default procs do not persist after mapping" do - original = Hash.new { 'foo' } - original[:a] = 'a' - mapped = original.transform_values { |v| v + '!' } + original = Hash.new { "foo" } + original[:a] = "a" + mapped = original.transform_values { |v| v + "!" } - assert_equal 'a!', mapped[:a] + assert_equal "a!", mapped[:a] assert_nil mapped[:b] end test "transform_values returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_values assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_values! returns a sized Enumerator if no block is given" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } enumerator = original.transform_values! assert_equal original.size, enumerator.size assert_equal Enumerator, enumerator.class end test "transform_values is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } mapped = original.transform_values.with_index { |v, i| [v, i].join } - assert_equal({ a: 'a0', b: 'b1' }, mapped) + assert_equal({ a: "a0", b: "b1" }, mapped) end test "transform_values! is chainable with Enumerable methods" do - original = { a: 'a', b: 'b' } + original = { a: "a", b: "b" } original.transform_values!.with_index { |v, i| [v, i].join } - assert_equal({ a: 'a0', b: 'b1' }, original) + assert_equal({ a: "a0", b: "b1" }, original) end end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index e8099baa35..ae35adb19b 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' -require 'active_support/core_ext/hash' -require 'bigdecimal' -require 'active_support/core_ext/string/access' -require 'active_support/ordered_hash' -require 'active_support/core_ext/object/conversions' -require 'active_support/core_ext/object/deep_dup' -require 'active_support/inflections' +require "abstract_unit" +require "active_support/core_ext/hash" +require "bigdecimal" +require "active_support/core_ext/string/access" +require "active_support/ordered_hash" +require "active_support/core_ext/object/conversions" +require "active_support/core_ext/object/deep_dup" +require "active_support/inflections" class HashExtTest < ActiveSupport::TestCase class IndifferentHash < ActiveSupport::HashWithIndifferentAccess @@ -34,22 +34,22 @@ class HashExtTest < ActiveSupport::TestCase end def setup - @strings = { 'a' => 1, 'b' => 2 } - @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } } - @symbols = { :a => 1, :b => 2 } - @nested_symbols = { :a => { :b => { :c => 3 } } } - @mixed = { :a => 1, 'b' => 2 } - @nested_mixed = { 'a' => { :b => { 'c' => 3 } } } + @strings = { "a" => 1, "b" => 2 } + @nested_strings = { "a" => { "b" => { "c" => 3 } } } + @symbols = { a: 1, b: 2 } + @nested_symbols = { a: { b: { c: 3 } } } + @mixed = { :a => 1, "b" => 2 } + @nested_mixed = { "a" => { b: { "c" => 3 } } } @integers = { 0 => 1, 1 => 2 } - @nested_integers = { 0 => { 1 => { 2 => 3} } } + @nested_integers = { 0 => { 1 => { 2 => 3 } } } @illegal_symbols = { [] => 3 } - @nested_illegal_symbols = { [] => { [] => 3} } - @upcase_strings = { 'A' => 1, 'B' => 2 } - @nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } } - @string_array_of_hashes = { 'a' => [ { 'b' => 2 }, { 'c' => 3 }, 4 ] } - @symbol_array_of_hashes = { :a => [ { :b => 2 }, { :c => 3 }, 4 ] } - @mixed_array_of_hashes = { :a => [ { :b => 2 }, { 'c' => 3 }, 4 ] } - @upcase_array_of_hashes = { 'A' => [ { 'B' => 2 }, { 'C' => 3 }, 4 ] } + @nested_illegal_symbols = { [] => { [] => 3 } } + @upcase_strings = { "A" => 1, "B" => 2 } + @nested_upcase_strings = { "A" => { "B" => { "C" => 3 } } } + @string_array_of_hashes = { "a" => [ { "b" => 2 }, { "c" => 3 }, 4 ] } + @symbol_array_of_hashes = { a: [ { b: 2 }, { c: 3 }, 4 ] } + @mixed_array_of_hashes = { a: [ { b: 2 }, { "c" => 3 }, 4 ] } + @upcase_array_of_hashes = { "A" => [ { "B" => 2 }, { "C" => 3 }, 4 ] } end def test_methods @@ -75,59 +75,59 @@ class HashExtTest < ActiveSupport::TestCase end def test_transform_keys - assert_equal @upcase_strings, @strings.transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @symbols.transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @mixed.transform_keys{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @strings.transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_strings, @symbols.transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_strings, @mixed.transform_keys { |key| key.to_s.upcase } end def test_transform_keys_not_mutates transformed_hash = @mixed.dup - transformed_hash.transform_keys{ |key| key.to_s.upcase } + transformed_hash.transform_keys { |key| key.to_s.upcase } assert_equal @mixed, transformed_hash end def test_deep_transform_keys - assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_transform_keys { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_transform_keys { |key| key.to_s.upcase } end def test_deep_transform_keys_not_mutates transformed_hash = @nested_mixed.deep_dup - transformed_hash.deep_transform_keys{ |key| key.to_s.upcase } + transformed_hash.deep_transform_keys { |key| key.to_s.upcase } assert_equal @nested_mixed, transformed_hash end def test_transform_keys! - assert_equal @upcase_strings, @symbols.dup.transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @strings.dup.transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_strings, @mixed.dup.transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @symbols.dup.transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_strings, @strings.dup.transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_strings, @mixed.dup.transform_keys! { |key| key.to_s.upcase } end def test_transform_keys_with_bang_mutates transformed_hash = @mixed.dup - transformed_hash.transform_keys!{ |key| key.to_s.upcase } + transformed_hash.transform_keys! { |key| key.to_s.upcase } assert_equal @upcase_strings, transformed_hash - assert_equal @mixed, { :a => 1, "b" => 2 } + assert_equal @mixed, :a => 1, "b" => 2 end def test_deep_transform_keys! - assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } + assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_transform_keys! { |key| key.to_s.upcase } end def test_deep_transform_keys_with_bang_mutates transformed_hash = @nested_mixed.deep_dup - transformed_hash.deep_transform_keys!{ |key| key.to_s.upcase } + transformed_hash.deep_transform_keys! { |key| key.to_s.upcase } assert_equal @nested_upcase_strings, transformed_hash - assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } + assert_equal @nested_mixed, "a" => { b: { "c" => 3 } } end def test_symbolize_keys @@ -167,7 +167,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @mixed.dup transformed_hash.deep_symbolize_keys! assert_equal @symbols, transformed_hash - assert_equal @mixed, { :a => 1, "b" => 2 } + assert_equal @mixed, :a => 1, "b" => 2 end def test_deep_symbolize_keys! @@ -183,7 +183,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @nested_mixed.deep_dup transformed_hash.deep_symbolize_keys! assert_equal @nested_symbols, transformed_hash - assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } + assert_equal @nested_mixed, "a" => { b: { "c" => 3 } } end def test_symbolize_keys_preserves_keys_that_cant_be_symbolized @@ -243,7 +243,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @mixed.dup transformed_hash.stringify_keys! assert_equal @strings, transformed_hash - assert_equal @mixed, { :a => 1, "b" => 2 } + assert_equal @mixed, :a => 1, "b" => 2 end def test_deep_stringify_keys! @@ -259,7 +259,7 @@ class HashExtTest < ActiveSupport::TestCase transformed_hash = @nested_mixed.deep_dup transformed_hash.deep_stringify_keys! assert_equal @nested_strings, transformed_hash - assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } + assert_equal @nested_mixed, "a" => { b: { "c" => 3 } } end def test_symbolize_keys_for_hash_with_indifferent_access @@ -276,7 +276,6 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @nested_symbols, @nested_mixed.with_indifferent_access.deep_symbolize_keys end - def test_symbolize_keys_bang_for_hash_with_indifferent_access assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! } assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! } @@ -353,31 +352,31 @@ class HashExtTest < ActiveSupport::TestCase @symbols = @symbols.with_indifferent_access @mixed = @mixed.with_indifferent_access - assert_equal 'a', @strings.__send__(:convert_key, :a) + assert_equal "a", @strings.__send__(:convert_key, :a) - assert_equal 1, @strings.fetch('a') + assert_equal 1, @strings.fetch("a") assert_equal 1, @strings.fetch(:a.to_s) assert_equal 1, @strings.fetch(:a) hashes = { :@strings => @strings, :@symbols => @symbols, :@mixed => @mixed } - method_map = { :'[]' => 1, :fetch => 1, :values_at => [1], - :has_key? => true, :include? => true, :key? => true, - :member? => true } + method_map = { '[]': 1, fetch: 1, values_at: [1], + has_key?: true, include?: true, key?: true, + member?: true } hashes.each do |name, hash| method_map.sort_by(&:to_s).each do |meth, expected| - assert_equal(expected, hash.__send__(meth, 'a'), + assert_equal(expected, hash.__send__(meth, "a"), "Calling #{name}.#{meth} 'a'") assert_equal(expected, hash.__send__(meth, :a), "Calling #{name}.#{meth} :a") end end - assert_equal [1, 2], @strings.values_at('a', 'b') + assert_equal [1, 2], @strings.values_at("a", "b") assert_equal [1, 2], @strings.values_at(:a, :b) - assert_equal [1, 2], @symbols.values_at('a', 'b') + assert_equal [1, 2], @symbols.values_at("a", "b") assert_equal [1, 2], @symbols.values_at(:a, :b) - assert_equal [1, 2], @mixed.values_at('a', 'b') + assert_equal [1, 2], @mixed.values_at("a", "b") assert_equal [1, 2], @mixed.values_at(:a, :b) end @@ -412,11 +411,11 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_writing hash = HashWithIndifferentAccess.new hash[:a] = 1 - hash['b'] = 2 + hash["b"] = 2 hash[3] = 3 - assert_equal hash['a'], 1 - assert_equal hash['b'], 2 + assert_equal hash["a"], 1 + assert_equal hash["b"], 2 assert_equal hash[:a], 1 assert_equal hash[:b], 2 assert_equal hash[3], 3 @@ -424,56 +423,56 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_update hash = HashWithIndifferentAccess.new - hash[:a] = 'a' - hash['b'] = 'b' + hash[:a] = "a" + hash["b"] = "b" updated_with_strings = hash.update(@strings) updated_with_symbols = hash.update(@symbols) updated_with_mixed = hash.update(@mixed) assert_equal updated_with_strings[:a], 1 - assert_equal updated_with_strings['a'], 1 - assert_equal updated_with_strings['b'], 2 + assert_equal updated_with_strings["a"], 1 + assert_equal updated_with_strings["b"], 2 assert_equal updated_with_symbols[:a], 1 - assert_equal updated_with_symbols['b'], 2 + assert_equal updated_with_symbols["b"], 2 assert_equal updated_with_symbols[:b], 2 assert_equal updated_with_mixed[:a], 1 - assert_equal updated_with_mixed['b'], 2 + assert_equal updated_with_mixed["b"], 2 assert [updated_with_strings, updated_with_symbols, updated_with_mixed].all? { |h| h.keys.size == 2 } end def test_update_with_to_hash_conversion hash = HashWithIndifferentAccess.new - hash.update HashByConversion.new({ :a => 1 }) - assert_equal hash['a'], 1 + hash.update HashByConversion.new(a: 1) + assert_equal hash["a"], 1 end def test_indifferent_merging hash = HashWithIndifferentAccess.new - hash[:a] = 'failure' - hash['b'] = 'failure' + hash[:a] = "failure" + hash["b"] = "failure" - other = { 'a' => 1, :b => 2 } + other = { "a" => 1, :b => 2 } merged = hash.merge(other) assert_equal HashWithIndifferentAccess, merged.class assert_equal 1, merged[:a] - assert_equal 2, merged['b'] + assert_equal 2, merged["b"] hash.update(other) assert_equal 1, hash[:a] - assert_equal 2, hash['b'] + assert_equal 2, hash["b"] end def test_merge_with_to_hash_conversion hash = HashWithIndifferentAccess.new - merged = hash.merge HashByConversion.new({ :a => 1 }) - assert_equal merged['a'], 1 + merged = hash.merge HashByConversion.new(a: 1) + assert_equal merged["a"], 1 end def test_indifferent_replace @@ -482,7 +481,7 @@ class HashExtTest < ActiveSupport::TestCase replaced = hash.replace(b: 12) - assert hash.key?('b') + assert hash.key?("b") assert !hash.key?(:a) assert_equal 12, hash[:b] assert_same hash, replaced @@ -494,7 +493,7 @@ class HashExtTest < ActiveSupport::TestCase replaced = hash.replace(HashByConversion.new(b: 12)) - assert hash.key?('b') + assert hash.key?("b") assert !hash.key?(:a) assert_equal 12, hash[:b] assert_same hash, replaced @@ -503,18 +502,18 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_merging_with_block hash = HashWithIndifferentAccess.new hash[:a] = 1 - hash['b'] = 3 + hash["b"] = 3 - other = { 'a' => 4, :b => 2, 'c' => 10 } + other = { "a" => 4, :b => 2, "c" => 10 } merged = hash.merge(other) { |key, old, new| old > new ? old : new } assert_equal HashWithIndifferentAccess, merged.class assert_equal 4, merged[:a] - assert_equal 3, merged['b'] + assert_equal 3, merged["b"] assert_equal 10, merged[:c] - other_indifferent = HashWithIndifferentAccess.new('a' => 9, :b => 2) + other_indifferent = HashWithIndifferentAccess.new("a" => 9, :b => 2) merged = hash.merge(other_indifferent) { |key, old, new| old + new } @@ -528,26 +527,26 @@ class HashExtTest < ActiveSupport::TestCase hash.reverse_merge! key: :new_value assert_equal :old_value, hash[:key] - hash = HashWithIndifferentAccess.new('some' => 'value', 'other' => 'value') - hash.reverse_merge!(:some => 'noclobber', :another => 'clobber') - assert_equal 'value', hash[:some] - assert_equal 'clobber', hash[:another] + hash = HashWithIndifferentAccess.new("some" => "value", "other" => "value") + hash.reverse_merge!(some: "noclobber", another: "clobber") + assert_equal "value", hash[:some] + assert_equal "clobber", hash[:another] end def test_indifferent_deleting - get_hash = proc{ { :a => 'foo' }.with_indifferent_access } + get_hash = proc { { a: "foo" }.with_indifferent_access } hash = get_hash.call - assert_equal hash.delete(:a), 'foo' + assert_equal hash.delete(:a), "foo" assert_equal hash.delete(:a), nil hash = get_hash.call - assert_equal hash.delete('a'), 'foo' - assert_equal hash.delete('a'), nil + assert_equal hash.delete("a"), "foo" + assert_equal hash.delete("a"), nil end def test_indifferent_select - hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select {|k,v| v == 1} + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select { |k,v| v == 1 } - assert_equal({ 'a' => 1 }, hash) + assert_equal({ "a" => 1 }, hash) assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash end @@ -557,23 +556,23 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_select_returns_a_hash_when_unchanged - hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select {|k,v| true} + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).select { |k,v| true } assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash end def test_indifferent_select_bang indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) - indifferent_strings.select! {|k,v| v == 1} + indifferent_strings.select! { |k,v| v == 1 } - assert_equal({ 'a' => 1 }, indifferent_strings) + assert_equal({ "a" => 1 }, indifferent_strings) assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings end def test_indifferent_reject - hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).reject {|k,v| v != 1} + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).reject { |k,v| v != 1 } - assert_equal({ 'a' => 1 }, hash) + assert_equal({ "a" => 1 }, hash) assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash end @@ -584,9 +583,9 @@ class HashExtTest < ActiveSupport::TestCase def test_indifferent_reject_bang indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) - indifferent_strings.reject! {|k,v| v != 1} + indifferent_strings.reject! { |k,v| v != 1 } - assert_equal({ 'a' => 1 }, indifferent_strings) + assert_equal({ "a" => 1 }, indifferent_strings) assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings end @@ -596,10 +595,10 @@ class HashExtTest < ActiveSupport::TestCase # Should preserve the default value. mixed_with_default = @mixed.dup - mixed_with_default.default = '1234' + mixed_with_default.default = "1234" roundtrip = mixed_with_default.with_indifferent_access.to_hash assert_equal @strings, roundtrip - assert_equal '1234', roundtrip.default + assert_equal "1234", roundtrip.default # Ensure nested hashes are not HashWithIndiffereneAccess new_to_hash = @nested_mixed.with_indifferent_access.to_hash @@ -609,21 +608,21 @@ class HashExtTest < ActiveSupport::TestCase end def test_lookup_returns_the_same_object_that_is_stored_in_hash_indifferent_access - hash = HashWithIndifferentAccess.new {|h, k| h[k] = []} + hash = HashWithIndifferentAccess.new { |h, k| h[k] = [] } hash[:a] << 1 assert_equal [1], hash[:a] end def test_with_indifferent_access_has_no_side_effects_on_existing_hash - hash = {content: [{:foo => :bar, 'bar' => 'baz'}]} + hash = { content: [{ :foo => :bar, "bar" => "baz" }] } hash.with_indifferent_access assert_equal [:foo, "bar"], hash[:content].first.keys end def test_indifferent_hash_with_array_of_hashes - hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access + hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] } }.with_indifferent_access assert_equal "1", hash[:urls][:url].first[:address] hash = hash.to_hash @@ -635,14 +634,14 @@ class HashExtTest < ActiveSupport::TestCase def test_should_preserve_array_subclass_when_value_is_array array = SubclassingArray.new array << { "address" => "1" } - hash = { "urls" => { "url" => array }}.with_indifferent_access + hash = { "urls" => { "url" => array } }.with_indifferent_access assert_equal SubclassingArray, hash[:urls][:url].class end def test_should_preserve_array_class_when_hash_value_is_frozen_array array = SubclassingArray.new array << { "address" => "1" } - hash = { "urls" => { "url" => array.freeze }}.with_indifferent_access + hash = { "urls" => { "url" => array.freeze } }.with_indifferent_access assert_equal SubclassingArray, hash[:urls][:url].class end @@ -650,9 +649,9 @@ class HashExtTest < ActiveSupport::TestCase h = HashWithIndifferentAccess.new h[:first] = 1 h = h.stringify_keys - assert_equal 1, h['first'] + assert_equal 1, h["first"] h = HashWithIndifferentAccess.new - h['first'] = 1 + h["first"] = 1 h = h.symbolize_keys assert_equal 1, h[:first] end @@ -661,40 +660,40 @@ class HashExtTest < ActiveSupport::TestCase h = HashWithIndifferentAccess.new h[:first] = 1 h = h.deep_stringify_keys - assert_equal 1, h['first'] + assert_equal 1, h["first"] h = HashWithIndifferentAccess.new - h['first'] = 1 + h["first"] = 1 h = h.deep_symbolize_keys assert_equal 1, h[:first] end def test_to_options_on_indifferent_preserves_hash h = HashWithIndifferentAccess.new - h['first'] = 1 + h["first"] = 1 h.to_options! - assert_equal 1, h['first'] + assert_equal 1, h["first"] end def test_to_options_on_indifferent_preserves_works_as_hash_with_dup - h = HashWithIndifferentAccess.new({ a: { b: 'b' } }) + h = HashWithIndifferentAccess.new(a: { b: "b" }) dup = h.dup - dup[:a][:c] = 'c' - assert_equal 'c', h[:a][:c] + dup[:a][:c] = "c" + assert_equal "c", h[:a][:c] end def test_indifferent_sub_hashes - h = {'user' => {'id' => 5}}.with_indifferent_access - ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} + h = { "user" => { "id" => 5 } }.with_indifferent_access + ["user", :user].each { |user| [:id, "id"].each { |id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5" } } - h = {:user => {:id => 5}}.with_indifferent_access - ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} + h = { user: { id: 5 } }.with_indifferent_access + ["user", :user].each { |user| [:id, "id"].each { |id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5" } } end def test_indifferent_duplication # Should preserve default value h = HashWithIndifferentAccess.new - h.default = '1234' + h.default = "1234" assert_equal h.default, h.dup.default # Should preserve class for subclasses @@ -704,52 +703,52 @@ class HashExtTest < ActiveSupport::TestCase def test_nested_dig_indifferent_access skip if RUBY_VERSION < "2.3.0" - data = {"this" => {"views" => 1234}}.with_indifferent_access + data = { "this" => { "views" => 1234 } }.with_indifferent_access assert_equal 1234, data.dig(:this, :views) end def test_assert_valid_keys assert_nothing_raised do - { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) - { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny) + { failure: "stuff", funny: "business" }.assert_valid_keys([ :failure, :funny ]) + { failure: "stuff", funny: "business" }.assert_valid_keys(:failure, :funny) end # not all valid keys are required to be present assert_nothing_raised do - { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny, :sunny ]) - { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny, :sunny) + { failure: "stuff", funny: "business" }.assert_valid_keys([ :failure, :funny, :sunny ]) + { failure: "stuff", funny: "business" }.assert_valid_keys(:failure, :funny, :sunny) end exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) + { failore: "stuff", funny: "business" }.assert_valid_keys([ :failure, :funny ]) end assert_equal "Unknown key: :failore. Valid keys are: :failure, :funny", exception.message exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny) + { failore: "stuff", funny: "business" }.assert_valid_keys(:failure, :funny) end assert_equal "Unknown key: :failore. Valid keys are: :failure, :funny", exception.message exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure ]) + { failore: "stuff", funny: "business" }.assert_valid_keys([ :failure ]) end assert_equal "Unknown key: :failore. Valid keys are: :failure", exception.message exception = assert_raise ArgumentError do - { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure) + { failore: "stuff", funny: "business" }.assert_valid_keys(:failure) end assert_equal "Unknown key: :failore. Valid keys are: :failure", exception.message end def test_assorted_keys_not_stringified - original = {Object.new => 2, 1 => 2, [] => true} + original = { Object.new => 2, 1 => 2, [] => true } indiff = original.with_indifferent_access - assert(!indiff.keys.any? {|k| k.kind_of? String}, "A key was converted to a string!") + assert(!indiff.keys.any? { |k| k.kind_of? String }, "A key was converted to a string!") end def test_deep_merge - hash_1 = { :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } } - hash_2 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } } - expected = { :a => 1, :b => "b", :c => { :c1 => 2, :c2 => "c2", :c3 => { :d1 => "d1", :d2 => "d2" } } } + hash_1 = { a: "a", b: "b", c: { c1: "c1", c2: "c2", c3: { d1: "d1" } } } + hash_2 = { a: 1, c: { c1: 2, c3: { d2: "d2" } } } + expected = { a: 1, b: "b", c: { c1: 2, c2: "c2", c3: { d1: "d1", d2: "d2" } } } assert_equal expected, hash_1.deep_merge(hash_2) hash_1.deep_merge!(hash_2) @@ -757,9 +756,9 @@ class HashExtTest < ActiveSupport::TestCase end def test_deep_merge_with_block - hash_1 = { :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } } - hash_2 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } } - expected = { :a => [:a, "a", 1], :b => "b", :c => { :c1 => [:c1, "c1", 2], :c2 => "c2", :c3 => { :d1 => "d1", :d2 => "d2" } } } + hash_1 = { a: "a", b: "b", c: { c1: "c1", c2: "c2", c3: { d1: "d1" } } } + hash_2 = { a: 1, c: { c1: 2, c3: { d2: "d2" } } } + expected = { a: [:a, "a", 1], b: "b", c: { c1: [:c1, "c1", 2], c2: "c2", c3: { d1: "d1", d2: "d2" } } } assert_equal(expected, hash_1.deep_merge(hash_2) { |k,o,n| [k, o, n] }) hash_1.deep_merge!(hash_2) { |k,o,n| [k, o, n] } @@ -768,8 +767,8 @@ class HashExtTest < ActiveSupport::TestCase def test_deep_merge_with_falsey_values hash_1 = { e: false } - hash_2 = { e: 'e' } - expected = { e: [:e, false, 'e'] } + hash_2 = { e: "e" } + expected = { e: [:e, false, "e"] } assert_equal(expected, hash_1.deep_merge(hash_2) { |k, o, n| [k, o, n] }) hash_1.deep_merge!(hash_2) { |k, o, n| [k, o, n] } @@ -777,9 +776,9 @@ class HashExtTest < ActiveSupport::TestCase end def test_deep_merge_on_indifferent_access - hash_1 = HashWithIndifferentAccess.new({ :a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } } }) - hash_2 = HashWithIndifferentAccess.new({ :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } }) - hash_3 = { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } } + hash_1 = HashWithIndifferentAccess.new(a: "a", b: "b", c: { c1: "c1", c2: "c2", c3: { d1: "d1" } }) + hash_2 = HashWithIndifferentAccess.new(a: 1, c: { c1: 2, c3: { d2: "d2" } }) + hash_3 = { a: 1, c: { c1: 2, c3: { d2: "d2" } } } expected = { "a" => 1, "b" => "b", "c" => { "c1" => 2, "c2" => "c2", "c3" => { "d1" => "d1", "d2" => "d2" } } } assert_equal expected, hash_1.deep_merge(hash_2) assert_equal expected, hash_1.deep_merge(hash_3) @@ -791,9 +790,9 @@ class HashExtTest < ActiveSupport::TestCase def test_store_on_indifferent_access hash = HashWithIndifferentAccess.new hash.store(:test1, 1) - hash.store('test1', 11) + hash.store("test1", 11) hash[:test2] = 2 - hash['test2'] = 22 + hash["test2"] = 22 expected = { "test1" => 11, "test2" => 22 } assert_equal expected, hash end @@ -801,16 +800,16 @@ class HashExtTest < ActiveSupport::TestCase def test_constructor_on_indifferent_access hash = HashWithIndifferentAccess[:foo, 1] assert_equal 1, hash[:foo] - assert_equal 1, hash['foo'] + assert_equal 1, hash["foo"] hash[:foo] = 3 assert_equal 3, hash[:foo] - assert_equal 3, hash['foo'] + assert_equal 3, hash["foo"] end def test_reverse_merge - defaults = { :a => "x", :b => "y", :c => 10 }.freeze - options = { :a => 1, :b => 2 } - expected = { :a => 1, :b => 2, :c => 10 } + defaults = { a: "x", b: "y", c: 10 }.freeze + options = { a: 1, b: 2 } + expected = { a: 1, b: 2, c: 10 } # Should merge defaults into options, creating a new hash. assert_equal expected, options.reverse_merge(defaults) @@ -828,8 +827,8 @@ class HashExtTest < ActiveSupport::TestCase end def test_slice - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y", c: 10 } + expected = { a: "x", b: "y" } # Should return a new hash with only the given keys. assert_equal expected, original.slice(:a, :b) @@ -837,15 +836,15 @@ class HashExtTest < ActiveSupport::TestCase end def test_slice_inplace - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :c => 10 } + original = { a: "x", b: "y", c: 10 } + expected = { c: 10 } # Should replace the hash with only the given keys. assert_equal expected, original.slice!(:a, :b) end def test_slice_with_an_array_key - original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" } + original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } expected = { [:a, :b] => "an array key", :c => 10 } # Should return a new hash with only the given keys when given an array key. @@ -854,26 +853,26 @@ class HashExtTest < ActiveSupport::TestCase end def test_slice_inplace_with_an_array_key - original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" } - expected = { :a => 'x', :b => 'y' } + original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } + expected = { a: "x", b: "y" } # Should replace the hash with only the given keys when given an array key. assert_equal expected, original.slice!([:a, :b], :c) end def test_slice_with_splatted_keys - original = { :a => 'x', :b => 'y', :c => 10, [:a, :b] => "an array key" } - expected = { :a => 'x', :b => "y" } + original = { :a => "x", :b => "y", :c => 10, [:a, :b] => "an array key" } + expected = { a: "x", b: "y" } # Should grab each of the splatted keys. assert_equal expected, original.slice(*[:a, :b]) end def test_indifferent_slice - original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access - expected = { :a => 'x', :b => 'y' }.with_indifferent_access + original = { a: "x", b: "y", c: 10 }.with_indifferent_access + expected = { a: "x", b: "y" }.with_indifferent_access - [['a', 'b'], [:a, :b]].each do |keys| + [["a", "b"], [:a, :b]].each do |keys| # Should return a new hash with only the given keys. assert_equal expected, original.slice(*keys), keys.inspect assert_not_equal expected, original @@ -881,10 +880,10 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_slice_inplace - original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access - expected = { :c => 10 }.with_indifferent_access + original = { a: "x", b: "y", c: 10 }.with_indifferent_access + expected = { c: 10 }.with_indifferent_access - [['a', 'b'], [:a, :b]].each do |keys| + [["a", "b"], [:a, :b]].each do |keys| # Should replace the hash with only the given keys. copy = original.dup assert_equal expected, copy.slice!(*keys) @@ -892,13 +891,13 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_slice_access_with_symbols - original = {'login' => 'bender', 'password' => 'shiny', 'stuff' => 'foo'} + original = { "login" => "bender", "password" => "shiny", "stuff" => "foo" } original = original.with_indifferent_access slice = original.slice(:login, :password) - assert_equal 'bender', slice[:login] - assert_equal 'bender', slice['login'] + assert_equal "bender", slice[:login] + assert_equal "bender", slice["login"] end def test_slice_bang_does_not_override_default @@ -920,17 +919,17 @@ class HashExtTest < ActiveSupport::TestCase end def test_extract - original = {:a => 1, :b => 2, :c => 3, :d => 4} - expected = {:a => 1, :b => 2} - remaining = {:c => 3, :d => 4} + original = { a: 1, b: 2, c: 3, d: 4 } + expected = { a: 1, b: 2 } + remaining = { c: 3, d: 4 } assert_equal expected, original.extract!(:a, :b, :x) assert_equal remaining, original end def test_extract_nils - original = {:a => nil, :b => nil} - expected = {:a => nil} + original = { a: nil, b: nil } + expected = { a: nil } extracted = original.extract!(:a, :x) assert_equal expected, extracted @@ -939,11 +938,11 @@ class HashExtTest < ActiveSupport::TestCase end def test_indifferent_extract - original = {:a => 1, 'b' => 2, :c => 3, 'd' => 4}.with_indifferent_access - expected = {:a => 1, :b => 2}.with_indifferent_access - remaining = {:c => 3, :d => 4}.with_indifferent_access + original = { :a => 1, "b" => 2, :c => 3, "d" => 4 }.with_indifferent_access + expected = { a: 1, b: 2 }.with_indifferent_access + remaining = { c: 3, d: 4 }.with_indifferent_access - [['a', 'b'], [:a, :b]].each do |keys| + [["a", "b"], [:a, :b]].each do |keys| copy = original.dup assert_equal expected, copy.extract!(*keys) assert_equal remaining, copy @@ -951,8 +950,8 @@ class HashExtTest < ActiveSupport::TestCase end def test_except - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y", c: 10 } + expected = { a: "x", b: "y" } # Should return a new hash without the given keys. assert_equal expected, original.except(:c) @@ -964,8 +963,8 @@ class HashExtTest < ActiveSupport::TestCase end def test_except_with_more_than_one_argument - original = { :a => 'x', :b => 'y', :c => 10 } - expected = { :a => 'x' } + original = { a: "x", b: "y", c: 10 } + expected = { a: "x" } assert_equal expected, original.except(:b, :c) @@ -974,7 +973,7 @@ class HashExtTest < ActiveSupport::TestCase end def test_except_with_original_frozen - original = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y" } original.freeze assert_nothing_raised { original.except(:a) } @@ -982,7 +981,7 @@ class HashExtTest < ActiveSupport::TestCase end def test_except_does_not_delete_values_in_original - original = { :a => 'x', :b => 'y' } + original = { a: "x", b: "y" } assert_not_called(original, :delete) do original.except(:a) end @@ -1024,7 +1023,7 @@ class HashExtTest < ActiveSupport::TestCase def test_new_with_to_hash_conversion hash = HashWithIndifferentAccess.new(HashByConversion.new(a: 1)) - assert hash.key?('a') + assert hash.key?("a") assert_equal 1, hash[:a] end @@ -1081,10 +1080,10 @@ end class IWriteMyOwnXML def to_xml(options = {}) options[:indent] ||= 2 - xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) + xml = options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent]) xml.instruct! unless options[:skip_instruct] xml.level_one do - xml.tag!(:second_level, 'content') + xml.tag!(:second_level, "content") end end end @@ -1097,139 +1096,139 @@ class HashExtToParamTests < ActiveSupport::TestCase end def test_string_hash - assert_equal '', {}.to_param - assert_equal 'hello=world', { :hello => "world" }.to_param - assert_equal 'hello=10', { "hello" => 10 }.to_param - assert_equal 'hello=world&say_bye=true', {:hello => "world", "say_bye" => true}.to_param + assert_equal "", {}.to_param + assert_equal "hello=world", { hello: "world" }.to_param + assert_equal "hello=10", { "hello" => 10 }.to_param + assert_equal "hello=world&say_bye=true", { :hello => "world", "say_bye" => true }.to_param end def test_number_hash - assert_equal '10=20&30=40&50=60', {10 => 20, 30 => 40, 50 => 60}.to_param + assert_equal "10=20&30=40&50=60", { 10 => 20, 30 => 40, 50 => 60 }.to_param end def test_to_param_hash - assert_equal 'custom-1=param-1&custom2-1=param2-1', {ToParam.new('custom') => ToParam.new('param'), ToParam.new('custom2') => ToParam.new('param2')}.to_param + assert_equal "custom-1=param-1&custom2-1=param2-1", { ToParam.new("custom") => ToParam.new("param"), ToParam.new("custom2") => ToParam.new("param2") }.to_param end def test_to_param_hash_escapes_its_keys_and_values - assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param + assert_equal "param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped", { "param 1" => "A string with / characters & that should be ? escaped" }.to_param end def test_to_param_orders_by_key_in_ascending_order - assert_equal 'a=2&b=1&c=0', Hash[*%w(b 1 c 0 a 2)].to_param + assert_equal "a=2&b=1&c=0", Hash[*%w(b 1 c 0 a 2)].to_param end end class HashToXmlTest < ActiveSupport::TestCase def setup - @xml_options = { :root => :person, :skip_instruct => true, :indent => 0 } + @xml_options = { root: :person, skip_instruct: true, indent: 0 } end def test_one_level - xml = { :name => "David", :street => "Paulina" }.to_xml(@xml_options) + xml = { name: "David", street: "Paulina" }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) end def test_one_level_dasherize_false - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => false)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(dasherize: false)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street_name>Paulina</street_name>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<street_name>Paulina</street_name>) + assert_includes xml, %(<name>David</name>) end def test_one_level_dasherize_true - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => true)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(dasherize: true)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street-name>Paulina</street-name>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<street-name>Paulina</street-name>) + assert_includes xml, %(<name>David</name>) end def test_one_level_camelize_true - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => true)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(camelize: true)) assert_equal "<Person>", xml.first(8) - assert xml.include?(%(<StreetName>Paulina</StreetName>)) - assert xml.include?(%(<Name>David</Name>)) + assert_includes xml, %(<StreetName>Paulina</StreetName>) + assert_includes xml, %(<Name>David</Name>) end def test_one_level_camelize_lower - xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => :lower)) + xml = { name: "David", street_name: "Paulina" }.to_xml(@xml_options.merge(camelize: :lower)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<streetName>Paulina</streetName>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<streetName>Paulina</streetName>) + assert_includes xml, %(<name>David</name>) end def test_one_level_with_types - xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options) + xml = { name: "David", street: "Paulina", age: 26, age_in_millis: 820497600000, moved_on: Date.new(2005, 11, 15), resident: :yes }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<age type="integer">26</age>)) - assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)) - assert xml.include?(%(<moved-on type="date">2005-11-15</moved-on>)) - assert xml.include?(%(<resident type="symbol">yes</resident>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<age type="integer">26</age>) + assert_includes xml, %(<age-in-millis type="integer">820497600000</age-in-millis>) + assert_includes xml, %(<moved-on type="date">2005-11-15</moved-on>) + assert_includes xml, %(<resident type="symbol">yes</resident>) end def test_one_level_with_nils - xml = { :name => "David", :street => "Paulina", :age => nil }.to_xml(@xml_options) + xml = { name: "David", street: "Paulina", age: nil }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<age nil="true"/>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<age nil="true"/>) end def test_one_level_with_skipping_types - xml = { :name => "David", :street => "Paulina", :age => nil }.to_xml(@xml_options.merge(:skip_types => true)) + xml = { name: "David", street: "Paulina", age: nil }.to_xml(@xml_options.merge(skip_types: true)) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<age nil="true"/>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<age nil="true"/>) end def test_one_level_with_yielding - xml = { :name => "David", :street => "Paulina" }.to_xml(@xml_options) do |x| + xml = { name: "David", street: "Paulina" }.to_xml(@xml_options) do |x| x.creator("Rails") end assert_equal "<person>", xml.first(8) - assert xml.include?(%(<street>Paulina</street>)) - assert xml.include?(%(<name>David</name>)) - assert xml.include?(%(<creator>Rails</creator>)) + assert_includes xml, %(<street>Paulina</street>) + assert_includes xml, %(<name>David</name>) + assert_includes xml, %(<creator>Rails</creator>) end def test_two_levels - xml = { :name => "David", :address => { :street => "Paulina" } }.to_xml(@xml_options) + xml = { name: "David", address: { street: "Paulina" } }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<address><street>Paulina</street></address>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<address><street>Paulina</street></address>) + assert_includes xml, %(<name>David</name>) end def test_two_levels_with_second_level_overriding_to_xml - xml = { :name => "David", :address => { :street => "Paulina" }, :child => IWriteMyOwnXML.new }.to_xml(@xml_options) + xml = { name: "David", address: { street: "Paulina" }, child: IWriteMyOwnXML.new }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<address><street>Paulina</street></address>)) - assert xml.include?(%(<level_one><second_level>content</second_level></level_one>)) + assert_includes xml, %(<address><street>Paulina</street></address>) + assert_includes xml, %(<level_one><second_level>content</second_level></level_one>) end def test_two_levels_with_array - xml = { :name => "David", :addresses => [{ :street => "Paulina" }, { :street => "Evergreen" }] }.to_xml(@xml_options) + xml = { name: "David", addresses: [{ street: "Paulina" }, { street: "Evergreen" }] }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) - assert xml.include?(%(<addresses type="array"><address>)) - assert xml.include?(%(<address><street>Paulina</street></address>)) - assert xml.include?(%(<address><street>Evergreen</street></address>)) - assert xml.include?(%(<name>David</name>)) + assert_includes xml, %(<addresses type="array"><address>) + assert_includes xml, %(<address><street>Paulina</street></address>) + assert_includes xml, %(<address><street>Evergreen</street></address>) + assert_includes xml, %(<name>David</name>) end def test_three_levels_with_array - xml = { :name => "David", :addresses => [{ :streets => [ { :name => "Paulina" }, { :name => "Paulina" } ] } ] }.to_xml(@xml_options) - assert xml.include?(%(<addresses type="array"><address><streets type="array"><street><name>)) + xml = { name: "David", addresses: [{ streets: [ { name: "Paulina" }, { name: "Paulina" } ] } ] }.to_xml(@xml_options) + assert_includes xml, %(<addresses type="array"><address><streets type="array"><street><name>) end def test_timezoned_attributes xml = { - :created_at => Time.utc(1999,2,2), - :local_created_at => Time.utc(1999,2,2).in_time_zone('Eastern Time (US & Canada)') + created_at: Time.utc(1999,2,2), + local_created_at: Time.utc(1999,2,2).in_time_zone("Eastern Time (US & Canada)") }.to_xml(@xml_options) assert_match %r{<created-at type=\"dateTime\">1999-02-02T00:00:00Z</created-at>}, xml assert_match %r{<local-created-at type=\"dateTime\">1999-02-01T19:00:00-05:00</local-created-at>}, xml @@ -1268,17 +1267,17 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => "The First Topic", - :author_name => "David", - :id => 1, - :approved => false, - :replies_count => 0, - :replies_close_in => 2592000000, - :written_on => Date.new(2003, 7, 16), - :viewed_at => Time.utc(2003, 7, 16, 9, 28), - :content => "Have a nice day", - :author_email_address => "david@loudthinking.com", - :parent_id => nil + title: "The First Topic", + author_name: "David", + id: 1, + approved: false, + replies_count: 0, + replies_close_in: 2592000000, + written_on: Date.new(2003, 7, 16), + viewed_at: Time.utc(2003, 7, 16, 9, 28), + content: "Have a nice day", + author_email_address: "david@loudthinking.com", + parent_id: nil }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topics_xml)["topics"].first @@ -1303,18 +1302,18 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => "The First Topic", - :author_name => "David", - :id => 1, - :approved => true, - :replies_count => 0, - :replies_close_in => 2592000000, - :written_on => Date.new(2003, 7, 16), - :viewed_at => Time.utc(2003, 7, 16, 9, 28), - :author_email_address => "david@loudthinking.com", - :parent_id => nil, - :ad_revenue => BigDecimal("1.50"), - :optimum_viewing_angle => 135.0, + title: "The First Topic", + author_name: "David", + id: 1, + approved: true, + replies_count: 0, + replies_close_in: 2592000000, + written_on: Date.new(2003, 7, 16), + viewed_at: Time.utc(2003, 7, 16, 9, 28), + author_email_address: "david@loudthinking.com", + parent_id: nil, + ad_revenue: BigDecimal("1.50"), + optimum_viewing_angle: 135.0, }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"] @@ -1333,12 +1332,12 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => nil, - :id => nil, - :approved => nil, - :written_on => nil, - :viewed_at => nil, - :parent_id => nil + title: nil, + id: nil, + approved: nil, + written_on: nil, + viewed_at: nil, + parent_id: nil }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"] @@ -1377,17 +1376,17 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :title => "The First Topic", - :author_name => "David", - :id => 1, - :approved => false, - :replies_count => 0, - :replies_close_in => 2592000000, - :written_on => Date.new(2003, 7, 16), - :viewed_at => Time.utc(2003, 7, 16, 9, 28), - :content => "Have a nice day", - :author_email_address => "david@loudthinking.com", - :parent_id => nil + title: "The First Topic", + author_name: "David", + id: 1, + approved: false, + replies_count: 0, + replies_close_in: 2592000000, + written_on: Date.new(2003, 7, 16), + viewed_at: Time.utc(2003, 7, 16, 9, 28), + content: "Have a nice day", + author_email_address: "david@loudthinking.com", + parent_id: nil }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topics_xml)["topics"].first @@ -1403,14 +1402,14 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_topic_hash = { - :id => "175756086", - :owner => "55569174@N00", - :secret => "0279bf37a1", - :server => "76", - :title => "Colored Pencil PhotoBooth Fun", - :ispublic => "1", - :isfriend => "0", - :isfamily => "0", + id: "175756086", + owner: "55569174@N00", + secret: "0279bf37a1", + server: "76", + title: "Colored Pencil PhotoBooth Fun", + ispublic: "1", + isfriend: "0", + isfamily: "0", }.stringify_keys assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"] @@ -1438,7 +1437,7 @@ class HashToXmlTest < ActiveSupport::TestCase <posts type="array"></posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => []}} + expected_blog_hash = { "blog" => { "posts" => [] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1449,7 +1448,7 @@ class HashToXmlTest < ActiveSupport::TestCase </posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => []}} + expected_blog_hash = { "blog" => { "posts" => [] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1461,7 +1460,7 @@ class HashToXmlTest < ActiveSupport::TestCase </posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => ["a post"]}} + expected_blog_hash = { "blog" => { "posts" => ["a post"] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1474,7 +1473,7 @@ class HashToXmlTest < ActiveSupport::TestCase </posts> </blog> XML - expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}} + expected_blog_hash = { "blog" => { "posts" => ["a post", "another post"] } } assert_equal expected_blog_hash, Hash.from_xml(blog_xml) end @@ -1486,12 +1485,12 @@ class HashToXmlTest < ActiveSupport::TestCase </blog> XML hash = Hash.from_xml(blog_xml) - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type end def test_file_from_xml_with_defaults @@ -1501,9 +1500,9 @@ class HashToXmlTest < ActiveSupport::TestCase </logo> </blog> XML - file = Hash.from_xml(blog_xml)['blog']['logo'] - assert_equal 'untitled', file.original_filename - assert_equal 'application/octet-stream', file.content_type + file = Hash.from_xml(blog_xml)["blog"]["logo"] + assert_equal "untitled", file.original_filename + assert_equal "application/octet-stream", file.content_type end def test_tag_with_attrs_and_whitespace @@ -1512,7 +1511,7 @@ class HashToXmlTest < ActiveSupport::TestCase </blog> XML hash = Hash.from_xml(xml) - assert_equal "bacon is the best", hash['blog']['name'] + assert_equal "bacon is the best", hash["blog"]["name"] end def test_empty_cdata_from_xml @@ -1535,13 +1534,13 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_bacon_hash = { - :weight => 0.5, - :chunky => true, - :price => BigDecimal("12.50"), - :expires_at => Time.utc(2007,12,25,12,34,56), - :notes => "", - :illustration => "babe.png", - :caption => "That'll do, pig." + weight: 0.5, + chunky: true, + price: BigDecimal("12.50"), + expires_at: Time.utc(2007,12,25,12,34,56), + notes: "", + illustration: "babe.png", + caption: "That'll do, pig." }.stringify_keys assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"] @@ -1557,8 +1556,8 @@ class HashToXmlTest < ActiveSupport::TestCase EOT expected_product_hash = { - :weight => 0.5, - :image => {'type' => 'ProductImage', 'filename' => 'image.gif' }, + weight: 0.5, + image: { "type" => "ProductImage", "filename" => "image.gif" }, }.stringify_keys assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"] @@ -1581,17 +1580,17 @@ class HashToXmlTest < ActiveSupport::TestCase end def test_from_xml_array_one - expected = { 'numbers' => { 'type' => 'Array', 'value' => '1' }} + expected = { "numbers" => { "type" => "Array", "value" => "1" } } assert_equal expected, Hash.from_xml('<numbers type="Array"><value>1</value></numbers>') end def test_from_xml_array_many - expected = { 'numbers' => { 'type' => 'Array', 'value' => [ '1', '2' ] }} + expected = { "numbers" => { "type" => "Array", "value" => [ "1", "2" ] } } assert_equal expected, Hash.from_xml('<numbers type="Array"><value>1</value><value>2</value></numbers>') end def test_from_trusted_xml_allows_symbol_and_yaml_types - expected = { 'product' => { 'name' => :value }} + expected = { "product" => { "name" => :value } } assert_equal expected, Hash.from_trusted_xml('<product><name type="symbol">value</name></product>') assert_equal expected, Hash.from_trusted_xml('<product><name type="yaml">:value</name></product>') end @@ -1654,8 +1653,8 @@ class HashToXmlTest < ActiveSupport::TestCase # The XML builder seems to fail miserably when trying to tag something # with the same name as a Kernel method (throw, test, loop, select ...) def test_kernel_method_names_to_xml - hash = { :throw => { :ball => 'red' } } - expected = '<person><throw><ball>red</ball></throw></person>' + hash = { throw: { ball: "red" } } + expected = "<person><throw><ball>red</ball></throw></person>" assert_nothing_raised do assert_equal expected, hash.to_xml(@xml_options) @@ -1670,30 +1669,30 @@ class HashToXmlTest < ActiveSupport::TestCase def test_escaping_to_xml hash = { - :bare_string => 'First & Last Name', - :pre_escaped_string => 'First & Last Name' + bare_string: "First & Last Name", + pre_escaped_string: "First & Last Name" }.stringify_keys - expected_xml = '<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>' + expected_xml = "<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>" assert_equal expected_xml, hash.to_xml(@xml_options) end def test_unescaping_from_xml - xml_string = '<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>' + xml_string = "<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>" expected_hash = { - :bare_string => 'First & Last Name', - :pre_escaped_string => 'First & Last Name' + bare_string: "First & Last Name", + pre_escaped_string: "First & Last Name" }.stringify_keys - assert_equal expected_hash, Hash.from_xml(xml_string)['person'] + assert_equal expected_hash, Hash.from_xml(xml_string)["person"] end def test_roundtrip_to_xml_from_xml hash = { - :bare_string => 'First & Last Name', - :pre_escaped_string => 'First & Last Name' + bare_string: "First & Last Name", + pre_escaped_string: "First & Last Name" }.stringify_keys - assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))['person'] + assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))["person"] end def test_datetime_xml_type_with_utc_time @@ -1702,7 +1701,7 @@ class HashToXmlTest < ActiveSupport::TestCase <alert_at type="datetime">2008-02-10T15:30:45Z</alert_at> </alert> XML - alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + alert_at = Hash.from_xml(alert_xml)["alert"]["alert_at"] assert alert_at.utc? assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at end @@ -1713,7 +1712,7 @@ class HashToXmlTest < ActiveSupport::TestCase <alert_at type="datetime">2008-02-10T10:30:45-05:00</alert_at> </alert> XML - alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + alert_at = Hash.from_xml(alert_xml)["alert"]["alert_at"] assert alert_at.utc? assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at end @@ -1724,7 +1723,7 @@ class HashToXmlTest < ActiveSupport::TestCase <alert_at type="datetime">2050-02-10T15:30:45Z</alert_at> </alert> XML - alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + alert_at = Hash.from_xml(alert_xml)["alert"]["alert_at"] assert alert_at.utc? assert_equal 2050, alert_at.year assert_equal 2, alert_at.month @@ -1735,20 +1734,20 @@ class HashToXmlTest < ActiveSupport::TestCase end def test_to_xml_dups_options - options = {:skip_instruct => true} + options = { skip_instruct: true } {}.to_xml(options) # :builder, etc, shouldn't be added to options - assert_equal({:skip_instruct => true}, options) + assert_equal({ skip_instruct: true }, options) end def test_expansion_count_is_limited expected = case ActiveSupport::XmlMini.backend.name - when 'ActiveSupport::XmlMini_REXML'; RuntimeError - when 'ActiveSupport::XmlMini_Nokogiri'; Nokogiri::XML::SyntaxError - when 'ActiveSupport::XmlMini_NokogiriSAX'; RuntimeError - when 'ActiveSupport::XmlMini_LibXML'; LibXML::XML::Error - when 'ActiveSupport::XmlMini_LibXMLSAX'; LibXML::XML::Error + when "ActiveSupport::XmlMini_REXML"; RuntimeError + when "ActiveSupport::XmlMini_Nokogiri"; Nokogiri::XML::SyntaxError + when "ActiveSupport::XmlMini_NokogiriSAX"; RuntimeError + when "ActiveSupport::XmlMini_LibXML"; LibXML::XML::Error + when "ActiveSupport::XmlMini_LibXMLSAX"; LibXML::XML::Error end assert_raise expected do diff --git a/activesupport/test/core_ext/integer_ext_test.rb b/activesupport/test/core_ext/integer_ext_test.rb index 41736fb672..137e8ce85f 100644 --- a/activesupport/test/core_ext/integer_ext_test.rb +++ b/activesupport/test/core_ext/integer_ext_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/integer' +require "abstract_unit" +require "active_support/core_ext/integer" class IntegerExtTest < ActiveSupport::TestCase PRIME = 22953686867719691230002707821868552601124472329079 @@ -19,12 +19,12 @@ class IntegerExtTest < ActiveSupport::TestCase def test_ordinalize # These tests are mostly just to ensure that the ordinalize method exists. # Its results are tested comprehensively in the inflector test cases. - assert_equal '1st', 1.ordinalize - assert_equal '8th', 8.ordinalize + assert_equal "1st", 1.ordinalize + assert_equal "8th", 8.ordinalize end def test_ordinal - assert_equal 'st', 1.ordinal - assert_equal 'th', 8.ordinal + assert_equal "st", 1.ordinal + assert_equal "th", 8.ordinal end end diff --git a/activesupport/test/core_ext/kernel/concern_test.rb b/activesupport/test/core_ext/kernel/concern_test.rb index 478a00d2d2..e7e4f99d7e 100644 --- a/activesupport/test/core_ext/kernel/concern_test.rb +++ b/activesupport/test/core_ext/kernel/concern_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/core_ext/kernel/concern' +require "abstract_unit" +require "active_support/core_ext/kernel/concern" class KernelConcernTest < ActiveSupport::TestCase def test_may_be_defined_at_toplevel - mod = ::TOPLEVEL_BINDING.eval 'concern(:ToplevelConcern) { }' + mod = ::TOPLEVEL_BINDING.eval "concern(:ToplevelConcern) { }" assert_equal mod, ::ToplevelConcern assert_kind_of ActiveSupport::Concern, ::ToplevelConcern assert_not Object.ancestors.include?(::ToplevelConcern), mod.ancestors.inspect diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb index 503e6595cb..db0008b735 100644 --- a/activesupport/test/core_ext/kernel_test.rb +++ b/activesupport/test/core_ext/kernel_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/kernel' +require "abstract_unit" +require "active_support/core_ext/kernel" class KernelTest < ActiveSupport::TestCase def test_silence_warnings diff --git a/activesupport/test/core_ext/load_error_test.rb b/activesupport/test/core_ext/load_error_test.rb index b2a75a2bcc..b50a35b2cb 100644 --- a/activesupport/test/core_ext/load_error_test.rb +++ b/activesupport/test/core_ext/load_error_test.rb @@ -1,6 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/load_error' - +require "abstract_unit" +require "active_support/core_ext/load_error" class TestMissingSourceFile < ActiveSupport::TestCase def test_it_is_deprecated @@ -15,12 +14,12 @@ class TestLoadError < ActiveSupport::TestCase assert_raise(LoadError) { require 'no_this_file_don\'t_exist' } end def test_with_load - assert_raise(LoadError) { load 'nor_does_this_one' } + assert_raise(LoadError) { load "nor_does_this_one" } end def test_path - begin load 'nor/this/one.rb' + begin load "nor/this/one.rb" rescue LoadError => e - assert_equal 'nor/this/one.rb', e.path + assert_equal "nor/this/one.rb", e.path end end end diff --git a/activesupport/test/core_ext/marshal_test.rb b/activesupport/test/core_ext/marshal_test.rb index 380f64c6fd..a899f98705 100644 --- a/activesupport/test/core_ext/marshal_test.rb +++ b/activesupport/test/core_ext/marshal_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/marshal' -require 'dependencies_test_helpers' +require "abstract_unit" +require "active_support/core_ext/marshal" +require "dependencies_test_helpers" class MarshalTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -12,7 +12,7 @@ class MarshalTest < ActiveSupport::TestCase end test "that Marshal#load still works" do - sanity_data = ["test", [1, 2, 3], {a: [1, 2, 3]}, ActiveSupport::TestCase] + sanity_data = ["test", [1, 2, 3], { a: [1, 2, 3] }, ActiveSupport::TestCase] sanity_data.each do |obj| dumped = Marshal.dump(obj) assert_equal Marshal.method(:load).super_method.call(dumped), Marshal.load(dumped) diff --git a/activesupport/test/core_ext/module/anonymous_test.rb b/activesupport/test/core_ext/module/anonymous_test.rb index cb556af772..f885444284 100644 --- a/activesupport/test/core_ext/module/anonymous_test.rb +++ b/activesupport/test/core_ext/module/anonymous_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/anonymous' +require "abstract_unit" +require "active_support/core_ext/module/anonymous" class AnonymousTest < ActiveSupport::TestCase test "an anonymous class or module are anonymous" do @@ -11,4 +11,4 @@ class AnonymousTest < ActiveSupport::TestCase assert !Kernel.anonymous? assert !Object.anonymous? end -end
\ No newline at end of file +end diff --git a/activesupport/test/core_ext/module/attr_internal_test.rb b/activesupport/test/core_ext/module/attr_internal_test.rb index 2aea14cf2b..8458e278ee 100644 --- a/activesupport/test/core_ext/module/attr_internal_test.rb +++ b/activesupport/test/core_ext/module/attr_internal_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/attr_internal' +require "abstract_unit" +require "active_support/core_ext/module/attr_internal" class AttrInternalTest < ActiveSupport::TestCase def setup @@ -10,44 +10,44 @@ class AttrInternalTest < ActiveSupport::TestCase def test_reader assert_nothing_raised { @target.attr_internal_reader :foo } - assert !@instance.instance_variable_defined?('@_foo') + assert !@instance.instance_variable_defined?("@_foo") assert_raise(NoMethodError) { @instance.foo = 1 } - @instance.instance_variable_set('@_foo', 1) + @instance.instance_variable_set("@_foo", 1) assert_nothing_raised { assert_equal 1, @instance.foo } end def test_writer assert_nothing_raised { @target.attr_internal_writer :foo } - assert !@instance.instance_variable_defined?('@_foo') + assert !@instance.instance_variable_defined?("@_foo") assert_nothing_raised { assert_equal 1, @instance.foo = 1 } - assert_equal 1, @instance.instance_variable_get('@_foo') + assert_equal 1, @instance.instance_variable_get("@_foo") assert_raise(NoMethodError) { @instance.foo } end def test_accessor assert_nothing_raised { @target.attr_internal :foo } - assert !@instance.instance_variable_defined?('@_foo') + assert !@instance.instance_variable_defined?("@_foo") assert_nothing_raised { assert_equal 1, @instance.foo = 1 } - assert_equal 1, @instance.instance_variable_get('@_foo') + assert_equal 1, @instance.instance_variable_get("@_foo") assert_nothing_raised { assert_equal 1, @instance.foo } end def test_naming_format - assert_equal '@_%s', Module.attr_internal_naming_format - assert_nothing_raised { Module.attr_internal_naming_format = '@abc%sdef' } + assert_equal "@_%s", Module.attr_internal_naming_format + assert_nothing_raised { Module.attr_internal_naming_format = "@abc%sdef" } @target.attr_internal :foo - assert !@instance.instance_variable_defined?('@_foo') - assert !@instance.instance_variable_defined?('@abcfoodef') + assert !@instance.instance_variable_defined?("@_foo") + assert !@instance.instance_variable_defined?("@abcfoodef") assert_nothing_raised { @instance.foo = 1 } - assert !@instance.instance_variable_defined?('@_foo') - assert @instance.instance_variable_defined?('@abcfoodef') + assert !@instance.instance_variable_defined?("@_foo") + assert @instance.instance_variable_defined?("@abcfoodef") ensure - Module.attr_internal_naming_format = '@_%s' + Module.attr_internal_naming_format = "@_%s" end end diff --git a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb index a9fd878b80..b816fa50e3 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/attribute_accessors_per_thread' +require "abstract_unit" +require "active_support/core_ext/module/attribute_accessors_per_thread" class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase def setup @@ -8,6 +8,12 @@ class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase thread_mattr_accessor :bar, instance_writer: false thread_mattr_reader :shaq, instance_reader: false thread_mattr_accessor :camp, instance_accessor: false + + def self.name; "MyClass" end + end + + @subclass = Class.new(@class) do + def self.name; "SubMyClass" end end @object = @class.new @@ -57,23 +63,23 @@ class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase def test_values_should_not_bleed_between_threads threads = [] threads << Thread.new do - @class.foo = 'things' + @class.foo = "things" sleep 1 - assert_equal 'things', @class.foo + assert_equal "things", @class.foo end threads << Thread.new do - @class.foo = 'other things' + @class.foo = "other things" sleep 1 - assert_equal 'other things', @class.foo + assert_equal "other things", @class.foo end - + threads << Thread.new do - @class.foo = 'really other things' + @class.foo = "really other things" sleep 1 - assert_equal 'really other things', @class.foo + assert_equal "really other things", @class.foo end - + threads.each { |t| t.join } end @@ -108,8 +114,18 @@ class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase end def test_should_return_same_value_by_class_or_instance_accessor - @class.foo = 'fries' + @class.foo = "fries" assert_equal @class.foo, @object.foo end + + def test_should_not_affect_superclass_if_subclass_set_value + @class.foo = "super" + assert_equal @class.foo, "super" + assert_nil @subclass.foo + + @subclass.foo = "sub" + assert_equal @class.foo, "super" + assert_equal @subclass.foo, "sub" + end end diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb index 0b0f3a2808..464a000d59 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb @@ -1,17 +1,17 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/attribute_accessors' +require "abstract_unit" +require "active_support/core_ext/module/attribute_accessors" class ModuleAttributeAccessorTest < ActiveSupport::TestCase def setup m = @module = Module.new do mattr_accessor :foo - mattr_accessor :bar, :instance_writer => false - mattr_reader :shaq, :instance_reader => false - mattr_accessor :camp, :instance_accessor => false + mattr_accessor :bar, instance_writer: false + mattr_reader :shaq, instance_reader: false + mattr_accessor :camp, instance_accessor: false - cattr_accessor(:defa) { 'default_accessor_value' } - cattr_reader(:defr) { 'default_reader_value' } - cattr_writer(:defw) { 'default_writer_value' } + cattr_accessor(:defa) { "default_accessor_value" } + cattr_reader(:defr) { "default_reader_value" } + cattr_writer(:defw) { "default_writer_value" } cattr_accessor(:quux) { :quux } end @class = Class.new @@ -86,14 +86,14 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase end def test_should_use_default_value_if_block_passed - assert_equal 'default_accessor_value', @module.defa - assert_equal 'default_reader_value', @module.defr - assert_equal 'default_writer_value', @module.class_variable_get('@@defw') + assert_equal "default_accessor_value", @module.defa + assert_equal "default_reader_value", @module.defr + assert_equal "default_writer_value", @module.class_variable_get("@@defw") end def test_should_not_invoke_default_value_block_multiple_times count = 0 - @module.cattr_accessor(:defcount){ count += 1 } + @module.cattr_accessor(:defcount) { count += 1 } assert_equal 1, count end end diff --git a/activesupport/test/core_ext/module/attribute_aliasing_test.rb b/activesupport/test/core_ext/module/attribute_aliasing_test.rb index 29c3053b47..d8c2dfd6b8 100644 --- a/activesupport/test/core_ext/module/attribute_aliasing_test.rb +++ b/activesupport/test/core_ext/module/attribute_aliasing_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/aliasing' +require "abstract_unit" +require "active_support/core_ext/module/aliasing" module AttributeAliasing class Content diff --git a/activesupport/test/core_ext/module/concerning_test.rb b/activesupport/test/core_ext/module/concerning_test.rb index 07d860b71c..098036828a 100644 --- a/activesupport/test/core_ext/module/concerning_test.rb +++ b/activesupport/test/core_ext/module/concerning_test.rb @@ -1,10 +1,10 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/concerning' +require "abstract_unit" +require "active_support/core_ext/module/concerning" class ModuleConcerningTest < ActiveSupport::TestCase def test_concerning_declares_a_concern_and_includes_it_immediately - klass = Class.new { concerning(:Foo) { } } - assert klass.ancestors.include?(klass::Foo), klass.ancestors.inspect + klass = Class.new { concerning(:Foo) {} } + assert_includes klass.ancestors, klass::Foo, klass.ancestors.inspect end end @@ -21,13 +21,13 @@ class ModuleConcernTest < ActiveSupport::TestCase assert klass.const_defined?(:Baz, false) assert !ModuleConcernTest.const_defined?(:Baz) assert_kind_of ActiveSupport::Concern, klass::Baz - assert !klass.ancestors.include?(klass::Baz), klass.ancestors.inspect + assert_not_includes klass.ancestors, klass::Baz, klass.ancestors.inspect # Public method visibility by default - assert klass::Baz.public_instance_methods.map(&:to_s).include?('should_be_public') + assert_includes klass::Baz.public_instance_methods.map(&:to_s), "should_be_public" # Calls included hook - assert_equal 1, Class.new { include klass::Baz }.instance_variable_get('@foo') + assert_equal 1, Class.new { include klass::Baz }.instance_variable_get("@foo") end class Foo diff --git a/activesupport/test/core_ext/module/qualified_const_test.rb b/activesupport/test/core_ext/module/qualified_const_test.rb index a3146cabe1..418bc80ab9 100644 --- a/activesupport/test/core_ext/module/qualified_const_test.rb +++ b/activesupport/test/core_ext/module/qualified_const_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/qualified_const' +require "abstract_unit" +require "active_support/core_ext/module/qualified_const" module QualifiedConstTestMod X = false @@ -68,7 +68,7 @@ class QualifiedConstTest < ActiveSupport::TestCase assert_equal 1, QualifiedConstTestMod.qualified_const_get("N::X") assert_equal 2, QualifiedConstTestMod.qualified_const_get("M::C::X") - assert_raise(NameError) { QualifiedConstTestMod.qualified_const_get("M::C::Y")} + assert_raise(NameError) { QualifiedConstTestMod.qualified_const_get("M::C::Y") } end end @@ -89,8 +89,8 @@ class QualifiedConstTest < ActiveSupport::TestCase end ensure silence_warnings do - QualifiedConstTestMod.qualified_const_set('QualifiedConstTestMod::X', false) - QualifiedConstTestMod::M.qualified_const_set('X', 1) + QualifiedConstTestMod.qualified_const_set("QualifiedConstTestMod::X", false) + QualifiedConstTestMod::M.qualified_const_set("X", 1) end end end @@ -98,21 +98,21 @@ class QualifiedConstTest < ActiveSupport::TestCase test "reject absolute paths" do assert_deprecated do - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X")} - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X::Y")} + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X") } + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_defined?("::X::Y") } - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X")} - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X::Y")} + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X") } + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_get("::X::Y") } - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X", nil)} - assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X::Y", nil)} + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X", nil) } + assert_raise_with_message(NameError, "wrong constant name ::X") { Object.qualified_const_set("::X::Y", nil) } end end private - def assert_raise_with_message(expected_exception, expected_message, &block) - exception = assert_raise(expected_exception, &block) - assert_equal expected_message, exception.message - end + def assert_raise_with_message(expected_exception, expected_message, &block) + exception = assert_raise(expected_exception, &block) + assert_equal expected_message, exception.message + end end diff --git a/activesupport/test/core_ext/module/reachable_test.rb b/activesupport/test/core_ext/module/reachable_test.rb index 80eb31a5c4..487c7dee16 100644 --- a/activesupport/test/core_ext/module/reachable_test.rb +++ b/activesupport/test/core_ext/module/reachable_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/reachable' +require "abstract_unit" +require "active_support/core_ext/module/reachable" class AnonymousTest < ActiveSupport::TestCase test "an anonymous class or module is not reachable" do @@ -38,4 +38,4 @@ class AnonymousTest < ActiveSupport::TestCase assert !c.reachable? assert !m.reachable? end -end
\ No newline at end of file +end diff --git a/activesupport/test/core_ext/module/remove_method_test.rb b/activesupport/test/core_ext/module/remove_method_test.rb index 0d684dc70e..0c627f1e74 100644 --- a/activesupport/test/core_ext/module/remove_method_test.rb +++ b/activesupport/test/core_ext/module/remove_method_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/remove_method' +require "abstract_unit" +require "active_support/core_ext/module/remove_method" module RemoveMethodTests class A @@ -26,26 +26,25 @@ module RemoveMethodTests end class RemoveMethodTest < ActiveSupport::TestCase - def test_remove_method_from_an_object - RemoveMethodTests::A.class_eval{ - self.remove_possible_method(:do_something) + RemoveMethodTests::A.class_eval { + remove_possible_method(:do_something) } assert !RemoveMethodTests::A.new.respond_to?(:do_something) end def test_remove_singleton_method_from_an_object - RemoveMethodTests::A.class_eval{ - self.remove_possible_singleton_method(:do_something_else) + RemoveMethodTests::A.class_eval { + remove_possible_singleton_method(:do_something_else) } assert !RemoveMethodTests::A.respond_to?(:do_something_else) end def test_redefine_method_in_an_object - RemoveMethodTests::A.class_eval{ - self.redefine_method(:do_something) { return 100 } - self.redefine_method(:do_something_protected) { return 100 } - self.redefine_method(:do_something_private) { return 100 } + RemoveMethodTests::A.class_eval { + redefine_method(:do_something) { return 100 } + redefine_method(:do_something_protected) { return 100 } + redefine_method(:do_something_private) { return 100 } } assert_equal 100, RemoveMethodTests::A.new.do_something assert_equal 100, RemoveMethodTests::A.new.send(:do_something_protected) @@ -55,5 +54,4 @@ class RemoveMethodTest < ActiveSupport::TestCase assert RemoveMethodTests::A.protected_method_defined? :do_something_protected assert RemoveMethodTests::A.private_method_defined? :do_something_private end - end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index 566f29b470..36073b28b7 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module' +require "abstract_unit" +require "active_support/core_ext/module" module One Constant1 = "Hello World" @@ -25,56 +25,56 @@ Somewhere = Struct.new(:street, :city) do end class Someone < Struct.new(:name, :place) - delegate :street, :city, :to_f, :to => :place - delegate :name=, :to => :place, :prefix => true - delegate :upcase, :to => "place.city" - delegate :table_name, :to => :class - delegate :table_name, :to => :class, :prefix => true + delegate :street, :city, :to_f, to: :place + delegate :name=, to: :place, prefix: true + delegate :upcase, to: "place.city" + delegate :table_name, to: :class + delegate :table_name, to: :class, prefix: true def self.table_name - 'some_table' + "some_table" end FAILED_DELEGATE_LINE = __LINE__ + 1 - delegate :foo, :to => :place + delegate :foo, to: :place FAILED_DELEGATE_LINE_2 = __LINE__ + 1 - delegate :bar, :to => :place, :allow_nil => true + delegate :bar, to: :place, allow_nil: true private - def private_name - "Private" - end + def private_name + "Private" + end end Invoice = Struct.new(:client) do - delegate :street, :city, :name, :to => :client, :prefix => true - delegate :street, :city, :name, :to => :client, :prefix => :customer + delegate :street, :city, :name, to: :client, prefix: true + delegate :street, :city, :name, to: :client, prefix: :customer end Project = Struct.new(:description, :person) do - delegate :name, :to => :person, :allow_nil => true - delegate :to_f, :to => :description, :allow_nil => true + delegate :name, to: :person, allow_nil: true + delegate :to_f, to: :description, allow_nil: true end Developer = Struct.new(:client) do - delegate :name, :to => :client, :prefix => nil + delegate :name, to: :client, prefix: nil end Event = Struct.new(:case) do - delegate :foo, :to => :case + delegate :foo, to: :case end Tester = Struct.new(:client) do - delegate :name, :to => :client, :prefix => false + delegate :name, to: :client, prefix: false def foo; 1; end end Product = Struct.new(:name) do - delegate :name, :to => :manufacturer, :prefix => true - delegate :name, :to => :type, :prefix => true + delegate :name, to: :manufacturer, prefix: true + delegate :name, to: :type, prefix: true def manufacturer @manufacturer ||= begin @@ -114,15 +114,15 @@ HasBlock = Struct.new(:block) do end class ParameterSet - delegate :[], :[]=, :to => :@params + delegate :[], :[]=, to: :@params def initialize - @params = {:foo => "bar"} + @params = { foo: "bar" } end end class Name - delegate :upcase, :to => :@full_name + delegate :upcase, to: :@full_name def initialize(first, last) @full_name = "#{first} #{last}" @@ -132,8 +132,8 @@ end class SideEffect attr_reader :ints - delegate :to_i, :to => :shift, :allow_nil => true - delegate :to_s, :to => :shift + delegate :to_i, to: :shift, allow_nil: true + delegate :to_s, to: :shift def initialize @ints = [1, 2, 3] @@ -180,8 +180,8 @@ class ModuleTest < ActiveSupport::TestCase end def test_delegation_to_class_method - assert_equal 'some_table', @david.table_name - assert_equal 'some_table', @david.class_table_name + assert_equal "some_table", @david.table_name + assert_equal "some_table", @david.class_table_name end def test_missing_delegation_target @@ -189,7 +189,7 @@ class ModuleTest < ActiveSupport::TestCase Name.send :delegate, :nowhere end assert_raise(ArgumentError) do - Name.send :delegate, :noplace, :tos => :hollywood + Name.send :delegate, :noplace, tos: :hollywood end end @@ -233,7 +233,7 @@ class ModuleTest < ActiveSupport::TestCase def initialize(client) @client = client end - delegate :name, :address, :to => :@client, :prefix => true + delegate :name, :address, to: :@client, prefix: true end end end @@ -261,7 +261,7 @@ class ModuleTest < ActiveSupport::TestCase def test_delegation_with_allow_nil_and_nil_value_and_prefix Project.class_eval do - delegate :name, :to => :person, :allow_nil => true, :prefix => true + delegate :name, to: :person, allow_nil: true, prefix: true end rails = Project.new("Rails") assert_nil rails.person_name @@ -290,7 +290,7 @@ class ModuleTest < ActiveSupport::TestCase assert_nothing_raised do Class.new(parent) do class << self - delegate :parent_method, :to => :superclass + delegate :parent_method, to: :superclass end end end @@ -312,7 +312,7 @@ class ModuleTest < ActiveSupport::TestCase rescue NoMethodError => e file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE}" # We can't simply check the first line of the backtrace, because JRuby reports the call to __send__ in the backtrace. - assert e.backtrace.any?{|a| a.include?(file_and_line)}, + assert e.backtrace.any? { |a| a.include?(file_and_line) }, "[#{e.backtrace.inspect}] did not include [#{file_and_line}]" end @@ -322,7 +322,7 @@ class ModuleTest < ActiveSupport::TestCase rescue NoMethodError => e file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE_2}" # We can't simply check the first line of the backtrace, because JRuby reports the call to __send__ in the backtrace. - assert e.backtrace.any?{|a| a.include?(file_and_line)}, + assert e.backtrace.any? { |a| a.include?(file_and_line) }, "[#{e.backtrace.inspect}] did not include [#{file_and_line}]" end @@ -332,12 +332,12 @@ class ModuleTest < ActiveSupport::TestCase assert_equal 1, se.to_i assert_equal [2, 3], se.ints - assert_equal '2', se.to_s + assert_equal "2", se.to_s assert_equal [3], se.ints end def test_delegation_doesnt_mask_nested_no_method_error_on_nil_receiver - product = Product.new('Widget') + product = Product.new("Widget") # Nested NoMethodError is a different name from the delegation assert_raise(NoMethodError) { product.manufacturer_name } @@ -408,11 +408,11 @@ end module BarMethods def bar_with_baz - bar_without_baz << '_with_baz' + bar_without_baz << "_with_baz" end def quux_with_baz! - quux_without_baz! << '_with_baz' + quux_without_baz! << "_with_baz" end def quux_with_baz? @@ -420,17 +420,17 @@ module BarMethods end def quux_with_baz=(v) - send(:quux_without_baz=, v) << '_with_baz' + send(:quux_without_baz=, v) << "_with_baz" end def duck_with_orange - duck_without_orange << '_with_orange' + duck_without_orange << "_with_orange" end end class MethodAliasingTest < ActiveSupport::TestCase def setup - Object.const_set :FooClassWithBarMethod, Class.new { def bar() 'bar' end } + Object.const_set :FooClassWithBarMethod, Class.new { def bar() "bar" end } @instance = FooClassWithBarMethod.new end @@ -461,7 +461,7 @@ class MethodAliasingTest < ActiveSupport::TestCase assert !@instance.respond_to?(method) end - assert_equal 'bar', @instance.bar + assert_equal "bar", @instance.bar FooClassWithBarMethod.class_eval { include BarMethodAliaser } @@ -469,15 +469,15 @@ class MethodAliasingTest < ActiveSupport::TestCase assert_respond_to @instance, method end - assert_equal 'bar_with_baz', @instance.bar - assert_equal 'bar', @instance.bar_without_baz + assert_equal "bar_with_baz", @instance.bar + assert_equal "bar", @instance.bar_without_baz end end def test_alias_method_chain_with_punctuation_method assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def quux!; 'quux' end + def quux!; "quux" end end assert !@instance.respond_to?(:quux_with_baz!) @@ -487,17 +487,17 @@ class MethodAliasingTest < ActiveSupport::TestCase end assert_respond_to @instance, :quux_with_baz! - assert_equal 'quux_with_baz', @instance.quux! - assert_equal 'quux', @instance.quux_without_baz! + assert_equal "quux_with_baz", @instance.quux! + assert_equal "quux", @instance.quux_without_baz! end end def test_alias_method_chain_with_same_names_between_predicates_and_bang_methods assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def quux!; 'quux!' end + def quux!; "quux!" end def quux?; true end - def quux=(v); 'quux=' end + def quux=(v); "quux=" end end assert !@instance.respond_to?(:quux_with_baz!) @@ -509,32 +509,31 @@ class MethodAliasingTest < ActiveSupport::TestCase assert_respond_to @instance, :quux_with_baz? assert_respond_to @instance, :quux_with_baz= - FooClassWithBarMethod.alias_method_chain :quux!, :baz - assert_equal 'quux!_with_baz', @instance.quux! - assert_equal 'quux!', @instance.quux_without_baz! + assert_equal "quux!_with_baz", @instance.quux! + assert_equal "quux!", @instance.quux_without_baz! FooClassWithBarMethod.alias_method_chain :quux?, :baz assert_equal false, @instance.quux? assert_equal true, @instance.quux_without_baz? FooClassWithBarMethod.alias_method_chain :quux=, :baz - assert_equal 'quux=_with_baz', @instance.send(:quux=, 1234) - assert_equal 'quux=', @instance.send(:quux_without_baz=, 1234) + assert_equal "quux=_with_baz", @instance.send(:quux=, 1234) + assert_equal "quux=", @instance.send(:quux_without_baz=, 1234) end end def test_alias_method_chain_with_feature_punctuation assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def quux; 'quux' end - def quux?; 'quux?' end + def quux; "quux" end + def quux?; "quux?" end include BarMethodAliaser alias_method_chain :quux, :baz! end assert_nothing_raised do - assert_equal 'quux_with_baz', @instance.quux_with_baz! + assert_equal "quux_with_baz", @instance.quux_with_baz! end assert_raise(NameError) do @@ -557,15 +556,15 @@ class MethodAliasingTest < ActiveSupport::TestCase end assert_not_nil args - assert_equal 'quux', args[0] - assert_equal '?', args[1] + assert_equal "quux", args[0] + assert_equal "?", args[1] end end def test_alias_method_chain_preserves_private_method_status assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def duck; 'duck' end + def duck; "duck" end include BarMethodAliaser private :duck alias_method_chain :duck, :orange @@ -575,7 +574,7 @@ class MethodAliasingTest < ActiveSupport::TestCase @instance.duck end - assert_equal 'duck_with_orange', @instance.instance_eval { duck } + assert_equal "duck_with_orange", @instance.instance_eval { duck } assert FooClassWithBarMethod.private_method_defined?(:duck) end end @@ -583,7 +582,7 @@ class MethodAliasingTest < ActiveSupport::TestCase def test_alias_method_chain_preserves_protected_method_status assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def duck; 'duck' end + def duck; "duck" end include BarMethodAliaser protected :duck alias_method_chain :duck, :orange @@ -593,7 +592,7 @@ class MethodAliasingTest < ActiveSupport::TestCase @instance.duck end - assert_equal 'duck_with_orange', @instance.instance_eval { duck } + assert_equal "duck_with_orange", @instance.instance_eval { duck } assert FooClassWithBarMethod.protected_method_defined?(:duck) end end @@ -601,13 +600,13 @@ class MethodAliasingTest < ActiveSupport::TestCase def test_alias_method_chain_preserves_public_method_status assert_deprecated(/alias_method_chain/) do FooClassWithBarMethod.class_eval do - def duck; 'duck' end + def duck; "duck" end include BarMethodAliaser public :duck alias_method_chain :duck, :orange end - assert_equal 'duck_with_orange', @instance.duck + assert_equal "duck_with_orange", @instance.duck assert FooClassWithBarMethod.public_method_defined?(:duck) end end diff --git a/activesupport/test/core_ext/name_error_test.rb b/activesupport/test/core_ext/name_error_test.rb index 7525f80cf0..fdb9493d3c 100644 --- a/activesupport/test/core_ext/name_error_test.rb +++ b/activesupport/test/core_ext/name_error_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/name_error' +require "abstract_unit" +require "active_support/core_ext/name_error" class NameErrorTest < ActiveSupport::TestCase def test_name_error_should_set_missing_name diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb index 69c30a8a9e..5e824747ed 100644 --- a/activesupport/test/core_ext/numeric_ext_test.rb +++ b/activesupport/test/core_ext/numeric_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'active_support/core_ext/numeric' -require 'active_support/core_ext/integer' +require "abstract_unit" +require "active_support/time" +require "active_support/core_ext/numeric" +require "active_support/core_ext/integer" class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase def setup @@ -23,41 +23,41 @@ class NumericExtTimeAndDateTimeTest < ActiveSupport::TestCase end def test_irregular_durations - assert_equal @now.advance(:days => 3000), 3000.days.since(@now) - assert_equal @now.advance(:months => 1), 1.month.since(@now) - assert_equal @now.advance(:months => -1), 1.month.until(@now) - assert_equal @now.advance(:years => 20), 20.years.since(@now) - assert_equal @dtnow.advance(:days => 3000), 3000.days.since(@dtnow) - assert_equal @dtnow.advance(:months => 1), 1.month.since(@dtnow) - assert_equal @dtnow.advance(:months => -1), 1.month.until(@dtnow) - assert_equal @dtnow.advance(:years => 20), 20.years.since(@dtnow) + assert_equal @now.advance(days: 3000), 3000.days.since(@now) + assert_equal @now.advance(months: 1), 1.month.since(@now) + assert_equal @now.advance(months: -1), 1.month.until(@now) + assert_equal @now.advance(years: 20), 20.years.since(@now) + assert_equal @dtnow.advance(days: 3000), 3000.days.since(@dtnow) + assert_equal @dtnow.advance(months: 1), 1.month.since(@dtnow) + assert_equal @dtnow.advance(months: -1), 1.month.until(@dtnow) + assert_equal @dtnow.advance(years: 20), 20.years.since(@dtnow) end def test_duration_addition - assert_equal @now.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@now) - assert_equal @now.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@now) - assert_equal @now.advance(:years => 2), (4.years - 2.years).since(@now) - assert_equal @dtnow.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@dtnow) - assert_equal @dtnow.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@dtnow) - assert_equal @dtnow.advance(:years => 2), (4.years - 2.years).since(@dtnow) + assert_equal @now.advance(days: 1).advance(months: 1), (1.day + 1.month).since(@now) + assert_equal @now.advance(days: 7), (1.week + 5.seconds - 5.seconds).since(@now) + assert_equal @now.advance(years: 2), (4.years - 2.years).since(@now) + assert_equal @dtnow.advance(days: 1).advance(months: 1), (1.day + 1.month).since(@dtnow) + assert_equal @dtnow.advance(days: 7), (1.week + 5.seconds - 5.seconds).since(@dtnow) + assert_equal @dtnow.advance(years: 2), (4.years - 2.years).since(@dtnow) end def test_time_plus_duration assert_equal @now + 8, @now + 8.seconds assert_equal @now + 22.9, @now + 22.9.seconds - assert_equal @now.advance(:days => 15), @now + 15.days - assert_equal @now.advance(:months => 1), @now + 1.month + assert_equal @now.advance(days: 15), @now + 15.days + assert_equal @now.advance(months: 1), @now + 1.month assert_equal @dtnow.since(8), @dtnow + 8.seconds assert_equal @dtnow.since(22.9), @dtnow + 22.9.seconds - assert_equal @dtnow.advance(:days => 15), @dtnow + 15.days - assert_equal @dtnow.advance(:months => 1), @dtnow + 1.month + assert_equal @dtnow.advance(days: 15), @dtnow + 15.days + assert_equal @dtnow.advance(months: 1), @dtnow + 1.month end def test_chaining_duration_operations - assert_equal @now.advance(:days => 2).advance(:months => -3), @now + 2.days - 3.months - assert_equal @now.advance(:days => 1).advance(:months => 2), @now + 1.day + 2.months - assert_equal @dtnow.advance(:days => 2).advance(:months => -3), @dtnow + 2.days - 3.months - assert_equal @dtnow.advance(:days => 1).advance(:months => 2), @dtnow + 1.day + 2.months + assert_equal @now.advance(days: 2).advance(months: -3), @now + 2.days - 3.months + assert_equal @now.advance(days: 1).advance(months: 2), @now + 1.day + 2.months + assert_equal @dtnow.advance(days: 2).advance(months: -3), @dtnow + 2.days - 3.months + assert_equal @dtnow.advance(days: 1).advance(months: 2), @dtnow + 1.day + 2.months end def test_duration_after_conversion_is_no_longer_accurate @@ -87,8 +87,8 @@ class NumericExtDateTest < ActiveSupport::TestCase end def test_chaining_duration_operations - assert_equal @today.advance(:days => 2).advance(:months => -3), @today + 2.days - 3.months - assert_equal @today.advance(:days => 1).advance(:months => 2), @today + 1.day + 2.months + assert_equal @today.advance(days: 2).advance(months: -3), @today + 2.days - 3.months + assert_equal @today.advance(days: 1).advance(months: 2), @today + 1.day + 2.months end def test_add_one_year_to_leap_day @@ -154,53 +154,52 @@ class NumericExtFormattingTest < ActiveSupport::TestCase def test_to_s__phone assert_equal("555-1234", 5551234.to_s(:phone)) assert_equal("800-555-1212", 8005551212.to_s(:phone)) - assert_equal("(800) 555-1212", 8005551212.to_s(:phone, :area_code => true)) - assert_equal("800 555 1212", 8005551212.to_s(:phone, :delimiter => " ")) - assert_equal("(800) 555-1212 x 123", 8005551212.to_s(:phone, :area_code => true, :extension => 123)) - assert_equal("800-555-1212", 8005551212.to_s(:phone, :extension => " ")) - assert_equal("555.1212", 5551212.to_s(:phone, :delimiter => '.')) - assert_equal("+1-800-555-1212", 8005551212.to_s(:phone, :country_code => 1)) - assert_equal("+18005551212", 8005551212.to_s(:phone, :country_code => 1, :delimiter => '')) + assert_equal("(800) 555-1212", 8005551212.to_s(:phone, area_code: true)) + assert_equal("800 555 1212", 8005551212.to_s(:phone, delimiter: " ")) + assert_equal("(800) 555-1212 x 123", 8005551212.to_s(:phone, area_code: true, extension: 123)) + assert_equal("800-555-1212", 8005551212.to_s(:phone, extension: " ")) + assert_equal("555.1212", 5551212.to_s(:phone, delimiter: ".")) + assert_equal("+1-800-555-1212", 8005551212.to_s(:phone, country_code: 1)) + assert_equal("+18005551212", 8005551212.to_s(:phone, country_code: 1, delimiter: "")) assert_equal("22-555-1212", 225551212.to_s(:phone)) - assert_equal("+45-22-555-1212", 225551212.to_s(:phone, :country_code => 45)) + assert_equal("+45-22-555-1212", 225551212.to_s(:phone, country_code: 45)) end def test_to_s__currency assert_equal("$1,234,567,890.50", 1234567890.50.to_s(:currency)) assert_equal("$1,234,567,890.51", 1234567890.506.to_s(:currency)) assert_equal("-$1,234,567,890.50", -1234567890.50.to_s(:currency)) - assert_equal("-$ 1,234,567,890.50", -1234567890.50.to_s(:currency, :format => "%u %n")) - assert_equal("($1,234,567,890.50)", -1234567890.50.to_s(:currency, :negative_format => "(%u%n)")) - assert_equal("$1,234,567,892", 1234567891.50.to_s(:currency, :precision => 0)) - assert_equal("$1,234,567,890.5", 1234567890.50.to_s(:currency, :precision => 1)) - assert_equal("£1234567890,50", 1234567890.50.to_s(:currency, :unit => "£", :separator => ",", :delimiter => "")) + assert_equal("-$ 1,234,567,890.50", -1234567890.50.to_s(:currency, format: "%u %n")) + assert_equal("($1,234,567,890.50)", -1234567890.50.to_s(:currency, negative_format: "(%u%n)")) + assert_equal("$1,234,567,892", 1234567891.50.to_s(:currency, precision: 0)) + assert_equal("$1,234,567,890.5", 1234567890.50.to_s(:currency, precision: 1)) + assert_equal("£1234567890,50", 1234567890.50.to_s(:currency, unit: "£", separator: ",", delimiter: "")) end - def test_to_s__rounded assert_equal("-111.235", -111.2346.to_s(:rounded)) assert_equal("111.235", 111.2346.to_s(:rounded)) - assert_equal("31.83", 31.825.to_s(:rounded, :precision => 2)) - assert_equal("111.23", 111.2346.to_s(:rounded, :precision => 2)) - assert_equal("111.00", 111.to_s(:rounded, :precision => 2)) - assert_equal("3268", (32.6751 * 100.00).to_s(:rounded, :precision => 0)) - assert_equal("112", 111.50.to_s(:rounded, :precision => 0)) - assert_equal("1234567892", 1234567891.50.to_s(:rounded, :precision => 0)) - assert_equal("0", 0.to_s(:rounded, :precision => 0)) - assert_equal("0.00100", 0.001.to_s(:rounded, :precision => 5)) - assert_equal("0.001", 0.00111.to_s(:rounded, :precision => 3)) - assert_equal("10.00", 9.995.to_s(:rounded, :precision => 2)) - assert_equal("11.00", 10.995.to_s(:rounded, :precision => 2)) - assert_equal("0.00", -0.001.to_s(:rounded, :precision => 2)) + assert_equal("31.83", 31.825.to_s(:rounded, precision: 2)) + assert_equal("111.23", 111.2346.to_s(:rounded, precision: 2)) + assert_equal("111.00", 111.to_s(:rounded, precision: 2)) + assert_equal("3268", (32.6751 * 100.00).to_s(:rounded, precision: 0)) + assert_equal("112", 111.50.to_s(:rounded, precision: 0)) + assert_equal("1234567892", 1234567891.50.to_s(:rounded, precision: 0)) + assert_equal("0", 0.to_s(:rounded, precision: 0)) + assert_equal("0.00100", 0.001.to_s(:rounded, precision: 5)) + assert_equal("0.001", 0.00111.to_s(:rounded, precision: 3)) + assert_equal("10.00", 9.995.to_s(:rounded, precision: 2)) + assert_equal("11.00", 10.995.to_s(:rounded, precision: 2)) + assert_equal("0.00", -0.001.to_s(:rounded, precision: 2)) end def test_to_s__percentage assert_equal("100.000%", 100.to_s(:percentage)) - assert_equal("100%", 100.to_s(:percentage, :precision => 0)) - assert_equal("302.06%", 302.0574.to_s(:percentage, :precision => 2)) - assert_equal("123.4%", 123.400.to_s(:percentage, :precision => 3, :strip_insignificant_zeros => true)) - assert_equal("1.000,000%", 1000.to_s(:percentage, :delimiter => '.', :separator => ',')) - assert_equal("1000.000 %", 1000.to_s(:percentage, :format => "%n %")) + assert_equal("100%", 100.to_s(:percentage, precision: 0)) + assert_equal("302.06%", 302.0574.to_s(:percentage, precision: 2)) + assert_equal("123.4%", 123.400.to_s(:percentage, precision: 3, strip_insignificant_zeros: true)) + assert_equal("1.000,000%", 1000.to_s(:percentage, delimiter: ".", separator: ",")) + assert_equal("1000.000 %", 1000.to_s(:percentage, format: "%n %")) end def test_to_s__delimited @@ -216,181 +215,180 @@ class NumericExtFormattingTest < ActiveSupport::TestCase end def test_to_s__delimited__with_options_hash - assert_equal '12 345 678', 12345678.to_s(:delimited, :delimiter => ' ') - assert_equal '12,345,678-05', 12345678.05.to_s(:delimited, :separator => '-') - assert_equal '12.345.678,05', 12345678.05.to_s(:delimited, :separator => ',', :delimiter => '.') - assert_equal '12.345.678,05', 12345678.05.to_s(:delimited, :delimiter => '.', :separator => ',') + assert_equal "12 345 678", 12345678.to_s(:delimited, delimiter: " ") + assert_equal "12,345,678-05", 12345678.05.to_s(:delimited, separator: "-") + assert_equal "12.345.678,05", 12345678.05.to_s(:delimited, separator: ",", delimiter: ".") + assert_equal "12.345.678,05", 12345678.05.to_s(:delimited, delimiter: ".", separator: ",") end - def test_to_s__rounded_with_custom_delimiter_and_separator - assert_equal '31,83', 31.825.to_s(:rounded, :precision => 2, :separator => ',') - assert_equal '1.231,83', 1231.825.to_s(:rounded, :precision => 2, :separator => ',', :delimiter => '.') + assert_equal "31,83", 31.825.to_s(:rounded, precision: 2, separator: ",") + assert_equal "1.231,83", 1231.825.to_s(:rounded, precision: 2, separator: ",", delimiter: ".") end def test_to_s__rounded__with_significant_digits - assert_equal "124000", 123987.to_s(:rounded, :precision => 3, :significant => true) - assert_equal "120000000", 123987876.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "9775", 9775.to_s(:rounded, :precision => 4, :significant => true ) - assert_equal "5.4", 5.3923.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "5", 5.3923.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "1", 1.232.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "7", 7.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "1", 1.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "53", 52.7923.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "9775.00", 9775.to_s(:rounded, :precision => 6, :significant => true ) - assert_equal "5.392900", 5.3929.to_s(:rounded, :precision => 7, :significant => true ) - assert_equal "0.0", 0.to_s(:rounded, :precision => 2, :significant => true ) - assert_equal "0", 0.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "0.0001", 0.0001.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "0.000100", 0.0001.to_s(:rounded, :precision => 3, :significant => true ) - assert_equal "0.0001", 0.0001111.to_s(:rounded, :precision => 1, :significant => true ) - assert_equal "10.0", 9.995.to_s(:rounded, :precision => 3, :significant => true) - assert_equal "9.99", 9.994.to_s(:rounded, :precision => 3, :significant => true) - assert_equal "11.0", 10.995.to_s(:rounded, :precision => 3, :significant => true) + assert_equal "124000", 123987.to_s(:rounded, precision: 3, significant: true) + assert_equal "120000000", 123987876.to_s(:rounded, precision: 2, significant: true ) + assert_equal "9775", 9775.to_s(:rounded, precision: 4, significant: true ) + assert_equal "5.4", 5.3923.to_s(:rounded, precision: 2, significant: true ) + assert_equal "5", 5.3923.to_s(:rounded, precision: 1, significant: true ) + assert_equal "1", 1.232.to_s(:rounded, precision: 1, significant: true ) + assert_equal "7", 7.to_s(:rounded, precision: 1, significant: true ) + assert_equal "1", 1.to_s(:rounded, precision: 1, significant: true ) + assert_equal "53", 52.7923.to_s(:rounded, precision: 2, significant: true ) + assert_equal "9775.00", 9775.to_s(:rounded, precision: 6, significant: true ) + assert_equal "5.392900", 5.3929.to_s(:rounded, precision: 7, significant: true ) + assert_equal "0.0", 0.to_s(:rounded, precision: 2, significant: true ) + assert_equal "0", 0.to_s(:rounded, precision: 1, significant: true ) + assert_equal "0.0001", 0.0001.to_s(:rounded, precision: 1, significant: true ) + assert_equal "0.000100", 0.0001.to_s(:rounded, precision: 3, significant: true ) + assert_equal "0.0001", 0.0001111.to_s(:rounded, precision: 1, significant: true ) + assert_equal "10.0", 9.995.to_s(:rounded, precision: 3, significant: true) + assert_equal "9.99", 9.994.to_s(:rounded, precision: 3, significant: true) + assert_equal "11.0", 10.995.to_s(:rounded, precision: 3, significant: true) end def test_to_s__rounded__with_strip_insignificant_zeros - assert_equal "9775.43", 9775.43.to_s(:rounded, :precision => 4, :strip_insignificant_zeros => true ) - assert_equal "9775.2", 9775.2.to_s(:rounded, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) - assert_equal "0", 0.to_s(:rounded, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) + assert_equal "9775.43", 9775.43.to_s(:rounded, precision: 4, strip_insignificant_zeros: true ) + assert_equal "9775.2", 9775.2.to_s(:rounded, precision: 6, significant: true, strip_insignificant_zeros: true ) + assert_equal "0", 0.to_s(:rounded, precision: 6, significant: true, strip_insignificant_zeros: true ) end def test_to_s__rounded__with_significant_true_and_zero_precision # Zero precision with significant is a mistake (would always return zero), # so we treat it as if significant was false (increases backwards compatibility for number_to_human_size) - assert_equal "124", 123.987.to_s(:rounded, :precision => 0, :significant => true) - assert_equal "12", 12.to_s(:rounded, :precision => 0, :significant => true ) + assert_equal "124", 123.987.to_s(:rounded, precision: 0, significant: true) + assert_equal "12", 12.to_s(:rounded, precision: 0, significant: true ) end def test_to_s__human_size - assert_equal '0 Bytes', 0.to_s(:human_size) - assert_equal '1 Byte', 1.to_s(:human_size) - assert_equal '3 Bytes', 3.14159265.to_s(:human_size) - assert_equal '123 Bytes', 123.0.to_s(:human_size) - assert_equal '123 Bytes', 123.to_s(:human_size) - assert_equal '1.21 KB', 1234.to_s(:human_size) - assert_equal '12.1 KB', 12345.to_s(:human_size) - assert_equal '1.18 MB', 1234567.to_s(:human_size) - assert_equal '1.15 GB', 1234567890.to_s(:human_size) - assert_equal '1.12 TB', 1234567890123.to_s(:human_size) - assert_equal '1.1 PB', 1234567890123456.to_s(:human_size) - assert_equal '1.07 EB', 1234567890123456789.to_s(:human_size) - assert_equal '1030 EB', exabytes(1026).to_s(:human_size) - assert_equal '444 KB', kilobytes(444).to_s(:human_size) - assert_equal '1020 MB', megabytes(1023).to_s(:human_size) - assert_equal '3 TB', terabytes(3).to_s(:human_size) - assert_equal '1.2 MB', 1234567.to_s(:human_size, :precision => 2) - assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :precision => 4) - assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2) - assert_equal '1.01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4) - assert_equal '10 KB', kilobytes(10.000).to_s(:human_size, :precision => 4) - assert_equal '1 Byte', 1.1.to_s(:human_size) - assert_equal '10 Bytes', 10.to_s(:human_size) + assert_equal "0 Bytes", 0.to_s(:human_size) + assert_equal "1 Byte", 1.to_s(:human_size) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size) + assert_equal "123 Bytes", 123.0.to_s(:human_size) + assert_equal "123 Bytes", 123.to_s(:human_size) + assert_equal "1.21 KB", 1234.to_s(:human_size) + assert_equal "12.1 KB", 12345.to_s(:human_size) + assert_equal "1.18 MB", 1234567.to_s(:human_size) + assert_equal "1.15 GB", 1234567890.to_s(:human_size) + assert_equal "1.12 TB", 1234567890123.to_s(:human_size) + assert_equal "1.1 PB", 1234567890123456.to_s(:human_size) + assert_equal "1.07 EB", 1234567890123456789.to_s(:human_size) + assert_equal "1030 EB", exabytes(1026).to_s(:human_size) + assert_equal "444 KB", kilobytes(444).to_s(:human_size) + assert_equal "1020 MB", megabytes(1023).to_s(:human_size) + assert_equal "3 TB", terabytes(3).to_s(:human_size) + assert_equal "1.2 MB", 1234567.to_s(:human_size, precision: 2) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size, precision: 4) + assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 2) + assert_equal "1.01 KB", kilobytes(1.0100).to_s(:human_size, precision: 4) + assert_equal "10 KB", kilobytes(10.000).to_s(:human_size, precision: 4) + assert_equal "1 Byte", 1.1.to_s(:human_size) + assert_equal "10 Bytes", 10.to_s(:human_size) end def test_to_s__human_size_with_si_prefix assert_deprecated do - assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :prefix => :si) - assert_equal '123 Bytes', 123.0.to_s(:human_size, :prefix => :si) - assert_equal '123 Bytes', 123.to_s(:human_size, :prefix => :si) - assert_equal '1.23 KB', 1234.to_s(:human_size, :prefix => :si) - assert_equal '12.3 KB', 12345.to_s(:human_size, :prefix => :si) - assert_equal '1.23 MB', 1234567.to_s(:human_size, :prefix => :si) - assert_equal '1.23 GB', 1234567890.to_s(:human_size, :prefix => :si) - assert_equal '1.23 TB', 1234567890123.to_s(:human_size, :prefix => :si) - assert_equal '1.23 PB', 1234567890123456.to_s(:human_size, :prefix => :si) - assert_equal '1.23 EB', 1234567890123456789.to_s(:human_size, :prefix => :si) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size, prefix: :si) + assert_equal "123 Bytes", 123.0.to_s(:human_size, prefix: :si) + assert_equal "123 Bytes", 123.to_s(:human_size, prefix: :si) + assert_equal "1.23 KB", 1234.to_s(:human_size, prefix: :si) + assert_equal "12.3 KB", 12345.to_s(:human_size, prefix: :si) + assert_equal "1.23 MB", 1234567.to_s(:human_size, prefix: :si) + assert_equal "1.23 GB", 1234567890.to_s(:human_size, prefix: :si) + assert_equal "1.23 TB", 1234567890123.to_s(:human_size, prefix: :si) + assert_equal "1.23 PB", 1234567890123456.to_s(:human_size, prefix: :si) + assert_equal "1.23 EB", 1234567890123456789.to_s(:human_size, prefix: :si) end end def test_to_s__human_size_with_options_hash - assert_equal '1.2 MB', 1234567.to_s(:human_size, :precision => 2) - assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :precision => 4) - assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2) - assert_equal '1.01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4) - assert_equal '10 KB', kilobytes(10.000).to_s(:human_size, :precision => 4) - assert_equal '1 TB', 1234567890123.to_s(:human_size, :precision => 1) - assert_equal '500 MB', 524288000.to_s(:human_size, :precision=>3) - assert_equal '10 MB', 9961472.to_s(:human_size, :precision=>0) - assert_equal '40 KB', 41010.to_s(:human_size, :precision => 1) - assert_equal '40 KB', 41100.to_s(:human_size, :precision => 2) - assert_equal '1.0 KB', kilobytes(1.0123).to_s(:human_size, :precision => 2, :strip_insignificant_zeros => false) - assert_equal '1.012 KB', kilobytes(1.0123).to_s(:human_size, :precision => 3, :significant => false) - assert_equal '1 KB', kilobytes(1.0123).to_s(:human_size, :precision => 0, :significant => true) #ignores significant it precision is 0 + assert_equal "1.2 MB", 1234567.to_s(:human_size, precision: 2) + assert_equal "3 Bytes", 3.14159265.to_s(:human_size, precision: 4) + assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 2) + assert_equal "1.01 KB", kilobytes(1.0100).to_s(:human_size, precision: 4) + assert_equal "10 KB", kilobytes(10.000).to_s(:human_size, precision: 4) + assert_equal "1 TB", 1234567890123.to_s(:human_size, precision: 1) + assert_equal "500 MB", 524288000.to_s(:human_size, precision: 3) + assert_equal "10 MB", 9961472.to_s(:human_size, precision: 0) + assert_equal "40 KB", 41010.to_s(:human_size, precision: 1) + assert_equal "40 KB", 41100.to_s(:human_size, precision: 2) + assert_equal "1.0 KB", kilobytes(1.0123).to_s(:human_size, precision: 2, strip_insignificant_zeros: false) + assert_equal "1.012 KB", kilobytes(1.0123).to_s(:human_size, precision: 3, significant: false) + assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 0, significant: true) #ignores significant it precision is 0 end def test_to_s__human_size_with_custom_delimiter_and_separator - assert_equal '1,01 KB', kilobytes(1.0123).to_s(:human_size, :precision => 3, :separator => ',') - assert_equal '1,01 KB', kilobytes(1.0100).to_s(:human_size, :precision => 4, :separator => ',') - assert_equal '1.000,1 TB', terabytes(1000.1).to_s(:human_size, :precision => 5, :delimiter => '.', :separator => ',') + assert_equal "1,01 KB", kilobytes(1.0123).to_s(:human_size, precision: 3, separator: ",") + assert_equal "1,01 KB", kilobytes(1.0100).to_s(:human_size, precision: 4, separator: ",") + assert_equal "1.000,1 TB", terabytes(1000.1).to_s(:human_size, precision: 5, delimiter: ".", separator: ",") end def test_number_to_human - assert_equal '-123', -123.to_s(:human) - assert_equal '-0.5', -0.5.to_s(:human) - assert_equal '0', 0.to_s(:human) - assert_equal '0.5', 0.5.to_s(:human) - assert_equal '123', 123.to_s(:human) - assert_equal '1.23 Thousand', 1234.to_s(:human) - assert_equal '12.3 Thousand', 12345.to_s(:human) - assert_equal '1.23 Million', 1234567.to_s(:human) - assert_equal '1.23 Billion', 1234567890.to_s(:human) - assert_equal '1.23 Trillion', 1234567890123.to_s(:human) - assert_equal '1.23 Quadrillion', 1234567890123456.to_s(:human) - assert_equal '1230 Quadrillion', 1234567890123456789.to_s(:human) - assert_equal '490 Thousand', 489939.to_s(:human, :precision => 2) - assert_equal '489.9 Thousand', 489939.to_s(:human, :precision => 4) - assert_equal '489 Thousand', 489000.to_s(:human, :precision => 4) - assert_equal '489.0 Thousand', 489000.to_s(:human, :precision => 4, :strip_insignificant_zeros => false) - assert_equal '1.2346 Million', 1234567.to_s(:human, :precision => 4, :significant => false) - assert_equal '1,2 Million', 1234567.to_s(:human, :precision => 1, :significant => false, :separator => ',') - assert_equal '1 Million', 1234567.to_s(:human, :precision => 0, :significant => true, :separator => ',') #significant forced to false + assert_equal "-123", -123.to_s(:human) + assert_equal "-0.5", -0.5.to_s(:human) + assert_equal "0", 0.to_s(:human) + assert_equal "0.5", 0.5.to_s(:human) + assert_equal "123", 123.to_s(:human) + assert_equal "1.23 Thousand", 1234.to_s(:human) + assert_equal "12.3 Thousand", 12345.to_s(:human) + assert_equal "1.23 Million", 1234567.to_s(:human) + assert_equal "1.23 Billion", 1234567890.to_s(:human) + assert_equal "1.23 Trillion", 1234567890123.to_s(:human) + assert_equal "1.23 Quadrillion", 1234567890123456.to_s(:human) + assert_equal "1230 Quadrillion", 1234567890123456789.to_s(:human) + assert_equal "490 Thousand", 489939.to_s(:human, precision: 2) + assert_equal "489.9 Thousand", 489939.to_s(:human, precision: 4) + assert_equal "489 Thousand", 489000.to_s(:human, precision: 4) + assert_equal "489.0 Thousand", 489000.to_s(:human, precision: 4, strip_insignificant_zeros: false) + assert_equal "1.2346 Million", 1234567.to_s(:human, precision: 4, significant: false) + assert_equal "1,2 Million", 1234567.to_s(:human, precision: 1, significant: false, separator: ",") + assert_equal "1 Million", 1234567.to_s(:human, precision: 0, significant: true, separator: ",") #significant forced to false end def test_number_to_human_with_custom_units #Only integers - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123 lt', 123456.to_s(:human, :units => volume) - assert_equal '12 ml', 12.to_s(:human, :units => volume) - assert_equal '1.23 m3', 1234567.to_s(:human, :units => volume) + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123 lt", 123456.to_s(:human, units: volume) + assert_equal "12 ml", 12.to_s(:human, units: volume) + assert_equal "1.23 m3", 1234567.to_s(:human, units: volume) #Including fractionals - distance = {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} - assert_equal '1.23 mm', 0.00123.to_s(:human, :units => distance) - assert_equal '1.23 cm', 0.0123.to_s(:human, :units => distance) - assert_equal '1.23 dm', 0.123.to_s(:human, :units => distance) - assert_equal '1.23 m', 1.23.to_s(:human, :units => distance) - assert_equal '1.23 dam', 12.3.to_s(:human, :units => distance) - assert_equal '1.23 hm', 123.to_s(:human, :units => distance) - assert_equal '1.23 km', 1230.to_s(:human, :units => distance) - assert_equal '1.23 km', 1230.to_s(:human, :units => distance) - assert_equal '1.23 km', 1230.to_s(:human, :units => distance) - assert_equal '12.3 km', 12300.to_s(:human, :units => distance) + distance = { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } + assert_equal "1.23 mm", 0.00123.to_s(:human, units: distance) + assert_equal "1.23 cm", 0.0123.to_s(:human, units: distance) + assert_equal "1.23 dm", 0.123.to_s(:human, units: distance) + assert_equal "1.23 m", 1.23.to_s(:human, units: distance) + assert_equal "1.23 dam", 12.3.to_s(:human, units: distance) + assert_equal "1.23 hm", 123.to_s(:human, units: distance) + assert_equal "1.23 km", 1230.to_s(:human, units: distance) + assert_equal "1.23 km", 1230.to_s(:human, units: distance) + assert_equal "1.23 km", 1230.to_s(:human, units: distance) + assert_equal "12.3 km", 12300.to_s(:human, units: distance) #The quantifiers don't need to be a continuous sequence - gangster = {:hundred => "hundred bucks", :million => "thousand quids"} - assert_equal '1 hundred bucks', 100.to_s(:human, :units => gangster) - assert_equal '25 hundred bucks', 2500.to_s(:human, :units => gangster) - assert_equal '25 thousand quids', 25000000.to_s(:human, :units => gangster) - assert_equal '12300 thousand quids', 12345000000.to_s(:human, :units => gangster) + gangster = { hundred: "hundred bucks", million: "thousand quids" } + assert_equal "1 hundred bucks", 100.to_s(:human, units: gangster) + assert_equal "25 hundred bucks", 2500.to_s(:human, units: gangster) + assert_equal "25 thousand quids", 25000000.to_s(:human, units: gangster) + assert_equal "12300 thousand quids", 12345000000.to_s(:human, units: gangster) #Spaces are stripped from the resulting string - assert_equal '4', 4.to_s(:human, :units => {:unit => "", :ten => 'tens '}) - assert_equal '4.5 tens', 45.to_s(:human, :units => {:unit => "", :ten => ' tens '}) + assert_equal "4", 4.to_s(:human, units: { unit: "", ten: "tens " }) + assert_equal "4.5 tens", 45.to_s(:human, units: { unit: "", ten: " tens " }) end def test_number_to_human_with_custom_format - assert_equal '123 times Thousand', 123456.to_s(:human, :format => "%n times %u") - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123.lt', 123456.to_s(:human, :units => volume, :format => "%n.%u") + assert_equal "123 times Thousand", 123456.to_s(:human, format: "%n times %u") + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123.lt", 123456.to_s(:human, units: volume, format: "%n.%u") end def test_to_s__injected_on_proper_types - assert_equal '1.23 Thousand', 1230.to_s(:human) - assert_equal '1.23 Thousand', Float(1230).to_s(:human) - assert_equal '100000 Quadrillion', (100**10).to_s(:human) - assert_equal '1 Million', BigDecimal("1000010").to_s(:human) + assert_equal "1.23 Thousand", 1230.to_s(:human) + assert_equal "1.23 Thousand", Float(1230).to_s(:human) + assert_equal "100000 Quadrillion", (100**10).to_s(:human) + assert_equal "1 Million", BigDecimal("1000010").to_s(:human) end def test_to_formatted_s_is_deprecated @@ -400,23 +398,23 @@ class NumericExtFormattingTest < ActiveSupport::TestCase end def test_to_s_with_invalid_formatter - assert_equal '123', 123.to_s(:invalid) - assert_equal '2.5', 2.5.to_s(:invalid) - assert_equal '100000000000000000000', (100**10).to_s(:invalid) - assert_equal '1000010.0', BigDecimal("1000010").to_s(:invalid) + assert_equal "123", 123.to_s(:invalid) + assert_equal "2.5", 2.5.to_s(:invalid) + assert_equal "100000000000000000000", (100**10).to_s(:invalid) + assert_equal "1000010.0", BigDecimal("1000010").to_s(:invalid) end def test_default_to_s - assert_equal '123', 123.to_s - assert_equal '1111011', 123.to_s(2) + assert_equal "123", 123.to_s + assert_equal "1111011", 123.to_s(2) - assert_equal '2.5', 2.5.to_s + assert_equal "2.5", 2.5.to_s - assert_equal '100000000000000000000', (100**10).to_s - assert_equal '1010110101111000111010111100010110101100011000100000000000000000000', (100**10).to_s(2) + assert_equal "100000000000000000000", (100**10).to_s + assert_equal "1010110101111000111010111100010110101100011000100000000000000000000", (100**10).to_s(2) - assert_equal '1000010.0', BigDecimal("1000010").to_s - assert_equal '10000 10.0', BigDecimal("1000010").to_s('5F') + assert_equal "1000010.0", BigDecimal("1000010").to_s + assert_equal "10000 10.0", BigDecimal("1000010").to_s("5F") end def test_in_milliseconds diff --git a/activesupport/test/core_ext/object/acts_like_test.rb b/activesupport/test/core_ext/object/acts_like_test.rb index e68b1d23cb..631f4e63a8 100644 --- a/activesupport/test/core_ext/object/acts_like_test.rb +++ b/activesupport/test/core_ext/object/acts_like_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class ObjectTests < ActiveSupport::TestCase class DuckTime diff --git a/activesupport/test/core_ext/object/blank_test.rb b/activesupport/test/core_ext/object/blank_test.rb index a142096993..ab0676524e 100644 --- a/activesupport/test/core_ext/object/blank_test.rb +++ b/activesupport/test/core_ext/object/blank_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/blank' +require "abstract_unit" +require "active_support/core_ext/object/blank" class BlankTest < ActiveSupport::TestCase class EmptyTrue @@ -14,8 +14,8 @@ class BlankTest < ActiveSupport::TestCase end end - BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", ' ', "\u00a0", [], {} ] - NOT = [ EmptyFalse.new, Object.new, true, 0, 1, 'a', [nil], { nil => 0 } ] + BLANK = [ EmptyTrue.new, nil, false, "", " ", " \n\t \r ", " ", "\u00a0", [], {} ] + NOT = [ EmptyFalse.new, Object.new, true, 0, 1, "a", [nil], { nil => 0 } ] def test_blank BLANK.each { |v| assert_equal true, v.blank?, "#{v.inspect} should be blank" } diff --git a/activesupport/test/core_ext/object/deep_dup_test.rb b/activesupport/test/core_ext/object/deep_dup_test.rb index aa839201ea..e335ec1b40 100644 --- a/activesupport/test/core_ext/object/deep_dup_test.rb +++ b/activesupport/test/core_ext/object/deep_dup_test.rb @@ -1,8 +1,7 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class DeepDupTest < ActiveSupport::TestCase - def test_array_deep_dup array = [1, [2, 3]] dup = array.deep_dup @@ -12,15 +11,15 @@ class DeepDupTest < ActiveSupport::TestCase end def test_hash_deep_dup - hash = { :a => { :b => 'b' } } + hash = { a: { b: "b" } } dup = hash.deep_dup - dup[:a][:c] = 'c' + dup[:a][:c] = "c" assert_equal nil, hash[:a][:c] - assert_equal 'c', dup[:a][:c] + assert_equal "c", dup[:a][:c] end def test_array_deep_dup_with_hash_inside - array = [1, { :a => 2, :b => 3 } ] + array = [1, { a: 2, b: 3 } ] dup = array.deep_dup dup[1][:c] = 4 assert_equal nil, array[1][:c] @@ -28,16 +27,16 @@ class DeepDupTest < ActiveSupport::TestCase end def test_hash_deep_dup_with_array_inside - hash = { :a => [1, 2] } + hash = { a: [1, 2] } dup = hash.deep_dup - dup[:a][2] = 'c' + dup[:a][2] = "c" assert_equal nil, hash[:a][2] - assert_equal 'c', dup[:a][2] + assert_equal "c", dup[:a][2] end def test_deep_dup_initialize zero_hash = Hash.new 0 - hash = { :a => zero_hash } + hash = { a: zero_hash } dup = hash.deep_dup assert_equal 0, dup[:a][44] end @@ -55,5 +54,4 @@ class DeepDupTest < ActiveSupport::TestCase dup = hash.deep_dup assert_equal 1, dup.keys.length end - end diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb index 042f5cfb34..2cbfefe235 100644 --- a/activesupport/test/core_ext/object/duplicable_test.rb +++ b/activesupport/test/core_ext/object/duplicable_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' -require 'bigdecimal' -require 'active_support/core_ext/object/duplicable' -require 'active_support/core_ext/numeric/time' +require "abstract_unit" +require "bigdecimal" +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/numeric/time" class DuplicableTest < ActiveSupport::TestCase RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, method(:puts)] - ALLOW_DUP = ['1', Object.new, /foo/, [], {}, Time.now, Class.new, Module.new] - ALLOW_DUP << BigDecimal.new('4.56') + ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new] + ALLOW_DUP << BigDecimal.new("4.56") def test_duplicable rubinius_skip "* Method#dup is allowed at the moment on Rubinius\n" \ diff --git a/activesupport/test/core_ext/object/inclusion_test.rb b/activesupport/test/core_ext/object/inclusion_test.rb index 32d512eca3..be211ec7dc 100644 --- a/activesupport/test/core_ext/object/inclusion_test.rb +++ b/activesupport/test/core_ext/object/inclusion_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/inclusion' +require "abstract_unit" +require "active_support/core_ext/object/inclusion" class InTest < ActiveSupport::TestCase def test_in_array @@ -46,11 +46,11 @@ class InTest < ActiveSupport::TestCase assert !A.in?(A) assert !A.in?(D) end - + def test_no_method_catching assert_raise(ArgumentError) { 1.in?(1) } end - + def test_presence_in assert_equal "stuff", "stuff".presence_in(%w( lots of stuff )) assert_nil "stuff".presence_in(%w( lots of crap )) diff --git a/activesupport/test/core_ext/object/instance_variables_test.rb b/activesupport/test/core_ext/object/instance_variables_test.rb index 9f4c5dc4f1..5bdb2fbc35 100644 --- a/activesupport/test/core_ext/object/instance_variables_test.rb +++ b/activesupport/test/core_ext/object/instance_variables_test.rb @@ -1,11 +1,11 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class ObjectInstanceVariableTest < ActiveSupport::TestCase def setup @source, @dest = Object.new, Object.new - @source.instance_variable_set(:@bar, 'bar') - @source.instance_variable_set(:@baz, 'baz') + @source.instance_variable_set(:@bar, "bar") + @source.instance_variable_set(:@baz, "baz") end def test_instance_variable_names @@ -13,19 +13,19 @@ class ObjectInstanceVariableTest < ActiveSupport::TestCase end def test_instance_values - assert_equal({'bar' => 'bar', 'baz' => 'baz'}, @source.instance_values) + assert_equal({ "bar" => "bar", "baz" => "baz" }, @source.instance_values) end def test_instance_exec_passes_arguments_to_block - assert_equal %w(hello goodbye), 'hello'.instance_exec('goodbye') { |v| [self, v] } + assert_equal %w(hello goodbye), "hello".instance_exec("goodbye") { |v| [self, v] } end def test_instance_exec_with_frozen_obj - assert_equal %w(olleh goodbye), 'hello'.freeze.instance_exec('goodbye') { |v| [reverse, v] } + assert_equal %w(olleh goodbye), "hello".freeze.instance_exec("goodbye") { |v| [reverse, v] } end def test_instance_exec_nested - assert_equal %w(goodbye olleh bar), 'hello'.instance_exec('goodbye') { |arg| - [arg] + instance_exec('bar') { |v| [reverse, v] } } + assert_equal %w(goodbye olleh bar), "hello".instance_exec("goodbye") { |arg| + [arg] + instance_exec("bar") { |v| [reverse, v] } } end end diff --git a/activesupport/test/core_ext/object/json_cherry_pick_test.rb b/activesupport/test/core_ext/object/json_cherry_pick_test.rb index 2f7ea3a497..dd4e90918e 100644 --- a/activesupport/test/core_ext/object/json_cherry_pick_test.rb +++ b/activesupport/test/core_ext/object/json_cherry_pick_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" # These test cases were added to test that cherry-picking the json extensions # works correctly, primarily for dependencies problems reported in #16131. They @@ -9,7 +9,7 @@ class JsonCherryPickTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation def test_time_as_json - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" expected = Time.new(2004, 7, 25) actual = Time.parse(expected.as_json) @@ -18,7 +18,7 @@ class JsonCherryPickTest < ActiveSupport::TestCase end def test_date_as_json - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" expected = Date.new(2004, 7, 25) actual = Date.parse(expected.as_json) @@ -27,7 +27,7 @@ class JsonCherryPickTest < ActiveSupport::TestCase end def test_datetime_as_json - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" expected = DateTime.new(2004, 7, 25) actual = DateTime.parse(expected.as_json) diff --git a/activesupport/test/core_ext/object/json_gem_encoding_test.rb b/activesupport/test/core_ext/object/json_gem_encoding_test.rb index 2cbb1d590f..f5016d0c2a 100644 --- a/activesupport/test/core_ext/object/json_gem_encoding_test.rb +++ b/activesupport/test/core_ext/object/json_gem_encoding_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'json' -require 'json/encoding_test_cases' +require "abstract_unit" +require "json" +require "json/encoding_test_cases" # These test cases were added to test that we do not interfere with json gem's # output when the AS encoder is loaded, primarily for problems reported in @@ -13,7 +13,7 @@ require 'json/encoding_test_cases' # we need to require this upfront to ensure we don't get a false failure, but # ideally we should just fix the BigDecimal core_ext to not change to_s without # arguments. -require 'active_support/core_ext/big_decimal' +require "active_support/core_ext/big_decimal" class JsonGemEncodingTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -48,7 +48,7 @@ class JsonGemEncodingTest < ActiveSupport::TestCase exception = e end - require_or_skip 'active_support/core_ext/object/json' + require_or_skip "active_support/core_ext/object/json" if exception assert_raises_with_message JSON::GeneratorError, e.message do diff --git a/activesupport/test/core_ext/object/to_param_test.rb b/activesupport/test/core_ext/object/to_param_test.rb index 30a7557dc2..56246b24f3 100644 --- a/activesupport/test/core_ext/object/to_param_test.rb +++ b/activesupport/test/core_ext/object/to_param_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/to_param' +require "abstract_unit" +require "active_support/core_ext/object/to_param" class ToParamTest < ActiveSupport::TestCase class CustomString < String @@ -10,8 +10,8 @@ class ToParamTest < ActiveSupport::TestCase def test_object foo = Object.new - def foo.to_s; 'foo' end - assert_equal 'foo', foo.to_param + def foo.to_s; "foo" end + assert_equal "foo", foo.to_param end def test_nil @@ -25,13 +25,13 @@ class ToParamTest < ActiveSupport::TestCase def test_array # Empty Array - assert_equal '', [].to_param + assert_equal "", [].to_param array = [1, 2, 3, 4] assert_equal "1/2/3/4", array.to_param # Array of different objects - array = [1, '3', { a: 1, b: 2 }, nil, true, false, CustomString.new('object')] + array = [1, "3", { a: 1, b: 2 }, nil, true, false, CustomString.new("object")] assert_equal "1/3/a=1&b=2//true/false/custom-object", array.to_param end end diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb index 09cab3ed35..298c8bf373 100644 --- a/activesupport/test/core_ext/object/to_query_test.rb +++ b/activesupport/test/core_ext/object/to_query_test.rb @@ -1,82 +1,82 @@ -require 'abstract_unit' -require 'active_support/ordered_hash' -require 'active_support/core_ext/object/to_query' -require 'active_support/core_ext/string/output_safety' +require "abstract_unit" +require "active_support/ordered_hash" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/string/output_safety" class ToQueryTest < ActiveSupport::TestCase def test_simple_conversion - assert_query_equal 'a=10', :a => 10 + assert_query_equal "a=10", a: 10 end def test_cgi_escaping - assert_query_equal 'a%3Ab=c+d', 'a:b' => 'c d' + assert_query_equal "a%3Ab=c+d", "a:b" => "c d" end def test_html_safe_parameter_key - assert_query_equal 'a%3Ab=c+d', 'a:b'.html_safe => 'c d' + assert_query_equal "a%3Ab=c+d", "a:b".html_safe => "c d" end def test_html_safe_parameter_value - assert_query_equal 'a=%5B10%5D', 'a' => '[10]'.html_safe + assert_query_equal "a=%5B10%5D", "a" => "[10]".html_safe end def test_nil_parameter_value empty = Object.new def empty.to_param; nil end - assert_query_equal 'a=', 'a' => empty + assert_query_equal "a=", "a" => empty end def test_nested_conversion - assert_query_equal 'person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas', - :person => Hash[:login, 'seckar', :name, 'Nicholas'] + assert_query_equal "person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas", + person: Hash[:login, "seckar", :name, "Nicholas"] end def test_multiple_nested - assert_query_equal 'account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10', - Hash[:account, {:person => {:id => 20}}, :person, {:id => 10}] + assert_query_equal "account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10", + Hash[:account, { person: { id: 20 } }, :person, { id: 10 }] end def test_array_values - assert_query_equal 'person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20', - :person => {:id => [10, 20]} + assert_query_equal "person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20", + person: { id: [10, 20] } end def test_array_values_are_not_sorted - assert_query_equal 'person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10', - :person => {:id => [20, 10]} + assert_query_equal "person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10", + person: { id: [20, 10] } end def test_empty_array - assert_equal "person%5B%5D=", [].to_query('person') + assert_equal "person%5B%5D=", [].to_query("person") end def test_nested_empty_hash - assert_equal '', + assert_equal "", {}.to_query - assert_query_equal 'a=1&b%5Bc%5D=3', - { a: 1, b: { c: 3, d: {} } } - assert_query_equal '', - { a: {b: {c: {}}} } - assert_query_equal 'b%5Bc%5D=false&b%5Be%5D=&b%5Bf%5D=&p=12', - { p: 12, b: { c: false, e: nil, f: '' } } - assert_query_equal 'b%5Bc%5D=3&b%5Bf%5D=', - { b: { c: 3, k: {}, f: '' } } - assert_query_equal 'b=3', - {a: [], b: 3} + assert_query_equal "a=1&b%5Bc%5D=3", + a: 1, b: { c: 3, d: {} } + assert_query_equal "", + a: { b: { c: {} } } + assert_query_equal "b%5Bc%5D=false&b%5Be%5D=&b%5Bf%5D=&p=12", + p: 12, b: { c: false, e: nil, f: "" } + assert_query_equal "b%5Bc%5D=3&b%5Bf%5D=", + b: { c: 3, k: {}, f: "" } + assert_query_equal "b=3", + a: [], b: 3 end def test_hash_with_namespace - hash = { name: 'Nakshay', nationality: 'Indian' } - assert_equal "user%5Bname%5D=Nakshay&user%5Bnationality%5D=Indian", hash.to_query('user') + hash = { name: "Nakshay", nationality: "Indian" } + assert_equal "user%5Bname%5D=Nakshay&user%5Bnationality%5D=Indian", hash.to_query("user") end def test_hash_sorted_lexicographically - hash = { type: 'human', name: 'Nakshay' } + hash = { type: "human", name: "Nakshay" } assert_equal "name=Nakshay&type=human", hash.to_query end private def assert_query_equal(expected, actual) - assert_equal expected.split('&'), actual.to_query.split('&') + assert_equal expected.split("&"), actual.to_query.split("&") end end diff --git a/activesupport/test/core_ext/object/try_test.rb b/activesupport/test/core_ext/object/try_test.rb index 25bf0207b8..5c8bf59952 100644 --- a/activesupport/test/core_ext/object/try_test.rb +++ b/activesupport/test/core_ext/object/try_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object' +require "abstract_unit" +require "active_support/core_ext/object" class ObjectTryTest < ActiveSupport::TestCase def setup @@ -15,7 +15,7 @@ class ObjectTryTest < ActiveSupport::TestCase def test_nonexisting_method_with_arguments method = :undefined_method assert !@string.respond_to?(method) - assert_nil @string.try(method, 'llo', 'y') + assert_nil @string.try(method, "llo", "y") end def test_nonexisting_method_bang @@ -27,7 +27,7 @@ class ObjectTryTest < ActiveSupport::TestCase def test_nonexisting_method_with_arguments_bang method = :undefined_method assert !@string.respond_to?(method) - assert_raise(NoMethodError) { @string.try!(method, 'llo', 'y') } + assert_raise(NoMethodError) { @string.try!(method, "llo", "y") } end def test_valid_method @@ -35,11 +35,11 @@ class ObjectTryTest < ActiveSupport::TestCase end def test_argument_forwarding - assert_equal 'Hey', @string.try(:sub, 'llo', 'y') + assert_equal "Hey", @string.try(:sub, "llo", "y") end def test_block_forwarding - assert_equal 'Hey', @string.try(:sub, 'llo') { |match| 'y' } + assert_equal "Hey", @string.try(:sub, "llo") { |match| "y" } end def test_nil_to_type @@ -48,7 +48,7 @@ class ObjectTryTest < ActiveSupport::TestCase end def test_false_try - assert_equal 'false', false.try(:to_s) + assert_equal "false", false.try(:to_s) end def test_try_only_block @@ -78,7 +78,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end @@ -90,7 +90,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end @@ -99,22 +99,22 @@ class ObjectTryTest < ActiveSupport::TestCase class Decorator < SimpleDelegator def delegator_method - 'delegator method' + "delegator method" end def reverse - 'overridden reverse' + "overridden reverse" end private def private_delegator_method - 'private delegator method' + "private delegator method" end end def test_try_with_method_on_delegator - assert_equal 'delegator method', Decorator.new(@string).try(:delegator_method) + assert_equal "delegator method", Decorator.new(@string).try(:delegator_method) end def test_try_with_method_on_delegator_target @@ -122,7 +122,7 @@ class ObjectTryTest < ActiveSupport::TestCase end def test_try_with_overridden_method_on_delegator - assert_equal 'overridden reverse', Decorator.new(@string).reverse + assert_equal "overridden reverse", Decorator.new(@string).reverse end def test_try_with_private_method_on_delegator @@ -140,7 +140,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end @@ -152,7 +152,7 @@ class ObjectTryTest < ActiveSupport::TestCase private def private_method - 'private method' + "private method" end end diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb index f28cebda3d..fc0e72e09a 100644 --- a/activesupport/test/core_ext/range_ext_test.rb +++ b/activesupport/test/core_ext/range_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'active_support/core_ext/numeric' -require 'active_support/core_ext/range' +require "abstract_unit" +require "active_support/time" +require "active_support/core_ext/numeric" +require "active_support/core_ext/range" class RangeTest < ActiveSupport::TestCase def test_to_s_from_dates @@ -66,15 +66,15 @@ class RangeTest < ActiveSupport::TestCase end def test_exclusive_end_should_not_include_identical_with_inclusive_end - assert !(1...10).include?(1..10) + assert_not_includes (1...10), 1..10 end def test_should_not_include_overlapping_first - assert !(2..8).include?(1..3) + assert_not_includes (2..8), 1..3 end def test_should_not_include_overlapping_last - assert !(2..8).include?(5..9) + assert_not_includes (2..8), 5..9 end def test_should_include_identical_exclusive_with_floats @@ -99,21 +99,21 @@ class RangeTest < ActiveSupport::TestCase end def test_each_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006,11,28,10,30)) assert_raises TypeError do ((twz - 1.hour)..twz).each {} end end def test_step_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006,11,28,10,30)) assert_raises TypeError do ((twz - 1.hour)..twz).step(1) {} end end def test_include_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone['Eastern Time (US & Canada)'] , Time.utc(2006,11,28,10,30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006,11,28,10,30)) assert_raises TypeError do ((twz - 1.hour)..twz).include?(twz) end diff --git a/activesupport/test/core_ext/regexp_ext_test.rb b/activesupport/test/core_ext/regexp_ext_test.rb index c2398d31bd..e569a9f234 100644 --- a/activesupport/test/core_ext/regexp_ext_test.rb +++ b/activesupport/test/core_ext/regexp_ext_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/regexp' +require "abstract_unit" +require "active_support/core_ext/regexp" class RegexpExtAccessTests < ActiveSupport::TestCase def test_multiline @@ -7,4 +7,28 @@ class RegexpExtAccessTests < ActiveSupport::TestCase assert_equal false, //.multiline? assert_equal false, /(?m:)/.multiline? end + + # Based on https://github.com/ruby/ruby/blob/trunk/test/ruby/test_regexp.rb. + def test_match_p + /back(...)/ =~ "backref" + # must match here, but not in a separate method, e.g., assert_send, + # to check if $~ is affected or not. + assert_equal false, //.match?(nil) + assert_equal true, //.match?("") + assert_equal true, /.../.match?(:abc) + assert_raise(TypeError) { /.../.match?(Object.new) } + assert_equal true, /b/.match?("abc") + assert_equal true, /b/.match?("abc", 1) + assert_equal true, /../.match?("abc", 1) + assert_equal true, /../.match?("abc", -2) + assert_equal false, /../.match?("abc", -4) + assert_equal false, /../.match?("abc", 4) + assert_equal true, /\z/.match?("") + assert_equal true, /\z/.match?("abc") + assert_equal true, /R.../.match?("Ruby") + assert_equal false, /R.../.match?("Ruby", 1) + assert_equal false, /P.../.match?("Ruby") + assert_equal "backref", $& + assert_equal "ref", $1 + end end diff --git a/activesupport/test/core_ext/secure_random_test.rb b/activesupport/test/core_ext/secure_random_test.rb index dfacb7fe9f..fc25f6ab41 100644 --- a/activesupport/test/core_ext/secure_random_test.rb +++ b/activesupport/test/core_ext/secure_random_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/securerandom' +require "abstract_unit" +require "active_support/core_ext/securerandom" class SecureRandomTest < ActiveSupport::TestCase def test_base58 diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index d68a77680b..4b40503d22 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -1,16 +1,16 @@ -require 'date' -require 'abstract_unit' -require 'inflector_test_cases' -require 'constantize_test_cases' - -require 'active_support/inflector' -require 'active_support/core_ext/string' -require 'active_support/time' -require 'active_support/core_ext/string/strip' -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/string/indent' -require 'time_zone_test_helpers' -require 'yaml' +require "date" +require "abstract_unit" +require "inflector_test_cases" +require "constantize_test_cases" + +require "active_support/inflector" +require "active_support/core_ext/string" +require "active_support/time" +require "active_support/core_ext/string/strip" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/string/indent" +require "time_zone_test_helpers" +require "yaml" class StringInflectionsTest < ActiveSupport::TestCase include InflectorTestCases @@ -18,12 +18,12 @@ class StringInflectionsTest < ActiveSupport::TestCase include TimeZoneTestHelpers def test_strip_heredoc_on_an_empty_string - assert_equal '', ''.strip_heredoc + assert_equal "", "".strip_heredoc end def test_strip_heredoc_on_a_string_with_no_lines - assert_equal 'x', 'x'.strip_heredoc - assert_equal 'x', ' x'.strip_heredoc + assert_equal "x", "x".strip_heredoc + assert_equal "x", " x".strip_heredoc end def test_strip_heredoc_on_a_heredoc_with_no_margin @@ -60,7 +60,7 @@ class StringInflectionsTest < ActiveSupport::TestCase assert_equal("blargles", "blargle".pluralize(2)) end - test 'pluralize with count = 1 still returns new string' do + test "pluralize with count = 1 still returns new string" do name = "Kuldeep" assert_not_same name.pluralize(1), name end @@ -96,7 +96,7 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_camelize_lower - assert_equal('capital', 'Capital'.camelize(:lower)) + assert_equal("capital", "Capital".camelize(:lower)) end def test_dasherize @@ -164,41 +164,41 @@ class StringInflectionsTest < ActiveSupport::TestCase def test_string_parameterized_no_separator StringToParameterizeWithNoSeparator.each do |normal, slugged| - assert_equal(normal.parameterize(separator: ''), slugged) + assert_equal(normal.parameterize(separator: ""), slugged) end end def test_string_parameterized_no_separator_deprecated StringToParameterizeWithNoSeparator.each do |normal, slugged| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: ''` instead./i) do - assert_equal(normal.parameterize(''), slugged) + assert_equal(normal.parameterize(""), slugged) end end end def test_string_parameterized_no_separator_preserve_case StringToParameterizePreserveCaseWithNoSeparator.each do |normal, slugged| - assert_equal(normal.parameterize(separator: '', preserve_case: true), slugged) + assert_equal(normal.parameterize(separator: "", preserve_case: true), slugged) end end def test_string_parameterized_underscore StringToParameterizeWithUnderscore.each do |normal, slugged| - assert_equal(normal.parameterize(separator: '_'), slugged) + assert_equal(normal.parameterize(separator: "_"), slugged) end end def test_string_parameterized_underscore_deprecated StringToParameterizeWithUnderscore.each do |normal, slugged| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '_'` instead./i) do - assert_equal(normal.parameterize('_'), slugged) + assert_equal(normal.parameterize("_"), slugged) end end end def test_string_parameterized_underscore_preserve_case StringToParameterizePreserceCaseWithUnderscore.each do |normal, slugged| - assert_equal(normal.parameterize(separator: '_', preserve_case: true), slugged) + assert_equal(normal.parameterize(separator: "_", preserve_case: true), slugged) end end @@ -215,23 +215,23 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_humanize_with_html_escape - assert_equal 'Hello', ERB::Util.html_escape("hello").humanize + assert_equal "Hello", ERB::Util.html_escape("hello").humanize end def test_ord - assert_equal 97, 'a'.ord - assert_equal 97, 'abc'.ord + assert_equal 97, "a".ord + assert_equal 97, "abc".ord end def test_starts_ends_with_alias s = "hello" - assert s.starts_with?('h') - assert s.starts_with?('hel') - assert !s.starts_with?('el') + assert s.starts_with?("h") + assert s.starts_with?("hel") + assert !s.starts_with?("el") - assert s.ends_with?('o') - assert s.ends_with?('lo') - assert !s.ends_with?('el') + assert s.ends_with?("o") + assert s.ends_with?("lo") + assert !s.ends_with?("el") end def test_string_squish @@ -263,16 +263,16 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_truncate_with_omission_and_separator - assert_equal "Hello[...]", "Hello World!".truncate(10, :omission => "[...]") - assert_equal "Hello[...]", "Hello Big World!".truncate(13, :omission => "[...]", :separator => ' ') - assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, :omission => "[...]", :separator => ' ') - assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, :omission => "[...]", :separator => ' ') + assert_equal "Hello[...]", "Hello World!".truncate(10, omission: "[...]") + assert_equal "Hello[...]", "Hello Big World!".truncate(13, omission: "[...]", separator: " ") + assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, omission: "[...]", separator: " ") + assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, omission: "[...]", separator: " ") end def test_truncate_with_omission_and_regexp_separator - assert_equal "Hello[...]", "Hello Big World!".truncate(13, :omission => "[...]", :separator => /\s/) - assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, :omission => "[...]", :separator => /\s/) - assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, :omission => "[...]", :separator => /\s/) + assert_equal "Hello[...]", "Hello Big World!".truncate(13, omission: "[...]", separator: /\s/) + assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, omission: "[...]", separator: /\s/) + assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, omission: "[...]", separator: /\s/) end def test_truncate_words @@ -281,19 +281,19 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_truncate_words_with_omission - assert_equal "Hello Big World!", "Hello Big World!".truncate_words(3, :omission => "[...]") - assert_equal "Hello Big[...]", "Hello Big World!".truncate_words(2, :omission => "[...]") + assert_equal "Hello Big World!", "Hello Big World!".truncate_words(3, omission: "[...]") + assert_equal "Hello Big[...]", "Hello Big World!".truncate_words(2, omission: "[...]") end def test_truncate_words_with_separator - assert_equal "Hello<br>Big<br>World!...", "Hello<br>Big<br>World!<br>".truncate_words(3, :separator => '<br>') - assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, :separator => '<br>') - assert_equal "Hello\n<br>Big...", "Hello\n<br>Big<br>Wide<br>World!".truncate_words(2, :separator => '<br>') + assert_equal "Hello<br>Big<br>World!...", "Hello<br>Big<br>World!<br>".truncate_words(3, separator: "<br>") + assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, separator: "<br>") + assert_equal "Hello\n<br>Big...", "Hello\n<br>Big<br>Wide<br>World!".truncate_words(2, separator: "<br>") end def test_truncate_words_with_separator_and_omission - assert_equal "Hello<br>Big<br>World![...]", "Hello<br>Big<br>World!<br>".truncate_words(3, :omission => "[...]", :separator => '<br>') - assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, :omission => "[...]", :separator => '<br>') + assert_equal "Hello<br>Big<br>World![...]", "Hello<br>Big<br>World!<br>".truncate_words(3, omission: "[...]", separator: "<br>") + assert_equal "Hello<br>Big<br>World!", "Hello<br>Big<br>World!".truncate_words(3, omission: "[...]", separator: "<br>") end def test_truncate_words_with_complex_string @@ -381,14 +381,14 @@ class StringAccessTest < ActiveSupport::TestCase test "#first returns the first character" do assert_equal "h", "hello".first - assert_equal 'x', 'x'.first + assert_equal "x", "x".first end test "#first with Integer, returns a substring from the beginning to position" do assert_equal "he", "hello".first(2) assert_equal "", "hello".first(0) assert_equal "hello", "hello".first(10) - assert_equal 'x', 'x'.first(4) + assert_equal "x", "x".first(4) end test "#first with Integer >= string length still returns a new string" do @@ -399,14 +399,14 @@ class StringAccessTest < ActiveSupport::TestCase test "#last returns the last character" do assert_equal "o", "hello".last - assert_equal 'x', 'x'.last + assert_equal "x", "x".last end test "#last with Integer, returns a substring from the end to position" do assert_equal "llo", "hello".last(3) assert_equal "hello", "hello".last(10) assert_equal "", "hello".last(0) - assert_equal 'x', 'x'.last(4) + assert_equal "x", "x".last(4) end test "#last with Integer >= string length still returns a new string" do @@ -633,14 +633,14 @@ end class StringBehaviourTest < ActiveSupport::TestCase def test_acts_like_string - assert 'Bambi'.acts_like_string? + assert "Bambi".acts_like_string? end end class CoreExtStringMultibyteTest < ActiveSupport::TestCase - UTF8_STRING = 'ã“ã«ã¡ã‚' - ASCII_STRING = 'ohayo'.encode('US-ASCII') - EUC_JP_STRING = 'ã•よãªã‚‰'.encode('EUC-JP') + UTF8_STRING = "ã“ã«ã¡ã‚" + ASCII_STRING = "ohayo".encode("US-ASCII") + EUC_JP_STRING = "ã•よãªã‚‰".encode("EUC-JP") INVALID_UTF8_STRING = "\270\236\010\210\245" def test_core_ext_adds_mb_chars @@ -820,8 +820,8 @@ class OutputSafetyTest < ActiveSupport::TestCase assert string.html_safe? end - test 'emits normal string yaml' do - assert_equal 'foo'.to_yaml, 'foo'.html_safe.to_yaml(:foo => 1) + test "emits normal string yaml" do + assert_equal "foo".to_yaml, "foo".html_safe.to_yaml(foo: 1) end test "call to_param returns a normal string" do @@ -832,7 +832,7 @@ class OutputSafetyTest < ActiveSupport::TestCase test "ERB::Util.html_escape should escape unsafe characters" do string = '<>&"\'' - expected = '<>&"'' + expected = "<>&"'" assert_equal expected, ERB::Util.html_escape(string) end @@ -848,7 +848,7 @@ class OutputSafetyTest < ActiveSupport::TestCase end test "ERB::Util.html_escape_once only escapes once" do - string = '1 < 2 & 3' + string = "1 < 2 & 3" escaped_string = "1 < 2 & 3" assert_equal escaped_string, ERB::Util.html_escape_once(string) @@ -863,15 +863,15 @@ class OutputSafetyTest < ActiveSupport::TestCase end class StringExcludeTest < ActiveSupport::TestCase - test 'inverse of #include' do - assert_equal false, 'foo'.exclude?('o') - assert_equal true, 'foo'.exclude?('p') + test "inverse of #include" do + assert_equal false, "foo".exclude?("o") + assert_equal true, "foo".exclude?("p") end end class StringIndentTest < ActiveSupport::TestCase - test 'does not indent strings that only contain newlines (edge cases)' do - ['', "\n", "\n" * 7].each do |str| + test "does not indent strings that only contain newlines (edge cases)" do + ["", "\n", "\n" * 7].each do |str| assert_nil str.indent!(8) assert_equal str, str.indent(8) assert_equal str, str.indent(1, "\t") @@ -893,8 +893,8 @@ class StringIndentTest < ActiveSupport::TestCase # Nothing is said about existing indentation that mixes spaces and tabs, so # there is nothing to test. - test 'uses the indent char if passed' do - assert_equal <<EXPECTED, <<ACTUAL.indent(4, '.') + test "uses the indent char if passed" do + assert_equal <<EXPECTED, <<ACTUAL.indent(4, ".") .... def some_method(x, y) .... some_code .... end @@ -904,7 +904,7 @@ EXPECTED end ACTUAL - assert_equal <<EXPECTED, <<ACTUAL.indent(2, ' ') + assert_equal <<EXPECTED, <<ACTUAL.indent(2, " ") def some_method(x, y) some_code end @@ -919,7 +919,7 @@ ACTUAL assert_equal " foo\n\n bar", "foo\n\nbar".indent(1) end - test 'indents blank lines if told so' do + test "indents blank lines if told so" do assert_equal " foo\n \n bar", "foo\n\nbar".indent(1, nil, true) end end diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 1205797fac..a6c9a7d5a8 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/time' -require 'core_ext/date_and_time_behavior' -require 'time_zone_test_helpers' +require "abstract_unit" +require "active_support/time" +require "core_ext/date_and_time_behavior" +require "time_zone_test_helpers" class TimeExtCalculationsTest < ActiveSupport::TestCase def date_time_init(year,month,day,hour,minute,second,usec=0) @@ -20,42 +20,42 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_seconds_since_midnight_at_daylight_savings_time_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 2:00am ST => April 3rd 3:00am DT - assert_equal 2*3600-1, Time.local(2005,4,3,1,59,59).seconds_since_midnight, 'just before DST start' - assert_equal 2*3600+1, Time.local(2005,4,3,3, 0, 1).seconds_since_midnight, 'just after DST start' + assert_equal 2*3600-1, Time.local(2005,4,3,1,59,59).seconds_since_midnight, "just before DST start" + assert_equal 2*3600+1, Time.local(2005,4,3,3, 0, 1).seconds_since_midnight, "just after DST start" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 2:00am ST => October 1st 3:00am DT - assert_equal 2*3600-1, Time.local(2006,10,1,1,59,59).seconds_since_midnight, 'just before DST start' - assert_equal 2*3600+1, Time.local(2006,10,1,3, 0, 1).seconds_since_midnight, 'just after DST start' + assert_equal 2*3600-1, Time.local(2006,10,1,1,59,59).seconds_since_midnight, "just before DST start" + assert_equal 2*3600+1, Time.local(2006,10,1,3, 0, 1).seconds_since_midnight, "just after DST start" end end def test_seconds_since_midnight_at_daylight_savings_time_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 2:00am DT => October 30th 1:00am ST # avoid setting a time between 1:00 and 2:00 since that requires specifying whether DST is active - assert_equal 1*3600-1, Time.local(2005,10,30,0,59,59).seconds_since_midnight, 'just before DST end' - assert_equal 3*3600+1, Time.local(2005,10,30,2, 0, 1).seconds_since_midnight, 'just after DST end' + assert_equal 1*3600-1, Time.local(2005,10,30,0,59,59).seconds_since_midnight, "just before DST end" + assert_equal 3*3600+1, Time.local(2005,10,30,2, 0, 1).seconds_since_midnight, "just after DST end" # now set a time between 1:00 and 2:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 1*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,true,ENV['TZ']).seconds_since_midnight, 'before DST end' - assert_equal 2*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,false,ENV['TZ']).seconds_since_midnight, 'after DST end' + assert_equal 1*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,true,ENV["TZ"]).seconds_since_midnight, "before DST end" + assert_equal 2*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,false,ENV["TZ"]).seconds_since_midnight, "after DST end" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 3:00am DT => March 19th 2:00am ST # avoid setting a time between 2:00 and 3:00 since that requires specifying whether DST is active - assert_equal 2*3600-1, Time.local(2006,3,19,1,59,59).seconds_since_midnight, 'just before DST end' - assert_equal 4*3600+1, Time.local(2006,3,19,3, 0, 1).seconds_since_midnight, 'just after DST end' + assert_equal 2*3600-1, Time.local(2006,3,19,1,59,59).seconds_since_midnight, "just before DST end" + assert_equal 4*3600+1, Time.local(2006,3,19,3, 0, 1).seconds_since_midnight, "just after DST end" # now set a time between 2:00 and 3:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 2*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,true, ENV['TZ']).seconds_since_midnight, 'before DST end' - assert_equal 3*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,false,ENV['TZ']).seconds_since_midnight, 'after DST end' + assert_equal 2*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,true, ENV["TZ"]).seconds_since_midnight, "before DST end" + assert_equal 3*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,false,ENV["TZ"]).seconds_since_midnight, "after DST end" end end @@ -68,42 +68,42 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_seconds_until_end_of_day_at_daylight_savings_time_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 2:00am ST => April 3rd 3:00am DT - assert_equal 21*3600, Time.local(2005,4,3,1,59,59).seconds_until_end_of_day, 'just before DST start' - assert_equal 21*3600-2, Time.local(2005,4,3,3,0,1).seconds_until_end_of_day, 'just after DST start' + assert_equal 21*3600, Time.local(2005,4,3,1,59,59).seconds_until_end_of_day, "just before DST start" + assert_equal 21*3600-2, Time.local(2005,4,3,3,0,1).seconds_until_end_of_day, "just after DST start" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 2:00am ST => October 1st 3:00am DT - assert_equal 21*3600, Time.local(2006,10,1,1,59,59).seconds_until_end_of_day, 'just before DST start' - assert_equal 21*3600-2, Time.local(2006,10,1,3,0,1).seconds_until_end_of_day, 'just after DST start' + assert_equal 21*3600, Time.local(2006,10,1,1,59,59).seconds_until_end_of_day, "just before DST start" + assert_equal 21*3600-2, Time.local(2006,10,1,3,0,1).seconds_until_end_of_day, "just after DST start" end end def test_seconds_until_end_of_day_at_daylight_savings_time_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 2:00am DT => October 30th 1:00am ST # avoid setting a time between 1:00 and 2:00 since that requires specifying whether DST is active - assert_equal 24*3600, Time.local(2005,10,30,0,59,59).seconds_until_end_of_day, 'just before DST end' - assert_equal 22*3600-2, Time.local(2005,10,30,2,0,1).seconds_until_end_of_day, 'just after DST end' + assert_equal 24*3600, Time.local(2005,10,30,0,59,59).seconds_until_end_of_day, "just before DST end" + assert_equal 22*3600-2, Time.local(2005,10,30,2,0,1).seconds_until_end_of_day, "just after DST end" # now set a time between 1:00 and 2:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 24*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,true,ENV['TZ']).seconds_until_end_of_day, 'before DST end' - assert_equal 23*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,false,ENV['TZ']).seconds_until_end_of_day, 'after DST end' + assert_equal 24*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,true,ENV["TZ"]).seconds_until_end_of_day, "before DST end" + assert_equal 23*3600-30*60-1, Time.local(0,30,1,30,10,2005,0,0,false,ENV["TZ"]).seconds_until_end_of_day, "after DST end" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 3:00am DT => March 19th 2:00am ST # avoid setting a time between 2:00 and 3:00 since that requires specifying whether DST is active - assert_equal 23*3600, Time.local(2006,3,19,1,59,59).seconds_until_end_of_day, 'just before DST end' - assert_equal 21*3600-2, Time.local(2006,3,19,3,0,1).seconds_until_end_of_day, 'just after DST end' + assert_equal 23*3600, Time.local(2006,3,19,1,59,59).seconds_until_end_of_day, "just before DST end" + assert_equal 21*3600-2, Time.local(2006,3,19,3,0,1).seconds_until_end_of_day, "just after DST end" # now set a time between 2:00 and 3:00 by specifying whether DST is active # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz ) - assert_equal 23*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,true, ENV['TZ']).seconds_until_end_of_day, 'before DST end' - assert_equal 22*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,false,ENV['TZ']).seconds_until_end_of_day, 'after DST end' + assert_equal 23*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,true, ENV["TZ"]).seconds_until_end_of_day, "before DST end" + assert_equal 22*3600-30*60-1, Time.local(0,30,2,19,3,2006,0,0,false,ENV["TZ"]).seconds_until_end_of_day, "after DST end" end end @@ -123,25 +123,25 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_beginning_of_day assert_equal Time.local(2005,2,4,0,0,0), Time.local(2005,2,4,10,10,10).beginning_of_day - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,4,2,0,0,0), Time.local(2006,4,2,10,10,10).beginning_of_day, 'start DST' - assert_equal Time.local(2006,10,29,0,0,0), Time.local(2006,10,29,10,10,10).beginning_of_day, 'ends DST' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,4,2,0,0,0), Time.local(2006,4,2,10,10,10).beginning_of_day, "start DST" + assert_equal Time.local(2006,10,29,0,0,0), Time.local(2006,10,29,10,10,10).beginning_of_day, "ends DST" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,19,0,0,0), Time.local(2006,3,19,10,10,10).beginning_of_day, 'ends DST' - assert_equal Time.local(2006,10,1,0,0,0), Time.local(2006,10,1,10,10,10).beginning_of_day, 'start DST' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,19,0,0,0), Time.local(2006,3,19,10,10,10).beginning_of_day, "ends DST" + assert_equal Time.local(2006,10,1,0,0,0), Time.local(2006,10,1,10,10,10).beginning_of_day, "start DST" end end def test_middle_of_day assert_equal Time.local(2005,2,4,12,0,0), Time.local(2005,2,4,10,10,10).middle_of_day - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,4,2,12,0,0), Time.local(2006,4,2,10,10,10).middle_of_day, 'start DST' - assert_equal Time.local(2006,10,29,12,0,0), Time.local(2006,10,29,10,10,10).middle_of_day, 'ends DST' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,4,2,12,0,0), Time.local(2006,4,2,10,10,10).middle_of_day, "start DST" + assert_equal Time.local(2006,10,29,12,0,0), Time.local(2006,10,29,10,10,10).middle_of_day, "ends DST" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,19,12,0,0), Time.local(2006,3,19,10,10,10).middle_of_day, 'ends DST' - assert_equal Time.local(2006,10,1,12,0,0), Time.local(2006,10,1,10,10,10).middle_of_day, 'start DST' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,19,12,0,0), Time.local(2006,3,19,10,10,10).middle_of_day, "ends DST" + assert_equal Time.local(2006,10,1,12,0,0), Time.local(2006,10,1,10,10,10).middle_of_day, "start DST" end end @@ -155,16 +155,16 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_end_of_day assert_equal Time.local(2007,8,12,23,59,59,Rational(999999999, 1000)), Time.local(2007,8,12,10,10,10).end_of_day - with_env_tz 'US/Eastern' do - assert_equal Time.local(2007,4,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,4,2,10,10,10).end_of_day, 'start DST' - assert_equal Time.local(2007,10,29,23,59,59,Rational(999999999, 1000)), Time.local(2007,10,29,10,10,10).end_of_day, 'ends DST' + with_env_tz "US/Eastern" do + assert_equal Time.local(2007,4,2,23,59,59,Rational(999999999, 1000)), Time.local(2007,4,2,10,10,10).end_of_day, "start DST" + assert_equal Time.local(2007,10,29,23,59,59,Rational(999999999, 1000)), Time.local(2007,10,29,10,10,10).end_of_day, "ends DST" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,19,23,59,59,Rational(999999999, 1000)), Time.local(2006,3,19,10,10,10).end_of_day, 'ends DST' - assert_equal Time.local(2006,10,1,23,59,59,Rational(999999999, 1000)), Time.local(2006,10,1,10,10,10).end_of_day, 'start DST' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,19,23,59,59,Rational(999999999, 1000)), Time.local(2006,3,19,10,10,10).end_of_day, "ends DST" + assert_equal Time.local(2006,10,1,23,59,59,Rational(999999999, 1000)), Time.local(2006,10,1,10,10,10).end_of_day, "start DST" end - with_env_tz 'Asia/Yekaterinburg' do - assert_equal Time.local(2015, 2, 8, 23, 59, 59, Rational(999999999, 1000)), Time.new(2015, 2, 8, 8, 0, 0, '+05:00').end_of_day + with_env_tz "Asia/Yekaterinburg" do + assert_equal Time.local(2015, 2, 8, 23, 59, 59, Rational(999999999, 1000)), Time.new(2015, 2, 8, 8, 0, 0, "+05:00").end_of_day end end @@ -188,74 +188,74 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_daylight_savings_time_crossings_backward_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 4:18am - assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(24.hours), 'dt-24.hours=>st' - assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400), 'dt-86400=>st' - assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400.seconds), 'dt-86400.seconds=>st' + assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(24.hours), "dt-24.hours=>st" + assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400), "dt-86400=>st" + assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400.seconds), "dt-86400.seconds=>st" - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(24.hours), 'st-24.hours=>st' - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), 'st-86400=>st' - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400.seconds), 'st-86400.seconds=>st' + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(24.hours), "st-24.hours=>st" + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), "st-86400=>st" + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400.seconds), "st-86400.seconds=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 4:18am - assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(24.hours), 'dt-24.hours=>st' - assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400), 'dt-86400=>st' - assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400.seconds), 'dt-86400.seconds=>st' + assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(24.hours), "dt-24.hours=>st" + assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400), "dt-86400=>st" + assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400.seconds), "dt-86400.seconds=>st" - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(24.hours), 'st-24.hours=>st' - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), 'st-86400=>st' - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400.seconds), 'st-86400.seconds=>st' + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(24.hours), "st-24.hours=>st" + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), "st-86400=>st" + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400.seconds), "st-86400.seconds=>st" end end def test_daylight_savings_time_crossings_backward_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 4:03am - assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(24.hours), 'st-24.hours=>dt' - assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400), 'st-86400=>dt' - assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400.seconds), 'st-86400.seconds=>dt' + assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(24.hours), "st-24.hours=>dt" + assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400), "st-86400=>dt" + assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400.seconds), "st-86400.seconds=>dt" - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(24.hours), 'dt-24.hours=>dt' - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), 'dt-86400=>dt' - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400.seconds), 'dt-86400.seconds=>dt' + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(24.hours), "dt-24.hours=>dt" + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), "dt-86400=>dt" + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400.seconds), "dt-86400.seconds=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 4:03am - assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(24.hours), 'st-24.hours=>dt' - assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400), 'st-86400=>dt' - assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400.seconds), 'st-86400.seconds=>dt' + assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(24.hours), "st-24.hours=>dt" + assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400), "st-86400=>dt" + assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400.seconds), "st-86400.seconds=>dt" - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(24.hours), 'dt-24.hours=>dt' - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), 'dt-86400=>dt' - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400.seconds), 'dt-86400.seconds=>dt' + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(24.hours), "dt-24.hours=>dt" + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), "dt-86400=>dt" + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400.seconds), "dt-86400.seconds=>dt" end end def test_daylight_savings_time_crossings_backward_start_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 April 3rd 4:18am - assert_equal Time.local(2005,4,2,4,18,0), Time.local(2005,4,3,4,18,0).ago(1.day), 'dt-1.day=>st' - assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(1.day), 'st-1.day=>st' + assert_equal Time.local(2005,4,2,4,18,0), Time.local(2005,4,3,4,18,0).ago(1.day), "dt-1.day=>st" + assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(1.day), "st-1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 October 1st 4:18am - assert_equal Time.local(2006,9,30,4,18,0), Time.local(2006,10,1,4,18,0).ago(1.day), 'dt-1.day=>st' - assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(1.day), 'st-1.day=>st' + assert_equal Time.local(2006,9,30,4,18,0), Time.local(2006,10,1,4,18,0).ago(1.day), "dt-1.day=>st" + assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(1.day), "st-1.day=>st" end end def test_daylight_savings_time_crossings_backward_end_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 October 30th 4:03am - assert_equal Time.local(2005,10,29,4,3), Time.local(2005,10,30,4,3,0).ago(1.day), 'st-1.day=>dt' - assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(1.day), 'dt-1.day=>dt' + assert_equal Time.local(2005,10,29,4,3), Time.local(2005,10,30,4,3,0).ago(1.day), "st-1.day=>dt" + assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(1.day), "dt-1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 March 19th 4:03am - assert_equal Time.local(2006,3,18,4,3), Time.local(2006,3,19,4,3,0).ago(1.day), 'st-1.day=>dt' - assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(1.day), 'dt-1.day=>dt' + assert_equal Time.local(2006,3,18,4,3), Time.local(2006,3,19,4,3,0).ago(1.day), "st-1.day=>dt" + assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(1.day), "dt-1.day=>dt" end end @@ -269,250 +269,250 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_daylight_savings_time_crossings_forward_start - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(24.hours), 'st+24.hours=>dt' - assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400), 'st+86400=>dt' - assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400.seconds), 'st+86400.seconds=>dt' + assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(24.hours), "st+24.hours=>dt" + assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400), "st+86400=>dt" + assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400.seconds), "st+86400.seconds=>dt" - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(24.hours), 'dt+24.hours=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), 'dt+86400=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400.seconds), 'dt+86400.seconds=>dt' + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(24.hours), "dt+24.hours=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), "dt+86400=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400.seconds), "dt+86400.seconds=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(24.hours), 'st+24.hours=>dt' - assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400), 'st+86400=>dt' - assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400.seconds), 'st+86400.seconds=>dt' + assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(24.hours), "st+24.hours=>dt" + assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400), "st+86400=>dt" + assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400.seconds), "st+86400.seconds=>dt" - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(24.hours), 'dt+24.hours=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), 'dt+86400=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400.seconds), 'dt+86400.seconds=>dt' + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(24.hours), "dt+24.hours=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), "dt+86400=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400.seconds), "dt+86400.seconds=>dt" end end def test_daylight_savings_time_crossings_forward_start_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).since(1.day), 'st+1.day=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(1.day), 'dt+1.day=>dt' + assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).since(1.day), "st+1.day=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(1.day), "dt+1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).since(1.day), 'st+1.day=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(1.day), 'dt+1.day=>dt' + assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).since(1.day), "st+1.day=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(1.day), "dt+1.day=>dt" end end def test_daylight_savings_time_crossings_forward_start_tomorrow - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).tomorrow, 'st+1.day=>dt' - assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).tomorrow, 'dt+1.day=>dt' + assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).tomorrow, "st+1.day=>dt" + assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).tomorrow, "dt+1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).tomorrow, 'st+1.day=>dt' - assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).tomorrow, 'dt+1.day=>dt' + assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).tomorrow, "st+1.day=>dt" + assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).tomorrow, "dt+1.day=>dt" end end def test_daylight_savings_time_crossings_backward_start_yesterday - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # st: US: 2005 April 2nd 7:27pm - assert_equal Time.local(2005,4,2,19,27,0), Time.local(2005,4,3,19,27,0).yesterday, 'dt-1.day=>st' - assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,4,19,27,0).yesterday, 'dt-1.day=>dt' + assert_equal Time.local(2005,4,2,19,27,0), Time.local(2005,4,3,19,27,0).yesterday, "dt-1.day=>st" + assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,4,19,27,0).yesterday, "dt-1.day=>dt" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # st: New Zealand: 2006 September 30th 7:27pm - assert_equal Time.local(2006,9,30,19,27,0), Time.local(2006,10,1,19,27,0).yesterday, 'dt-1.day=>st' - assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,10,2,19,27,0).yesterday, 'dt-1.day=>dt' + assert_equal Time.local(2006,9,30,19,27,0), Time.local(2006,10,1,19,27,0).yesterday, "dt-1.day=>st" + assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,10,2,19,27,0).yesterday, "dt-1.day=>dt" end end def test_daylight_savings_time_crossings_forward_end - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(24.hours), 'dt+24.hours=>st' - assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400), 'dt+86400=>st' - assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400.seconds), 'dt+86400.seconds=>st' + assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(24.hours), "dt+24.hours=>st" + assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400), "dt+86400=>st" + assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400.seconds), "dt+86400.seconds=>st" - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(24.hours), 'st+24.hours=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), 'st+86400=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400.seconds), 'st+86400.seconds=>st' + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(24.hours), "st+24.hours=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), "st+86400=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400.seconds), "st+86400.seconds=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(24.hours), 'dt+24.hours=>st' - assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400), 'dt+86400=>st' - assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400.seconds), 'dt+86400.seconds=>st' + assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(24.hours), "dt+24.hours=>st" + assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400), "dt+86400=>st" + assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400.seconds), "dt+86400.seconds=>st" - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(24.hours), 'st+24.hours=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), 'st+86400=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400.seconds), 'st+86400.seconds=>st' + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(24.hours), "st+24.hours=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), "st+86400=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400.seconds), "st+86400.seconds=>st" end end def test_daylight_savings_time_crossings_forward_end_1day - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).since(1.day), 'dt+1.day=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(1.day), 'st+1.day=>st' + assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).since(1.day), "dt+1.day=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(1.day), "st+1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).since(1.day), 'dt+1.day=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(1.day), 'st+1.day=>st' + assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).since(1.day), "dt+1.day=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(1.day), "st+1.day=>st" end end def test_daylight_savings_time_crossings_forward_end_tomorrow - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).tomorrow, 'dt+1.day=>st' - assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).tomorrow, 'st+1.day=>st' + assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).tomorrow, "dt+1.day=>st" + assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).tomorrow, "st+1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).tomorrow, 'dt+1.day=>st' - assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).tomorrow, 'st+1.day=>st' + assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).tomorrow, "dt+1.day=>st" + assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).tomorrow, "st+1.day=>st" end end def test_daylight_savings_time_crossings_backward_end_yesterday - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # dt: US: 2005 October 30th 12:45am - assert_equal Time.local(2005,10,30,0,45,0), Time.local(2005,10,31,0,45,0).yesterday, 'st-1.day=>dt' - assert_equal Time.local(2005,10, 31,0,45,0), Time.local(2005,11,1,0,45,0).yesterday, 'st-1.day=>st' + assert_equal Time.local(2005,10,30,0,45,0), Time.local(2005,10,31,0,45,0).yesterday, "st-1.day=>dt" + assert_equal Time.local(2005,10, 31,0,45,0), Time.local(2005,11,1,0,45,0).yesterday, "st-1.day=>st" end - with_env_tz 'NZ' do + with_env_tz "NZ" do # dt: New Zealand: 2006 March 19th 1:45am - assert_equal Time.local(2006,3,19,1,45,0), Time.local(2006,3,20,1,45,0).yesterday, 'st-1.day=>dt' - assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,21,1,45,0).yesterday, 'st-1.day=>st' + assert_equal Time.local(2006,3,19,1,45,0), Time.local(2006,3,20,1,45,0).yesterday, "st-1.day=>dt" + assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,21,1,45,0).yesterday, "st-1.day=>st" end end def test_change - assert_equal Time.local(2006,2,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:year => 2006) - assert_equal Time.local(2005,6,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:month => 6) - assert_equal Time.local(2012,9,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:year => 2012, :month => 9) - assert_equal Time.local(2005,2,22,16), Time.local(2005,2,22,15,15,10).change(:hour => 16) - assert_equal Time.local(2005,2,22,16,45), Time.local(2005,2,22,15,15,10).change(:hour => 16, :min => 45) - assert_equal Time.local(2005,2,22,15,45), Time.local(2005,2,22,15,15,10).change(:min => 45) - - assert_equal Time.local(2005,1,2, 5, 0, 0, 0), Time.local(2005,1,2,11,22,33,44).change(:hour => 5) - assert_equal Time.local(2005,1,2,11, 6, 0, 0), Time.local(2005,1,2,11,22,33,44).change(:min => 6) - assert_equal Time.local(2005,1,2,11,22, 7, 0), Time.local(2005,1,2,11,22,33,44).change(:sec => 7) - assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,44).change(:usec => 8) - assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,2).change(:nsec => 8000) - assert_raise(ArgumentError) { Time.local(2005,1,2,11,22,33, 8).change(:usec => 1, :nsec => 1) } - assert_nothing_raised { Time.new(2015, 5, 9, 10, 00, 00, '+03:00').change(nsec: 999999999) } + assert_equal Time.local(2006,2,22,15,15,10), Time.local(2005,2,22,15,15,10).change(year: 2006) + assert_equal Time.local(2005,6,22,15,15,10), Time.local(2005,2,22,15,15,10).change(month: 6) + assert_equal Time.local(2012,9,22,15,15,10), Time.local(2005,2,22,15,15,10).change(year: 2012, month: 9) + assert_equal Time.local(2005,2,22,16), Time.local(2005,2,22,15,15,10).change(hour: 16) + assert_equal Time.local(2005,2,22,16,45), Time.local(2005,2,22,15,15,10).change(hour: 16, min: 45) + assert_equal Time.local(2005,2,22,15,45), Time.local(2005,2,22,15,15,10).change(min: 45) + + assert_equal Time.local(2005,1,2, 5, 0, 0, 0), Time.local(2005,1,2,11,22,33,44).change(hour: 5) + assert_equal Time.local(2005,1,2,11, 6, 0, 0), Time.local(2005,1,2,11,22,33,44).change(min: 6) + assert_equal Time.local(2005,1,2,11,22, 7, 0), Time.local(2005,1,2,11,22,33,44).change(sec: 7) + assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,44).change(usec: 8) + assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,2).change(nsec: 8000) + assert_raise(ArgumentError) { Time.local(2005,1,2,11,22,33, 8).change(usec: 1, nsec: 1) } + assert_nothing_raised { Time.new(2015, 5, 9, 10, 00, 00, "+03:00").change(nsec: 999999999) } end def test_utc_change - assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:year => 2006) - assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:month => 6) - assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:year => 2012, :month => 9) - assert_equal Time.utc(2005,2,22,16), Time.utc(2005,2,22,15,15,10).change(:hour => 16) - assert_equal Time.utc(2005,2,22,16,45), Time.utc(2005,2,22,15,15,10).change(:hour => 16, :min => 45) - assert_equal Time.utc(2005,2,22,15,45), Time.utc(2005,2,22,15,15,10).change(:min => 45) - assert_equal Time.utc(2005,1,2,11,22,33,8), Time.utc(2005,1,2,11,22,33,2).change(:nsec => 8000) + assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(year: 2006) + assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(month: 6) + assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(year: 2012, month: 9) + assert_equal Time.utc(2005,2,22,16), Time.utc(2005,2,22,15,15,10).change(hour: 16) + assert_equal Time.utc(2005,2,22,16,45), Time.utc(2005,2,22,15,15,10).change(hour: 16, min: 45) + assert_equal Time.utc(2005,2,22,15,45), Time.utc(2005,2,22,15,15,10).change(min: 45) + assert_equal Time.utc(2005,1,2,11,22,33,8), Time.utc(2005,1,2,11,22,33,2).change(nsec: 8000) end def test_offset_change - assert_equal Time.new(2006,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:year => 2006) - assert_equal Time.new(2005,6,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:month => 6) - assert_equal Time.new(2012,9,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:year => 2012, :month => 9) - assert_equal Time.new(2005,2,22,16,0,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:hour => 16) - assert_equal Time.new(2005,2,22,16,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:hour => 16, :min => 45) - assert_equal Time.new(2005,2,22,15,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(:min => 45) - assert_equal Time.new(2005,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,0,"-08:00").change(:sec => 10) - assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(:usec => 10).usec - assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(:nsec => 10).nsec - assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(:usec => 1000000) } - assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(:nsec => 1000000000) } + assert_equal Time.new(2006,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(year: 2006) + assert_equal Time.new(2005,6,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(month: 6) + assert_equal Time.new(2012,9,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(year: 2012, month: 9) + assert_equal Time.new(2005,2,22,16,0,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(hour: 16) + assert_equal Time.new(2005,2,22,16,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(hour: 16, min: 45) + assert_equal Time.new(2005,2,22,15,45,0,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").change(min: 45) + assert_equal Time.new(2005,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,0,"-08:00").change(sec: 10) + assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(usec: 10).usec + assert_equal 10, Time.new(2005,2,22,15,15,0,"-08:00").change(nsec: 10).nsec + assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(usec: 1000000) } + assert_raise(ArgumentError) { Time.new(2005, 2, 22, 15, 15, 45, "-08:00").change(nsec: 1000000000) } end def test_advance - assert_equal Time.local(2006,2,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 1) - assert_equal Time.local(2005,6,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:months => 4) - assert_equal Time.local(2005,3,21,15,15,10), Time.local(2005,2,28,15,15,10).advance(:weeks => 3) - assert_equal Time.local(2005,3,25,3,15,10), Time.local(2005,2,28,15,15,10).advance(:weeks => 3.5) - assert_in_delta Time.local(2005,3,26,12,51,10), Time.local(2005,2,28,15,15,10).advance(:weeks => 3.7), 1 - assert_equal Time.local(2005,3,5,15,15,10), Time.local(2005,2,28,15,15,10).advance(:days => 5) - assert_equal Time.local(2005,3,6,3,15,10), Time.local(2005,2,28,15,15,10).advance(:days => 5.5) - assert_in_delta Time.local(2005,3,6,8,3,10), Time.local(2005,2,28,15,15,10).advance(:days => 5.7), 1 - assert_equal Time.local(2012,9,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 7) - assert_equal Time.local(2013,10,3,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :days => 5) - assert_equal Time.local(2013,10,17,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Time.local(2001,12,27,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1) - assert_equal Time.local(2005,2,28,15,15,10), Time.local(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year - assert_equal Time.local(2005,2,28,20,15,10), Time.local(2005,2,28,15,15,10).advance(:hours => 5) - assert_equal Time.local(2005,2,28,15,22,10), Time.local(2005,2,28,15,15,10).advance(:minutes => 7) - assert_equal Time.local(2005,2,28,15,15,19), Time.local(2005,2,28,15,15,10).advance(:seconds => 9) - assert_equal Time.local(2005,2,28,20,22,19), Time.local(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal Time.local(2005,2,28,10,8,1), Time.local(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal Time.local(2013,10,17,20,22,19), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal Time.local(2006,2,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 1) + assert_equal Time.local(2005,6,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(months: 4) + assert_equal Time.local(2005,3,21,15,15,10), Time.local(2005,2,28,15,15,10).advance(weeks: 3) + assert_equal Time.local(2005,3,25,3,15,10), Time.local(2005,2,28,15,15,10).advance(weeks: 3.5) + assert_in_delta Time.local(2005,3,26,12,51,10), Time.local(2005,2,28,15,15,10).advance(weeks: 3.7), 1 + assert_equal Time.local(2005,3,5,15,15,10), Time.local(2005,2,28,15,15,10).advance(days: 5) + assert_equal Time.local(2005,3,6,3,15,10), Time.local(2005,2,28,15,15,10).advance(days: 5.5) + assert_in_delta Time.local(2005,3,6,8,3,10), Time.local(2005,2,28,15,15,10).advance(days: 5.7), 1 + assert_equal Time.local(2012,9,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 7) + assert_equal Time.local(2013,10,3,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 19, days: 5) + assert_equal Time.local(2013,10,17,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Time.local(2001,12,27,15,15,10), Time.local(2005,2,28,15,15,10).advance(years: -3, months: -2, days: -1) + assert_equal Time.local(2005,2,28,15,15,10), Time.local(2004,2,29,15,15,10).advance(years: 1) #leap day plus one year + assert_equal Time.local(2005,2,28,20,15,10), Time.local(2005,2,28,15,15,10).advance(hours: 5) + assert_equal Time.local(2005,2,28,15,22,10), Time.local(2005,2,28,15,15,10).advance(minutes: 7) + assert_equal Time.local(2005,2,28,15,15,19), Time.local(2005,2,28,15,15,10).advance(seconds: 9) + assert_equal Time.local(2005,2,28,20,22,19), Time.local(2005,2,28,15,15,10).advance(hours: 5, minutes: 7, seconds: 9) + assert_equal Time.local(2005,2,28,10,8,1), Time.local(2005,2,28,15,15,10).advance(hours: -5, minutes: -7, seconds: -9) + assert_equal Time.local(2013,10,17,20,22,19), Time.local(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_utc_advance - assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 1) - assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:months => 4) - assert_equal Time.utc(2005,3,21,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:weeks => 3) - assert_equal Time.utc(2005,3,25,3,15,10), Time.utc(2005,2,28,15,15,10).advance(:weeks => 3.5) - assert_in_delta Time.utc(2005,3,26,12,51,10), Time.utc(2005,2,28,15,15,10).advance(:weeks => 3.7), 1 - assert_equal Time.utc(2005,3,5,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:days => 5) - assert_equal Time.utc(2005,3,6,3,15,10), Time.utc(2005,2,28,15,15,10).advance(:days => 5.5) - assert_in_delta Time.utc(2005,3,6,8,3,10), Time.utc(2005,2,28,15,15,10).advance(:days => 5.7), 1 - assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 7) - assert_equal Time.utc(2013,10,3,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 19, :days => 11) - assert_equal Time.utc(2013,10,17,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Time.utc(2001,12,27,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1) - assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year - assert_equal Time.utc(2005,2,28,20,15,10), Time.utc(2005,2,28,15,15,10).advance(:hours => 5) - assert_equal Time.utc(2005,2,28,15,22,10), Time.utc(2005,2,28,15,15,10).advance(:minutes => 7) - assert_equal Time.utc(2005,2,28,15,15,19), Time.utc(2005,2,28,15,15,10).advance(:seconds => 9) - assert_equal Time.utc(2005,2,28,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal Time.utc(2005,2,28,10,8,1), Time.utc(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal Time.utc(2013,10,17,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(years: 1) + assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(months: 4) + assert_equal Time.utc(2005,3,21,15,15,10), Time.utc(2005,2,28,15,15,10).advance(weeks: 3) + assert_equal Time.utc(2005,3,25,3,15,10), Time.utc(2005,2,28,15,15,10).advance(weeks: 3.5) + assert_in_delta Time.utc(2005,3,26,12,51,10), Time.utc(2005,2,28,15,15,10).advance(weeks: 3.7), 1 + assert_equal Time.utc(2005,3,5,15,15,10), Time.utc(2005,2,28,15,15,10).advance(days: 5) + assert_equal Time.utc(2005,3,6,3,15,10), Time.utc(2005,2,28,15,15,10).advance(days: 5.5) + assert_in_delta Time.utc(2005,3,6,8,3,10), Time.utc(2005,2,28,15,15,10).advance(days: 5.7), 1 + assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(years: 7, months: 7) + assert_equal Time.utc(2013,10,3,15,15,10), Time.utc(2005,2,22,15,15,10).advance(years: 7, months: 19, days: 11) + assert_equal Time.utc(2013,10,17,15,15,10), Time.utc(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Time.utc(2001,12,27,15,15,10), Time.utc(2005,2,28,15,15,10).advance(years: -3, months: -2, days: -1) + assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10).advance(years: 1) #leap day plus one year + assert_equal Time.utc(2005,2,28,20,15,10), Time.utc(2005,2,28,15,15,10).advance(hours: 5) + assert_equal Time.utc(2005,2,28,15,22,10), Time.utc(2005,2,28,15,15,10).advance(minutes: 7) + assert_equal Time.utc(2005,2,28,15,15,19), Time.utc(2005,2,28,15,15,10).advance(seconds: 9) + assert_equal Time.utc(2005,2,28,20,22,19), Time.utc(2005,2,28,15,15,10).advance(hours: 5, minutes: 7, seconds: 9) + assert_equal Time.utc(2005,2,28,10,8,1), Time.utc(2005,2,28,15,15,10).advance(hours: -5, minutes: -7, seconds: -9) + assert_equal Time.utc(2013,10,17,20,22,19), Time.utc(2005,2,28,15,15,10).advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_offset_advance - assert_equal Time.new(2006,2,22,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:years => 1) - assert_equal Time.new(2005,6,22,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:months => 4) - assert_equal Time.new(2005,3,21,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:weeks => 3) - assert_equal Time.new(2005,3,25,3,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:weeks => 3.5) - assert_in_delta Time.new(2005,3,26,12,51,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:weeks => 3.7), 1 - assert_equal Time.new(2005,3,5,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:days => 5) - assert_equal Time.new(2005,3,6,3,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:days => 5.5) - assert_in_delta Time.new(2005,3,6,8,3,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:days => 5.7), 1 - assert_equal Time.new(2012,9,22,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:years => 7, :months => 7) - assert_equal Time.new(2013,10,3,15,15,10,'-08:00'), Time.new(2005,2,22,15,15,10,'-08:00').advance(:years => 7, :months => 19, :days => 11) - assert_equal Time.new(2013,10,17,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:years => 7, :months => 19, :weeks => 2, :days => 5) - assert_equal Time.new(2001,12,27,15,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:years => -3, :months => -2, :days => -1) - assert_equal Time.new(2005,2,28,15,15,10,'-08:00'), Time.new(2004,2,29,15,15,10,'-08:00').advance(:years => 1) #leap day plus one year - assert_equal Time.new(2005,2,28,20,15,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:hours => 5) - assert_equal Time.new(2005,2,28,15,22,10,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:minutes => 7) - assert_equal Time.new(2005,2,28,15,15,19,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:seconds => 9) - assert_equal Time.new(2005,2,28,20,22,19,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:hours => 5, :minutes => 7, :seconds => 9) - assert_equal Time.new(2005,2,28,10,8,1,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:hours => -5, :minutes => -7, :seconds => -9) - assert_equal Time.new(2013,10,17,20,22,19,'-08:00'), Time.new(2005,2,28,15,15,10,'-08:00').advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9) + assert_equal Time.new(2006,2,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(years: 1) + assert_equal Time.new(2005,6,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(months: 4) + assert_equal Time.new(2005,3,21,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(weeks: 3) + assert_equal Time.new(2005,3,25,3,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(weeks: 3.5) + assert_in_delta Time.new(2005,3,26,12,51,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(weeks: 3.7), 1 + assert_equal Time.new(2005,3,5,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(days: 5) + assert_equal Time.new(2005,3,6,3,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(days: 5.5) + assert_in_delta Time.new(2005,3,6,8,3,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(days: 5.7), 1 + assert_equal Time.new(2012,9,22,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(years: 7, months: 7) + assert_equal Time.new(2013,10,3,15,15,10,"-08:00"), Time.new(2005,2,22,15,15,10,"-08:00").advance(years: 7, months: 19, days: 11) + assert_equal Time.new(2013,10,17,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(years: 7, months: 19, weeks: 2, days: 5) + assert_equal Time.new(2001,12,27,15,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(years: -3, months: -2, days: -1) + assert_equal Time.new(2005,2,28,15,15,10,"-08:00"), Time.new(2004,2,29,15,15,10,"-08:00").advance(years: 1) #leap day plus one year + assert_equal Time.new(2005,2,28,20,15,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(hours: 5) + assert_equal Time.new(2005,2,28,15,22,10,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(minutes: 7) + assert_equal Time.new(2005,2,28,15,15,19,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(seconds: 9) + assert_equal Time.new(2005,2,28,20,22,19,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(hours: 5, minutes: 7, seconds: 9) + assert_equal Time.new(2005,2,28,10,8,1,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(hours: -5, minutes: -7, seconds: -9) + assert_equal Time.new(2013,10,17,20,22,19,"-08:00"), Time.new(2005,2,28,15,15,10,"-08:00").advance(years: 7, months: 19, weeks: 2, days: 5, hours: 5, minutes: 7, seconds: 9) end def test_advance_with_nsec t = Time.at(0, Rational(108635108, 1000)) - assert_equal t, t.advance(:months => 0) + assert_equal t, t.advance(months: 0) end def test_advance_gregorian_proleptic - assert_equal Time.local(1582,10,14,15,15,10), Time.local(1582,10,15,15,15,10).advance(:days => -1) - assert_equal Time.local(1582,10,15,15,15,10), Time.local(1582,10,14,15,15,10).advance(:days => 1) - assert_equal Time.local(1582,10,5,15,15,10), Time.local(1582,10,4,15,15,10).advance(:days => 1) - assert_equal Time.local(1582,10,4,15,15,10), Time.local(1582,10,5,15,15,10).advance(:days => -1) + assert_equal Time.local(1582,10,14,15,15,10), Time.local(1582,10,15,15,15,10).advance(days: -1) + assert_equal Time.local(1582,10,15,15,15,10), Time.local(1582,10,14,15,15,10).advance(days: 1) + assert_equal Time.local(1582,10,5,15,15,10), Time.local(1582,10,4,15,15,10).advance(days: 1) + assert_equal Time.local(1582,10,4,15,15,10), Time.local(1582,10,5,15,15,10).advance(days: -1) end def test_last_week - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.local(2005,2,21), Time.local(2005,3,1,15,15,10).last_week assert_equal Time.local(2005,2,22), Time.local(2005,3,1,15,15,10).last_week(:tuesday) assert_equal Time.local(2005,2,25), Time.local(2005,3,1,15,15,10).last_week(:friday) @@ -522,20 +522,20 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_next_week_near_daylight_start - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,4,3), Time.local(2006,4,2,23,1,0).next_week, 'just crossed standard => daylight' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,4,3), Time.local(2006,4,2,23,1,0).next_week, "just crossed standard => daylight" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,10,2), Time.local(2006,10,1,23,1,0).next_week, 'just crossed standard => daylight' + with_env_tz "NZ" do + assert_equal Time.local(2006,10,2), Time.local(2006,10,1,23,1,0).next_week, "just crossed standard => daylight" end end def test_next_week_near_daylight_end - with_env_tz 'US/Eastern' do - assert_equal Time.local(2006,10,30), Time.local(2006,10,29,23,1,0).next_week, 'just crossed daylight => standard' + with_env_tz "US/Eastern" do + assert_equal Time.local(2006,10,30), Time.local(2006,10,29,23,1,0).next_week, "just crossed daylight => standard" end - with_env_tz 'NZ' do - assert_equal Time.local(2006,3,20), Time.local(2006,3,19,23,1,0).next_week, 'just crossed daylight => standard' + with_env_tz "NZ" do + assert_equal Time.local(2006,3,20), Time.local(2006,3,19,23,1,0).next_week, "just crossed daylight => standard" end end @@ -564,8 +564,8 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_custom_date_format - Time::DATE_FORMATS[:custom] = '%Y%m%d%H%M%S' - assert_equal '20050221143000', Time.local(2005, 2, 21, 14, 30, 0).to_s(:custom) + Time::DATE_FORMATS[:custom] = "%Y%m%d%H%M%S" + assert_equal "20050221143000", Time.local(2005, 2, 21, 14, 30, 0).to_s(:custom) Time::DATE_FORMATS.delete(:custom) end @@ -575,17 +575,17 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_to_datetime assert_equal Time.utc(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, 0) - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.local(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, Rational(Time.local(2005, 2, 21, 17, 44, 30).utc_offset, 86400)) end - with_env_tz 'NZ' do + with_env_tz "NZ" do assert_equal Time.local(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, Rational(Time.local(2005, 2, 21, 17, 44, 30).utc_offset, 86400)) end assert_equal ::Date::ITALY, Time.utc(2005, 2, 21, 17, 44, 30).to_datetime.start # use Ruby's default start value end def test_to_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time, Time.local(2005, 2, 21, 17, 44, 30).to_time.class assert_equal Time.local(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30).to_time assert_equal Time.local(2005, 2, 21, 17, 44, 30).utc_offset, Time.local(2005, 2, 21, 17, 44, 30).to_time.utc_offset @@ -677,7 +677,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_past_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal true, Time.local(2005,2,10,15,30,44).past? assert_equal false, Time.local(2005,2,10,15,30,45).past? @@ -690,8 +690,8 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_past_with_time_current_as_time_with_zone - with_env_tz 'US/Eastern' do - twz = Time.utc(2005,2,10,15,30,45).in_time_zone('Central Time (US & Canada)') + with_env_tz "US/Eastern" do + twz = Time.utc(2005,2,10,15,30,45).in_time_zone("Central Time (US & Canada)") Time.stub(:current, twz) do assert_equal true, Time.local(2005,2,10,10,30,44).past? assert_equal false, Time.local(2005,2,10,10,30,45).past? @@ -704,7 +704,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_future_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal false, Time.local(2005,2,10,15,30,44).future? assert_equal false, Time.local(2005,2,10,15,30,45).future? @@ -717,8 +717,8 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_future_with_time_current_as_time_with_zone - with_env_tz 'US/Eastern' do - twz = Time.utc(2005,2,10,15,30,45).in_time_zone('Central Time (US & Canada)') + with_env_tz "US/Eastern" do + twz = Time.utc(2005,2,10,15,30,45).in_time_zone("Central Time (US & Canada)") Time.stub(:current, twz) do assert_equal false, Time.local(2005,2,10,10,30,44).future? assert_equal false, Time.local(2005,2,10,10,30,45).future? @@ -735,17 +735,17 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_formatted_offset_with_utc - assert_equal '+00:00', Time.utc(2000).formatted_offset - assert_equal '+0000', Time.utc(2000).formatted_offset(false) - assert_equal 'UTC', Time.utc(2000).formatted_offset(true, 'UTC') + assert_equal "+00:00", Time.utc(2000).formatted_offset + assert_equal "+0000", Time.utc(2000).formatted_offset(false) + assert_equal "UTC", Time.utc(2000).formatted_offset(true, "UTC") end def test_formatted_offset_with_local - with_env_tz 'US/Eastern' do - assert_equal '-05:00', Time.local(2000).formatted_offset - assert_equal '-0500', Time.local(2000).formatted_offset(false) - assert_equal '-04:00', Time.local(2000, 7).formatted_offset - assert_equal '-0400', Time.local(2000, 7).formatted_offset(false) + with_env_tz "US/Eastern" do + assert_equal "-05:00", Time.local(2000).formatted_offset + assert_equal "-0500", Time.local(2000).formatted_offset(false) + assert_equal "-04:00", Time.local(2000, 7).formatted_offset + assert_equal "-0400", Time.local(2000, 7).formatted_offset(false) end end @@ -762,16 +762,16 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_compare_with_time_with_zone - assert_equal 1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] ) - assert_equal 0, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] ) - assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] )) + assert_equal 1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone["UTC"] ) + assert_equal 0, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"] ) + assert_equal(-1, Time.utc(2000) <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone["UTC"] )) end def test_compare_with_string assert_equal 1, Time.utc(2000) <=> Time.utc(1999, 12, 31, 23, 59, 59, 999).to_s assert_equal 0, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 0).to_s assert_equal( -1, Time.utc(2000) <=> Time.utc(2000, 1, 1, 0, 0, 1, 0).to_s) - assert_equal nil, Time.utc(2000) <=> 'Invalid as Time' + assert_equal nil, Time.utc(2000) <=> "Invalid as Time" end def test_at_with_datetime @@ -786,42 +786,42 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_at_with_datetime_returns_local_time - with_env_tz 'US/Eastern' do - dt = DateTime.civil(2000, 1, 1, 0, 0, 0, '+0') + with_env_tz "US/Eastern" do + dt = DateTime.civil(2000, 1, 1, 0, 0, 0, "+0") assert_equal Time.local(1999, 12, 31, 19, 0, 0), Time.at(dt) - assert_equal 'EST', Time.at(dt).zone + assert_equal "EST", Time.at(dt).zone assert_equal(-18000, Time.at(dt).utc_offset) # Daylight savings - dt = DateTime.civil(2000, 7, 1, 1, 0, 0, '+1') + dt = DateTime.civil(2000, 7, 1, 1, 0, 0, "+1") assert_equal Time.local(2000, 6, 30, 20, 0, 0), Time.at(dt) - assert_equal 'EDT', Time.at(dt).zone + assert_equal "EDT", Time.at(dt).zone assert_equal(-14400, Time.at(dt).utc_offset) end end def test_at_with_time_with_zone - assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'])) + assert_equal Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"])) # Only test this if the underlying Time.at raises a TypeError begin Time.at_without_coercion(Time.now, 0) rescue TypeError - assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC']), 0)) } + assert_raise(TypeError) { assert_equal(Time.utc(2000, 1, 1, 0, 0, 0), Time.at(ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"]), 0)) } end end def test_at_with_time_with_zone_returns_local_time - with_env_tz 'US/Eastern' do - twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['London']) + with_env_tz "US/Eastern" do + twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["London"]) assert_equal Time.local(1999, 12, 31, 19, 0, 0), Time.at(twz) - assert_equal 'EST', Time.at(twz).zone + assert_equal "EST", Time.at(twz).zone assert_equal(-18000, Time.at(twz).utc_offset) # Daylight savings - twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 7, 1, 0, 0, 0), ActiveSupport::TimeZone['London']) + twz = ActiveSupport::TimeWithZone.new(Time.utc(2000, 7, 1, 0, 0, 0), ActiveSupport::TimeZone["London"]) assert_equal Time.local(2000, 6, 30, 20, 0, 0), Time.at(twz) - assert_equal 'EDT', Time.at(twz).zone + assert_equal "EDT", Time.at(twz).zone assert_equal(-14400, Time.at(twz).utc_offset) end end @@ -831,33 +831,33 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_at_with_utc_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.utc(2000), Time.at(Time.utc(2000)) - assert_equal 'UTC', Time.at(Time.utc(2000)).zone + assert_equal "UTC", Time.at(Time.utc(2000)).zone assert_equal(0, Time.at(Time.utc(2000)).utc_offset) end end def test_at_with_local_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time.local(2000), Time.at(Time.local(2000)) - assert_equal 'EST', Time.at(Time.local(2000)).zone + assert_equal "EST", Time.at(Time.local(2000)).zone assert_equal(-18000, Time.at(Time.local(2000)).utc_offset) assert_equal Time.local(2000, 7, 1), Time.at(Time.local(2000, 7, 1)) - assert_equal 'EDT', Time.at(Time.local(2000, 7, 1)).zone + assert_equal "EDT", Time.at(Time.local(2000, 7, 1)).zone assert_equal(-14400, Time.at(Time.local(2000, 7, 1)).utc_offset) end end def test_eql? - assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) ) + assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) ) assert_equal true, Time.utc(2000).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Hawaii"]) ) - assert_equal false,Time.utc(2000, 1, 1, 0, 0, 1).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) ) + assert_equal false,Time.utc(2000, 1, 1, 0, 0, 1).eql?( ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) ) end def test_minus_with_time_with_zone - assert_equal 86_400.0, Time.utc(2000, 1, 2) - ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] ) + assert_equal 86_400.0, Time.utc(2000, 1, 2) - ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["UTC"] ) end def test_minus_with_datetime @@ -865,7 +865,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end def test_time_created_with_local_constructor_cannot_represent_times_during_hour_skipped_by_dst - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do # On Apr 2 2006 at 2:00AM in US, clocks were moved forward to 3:00AM. # Therefore, 2AM EST doesn't exist for this date; Time.local fails over to 3:00AM EDT assert_equal Time.local(2006, 4, 2, 3), Time.local(2006, 4, 2, 2) @@ -875,11 +875,11 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase def test_case_equality assert Time === Time.utc(2000) - assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) + assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) assert Time === Class.new(Time).utc(2000) assert_equal false, Time === DateTime.civil(2000) assert_equal false, Class.new(Time) === Time.utc(2000) - assert_equal false, Class.new(Time) === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']) + assert_equal false, Class.new(Time) === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]) end def test_all_day @@ -942,7 +942,7 @@ class TimeExtMarshalingTest < ActiveSupport::TestCase end def test_marshalling_preserves_fractional_seconds - t = Time.parse('00:00:00.500') + t = Time.parse("00:00:00.500") unmarshaled = Marshal.load(Marshal.dump(t)) assert_equal t.to_f, unmarshaled.to_f assert_equal t, unmarshaled diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index d90714acdb..e35aa6e154 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -1,15 +1,15 @@ -require 'abstract_unit' -require 'active_support/time' -require 'time_zone_test_helpers' -require 'active_support/core_ext/string/strip' -require 'yaml' +require "abstract_unit" +require "active_support/time" +require "time_zone_test_helpers" +require "active_support/core_ext/string/strip" +require "yaml" class TimeWithZoneTest < ActiveSupport::TestCase include TimeZoneTestHelpers def setup @utc = Time.utc(2000, 1, 1, 0) - @time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + @time_zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] @twz = ActiveSupport::TimeWithZone.new(@utc, @time_zone) @dt_twz = ActiveSupport::TimeWithZone.new(@utc.to_datetime, @time_zone) end @@ -29,21 +29,21 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_in_time_zone - Time.use_zone 'Alaska' do - assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone['Alaska']), @twz.in_time_zone + Time.use_zone "Alaska" do + assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone["Alaska"]), @twz.in_time_zone end end def test_in_time_zone_with_argument - assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone['Alaska']), @twz.in_time_zone('Alaska') + assert_equal ActiveSupport::TimeWithZone.new(@utc, ActiveSupport::TimeZone["Alaska"]), @twz.in_time_zone("Alaska") end def test_in_time_zone_with_new_zone_equal_to_old_zone_does_not_create_new_object - assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone['Eastern Time (US & Canada)']).object_id + assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone["Eastern Time (US & Canada)"]).object_id end def test_in_time_zone_with_bad_argument - assert_raise(ArgumentError) { @twz.in_time_zone('No such timezone exists') } + assert_raise(ArgumentError) { @twz.in_time_zone("No such timezone exists") } assert_raise(ArgumentError) { @twz.in_time_zone(-15.hours) } assert_raise(ArgumentError) { @twz.in_time_zone(Object.new) } end @@ -57,26 +57,26 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_utc? assert_equal false, @twz.utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Etc/UTC']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Universal']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UCT']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Etc/UCT']).utc? - assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Etc/Universal']).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UTC"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Etc/UTC"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Universal"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["UCT"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Etc/UCT"]).utc? + assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Etc/Universal"]).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Abidjan']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Banjul']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Freetown']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['GMT']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['GMT0']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Greenwich']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Iceland']).utc? - assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['Africa/Monrovia']).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Abidjan"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Banjul"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Freetown"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["GMT"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["GMT0"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Greenwich"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Iceland"]).utc? + assert_equal false, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone["Africa/Monrovia"]).utc? end def test_formatted_offset - assert_equal '-05:00', @twz.formatted_offset - assert_equal '-04:00', ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).formatted_offset #dst + assert_equal "-05:00", @twz.formatted_offset + assert_equal "-04:00", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).formatted_offset #dst end def test_dst? @@ -85,8 +85,8 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_zone - assert_equal 'EST', @twz.zone - assert_equal 'EDT', ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone #dst + assert_equal "EST", @twz.zone + assert_equal "EDT", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone #dst end def test_nsec @@ -98,28 +98,28 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_strftime - assert_equal '1999-12-31 19:00:00 EST -0500', @twz.strftime('%Y-%m-%d %H:%M:%S %Z %z') + assert_equal "1999-12-31 19:00:00 EST -0500", @twz.strftime("%Y-%m-%d %H:%M:%S %Z %z") end def test_strftime_with_escaping - assert_equal '%Z %z', @twz.strftime('%%Z %%z') - assert_equal '%EST %-0500', @twz.strftime('%%%Z %%%z') + assert_equal "%Z %z", @twz.strftime("%%Z %%z") + assert_equal "%EST %-0500", @twz.strftime("%%%Z %%%z") end def test_inspect - assert_equal 'Fri, 31 Dec 1999 19:00:00 EST -05:00', @twz.inspect + assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect end def test_to_s - assert_equal '1999-12-31 19:00:00 -0500', @twz.to_s + assert_equal "1999-12-31 19:00:00 -0500", @twz.to_s end def test_to_formatted_s - assert_equal '1999-12-31 19:00:00 -0500', @twz.to_formatted_s + assert_equal "1999-12-31 19:00:00 -0500", @twz.to_formatted_s end def test_to_s_db - assert_equal '2000-01-01 00:00:00', @twz.to_s(:db) + assert_equal "2000-01-01 00:00:00", @twz.to_s(:db) end def test_xmlschema @@ -166,7 +166,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase time: 1999-12-31 19:00:00.000000000 Z EOF - assert_equal(yaml, { 'twz' => @twz }.to_yaml) + assert_equal(yaml, { "twz" => @twz }.to_yaml) end def test_yaml_load @@ -191,11 +191,11 @@ class TimeWithZoneTest < ActiveSupport::TestCase time: 1999-12-31 19:00:00.000000000 Z EOF - assert_equal({ 'twz' => @twz }, YAML.load(yaml)) + assert_equal({ "twz" => @twz }, YAML.load(yaml)) end def test_httpdate - assert_equal 'Sat, 01 Jan 2000 00:00:00 GMT', @twz.httpdate + assert_equal "Sat, 01 Jan 2000 00:00:00 GMT", @twz.httpdate end def test_rfc2822 @@ -215,9 +215,9 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_compare_with_time_with_zone - assert_equal 1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone['UTC'] ) - assert_equal 0, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone['UTC'] ) - assert_equal(-1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone['UTC'] )) + assert_equal 1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone["UTC"] ) + assert_equal 0, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0), ActiveSupport::TimeZone["UTC"] ) + assert_equal(-1, @twz <=> ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 1), ActiveSupport::TimeZone["UTC"] )) end def test_between? @@ -235,7 +235,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_past_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal true, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).past? assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).past? @@ -254,7 +254,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_future_with_time_current_as_time_local - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:current, Time.local(2005,2,10,15,30,45)) do assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,44)).future? assert_equal false, ActiveSupport::TimeWithZone.new( nil, @time_zone, Time.local(2005,2,10,15,30,45)).future? @@ -322,38 +322,38 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_minus_with_time - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 1) - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['Hawaii'] ) - Time.utc(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - Time.utc(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["Hawaii"] ) - Time.utc(2000, 1, 1) end def test_minus_with_time_precision - assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) - assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['Hawaii'] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) + assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["UTC"] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) + assert_equal 86_399.999999998, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["Hawaii"] ) - Time.utc(2000, 1, 2, 0, 0, 0, Rational(1, 1000)) end def test_minus_with_time_with_zone - twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['UTC'] ) - twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) + twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["UTC"] ) + twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) assert_equal 86_400.0, twz2 - twz1 end def test_minus_with_time_with_zone_precision - twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0, Rational(1, 1000)), ActiveSupport::TimeZone['UTC'] ) - twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) + twz1 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 0, 0, 0, Rational(1, 1000)), ActiveSupport::TimeZone["UTC"] ) + twz2 = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["UTC"] ) assert_equal 86_399.999999998, twz2 - twz1 end def test_minus_with_datetime - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - DateTime.civil(2000, 1, 1) end def test_minus_with_datetime_precision - assert_equal 86_399.999999999, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) + assert_equal 86_399.999999999, ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 23, 59, 59, Rational(999999999, 1000)), ActiveSupport::TimeZone["UTC"] ) - DateTime.civil(2000, 1, 1) end def test_minus_with_wrapped_datetime - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - Time.utc(2000, 1, 1) - assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone['UTC'] ) - DateTime.civil(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - Time.utc(2000, 1, 1) + assert_equal 86_400.0, ActiveSupport::TimeWithZone.new( DateTime.civil(2000, 1, 2), ActiveSupport::TimeZone["UTC"] ) - DateTime.civil(2000, 1, 1) end def test_plus_and_minus_enforce_spring_dst_rules @@ -361,15 +361,15 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(utc, @time_zone) assert_equal Time.utc(2006,4,2,1,59,59), twz.time assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone twz = twz + 1 assert_equal Time.utc(2006,4,2,3), twz.time # adding 1 sec springs forward to 3:00AM EDT assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone twz = twz - 1 # subtracting 1 second takes goes back to 1:59:59AM EST assert_equal Time.utc(2006,4,2,1,59,59), twz.time assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone end def test_plus_and_minus_enforce_fall_dst_rules @@ -377,29 +377,29 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(utc, @time_zone) assert_equal Time.utc(2006,10,29,1,59,59), twz.time assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone twz = twz + 1 assert_equal Time.utc(2006,10,29,1), twz.time # adding 1 sec falls back from 1:59:59 EDT to 1:00AM EST assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone twz = twz - 1 assert_equal Time.utc(2006,10,29,1,59,59), twz.time # subtracting 1 sec goes back to 1:59:59AM EDT assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_to_a - assert_equal [45, 30, 5, 1, 2, 2000, 2, 32, false, "HST"], ActiveSupport::TimeWithZone.new( Time.utc(2000, 2, 1, 15, 30, 45), ActiveSupport::TimeZone['Hawaii'] ).to_a + assert_equal [45, 30, 5, 1, 2, 2000, 2, 32, false, "HST"], ActiveSupport::TimeWithZone.new( Time.utc(2000, 2, 1, 15, 30, 45), ActiveSupport::TimeZone["Hawaii"] ).to_a end def test_to_f - result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_f + result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"] ).to_f assert_equal 946684800.0, result assert_kind_of Float, result end def test_to_i - result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_i + result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"] ).to_i assert_equal 946684800, result assert_kind_of Integer, result end @@ -411,18 +411,18 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_to_r - result = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii']).to_r + result = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"]).to_r assert_equal Rational(946684800, 1), result assert_kind_of Rational, result end def test_time_at - time = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii']) + time = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone["Hawaii"]) assert_equal time, Time.at(time) end def test_to_time - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal Time, @twz.to_time.class assert_equal Time.local(1999, 12, 31, 19), @twz.to_time assert_equal Time.local(1999, 12, 31, 19).utc_offset, @twz.to_time.utc_offset @@ -431,13 +431,13 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_to_date # 1 sec before midnight Jan 1 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 4, 59, 59), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 4, 59, 59), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date # midnight Jan 1 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 5, 0, 0), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1, 5, 0, 0), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date # 1 sec before midnight Jan 2 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 4, 59, 59), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 4, 59, 59), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 5, 0, 0), ActiveSupport::TimeZone['Eastern Time (US & Canada)'] ).to_date + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 2, 5, 0, 0), ActiveSupport::TimeZone["Eastern Time (US & Canada)"] ).to_date end def test_to_datetime @@ -462,7 +462,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_class_name - assert_equal 'Time', ActiveSupport::TimeWithZone.name + assert_equal "Time", ActiveSupport::TimeWithZone.name end def test_method_missing_with_time_return_value @@ -475,19 +475,19 @@ class TimeWithZoneTest < ActiveSupport::TestCase mtime = Marshal.load(marshal_str) assert_equal Time.utc(2000, 1, 1, 0), mtime.utc assert mtime.utc.utc? - assert_equal ActiveSupport::TimeZone['Eastern Time (US & Canada)'], mtime.time_zone + assert_equal ActiveSupport::TimeZone["Eastern Time (US & Canada)"], mtime.time_zone assert_equal Time.utc(1999, 12, 31, 19), mtime.time assert mtime.time.utc? assert_equal @twz.inspect, mtime.inspect end def test_marshal_dump_and_load_with_tzinfo_identifier - twz = ActiveSupport::TimeWithZone.new(@utc, TZInfo::Timezone.get('America/New_York')) + twz = ActiveSupport::TimeWithZone.new(@utc, TZInfo::Timezone.get("America/New_York")) marshal_str = Marshal.dump(twz) mtime = Marshal.load(marshal_str) assert_equal Time.utc(2000, 1, 1, 0), mtime.utc assert mtime.utc.utc? - assert_equal 'America/New_York', mtime.time_zone.name + assert_equal "America/New_York", mtime.time_zone.name assert_equal Time.utc(1999, 12, 31, 19), mtime.time assert mtime.time.utc? assert_equal @twz.inspect, mtime.inspect @@ -508,8 +508,8 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_method_missing_with_non_time_return_value time = @twz.time - def time.foo; 'bar'; end - assert_equal 'bar', @twz.foo + def time.foo; "bar"; end + assert_equal "bar", @twz.foo end def test_date_part_value_methods @@ -543,9 +543,9 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_utc_to_local_conversion_saves_period_in_instance_variable - assert_nil @twz.instance_variable_get('@period') + assert_nil @twz.instance_variable_get("@period") @twz.time - assert_kind_of TZInfo::TimezonePeriod, @twz.instance_variable_get('@period') + assert_kind_of TZInfo::TimezonePeriod, @twz.instance_variable_get("@period") end def test_instance_created_with_local_time_returns_correct_utc_time @@ -557,14 +557,14 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,2)) # first second of DST assert_equal Time.utc(2006,4,2,3), twz.time # springs forward to 3AM assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_instance_created_with_local_time_enforces_fall_dst_rules twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,29,1)) # 1AM can be either DST or non-DST; we'll pick DST assert_equal Time.utc(2006,10,29,1), twz.time assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_ruby_19_weekday_name_query_methods @@ -584,33 +584,33 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_change assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect - assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.change(:year => 2001).inspect - assert_equal "Wed, 31 Mar 1999 19:00:00 EST -05:00", @twz.change(:month => 3).inspect - assert_equal "Wed, 03 Mar 1999 19:00:00 EST -05:00", @twz.change(:month => 2).inspect - assert_equal "Wed, 15 Dec 1999 19:00:00 EST -05:00", @twz.change(:day => 15).inspect - assert_equal "Fri, 31 Dec 1999 06:00:00 EST -05:00", @twz.change(:hour => 6).inspect - assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.change(:min => 15).inspect - assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.change(:sec => 30).inspect + assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.change(year: 2001).inspect + assert_equal "Wed, 31 Mar 1999 19:00:00 EST -05:00", @twz.change(month: 3).inspect + assert_equal "Wed, 03 Mar 1999 19:00:00 EST -05:00", @twz.change(month: 2).inspect + assert_equal "Wed, 15 Dec 1999 19:00:00 EST -05:00", @twz.change(day: 15).inspect + assert_equal "Fri, 31 Dec 1999 06:00:00 EST -05:00", @twz.change(hour: 6).inspect + assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.change(min: 15).inspect + assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.change(sec: 30).inspect end def test_change_at_dst_boundary - twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone['Madrid']) - assert_equal twz, twz.change(:min => 0) + twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone["Madrid"]) + assert_equal twz, twz.change(min: 0) end def test_round_at_dst_boundary - twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone['Madrid']) + twz = ActiveSupport::TimeWithZone.new(Time.at(1319936400).getutc, ActiveSupport::TimeZone["Madrid"]) assert_equal twz, twz.round end def test_advance assert_equal "Fri, 31 Dec 1999 19:00:00 EST -05:00", @twz.inspect - assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.advance(:years => 2).inspect - assert_equal "Fri, 31 Mar 2000 19:00:00 EST -05:00", @twz.advance(:months => 3).inspect - assert_equal "Tue, 04 Jan 2000 19:00:00 EST -05:00", @twz.advance(:days => 4).inspect - assert_equal "Sat, 01 Jan 2000 01:00:00 EST -05:00", @twz.advance(:hours => 6).inspect - assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.advance(:minutes => 15).inspect - assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.advance(:seconds => 30).inspect + assert_equal "Mon, 31 Dec 2001 19:00:00 EST -05:00", @twz.advance(years: 2).inspect + assert_equal "Fri, 31 Mar 2000 19:00:00 EST -05:00", @twz.advance(months: 3).inspect + assert_equal "Tue, 04 Jan 2000 19:00:00 EST -05:00", @twz.advance(days: 4).inspect + assert_equal "Sat, 01 Jan 2000 01:00:00 EST -05:00", @twz.advance(hours: 6).inspect + assert_equal "Fri, 31 Dec 1999 19:15:00 EST -05:00", @twz.advance(minutes: 15).inspect + assert_equal "Fri, 31 Dec 1999 19:00:30 EST -05:00", @twz.advance(seconds: 30).inspect end def test_beginning_of_year @@ -675,6 +675,10 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Fri, 31 Dec 1999 19:00:01 EST -05:00", @twz.since(1).inspect end + def test_in + assert_equal "Fri, 31 Dec 1999 19:00:01 EST -05:00", @twz.in(1).inspect + end + def test_ago assert_equal "Fri, 31 Dec 1999 18:59:59 EST -05:00", @twz.ago(1).inspect end @@ -685,53 +689,61 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_advance_1_year_from_leap_day twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2004,2,29)) - assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(:years => 1).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(years: 1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.years_since(1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.since(1.year).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.in(1.year).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", (twz + 1.year).inspect end def test_advance_1_month_from_last_day_of_january twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2005,1,31)) - assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(:months => 1).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.advance(months: 1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.months_since(1).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.since(1.month).inspect + assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", twz.in(1.month).inspect assert_equal "Mon, 28 Feb 2005 00:00:00 EST -05:00", (twz + 1.month).inspect end def test_advance_1_month_from_last_day_of_january_during_leap_year twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2000,1,31)) - assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.advance(:months => 1).inspect + assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.advance(months: 1).inspect assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.months_since(1).inspect assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.since(1.month).inspect + assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", twz.in(1.month).inspect assert_equal "Tue, 29 Feb 2000 00:00:00 EST -05:00", (twz + 1.month).inspect end def test_advance_1_month_into_spring_dst_gap twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,3,2,2)) - assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(:months => 1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(months: 1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.months_since(1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.since(1.month).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.in(1.month).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1.month).inspect end def test_advance_1_second_into_spring_dst_gap twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,1,59,59)) - assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(:seconds => 1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.advance(seconds: 1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1.second).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.since(1).inspect assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.since(1.second).inspect - assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", (twz + 1.second).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.in(1).inspect + assert_equal "Sun, 02 Apr 2006 03:00:00 EDT -04:00", twz.in(1.second).inspect end def test_advance_1_day_across_spring_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,1,10,30)) # In 2006, spring DST transition occurred Apr 2 at 2AM; this day was only 23 hours long # When we advance 1 day, we want to end up at the same time on the next day - assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.advance(:days => 1).inspect + assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.advance(days: 1).inspect assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.since(1.days).inspect + assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", twz.in(1.days).inspect assert_equal "Sun, 02 Apr 2006 10:30:00 EDT -04:00", (twz + 1.days).inspect assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", twz.since(1.days + 1.second).inspect + assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", twz.in(1.days + 1.second).inspect assert_equal "Sun, 02 Apr 2006 10:30:01 EDT -04:00", (twz + 1.days + 1.second).inspect end @@ -739,7 +751,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,2,10,30)) # In 2006, spring DST transition occurred Apr 2 at 2AM; this day was only 23 hours long # When we advance back 1 day, we want to end up at the same time on the previous day - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:days => -1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(days: -1).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1.days).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1.days).inspect assert_equal "Sat, 01 Apr 2006 10:30:01 EST -05:00", twz.ago(1.days - 1.second).inspect @@ -753,13 +765,17 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", (twz + 86400.seconds).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(86400).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(86400.seconds).inspect - assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(:seconds => 86400).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(86400).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(86400.seconds).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(seconds: 86400).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", (twz + 1440.minutes).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(1440.minutes).inspect - assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(:minutes => 1440).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(1440.minutes).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(minutes: 1440).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", (twz + 24.hours).inspect assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.since(24.hours).inspect - assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(:hours => 24).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.in(24.hours).inspect + assert_equal "Sun, 02 Apr 2006 11:30:00 EDT -04:00", twz.advance(hours: 24).inspect end def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_spring_dst_transition_backwards @@ -770,23 +786,25 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 86400.seconds).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(86400).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(86400.seconds).inspect - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:seconds => -86400).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(seconds: -86400).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1440.minutes).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1440.minutes).inspect - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:minutes => -1440).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(minutes: -1440).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 24.hours).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(24.hours).inspect - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:hours => -24).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(hours: -24).inspect end def test_advance_1_day_across_fall_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30)) # In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long # When we advance 1 day, we want to end up at the same time on the next day - assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.advance(:days => 1).inspect + assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.advance(days: 1).inspect assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.since(1.days).inspect + assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", twz.in(1.days).inspect assert_equal "Sun, 29 Oct 2006 10:30:00 EST -05:00", (twz + 1.days).inspect assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", twz.since(1.days + 1.second).inspect + assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", twz.in(1.days + 1.second).inspect assert_equal "Sun, 29 Oct 2006 10:30:01 EST -05:00", (twz + 1.days + 1.second).inspect end @@ -794,7 +812,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,29,10,30)) # In 2006, fall DST transition occurred Oct 29 at 2AM; this day was 25 hours long # When we advance backwards 1 day, we want to end up at the same time on the previous day - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:days => -1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(days: -1).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1.days).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.days).inspect assert_equal "Sat, 28 Oct 2006 10:30:01 EDT -04:00", twz.ago(1.days - 1.second).inspect @@ -808,13 +826,17 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", (twz + 86400.seconds).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(86400).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(86400.seconds).inspect - assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(:seconds => 86400).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(86400).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(86400.seconds).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(seconds: 86400).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", (twz + 1440.minutes).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(1440.minutes).inspect - assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(:minutes => 1440).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(1440.minutes).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(minutes: 1440).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", (twz + 24.hours).inspect assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.since(24.hours).inspect - assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(:hours => 24).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.in(24.hours).inspect + assert_equal "Sun, 29 Oct 2006 09:30:00 EST -05:00", twz.advance(hours: 24).inspect end def test_advance_1_day_expressed_as_number_of_seconds_minutes_or_hours_across_fall_dst_transition_backwards @@ -825,26 +847,61 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 86400.seconds).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(86400).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(86400.seconds).inspect - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:seconds => -86400).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(seconds: -86400).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1440.minutes).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1440.minutes).inspect - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:minutes => -1440).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(minutes: -1440).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 24.hours).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(24.hours).inspect - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:hours => -24).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(hours: -24).inspect + end + + def test_advance_1_week_across_spring_dst_transition + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,1,10,30)) + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.advance(weeks: 1).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.weeks_since(1).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.since(1.week).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", twz.in(1.week).inspect + assert_equal "Sat, 08 Apr 2006 10:30:00 EDT -04:00", (twz + 1.week).inspect + end + + def test_advance_1_week_across_spring_dst_transition_backwards + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,8,10,30)) + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(weeks: -1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.weeks_ago(1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1.week).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1.week).inspect + end + + def test_advance_1_week_across_fall_dst_transition + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30)) + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.advance(weeks: 1).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.weeks_since(1).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.since(1.week).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", twz.in(1.week).inspect + assert_equal "Sat, 04 Nov 2006 10:30:00 EST -05:00", (twz + 1.week).inspect + end + + def test_advance_1_week_across_fall_dst_transition_backwards + twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,11,4,10,30)) + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(weeks: -1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.weeks_ago(1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1.week).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.week).inspect end def test_advance_1_month_across_spring_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,4,1,10,30)) - assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.advance(:months => 1).inspect + assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.advance(months: 1).inspect assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.months_since(1).inspect assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.since(1.month).inspect + assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", twz.in(1.month).inspect assert_equal "Mon, 01 May 2006 10:30:00 EDT -04:00", (twz + 1.month).inspect end def test_advance_1_month_across_spring_dst_transition_backwards twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,5,1,10,30)) - assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(:months => -1).inspect + assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.advance(months: -1).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.months_ago(1).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", twz.ago(1.month).inspect assert_equal "Sat, 01 Apr 2006 10:30:00 EST -05:00", (twz - 1.month).inspect @@ -852,15 +909,16 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_advance_1_month_across_fall_dst_transition twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,10,28,10,30)) - assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.advance(:months => 1).inspect + assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.advance(months: 1).inspect assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.months_since(1).inspect assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.since(1.month).inspect + assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", twz.in(1.month).inspect assert_equal "Tue, 28 Nov 2006 10:30:00 EST -05:00", (twz + 1.month).inspect end def test_advance_1_month_across_fall_dst_transition_backwards twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2006,11,28,10,30)) - assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(:months => -1).inspect + assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.advance(months: -1).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.months_ago(1).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", twz.ago(1.month).inspect assert_equal "Sat, 28 Oct 2006 10:30:00 EDT -04:00", (twz - 1.month).inspect @@ -868,20 +926,24 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_advance_1_year twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2008,2,15,10,30)) - assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.advance(:years => 1).inspect + assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.advance(years: 1).inspect assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.years_since(1).inspect + assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.since(1.year).inspect + assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", twz.in(1.year).inspect assert_equal "Sun, 15 Feb 2009 10:30:00 EST -05:00", (twz + 1.year).inspect - assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", twz.advance(:years => -1).inspect + assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", twz.advance(years: -1).inspect assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", twz.years_ago(1).inspect assert_equal "Thu, 15 Feb 2007 10:30:00 EST -05:00", (twz - 1.year).inspect end def test_advance_1_year_during_dst twz = ActiveSupport::TimeWithZone.new(nil, @time_zone, Time.utc(2008,7,15,10,30)) - assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.advance(:years => 1).inspect + assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.advance(years: 1).inspect assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.years_since(1).inspect + assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.since(1.year).inspect + assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", twz.in(1.year).inspect assert_equal "Wed, 15 Jul 2009 10:30:00 EDT -04:00", (twz + 1.year).inspect - assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.advance(:years => -1).inspect + assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.advance(years: -1).inspect assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", twz.years_ago(1).inspect assert_equal "Sun, 15 Jul 2007 10:30:00 EDT -04:00", (twz - 1.year).inspect end @@ -909,13 +971,13 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase end def test_in_time_zone - Time.use_zone 'Alaska' do - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @t.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @dt.in_time_zone.inspect + Time.use_zone "Alaska" do + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @t.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @dt.in_time_zone.inspect end - Time.use_zone 'Hawaii' do - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @t.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @dt.in_time_zone.inspect + Time.use_zone "Hawaii" do + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @t.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @dt.in_time_zone.inspect end Time.use_zone nil do assert_equal @t, @t.in_time_zone @@ -925,20 +987,20 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase def test_nil_time_zone Time.use_zone nil do - assert !@t.in_time_zone.respond_to?(:period), 'no period method' - assert !@dt.in_time_zone.respond_to?(:period), 'no period method' + assert !@t.in_time_zone.respond_to?(:period), "no period method" + assert !@dt.in_time_zone.respond_to?(:period), "no period method" end end def test_in_time_zone_with_argument - Time.use_zone 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone) - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @t.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @dt.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @t.in_time_zone('Hawaii').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @dt.in_time_zone('Hawaii').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @t.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @dt.in_time_zone('UTC').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @t.in_time_zone(-9.hours).inspect + Time.use_zone "Eastern Time (US & Canada)" do # Time.zone will not affect #in_time_zone(zone) + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @t.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @dt.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @t.in_time_zone("Hawaii").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @dt.in_time_zone("Hawaii").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @t.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @dt.in_time_zone("UTC").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @t.in_time_zone(-9.hours).inspect end end @@ -952,119 +1014,119 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase end def test_in_time_zone_with_time_local_instance - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do time = Time.local(1999, 12, 31, 19) # == Time.utc(2000) - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', time.in_time_zone('Alaska').inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", time.in_time_zone("Alaska").inspect end end def test_localtime - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal @dt.in_time_zone.localtime, @dt.in_time_zone.utc.to_time.getlocal end def test_use_zone - Time.zone = 'Alaska' - Time.use_zone 'Hawaii' do - assert_equal ActiveSupport::TimeZone['Hawaii'], Time.zone + Time.zone = "Alaska" + Time.use_zone "Hawaii" do + assert_equal ActiveSupport::TimeZone["Hawaii"], Time.zone end - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone end def test_use_zone_with_exception_raised - Time.zone = 'Alaska' + Time.zone = "Alaska" assert_raise RuntimeError do - Time.use_zone('Hawaii') { raise RuntimeError } + Time.use_zone("Hawaii") { raise RuntimeError } end - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone end def test_use_zone_raises_on_invalid_timezone - Time.zone = 'Alaska' + Time.zone = "Alaska" assert_raise ArgumentError do - Time.use_zone("No such timezone exists") { } + Time.use_zone("No such timezone exists") {} end - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone end def test_time_zone_getter_and_setter - Time.zone = ActiveSupport::TimeZone['Alaska'] - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone - Time.zone = 'Alaska' - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + Time.zone = ActiveSupport::TimeZone["Alaska"] + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone + Time.zone = "Alaska" + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone Time.zone = -9.hours - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone Time.zone = nil assert_equal nil, Time.zone end def test_time_zone_getter_and_setter_with_zone_default_set old_zone_default = Time.zone_default - Time.zone_default = ActiveSupport::TimeZone['Alaska'] - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone - Time.zone = ActiveSupport::TimeZone['Hawaii'] - assert_equal ActiveSupport::TimeZone['Hawaii'], Time.zone + Time.zone_default = ActiveSupport::TimeZone["Alaska"] + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone + Time.zone = ActiveSupport::TimeZone["Hawaii"] + assert_equal ActiveSupport::TimeZone["Hawaii"], Time.zone Time.zone = nil - assert_equal ActiveSupport::TimeZone['Alaska'], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], Time.zone ensure Time.zone_default = old_zone_default end def test_time_zone_setter_is_thread_safe - Time.use_zone 'Paris' do - t1 = Thread.new { Time.zone = 'Alaska' }.join - t2 = Thread.new { Time.zone = 'Hawaii' }.join + Time.use_zone "Paris" do + t1 = Thread.new { Time.zone = "Alaska" }.join + t2 = Thread.new { Time.zone = "Hawaii" }.join assert t1.stop?, "Thread 1 did not finish running" assert t2.stop?, "Thread 2 did not finish running" - assert_equal ActiveSupport::TimeZone['Paris'], Time.zone - assert_equal ActiveSupport::TimeZone['Alaska'], t1[:time_zone] - assert_equal ActiveSupport::TimeZone['Hawaii'], t2[:time_zone] + assert_equal ActiveSupport::TimeZone["Paris"], Time.zone + assert_equal ActiveSupport::TimeZone["Alaska"], t1[:time_zone] + assert_equal ActiveSupport::TimeZone["Hawaii"], t2[:time_zone] end end def test_time_zone_setter_with_tzinfo_timezone_object_wraps_in_rails_time_zone - tzinfo = TZInfo::Timezone.get('America/New_York') + tzinfo = TZInfo::Timezone.get("America/New_York") Time.zone = tzinfo assert_kind_of ActiveSupport::TimeZone, Time.zone assert_equal tzinfo, Time.zone.tzinfo - assert_equal 'America/New_York', Time.zone.name + assert_equal "America/New_York", Time.zone.name assert_equal(-18_000, Time.zone.utc_offset) end def test_time_zone_setter_with_tzinfo_timezone_identifier_does_lookup_and_wraps_in_rails_time_zone - Time.zone = 'America/New_York' + Time.zone = "America/New_York" assert_kind_of ActiveSupport::TimeZone, Time.zone - assert_equal 'America/New_York', Time.zone.tzinfo.name - assert_equal 'America/New_York', Time.zone.name + assert_equal "America/New_York", Time.zone.tzinfo.name + assert_equal "America/New_York", Time.zone.name assert_equal(-18_000, Time.zone.utc_offset) end def test_time_zone_setter_with_invalid_zone - assert_raise(ArgumentError){ Time.zone = "No such timezone exists" } - assert_raise(ArgumentError){ Time.zone = -15.hours } - assert_raise(ArgumentError){ Time.zone = Object.new } + assert_raise(ArgumentError) { Time.zone = "No such timezone exists" } + assert_raise(ArgumentError) { Time.zone = -15.hours } + assert_raise(ArgumentError) { Time.zone = Object.new } end def test_find_zone_without_bang_returns_nil_if_time_zone_can_not_be_found - assert_nil Time.find_zone('No such timezone exists') + assert_nil Time.find_zone("No such timezone exists") assert_nil Time.find_zone(-15.hours) assert_nil Time.find_zone(Object.new) end def test_find_zone_with_bang_raises_if_time_zone_can_not_be_found - assert_raise(ArgumentError) { Time.find_zone!('No such timezone exists') } + assert_raise(ArgumentError) { Time.find_zone!("No such timezone exists") } assert_raise(ArgumentError) { Time.find_zone!(-15.hours) } assert_raise(ArgumentError) { Time.find_zone!(Object.new) } end def test_time_zone_setter_with_find_zone_without_bang - assert_nil Time.zone = Time.find_zone('No such timezone exists') + assert_nil Time.zone = Time.find_zone("No such timezone exists") assert_nil Time.zone = Time.find_zone(-15.hours) assert_nil Time.zone = Time.find_zone(Object.new) end def test_current_returns_time_now_when_zone_not_set - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do assert_equal false, Time.current.is_a?(ActiveSupport::TimeWithZone) assert_equal Time.local(2000), Time.current @@ -1073,22 +1135,22 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < ActiveSupport::TestCase end def test_current_returns_time_zone_now_when_zone_set - Time.zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - with_env_tz 'US/Eastern' do + Time.zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + with_env_tz "US/Eastern" do Time.stub(:now, Time.local(2000)) do assert_equal true, Time.current.is_a?(ActiveSupport::TimeWithZone) - assert_equal 'Eastern Time (US & Canada)', Time.current.time_zone.name + assert_equal "Eastern Time (US & Canada)", Time.current.time_zone.name assert_equal Time.utc(2000), Time.current.time end end end def test_time_in_time_zone_doesnt_affect_receiver - with_env_tz 'Europe/London' do + with_env_tz "Europe/London" do time = Time.local(2000, 7, 1) - time_with_zone = time.in_time_zone('Eastern Time (US & Canada)') + time_with_zone = time.in_time_zone("Eastern Time (US & Canada)") assert_equal Time.utc(2000, 6, 30, 23, 0, 0), time_with_zone - assert_not time.utc?, 'time expected to be local, but is UTC' + assert_not time.utc?, "time expected to be local, but is UTC" end end end @@ -1101,11 +1163,11 @@ class TimeWithZoneMethodsForDate < ActiveSupport::TestCase end def test_in_time_zone - with_tz_default 'Alaska' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone.inspect + with_tz_default "Alaska" do + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @d.in_time_zone.inspect end - with_tz_default 'Hawaii' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @d.in_time_zone.inspect + with_tz_default "Hawaii" do + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @d.in_time_zone.inspect end with_tz_default nil do assert_equal @d.to_time, @d.in_time_zone @@ -1114,16 +1176,16 @@ class TimeWithZoneMethodsForDate < ActiveSupport::TestCase def test_nil_time_zone with_tz_default nil do - assert !@d.in_time_zone.respond_to?(:period), 'no period method' + assert !@d.in_time_zone.respond_to?(:period), "no period method" end end def test_in_time_zone_with_argument - with_tz_default 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone) - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone('Alaska').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @d.in_time_zone('Hawaii').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @d.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @d.in_time_zone(-9.hours).inspect + with_tz_default "Eastern Time (US & Canada)" do # Time.zone will not affect #in_time_zone(zone) + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @d.in_time_zone("Alaska").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @d.in_time_zone("Hawaii").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @d.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @d.in_time_zone(-9.hours).inspect end end @@ -1144,15 +1206,15 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase end def test_in_time_zone - with_tz_default 'Alaska' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone.inspect + with_tz_default "Alaska" do + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @s.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @u.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @z.in_time_zone.inspect end - with_tz_default 'Hawaii' do - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @s.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @u.in_time_zone.inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @z.in_time_zone.inspect + with_tz_default "Hawaii" do + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @s.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @u.in_time_zone.inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @z.in_time_zone.inspect end with_tz_default nil do assert_equal @s.to_time, @s.in_time_zone @@ -1163,26 +1225,26 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase def test_nil_time_zone with_tz_default nil do - assert !@s.in_time_zone.respond_to?(:period), 'no period method' - assert !@u.in_time_zone.respond_to?(:period), 'no period method' - assert !@z.in_time_zone.respond_to?(:period), 'no period method' + assert !@s.in_time_zone.respond_to?(:period), "no period method" + assert !@u.in_time_zone.respond_to?(:period), "no period method" + assert !@z.in_time_zone.respond_to?(:period), "no period method" end end def test_in_time_zone_with_argument - with_tz_default 'Eastern Time (US & Canada)' do # Time.zone will not affect #in_time_zone(zone) - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone('Alaska').inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone('Alaska').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 HST -10:00', @s.in_time_zone('Hawaii').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @u.in_time_zone('Hawaii').inspect - assert_equal 'Fri, 31 Dec 1999 14:00:00 HST -10:00', @z.in_time_zone('Hawaii').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @s.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @u.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 UTC +00:00', @z.in_time_zone('UTC').inspect - assert_equal 'Sat, 01 Jan 2000 00:00:00 AKST -09:00', @s.in_time_zone(-9.hours).inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @u.in_time_zone(-9.hours).inspect - assert_equal 'Fri, 31 Dec 1999 15:00:00 AKST -09:00', @z.in_time_zone(-9.hours).inspect + with_tz_default "Eastern Time (US & Canada)" do # Time.zone will not affect #in_time_zone(zone) + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @s.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @u.in_time_zone("Alaska").inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @z.in_time_zone("Alaska").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 HST -10:00", @s.in_time_zone("Hawaii").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @u.in_time_zone("Hawaii").inspect + assert_equal "Fri, 31 Dec 1999 14:00:00 HST -10:00", @z.in_time_zone("Hawaii").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @s.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @u.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 UTC +00:00", @z.in_time_zone("UTC").inspect + assert_equal "Sat, 01 Jan 2000 00:00:00 AKST -09:00", @s.in_time_zone(-9.hours).inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @u.in_time_zone(-9.hours).inspect + assert_equal "Fri, 31 Dec 1999 15:00:00 AKST -09:00", @z.in_time_zone(-9.hours).inspect end end diff --git a/activesupport/test/core_ext/uri_ext_test.rb b/activesupport/test/core_ext/uri_ext_test.rb index 1694fe7e72..0f13ca9c0e 100644 --- a/activesupport/test/core_ext/uri_ext_test.rb +++ b/activesupport/test/core_ext/uri_ext_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'uri' -require 'active_support/core_ext/uri' +require "abstract_unit" +require "uri" +require "active_support/core_ext/uri" class URIExtTest < ActiveSupport::TestCase def test_uri_decode_handle_multibyte diff --git a/activesupport/test/dependencies/conflict.rb b/activesupport/test/dependencies/conflict.rb index e888b7b54c..7eff49bbfa 100644 --- a/activesupport/test/dependencies/conflict.rb +++ b/activesupport/test/dependencies/conflict.rb @@ -1 +1 @@ -Conflict = 1
\ No newline at end of file +Conflict = 1 diff --git a/activesupport/test/dependencies/cross_site_depender.rb b/activesupport/test/dependencies/cross_site_depender.rb index a31015fc5e..fbc3b64f56 100644 --- a/activesupport/test/dependencies/cross_site_depender.rb +++ b/activesupport/test/dependencies/cross_site_depender.rb @@ -1,3 +1,3 @@ class CrossSiteDepender CrossSiteDependency -end
\ No newline at end of file +end diff --git a/activesupport/test/dependencies/mutual_one.rb b/activesupport/test/dependencies/mutual_one.rb index 576eb31711..05f08f82d3 100644 --- a/activesupport/test/dependencies/mutual_one.rb +++ b/activesupport/test/dependencies/mutual_one.rb @@ -1,4 +1,4 @@ $mutual_dependencies_count += 1 -require_dependency 'mutual_two' -require_dependency 'mutual_two.rb' -require_dependency 'mutual_two' +require_dependency "mutual_two" +require_dependency "mutual_two.rb" +require_dependency "mutual_two" diff --git a/activesupport/test/dependencies/mutual_two.rb b/activesupport/test/dependencies/mutual_two.rb index fdbc2dcd84..1d87d334af 100644 --- a/activesupport/test/dependencies/mutual_two.rb +++ b/activesupport/test/dependencies/mutual_two.rb @@ -1,4 +1,4 @@ $mutual_dependencies_count += 1 -require_dependency 'mutual_one.rb' -require_dependency 'mutual_one' -require_dependency 'mutual_one.rb' +require_dependency "mutual_one.rb" +require_dependency "mutual_one" +require_dependency "mutual_one.rb" diff --git a/activesupport/test/dependencies/raises_exception.rb b/activesupport/test/dependencies/raises_exception.rb index dd745ac20e..0a56680fe3 100644 --- a/activesupport/test/dependencies/raises_exception.rb +++ b/activesupport/test/dependencies/raises_exception.rb @@ -1,3 +1,3 @@ $raises_exception_load_count += 1 -raise Exception, 'Loading me failed, so do not add to loaded or history.' +raise Exception, "Loading me failed, so do not add to loaded or history." $raises_exception_load_count += 1 diff --git a/activesupport/test/dependencies/raises_exception_without_blame_file.rb b/activesupport/test/dependencies/raises_exception_without_blame_file.rb index 4b2da6ff30..7c3856b1e6 100644 --- a/activesupport/test/dependencies/raises_exception_without_blame_file.rb +++ b/activesupport/test/dependencies/raises_exception_without_blame_file.rb @@ -1,4 +1,4 @@ -exception = Exception.new('I am not blamable!') +exception = Exception.new("I am not blamable!") class << exception undef_method(:blame_file!) end diff --git a/activesupport/test/dependencies/requires_nonexistent0.rb b/activesupport/test/dependencies/requires_nonexistent0.rb index 7e24b3916c..7f8a0d8419 100644 --- a/activesupport/test/dependencies/requires_nonexistent0.rb +++ b/activesupport/test/dependencies/requires_nonexistent0.rb @@ -1 +1 @@ -require 'RMagickDontExistDude' +require "RMagickDontExistDude" diff --git a/activesupport/test/dependencies/requires_nonexistent1.rb b/activesupport/test/dependencies/requires_nonexistent1.rb index 41e6668164..0055177d67 100644 --- a/activesupport/test/dependencies/requires_nonexistent1.rb +++ b/activesupport/test/dependencies/requires_nonexistent1.rb @@ -1 +1 @@ -require_dependency 'requires_nonexistent0' +require_dependency "requires_nonexistent0" diff --git a/activesupport/test/dependencies/service_one.rb b/activesupport/test/dependencies/service_one.rb index f43bfea235..afc3042269 100644 --- a/activesupport/test/dependencies/service_one.rb +++ b/activesupport/test/dependencies/service_one.rb @@ -2,4 +2,4 @@ $loaded_service_one ||= 0 $loaded_service_one += 1 class ServiceOne -end
\ No newline at end of file +end diff --git a/activesupport/test/dependencies/service_two.rb b/activesupport/test/dependencies/service_two.rb index 5205a78bb8..aabfc3c553 100644 --- a/activesupport/test/dependencies/service_two.rb +++ b/activesupport/test/dependencies/service_two.rb @@ -1,2 +1,2 @@ class ServiceTwo -end
\ No newline at end of file +end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 04e7b24d30..54068f5a08 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'pp' -require 'active_support/dependencies' -require 'dependencies_test_helpers' +require "abstract_unit" +require "pp" +require "active_support/dependencies" +require "dependencies_test_helpers" module ModuleWithMissing mattr_accessor :missing_count @@ -29,18 +29,18 @@ class DependenciesTest < ActiveSupport::TestCase def test_depend_on_path expected = assert_raises(LoadError) do - Kernel.require 'omgwtfbbq' + Kernel.require "omgwtfbbq" end e = assert_raises(LoadError) do - ActiveSupport::Dependencies.depend_on 'omgwtfbbq' + ActiveSupport::Dependencies.depend_on "omgwtfbbq" end assert_equal expected.path, e.path end def test_require_dependency_accepts_an_object_which_implements_to_path o = Object.new - def o.to_path; 'dependencies/service_one'; end + def o.to_path; "dependencies/service_one"; end assert_nothing_raised { require_dependency o } @@ -51,8 +51,8 @@ class DependenciesTest < ActiveSupport::TestCase def test_tracking_loaded_files with_loading do - require_dependency 'dependencies/service_one' - require_dependency 'dependencies/service_two' + require_dependency "dependencies/service_one" + require_dependency "dependencies/service_two" assert_equal 2, ActiveSupport::Dependencies.loaded.size end ensure @@ -61,8 +61,8 @@ class DependenciesTest < ActiveSupport::TestCase def test_tracking_identical_loaded_files with_loading do - require_dependency 'dependencies/service_one' - require_dependency 'dependencies/service_one' + require_dependency "dependencies/service_one" + require_dependency "dependencies/service_one" assert_equal 1, ActiveSupport::Dependencies.loaded.size end ensure @@ -75,16 +75,16 @@ class DependenciesTest < ActiveSupport::TestCase def test_dependency_which_raises_exception_isnt_added_to_loaded_set with_loading do - filename = 'dependencies/raises_exception' + filename = "dependencies/raises_exception" expanded = File.expand_path(filename) $raises_exception_load_count = 0 5.times do |count| - e = assert_raise Exception, 'should have loaded dependencies/raises_exception which raises an exception' do + e = assert_raise Exception, "should have loaded dependencies/raises_exception which raises an exception" do require_dependency filename end - assert_equal 'Loading me failed, so do not add to loaded or history.', e.message + assert_equal "Loading me failed, so do not add to loaded or history.", e.message assert_equal count + 1, $raises_exception_load_count assert_not ActiveSupport::Dependencies.loaded.include?(expanded) @@ -95,13 +95,13 @@ class DependenciesTest < ActiveSupport::TestCase def test_dependency_which_raises_doesnt_blindly_call_blame_file! with_loading do - filename = 'dependencies/raises_exception_without_blame_file' + filename = "dependencies/raises_exception_without_blame_file" assert_raises(Exception) { require_dependency filename } end end def test_warnings_should_be_enabled_on_first_load - with_loading 'dependencies' do + with_loading "dependencies" do old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true filename = "check_warnings" expanded = File.expand_path("#{File.dirname(__FILE__)}/dependencies/#{filename}") @@ -112,41 +112,41 @@ class DependenciesTest < ActiveSupport::TestCase silence_warnings { require_dependency filename } assert_equal 1, $check_warnings_load_count - assert_equal true, $checked_verbose, 'On first load warnings should be enabled.' + assert_equal true, $checked_verbose, "On first load warnings should be enabled." - assert ActiveSupport::Dependencies.loaded.include?(expanded) + assert_includes ActiveSupport::Dependencies.loaded, expanded ActiveSupport::Dependencies.clear assert_not ActiveSupport::Dependencies.loaded.include?(expanded) - assert ActiveSupport::Dependencies.history.include?(expanded) + assert_includes ActiveSupport::Dependencies.history, expanded silence_warnings { require_dependency filename } assert_equal 2, $check_warnings_load_count - assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.' + assert_equal nil, $checked_verbose, "After first load warnings should be left alone." - assert ActiveSupport::Dependencies.loaded.include?(expanded) + assert_includes ActiveSupport::Dependencies.loaded, expanded ActiveSupport::Dependencies.clear assert_not ActiveSupport::Dependencies.loaded.include?(expanded) - assert ActiveSupport::Dependencies.history.include?(expanded) + assert_includes ActiveSupport::Dependencies.history, expanded enable_warnings { require_dependency filename } assert_equal 3, $check_warnings_load_count - assert_equal true, $checked_verbose, 'After first load warnings should be left alone.' + assert_equal true, $checked_verbose, "After first load warnings should be left alone." - assert ActiveSupport::Dependencies.loaded.include?(expanded) + assert_includes ActiveSupport::Dependencies.loaded, expanded ActiveSupport::Dependencies.warnings_on_first_load = old_warnings end end def test_mutual_dependencies_dont_infinite_loop - with_loading 'dependencies' do + with_loading "dependencies" do $mutual_dependencies_count = 0 - assert_nothing_raised { require_dependency 'mutual_one' } + assert_nothing_raised { require_dependency "mutual_one" } assert_equal 2, $mutual_dependencies_count ActiveSupport::Dependencies.clear $mutual_dependencies_count = 0 - assert_nothing_raised { require_dependency 'mutual_two' } + assert_nothing_raised { require_dependency "mutual_two" } assert_equal 2, $mutual_dependencies_count end end @@ -167,7 +167,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_require_dependency_does_not_assume_any_particular_constant_is_defined with_autoloading_fixtures do - require_dependency 'typo' + require_dependency "typo" assert_equal 1, TypO end end @@ -175,7 +175,7 @@ class DependenciesTest < ActiveSupport::TestCase # Regression, see https://github.com/rails/rails/issues/16468. def test_require_dependency_interaction_with_autoloading with_autoloading_fixtures do - require_dependency 'typo' + require_dependency "typo" assert_equal 1, TypO e = assert_raise(LoadError) { Typo } @@ -253,7 +253,7 @@ class DependenciesTest < ActiveSupport::TestCase with_autoloading_fixtures do assert_kind_of Class, ClassFolder::ClassFolderSubclass assert_kind_of Class, ClassFolder - assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder + assert_equal "indeed", ClassFolder::ClassFolderSubclass::ConstantInClassFolder end ensure remove_constants(:ClassFolder) @@ -271,7 +271,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_raising_discards_autoloaded_constants with_autoloading_fixtures do - assert_raises(Exception, 'arbitray exception message') { RaisesArbitraryException } + assert_raises(Exception, "arbitray exception message") { RaisesArbitraryException } assert_not defined?(A) assert_not defined?(RaisesArbitraryException) end @@ -336,7 +336,7 @@ class DependenciesTest < ActiveSupport::TestCase $:.push(path) with_loading do - assert_equal true, require('loaded_constant') + assert_equal true, require("loaded_constant") end ensure remove_constants(:LoadedConstant) @@ -350,7 +350,7 @@ class DependenciesTest < ActiveSupport::TestCase with_loading do Object.module_eval "module LoadedConstant; end" - assert_equal true, require('loaded_constant') + assert_equal true, require("loaded_constant") end ensure remove_constants(:LoadedConstant) @@ -363,8 +363,8 @@ class DependenciesTest < ActiveSupport::TestCase $:.push(path) with_loading do - require 'loaded_constant' - assert_equal false, require('loaded_constant') + require "loaded_constant" + assert_equal false, require("loaded_constant") end ensure remove_constants(:LoadedConstant) @@ -373,7 +373,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_require_raises_load_error_when_file_not_found with_loading do - assert_raise(LoadError) { require 'this_file_dont_exist_dude' } + assert_raise(LoadError) { require "this_file_dont_exist_dude" } end end @@ -383,8 +383,8 @@ class DependenciesTest < ActiveSupport::TestCase $:.push(path) with_loading do - assert_equal true, load('loaded_constant.rb') - assert_equal true, load('loaded_constant.rb') + assert_equal true, load("loaded_constant.rb") + assert_equal true, load("loaded_constant.rb") end ensure remove_constants(:LoadedConstant) @@ -393,7 +393,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_load_raises_load_error_when_file_not_found with_loading do - assert_raise(LoadError) { load 'this_file_dont_exist_dude.rb' } + assert_raise(LoadError) { load "this_file_dont_exist_dude.rb" } end end @@ -429,38 +429,38 @@ class DependenciesTest < ActiveSupport::TestCase end def test_loadable_constants_for_path_should_handle_empty_autoloads - assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path('hello') + assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path("hello") end def test_loadable_constants_for_path_should_handle_relative_paths - fake_root = 'dependencies' - relative_root = File.dirname(__FILE__) + '/dependencies' - ['', '/'].each do |suffix| + fake_root = "dependencies" + relative_root = File.dirname(__FILE__) + "/dependencies" + ["", "/"].each do |suffix| with_loading fake_root + suffix do - assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + '/a/b') + assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(relative_root + "/a/b") end end end def test_loadable_constants_for_path_should_provide_all_results - fake_root = '/usr/apps/backpack' - with_loading fake_root, fake_root + '/lib' do + fake_root = "/usr/apps/backpack" + with_loading fake_root, fake_root + "/lib" do root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/lib/a/b') + assert_equal ["Lib::A::B", "A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + "/lib/a/b") end end def test_loadable_constants_for_path_should_uniq_results - fake_root = '/usr/apps/backpack/lib' - with_loading fake_root, fake_root + '/' do + fake_root = "/usr/apps/backpack/lib" + with_loading fake_root, fake_root + "/" do root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + '/a/b') + assert_equal ["A::B"], ActiveSupport::Dependencies.loadable_constants_for_path(root + "/a/b") end end def test_loadable_constants_with_load_path_without_trailing_slash - path = File.dirname(__FILE__) + '/autoloading_fixtures/class_folder/inline_class.rb' - with_loading 'autoloading_fixtures/class/' do + path = File.dirname(__FILE__) + "/autoloading_fixtures/class_folder/inline_class.rb" + with_loading "autoloading_fixtures/class/" do assert_equal [], ActiveSupport::Dependencies.loadable_constants_for_path(path) end end @@ -524,29 +524,29 @@ class DependenciesTest < ActiveSupport::TestCase end def test_file_search - with_loading 'dependencies' do + with_loading "dependencies" do root = ActiveSupport::Dependencies.autoload_paths.first - assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three') - assert_equal nil, ActiveSupport::Dependencies.search_for_file('service_three.rb') - assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one') - assert_equal root + '/service_one.rb', ActiveSupport::Dependencies.search_for_file('service_one.rb') + assert_equal nil, ActiveSupport::Dependencies.search_for_file("service_three") + assert_equal nil, ActiveSupport::Dependencies.search_for_file("service_three.rb") + assert_equal root + "/service_one.rb", ActiveSupport::Dependencies.search_for_file("service_one") + assert_equal root + "/service_one.rb", ActiveSupport::Dependencies.search_for_file("service_one.rb") end end def test_file_search_uses_first_in_load_path - with_loading 'dependencies', 'autoloading_fixtures' do + with_loading "dependencies", "autoloading_fixtures" do deps, autoload = ActiveSupport::Dependencies.autoload_paths assert_match %r/dependencies/, deps assert_match %r/autoloading_fixtures/, autoload - assert_equal deps + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict') + assert_equal deps + "/conflict.rb", ActiveSupport::Dependencies.search_for_file("conflict") end - with_loading 'autoloading_fixtures', 'dependencies' do + with_loading "autoloading_fixtures", "dependencies" do autoload, deps = ActiveSupport::Dependencies.autoload_paths assert_match %r/dependencies/, deps assert_match %r/autoloading_fixtures/, autoload - assert_equal autoload + '/conflict.rb', ActiveSupport::Dependencies.search_for_file('conflict') + assert_equal autoload + "/conflict.rb", ActiveSupport::Dependencies.search_for_file("conflict") end end @@ -584,11 +584,11 @@ class DependenciesTest < ActiveSupport::TestCase def test_const_missing_in_anonymous_modules_raises_if_the_constant_belongs_to_Object with_autoloading_fixtures do - require_dependency 'em' + require_dependency "em" mod = Module.new e = assert_raise(NameError) { mod::EM } - assert_equal 'EM cannot be autoloaded from an anonymous class or module', e.message + assert_equal "EM cannot be autoloaded from an anonymous class or module", e.message assert_equal :EM, e.name end ensure @@ -596,7 +596,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_removal_from_tree_should_be_detected - with_loading 'dependencies' do + with_loading "dependencies" do c = ServiceOne ActiveSupport::Dependencies.clear assert_not defined?(ServiceOne) @@ -610,7 +610,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_references_should_work - with_loading 'dependencies' do + with_loading "dependencies" do c = ActiveSupport::Dependencies.reference("ServiceOne") service_one_first = ServiceOne assert_equal service_one_first, c.get("ServiceOne") @@ -625,7 +625,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_constantize_shortcut_for_cached_constant_lookups - with_loading 'dependencies' do + with_loading "dependencies" do assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne") end ensure @@ -633,7 +633,7 @@ class DependenciesTest < ActiveSupport::TestCase end def test_nested_load_error_isnt_rescued - with_loading 'dependencies' do + with_loading "dependencies" do assert_raise(LoadError) do RequiresNonexistent1 end @@ -659,7 +659,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_autoload_once_pathnames_do_not_add_to_autoloaded_constants with_autoloading_fixtures do - pathnames = ActiveSupport::Dependencies.autoload_paths.collect{|p| Pathname.new(p)} + pathnames = ActiveSupport::Dependencies.autoload_paths.collect { |p| Pathname.new(p) } ActiveSupport::Dependencies.autoload_paths = pathnames ActiveSupport::Dependencies.autoload_once_paths = pathnames @@ -677,7 +677,7 @@ class DependenciesTest < ActiveSupport::TestCase def test_application_should_special_case_application_controller with_autoloading_fixtures do - require_dependency 'application' + require_dependency "application" assert_equal 10, ApplicationController assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController) end @@ -687,14 +687,14 @@ class DependenciesTest < ActiveSupport::TestCase def test_preexisting_constants_are_not_marked_as_autoloaded with_autoloading_fixtures do - require_dependency 'em' + require_dependency "em" assert ActiveSupport::Dependencies.autoloaded?(:EM) ActiveSupport::Dependencies.clear end Object.const_set :EM, Class.new with_autoloading_fixtures do - require_dependency 'em' + require_dependency "em" assert ! ActiveSupport::Dependencies.autoloaded?(:EM), "EM shouldn't be marked autoloaded!" ActiveSupport::Dependencies.clear end @@ -756,15 +756,15 @@ class DependenciesTest < ActiveSupport::TestCase end def test_new_contants_in_without_constants - assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { }) - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) {}) + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } end def test_new_constants_in_with_a_single_constant assert_equal ["Hello"], ActiveSupport::Dependencies.new_constants_in(Object) { Object.const_set :Hello, 10 }.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:Hello) end @@ -781,7 +781,7 @@ class DependenciesTest < ActiveSupport::TestCase end assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s) - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:OuterBefore, :Inner, :OuterAfter) end @@ -800,7 +800,7 @@ class DependenciesTest < ActiveSupport::TestCase M.const_set :OuterAfter, 30 end assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:M) end @@ -818,7 +818,7 @@ class DependenciesTest < ActiveSupport::TestCase M.const_set :OuterAfter, 30 end assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort - assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? } + assert ActiveSupport::Dependencies.constant_watch_stack.all? { |k,v| v.empty? } ensure remove_constants(:M) end @@ -841,7 +841,7 @@ class DependenciesTest < ActiveSupport::TestCase assert_not defined?(MultipleConstantFile) assert_not defined?(SiblingConstant) - require_dependency 'multiple_constant_file' + require_dependency "multiple_constant_file" assert defined?(MultipleConstantFile) assert defined?(SiblingConstant) assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile) @@ -881,7 +881,7 @@ class DependenciesTest < ActiveSupport::TestCase assert_not defined?(ClassFolder::NestedClass) assert_not defined?(ClassFolder::SiblingClass) - require_dependency 'class_folder/nested_class' + require_dependency "class_folder/nested_class" assert defined?(ClassFolder::NestedClass) assert defined?(ClassFolder::SiblingClass) @@ -959,7 +959,7 @@ class DependenciesTest < ActiveSupport::TestCase e = assert_raise NameError do ::RaisesNameError::FooBarBaz.object_id end - assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message + assert_equal "uninitialized constant RaisesNameError::FooBarBaz", e.message assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!" end @@ -974,8 +974,8 @@ class DependenciesTest < ActiveSupport::TestCase end def test_remove_constant_handles_double_colon_at_start - Object.const_set 'DeleteMe', Module.new - DeleteMe.const_set 'OrMe', Module.new + Object.const_set "DeleteMe", Module.new + DeleteMe.const_set "OrMe", Module.new ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe" assert_not defined?(DeleteMe::OrMe) assert defined?(DeleteMe) @@ -986,9 +986,9 @@ class DependenciesTest < ActiveSupport::TestCase end def test_remove_constant_does_not_trigger_loading_autoloads - constant = 'ShouldNotBeAutoloaded' + constant = "ShouldNotBeAutoloaded" Object.class_eval do - autoload constant, File.expand_path('../autoloading_fixtures/should_not_be_required', __FILE__) + autoload constant, File.expand_path("../autoloading_fixtures/should_not_be_required", __FILE__) end assert_nil ActiveSupport::Dependencies.remove_constant(constant), "Kernel#autoload has been triggered by remove_constant" @@ -1001,8 +1001,8 @@ class DependenciesTest < ActiveSupport::TestCase with_autoloading_fixtures do _ = ::A # assignment to silence parse-time warning "possibly useless use of :: in void context" _ = ::A::B # assignment to silence parse-time warning "possibly useless use of :: in void context" - ActiveSupport::Dependencies.remove_constant('A') - ActiveSupport::Dependencies.remove_constant('A::B') + ActiveSupport::Dependencies.remove_constant("A") + ActiveSupport::Dependencies.remove_constant("A::B") assert_not defined?(A) end ensure @@ -1036,10 +1036,9 @@ class DependenciesTest < ActiveSupport::TestCase remove_constants(:A) end - def test_autoload_once_paths_should_behave_when_recursively_loading old_path = ActiveSupport::Dependencies.autoload_once_paths - with_loading 'dependencies', 'autoloading_fixtures' do + with_loading "dependencies", "autoloading_fixtures" do ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last] assert_not defined?(CrossSiteDependency) assert_nothing_raised { CrossSiteDepender.nil? } @@ -1060,13 +1059,13 @@ class DependenciesTest < ActiveSupport::TestCase end def test_load_and_require_stay_private - assert Object.private_methods.include?(:load) - assert Object.private_methods.include?(:require) + assert_includes Object.private_methods, :load + assert_includes Object.private_methods, :require ActiveSupport::Dependencies.unhook! - assert Object.private_methods.include?(:load) - assert Object.private_methods.include?(:require) + assert_includes Object.private_methods, :load + assert_includes Object.private_methods, :require ensure ActiveSupport::Dependencies.hook! end diff --git a/activesupport/test/dependencies_test_helpers.rb b/activesupport/test/dependencies_test_helpers.rb index e4d5197112..9bc63ed89e 100644 --- a/activesupport/test/dependencies_test_helpers.rb +++ b/activesupport/test/dependencies_test_helpers.rb @@ -17,7 +17,7 @@ module DependenciesTestHelpers end def with_autoloading_fixtures(&block) - with_loading 'autoloading_fixtures', &block + with_loading "autoloading_fixtures", &block end def remove_constants(*constants) @@ -25,4 +25,4 @@ module DependenciesTestHelpers Object.send(:remove_const, constant) if Object.const_defined?(constant) end end -end
\ No newline at end of file +end diff --git a/activesupport/test/deprecation/method_wrappers_test.rb b/activesupport/test/deprecation/method_wrappers_test.rb index 9a4ca2b217..85d057bb02 100644 --- a/activesupport/test/deprecation/method_wrappers_test.rb +++ b/activesupport/test/deprecation/method_wrappers_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/deprecation' +require "abstract_unit" +require "active_support/deprecation" class MethodWrappersTest < ActiveSupport::TestCase def setup @@ -11,7 +11,7 @@ class MethodWrappersTest < ActiveSupport::TestCase def test_deprecate_methods_warning_default warning = /old_method is deprecated and will be removed from Rails \d.\d \(use new_method instead\)/ - ActiveSupport::Deprecation.deprecate_methods(@klass, :old_method => :new_method) + ActiveSupport::Deprecation.deprecate_methods(@klass, old_method: :new_method) assert_deprecated(warning) { assert_equal "abc", @klass.new.old_method } end @@ -19,7 +19,7 @@ class MethodWrappersTest < ActiveSupport::TestCase def test_deprecate_methods_warning_with_optional_deprecator warning = /old_method is deprecated and will be removed from MyGem next-release \(use new_method instead\)/ deprecator = ActiveSupport::Deprecation.new("next-release", "MyGem") - ActiveSupport::Deprecation.deprecate_methods(@klass, :old_method => :new_method, :deprecator => deprecator) + ActiveSupport::Deprecation.deprecate_methods(@klass, old_method: :new_method, deprecator: deprecator) assert_deprecated(warning, deprecator) { assert_equal "abc", @klass.new.old_method } end @@ -27,7 +27,7 @@ class MethodWrappersTest < ActiveSupport::TestCase def test_deprecate_methods_warning_when_deprecated_with_custom_deprecator warning = /old_method is deprecated and will be removed from MyGem next-release \(use new_method instead\)/ deprecator = ActiveSupport::Deprecation.new("next-release", "MyGem") - deprecator.deprecate_methods(@klass, :old_method => :new_method) + deprecator.deprecate_methods(@klass, old_method: :new_method) assert_deprecated(warning, deprecator) { assert_equal "abc", @klass.new.old_method } end diff --git a/activesupport/test/deprecation/proxy_wrappers_test.rb b/activesupport/test/deprecation/proxy_wrappers_test.rb index e4f0f0f7c2..67afd75c44 100644 --- a/activesupport/test/deprecation/proxy_wrappers_test.rb +++ b/activesupport/test/deprecation/proxy_wrappers_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/deprecation' +require "abstract_unit" +require "active_support/deprecation" class ProxyWrappersTest < ActiveSupport::TestCase Waffles = false diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb index dbde3d2e15..e2a3331cfa 100644 --- a/activesupport/test/deprecation_test.rb +++ b/activesupport/test/deprecation_test.rb @@ -1,16 +1,16 @@ -require 'abstract_unit' -require 'active_support/testing/stream' +require "abstract_unit" +require "active_support/testing/stream" class Deprecatee def initialize @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request) - @_request = 'there we go' + @_request = "there we go" end def request; @_request end def old_request; @request end def partially(foo = nil) - ActiveSupport::Deprecation.warn('calling with foo=nil is out') if foo.nil? + ActiveSupport::Deprecation.warn("calling with foo=nil is out") if foo.nil? end def not() 2 end @@ -24,7 +24,7 @@ class Deprecatee def c; end def d; end def e; end - deprecate :a, :b, :c => :e, :d => "you now need to do something extra for this one" + deprecate :a, :b, c: :e, d: "you now need to do something extra for this one" def f=(v); end deprecate :f= @@ -32,10 +32,9 @@ class Deprecatee module B C = 1 end - A = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Deprecatee::A', 'Deprecatee::B::C') + A = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("Deprecatee::A", "Deprecatee::B::C") end - class DeprecationTest < ActiveSupport::TestCase include ActiveSupport::Testing::Stream @@ -79,7 +78,7 @@ class DeprecationTest < ActiveSupport::TestCase end def test_deprecate_object - deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, ':bomb:') + deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, ":bomb:") assert_deprecated(/:bomb:/) { deprecated_object.to_s } end @@ -104,7 +103,7 @@ class DeprecationTest < ActiveSupport::TestCase def test_raise_behaviour ActiveSupport::Deprecation.behavior = :raise - message = 'Revise this deprecated stuff now!' + message = "Revise this deprecated stuff now!" callstack = caller_locations e = assert_raise ActiveSupport::DeprecationException do @@ -119,7 +118,7 @@ class DeprecationTest < ActiveSupport::TestCase behavior = ActiveSupport::Deprecation.behavior.first content = capture(:stderr) { - assert_nil behavior.call('Some error!', ['call stack!']) + assert_nil behavior.call("Some error!", ["call stack!"]) } assert_match(/Some error!/, content) assert_match(/call stack!/, content) @@ -129,7 +128,7 @@ class DeprecationTest < ActiveSupport::TestCase ActiveSupport::Deprecation.behavior = :stderr content = capture(:stderr) { - ActiveSupport::Deprecation.warn('Instance error!', ['instance call stack!']) + ActiveSupport::Deprecation.warn("Instance error!", ["instance call stack!"]) } assert_match(/Instance error!/, content) @@ -141,7 +140,7 @@ class DeprecationTest < ActiveSupport::TestCase behavior = ActiveSupport::Deprecation.behavior.first stderr_output = capture(:stderr) { - assert_nil behavior.call('Some error!', ['call stack!']) + assert_nil behavior.call("Some error!", ["call stack!"]) } assert stderr_output.empty? end @@ -149,8 +148,8 @@ class DeprecationTest < ActiveSupport::TestCase def test_deprecated_instance_variable_proxy assert_not_deprecated { @dtc.request.size } - assert_deprecated('@request.size') { assert_equal @dtc.request.size, @dtc.old_request.size } - assert_deprecated('@request.to_s') { assert_equal @dtc.request.to_s, @dtc.old_request.to_s } + assert_deprecated("@request.size") { assert_equal @dtc.request.size, @dtc.old_request.size } + assert_deprecated("@request.to_s") { assert_equal @dtc.request.to_s, @dtc.old_request.to_s } end def test_deprecated_instance_variable_proxy_shouldnt_warn_on_inspect @@ -159,7 +158,7 @@ class DeprecationTest < ActiveSupport::TestCase def test_deprecated_constant_proxy assert_not_deprecated { Deprecatee::B::C } - assert_deprecated('Deprecatee::A') { assert_equal Deprecatee::B::C, Deprecatee::A } + assert_deprecated("Deprecatee::A") { assert_equal Deprecatee::B::C, Deprecatee::A } assert_not_deprecated { assert_equal Deprecatee::B::C.class, Deprecatee::A.class } end @@ -178,12 +177,12 @@ class DeprecationTest < ActiveSupport::TestCase end def test_assert_deprecated_matches_any_warning - assert_deprecated 'abc' do - ActiveSupport::Deprecation.warn 'abc' - ActiveSupport::Deprecation.warn 'def' + assert_deprecated "abc" do + ActiveSupport::Deprecation.warn "abc" + ActiveSupport::Deprecation.warn "def" end rescue Minitest::Assertion - flunk 'assert_deprecated should match any warning in block, not just the last one' + flunk "assert_deprecated should match any warning in block, not just the last one" end def test_assert_not_deprecated_returns_result_of_block @@ -191,17 +190,17 @@ class DeprecationTest < ActiveSupport::TestCase end def test_assert_deprecated_returns_result_of_block - result = assert_deprecated('abc') do - ActiveSupport::Deprecation.warn 'abc' + result = assert_deprecated("abc") do + ActiveSupport::Deprecation.warn "abc" 123 end assert_equal 123, result end def test_assert_deprecated_warn_work_with_default_behavior - ActiveSupport::Deprecation.instance_variable_set('@behavior', nil) - assert_deprecated('abc') do - ActiveSupport::Deprecation.warn 'abc' + ActiveSupport::Deprecation.instance_variable_set("@behavior", nil) + assert_deprecated("abc") do + ActiveSupport::Deprecation.warn "abc" end end @@ -280,7 +279,7 @@ class DeprecationTest < ActiveSupport::TestCase def test_deprecated_constant_with_deprecator_given deprecator = deprecator_with_messages klass = Class.new - klass.const_set(:OLD, ActiveSupport::Deprecation::DeprecatedConstantProxy.new('klass::OLD', 'Object', deprecator) ) + klass.const_set(:OLD, ActiveSupport::Deprecation::DeprecatedConstantProxy.new("klass::OLD", "Object", deprecator) ) assert_difference("deprecator.messages.size") do klass::OLD.to_s end @@ -353,7 +352,7 @@ class DeprecationTest < ActiveSupport::TestCase end def test_custom_gem_name - deprecator = ActiveSupport::Deprecation.new('2.0', 'Custom') + deprecator = ActiveSupport::Deprecation.new("2.0", "Custom") deprecator.send(:deprecated_method_warning, :deprecated_method, "You are calling deprecated method").tap do |message| assert_match(/is deprecated and will be removed from Custom/, message) @@ -364,11 +363,10 @@ class DeprecationTest < ActiveSupport::TestCase def deprecator_with_messages klass = Class.new(ActiveSupport::Deprecation) deprecator = klass.new - deprecator.behavior = Proc.new{|message, callstack| deprecator.messages << message} + deprecator.behavior = Proc.new { |message, callstack| deprecator.messages << message } def deprecator.messages @messages ||= [] end deprecator end - end diff --git a/activesupport/test/descendants_tracker_test_cases.rb b/activesupport/test/descendants_tracker_test_cases.rb index 69e046998e..09c5ce1f07 100644 --- a/activesupport/test/descendants_tracker_test_cases.rb +++ b/activesupport/test/descendants_tracker_test_cases.rb @@ -1,4 +1,4 @@ -require 'set' +require "set" module DescendantsTrackerTestCases class Parent @@ -42,24 +42,24 @@ module DescendantsTrackerTestCases protected - def assert_equal_sets(expected, actual) - assert_equal Set.new(expected), Set.new(actual) - end - - def mark_as_autoloaded(*klasses) - # If ActiveSupport::Dependencies is not loaded, forget about autoloading. - # This allows using AS::DescendantsTracker without AS::Dependencies. - if defined? ActiveSupport::Dependencies - old_autoloaded = ActiveSupport::Dependencies.autoloaded_constants.dup - ActiveSupport::Dependencies.autoloaded_constants = klasses.map(&:name) + def assert_equal_sets(expected, actual) + assert_equal Set.new(expected), Set.new(actual) end - old_descendants = ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").dup - old_descendants.each { |k, v| old_descendants[k] = v.dup } + def mark_as_autoloaded(*klasses) + # If ActiveSupport::Dependencies is not loaded, forget about autoloading. + # This allows using AS::DescendantsTracker without AS::Dependencies. + if defined? ActiveSupport::Dependencies + old_autoloaded = ActiveSupport::Dependencies.autoloaded_constants.dup + ActiveSupport::Dependencies.autoloaded_constants = klasses.map(&:name) + end + + old_descendants = ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").dup + old_descendants.each { |k, v| old_descendants[k] = v.dup } - yield - ensure - ActiveSupport::Dependencies.autoloaded_constants = old_autoloaded if defined? ActiveSupport::Dependencies - ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").replace(old_descendants) - end + yield + ensure + ActiveSupport::Dependencies.autoloaded_constants = old_autoloaded if defined? ActiveSupport::Dependencies + ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").replace(old_descendants) + end end diff --git a/activesupport/test/descendants_tracker_with_autoloading_test.rb b/activesupport/test/descendants_tracker_with_autoloading_test.rb index a2ae066a21..e202667a8a 100644 --- a/activesupport/test/descendants_tracker_with_autoloading_test.rb +++ b/activesupport/test/descendants_tracker_with_autoloading_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'active_support/descendants_tracker' -require 'active_support/dependencies' -require 'descendants_tracker_test_cases' +require "abstract_unit" +require "active_support/descendants_tracker" +require "active_support/dependencies" +require "descendants_tracker_test_cases" class DescendantsTrackerWithAutoloadingTest < ActiveSupport::TestCase include DescendantsTrackerTestCases diff --git a/activesupport/test/descendants_tracker_without_autoloading_test.rb b/activesupport/test/descendants_tracker_without_autoloading_test.rb index 00b449af51..72adc30ace 100644 --- a/activesupport/test/descendants_tracker_without_autoloading_test.rb +++ b/activesupport/test/descendants_tracker_without_autoloading_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/descendants_tracker' -require 'descendants_tracker_test_cases' +require "abstract_unit" +require "active_support/descendants_tracker" +require "descendants_tracker_test_cases" class DescendantsTrackerWithoutAutoloadingTest < ActiveSupport::TestCase include DescendantsTrackerTestCases diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb index 2cb2d8167f..77d8dcb0f8 100644 --- a/activesupport/test/evented_file_update_checker_test.rb +++ b/activesupport/test/evented_file_update_checker_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' -require 'pathname' -require 'file_update_checker_shared_tests' +require "abstract_unit" +require "pathname" +require "file_update_checker_shared_tests" class EventedFileUpdateCheckerTest < ActiveSupport::TestCase include FileUpdateCheckerSharedTests def setup - skip if ENV['LISTEN'] == '0' + skip if ENV["LISTEN"] == "0" super end @@ -35,10 +35,12 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase wait end - test 'notifies forked processes' do + test "notifies forked processes" do + jruby_skip "Forking not available on JRuby" + FileUtils.touch(tmpfiles) - checker = new_checker(tmpfiles) { } + checker = new_checker(tmpfiles) {} assert !checker.updated? # Pipes used for flow controll across fork. @@ -87,33 +89,33 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase @ph = ActiveSupport::EventedFileUpdateChecker::PathHelper.new end - test '#xpath returns the expanded path as a Pathname object' do + test "#xpath returns the expanded path as a Pathname object" do assert_equal pn(__FILE__).expand_path, @ph.xpath(__FILE__) end - test '#normalize_extension returns a bare extension as is' do - assert_equal 'rb', @ph.normalize_extension('rb') + test "#normalize_extension returns a bare extension as is" do + assert_equal "rb", @ph.normalize_extension("rb") end - test '#normalize_extension removes a leading dot' do - assert_equal 'rb', @ph.normalize_extension('.rb') + test "#normalize_extension removes a leading dot" do + assert_equal "rb", @ph.normalize_extension(".rb") end - test '#normalize_extension supports symbols' do - assert_equal 'rb', @ph.normalize_extension(:rb) + test "#normalize_extension supports symbols" do + assert_equal "rb", @ph.normalize_extension(:rb) end - test '#longest_common_subpath finds the longest common subpath, if there is one' do + test "#longest_common_subpath finds the longest common subpath, if there is one" do paths = %w( /foo/bar /foo/baz /foo/bar/baz/woo/zoo ).map { |path| pn(path) } - assert_equal pn('/foo'), @ph.longest_common_subpath(paths) + assert_equal pn("/foo"), @ph.longest_common_subpath(paths) end - test '#longest_common_subpath returns the root directory as an edge case' do + test "#longest_common_subpath returns the root directory as an edge case" do paths = %w( /foo/bar /foo/baz @@ -121,30 +123,30 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase /wadus ).map { |path| pn(path) } - assert_equal pn('/'), @ph.longest_common_subpath(paths) + assert_equal pn("/"), @ph.longest_common_subpath(paths) end - test '#longest_common_subpath returns nil for an empty collection' do + test "#longest_common_subpath returns nil for an empty collection" do assert_nil @ph.longest_common_subpath([]) end - test '#existing_parent returns the most specific existing ascendant' do + test "#existing_parent returns the most specific existing ascendant" do wd = Pathname.getwd assert_equal wd, @ph.existing_parent(wd) - assert_equal wd, @ph.existing_parent(wd.join('non-existing/directory')) - assert_equal pn('/'), @ph.existing_parent(pn('/non-existing/directory')) + assert_equal wd, @ph.existing_parent(wd.join("non-existing/directory")) + assert_equal pn("/"), @ph.existing_parent(pn("/non-existing/directory")) end - test '#filter_out_descendants returns the same collection if there are no descendants (empty)' do + test "#filter_out_descendants returns the same collection if there are no descendants (empty)" do assert_equal [], @ph.filter_out_descendants([]) end - test '#filter_out_descendants returns the same collection if there are no descendants (one)' do - assert_equal ['/foo'], @ph.filter_out_descendants(['/foo']) + test "#filter_out_descendants returns the same collection if there are no descendants (one)" do + assert_equal ["/foo"], @ph.filter_out_descendants(["/foo"]) end - test '#filter_out_descendants returns the same collection if there are no descendants (several)' do + test "#filter_out_descendants returns the same collection if there are no descendants (several)" do paths = %w( /Rails.root/app/controllers /Rails.root/app/models @@ -154,7 +156,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths, @ph.filter_out_descendants(paths) end - test '#filter_out_descendants filters out descendants preserving order' do + test "#filter_out_descendants filters out descendants preserving order" do paths = %w( /Rails.root/app/controllers /Rails.root/app/controllers/concerns @@ -166,7 +168,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths.values_at(0, 2, 4), @ph.filter_out_descendants(paths) end - test '#filter_out_descendants works on path units' do + test "#filter_out_descendants works on path units" do paths = %w( /foo/bar /foo/barrrr @@ -175,7 +177,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths, @ph.filter_out_descendants(paths) end - test '#filter_out_descendants deals correctly with the root directory' do + test "#filter_out_descendants deals correctly with the root directory" do paths = %w( / /foo @@ -185,7 +187,7 @@ class EventedFileUpdateCheckerPathHelperTest < ActiveSupport::TestCase assert_equal paths.values_at(0), @ph.filter_out_descendants(paths) end - test '#filter_out_descendants preserves duplicates' do + test "#filter_out_descendants preserves duplicates" do paths = %w( /foo /foo/bar diff --git a/activesupport/test/executor_test.rb b/activesupport/test/executor_test.rb index d9b389461a..03ec6020c3 100644 --- a/activesupport/test/executor_test.rb +++ b/activesupport/test/executor_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ExecutorTest < ActiveSupport::TestCase class DummyError < RuntimeError @@ -21,7 +21,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.to_run { @foo = true } executor.to_complete { result = @foo } - executor.wrap { } + executor.wrap {} assert result end @@ -83,7 +83,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook) - executor.wrap { } + executor.wrap {} assert_equal :some_state, supplied_state end @@ -103,7 +103,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook) - executor.wrap { } + executor.wrap {} assert_equal nil, supplied_state end @@ -127,7 +127,7 @@ class ExecutorTest < ActiveSupport::TestCase executor.register_hook(hook) assert_raises(DummyError) do - executor.wrap { } + executor.wrap {} end assert_equal :none, supplied_state @@ -152,12 +152,69 @@ class ExecutorTest < ActiveSupport::TestCase end assert_raises(DummyError) do - executor.wrap { } + executor.wrap {} end assert_equal :some_state, supplied_state end + def test_hook_insertion_order + invoked = [] + supplied_state = [] + + hook_class = Class.new do + attr_accessor :letter + + define_method(:initialize) do |letter| + self.letter = letter + end + + define_method(:run) do + invoked << :"run_#{letter}" + :"state_#{letter}" + end + + define_method(:complete) do |state| + invoked << :"complete_#{letter}" + supplied_state << state + end + end + + executor.register_hook(hook_class.new(:a)) + executor.register_hook(hook_class.new(:b)) + executor.register_hook(hook_class.new(:c), outer: true) + executor.register_hook(hook_class.new(:d)) + + executor.wrap {} + + assert_equal [:run_c, :run_a, :run_b, :run_d, :complete_a, :complete_b, :complete_d, :complete_c], invoked + assert_equal [:state_a, :state_b, :state_d, :state_c], supplied_state + end + + def test_class_serial_is_unaffected + skip if !defined?(RubyVM) + + hook = Class.new do + define_method(:run) do + nil + end + + define_method(:complete) do |state| + nil + end + end.new + + executor.register_hook(hook) + + before = RubyVM.stat(:class_serial) + executor.wrap {} + executor.wrap {} + executor.wrap {} + after = RubyVM.stat(:class_serial) + + assert_equal before, after + end + def test_separate_classes_can_wrap other_executor = Class.new(ActiveSupport::Executor) diff --git a/activesupport/test/file_update_checker_shared_tests.rb b/activesupport/test/file_update_checker_shared_tests.rb index 40ae0c7617..48cd387196 100644 --- a/activesupport/test/file_update_checker_shared_tests.rb +++ b/activesupport/test/file_update_checker_shared_tests.rb @@ -1,4 +1,4 @@ -require 'fileutils' +require "fileutils" module FileUpdateCheckerSharedTests extend ActiveSupport::Testing::Declarative @@ -22,8 +22,8 @@ module FileUpdateCheckerSharedTests end end - test 'should not execute the block if no paths are given' do - silence_warnings { require 'listen' } + test "should not execute the block if no paths are given" do + silence_warnings { require "listen" } i = 0 checker = new_checker { i += 1 } @@ -32,7 +32,7 @@ module FileUpdateCheckerSharedTests assert_equal 0, i end - test 'should not execute the block if no files change' do + test "should not execute the block if no files change" do i = 0 FileUtils.touch(tmpfiles) @@ -43,18 +43,19 @@ module FileUpdateCheckerSharedTests assert_equal 0, i end - test 'should execute the block once when files are created' do + test "should execute the block once when files are created" do i = 0 checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should execute the block once when files are modified' do + test "should execute the block once when files are modified" do i = 0 FileUtils.touch(tmpfiles) @@ -62,12 +63,13 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should execute the block once when files are deleted' do + test "should execute the block once when files are deleted" do i = 0 FileUtils.touch(tmpfiles) @@ -75,25 +77,25 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } rm_f(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i end - - test 'updated should become true when watched files are created' do + test "updated should become true when watched files are created" do i = 0 checker = new_checker(tmpfiles) { i += 1 } assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? end - - test 'updated should become true when watched files are modified' do + test "updated should become true when watched files are modified" do i = 0 FileUtils.touch(tmpfiles) @@ -102,11 +104,12 @@ module FileUpdateCheckerSharedTests assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? end - test 'updated should become true when watched files are deleted' do + test "updated should become true when watched files are deleted" do i = 0 FileUtils.touch(tmpfiles) @@ -115,11 +118,12 @@ module FileUpdateCheckerSharedTests assert !checker.updated? rm_f(tmpfiles) + wait assert checker.updated? end - test 'should be robust to handle files with wrong modified time' do + test "should be robust to handle files with wrong modified time" do i = 0 FileUtils.touch(tmpfiles) @@ -131,12 +135,13 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles[1..-1]) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should return max_time for files with mtime = Time.at(0)' do + test "should return max_time for files with mtime = Time.at(0)" do i = 0 FileUtils.touch(tmpfiles) @@ -147,80 +152,87 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles[1..-1]) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should cache updated result until execute' do + test "should cache updated result until execute" do i = 0 checker = new_checker(tmpfiles) { i += 1 } assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? checker.execute assert !checker.updated? end - test 'should execute the block if files change in a watched directory one extension' do + test "should execute the block if files change in a watched directory one extension" do i = 0 checker = new_checker([], tmpdir => :rb) { i += 1 } - touch(tmpfile('foo.rb')) + touch(tmpfile("foo.rb")) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'should execute the block if files change in a watched directory several extensions' do + test "should execute the block if files change in a watched directory several extensions" do i = 0 checker = new_checker([], tmpdir => [:rb, :txt]) { i += 1 } - touch(tmpfile('foo.rb')) + touch(tmpfile("foo.rb")) + wait assert checker.execute_if_updated assert_equal 1, i - touch(tmpfile('foo.txt')) + touch(tmpfile("foo.txt")) + wait assert checker.execute_if_updated assert_equal 2, i end - test 'should not execute the block if the file extension is not watched' do + test "should not execute the block if the file extension is not watched" do i = 0 checker = new_checker([], tmpdir => :txt) { i += 1 } - touch(tmpfile('foo.rb')) + touch(tmpfile("foo.rb")) + wait assert !checker.execute_if_updated assert_equal 0, i end - test 'does not assume files exist on instantiation' do + test "does not assume files exist on instantiation" do i = 0 - non_existing = tmpfile('non_existing.rb') + non_existing = tmpfile("non_existing.rb") checker = new_checker([non_existing]) { i += 1 } touch(non_existing) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'detects files in new subdirectories' do + test "detects files in new subdirectories" do i = 0 checker = new_checker([], tmpdir => :rb) { i += 1 } - subdir = tmpfile('subdir') + subdir = tmpfile("subdir") mkdir(subdir) wait @@ -228,31 +240,35 @@ module FileUpdateCheckerSharedTests assert_equal 0, i touch(File.join(subdir, "nested.rb")) + wait assert checker.execute_if_updated assert_equal 1, i end - test 'looked up extensions are inherited in subdirectories not listening to them' do + test "looked up extensions are inherited in subdirectories not listening to them" do i = 0 - subdir = tmpfile('subdir') + subdir = tmpfile("subdir") mkdir(subdir) checker = new_checker([], tmpdir => :rb, subdir => :txt) { i += 1 } - touch(tmpfile('new.txt')) + touch(tmpfile("new.txt")) + wait assert !checker.execute_if_updated assert_equal 0, i # subdir does not look for Ruby files, but its parent tmpdir does. touch(File.join(subdir, "nested.rb")) + wait assert checker.execute_if_updated assert_equal 1, i touch(File.join(subdir, "nested.txt")) + wait assert checker.execute_if_updated assert_equal 2, i diff --git a/activesupport/test/file_update_checker_test.rb b/activesupport/test/file_update_checker_test.rb index 752f7836cd..55b0b46644 100644 --- a/activesupport/test/file_update_checker_test.rb +++ b/activesupport/test/file_update_checker_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'file_update_checker_shared_tests' +require "abstract_unit" +require "file_update_checker_shared_tests" class FileUpdateCheckerTest < ActiveSupport::TestCase include FileUpdateCheckerSharedTests diff --git a/activesupport/test/fixtures/autoload/another_class.rb b/activesupport/test/fixtures/autoload/another_class.rb index a240b3de41..ab6e075ab4 100644 --- a/activesupport/test/fixtures/autoload/another_class.rb +++ b/activesupport/test/fixtures/autoload/another_class.rb @@ -1,2 +1,2 @@ class Fixtures::AnotherClass -end
\ No newline at end of file +end diff --git a/activesupport/test/fixtures/autoload/some_class.rb b/activesupport/test/fixtures/autoload/some_class.rb index 13b3c73ef5..30d41eb0bf 100644 --- a/activesupport/test/fixtures/autoload/some_class.rb +++ b/activesupport/test/fixtures/autoload/some_class.rb @@ -1,2 +1,2 @@ class Fixtures::Autoload::SomeClass -end
\ No newline at end of file +end diff --git a/activesupport/test/gzip_test.rb b/activesupport/test/gzip_test.rb index 0e3cf3b429..d88408b55c 100644 --- a/activesupport/test/gzip_test.rb +++ b/activesupport/test/gzip_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/blank' +require "abstract_unit" +require "active_support/core_ext/object/blank" class GzipTest < ActiveSupport::TestCase def test_compress_should_decompress_to_the_same_value @@ -13,9 +13,9 @@ class GzipTest < ActiveSupport::TestCase end def test_compress_should_return_a_binary_string - compressed = ActiveSupport::Gzip.compress('') + compressed = ActiveSupport::Gzip.compress("") - assert_equal Encoding.find('binary'), compressed.encoding + assert_equal Encoding.find("binary"), compressed.encoding assert !compressed.blank?, "a compressed blank string should not be blank" end diff --git a/activesupport/test/i18n_test.rb b/activesupport/test/i18n_test.rb index 3faa15e7fd..7d88d2dc6b 100644 --- a/activesupport/test/i18n_test.rb +++ b/activesupport/test/i18n_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/time' -require 'active_support/core_ext/array/conversions' +require "abstract_unit" +require "active_support/time" +require "active_support/core_ext/array/conversions" class I18nTest < ActiveSupport::TestCase def setup @@ -18,15 +18,15 @@ class I18nTest < ActiveSupport::TestCase end def test_date_localization_with_default_format - assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date, :format => :default) + assert_equal @date.strftime("%Y-%m-%d"), I18n.localize(@date, format: :default) end def test_date_localization_with_short_format - assert_equal @date.strftime("%b %d"), I18n.localize(@date, :format => :short) + assert_equal @date.strftime("%b %d"), I18n.localize(@date, format: :short) end def test_date_localization_with_long_format - assert_equal @date.strftime("%B %d, %Y"), I18n.localize(@date, :format => :long) + assert_equal @date.strftime("%B %d, %Y"), I18n.localize(@date, format: :long) end def test_time_localization_should_use_default_format @@ -34,15 +34,15 @@ class I18nTest < ActiveSupport::TestCase end def test_time_localization_with_default_format - assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time, :format => :default) + assert_equal @time.strftime("%a, %d %b %Y %H:%M:%S %z"), I18n.localize(@time, format: :default) end def test_time_localization_with_short_format - assert_equal @time.strftime("%d %b %H:%M"), I18n.localize(@time, :format => :short) + assert_equal @time.strftime("%d %b %H:%M"), I18n.localize(@time, format: :short) end def test_time_localization_with_long_format - assert_equal @time.strftime("%B %d, %Y %H:%M"), I18n.localize(@time, :format => :long) + assert_equal @time.strftime("%B %d, %Y %H:%M"), I18n.localize(@time, format: :long) end def test_day_names @@ -66,39 +66,39 @@ class I18nTest < ActiveSupport::TestCase end def test_time_am - assert_equal 'am', I18n.translate(:'time.am') + assert_equal "am", I18n.translate(:'time.am') end def test_time_pm - assert_equal 'pm', I18n.translate(:'time.pm') + assert_equal "pm", I18n.translate(:'time.pm') end def test_words_connector - assert_equal ', ', I18n.translate(:'support.array.words_connector') + assert_equal ", ", I18n.translate(:'support.array.words_connector') end def test_two_words_connector - assert_equal ' and ', I18n.translate(:'support.array.two_words_connector') + assert_equal " and ", I18n.translate(:'support.array.two_words_connector') end def test_last_word_connector - assert_equal ', and ', I18n.translate(:'support.array.last_word_connector') + assert_equal ", and ", I18n.translate(:'support.array.last_word_connector') end def test_to_sentence default_two_words_connector = I18n.translate(:'support.array.two_words_connector') default_last_word_connector = I18n.translate(:'support.array.last_word_connector') - assert_equal 'a, b, and c', %w[a b c].to_sentence - I18n.backend.store_translations 'en', :support => { :array => { :two_words_connector => ' & ' } } - assert_equal 'a & b', %w[a b].to_sentence - I18n.backend.store_translations 'en', :support => { :array => { :last_word_connector => ' and ' } } - assert_equal 'a, b and c', %w[a b c].to_sentence + assert_equal "a, b, and c", %w[a b c].to_sentence + I18n.backend.store_translations "en", support: { array: { two_words_connector: " & " } } + assert_equal "a & b", %w[a b].to_sentence + I18n.backend.store_translations "en", support: { array: { last_word_connector: " and " } } + assert_equal "a, b and c", %w[a b c].to_sentence ensure - I18n.backend.store_translations 'en', :support => { :array => { :two_words_connector => default_two_words_connector } } - I18n.backend.store_translations 'en', :support => { :array => { :last_word_connector => default_last_word_connector } } + I18n.backend.store_translations "en", support: { array: { two_words_connector: default_two_words_connector } } + I18n.backend.store_translations "en", support: { array: { last_word_connector: default_last_word_connector } } end def test_to_sentence_with_empty_i18n_store - assert_equal 'a, b, and c', %w[a b c].to_sentence(locale: 'empty') + assert_equal "a, b, and c", %w[a b c].to_sentence(locale: "empty") end end diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 06cd41c86d..1c5a4f378c 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' -require 'active_support/inflector' +require "abstract_unit" +require "active_support/inflector" -require 'inflector_test_cases' -require 'constantize_test_cases' +require "inflector_test_cases" +require "constantize_test_cases" class InflectorTest < ActiveSupport::TestCase include InflectorTestCases @@ -80,7 +80,6 @@ class InflectorTest < ActiveSupport::TestCase end end - def test_overwrite_previous_inflectors assert_equal("series", ActiveSupport::Inflector.singularize("series")) ActiveSupport::Inflector.inflections.singular "series", "serie" @@ -101,11 +100,11 @@ class InflectorTest < ActiveSupport::TestCase end def test_camelize_with_lower_downcases_the_first_letter - assert_equal('capital', ActiveSupport::Inflector.camelize('Capital', false)) + assert_equal("capital", ActiveSupport::Inflector.camelize("Capital", false)) end def test_camelize_with_underscores - assert_equal("CamelCase", ActiveSupport::Inflector.camelize('Camel_Case')) + assert_equal("CamelCase", ActiveSupport::Inflector.camelize("Camel_Case")) end def test_acronyms @@ -246,12 +245,12 @@ class InflectorTest < ActiveSupport::TestCase end end -# FIXME: get following tests to pass on jruby, currently skipped -# -# Currently this fails because ActiveSupport::Multibyte::Unicode#tidy_bytes -# required a specific Encoding::Converter(UTF-8 to UTF8-MAC) which unavailable on JRuby -# causing our tests to error out. -# related bug http://jira.codehaus.org/browse/JRUBY-7194 + # FIXME: get following tests to pass on jruby, currently skipped + # + # Currently this fails because ActiveSupport::Multibyte::Unicode#tidy_bytes + # required a specific Encoding::Converter(UTF-8 to UTF8-MAC) which unavailable on JRuby + # causing our tests to error out. + # related bug http://jira.codehaus.org/browse/JRUBY-7194 def test_parameterize jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| @@ -269,7 +268,7 @@ class InflectorTest < ActiveSupport::TestCase def test_parameterize_with_custom_separator jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizeWithUnderscore.each do |some_string, parameterized_string| - assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, separator: '_')) + assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, separator: "_")) end end @@ -277,7 +276,7 @@ class InflectorTest < ActiveSupport::TestCase jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterizeWithUnderscore.each do |some_string, parameterized_string| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '_'` instead./i) do - assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, '_')) + assert_equal(parameterized_string, ActiveSupport::Inflector.parameterize(some_string, "_")) end end end @@ -285,7 +284,7 @@ class InflectorTest < ActiveSupport::TestCase def test_parameterize_with_multi_character_separator jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| - assert_equal(parameterized_string.gsub('-', '__sep__'), ActiveSupport::Inflector.parameterize(some_string, separator: '__sep__')) + assert_equal(parameterized_string.gsub("-", "__sep__"), ActiveSupport::Inflector.parameterize(some_string, separator: "__sep__")) end end @@ -293,7 +292,7 @@ class InflectorTest < ActiveSupport::TestCase jruby_skip "UTF-8 to UTF8-MAC Converter is unavailable" StringToParameterized.each do |some_string, parameterized_string| assert_deprecated(/Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '__sep__'` instead./i) do - assert_equal(parameterized_string.gsub('-', '__sep__'), ActiveSupport::Inflector.parameterize(some_string, '__sep__')) + assert_equal(parameterized_string.gsub("-", "__sep__"), ActiveSupport::Inflector.parameterize(some_string, "__sep__")) end end end @@ -307,12 +306,12 @@ class InflectorTest < ActiveSupport::TestCase def test_classify_with_symbol assert_nothing_raised do - assert_equal 'FooBar', ActiveSupport::Inflector.classify(:foo_bars) + assert_equal "FooBar", ActiveSupport::Inflector.classify(:foo_bars) end end def test_classify_with_leading_schema_name - assert_equal 'FooBar', ActiveSupport::Inflector.classify('schema.foo_bar') + assert_equal "FooBar", ActiveSupport::Inflector.classify("schema.foo_bar") end def test_humanize @@ -403,24 +402,24 @@ class InflectorTest < ActiveSupport::TestCase def test_inflector_locality ActiveSupport::Inflector.inflections(:es) do |inflect| - inflect.plural(/$/, 's') - inflect.plural(/z$/i, 'ces') + inflect.plural(/$/, "s") + inflect.plural(/z$/i, "ces") - inflect.singular(/s$/, '') - inflect.singular(/es$/, '') + inflect.singular(/s$/, "") + inflect.singular(/es$/, "") - inflect.irregular('el', 'los') + inflect.irregular("el", "los") end - assert_equal('hijos', 'hijo'.pluralize(:es)) - assert_equal('luces', 'luz'.pluralize(:es)) - assert_equal('luzs', 'luz'.pluralize) + assert_equal("hijos", "hijo".pluralize(:es)) + assert_equal("luces", "luz".pluralize(:es)) + assert_equal("luzs", "luz".pluralize) - assert_equal('sociedad', 'sociedades'.singularize(:es)) - assert_equal('sociedade', 'sociedades'.singularize) + assert_equal("sociedad", "sociedades".singularize(:es)) + assert_equal("sociedade", "sociedades".singularize) - assert_equal('los', 'el'.pluralize(:es)) - assert_equal('els', 'el'.pluralize) + assert_equal("los", "el".pluralize(:es)) + assert_equal("els", "el".pluralize) ActiveSupport::Inflector.inflections(:es) { |inflect| inflect.clear } @@ -435,7 +434,7 @@ class InflectorTest < ActiveSupport::TestCase # ensure any data is present inflect.plural(/(quiz)$/i, '\1zes') inflect.singular(/(database)s$/i, '\1') - inflect.uncountable('series') + inflect.uncountable("series") inflect.human("col_rpted_bugs", "Reported bugs") inflect.clear :all @@ -452,7 +451,7 @@ class InflectorTest < ActiveSupport::TestCase # ensure any data is present inflect.plural(/(quiz)$/i, '\1zes') inflect.singular(/(database)s$/i, '\1') - inflect.uncountable('series') + inflect.uncountable("series") inflect.human("col_rpted_bugs", "Reported bugs") inflect.clear diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index c7dc1dadb6..a8283301b3 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -128,10 +128,10 @@ module InflectorTestCases } SymbolToLowerCamel = { - :product => 'product', - :special_guest => 'specialGuest', - :application_controller => 'applicationController', - :area51_controller => 'area51Controller' + product: "product", + special_guest: "specialGuest", + application_controller: "applicationController", + area51_controller: "area51Controller" } CamelToUnderscoreWithoutReverse = { @@ -176,12 +176,12 @@ module InflectorTestCases StringToParameterizedPreserveCase = { "Donald E. Knuth" => "Donald-E-Knuth", - "Random text with *(bad)* characters" => "Random-text-with-bad-characters", - "Allow_Under_Scores" => "Allow_Under_Scores", - "Trailing bad characters!@#" => "Trailing-bad-characters", - "!@#Leading bad characters" => "Leading-bad-characters", - "Squeeze separators" => "Squeeze-separators", - "Test with + sign" => "Test-with-sign", + "Random text with *(bad)* characters" => "Random-text-with-bad-characters", + "Allow_Under_Scores" => "Allow_Under_Scores", + "Trailing bad characters!@#" => "Trailing-bad-characters", + "!@#Leading bad characters" => "Leading-bad-characters", + "Squeeze separators" => "Squeeze-separators", + "Test with + sign" => "Test-with-sign", "Test with malformed utf8 \xA9" => "Test-with-malformed-utf8" } @@ -199,11 +199,11 @@ module InflectorTestCases StringToParameterizePreserveCaseWithNoSeparator = { "Donald E. Knuth" => "DonaldEKnuth", "With-some-dashes" => "With-some-dashes", - "Random text with *(bad)* characters" => "Randomtextwithbadcharacters", - "Trailing bad characters!@#" => "Trailingbadcharacters", - "!@#Leading bad characters" => "Leadingbadcharacters", - "Squeeze separators" => "Squeezeseparators", - "Test with + sign" => "Testwithsign", + "Random text with *(bad)* characters" => "Randomtextwithbadcharacters", + "Trailing bad characters!@#" => "Trailingbadcharacters", + "!@#Leading bad characters" => "Leadingbadcharacters", + "Squeeze separators" => "Squeezeseparators", + "Test with + sign" => "Testwithsign", "Test with malformed utf8 \xA9" => "Testwithmalformedutf8" } @@ -220,14 +220,14 @@ module InflectorTestCases } StringToParameterizePreserceCaseWithUnderscore = { - "Donald E. Knuth" => "Donald_E_Knuth", + "Donald E. Knuth" => "Donald_E_Knuth", "Random text with *(bad)* characters" => "Random_text_with_bad_characters", - "With-some-dashes" => "With-some-dashes", - "Allow_Under_Scores" => "Allow_Under_Scores", - "Trailing bad characters!@#" => "Trailing_bad_characters", - "!@#Leading bad characters" => "Leading_bad_characters", - "Squeeze separators" => "Squeeze_separators", - "Test with + sign" => "Test_with_sign", + "With-some-dashes" => "With-some-dashes", + "Allow_Under_Scores" => "Allow_Under_Scores", + "Trailing bad characters!@#" => "Trailing_bad_characters", + "!@#Leading bad characters" => "Leading_bad_characters", + "Squeeze separators" => "Squeeze_separators", + "Test with + sign" => "Test_with_sign", "Test with malformed utf8 \xA9" => "Test_with_malformed_utf8" } @@ -241,11 +241,11 @@ module InflectorTestCases } UnderscoreToHuman = { - 'employee_salary' => 'Employee salary', - 'employee_id' => 'Employee', - 'underground' => 'Underground', - '_id' => 'Id', - '_external_id' => 'External' + "employee_salary" => "Employee salary", + "employee_id" => "Employee", + "underground" => "Underground", + "_id" => "Id", + "_external_id" => "External" } UnderscoreToHumanWithoutCapitalize = { @@ -255,20 +255,20 @@ module InflectorTestCases } MixtureToTitleCase = { - 'active_record' => 'Active Record', - 'ActiveRecord' => 'Active Record', - 'action web service' => 'Action Web Service', - 'Action Web Service' => 'Action Web Service', - 'Action web service' => 'Action Web Service', - 'actionwebservice' => 'Actionwebservice', - 'Actionwebservice' => 'Actionwebservice', + "active_record" => "Active Record", + "ActiveRecord" => "Active Record", + "action web service" => "Action Web Service", + "Action Web Service" => "Action Web Service", + "Action web service" => "Action Web Service", + "actionwebservice" => "Actionwebservice", + "Actionwebservice" => "Actionwebservice", "david's code" => "David's Code", "David's code" => "David's Code", "david's Code" => "David's Code", "sgt. pepper's" => "Sgt. Pepper's", "i've just seen a face" => "I've Just Seen A Face", "maybe you'll be there" => "Maybe You'll Be There", - "¿por qué?" => '¿Por Qué?', + "¿por qué?" => "¿Por Qué?", "Fred’s" => "Fred’s", "Fred`s" => "Fred`s", ActiveSupport::SafeBuffer.new("confirmation num") => "Confirmation Num" @@ -345,13 +345,13 @@ module InflectorTestCases } Irregularities = { - 'person' => 'people', - 'man' => 'men', - 'child' => 'children', - 'sex' => 'sexes', - 'move' => 'moves', - 'cow' => 'kine', # Test inflections with different starting letters - 'zombie' => 'zombies', - 'genus' => 'genera' + "person" => "people", + "man" => "men", + "child" => "children", + "sex" => "sexes", + "move" => "moves", + "cow" => "kine", # Test inflections with different starting letters + "zombie" => "zombies", + "genus" => "genera" } end diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index f2fc456f4b..dd8382754b 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -1,8 +1,11 @@ -require 'abstract_unit' -require 'active_support/json' -require 'active_support/time' +require "abstract_unit" +require "active_support/json" +require "active_support/time" +require "time_zone_test_helpers" class TestJSONDecoding < ActiveSupport::TestCase + include TimeZoneTestHelpers + class Foo def self.json_create(object) "Foo" @@ -10,72 +13,75 @@ class TestJSONDecoding < ActiveSupport::TestCase end TESTS = { - %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}}, - %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}}, - %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}}, - %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]}, - %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]}, - %({"a": "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"}, - %({"a": "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"}, + %q({"returnTo":{"\/categories":"\/"}}) => { "returnTo" => { "/categories" => "/" } }, + %q({"return\\"To\\":":{"\/categories":"\/"}}) => { "return\"To\":" => { "/categories" => "/" } }, + %q({"returnTo":{"\/categories":1}}) => { "returnTo" => { "/categories" => 1 } }, + %({"returnTo":[1,"a"]}) => { "returnTo" => [1, "a"] }, + %({"returnTo":[1,"\\"a\\",", "b"]}) => { "returnTo" => [1, "\"a\",", "b"] }, + %({"a": "'", "b": "5,000"}) => { "a" => "'", "b" => "5,000" }, + %({"a": "a's, b's and c's", "b": "5,000"}) => { "a" => "a's, b's and c's", "b" => "5,000" }, # multibyte - %({"matzue": "æ¾æ±Ÿ", "asakusa": "æµ…è‰"}) => {"matzue" => "æ¾æ±Ÿ", "asakusa" => "æµ…è‰"}, - %({"a": "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)}, - %({"a": "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)}, + %({"matzue": "æ¾æ±Ÿ", "asakusa": "æµ…è‰"}) => { "matzue" => "æ¾æ±Ÿ", "asakusa" => "æµ…è‰" }, + %({"a": "2007-01-01"}) => { "a" => Date.new(2007, 1, 1) }, + %({"a": "2007-01-01 01:12:34 Z"}) => { "a" => Time.utc(2007, 1, 1, 1, 12, 34) }, %(["2007-01-01 01:12:34 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34)], %(["2007-01-01 01:12:34 Z", "2007-01-01 01:12:35 Z"]) => [Time.utc(2007, 1, 1, 1, 12, 34), Time.utc(2007, 1, 1, 1, 12, 35)], # no time zone - %({"a": "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"}, + %({"a": "2007-01-01 01:12:34"}) => { "a" => Time.new(2007, 1, 1, 1, 12, 34, "-05:00") }, # invalid date - %({"a": "1089-10-40"}) => {'a' => "1089-10-40"}, + %({"a": "1089-10-40"}) => { "a" => "1089-10-40" }, # xmlschema date notation - %({"a": "2009-08-10T19:01:02Z"}) => {'a' => Time.utc(2009, 8, 10, 19, 1, 2)}, - %({"a": "2009-08-10T19:01:02+02:00"}) => {'a' => Time.utc(2009, 8, 10, 17, 1, 2)}, - %({"a": "2009-08-10T19:01:02-05:00"}) => {'a' => Time.utc(2009, 8, 11, 00, 1, 2)}, + %({"a": "2009-08-10T19:01:02"}) => { "a" => Time.new(2009, 8, 10, 19, 1, 2, "-04:00") }, + %({"a": "2009-08-10T19:01:02Z"}) => { "a" => Time.utc(2009, 8, 10, 19, 1, 2) }, + %({"a": "2009-08-10T19:01:02+02:00"}) => { "a" => Time.utc(2009, 8, 10, 17, 1, 2) }, + %({"a": "2009-08-10T19:01:02-05:00"}) => { "a" => Time.utc(2009, 8, 11, 00, 1, 2) }, # needs to be *exact* - %({"a": " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "}, - %({"a": "2007-01-01 : it's your birthday"}) => {'a' => "2007-01-01 : it's your birthday"}, + %({"a": " 2007-01-01 01:12:34 Z "}) => { "a" => " 2007-01-01 01:12:34 Z " }, + %({"a": "2007-01-01 : it's your birthday"}) => { "a" => "2007-01-01 : it's your birthday" }, %([]) => [], %({}) => {}, - %({"a":1}) => {"a" => 1}, - %({"a": ""}) => {"a" => ""}, - %({"a":"\\""}) => {"a" => "\""}, - %({"a": null}) => {"a" => nil}, - %({"a": true}) => {"a" => true}, - %({"a": false}) => {"a" => false}, - %q({"bad":"\\\\","trailing":""}) => {"bad" => "\\", "trailing" => ""}, - %q({"a": "http:\/\/test.host\/posts\/1"}) => {"a" => "http://test.host/posts/1"}, - %q({"a": "\u003cunicode\u0020escape\u003e"}) => {"a" => "<unicode escape>"}, - %q({"a": "\\\\u0020skip double backslashes"}) => {"a" => "\\u0020skip double backslashes"}, - %q({"a": "\u003cbr /\u003e"}) => {'a' => "<br />"}, - %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => {'b' => ["<i>","<b>","<u>"]}, + %({"a":1}) => { "a" => 1 }, + %({"a": ""}) => { "a" => "" }, + %({"a":"\\""}) => { "a" => "\"" }, + %({"a": null}) => { "a" => nil }, + %({"a": true}) => { "a" => true }, + %({"a": false}) => { "a" => false }, + '{"bad":"\\\\","trailing":""}' => { "bad" => "\\", "trailing" => "" }, + %q({"a": "http:\/\/test.host\/posts\/1"}) => { "a" => "http://test.host/posts/1" }, + %q({"a": "\u003cunicode\u0020escape\u003e"}) => { "a" => "<unicode escape>" }, + '{"a": "\\\\u0020skip double backslashes"}' => { "a" => "\\u0020skip double backslashes" }, + %q({"a": "\u003cbr /\u003e"}) => { "a" => "<br />" }, + %q({"b":["\u003ci\u003e","\u003cb\u003e","\u003cu\u003e"]}) => { "b" => ["<i>","<b>","<u>"] }, # test combination of dates and escaped or unicode encoded data in arrays %q([{"d":"1970-01-01", "s":"\u0020escape"},{"d":"1970-01-01", "s":"\u0020escape"}]) => - [{'d' => Date.new(1970, 1, 1), 's' => ' escape'},{'d' => Date.new(1970, 1, 1), 's' => ' escape'}], + [{ "d" => Date.new(1970, 1, 1), "s" => " escape" },{ "d" => Date.new(1970, 1, 1), "s" => " escape" }], %q([{"d":"1970-01-01","s":"http:\/\/example.com"},{"d":"1970-01-01","s":"http:\/\/example.com"}]) => - [{'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}, - {'d' => Date.new(1970, 1, 1), 's' => 'http://example.com'}], + [{ "d" => Date.new(1970, 1, 1), "s" => "http://example.com" }, + { "d" => Date.new(1970, 1, 1), "s" => "http://example.com" }], # tests escaping of "\n" char with Yaml backend - %q({"a":"\n"}) => {"a"=>"\n"}, - %q({"a":"\u000a"}) => {"a"=>"\n"}, - %q({"a":"Line1\u000aLine2"}) => {"a"=>"Line1\nLine2"}, + %q({"a":"\n"}) => { "a"=>"\n" }, + %q({"a":"\u000a"}) => { "a"=>"\n" }, + %q({"a":"Line1\u000aLine2"}) => { "a"=>"Line1\nLine2" }, # prevent json unmarshalling - %q({"json_class":"TestJSONDecoding::Foo"}) => {"json_class"=>"TestJSONDecoding::Foo"}, + '{"json_class":"TestJSONDecoding::Foo"}' => { "json_class"=>"TestJSONDecoding::Foo" }, # json "fragments" - these are invalid JSON, but ActionPack relies on this - %q("a string") => "a string", - %q(1.1) => 1.1, - %q(1) => 1, - %q(-1) => -1, - %q(true) => true, - %q(false) => false, - %q(null) => nil + '"a string"' => "a string", + "1.1" => 1.1, + "1" => 1, + "-1" => -1, + "true" => true, + "false" => false, + "null" => nil } TESTS.each_with_index do |(json, expected), index| test "json decodes #{index}" do - with_parse_json_times(true) do - silence_warnings do - assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \ - failed for #{json}" + with_tz_default "Eastern Time (US & Canada)" do + with_parse_json_times(true) do + silence_warnings do + assert_equal expected, ActiveSupport::JSON.decode(json), "JSON decoding \ + failed for #{json}" + end end end end @@ -83,7 +89,7 @@ class TestJSONDecoding < ActiveSupport::TestCase test "json decodes time json with time parsing disabled" do with_parse_json_times(false) do - expected = {"a" => "2007-01-01 01:12:34 Z"} + expected = { "a" => "2007-01-01 01:12:34 Z" } assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) end end @@ -101,12 +107,11 @@ class TestJSONDecoding < ActiveSupport::TestCase private - def with_parse_json_times(value) - old_value = ActiveSupport.parse_json_times - ActiveSupport.parse_json_times = value - yield - ensure - ActiveSupport.parse_json_times = old_value - end + def with_parse_json_times(value) + old_value = ActiveSupport.parse_json_times + ActiveSupport.parse_json_times = value + yield + ensure + ActiveSupport.parse_json_times = old_value + end end - diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 5fc2e16336..d125cc939f 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -1,17 +1,21 @@ -require 'securerandom' -require 'abstract_unit' -require 'active_support/core_ext/string/inflections' -require 'active_support/json' -require 'active_support/time' -require 'time_zone_test_helpers' -require 'json/encoding_test_cases' +require "securerandom" +require "abstract_unit" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/regexp" +require "active_support/json" +require "active_support/time" +require "time_zone_test_helpers" +require "json/encoding_test_cases" class TestJSONEncoding < ActiveSupport::TestCase include TimeZoneTestHelpers def sorted_json(json) - return json unless json =~ /^\{.*\}$/ - '{' + json[1..-2].split(',').sort.join(',') + '}' + if json.start_with?("{") && json.end_with?("}") + "{" + json[1..-2].split(",").sort.join(",") + "}" + else + json + end end JSONTest::EncodingTestCases.constants.each do |class_tests| @@ -19,8 +23,10 @@ class TestJSONEncoding < ActiveSupport::TestCase begin prev = ActiveSupport.use_standard_json_time_format - ActiveSupport.escape_html_entities_in_json = class_tests !~ /^Standard/ - ActiveSupport.use_standard_json_time_format = class_tests =~ /^Standard/ + standard_class_tests = /Standard/.match?(class_tests) + + ActiveSupport.escape_html_entities_in_json = !standard_class_tests + ActiveSupport.use_standard_json_time_format = standard_class_tests JSONTest::EncodingTestCases.const_get(class_tests).each do |pair| assert_equal pair.last, sorted_json(ActiveSupport::JSON.encode(pair.first)) end @@ -41,12 +47,12 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_hash_encoding - assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(:a => :b) - assert_equal %({\"a\":1}), ActiveSupport::JSON.encode('a' => 1) - assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode('a' => [1,2]) + assert_equal %({\"a\":\"b\"}), ActiveSupport::JSON.encode(a: :b) + assert_equal %({\"a\":1}), ActiveSupport::JSON.encode("a" => 1) + assert_equal %({\"a\":[1,2]}), ActiveSupport::JSON.encode("a" => [1,2]) assert_equal %({"1":2}), ActiveSupport::JSON.encode(1 => 2) - assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(:a => :b, :c => :d)) + assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(a: :b, c: :d)) end def test_hash_keys_encoding @@ -57,24 +63,24 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_utf8_string_encoded_properly - result = ActiveSupport::JSON.encode('€2.99') + result = ActiveSupport::JSON.encode("€2.99") assert_equal '"€2.99"', result assert_equal(Encoding::UTF_8, result.encoding) - result = ActiveSupport::JSON.encode('✎☺') + result = ActiveSupport::JSON.encode("✎☺") assert_equal '"✎☺"', result assert_equal(Encoding::UTF_8, result.encoding) end def test_non_utf8_string_transcodes - s = '二'.encode('Shift_JIS') + s = "二".encode("Shift_JIS") result = ActiveSupport::JSON.encode(s) assert_equal '"二"', result assert_equal Encoding::UTF_8, result.encoding end def test_wide_utf8_chars - w = '𠜎' + w = "𠜎" result = ActiveSupport::JSON.encode(w) assert_equal '"𠜎"', result end @@ -83,25 +89,25 @@ class TestJSONEncoding < ActiveSupport::TestCase hash = { string: "ð’‘" } json = ActiveSupport::JSON.encode(hash) decoded_hash = ActiveSupport::JSON.decode(json) - assert_equal "ð’‘", decoded_hash['string'] + assert_equal "ð’‘", decoded_hash["string"] end def test_hash_key_identifiers_are_always_quoted - values = {0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B"} + values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" } assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values)) end def test_hash_should_allow_key_filtering_with_only - assert_equal %({"a":1}), ActiveSupport::JSON.encode({'a' => 1, :b => 2, :c => 3}, :only => 'a') + assert_equal %({"a":1}), ActiveSupport::JSON.encode({ "a" => 1, :b => 2, :c => 3 }, only: "a") end def test_hash_should_allow_key_filtering_with_except - assert_equal %({"b":2}), ActiveSupport::JSON.encode({'foo' => 'bar', :b => 2, :c => 3}, :except => ['foo', :c]) + assert_equal %({"b":2}), ActiveSupport::JSON.encode({ "foo" => "bar", :b => 2, :c => 3 }, except: ["foo", :c]) end def test_time_to_json_includes_local_offset with_standard_json_time_format(true) do - with_env_tz 'US/Eastern' do + with_env_tz "US/Eastern" do assert_equal %("2005-02-01T15:15:10.000-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10)) end end @@ -109,7 +115,7 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_hash_with_time_to_json with_standard_json_time_format(false) do - assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { :time => Time.utc(2009) }.to_json + assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { time: Time.utc(2009) }.to_json end end @@ -117,8 +123,8 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_nothing_raised do hash = { "CHI" => { - :display_name => "chicago", - :latitude => 123.234 + display_name: "chicago", + latitude: 123.234 } } ActiveSupport::JSON.encode(hash) @@ -127,64 +133,64 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_hash_like_with_options h = JSONTest::Hashlike.new - json = h.to_json :only => [:foo] + json = h.to_json only: [:foo] - assert_equal({"foo"=>"hello"}, JSON.parse(json)) + assert_equal({ "foo"=>"hello" }, JSON.parse(json)) end def test_object_to_json_with_options obj = Object.new obj.instance_variable_set :@foo, "hello" obj.instance_variable_set :@bar, "world" - json = obj.to_json :only => ["foo"] + json = obj.to_json only: ["foo"] - assert_equal({"foo"=>"hello"}, JSON.parse(json)) + assert_equal({ "foo"=>"hello" }, JSON.parse(json)) end def test_struct_to_json_with_options struct = Struct.new(:foo, :bar).new struct.foo = "hello" struct.bar = "world" - json = struct.to_json :only => [:foo] + json = struct.to_json only: [:foo] - assert_equal({"foo"=>"hello"}, JSON.parse(json)) + assert_equal({ "foo"=>"hello" }, JSON.parse(json)) end def test_hash_should_pass_encoding_options_to_children_in_as_json person = { - :name => 'John', - :address => { - :city => 'London', - :country => 'UK' + name: "John", + address: { + city: "London", + country: "UK" } } - json = person.as_json :only => [:address, :city] + json = person.as_json only: [:address, :city] - assert_equal({ 'address' => { 'city' => 'London' }}, json) + assert_equal({ "address" => { "city" => "London" } }, json) end def test_hash_should_pass_encoding_options_to_children_in_to_json person = { - :name => 'John', - :address => { - :city => 'London', - :country => 'UK' + name: "John", + address: { + city: "London", + country: "UK" } } - json = person.to_json :only => [:address, :city] + json = person.to_json only: [:address, :city] assert_equal(%({"address":{"city":"London"}}), json) end def test_array_should_pass_encoding_options_to_children_in_as_json people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + { name: "John", address: { city: "London", country: "UK" } }, + { name: "Jean", address: { city: "Paris" , country: "France" } } ] - json = people.as_json :only => [:address, :city] + json = people.as_json only: [:address, :city] expected = [ - { 'address' => { 'city' => 'London' }}, - { 'address' => { 'city' => 'Paris' }} + { "address" => { "city" => "London" } }, + { "address" => { "city" => "Paris" } } ] assert_equal(expected, json) @@ -192,10 +198,10 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_array_should_pass_encoding_options_to_children_in_to_json people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + { name: "John", address: { city: "London", country: "UK" } }, + { name: "Jean", address: { city: "Paris" , country: "France" } } ] - json = people.to_json :only => [:address, :city] + json = people.to_json only: [:address, :city] assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end @@ -204,8 +210,8 @@ class TestJSONEncoding < ActiveSupport::TestCase include Enumerable def initialize() @people = [ - { :name => 'John', :address => { :city => 'London', :country => 'UK' }}, - { :name => 'Jean', :address => { :city => 'Paris' , :country => 'France' }} + { name: "John", address: { city: "London", country: "UK" } }, + { name: "Jean", address: { city: "Paris" , country: "France" } } ] end def each(*, &blk) @@ -217,32 +223,32 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_enumerable_should_generate_json_with_as_json - json = People.new.as_json :only => [:address, :city] + json = People.new.as_json only: [:address, :city] expected = [ - { 'address' => { 'city' => 'London' }}, - { 'address' => { 'city' => 'Paris' }} + { "address" => { "city" => "London" } }, + { "address" => { "city" => "Paris" } } ] assert_equal(expected, json) end def test_enumerable_should_generate_json_with_to_json - json = People.new.to_json :only => [:address, :city] + json = People.new.to_json only: [:address, :city] assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end def test_enumerable_should_pass_encoding_options_to_children_in_as_json - json = People.new.each.as_json :only => [:address, :city] + json = People.new.each.as_json only: [:address, :city] expected = [ - { 'address' => { 'city' => 'London' }}, - { 'address' => { 'city' => 'Paris' }} + { "address" => { "city" => "London" } }, + { "address" => { "city" => "Paris" } } ] assert_equal(expected, json) end def test_enumerable_should_pass_encoding_options_to_children_in_to_json - json = People.new.each.to_json :only => [:address, :city] + json = People.new.each.to_json only: [:address, :city] assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end @@ -261,9 +267,9 @@ class TestJSONEncoding < ActiveSupport::TestCase f.foo = "hello" f.bar = "world" - hash = {"foo" => f, "other_hash" => {"foo" => "other_foo", "test" => "other_test"}} - assert_equal({"foo"=>{"foo"=>"hello","bar"=>"world"}, - "other_hash" => {"foo"=>"other_foo","test"=>"other_test"}}, ActiveSupport::JSON.decode(hash.to_json)) + hash = { "foo" => f, "other_hash" => { "foo" => "other_foo", "test" => "other_test" } } + assert_equal({ "foo"=>{ "foo"=>"hello","bar"=>"world" }, + "other_hash" => { "foo"=>"other_foo","test"=>"other_test" } }, ActiveSupport::JSON.decode(hash.to_json)) end def test_array_to_json_should_not_keep_options_around @@ -271,9 +277,9 @@ class TestJSONEncoding < ActiveSupport::TestCase f.foo = "hello" f.bar = "world" - array = [f, {"foo" => "other_foo", "test" => "other_test"}] - assert_equal([{"foo"=>"hello","bar"=>"world"}, - {"foo"=>"other_foo","test"=>"other_test"}], ActiveSupport::JSON.decode(array.to_json)) + array = [f, { "foo" => "other_foo", "test" => "other_test" }] + assert_equal([{ "foo"=>"hello","bar"=>"world" }, + { "foo"=>"other_foo","test"=>"other_test" }], ActiveSupport::JSON.decode(array.to_json)) end class OptionsTest @@ -284,7 +290,7 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_hash_as_json_without_options json = { foo: OptionsTest.new }.as_json - assert_equal({"foo" => :default}, json) + assert_equal({ "foo" => :default }, json) end def test_array_as_json_without_options @@ -293,13 +299,12 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_struct_encoding - Struct.new('UserNameAndEmail', :name, :email) - Struct.new('UserNameAndDate', :name, :date) - Struct.new('Custom', :name, :sub) - user_email = Struct::UserNameAndEmail.new 'David', 'sample@example.com' - user_birthday = Struct::UserNameAndDate.new 'David', Date.new(2010, 01, 01) - custom = Struct::Custom.new 'David', user_birthday - + Struct.new("UserNameAndEmail", :name, :email) + Struct.new("UserNameAndDate", :name, :date) + Struct.new("Custom", :name, :sub) + user_email = Struct::UserNameAndEmail.new "David", "sample@example.com" + user_birthday = Struct::UserNameAndDate.new "David", Date.new(2010, 01, 01) + custom = Struct::Custom.new "David", user_birthday json_strings = "" json_string_and_date = "" @@ -311,15 +316,15 @@ class TestJSONEncoding < ActiveSupport::TestCase json_custom = custom.to_json end - assert_equal({"name" => "David", + assert_equal({ "name" => "David", "sub" => { "name" => "David", - "date" => "2010-01-01" }}, ActiveSupport::JSON.decode(json_custom)) + "date" => "2010-01-01" } }, ActiveSupport::JSON.decode(json_custom)) - assert_equal({"name" => "David", "email" => "sample@example.com"}, + assert_equal({ "name" => "David", "email" => "sample@example.com" }, ActiveSupport::JSON.decode(json_strings)) - assert_equal({"name" => "David", "date" => "2010-01-01"}, + assert_equal({ "name" => "David", "date" => "2010-01-01" }, ActiveSupport::JSON.decode(json_string_and_date)) end @@ -376,7 +381,7 @@ EXPECTED def test_twz_to_json_with_use_standard_json_time_format_config_set_to_false with_standard_json_time_format(false) do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) assert_equal "\"1999/12/31 19:00:00 -0500\"", ActiveSupport::JSON.encode(time) end @@ -384,7 +389,7 @@ EXPECTED def test_twz_to_json_with_use_standard_json_time_format_config_set_to_true with_standard_json_time_format(true) do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(time) end @@ -393,7 +398,7 @@ EXPECTED def test_twz_to_json_with_custom_time_precision with_standard_json_time_format(true) do with_time_precision(0) do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(Time.utc(2000), zone) assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(time) end @@ -417,7 +422,7 @@ EXPECTED end def test_twz_to_json_when_wrapping_a_date_time - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] time = ActiveSupport::TimeWithZone.new(DateTime.new(2000), zone) assert_equal '"1999-12-31T19:00:00.000-05:00"', ActiveSupport::JSON.encode(time) end diff --git a/activesupport/test/json/encoding_test_cases.rb b/activesupport/test/json/encoding_test_cases.rb index 0159ba8606..ff2ed3a788 100644 --- a/activesupport/test/json/encoding_test_cases.rb +++ b/activesupport/test/json/encoding_test_cases.rb @@ -1,4 +1,4 @@ -require 'bigdecimal' +require "bigdecimal" module JSONTest class Foo @@ -9,7 +9,7 @@ module JSONTest class Hashlike def to_hash - { :foo => "hello", :bar => "world" } + { foo: "hello", bar: "world" } end end @@ -39,20 +39,20 @@ module JSONTest [ 0.0/0.0, %(null) ], [ 1.0/0.0, %(null) ], [ -1.0/0.0, %(null) ], - [ BigDecimal('0.0')/BigDecimal('0.0'), %(null) ], - [ BigDecimal('2.5'), %("#{BigDecimal('2.5')}") ]] + [ BigDecimal("0.0")/BigDecimal("0.0"), %(null) ], + [ BigDecimal("2.5"), %("#{BigDecimal('2.5')}") ]] - StringTests = [[ 'this is the <string>', %("this is the \\u003cstring\\u003e")], + StringTests = [[ "this is the <string>", %("this is the \\u003cstring\\u003e")], [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ], - [ 'http://test.host/posts/1', %("http://test.host/posts/1")], + [ "http://test.host/posts/1", %("http://test.host/posts/1")], [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\u2028\u2029", %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\u2028\\u2029") ]] - ArrayTests = [[ ['a', 'b', 'c'], %([\"a\",\"b\",\"c\"]) ], - [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] + ArrayTests = [[ ["a", "b", "c"], %([\"a\",\"b\",\"c\"]) ], + [ [1, "a", :b, nil, false], %([1,\"a\",\"b\",null,false]) ]] - HashTests = [[ {foo: "bar"}, %({\"foo\":\"bar\"}) ], - [ {1 => 1, 2 => 'a', 3 => :b, 4 => nil, 5 => false}, %({\"1\":1,\"2\":\"a\",\"3\":\"b\",\"4\":null,\"5\":false}) ]] + HashTests = [[ { foo: "bar" }, %({\"foo\":\"bar\"}) ], + [ { 1 => 1, 2 => "a", 3 => :b, 4 => nil, 5 => false }, %({\"1\":1,\"2\":\"a\",\"3\":\"b\",\"4\":null,\"5\":false}) ]] RangeTests = [[ 1..2, %("1..2")], [ 1...2, %("1...2")], @@ -67,15 +67,19 @@ module JSONTest StructTests = [[ MyStruct.new(:foo, "bar"), %({\"name\":\"foo\",\"value\":\"bar\"}) ], [ MyStruct.new(nil, nil), %({\"name\":null,\"value\":null}) ]] CustomTests = [[ Custom.new("custom"), '"custom"' ], - [ Custom.new(nil), 'null' ], + [ Custom.new(nil), "null" ], [ Custom.new(:a), '"a"' ], [ Custom.new([ :foo, "bar" ]), '["foo","bar"]' ], - [ Custom.new({ :foo => "hello", :bar => "world" }), '{"bar":"world","foo":"hello"}' ], + [ Custom.new(foo: "hello", bar: "world"), '{"bar":"world","foo":"hello"}' ], [ Custom.new(Hashlike.new), '{"bar":"world","foo":"hello"}' ], [ Custom.new(Custom.new(Custom.new(:a))), '"a"' ]] RegexpTests = [[ /^a/, '"(?-mix:^a)"' ], [/^\w{1,2}[a-z]+/ix, '"(?ix-m:^\\\\w{1,2}[a-z]+)"']] + URITests = [[ URI.parse("http://example.com"), %("http://example.com") ]] + + PathnameTests = [[ Pathname.new("lib/index.rb"), %("lib/index.rb") ]] + DateTests = [[ Date.new(2005,2,1), %("2005/02/01") ]] TimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]] DateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]] @@ -83,6 +87,6 @@ module JSONTest StandardDateTests = [[ Date.new(2005,2,1), %("2005-02-01") ]] StandardTimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000Z") ]] StandardDateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005-02-01T15:15:10.000+00:00") ]] - StandardStringTests = [[ 'this is the <string>', %("this is the <string>")]] + StandardStringTests = [[ "this is the <string>", %("this is the <string>")]] end end diff --git a/activesupport/test/key_generator_test.rb b/activesupport/test/key_generator_test.rb index f7e8e9a795..89db9563ac 100644 --- a/activesupport/test/key_generator_test.rb +++ b/activesupport/test/key_generator_test.rb @@ -1,62 +1,77 @@ -require 'abstract_unit' +require "abstract_unit" begin - require 'openssl' + require "openssl" OpenSSL::PKCS5 rescue LoadError, NameError $stderr.puts "Skipping KeyGenerator test: broken OpenSSL install" else -require 'active_support/time' -require 'active_support/json' + require "active_support/time" + require "active_support/json" -class KeyGeneratorTest < ActiveSupport::TestCase - def setup - @secret = SecureRandom.hex(64) - @generator = ActiveSupport::KeyGenerator.new(@secret, :iterations=>2) - end + class KeyGeneratorTest < ActiveSupport::TestCase + def setup + @secret = SecureRandom.hex(64) + @generator = ActiveSupport::KeyGenerator.new(@secret, iterations: 2) + end - test "Generating a key of the default length" do - derived_key = @generator.generate_key("some_salt") - assert_kind_of String, derived_key - assert_equal OpenSSL::Digest::SHA1.new.block_length, derived_key.length, "Should have generated a key of the default size" - end + test "Generating a key of the default length" do + derived_key = @generator.generate_key("some_salt") + assert_kind_of String, derived_key + assert_equal 64, derived_key.length, "Should have generated a key of the default size" + end - test "Generating a key of an alternative length" do - derived_key = @generator.generate_key("some_salt", 32) - assert_kind_of String, derived_key - assert_equal 32, derived_key.length, "Should have generated a key of the right size" - end -end + test "Generating a key of an alternative length" do + derived_key = @generator.generate_key("some_salt", 32) + assert_kind_of String, derived_key + assert_equal 32, derived_key.length, "Should have generated a key of the right size" + end -class CachingKeyGeneratorTest < ActiveSupport::TestCase - def setup - @secret = SecureRandom.hex(64) - @generator = ActiveSupport::KeyGenerator.new(@secret, :iterations=>2) - @caching_generator = ActiveSupport::CachingKeyGenerator.new(@generator) - end + test "Expected results" do + # For any given set of inputs, this method must continue to return + # the same output: if it changes, any existing values relying on a + # key would break. + + expected = "b129376f68f1ecae788d7433310249d65ceec090ecacd4c872a3a9e9ec78e055739be5cc6956345d5ae38e7e1daa66f1de587dc8da2bf9e8b965af4b3918a122" + assert_equal expected, ActiveSupport::KeyGenerator.new("0" * 64).generate_key("some_salt").unpack("H*").first - test "Generating a cached key for same salt and key size" do - derived_key = @caching_generator.generate_key("some_salt", 32) - cached_key = @caching_generator.generate_key("some_salt", 32) + expected = "b129376f68f1ecae788d7433310249d65ceec090ecacd4c872a3a9e9ec78e055" + assert_equal expected, ActiveSupport::KeyGenerator.new("0" * 64).generate_key("some_salt", 32).unpack("H*").first - assert_equal derived_key, cached_key - assert_equal derived_key.object_id, cached_key.object_id + expected = "cbea7f7f47df705967dc508f4e446fd99e7797b1d70011c6899cd39bbe62907b8508337d678505a7dc8184e037f1003ba3d19fc5d829454668e91d2518692eae" + assert_equal expected, ActiveSupport::KeyGenerator.new("0" * 64, iterations: 2).generate_key("some_salt").unpack("H*").first + end end - test "Does not cache key for different salt" do - derived_key = @caching_generator.generate_key("some_salt", 32) - different_salt_key = @caching_generator.generate_key("other_salt", 32) + class CachingKeyGeneratorTest < ActiveSupport::TestCase + def setup + @secret = SecureRandom.hex(64) + @generator = ActiveSupport::KeyGenerator.new(@secret, iterations: 2) + @caching_generator = ActiveSupport::CachingKeyGenerator.new(@generator) + end - assert_not_equal derived_key, different_salt_key - end + test "Generating a cached key for same salt and key size" do + derived_key = @caching_generator.generate_key("some_salt", 32) + cached_key = @caching_generator.generate_key("some_salt", 32) + + assert_equal derived_key, cached_key + assert_equal derived_key.object_id, cached_key.object_id + end + + test "Does not cache key for different salt" do + derived_key = @caching_generator.generate_key("some_salt", 32) + different_salt_key = @caching_generator.generate_key("other_salt", 32) - test "Does not cache key for different length" do - derived_key = @caching_generator.generate_key("some_salt", 32) - different_length_key = @caching_generator.generate_key("some_salt", 64) + assert_not_equal derived_key, different_salt_key + end - assert_not_equal derived_key, different_length_key + test "Does not cache key for different length" do + derived_key = @caching_generator.generate_key("some_salt", 32) + different_length_key = @caching_generator.generate_key("some_salt", 64) + + assert_not_equal derived_key, different_length_key + end end -end end diff --git a/activesupport/test/lazy_load_hooks_test.rb b/activesupport/test/lazy_load_hooks_test.rb index 7851634dbf..3b1959a1c9 100644 --- a/activesupport/test/lazy_load_hooks_test.rb +++ b/activesupport/test/lazy_load_hooks_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class LazyLoadHooksTest < ActiveSupport::TestCase def test_basic_hook @@ -63,7 +63,7 @@ class LazyLoadHooksTest < ActiveSupport::TestCase def test_hook_with_yield_true i = 0 - ActiveSupport.on_load(:contextual_yield, :yield => true) do |obj| + ActiveSupport.on_load(:contextual_yield, yield: true) do |obj| i += obj.incr + incr_amt end assert_equal 0, i @@ -75,7 +75,7 @@ class LazyLoadHooksTest < ActiveSupport::TestCase i = 0 ActiveSupport.run_load_hooks(:contextual_yield_after, FakeContext.new(2)) assert_equal 0, i - ActiveSupport.on_load(:contextual_yield_after, :yield => true) do |obj| + ActiveSupport.on_load(:contextual_yield_after, yield: true) do |obj| i += obj.incr + incr_amt end assert_equal 7, i @@ -93,4 +93,4 @@ private @incr = incr end end -end
\ No newline at end of file +end diff --git a/activesupport/test/load_paths_test.rb b/activesupport/test/load_paths_test.rb deleted file mode 100644 index ac617a9fd8..0000000000 --- a/activesupport/test/load_paths_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'abstract_unit' - -class LoadPathsTest < ActiveSupport::TestCase - def test_uniq_load_paths - load_paths_count = $LOAD_PATH.inject({}) { |paths, path| - expanded_path = File.expand_path(path) - paths[expanded_path] ||= 0 - paths[expanded_path] += 1 - paths - } - load_paths_count[File.expand_path('../../lib', __FILE__)] -= 1 - - load_paths_count.select! { |k, v| v > 1 } - assert load_paths_count.empty?, load_paths_count.inspect - end -end diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb index 998a6887c5..f6496ef7d6 100644 --- a/activesupport/test/log_subscriber_test.rb +++ b/activesupport/test/log_subscriber_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/log_subscriber/test_helper' +require "abstract_unit" +require "active_support/log_subscriber/test_helper" class MyLogSubscriber < ActiveSupport::LogSubscriber attr_reader :event @@ -116,7 +116,7 @@ class SyncLogSubscriberTest < ActiveSupport::TestCase wait assert_equal 1, @logger.logged(:info).size - assert_equal 'some_event.my_log_subscriber', @logger.logged(:info).last + assert_equal "some_event.my_log_subscriber", @logger.logged(:info).last assert_equal 1, @logger.logged(:error).size assert_match 'Could not log "puke.my_log_subscriber" event. RuntimeError: puke', @logger.logged(:error).last diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb index dfc5f3fdf4..3f04783401 100644 --- a/activesupport/test/logger_test.rb +++ b/activesupport/test/logger_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'multibyte_test_helpers' -require 'stringio' -require 'fileutils' -require 'tempfile' -require 'concurrent/atomics' +require "abstract_unit" +require "multibyte_test_helpers" +require "stringio" +require "fileutils" +require "tempfile" +require "concurrent/atomics" class LoggerTest < ActiveSupport::TestCase include MultibyteTestHelpers @@ -26,12 +26,12 @@ class LoggerTest < ActiveSupport::TestCase end def test_write_binary_data_to_existing_file - t = Tempfile.new ['development', 'log'] + t = Tempfile.new ["development", "log"] t.binmode - t.write 'hi mom!' + t.write "hi mom!" t.close - f = File.open(t.path, 'w') + f = File.open(t.path, "w") f.binmode logger = Logger.new f @@ -47,9 +47,9 @@ class LoggerTest < ActiveSupport::TestCase end def test_write_binary_data_create_file - fname = File.join Dir.tmpdir, 'lol', 'rofl.log' + fname = File.join Dir.tmpdir, "lol", "rofl.log" FileUtils.mkdir_p File.dirname(fname) - f = File.open(fname, 'w') + f = File.open(fname, "w") f.binmode logger = Logger.new f @@ -67,7 +67,7 @@ class LoggerTest < ActiveSupport::TestCase def test_should_log_debugging_message_when_debugging @logger.level = Logger::DEBUG @logger.add(Logger::DEBUG, @message) - assert @output.string.include?(@message) + assert_includes @output.string, @message end def test_should_not_log_debug_messages_when_log_level_is_info @@ -78,32 +78,32 @@ class LoggerTest < ActiveSupport::TestCase def test_should_add_message_passed_as_block_when_using_add @logger.level = Logger::INFO - @logger.add(Logger::INFO) {@message} - assert @output.string.include?(@message) + @logger.add(Logger::INFO) { @message } + assert_includes @output.string, @message end def test_should_add_message_passed_as_block_when_using_shortcut @logger.level = Logger::INFO - @logger.info {@message} - assert @output.string.include?(@message) + @logger.info { @message } + assert_includes @output.string, @message end def test_should_convert_message_to_string @logger.level = Logger::INFO @logger.info @integer_message - assert @output.string.include?(@integer_message.to_s) + assert_includes @output.string, @integer_message.to_s end def test_should_convert_message_to_string_when_passed_in_block @logger.level = Logger::INFO - @logger.info {@integer_message} - assert @output.string.include?(@integer_message.to_s) + @logger.info { @integer_message } + assert_includes @output.string, @integer_message.to_s end def test_should_not_evaluate_block_if_message_wont_be_logged @logger.level = Logger::INFO evaluated = false - @logger.add(Logger::DEBUG) {evaluated = true} + @logger.add(Logger::DEBUG) { evaluated = true } assert evaluated == false end @@ -115,7 +115,7 @@ class LoggerTest < ActiveSupport::TestCase def test_should_know_if_its_loglevel_is_below_a_given_level Logger::Severity.constants.each do |level| - next if level.to_s == 'UNKNOWN' + next if level.to_s == "UNKNOWN" @logger.level = Logger::Severity.const_get(level) - 1 assert @logger.send("#{level.downcase}?"), "didn't know if it was #{level.downcase}? or below" end @@ -125,10 +125,10 @@ class LoggerTest < ActiveSupport::TestCase @logger.level = Logger::INFO @logger.info(UNICODE_STRING) @logger.info(BYTE_STRING) - assert @output.string.include?(UNICODE_STRING) + assert_includes @output.string, UNICODE_STRING byte_string = @output.string.dup byte_string.force_encoding("ASCII-8BIT") - assert byte_string.include?(BYTE_STRING) + assert_includes byte_string, BYTE_STRING end def test_silencing_everything_but_errors @@ -138,7 +138,7 @@ class LoggerTest < ActiveSupport::TestCase end assert_not @output.string.include?("NOT THERE") - assert @output.string.include?("THIS IS HERE") + assert_includes @output.string, "THIS IS HERE" end def test_logger_silencing_works_for_broadcast @@ -154,12 +154,12 @@ class LoggerTest < ActiveSupport::TestCase @logger.error "CORRECT ERROR" end - assert @output.string.include?("CORRECT DEBUG") - assert @output.string.include?("CORRECT ERROR") + assert_includes @output.string, "CORRECT DEBUG" + assert_includes @output.string, "CORRECT ERROR" assert_not @output.string.include?("FAILURE") - assert another_output.string.include?("CORRECT DEBUG") - assert another_output.string.include?("CORRECT ERROR") + assert_includes another_output.string, "CORRECT DEBUG" + assert_includes another_output.string, "CORRECT ERROR" assert_not another_output.string.include?("FAILURE") end @@ -176,13 +176,13 @@ class LoggerTest < ActiveSupport::TestCase @logger.error "CORRECT ERROR" end - assert @output.string.include?("CORRECT DEBUG") - assert @output.string.include?("CORRECT ERROR") + assert_includes @output.string, "CORRECT DEBUG" + assert_includes @output.string, "CORRECT ERROR" assert_not @output.string.include?("FAILURE") - assert another_output.string.include?("CORRECT DEBUG") - assert another_output.string.include?("CORRECT ERROR") - assert another_output.string.include?("FAILURE") + assert_includes another_output.string, "CORRECT DEBUG" + assert_includes another_output.string, "CORRECT ERROR" + assert_includes another_output.string, "FAILURE" # We can't silence plain ruby Logger cause with thread safety # but at least we don't break it end diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index eb71369397..f8282c89ca 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -1,7 +1,7 @@ -require 'abstract_unit' -require 'openssl' -require 'active_support/time' -require 'active_support/json' +require "abstract_unit" +require "openssl" +require "active_support/time" +require "active_support/json" class MessageEncryptorTest < ActiveSupport::TestCase class JSONSerializer @@ -15,10 +15,10 @@ class MessageEncryptorTest < ActiveSupport::TestCase end def setup - @secret = SecureRandom.hex(64) - @verifier = ActiveSupport::MessageVerifier.new(@secret, :serializer => ActiveSupport::MessageEncryptor::NullSerializer) + @secret = SecureRandom.random_bytes(32) + @verifier = ActiveSupport::MessageVerifier.new(@secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer) @encryptor = ActiveSupport::MessageEncryptor.new(@secret) - @data = { :some => "data", :now => Time.local(2010) } + @data = { some: "data", now: Time.local(2010) } end def test_encrypting_twice_yields_differing_cipher_text @@ -48,11 +48,21 @@ class MessageEncryptorTest < ActiveSupport::TestCase assert_equal @data, @encryptor.decrypt_and_verify(message) end + def test_backwards_compat_for_64_bytes_key + # 64 bit key + secret = ["3942b1bf81e622559ed509e3ff274a780784fe9e75b065866bd270438c74da822219de3156473cc27df1fd590e4baf68c95eeb537b6e4d4c5a10f41635b5597e"].pack("H*") + # Encryptor with 32 bit key, 64 bit secret for verifier + encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], secret) + # Message generated with 64 bit key + message = "eHdGeExnZEwvMSt3U3dKaFl1WFo0TjVvYzA0eGpjbm5WSkt5MXlsNzhpZ0ZnbWhBWFlQZTRwaXE1bVJCS2oxMDZhYVp2dVN3V0lNZUlWQ3c2eVhQbnhnVjFmeVVubmhRKzF3WnZyWHVNMDg9LS1HSisyakJVSFlPb05ISzRMaXRzcFdBPT0=--831a1d54a3cda8a0658dc668a03dedcbce13b5ca" + assert_equal "data", encryptor.decrypt_and_verify(message)[:some] + end + def test_alternative_serialization_method prev = ActiveSupport.use_standard_json_time_format ActiveSupport.use_standard_json_time_format = true - encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.hex(64), SecureRandom.hex(64), :serializer => JSONSerializer.new) - message = encryptor.encrypt_and_sign({ :foo => 123, 'bar' => Time.utc(2010) }) + encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.random_bytes(32), SecureRandom.random_bytes(128), serializer: JSONSerializer.new) + message = encryptor.encrypt_and_sign(:foo => 123, "bar" => Time.utc(2010)) exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00.000Z" } assert_equal exp, encryptor.decrypt_and_verify(message) ensure @@ -70,23 +80,41 @@ class MessageEncryptorTest < ActiveSupport::TestCase assert_not_verified([iv, message] * bad_encoding_characters) end + def test_aead_mode_encryption + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + message = encryptor.encrypt_and_sign(@data) + assert_equal @data, encryptor.decrypt_and_verify(message) + end + + def test_messing_with_aead_values_causes_failures + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + text, iv, auth_tag = encryptor.encrypt_and_sign(@data).split("--") + assert_not_decrypted([iv, text, auth_tag] * "--") + assert_not_decrypted([munge(text), iv, auth_tag] * "--") + assert_not_decrypted([text, munge(iv), auth_tag] * "--") + assert_not_decrypted([text, iv, munge(auth_tag)] * "--") + assert_not_decrypted([munge(text), munge(iv), munge(auth_tag)] * "--") + assert_not_decrypted([text, iv] * "--") + assert_not_decrypted([text, iv, auth_tag[0..-2]] * "--") + end + private - def assert_not_decrypted(value) - assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do - @encryptor.decrypt_and_verify(@verifier.generate(value)) + def assert_not_decrypted(value) + assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do + @encryptor.decrypt_and_verify(@verifier.generate(value)) + end end - end - def assert_not_verified(value) - assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do - @encryptor.decrypt_and_verify(value) + def assert_not_verified(value) + assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do + @encryptor.decrypt_and_verify(value) + end end - end - def munge(base64_string) - bits = ::Base64.strict_decode64(base64_string) - bits.reverse! - ::Base64.strict_encode64(bits) - end + def munge(base64_string) + bits = ::Base64.strict_decode64(base64_string) + bits.reverse! + ::Base64.strict_encode64(bits) + end end diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index 668d78492e..d56a46b250 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -1,10 +1,9 @@ -require 'abstract_unit' -require 'openssl' -require 'active_support/time' -require 'active_support/json' +require "abstract_unit" +require "openssl" +require "active_support/time" +require "active_support/json" class MessageVerifierTest < ActiveSupport::TestCase - class JSONSerializer def dump(value) ActiveSupport::JSON.encode(value) @@ -17,7 +16,7 @@ class MessageVerifierTest < ActiveSupport::TestCase def setup @verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!") - @data = { :some => "data", :now => Time.local(2010) } + @data = { some: "data", now: Time.local(2010) } end def test_valid_message @@ -49,8 +48,8 @@ class MessageVerifierTest < ActiveSupport::TestCase def test_alternative_serialization_method prev = ActiveSupport.use_standard_json_time_format ActiveSupport.use_standard_json_time_format = true - verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", :serializer => JSONSerializer.new) - message = verifier.generate({ :foo => 123, 'bar' => Time.utc(2010) }) + verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", serializer: JSONSerializer.new) + message = verifier.generate(:foo => 123, "bar" => Time.utc(2010)) exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00.000Z" } assert_equal exp, verifier.verified(message) assert_equal exp, verifier.verify(message) @@ -81,6 +80,6 @@ class MessageVerifierTest < ActiveSupport::TestCase exception = assert_raise(ArgumentError) do ActiveSupport::MessageVerifier.new(nil) end - assert_equal exception.message, 'Secret should not be nil.' + assert_equal exception.message, "Secret should not be nil." end end diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index c1e0b19248..5ff1543328 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'multibyte_test_helpers' -require 'active_support/core_ext/string/multibyte' +require "abstract_unit" +require "multibyte_test_helpers" +require "active_support/core_ext/string/multibyte" class MultibyteCharsTest < ActiveSupport::TestCase include MultibyteTestHelpers @@ -16,7 +16,7 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_should_allow_method_calls_to_string - @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; 'result'; end } + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; "result"; end } assert_nothing_raised do @chars.__method_for_multibyte_testing @@ -27,14 +27,14 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_forwarded_method_calls_should_return_new_chars_instance - @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; 'result'; end } + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing; "result"; end } assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing assert_not_equal @chars.object_id, @chars.__method_for_multibyte_testing.object_id end def test_forwarded_bang_method_calls_should_return_the_original_chars_instance_when_result_is_not_nil - @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing!; 'result'; end } + @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing!; "result"; end } assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing! assert_equal @chars.object_id, @chars.__method_for_multibyte_testing!.object_id @@ -51,7 +51,7 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_forwarded_method_with_non_string_result_should_be_returned_vertabim - str = '' + str = "" str.singleton_class.class_eval { def __method_for_multibyte_testing_with_integer_result; 1; end } @chars.wrapped_string.singleton_class.class_eval { def __method_for_multibyte_testing_with_integer_result; 1; end } @@ -59,15 +59,15 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_should_concatenate - mb_a = 'a'.mb_chars - mb_b = 'b'.mb_chars - assert_equal 'ab', mb_a + 'b' - assert_equal 'ab', 'a' + mb_b - assert_equal 'ab', mb_a + mb_b + mb_a = "a".mb_chars + mb_b = "b".mb_chars + assert_equal "ab", mb_a + "b" + assert_equal "ab", "a" + mb_b + assert_equal "ab", mb_a + mb_b - assert_equal 'ab', mb_a << 'b' - assert_equal 'ab', 'a' << mb_b - assert_equal 'abb', mb_a << mb_b + assert_equal "ab", mb_a << "b" + assert_equal "ab", "a" << mb_b + assert_equal "abb", mb_a << mb_b end def test_consumes_utf8_strings @@ -77,8 +77,8 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_concatenation_should_return_a_proxy_class_instance - assert_equal ActiveSupport::Multibyte.proxy_class, ('a'.mb_chars + 'b').class - assert_equal ActiveSupport::Multibyte.proxy_class, ('a'.mb_chars << 'b').class + assert_equal ActiveSupport::Multibyte.proxy_class, ("a".mb_chars + "b").class + assert_equal ActiveSupport::Multibyte.proxy_class, ("a".mb_chars << "b").class end def test_ascii_strings_are_treated_at_utf8_strings @@ -86,10 +86,10 @@ class MultibyteCharsTest < ActiveSupport::TestCase end def test_concatenate_should_return_proxy_instance - assert(('a'.mb_chars + 'b').kind_of?(@proxy_class)) - assert(('a'.mb_chars + 'b'.mb_chars).kind_of?(@proxy_class)) - assert(('a'.mb_chars << 'b').kind_of?(@proxy_class)) - assert(('a'.mb_chars << 'b'.mb_chars).kind_of?(@proxy_class)) + assert(("a".mb_chars + "b").kind_of?(@proxy_class)) + assert(("a".mb_chars + "b".mb_chars).kind_of?(@proxy_class)) + assert(("a".mb_chars << "b").kind_of?(@proxy_class)) + assert(("a".mb_chars << "b".mb_chars).kind_of?(@proxy_class)) end def test_should_return_string_as_json @@ -150,24 +150,24 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_string_methods_are_chainable - assert chars('').insert(0, '').kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').rjust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').ljust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').center(1).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').rstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').lstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').strip.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').reverse.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars(' ').slice(0).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').limit(0).kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').upcase.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').downcase.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').capitalize.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').normalize.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').decompose.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').compose.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').tidy_bytes.kind_of?(ActiveSupport::Multibyte.proxy_class) - assert chars('').swapcase.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").insert(0, "").kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").rjust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").ljust(1).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").center(1).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").rstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").lstrip.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").strip.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").reverse.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars(" ").slice(0).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").limit(0).kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").upcase.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").downcase.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").capitalize.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").normalize.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").decompose.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").compose.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").tidy_bytes.kind_of?(ActiveSupport::Multibyte.proxy_class) + assert chars("").swapcase.kind_of?(ActiveSupport::Multibyte.proxy_class) end def test_should_be_equal_to_the_wrapped_string @@ -176,8 +176,8 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_should_not_be_equal_to_an_other_string - assert_not_equal @chars, 'other' - assert_not_equal 'other', @chars + assert_not_equal @chars, "other" + assert_not_equal "other", @chars end def test_sortability @@ -195,29 +195,29 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_should_use_character_offsets_for_insert_offsets - assert_equal '', ''.mb_chars.insert(0, '') - assert_equal 'ã“ã‚ã«ã¡ã‚', @chars.insert(1, 'ã‚') - assert_equal 'ã“ã‚ã‚ã‚ã«ã¡ã‚', @chars.insert(2, 'ã‚ã‚') - assert_equal 'ã‚ã“ã‚ã‚ã‚ã«ã¡ã‚', @chars.insert(0, 'ã‚') - assert_equal 'ã‚ã“ã‚ã‚ã‚ã«ã¡ã‚', @chars.wrapped_string + assert_equal "", "".mb_chars.insert(0, "") + assert_equal "ã“ã‚ã«ã¡ã‚", @chars.insert(1, "ã‚") + assert_equal "ã“ã‚ã‚ã‚ã«ã¡ã‚", @chars.insert(2, "ã‚ã‚") + assert_equal "ã‚ã“ã‚ã‚ã‚ã«ã¡ã‚", @chars.insert(0, "ã‚") + assert_equal "ã‚ã“ã‚ã‚ã‚ã«ã¡ã‚", @chars.wrapped_string end def test_insert_should_be_destructive - @chars.insert(1, 'ã‚') - assert_equal 'ã“ã‚ã«ã¡ã‚', @chars + @chars.insert(1, "ã‚") + assert_equal "ã“ã‚ã«ã¡ã‚", @chars end def test_insert_throws_index_error - assert_raise(IndexError) { @chars.insert(-12, 'ã‚')} - assert_raise(IndexError) { @chars.insert(12, 'ã‚') } + assert_raise(IndexError) { @chars.insert(-12, "ã‚") } + assert_raise(IndexError) { @chars.insert(12, "ã‚") } end def test_should_know_if_one_includes_the_other - assert @chars.include?('') - assert @chars.include?('ã¡') - assert @chars.include?('ã‚') - assert !@chars.include?('ã“ã¡ã‚') - assert !@chars.include?('a') + assert_includes @chars, "" + assert_includes @chars, "ã¡" + assert_includes @chars, "ã‚" + assert_not_includes @chars, "ã“ã¡ã‚" + assert_not_includes @chars, "a" end def test_include_raises_when_nil_is_passed @@ -227,62 +227,62 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_index_should_return_character_offset - assert_nil @chars.index('u') - assert_equal 0, @chars.index('ã“ã«') - assert_equal 2, @chars.index('ã¡') - assert_equal 2, @chars.index('ã¡', -2) - assert_equal nil, @chars.index('ã¡', -1) - assert_equal 3, @chars.index('ã‚') - assert_equal 5, 'ééxééx'.mb_chars.index('x', 4) + assert_nil @chars.index("u") + assert_equal 0, @chars.index("ã“ã«") + assert_equal 2, @chars.index("ã¡") + assert_equal 2, @chars.index("ã¡", -2) + assert_equal nil, @chars.index("ã¡", -1) + assert_equal 3, @chars.index("ã‚") + assert_equal 5, "ééxééx".mb_chars.index("x", 4) end def test_rindex_should_return_character_offset - assert_nil @chars.rindex('u') - assert_equal 1, @chars.rindex('ã«') - assert_equal 2, @chars.rindex('ã¡', -2) - assert_nil @chars.rindex('ã¡', -3) - assert_equal 6, 'Café périferôl'.mb_chars.rindex('é') - assert_equal 13, 'Café périferôl'.mb_chars.rindex(/\w/u) + assert_nil @chars.rindex("u") + assert_equal 1, @chars.rindex("ã«") + assert_equal 2, @chars.rindex("ã¡", -2) + assert_nil @chars.rindex("ã¡", -3) + assert_equal 6, "Café périferôl".mb_chars.rindex("é") + assert_equal 13, "Café périferôl".mb_chars.rindex(/\w/u) end def test_indexed_insert_should_take_character_offsets - @chars[2] = 'a' - assert_equal 'ã“ã«aã‚', @chars - @chars[2] = 'ηη' - assert_equal 'ã“ã«Î·Î·ã‚', @chars - @chars[3, 2] = 'λλλ' - assert_equal 'ã“ã«Î·Î»Î»Î»', @chars + @chars[2] = "a" + assert_equal "ã“ã«aã‚", @chars + @chars[2] = "ηη" + assert_equal "ã“ã«Î·Î·ã‚", @chars + @chars[3, 2] = "λλλ" + assert_equal "ã“ã«Î·Î»Î»Î»", @chars @chars[1, 0] = "λ" - assert_equal 'ã“λã«Î·Î»Î»Î»', @chars + assert_equal "ã“λã«Î·Î»Î»Î»", @chars @chars[4..6] = "ηη" - assert_equal 'ã“λã«Î·Î·Î·', @chars + assert_equal "ã“λã«Î·Î·Î·", @chars @chars[/ηη/] = "λλλ" - assert_equal 'ã“λã«Î»Î»Î»Î·', @chars + assert_equal "ã“λã«Î»Î»Î»Î·", @chars @chars[/(λλ)(.)/, 2] = "α" - assert_equal 'ã“λã«Î»Î»Î±Î·', @chars + assert_equal "ã“λã«Î»Î»Î±Î·", @chars @chars["α"] = "¢" - assert_equal 'ã“λã«Î»Î»Â¢Î·', @chars + assert_equal "ã“λã«Î»Î»Â¢Î·", @chars @chars["λλ"] = "ααα" - assert_equal 'ã“λã«Î±Î±Î±Â¢Î·', @chars + assert_equal "ã“λã«Î±Î±Î±Â¢Î·", @chars end def test_indexed_insert_should_raise_on_index_overflow before = @chars.to_s - assert_raise(IndexError) { @chars[10] = 'a' } - assert_raise(IndexError) { @chars[10, 4] = 'a' } - assert_raise(IndexError) { @chars[/ii/] = 'a' } - assert_raise(IndexError) { @chars[/()/, 10] = 'a' } + assert_raise(IndexError) { @chars[10] = "a" } + assert_raise(IndexError) { @chars[10, 4] = "a" } + assert_raise(IndexError) { @chars[/ii/] = "a" } + assert_raise(IndexError) { @chars[/()/, 10] = "a" } assert_equal before, @chars end def test_indexed_insert_should_raise_on_range_overflow before = @chars.to_s - assert_raise(RangeError) { @chars[10..12] = 'a' } + assert_raise(RangeError) { @chars[10..12] = "a" } assert_equal before, @chars end def test_rjust_should_raise_argument_errors_on_bad_arguments - assert_raise(ArgumentError) { @chars.rjust(10, '') } + assert_raise(ArgumentError) { @chars.rjust(10, "") } assert_raise(ArgumentError) { @chars.rjust } end @@ -292,15 +292,15 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert_equal UNICODE_STRING, @chars.rjust(4) assert_equal " #{UNICODE_STRING}", @chars.rjust(5) assert_equal " #{UNICODE_STRING}", @chars.rjust(7) - assert_equal "---#{UNICODE_STRING}", @chars.rjust(7, '-') - assert_equal "ααα#{UNICODE_STRING}", @chars.rjust(7, 'α') - assert_equal "aba#{UNICODE_STRING}", @chars.rjust(7, 'ab') - assert_equal "αηα#{UNICODE_STRING}", @chars.rjust(7, 'αη') - assert_equal "αηαη#{UNICODE_STRING}", @chars.rjust(8, 'αη') + assert_equal "---#{UNICODE_STRING}", @chars.rjust(7, "-") + assert_equal "ααα#{UNICODE_STRING}", @chars.rjust(7, "α") + assert_equal "aba#{UNICODE_STRING}", @chars.rjust(7, "ab") + assert_equal "αηα#{UNICODE_STRING}", @chars.rjust(7, "αη") + assert_equal "αηαη#{UNICODE_STRING}", @chars.rjust(8, "αη") end def test_ljust_should_raise_argument_errors_on_bad_arguments - assert_raise(ArgumentError) { @chars.ljust(10, '') } + assert_raise(ArgumentError) { @chars.ljust(10, "") } assert_raise(ArgumentError) { @chars.ljust } end @@ -310,15 +310,15 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert_equal UNICODE_STRING, @chars.ljust(4) assert_equal "#{UNICODE_STRING} ", @chars.ljust(5) assert_equal "#{UNICODE_STRING} ", @chars.ljust(7) - assert_equal "#{UNICODE_STRING}---", @chars.ljust(7, '-') - assert_equal "#{UNICODE_STRING}ααα", @chars.ljust(7, 'α') - assert_equal "#{UNICODE_STRING}aba", @chars.ljust(7, 'ab') - assert_equal "#{UNICODE_STRING}αηα", @chars.ljust(7, 'αη') - assert_equal "#{UNICODE_STRING}αηαη", @chars.ljust(8, 'αη') + assert_equal "#{UNICODE_STRING}---", @chars.ljust(7, "-") + assert_equal "#{UNICODE_STRING}ααα", @chars.ljust(7, "α") + assert_equal "#{UNICODE_STRING}aba", @chars.ljust(7, "ab") + assert_equal "#{UNICODE_STRING}αηα", @chars.ljust(7, "αη") + assert_equal "#{UNICODE_STRING}αηαη", @chars.ljust(8, "αη") end def test_center_should_raise_argument_errors_on_bad_arguments - assert_raise(ArgumentError) { @chars.center(10, '') } + assert_raise(ArgumentError) { @chars.center(10, "") } assert_raise(ArgumentError) { @chars.center } end @@ -329,15 +329,15 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert_equal "#{UNICODE_STRING} ", @chars.center(5) assert_equal " #{UNICODE_STRING} ", @chars.center(6) assert_equal " #{UNICODE_STRING} ", @chars.center(7) - assert_equal "--#{UNICODE_STRING}--", @chars.center(8, '-') - assert_equal "--#{UNICODE_STRING}---", @chars.center(9, '-') - assert_equal "αα#{UNICODE_STRING}αα", @chars.center(8, 'α') - assert_equal "αα#{UNICODE_STRING}ααα", @chars.center(9, 'α') - assert_equal "a#{UNICODE_STRING}ab", @chars.center(7, 'ab') - assert_equal "ab#{UNICODE_STRING}ab", @chars.center(8, 'ab') - assert_equal "abab#{UNICODE_STRING}abab", @chars.center(12, 'ab') - assert_equal "α#{UNICODE_STRING}αη", @chars.center(7, 'αη') - assert_equal "αη#{UNICODE_STRING}αη", @chars.center(8, 'αη') + assert_equal "--#{UNICODE_STRING}--", @chars.center(8, "-") + assert_equal "--#{UNICODE_STRING}---", @chars.center(9, "-") + assert_equal "αα#{UNICODE_STRING}αα", @chars.center(8, "α") + assert_equal "αα#{UNICODE_STRING}ααα", @chars.center(9, "α") + assert_equal "a#{UNICODE_STRING}ab", @chars.center(7, "ab") + assert_equal "ab#{UNICODE_STRING}ab", @chars.center(8, "ab") + assert_equal "abab#{UNICODE_STRING}abab", @chars.center(12, "ab") + assert_equal "α#{UNICODE_STRING}αη", @chars.center(7, "αη") + assert_equal "αη#{UNICODE_STRING}αη", @chars.center(8, "αη") end def test_lstrip_strips_whitespace_from_the_left_of_the_string @@ -367,20 +367,20 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_size_returns_characters_instead_of_bytes - assert_equal 0, ''.mb_chars.size + assert_equal 0, "".mb_chars.size assert_equal 4, @chars.size assert_equal 4, @chars.length assert_equal 5, ASCII_STRING.mb_chars.size end def test_reverse_reverses_characters - assert_equal '', ''.mb_chars.reverse - assert_equal 'ã‚ã¡ã«ã“', @chars.reverse + assert_equal "", "".mb_chars.reverse + assert_equal "ã‚ã¡ã«ã“", @chars.reverse end def test_reverse_should_work_with_normalized_strings - str = 'bös' - reversed_str = 'söb' + str = "bös" + reversed_str = "söb" assert_equal chars(reversed_str).normalize(:kc), chars(str).normalize(:kc).reverse assert_equal chars(reversed_str).normalize(:c), chars(str).normalize(:c).reverse assert_equal chars(reversed_str).normalize(:d), chars(str).normalize(:d).reverse @@ -390,27 +390,27 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_slice_should_take_character_offsets - assert_equal nil, ''.mb_chars.slice(0) - assert_equal 'ã“', @chars.slice(0) - assert_equal 'ã‚', @chars.slice(3) - assert_equal nil, ''.mb_chars.slice(-1..1) - assert_equal nil, ''.mb_chars.slice(-1, 1) - assert_equal '', ''.mb_chars.slice(0..10) - assert_equal 'ã«ã¡ã‚', @chars.slice(1..3) - assert_equal 'ã«ã¡ã‚', @chars.slice(1, 3) - assert_equal 'ã“', @chars.slice(0, 1) - assert_equal 'ã¡ã‚', @chars.slice(2..10) - assert_equal '', @chars.slice(4..10) - assert_equal 'ã«', @chars.slice(/ã«/u) - assert_equal 'ã«ã¡', @chars.slice(/ã«./u) + assert_equal nil, "".mb_chars.slice(0) + assert_equal "ã“", @chars.slice(0) + assert_equal "ã‚", @chars.slice(3) + assert_equal nil, "".mb_chars.slice(-1..1) + assert_equal nil, "".mb_chars.slice(-1, 1) + assert_equal "", "".mb_chars.slice(0..10) + assert_equal "ã«ã¡ã‚", @chars.slice(1..3) + assert_equal "ã«ã¡ã‚", @chars.slice(1, 3) + assert_equal "ã“", @chars.slice(0, 1) + assert_equal "ã¡ã‚", @chars.slice(2..10) + assert_equal "", @chars.slice(4..10) + assert_equal "ã«", @chars.slice(/ã«/u) + assert_equal "ã«ã¡", @chars.slice(/ã«./u) assert_equal nil, @chars.slice(/unknown/u) - assert_equal 'ã«ã¡', @chars.slice(/(ã«ã¡)/u, 1) + assert_equal "ã«ã¡", @chars.slice(/(ã«ã¡)/u, 1) assert_equal nil, @chars.slice(/(ã«ã¡)/u, 2) assert_equal nil, @chars.slice(7..6) end def test_slice_bang_returns_sliced_out_substring - assert_equal 'ã«ã¡', @chars.slice!(1..2) + assert_equal "ã«ã¡", @chars.slice!(1..2) end def test_slice_bang_returns_nil_on_out_of_bound_arguments @@ -418,17 +418,17 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_slice_bang_removes_the_slice_from_the_receiver - chars = 'úüù'.mb_chars + chars = "úüù".mb_chars chars.slice!(0,2) - assert_equal 'ù', chars + assert_equal "ù", chars end def test_slice_bang_returns_nil_and_does_not_modify_receiver_if_out_of_bounds - string = 'úüù' + string = "úüù" chars = string.mb_chars assert_nil chars.slice!(4, 5) - assert_equal 'úüù', chars - assert_equal 'úüù', string + assert_equal "úüù", chars + assert_equal "úüù", string end def test_slice_should_throw_exceptions_on_invalid_arguments @@ -442,48 +442,48 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase end def test_upcase_should_upcase_ascii_characters - assert_equal '', ''.mb_chars.upcase - assert_equal 'ABC', 'aBc'.mb_chars.upcase + assert_equal "", "".mb_chars.upcase + assert_equal "ABC", "aBc".mb_chars.upcase end def test_downcase_should_downcase_ascii_characters - assert_equal '', ''.mb_chars.downcase - assert_equal 'abc', 'aBc'.mb_chars.downcase + assert_equal "", "".mb_chars.downcase + assert_equal "abc", "aBc".mb_chars.downcase end def test_swapcase_should_swap_ascii_characters - assert_equal '', ''.mb_chars.swapcase - assert_equal 'AbC', 'aBc'.mb_chars.swapcase + assert_equal "", "".mb_chars.swapcase + assert_equal "AbC", "aBc".mb_chars.swapcase end def test_capitalize_should_work_on_ascii_characters - assert_equal '', ''.mb_chars.capitalize - assert_equal 'Abc', 'abc'.mb_chars.capitalize + assert_equal "", "".mb_chars.capitalize + assert_equal "Abc", "abc".mb_chars.capitalize end def test_titleize_should_work_on_ascii_characters - assert_equal '', ''.mb_chars.titleize - assert_equal 'Abc Abc', 'abc abc'.mb_chars.titleize + assert_equal "", "".mb_chars.titleize + assert_equal "Abc Abc", "abc abc".mb_chars.titleize end def test_respond_to_knows_which_methods_the_proxy_responds_to - assert ''.mb_chars.respond_to?(:slice) # Defined on Chars - assert ''.mb_chars.respond_to?(:capitalize!) # Defined on Chars - assert ''.mb_chars.respond_to?(:gsub) # Defined on String - assert !''.mb_chars.respond_to?(:undefined_method) # Not defined + assert "".mb_chars.respond_to?(:slice) # Defined on Chars + assert "".mb_chars.respond_to?(:capitalize!) # Defined on Chars + assert "".mb_chars.respond_to?(:gsub) # Defined on String + assert !"".mb_chars.respond_to?(:undefined_method) # Not defined end def test_method_works_for_proxyed_methods - assert_equal 'll', 'hello'.mb_chars.method(:slice).call(2..3) # Defined on Chars - chars = 'hello'.mb_chars - assert_equal 'Hello', chars.method(:capitalize!).call # Defined on Chars - assert_equal 'Hello', chars - assert_equal 'jello', 'hello'.mb_chars.method(:gsub).call(/h/, 'j') # Defined on String - assert_raise(NameError){ ''.mb_chars.method(:undefined_method) } # Not defined + assert_equal "ll", "hello".mb_chars.method(:slice).call(2..3) # Defined on Chars + chars = "hello".mb_chars + assert_equal "Hello", chars.method(:capitalize!).call # Defined on Chars + assert_equal "Hello", chars + assert_equal "jello", "hello".mb_chars.method(:gsub).call(/h/, "j") # Defined on String + assert_raise(NameError) { "".mb_chars.method(:undefined_method) } # Not defined end def test_acts_like_string - assert 'Bambi'.mb_chars.acts_like_string? + assert "Bambi".mb_chars.acts_like_string? end end @@ -495,25 +495,25 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase def test_upcase_should_be_unicode_aware assert_equal "ÐБВГД\0F", chars("аБвгд\0f").upcase - assert_equal 'ã“ã«ã¡ã‚', chars('ã“ã«ã¡ã‚').upcase + assert_equal "ã“ã«ã¡ã‚", chars("ã“ã«ã¡ã‚").upcase end def test_downcase_should_be_unicode_aware assert_equal "абвгд\0f", chars("аБвгд\0F").downcase - assert_equal 'ã“ã«ã¡ã‚', chars('ã“ã«ã¡ã‚').downcase + assert_equal "ã“ã«ã¡ã‚", chars("ã“ã«ã¡ã‚").downcase end def test_swapcase_should_be_unicode_aware assert_equal "аaéÜ\0f", chars("ÐAÉü\0F").swapcase - assert_equal 'ã“ã«ã¡ã‚', chars('ã“ã«ã¡ã‚').swapcase + assert_equal "ã“ã«ã¡ã‚", chars("ã“ã«ã¡ã‚").swapcase end def test_capitalize_should_be_unicode_aware - { 'аБвг аБвг' => 'Ðбвг абвг', - 'аБвг ÐБВГ' => 'Ðбвг абвг', - 'ÐБВГ ÐБВГ' => 'Ðбвг абвг', - '' => '' }.each do |f,t| - assert_equal t, chars(f).capitalize + { "аБвг аБвг" => "Ðбвг абвг", + "аБвг ÐБВГ" => "Ðбвг абвг", + "ÐБВГ ÐБВГ" => "Ðбвг абвг", + "" => "" }.each do |f,t| + assert_equal t, chars(f).capitalize end end @@ -527,7 +527,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase end def test_limit_should_not_break_on_blank_strings - example = chars('') + example = chars("") assert_equal example, example.limit(0) assert_equal example, example.limit(1) end @@ -537,23 +537,23 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase bytesize = UNICODE_STRING.bytesize assert_equal UNICODE_STRING, example.limit(bytesize) - assert_equal '', example.limit(0) - assert_equal '', example.limit(1) - assert_equal 'ã“', example.limit(3) - assert_equal 'ã“ã«', example.limit(6) - assert_equal 'ã“ã«', example.limit(8) - assert_equal 'ã“ã«ã¡', example.limit(9) - assert_equal 'ã“ã«ã¡ã‚', example.limit(50) + assert_equal "", example.limit(0) + assert_equal "", example.limit(1) + assert_equal "ã“", example.limit(3) + assert_equal "ã“ã«", example.limit(6) + assert_equal "ã“ã«", example.limit(8) + assert_equal "ã“ã«ã¡", example.limit(9) + assert_equal "ã“ã«ã¡ã‚", example.limit(50) end def test_limit_should_work_on_an_ascii_string ascii = chars(ASCII_STRING) assert_equal ASCII_STRING, ascii.limit(ASCII_STRING.length) - assert_equal '', ascii.limit(0) - assert_equal 'o', ascii.limit(1) - assert_equal 'oh', ascii.limit(2) - assert_equal 'ohay', ascii.limit(4) - assert_equal 'ohayo', ascii.limit(50) + assert_equal "", ascii.limit(0) + assert_equal "o", ascii.limit(1) + assert_equal "oh", ascii.limit(2) + assert_equal "ohay", ascii.limit(4) + assert_equal "ohayo", ascii.limit(50) end def test_limit_should_keep_under_the_specified_byte_limit @@ -565,7 +565,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase def test_composition_exclusion_is_set_up_properly # Normalization of DEVANAGARI LETTER QA breaks when composition exclusion isn't used correctly - qa = [0x915, 0x93c].pack('U*') + qa = [0x915, 0x93c].pack("U*") assert_equal qa, chars(qa).normalize(:c) end @@ -575,7 +575,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase [ [0x0B47, 0x0300, 0x0B3E], [0x1100, 0x0300, 0x1161] - ].map { |c| c.pack('U*') }.each do |c| + ].map { |c| c.pack("U*") }.each do |c| assert_equal_codepoints c, chars(c).normalize(:c) end end @@ -599,7 +599,7 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase 323 # COMBINING DOT BELOW ].pack("U*") - assert_equal_codepoints '', chars('').normalize + assert_equal_codepoints "", chars("").normalize assert_equal_codepoints [44,105,106,328,323].pack("U*"), chars(comp_str).normalize(:kc).to_s assert_equal_codepoints [44,307,328,323].pack("U*"), chars(comp_str).normalize(:c).to_s assert_equal_codepoints [44,307,110,780,78,769].pack("U*"), chars(comp_str).normalize(:d).to_s @@ -608,10 +608,10 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase def test_should_compute_grapheme_length [ - ['', 0], - ['abc', 3], - ['ã“ã«ã¡ã‚', 4], - [[0x0924, 0x094D, 0x0930].pack('U*'), 2], + ["", 0], + ["abc", 3], + ["ã“ã«ã¡ã‚", 4], + [[0x0924, 0x094D, 0x0930].pack("U*"), 2], # GB3 [%w(cr lf), 1], # GB4 @@ -699,9 +699,9 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase end byte_string = "\270\236\010\210\245" - tidy_string = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].pack('U*') + tidy_string = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].pack("U*") assert_equal_codepoints tidy_string, chars(byte_string).tidy_bytes - assert_nothing_raised { chars(byte_string).tidy_bytes.to_s.unpack('U*') } + assert_nothing_raised { chars(byte_string).tidy_bytes.to_s.unpack("U*") } # UTF-8 leading byte followed by too few continuation bytes assert_equal_codepoints "\xc3\xb0\xc2\xa5\xc2\xa4\x21", chars("\xf0\xa5\xa4\x21").tidy_bytes @@ -720,16 +720,16 @@ class MultibyteCharsExtrasTest < ActiveSupport::TestCase private - def string_from_classes(classes) - # Characters from the character classes as described in UAX #29 - character_from_class = { - :l => 0x1100, :v => 0x1160, :t => 0x11A8, :lv => 0xAC00, :lvt => 0xAC01, :cr => 0x000D, :lf => 0x000A, - :extend => 0x094D, :n => 0x64, :spacingmark => 0x0903, :r => 0x1F1E6, :control => 0x0001 - } - classes.collect do |k| - character_from_class[k.intern] - end.pack('U*') - end + def string_from_classes(classes) + # Characters from the character classes as described in UAX #29 + character_from_class = { + l: 0x1100, v: 0x1160, t: 0x11A8, lv: 0xAC00, lvt: 0xAC01, cr: 0x000D, lf: 0x000A, + extend: 0x094D, n: 0x64, spacingmark: 0x0903, r: 0x1F1E6, control: 0x0001 + } + classes.collect do |k| + character_from_class[k.intern] + end.pack("U*") + end end class MultibyteInternalsTest < ActiveSupport::TestCase diff --git a/activesupport/test/multibyte_conformance_test.rb b/activesupport/test/multibyte_conformance_test.rb index 9fca47a985..bf004d7924 100644 --- a/activesupport/test/multibyte_conformance_test.rb +++ b/activesupport/test/multibyte_conformance_test.rb @@ -1,34 +1,14 @@ -require 'abstract_unit' -require 'multibyte_test_helpers' +require "abstract_unit" +require "multibyte_test_helpers" -require 'fileutils' -require 'open-uri' -require 'tmpdir' +require "fileutils" +require "open-uri" +require "tmpdir" class MultibyteConformanceTest < ActiveSupport::TestCase - class Downloader - def self.download(from, to) - unless File.exist?(to) - unless File.exist?(File.dirname(to)) - system "mkdir -p #{File.dirname(to)}" - end - open(from) do |source| - File.open(to, 'w') do |target| - source.each_line do |l| - target.write l - end - end - end - end - true - end - end - include MultibyteTestHelpers - UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd" - UNIDATA_FILE = '/NormalizationTest.txt' - CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance" + UNIDATA_FILE = "/NormalizationTest.txt" FileUtils.mkdir_p(CACHE_DIR) RUN_P = begin Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) @@ -104,17 +84,17 @@ class MultibyteConformanceTest < ActiveSupport::TestCase protected def each_line_of_norm_tests(&block) - File.open(File.join(CACHE_DIR, UNIDATA_FILE), 'r') do | f | + File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f | until f.eof? line = f.gets.chomp! - next if (line.empty? || line =~ /^\#/) + next if line.empty? || line.start_with?("#") cols, comment = line.split("#") cols = cols.split(";").map(&:strip).reject(&:empty?) next unless cols.length == 5 # codepoints are in hex in the test suite, pack wants them as integers - cols.map!{|c| c.split.map{|codepoint| codepoint.to_i(16)}.pack("U*") } + cols.map! { |c| c.split.map { |codepoint| codepoint.to_i(16) }.pack("U*") } cols << comment yield(*cols) @@ -123,6 +103,6 @@ class MultibyteConformanceTest < ActiveSupport::TestCase end def inspect_codepoints(str) - str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ') + str.to_s.unpack("U*").map { |cp| cp.to_s(16) }.join(" ") end end diff --git a/activesupport/test/multibyte_grapheme_break_conformance_test.rb b/activesupport/test/multibyte_grapheme_break_conformance_test.rb index 6e2f02abed..04a7d290d9 100644 --- a/activesupport/test/multibyte_grapheme_break_conformance_test.rb +++ b/activesupport/test/multibyte_grapheme_break_conformance_test.rb @@ -1,37 +1,23 @@ # encoding: utf-8 -require 'abstract_unit' +require "abstract_unit" +require "multibyte_test_helpers" -require 'fileutils' -require 'open-uri' -require 'tmpdir' +require "fileutils" +require "open-uri" +require "tmpdir" class MultibyteGraphemeBreakConformanceTest < ActiveSupport::TestCase - class Downloader - def self.download(from, to) - unless File.exist?(to) - $stderr.puts "Downloading #{from} to #{to}" - unless File.exist?(File.dirname(to)) - system "mkdir -p #{File.dirname(to)}" - end - open(from) do |source| - File.open(to, 'w') do |target| - source.each_line do |l| - target.write l - end - end - end - end - end - end + include MultibyteTestHelpers - TEST_DATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd/auxiliary" - TEST_DATA_FILE = '/GraphemeBreakTest.txt' - CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance" + UNIDATA_FILE = "/auxiliary/GraphemeBreakTest.txt" + RUN_P = begin + Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) + rescue + end def setup - FileUtils.mkdir_p(CACHE_DIR) - Downloader.download(TEST_DATA_URL + TEST_DATA_FILE, CACHE_DIR + TEST_DATA_FILE) + skip "Unable to download test data" unless RUN_P end def test_breaks @@ -46,20 +32,20 @@ class MultibyteGraphemeBreakConformanceTest < ActiveSupport::TestCase def each_line_of_break_tests(&block) lines = 0 max_test_lines = 0 # Don't limit below 21, because that's the header of the testfile - File.open(File.join(CACHE_DIR, TEST_DATA_FILE), 'r') do | f | - until f.eof? || (max_test_lines > 21 and lines > max_test_lines) + File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f | + until f.eof? || (max_test_lines > 21 && lines > max_test_lines) lines += 1 line = f.gets.chomp! - next if (line.empty? || line =~ /^\#/) + next if line.empty? || line.start_with?("#") cols, comment = line.split("#") # Cluster breaks are represented by ÷ - clusters = cols.split("÷").map{|e| e.strip}.reject{|e| e.empty? } + clusters = cols.split("÷").map { |e| e.strip }.reject { |e| e.empty? } clusters = clusters.map do |cluster| # Codepoints within each cluster are separated by × - codepoints = cluster.split("×").map{|e| e.strip}.reject{|e| e.empty? } + codepoints = cluster.split("×").map { |e| e.strip }.reject { |e| e.empty? } # codepoints are in hex in the test suite, pack wants them as integers - codepoints.map{|codepoint| codepoint.to_i(16)} + codepoints.map { |codepoint| codepoint.to_i(16) } end # The tests contain a solitary U+D800 <Non Private Use High diff --git a/activesupport/test/multibyte_normalization_conformance_test.rb b/activesupport/test/multibyte_normalization_conformance_test.rb index 0d31c9520f..e013bd578f 100644 --- a/activesupport/test/multibyte_normalization_conformance_test.rb +++ b/activesupport/test/multibyte_normalization_conformance_test.rb @@ -1,41 +1,24 @@ # encoding: utf-8 -require 'abstract_unit' -require 'multibyte_test_helpers' +require "abstract_unit" +require "multibyte_test_helpers" -require 'fileutils' -require 'open-uri' -require 'tmpdir' +require "fileutils" +require "open-uri" +require "tmpdir" class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase - class Downloader - def self.download(from, to) - unless File.exist?(to) - $stderr.puts "Downloading #{from} to #{to}" - unless File.exist?(File.dirname(to)) - system "mkdir -p #{File.dirname(to)}" - end - open(from) do |source| - File.open(to, 'w') do |target| - source.each_line do |l| - target.write l - end - end - end - end - end - end - include MultibyteTestHelpers - UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd" - UNIDATA_FILE = '/NormalizationTest.txt' - CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance" + UNIDATA_FILE = "/NormalizationTest.txt" + RUN_P = begin + Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) + rescue + end def setup - FileUtils.mkdir_p(CACHE_DIR) - Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE) @proxy = ActiveSupport::Multibyte::Chars + skip "Unable to download test data" unless RUN_P end def test_normalizations_C @@ -104,18 +87,18 @@ class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase def each_line_of_norm_tests(&block) lines = 0 max_test_lines = 0 # Don't limit below 38, because that's the header of the testfile - File.open(File.join(CACHE_DIR, UNIDATA_FILE), 'r') do | f | - until f.eof? || (max_test_lines > 38 and lines > max_test_lines) + File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f | + until f.eof? || (max_test_lines > 38 && lines > max_test_lines) lines += 1 line = f.gets.chomp! - next if (line.empty? || line =~ /^\#/) + next if line.empty? || line.start_with?("#") cols, comment = line.split("#") - cols = cols.split(";").map{|e| e.strip}.reject{|e| e.empty? } + cols = cols.split(";").map { |e| e.strip }.reject { |e| e.empty? } next unless cols.length == 5 # codepoints are in hex in the test suite, pack wants them as integers - cols.map!{|c| c.split.map{|codepoint| codepoint.to_i(16)}.pack("U*") } + cols.map! { |c| c.split.map { |codepoint| codepoint.to_i(16) }.pack("U*") } cols << comment yield(*cols) @@ -124,6 +107,6 @@ class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase end def inspect_codepoints(str) - str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ') + str.to_s.unpack("U*").map { |cp| cp.to_s(16) }.join(" ") end end diff --git a/activesupport/test/multibyte_proxy_test.rb b/activesupport/test/multibyte_proxy_test.rb index 360cf57302..c303097f80 100644 --- a/activesupport/test/multibyte_proxy_test.rb +++ b/activesupport/test/multibyte_proxy_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class MultibyteProxyText < ActiveSupport::TestCase class AsciiOnlyEncoder @@ -6,7 +6,7 @@ class MultibyteProxyText < ActiveSupport::TestCase alias to_s wrapped_string def initialize(string) - @wrapped_string = string.gsub(/[^\u0000-\u007F]/, '?') + @wrapped_string = string.gsub(/[^\u0000-\u007F]/, "?") end end diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb index 58cf5488cd..22c586c50d 100644 --- a/activesupport/test/multibyte_test_helpers.rb +++ b/activesupport/test/multibyte_test_helpers.rb @@ -1,6 +1,28 @@ module MultibyteTestHelpers - UNICODE_STRING = 'ã“ã«ã¡ã‚'.freeze - ASCII_STRING = 'ohayo'.freeze + class Downloader + def self.download(from, to) + unless File.exist?(to) + unless File.exist?(File.dirname(to)) + system "mkdir -p #{File.dirname(to)}" + end + open(from) do |source| + File.open(to, "w") do |target| + source.each_line do |l| + target.write l + end + end + end + end + true + end + end + + UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd" + CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance" + FileUtils.mkdir_p(CACHE_DIR) + + UNICODE_STRING = "ã“ã«ã¡ã‚".freeze + ASCII_STRING = "ohayo".freeze BYTE_STRING = "\270\236\010\210\245".force_encoding("ASCII-8BIT").freeze def chars(str) @@ -8,7 +30,7 @@ module MultibyteTestHelpers end def inspect_codepoints(str) - str.to_s.unpack("U*").map{|cp| cp.to_s(16) }.join(' ') + str.to_s.unpack("U*").map { |cp| cp.to_s(16) }.join(" ") end def assert_equal_codepoints(expected, actual, message=nil) diff --git a/activesupport/test/multibyte_unicode_database_test.rb b/activesupport/test/multibyte_unicode_database_test.rb index dd33641ec2..3724782930 100644 --- a/activesupport/test/multibyte_unicode_database_test.rb +++ b/activesupport/test/multibyte_unicode_database_test.rb @@ -1,8 +1,6 @@ -require 'abstract_unit' - +require "abstract_unit" class MultibyteUnicodeDatabaseTest < ActiveSupport::TestCase - include ActiveSupport::Multibyte::Unicode def setup diff --git a/activesupport/test/notifications/evented_notification_test.rb b/activesupport/test/notifications/evented_notification_test.rb index f690ad43fc..688971c858 100644 --- a/activesupport/test/notifications/evented_notification_test.rb +++ b/activesupport/test/notifications/evented_notification_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActiveSupport module Notifications @@ -28,26 +28,26 @@ module ActiveSupport def test_evented_listener notifier = Fanout.new listener = Listener.new - notifier.subscribe 'hi', listener - notifier.start 'hi', 1, {} - notifier.start 'hi', 2, {} - notifier.finish 'hi', 2, {} - notifier.finish 'hi', 1, {} + notifier.subscribe "hi", listener + notifier.start "hi", 1, {} + notifier.start "hi", 2, {} + notifier.finish "hi", 2, {} + notifier.finish "hi", 1, {} assert_equal 4, listener.events.length assert_equal [ - [:start, 'hi', 1, {}], - [:start, 'hi', 2, {}], - [:finish, 'hi', 2, {}], - [:finish, 'hi', 1, {}], + [:start, "hi", 1, {}], + [:start, "hi", 2, {}], + [:finish, "hi", 2, {}], + [:finish, "hi", 1, {}], ], listener.events end def test_evented_listener_no_events notifier = Fanout.new listener = Listener.new - notifier.subscribe 'hi', listener - notifier.start 'world', 1, {} + notifier.subscribe "hi", listener + notifier.start "world", 1, {} assert_equal 0, listener.events.length end @@ -55,31 +55,31 @@ module ActiveSupport notifier = Fanout.new listener = Listener.new notifier.subscribe nil, listener - notifier.start 'hello', 1, {} - notifier.start 'world', 1, {} - notifier.finish 'world', 1, {} - notifier.finish 'hello', 1, {} + notifier.start "hello", 1, {} + notifier.start "world", 1, {} + notifier.finish "world", 1, {} + notifier.finish "hello", 1, {} assert_equal 4, listener.events.length assert_equal [ - [:start, 'hello', 1, {}], - [:start, 'world', 1, {}], - [:finish, 'world', 1, {}], - [:finish, 'hello', 1, {}], + [:start, "hello", 1, {}], + [:start, "world", 1, {}], + [:finish, "world", 1, {}], + [:finish, "hello", 1, {}], ], listener.events end def test_evented_listener_priority notifier = Fanout.new listener = ListenerWithTimedSupport.new - notifier.subscribe 'hi', listener + notifier.subscribe "hi", listener - notifier.start 'hi', 1, {} - notifier.finish 'hi', 1, {} + notifier.start "hi", 1, {} + notifier.finish "hi", 1, {} assert_equal [ - [:start, 'hi', 1, {}], - [:finish, 'hi', 1, {}] + [:start, "hi", 1, {}], + [:finish, "hi", 1, {}] ], listener.events end end diff --git a/activesupport/test/notifications/instrumenter_test.rb b/activesupport/test/notifications/instrumenter_test.rb index f46e96f636..e454e6897b 100644 --- a/activesupport/test/notifications/instrumenter_test.rb +++ b/activesupport/test/notifications/instrumenter_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/notifications/instrumenter' +require "abstract_unit" +require "active_support/notifications/instrumenter" module ActiveSupport module Notifications @@ -22,7 +22,7 @@ module ActiveSupport super @notifier = TestNotifier.new @instrumenter = Instrumenter.new @notifier - @payload = { :foo => Object.new } + @payload = { foo: Object.new } end def test_instrument @@ -39,7 +39,7 @@ module ActiveSupport assert_equal 1, notifier.finishes.size name, _, payload = notifier.finishes.first assert_equal "awesome", name - assert_equal Hash[:result => 2], payload + assert_equal Hash[result: 2], payload end def test_start diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index 1cb17e6197..a6f0d82e8a 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/delegation' +require "abstract_unit" +require "active_support/core_ext/module/delegation" module Notifications class TestCase < ActiveSupport::TestCase @@ -31,7 +31,7 @@ module Notifications expected = [name, name] events = [] - callback = lambda {|*_| events << _.first} + callback = lambda { |*_| events << _.first } ActiveSupport::Notifications.subscribed(callback, name) do ActiveSupport::Notifications.instrument(name) ActiveSupport::Notifications.instrument(name2) @@ -49,10 +49,10 @@ module Notifications old_notifier = ActiveSupport::Notifications.notifier ActiveSupport::Notifications.notifier = ActiveSupport::Notifications::Fanout.new - ActiveSupport::Notifications.subscribe('foo', TestSubscriber.new) + ActiveSupport::Notifications.subscribe("foo", TestSubscriber.new) - ActiveSupport::Notifications.instrument('foo') do - ActiveSupport::Notifications.subscribe('foo') {} + ActiveSupport::Notifications.instrument("foo") do + ActiveSupport::Notifications.subscribe("foo") {} end ensure ActiveSupport::Notifications.notifier = old_notifier @@ -141,26 +141,26 @@ module Notifications def test_log_subscriber_with_string events = [] - @notifier.subscribe('1') { |*args| events << args } + @notifier.subscribe("1") { |*args| events << args } - @notifier.publish '1' - @notifier.publish '1.a' - @notifier.publish 'a.1' + @notifier.publish "1" + @notifier.publish "1.a" + @notifier.publish "a.1" @notifier.wait - assert_equal [['1']], events + assert_equal [["1"]], events end def test_log_subscriber_with_pattern events = [] @notifier.subscribe(/\d/) { |*args| events << args } - @notifier.publish '1' - @notifier.publish 'a.1' - @notifier.publish '1.a' + @notifier.publish "1" + @notifier.publish "a.1" + @notifier.publish "1.a" @notifier.wait - assert_equal [['1'], ['a.1'], ['1.a']], events + assert_equal [["1"], ["a.1"], ["1.a"]], events end def test_multiple_log_subscribers @@ -188,7 +188,7 @@ module Notifications end class InstrumentationTest < TestCase - delegate :instrument, :to => ActiveSupport::Notifications + delegate :instrument, to: ActiveSupport::Notifications def test_instrument_returns_block_result assert_equal 2, instrument(:awesome) { 1 + 1 } @@ -198,7 +198,7 @@ module Notifications assert_equal 2, instrument(:awesome) { |p| p[:result] = 1 + 1 } assert_equal 1, @events.size assert_equal :awesome, @events.first.name - assert_equal Hash[:result => 2], @events.first.payload + assert_equal Hash[result: 2], @events.first.payload end def test_instrumenter_exposes_its_id @@ -206,24 +206,24 @@ module Notifications end def test_nested_events_can_be_instrumented - instrument(:awesome, :payload => "notifications") do - instrument(:wot, :payload => "child") do + instrument(:awesome, payload: "notifications") do + instrument(:wot, payload: "child") do 1 + 1 end assert_equal 1, @events.size assert_equal :wot, @events.first.name - assert_equal Hash[:payload => "child"], @events.first.payload + assert_equal Hash[payload: "child"], @events.first.payload end assert_equal 2, @events.size assert_equal :awesome, @events.last.name - assert_equal Hash[:payload => "notifications"], @events.last.payload + assert_equal Hash[payload: "notifications"], @events.last.payload end def test_instrument_publishes_when_exception_is_raised begin - instrument(:awesome, :payload => "notifications") do + instrument(:awesome, payload: "notifications") do raise "FAIL" end rescue RuntimeError => e @@ -231,15 +231,15 @@ module Notifications end assert_equal 1, @events.size - assert_equal Hash[:payload => "notifications", - :exception => ["RuntimeError", "FAIL"], :exception_object => e], @events.last.payload + assert_equal Hash[payload: "notifications", + exception: ["RuntimeError", "FAIL"], exception_object: e], @events.last.payload end def test_event_is_pushed_even_without_block - instrument(:awesome, :payload => "notifications") + instrument(:awesome, payload: "notifications") assert_equal 1, @events.size assert_equal :awesome, @events.last.name - assert_equal Hash[:payload => "notifications"], @events.last.payload + assert_equal Hash[payload: "notifications"], @events.last.payload end end @@ -254,8 +254,8 @@ module Notifications end def test_events_consumes_information_given_as_payload - event = event(:foo, Time.now, Time.now + 1, random_id, :payload => :bar) - assert_equal Hash[:payload => :bar], event.payload + event = event(:foo, Time.now, Time.now + 1, random_id, payload: :bar) + assert_equal Hash[payload: :bar], event.payload end def test_event_is_parent_based_on_children diff --git a/activesupport/test/number_helper_i18n_test.rb b/activesupport/test/number_helper_i18n_test.rb index e6925e9083..4f58e6607a 100644 --- a/activesupport/test/number_helper_i18n_test.rb +++ b/activesupport/test/number_helper_i18n_test.rb @@ -1,46 +1,46 @@ -require 'abstract_unit' -require 'active_support/number_helper' +require "abstract_unit" +require "active_support/number_helper" module ActiveSupport class NumberHelperI18nTest < ActiveSupport::TestCase include ActiveSupport::NumberHelper def setup - I18n.backend.store_translations 'ts', - :number => { - :format => { :precision => 3, :delimiter => ',', :separator => '.', :significant => false, :strip_insignificant_zeros => false }, - :currency => { :format => { :unit => '&$', :format => '%u - %n', :negative_format => '(%u - %n)', :precision => 2 } }, - :human => { - :format => { - :precision => 2, - :significant => true, - :strip_insignificant_zeros => true + I18n.backend.store_translations "ts", + number: { + format: { precision: 3, delimiter: ",", separator: ".", significant: false, strip_insignificant_zeros: false }, + currency: { format: { unit: "&$", format: "%u - %n", negative_format: "(%u - %n)", precision: 2 } }, + human: { + format: { + precision: 2, + significant: true, + strip_insignificant_zeros: true }, - :storage_units => { - :format => "%n %u", - :units => { - :byte => "b", - :kb => "k" + storage_units: { + format: "%n %u", + units: { + byte: "b", + kb: "k" } }, - :decimal_units => { - :format => "%n %u", - :units => { - :deci => {:one => "Tenth", :other => "Tenths"}, - :unit => "u", - :ten => {:one => "Ten", :other => "Tens"}, - :thousand => "t", - :million => "m", - :billion =>"b", - :trillion =>"t" , - :quadrillion =>"q" + decimal_units: { + format: "%n %u", + units: { + deci: { one: "Tenth", other: "Tenths" }, + unit: "u", + ten: { one: "Ten", other: "Tens" }, + thousand: "t", + million: "m", + billion: "b", + trillion: "t" , + quadrillion: "q" } } }, - :percentage => { :format => {:delimiter => '', :precision => 2, :strip_insignificant_zeros => true} }, - :precision => { :format => {:delimiter => '', :significant => true} } + percentage: { format: { delimiter: "", precision: 2, strip_insignificant_zeros: true } }, + precision: { format: { delimiter: "", significant: true } } }, - :custom_units_for_number_to_human => {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} + custom_units_for_number_to_human: { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } end def teardown @@ -48,101 +48,101 @@ module ActiveSupport end def test_number_to_i18n_currency - assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts')) - assert_equal("(&$ - 10.00)", number_to_currency(-10, :locale => 'ts')) - assert_equal("-10.00 - &$", number_to_currency(-10, :locale => 'ts', :format => "%n - %u")) + assert_equal("&$ - 10.00", number_to_currency(10, locale: "ts")) + assert_equal("(&$ - 10.00)", number_to_currency(-10, locale: "ts")) + assert_equal("-10.00 - &$", number_to_currency(-10, locale: "ts", format: "%n - %u")) end def test_number_to_currency_with_empty_i18n_store - assert_equal("$10.00", number_to_currency(10, :locale => 'empty')) - assert_equal("-$10.00", number_to_currency(-10, :locale => 'empty')) + assert_equal("$10.00", number_to_currency(10, locale: "empty")) + assert_equal("-$10.00", number_to_currency(-10, locale: "empty")) end def test_locale_default_format_has_precedence_over_helper_defaults - I18n.backend.store_translations 'ts', - { :number => { :format => { :separator => ";" } } } + I18n.backend.store_translations "ts", + number: { format: { separator: ";" } } - assert_equal("&$ - 10;00", number_to_currency(10, :locale => 'ts')) + assert_equal("&$ - 10;00", number_to_currency(10, locale: "ts")) end def test_number_to_currency_without_currency_negative_format - I18n.backend.store_translations 'no_negative_format', :number => { - :currency => { :format => { :unit => '@', :format => '%n %u' } } + I18n.backend.store_translations "no_negative_format", number: { + currency: { format: { unit: "@", format: "%n %u" } } } - assert_equal("-10.00 @", number_to_currency(-10, :locale => 'no_negative_format')) + assert_equal("-10.00 @", number_to_currency(-10, locale: "no_negative_format")) end def test_number_with_i18n_precision #Delimiter was set to "" - assert_equal("10000", number_to_rounded(10000, :locale => 'ts')) + assert_equal("10000", number_to_rounded(10000, locale: "ts")) #Precision inherited and significant was set - assert_equal("1.00", number_to_rounded(1.0, :locale => 'ts')) + assert_equal("1.00", number_to_rounded(1.0, locale: "ts")) end def test_number_with_i18n_precision_and_empty_i18n_store - assert_equal("123456789.123", number_to_rounded(123456789.123456789, :locale => 'empty')) - assert_equal("1.000", number_to_rounded(1.0000, :locale => 'empty')) + assert_equal("123456789.123", number_to_rounded(123456789.123456789, locale: "empty")) + assert_equal("1.000", number_to_rounded(1.0000, locale: "empty")) end def test_number_with_i18n_delimiter #Delimiter "," and separator "." - assert_equal("1,000,000.234", number_to_delimited(1000000.234, :locale => 'ts')) + assert_equal("1,000,000.234", number_to_delimited(1000000.234, locale: "ts")) end def test_number_with_i18n_delimiter_and_empty_i18n_store - assert_equal("1,000,000.234", number_to_delimited(1000000.234, :locale => 'empty')) + assert_equal("1,000,000.234", number_to_delimited(1000000.234, locale: "empty")) end def test_number_to_i18n_percentage # to see if strip_insignificant_zeros is true - assert_equal("1%", number_to_percentage(1, :locale => 'ts')) + assert_equal("1%", number_to_percentage(1, locale: "ts")) # precision is 2, significant should be inherited - assert_equal("1.24%", number_to_percentage(1.2434, :locale => 'ts')) + assert_equal("1.24%", number_to_percentage(1.2434, locale: "ts")) # no delimiter - assert_equal("12434%", number_to_percentage(12434, :locale => 'ts')) + assert_equal("12434%", number_to_percentage(12434, locale: "ts")) end def test_number_to_i18n_percentage_and_empty_i18n_store - assert_equal("1.000%", number_to_percentage(1, :locale => 'empty')) - assert_equal("1.243%", number_to_percentage(1.2434, :locale => 'empty')) - assert_equal("12434.000%", number_to_percentage(12434, :locale => 'empty')) + assert_equal("1.000%", number_to_percentage(1, locale: "empty")) + assert_equal("1.243%", number_to_percentage(1.2434, locale: "empty")) + assert_equal("12434.000%", number_to_percentage(12434, locale: "empty")) end def test_number_to_i18n_human_size #b for bytes and k for kbytes - assert_equal("2 k", number_to_human_size(2048, :locale => 'ts')) - assert_equal("42 b", number_to_human_size(42, :locale => 'ts')) + assert_equal("2 k", number_to_human_size(2048, locale: "ts")) + assert_equal("42 b", number_to_human_size(42, locale: "ts")) end def test_number_to_i18n_human_size_with_empty_i18n_store - assert_equal("2 KB", number_to_human_size(2048, :locale => 'empty')) - assert_equal("42 Bytes", number_to_human_size(42, :locale => 'empty')) + assert_equal("2 KB", number_to_human_size(2048, locale: "empty")) + assert_equal("42 Bytes", number_to_human_size(42, locale: "empty")) end def test_number_to_human_with_default_translation_scope #Using t for thousand - assert_equal "2 t", number_to_human(2000, :locale => 'ts') + assert_equal "2 t", number_to_human(2000, locale: "ts") #Significant was set to true with precision 2, using b for billion - assert_equal "1.2 b", number_to_human(1234567890, :locale => 'ts') + assert_equal "1.2 b", number_to_human(1234567890, locale: "ts") #Using pluralization (Ten/Tens and Tenth/Tenths) - assert_equal "1 Tenth", number_to_human(0.1, :locale => 'ts') - assert_equal "1.3 Tenth", number_to_human(0.134, :locale => 'ts') - assert_equal "2 Tenths", number_to_human(0.2, :locale => 'ts') - assert_equal "1 Ten", number_to_human(10, :locale => 'ts') - assert_equal "1.2 Ten", number_to_human(12, :locale => 'ts') - assert_equal "2 Tens", number_to_human(20, :locale => 'ts') + assert_equal "1 Tenth", number_to_human(0.1, locale: "ts") + assert_equal "1.3 Tenth", number_to_human(0.134, locale: "ts") + assert_equal "2 Tenths", number_to_human(0.2, locale: "ts") + assert_equal "1 Ten", number_to_human(10, locale: "ts") + assert_equal "1.2 Ten", number_to_human(12, locale: "ts") + assert_equal "2 Tens", number_to_human(20, locale: "ts") end def test_number_to_human_with_empty_i18n_store - assert_equal "2 Thousand", number_to_human(2000, :locale => 'empty') - assert_equal "1.23 Billion", number_to_human(1234567890, :locale => 'empty') + assert_equal "2 Thousand", number_to_human(2000, locale: "empty") + assert_equal "1.23 Billion", number_to_human(1234567890, locale: "empty") end def test_number_to_human_with_custom_translation_scope #Significant was set to true with precision 2, with custom translated units - assert_equal "4.3 cm", number_to_human(0.0432, :locale => 'ts', :units => :custom_units_for_number_to_human) + assert_equal "4.3 cm", number_to_human(0.0432, locale: "ts", units: :custom_units_for_number_to_human) end end end diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb index 074c872efc..1a59210018 100644 --- a/activesupport/test/number_helper_test.rb +++ b/activesupport/test/number_helper_test.rb @@ -1,11 +1,10 @@ -require 'abstract_unit' -require 'active_support/number_helper' -require 'active_support/core_ext/string/output_safety' +require "abstract_unit" +require "active_support/number_helper" +require "active_support/core_ext/string/output_safety" module ActiveSupport module NumberHelper class NumberHelperTest < ActiveSupport::TestCase - class TestClassWithInstanceNumberHelpers include ActiveSupport::NumberHelper end @@ -46,17 +45,17 @@ module ActiveSupport [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| assert_equal("555-1234", number_helper.number_to_phone(5551234)) assert_equal("800-555-1212", number_helper.number_to_phone(8005551212)) - assert_equal("(800) 555-1212", number_helper.number_to_phone(8005551212, {:area_code => true})) - assert_equal("", number_helper.number_to_phone("", {:area_code => true})) - assert_equal("800 555 1212", number_helper.number_to_phone(8005551212, {:delimiter => " "})) - assert_equal("(800) 555-1212 x 123", number_helper.number_to_phone(8005551212, {:area_code => true, :extension => 123})) - assert_equal("800-555-1212", number_helper.number_to_phone(8005551212, :extension => " ")) - assert_equal("555.1212", number_helper.number_to_phone(5551212, :delimiter => '.')) + assert_equal("(800) 555-1212", number_helper.number_to_phone(8005551212, area_code: true)) + assert_equal("", number_helper.number_to_phone("", area_code: true)) + assert_equal("800 555 1212", number_helper.number_to_phone(8005551212, delimiter: " ")) + assert_equal("(800) 555-1212 x 123", number_helper.number_to_phone(8005551212, area_code: true, extension: 123)) + assert_equal("800-555-1212", number_helper.number_to_phone(8005551212, extension: " ")) + assert_equal("555.1212", number_helper.number_to_phone(5551212, delimiter: ".")) assert_equal("800-555-1212", number_helper.number_to_phone("8005551212")) - assert_equal("+1-800-555-1212", number_helper.number_to_phone(8005551212, :country_code => 1)) - assert_equal("+18005551212", number_helper.number_to_phone(8005551212, :country_code => 1, :delimiter => '')) + assert_equal("+1-800-555-1212", number_helper.number_to_phone(8005551212, country_code: 1)) + assert_equal("+18005551212", number_helper.number_to_phone(8005551212, country_code: 1, delimiter: "")) assert_equal("22-555-1212", number_helper.number_to_phone(225551212)) - assert_equal("+45-22-555-1212", number_helper.number_to_phone(225551212, :country_code => 45)) + assert_equal("+45-22-555-1212", number_helper.number_to_phone(225551212, country_code: 45)) assert_equal("(755) 6123-4567", number_helper.number_to_phone(75561234567, pattern: /(\d{3,4})(\d{4})(\d{4})/, area_code: true)) assert_equal("133-1234-5678", number_helper.number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})/)) end @@ -67,28 +66,28 @@ module ActiveSupport assert_equal("$1,234,567,890.50", number_helper.number_to_currency(1234567890.50)) assert_equal("$1,234,567,890.51", number_helper.number_to_currency(1234567890.506)) assert_equal("-$1,234,567,890.50", number_helper.number_to_currency(-1234567890.50)) - assert_equal("-$ 1,234,567,890.50", number_helper.number_to_currency(-1234567890.50, {:format => "%u %n"})) - assert_equal("($1,234,567,890.50)", number_helper.number_to_currency(-1234567890.50, {:negative_format => "(%u%n)"})) - assert_equal("$1,234,567,892", number_helper.number_to_currency(1234567891.50, {:precision => 0})) - assert_equal("$1,234,567,890.5", number_helper.number_to_currency(1234567890.50, {:precision => 1})) - assert_equal("£1234567890,50", number_helper.number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""})) + assert_equal("-$ 1,234,567,890.50", number_helper.number_to_currency(-1234567890.50, format: "%u %n")) + assert_equal("($1,234,567,890.50)", number_helper.number_to_currency(-1234567890.50, negative_format: "(%u%n)")) + assert_equal("$1,234,567,892", number_helper.number_to_currency(1234567891.50, precision: 0)) + assert_equal("$1,234,567,890.5", number_helper.number_to_currency(1234567890.50, precision: 1)) + assert_equal("£1234567890,50", number_helper.number_to_currency(1234567890.50, unit: "£", separator: ",", delimiter: "")) assert_equal("$1,234,567,890.50", number_helper.number_to_currency("1234567890.50")) - assert_equal("1,234,567,890.50 Kč", number_helper.number_to_currency("1234567890.50", {:unit => "Kč", :format => "%n %u"})) - assert_equal("1,234,567,890.50 - Kč", number_helper.number_to_currency("-1234567890.50", {:unit => "Kč", :format => "%n %u", :negative_format => "%n - %u"})) - assert_equal("0.00", number_helper.number_to_currency(+0.0, {:unit => "", :negative_format => "(%n)"})) + assert_equal("1,234,567,890.50 Kč", number_helper.number_to_currency("1234567890.50", unit: "Kč", format: "%n %u")) + assert_equal("1,234,567,890.50 - Kč", number_helper.number_to_currency("-1234567890.50", unit: "Kč", format: "%n %u", negative_format: "%n - %u")) + assert_equal("0.00", number_helper.number_to_currency(+0.0, unit: "", negative_format: "(%n)")) end end def test_number_to_percentage [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| assert_equal("100.000%", number_helper.number_to_percentage(100)) - assert_equal("100%", number_helper.number_to_percentage(100, {:precision => 0})) - assert_equal("302.06%", number_helper.number_to_percentage(302.0574, {:precision => 2})) + assert_equal("100%", number_helper.number_to_percentage(100, precision: 0)) + assert_equal("302.06%", number_helper.number_to_percentage(302.0574, precision: 2)) assert_equal("100.000%", number_helper.number_to_percentage("100")) assert_equal("1000.000%", number_helper.number_to_percentage("1000")) - assert_equal("123.4%", number_helper.number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true)) - assert_equal("1.000,000%", number_helper.number_to_percentage(1000, :delimiter => '.', :separator => ',')) - assert_equal("1000.000 %", number_helper.number_to_percentage(1000, :format => "%n %")) + assert_equal("123.4%", number_helper.number_to_percentage(123.400, precision: 3, strip_insignificant_zeros: true)) + assert_equal("1.000,000%", number_helper.number_to_percentage(1000, delimiter: ".", separator: ",")) + assert_equal("1000.000 %", number_helper.number_to_percentage(1000, format: "%n %")) assert_equal("98a%", number_helper.number_to_percentage("98a")) assert_equal("NaN%", number_helper.number_to_percentage(Float::NAN)) assert_equal("Inf%", number_helper.number_to_percentage(Float::INFINITY)) @@ -122,9 +121,9 @@ module ActiveSupport def test_to_delimited_with_options_hash [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '12 345 678', number_helper.number_to_delimited(12345678, :delimiter => ' ') - assert_equal '12,345,678-05', number_helper.number_to_delimited(12345678.05, :separator => '-') - assert_equal '12.345.678,05', number_helper.number_to_delimited(12345678.05, :separator => ',', :delimiter => '.') + assert_equal "12 345 678", number_helper.number_to_delimited(12345678, delimiter: " ") + assert_equal "12,345,678-05", number_helper.number_to_delimited(12345678.05, separator: "-") + assert_equal "12.345.678,05", number_helper.number_to_delimited(12345678.05, separator: ",", delimiter: ".") end end @@ -132,77 +131,77 @@ module ActiveSupport [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| assert_equal("-111.235", number_helper.number_to_rounded(-111.2346)) assert_equal("111.235", number_helper.number_to_rounded(111.2346)) - assert_equal("31.83", number_helper.number_to_rounded(31.825, :precision => 2)) - assert_equal("111.23", number_helper.number_to_rounded(111.2346, :precision => 2)) - assert_equal("111.00", number_helper.number_to_rounded(111, :precision => 2)) + assert_equal("31.83", number_helper.number_to_rounded(31.825, precision: 2)) + assert_equal("111.23", number_helper.number_to_rounded(111.2346, precision: 2)) + assert_equal("111.00", number_helper.number_to_rounded(111, precision: 2)) assert_equal("111.235", number_helper.number_to_rounded("111.2346")) - assert_equal("31.83", number_helper.number_to_rounded("31.825", :precision => 2)) - assert_equal("3268", number_helper.number_to_rounded((32.6751 * 100.00), :precision => 0)) - assert_equal("112", number_helper.number_to_rounded(111.50, :precision => 0)) - assert_equal("1234567892", number_helper.number_to_rounded(1234567891.50, :precision => 0)) - assert_equal("0", number_helper.number_to_rounded(0, :precision => 0)) - assert_equal("0.00100", number_helper.number_to_rounded(0.001, :precision => 5)) - assert_equal("0.001", number_helper.number_to_rounded(0.00111, :precision => 3)) - assert_equal("10.00", number_helper.number_to_rounded(9.995, :precision => 2)) - assert_equal("11.00", number_helper.number_to_rounded(10.995, :precision => 2)) - assert_equal("0.00", number_helper.number_to_rounded(-0.001, :precision => 2)) - - assert_equal("111.23460000000000000000", number_helper.number_to_rounded(111.2346, :precision => 20)) - assert_equal("111.23460000000000000000", number_helper.number_to_rounded(Rational(1112346, 10000), :precision => 20)) - assert_equal("111.23460000000000000000", number_helper.number_to_rounded('111.2346', :precision => 20)) - assert_equal("111.23460000000000000000", number_helper.number_to_rounded(BigDecimal(111.2346, Float::DIG), :precision => 20)) - assert_equal("111.2346" + "0"*96, number_helper.number_to_rounded('111.2346', :precision => 100)) - assert_equal("111.2346", number_helper.number_to_rounded(Rational(1112346, 10000), :precision => 4)) - assert_equal('0.00', number_helper.number_to_rounded(Rational(0, 1), :precision => 2)) + assert_equal("31.83", number_helper.number_to_rounded("31.825", precision: 2)) + assert_equal("3268", number_helper.number_to_rounded((32.6751 * 100.00), precision: 0)) + assert_equal("112", number_helper.number_to_rounded(111.50, precision: 0)) + assert_equal("1234567892", number_helper.number_to_rounded(1234567891.50, precision: 0)) + assert_equal("0", number_helper.number_to_rounded(0, precision: 0)) + assert_equal("0.00100", number_helper.number_to_rounded(0.001, precision: 5)) + assert_equal("0.001", number_helper.number_to_rounded(0.00111, precision: 3)) + assert_equal("10.00", number_helper.number_to_rounded(9.995, precision: 2)) + assert_equal("11.00", number_helper.number_to_rounded(10.995, precision: 2)) + assert_equal("0.00", number_helper.number_to_rounded(-0.001, precision: 2)) + + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(111.2346, precision: 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(Rational(1112346, 10000), precision: 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded("111.2346", precision: 20)) + assert_equal("111.23460000000000000000", number_helper.number_to_rounded(BigDecimal(111.2346, Float::DIG), precision: 20)) + assert_equal("111.2346" + "0"*96, number_helper.number_to_rounded("111.2346", precision: 100)) + assert_equal("111.2346", number_helper.number_to_rounded(Rational(1112346, 10000), precision: 4)) + assert_equal("0.00", number_helper.number_to_rounded(Rational(0, 1), precision: 2)) end end def test_to_rounded_with_custom_delimiter_and_separator [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '31,83', number_helper.number_to_rounded(31.825, :precision => 2, :separator => ',') - assert_equal '1.231,83', number_helper.number_to_rounded(1231.825, :precision => 2, :separator => ',', :delimiter => '.') + assert_equal "31,83", number_helper.number_to_rounded(31.825, precision: 2, separator: ",") + assert_equal "1.231,83", number_helper.number_to_rounded(1231.825, precision: 2, separator: ",", delimiter: ".") end end def test_to_rounded_with_significant_digits [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal "124000", number_helper.number_to_rounded(123987, :precision => 3, :significant => true) - assert_equal "120000000", number_helper.number_to_rounded(123987876, :precision => 2, :significant => true ) - assert_equal "40000", number_helper.number_to_rounded("43523", :precision => 1, :significant => true ) - assert_equal "9775", number_helper.number_to_rounded(9775, :precision => 4, :significant => true ) - assert_equal "5.4", number_helper.number_to_rounded(5.3923, :precision => 2, :significant => true ) - assert_equal "5", number_helper.number_to_rounded(5.3923, :precision => 1, :significant => true ) - assert_equal "1", number_helper.number_to_rounded(1.232, :precision => 1, :significant => true ) - assert_equal "7", number_helper.number_to_rounded(7, :precision => 1, :significant => true ) - assert_equal "1", number_helper.number_to_rounded(1, :precision => 1, :significant => true ) - assert_equal "53", number_helper.number_to_rounded(52.7923, :precision => 2, :significant => true ) - assert_equal "9775.00", number_helper.number_to_rounded(9775, :precision => 6, :significant => true ) - assert_equal "5.392900", number_helper.number_to_rounded(5.3929, :precision => 7, :significant => true ) - assert_equal "0.0", number_helper.number_to_rounded(0, :precision => 2, :significant => true ) - assert_equal "0", number_helper.number_to_rounded(0, :precision => 1, :significant => true ) - assert_equal "0.0001", number_helper.number_to_rounded(0.0001, :precision => 1, :significant => true ) - assert_equal "0.000100", number_helper.number_to_rounded(0.0001, :precision => 3, :significant => true ) - assert_equal "0.0001", number_helper.number_to_rounded(0.0001111, :precision => 1, :significant => true ) - assert_equal "10.0", number_helper.number_to_rounded(9.995, :precision => 3, :significant => true) - assert_equal "9.99", number_helper.number_to_rounded(9.994, :precision => 3, :significant => true) - assert_equal "11.0", number_helper.number_to_rounded(10.995, :precision => 3, :significant => true) - - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775, :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775.0, :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(Rational(9775, 1), :precision => 20, :significant => true ) - assert_equal "97.750000000000000000", number_helper.number_to_rounded(Rational(9775, 100), :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded(BigDecimal(9775), :precision => 20, :significant => true ) - assert_equal "9775.0000000000000000", number_helper.number_to_rounded("9775", :precision => 20, :significant => true ) - assert_equal "9775." + "0"*96, number_helper.number_to_rounded("9775", :precision => 100, :significant => true ) - assert_equal("97.7", number_helper.number_to_rounded(Rational(9772, 100), :precision => 3, :significant => true)) + assert_equal "124000", number_helper.number_to_rounded(123987, precision: 3, significant: true) + assert_equal "120000000", number_helper.number_to_rounded(123987876, precision: 2, significant: true ) + assert_equal "40000", number_helper.number_to_rounded("43523", precision: 1, significant: true ) + assert_equal "9775", number_helper.number_to_rounded(9775, precision: 4, significant: true ) + assert_equal "5.4", number_helper.number_to_rounded(5.3923, precision: 2, significant: true ) + assert_equal "5", number_helper.number_to_rounded(5.3923, precision: 1, significant: true ) + assert_equal "1", number_helper.number_to_rounded(1.232, precision: 1, significant: true ) + assert_equal "7", number_helper.number_to_rounded(7, precision: 1, significant: true ) + assert_equal "1", number_helper.number_to_rounded(1, precision: 1, significant: true ) + assert_equal "53", number_helper.number_to_rounded(52.7923, precision: 2, significant: true ) + assert_equal "9775.00", number_helper.number_to_rounded(9775, precision: 6, significant: true ) + assert_equal "5.392900", number_helper.number_to_rounded(5.3929, precision: 7, significant: true ) + assert_equal "0.0", number_helper.number_to_rounded(0, precision: 2, significant: true ) + assert_equal "0", number_helper.number_to_rounded(0, precision: 1, significant: true ) + assert_equal "0.0001", number_helper.number_to_rounded(0.0001, precision: 1, significant: true ) + assert_equal "0.000100", number_helper.number_to_rounded(0.0001, precision: 3, significant: true ) + assert_equal "0.0001", number_helper.number_to_rounded(0.0001111, precision: 1, significant: true ) + assert_equal "10.0", number_helper.number_to_rounded(9.995, precision: 3, significant: true) + assert_equal "9.99", number_helper.number_to_rounded(9.994, precision: 3, significant: true) + assert_equal "11.0", number_helper.number_to_rounded(10.995, precision: 3, significant: true) + + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775, precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(9775.0, precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(Rational(9775, 1), precision: 20, significant: true ) + assert_equal "97.750000000000000000", number_helper.number_to_rounded(Rational(9775, 100), precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded(BigDecimal(9775), precision: 20, significant: true ) + assert_equal "9775.0000000000000000", number_helper.number_to_rounded("9775", precision: 20, significant: true ) + assert_equal "9775." + "0"*96, number_helper.number_to_rounded("9775", precision: 100, significant: true ) + assert_equal("97.7", number_helper.number_to_rounded(Rational(9772, 100), precision: 3, significant: true)) end end def test_to_rounded_with_strip_insignificant_zeros [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal "9775.43", number_helper.number_to_rounded(9775.43, :precision => 4, :strip_insignificant_zeros => true ) - assert_equal "9775.2", number_helper.number_to_rounded(9775.2, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) - assert_equal "0", number_helper.number_to_rounded(0, :precision => 6, :significant => true, :strip_insignificant_zeros => true ) + assert_equal "9775.43", number_helper.number_to_rounded(9775.43, precision: 4, strip_insignificant_zeros: true ) + assert_equal "9775.2", number_helper.number_to_rounded(9775.2, precision: 6, significant: true, strip_insignificant_zeros: true ) + assert_equal "0", number_helper.number_to_rounded(0, precision: 6, significant: true, strip_insignificant_zeros: true ) end end @@ -210,156 +209,156 @@ module ActiveSupport [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| # Zero precision with significant is a mistake (would always return zero), # so we treat it as if significant was false (increases backwards compatibility for number_to_human_size) - assert_equal "124", number_helper.number_to_rounded(123.987, :precision => 0, :significant => true) - assert_equal "12", number_helper.number_to_rounded(12, :precision => 0, :significant => true ) - assert_equal "12", number_helper.number_to_rounded("12.3", :precision => 0, :significant => true ) + assert_equal "124", number_helper.number_to_rounded(123.987, precision: 0, significant: true) + assert_equal "12", number_helper.number_to_rounded(12, precision: 0, significant: true ) + assert_equal "12", number_helper.number_to_rounded("12.3", precision: 0, significant: true ) end end def test_number_number_to_human_size [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '0 Bytes', number_helper.number_to_human_size(0) - assert_equal '1 Byte', number_helper.number_to_human_size(1) - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265) - assert_equal '123 Bytes', number_helper.number_to_human_size(123.0) - assert_equal '123 Bytes', number_helper.number_to_human_size(123) - assert_equal '1.21 KB', number_helper.number_to_human_size(1234) - assert_equal '12.1 KB', number_helper.number_to_human_size(12345) - assert_equal '1.18 MB', number_helper.number_to_human_size(1234567) - assert_equal '1.15 GB', number_helper.number_to_human_size(1234567890) - assert_equal '1.12 TB', number_helper.number_to_human_size(1234567890123) - assert_equal '1.1 PB', number_helper.number_to_human_size(1234567890123456) - assert_equal '1.07 EB', number_helper.number_to_human_size(1234567890123456789) - assert_equal '1030 EB', number_helper.number_to_human_size(exabytes(1026)) - assert_equal '444 KB', number_helper.number_to_human_size(kilobytes(444)) - assert_equal '1020 MB', number_helper.number_to_human_size(megabytes(1023)) - assert_equal '3 TB', number_helper.number_to_human_size(terabytes(3)) - assert_equal '1.2 MB', number_helper.number_to_human_size(1234567, :precision => 2) - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :precision => 4) - assert_equal '123 Bytes', number_helper.number_to_human_size('123') - assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2) - assert_equal '1.01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4) - assert_equal '10 KB', number_helper.number_to_human_size(kilobytes(10.000), :precision => 4) - assert_equal '1 Byte', number_helper.number_to_human_size(1.1) - assert_equal '10 Bytes', number_helper.number_to_human_size(10) + assert_equal "0 Bytes", number_helper.number_to_human_size(0) + assert_equal "1 Byte", number_helper.number_to_human_size(1) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265) + assert_equal "123 Bytes", number_helper.number_to_human_size(123.0) + assert_equal "123 Bytes", number_helper.number_to_human_size(123) + assert_equal "1.21 KB", number_helper.number_to_human_size(1234) + assert_equal "12.1 KB", number_helper.number_to_human_size(12345) + assert_equal "1.18 MB", number_helper.number_to_human_size(1234567) + assert_equal "1.15 GB", number_helper.number_to_human_size(1234567890) + assert_equal "1.12 TB", number_helper.number_to_human_size(1234567890123) + assert_equal "1.1 PB", number_helper.number_to_human_size(1234567890123456) + assert_equal "1.07 EB", number_helper.number_to_human_size(1234567890123456789) + assert_equal "1030 EB", number_helper.number_to_human_size(exabytes(1026)) + assert_equal "444 KB", number_helper.number_to_human_size(kilobytes(444)) + assert_equal "1020 MB", number_helper.number_to_human_size(megabytes(1023)) + assert_equal "3 TB", number_helper.number_to_human_size(terabytes(3)) + assert_equal "1.2 MB", number_helper.number_to_human_size(1234567, precision: 2) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265, precision: 4) + assert_equal "123 Bytes", number_helper.number_to_human_size("123") + assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 2) + assert_equal "1.01 KB", number_helper.number_to_human_size(kilobytes(1.0100), precision: 4) + assert_equal "10 KB", number_helper.number_to_human_size(kilobytes(10.000), precision: 4) + assert_equal "1 Byte", number_helper.number_to_human_size(1.1) + assert_equal "10 Bytes", number_helper.number_to_human_size(10) end end def test_number_to_human_size_with_si_prefix assert_deprecated do [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :prefix => :si) - assert_equal '123 Bytes', number_helper.number_to_human_size(123.0, :prefix => :si) - assert_equal '123 Bytes', number_helper.number_to_human_size(123, :prefix => :si) - assert_equal '1.23 KB', number_helper.number_to_human_size(1234, :prefix => :si) - assert_equal '12.3 KB', number_helper.number_to_human_size(12345, :prefix => :si) - assert_equal '1.23 MB', number_helper.number_to_human_size(1234567, :prefix => :si) - assert_equal '1.23 GB', number_helper.number_to_human_size(1234567890, :prefix => :si) - assert_equal '1.23 TB', number_helper.number_to_human_size(1234567890123, :prefix => :si) - assert_equal '1.23 PB', number_helper.number_to_human_size(1234567890123456, :prefix => :si) - assert_equal '1.23 EB', number_helper.number_to_human_size(1234567890123456789, :prefix => :si) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265, prefix: :si) + assert_equal "123 Bytes", number_helper.number_to_human_size(123.0, prefix: :si) + assert_equal "123 Bytes", number_helper.number_to_human_size(123, prefix: :si) + assert_equal "1.23 KB", number_helper.number_to_human_size(1234, prefix: :si) + assert_equal "12.3 KB", number_helper.number_to_human_size(12345, prefix: :si) + assert_equal "1.23 MB", number_helper.number_to_human_size(1234567, prefix: :si) + assert_equal "1.23 GB", number_helper.number_to_human_size(1234567890, prefix: :si) + assert_equal "1.23 TB", number_helper.number_to_human_size(1234567890123, prefix: :si) + assert_equal "1.23 PB", number_helper.number_to_human_size(1234567890123456, prefix: :si) + assert_equal "1.23 EB", number_helper.number_to_human_size(1234567890123456789, prefix: :si) end end end def test_number_to_human_size_with_options_hash [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '1.2 MB', number_helper.number_to_human_size(1234567, :precision => 2) - assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :precision => 4) - assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2) - assert_equal '1.01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4) - assert_equal '10 KB', number_helper.number_to_human_size(kilobytes(10.000), :precision => 4) - assert_equal '1 TB', number_helper.number_to_human_size(1234567890123, :precision => 1) - assert_equal '500 MB', number_helper.number_to_human_size(524288000, :precision=>3) - assert_equal '10 MB', number_helper.number_to_human_size(9961472, :precision=>0) - assert_equal '40 KB', number_helper.number_to_human_size(41010, :precision => 1) - assert_equal '40 KB', number_helper.number_to_human_size(41100, :precision => 2) - assert_equal '1.0 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 2, :strip_insignificant_zeros => false) - assert_equal '1.012 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 3, :significant => false) - assert_equal '1 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 0, :significant => true) #ignores significant it precision is 0 + assert_equal "1.2 MB", number_helper.number_to_human_size(1234567, precision: 2) + assert_equal "3 Bytes", number_helper.number_to_human_size(3.14159265, precision: 4) + assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 2) + assert_equal "1.01 KB", number_helper.number_to_human_size(kilobytes(1.0100), precision: 4) + assert_equal "10 KB", number_helper.number_to_human_size(kilobytes(10.000), precision: 4) + assert_equal "1 TB", number_helper.number_to_human_size(1234567890123, precision: 1) + assert_equal "500 MB", number_helper.number_to_human_size(524288000, precision: 3) + assert_equal "10 MB", number_helper.number_to_human_size(9961472, precision: 0) + assert_equal "40 KB", number_helper.number_to_human_size(41010, precision: 1) + assert_equal "40 KB", number_helper.number_to_human_size(41100, precision: 2) + assert_equal "1.0 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 2, strip_insignificant_zeros: false) + assert_equal "1.012 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 3, significant: false) + assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 0, significant: true) #ignores significant it precision is 0 end end def test_number_to_human_size_with_custom_delimiter_and_separator [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '1,01 KB', number_helper.number_to_human_size(kilobytes(1.0123), :precision => 3, :separator => ',') - assert_equal '1,01 KB', number_helper.number_to_human_size(kilobytes(1.0100), :precision => 4, :separator => ',') - assert_equal '1.000,1 TB', number_helper.number_to_human_size(terabytes(1000.1), :precision => 5, :delimiter => '.', :separator => ',') + assert_equal "1,01 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 3, separator: ",") + assert_equal "1,01 KB", number_helper.number_to_human_size(kilobytes(1.0100), precision: 4, separator: ",") + assert_equal "1.000,1 TB", number_helper.number_to_human_size(terabytes(1000.1), precision: 5, delimiter: ".", separator: ",") end end def test_number_to_human [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '-123', number_helper.number_to_human(-123) - assert_equal '-0.5', number_helper.number_to_human(-0.5) - assert_equal '0', number_helper.number_to_human(0) - assert_equal '0.5', number_helper.number_to_human(0.5) - assert_equal '123', number_helper.number_to_human(123) - assert_equal '1.23 Thousand', number_helper.number_to_human(1234) - assert_equal '12.3 Thousand', number_helper.number_to_human(12345) - assert_equal '1.23 Million', number_helper.number_to_human(1234567) - assert_equal '1.23 Billion', number_helper.number_to_human(1234567890) - assert_equal '1.23 Trillion', number_helper.number_to_human(1234567890123) - assert_equal '1.23 Quadrillion', number_helper.number_to_human(1234567890123456) - assert_equal '1230 Quadrillion', number_helper.number_to_human(1234567890123456789) - assert_equal '490 Thousand', number_helper.number_to_human(489939, :precision => 2) - assert_equal '489.9 Thousand', number_helper.number_to_human(489939, :precision => 4) - assert_equal '489 Thousand', number_helper.number_to_human(489000, :precision => 4) - assert_equal '489.0 Thousand', number_helper.number_to_human(489000, :precision => 4, :strip_insignificant_zeros => false) - assert_equal '1.2346 Million', number_helper.number_to_human(1234567, :precision => 4, :significant => false) - assert_equal '1,2 Million', number_helper.number_to_human(1234567, :precision => 1, :significant => false, :separator => ',') - assert_equal '1 Million', number_helper.number_to_human(1234567, :precision => 0, :significant => true, :separator => ',') #significant forced to false - assert_equal '1 Million', number_helper.number_to_human(999999) - assert_equal '1 Billion', number_helper.number_to_human(999999999) + assert_equal "-123", number_helper.number_to_human(-123) + assert_equal "-0.5", number_helper.number_to_human(-0.5) + assert_equal "0", number_helper.number_to_human(0) + assert_equal "0.5", number_helper.number_to_human(0.5) + assert_equal "123", number_helper.number_to_human(123) + assert_equal "1.23 Thousand", number_helper.number_to_human(1234) + assert_equal "12.3 Thousand", number_helper.number_to_human(12345) + assert_equal "1.23 Million", number_helper.number_to_human(1234567) + assert_equal "1.23 Billion", number_helper.number_to_human(1234567890) + assert_equal "1.23 Trillion", number_helper.number_to_human(1234567890123) + assert_equal "1.23 Quadrillion", number_helper.number_to_human(1234567890123456) + assert_equal "1230 Quadrillion", number_helper.number_to_human(1234567890123456789) + assert_equal "490 Thousand", number_helper.number_to_human(489939, precision: 2) + assert_equal "489.9 Thousand", number_helper.number_to_human(489939, precision: 4) + assert_equal "489 Thousand", number_helper.number_to_human(489000, precision: 4) + assert_equal "489.0 Thousand", number_helper.number_to_human(489000, precision: 4, strip_insignificant_zeros: false) + assert_equal "1.2346 Million", number_helper.number_to_human(1234567, precision: 4, significant: false) + assert_equal "1,2 Million", number_helper.number_to_human(1234567, precision: 1, significant: false, separator: ",") + assert_equal "1 Million", number_helper.number_to_human(1234567, precision: 0, significant: true, separator: ",") #significant forced to false + assert_equal "1 Million", number_helper.number_to_human(999999) + assert_equal "1 Billion", number_helper.number_to_human(999999999) end end def test_number_to_human_with_custom_units [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| #Only integers - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123 lt', number_helper.number_to_human(123456, :units => volume) - assert_equal '12 ml', number_helper.number_to_human(12, :units => volume) - assert_equal '1.23 m3', number_helper.number_to_human(1234567, :units => volume) + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123 lt", number_helper.number_to_human(123456, units: volume) + assert_equal "12 ml", number_helper.number_to_human(12, units: volume) + assert_equal "1.23 m3", number_helper.number_to_human(1234567, units: volume) #Including fractionals - distance = {:mili => "mm", :centi => "cm", :deci => "dm", :unit => "m", :ten => "dam", :hundred => "hm", :thousand => "km"} - assert_equal '1.23 mm', number_helper.number_to_human(0.00123, :units => distance) - assert_equal '1.23 cm', number_helper.number_to_human(0.0123, :units => distance) - assert_equal '1.23 dm', number_helper.number_to_human(0.123, :units => distance) - assert_equal '1.23 m', number_helper.number_to_human(1.23, :units => distance) - assert_equal '1.23 dam', number_helper.number_to_human(12.3, :units => distance) - assert_equal '1.23 hm', number_helper.number_to_human(123, :units => distance) - assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance) - assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance) - assert_equal '1.23 km', number_helper.number_to_human(1230, :units => distance) - assert_equal '12.3 km', number_helper.number_to_human(12300, :units => distance) + distance = { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } + assert_equal "1.23 mm", number_helper.number_to_human(0.00123, units: distance) + assert_equal "1.23 cm", number_helper.number_to_human(0.0123, units: distance) + assert_equal "1.23 dm", number_helper.number_to_human(0.123, units: distance) + assert_equal "1.23 m", number_helper.number_to_human(1.23, units: distance) + assert_equal "1.23 dam", number_helper.number_to_human(12.3, units: distance) + assert_equal "1.23 hm", number_helper.number_to_human(123, units: distance) + assert_equal "1.23 km", number_helper.number_to_human(1230, units: distance) + assert_equal "1.23 km", number_helper.number_to_human(1230, units: distance) + assert_equal "1.23 km", number_helper.number_to_human(1230, units: distance) + assert_equal "12.3 km", number_helper.number_to_human(12300, units: distance) #The quantifiers don't need to be a continuous sequence - gangster = {:hundred => "hundred bucks", :million => "thousand quids"} - assert_equal '1 hundred bucks', number_helper.number_to_human(100, :units => gangster) - assert_equal '25 hundred bucks', number_helper.number_to_human(2500, :units => gangster) - assert_equal '25 thousand quids', number_helper.number_to_human(25000000, :units => gangster) - assert_equal '12300 thousand quids', number_helper.number_to_human(12345000000, :units => gangster) + gangster = { hundred: "hundred bucks", million: "thousand quids" } + assert_equal "1 hundred bucks", number_helper.number_to_human(100, units: gangster) + assert_equal "25 hundred bucks", number_helper.number_to_human(2500, units: gangster) + assert_equal "25 thousand quids", number_helper.number_to_human(25000000, units: gangster) + assert_equal "12300 thousand quids", number_helper.number_to_human(12345000000, units: gangster) #Spaces are stripped from the resulting string - assert_equal '4', number_helper.number_to_human(4, :units => {:unit => "", :ten => 'tens '}) - assert_equal '4.5 tens', number_helper.number_to_human(45, :units => {:unit => "", :ten => ' tens '}) + assert_equal "4", number_helper.number_to_human(4, units: { unit: "", ten: "tens " }) + assert_equal "4.5 tens", number_helper.number_to_human(45, units: { unit: "", ten: " tens " }) end end def test_number_to_human_with_custom_units_that_are_missing_the_needed_key [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '123', number_helper.number_to_human(123, units: { thousand: 'k'}) - assert_equal '123', number_helper.number_to_human(123, units: {}) + assert_equal "123", number_helper.number_to_human(123, units: { thousand: "k" }) + assert_equal "123", number_helper.number_to_human(123, units: {}) end end def test_number_to_human_with_custom_format [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal '123 times Thousand', number_helper.number_to_human(123456, :format => "%n times %u") - volume = {:unit => "ml", :thousand => "lt", :million => "m3"} - assert_equal '123.lt', number_helper.number_to_human(123456, :units => volume, :format => "%n.%u") + assert_equal "123 times Thousand", number_helper.number_to_human(123456, format: "%n times %u") + volume = { unit: "ml", thousand: "lt", million: "m3" } + assert_equal "123.lt", number_helper.number_to_human(123456, units: volume, format: "%n.%u") end end @@ -377,34 +376,34 @@ module ActiveSupport def test_number_helpers_do_not_mutate_options_hash [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - options = { 'raise' => true } + options = { "raise" => true } number_helper.number_to_phone(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_currency(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_percentage(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_delimited(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_rounded(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_human_size(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) number_helper.number_to_human(1, options) - assert_equal({ 'raise' => true }, options) + assert_equal({ "raise" => true }, options) end end def test_number_helpers_should_return_non_numeric_param_unchanged [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - assert_equal("+1-x x 123", number_helper.number_to_phone("x", :country_code => 1, :extension => 123)) + assert_equal("+1-x x 123", number_helper.number_to_phone("x", country_code: 1, extension: 123)) assert_equal("x", number_helper.number_to_phone("x")) assert_equal("$x.", number_helper.number_to_currency("x.")) assert_equal("$x", number_helper.number_to_currency("x")) @@ -412,11 +411,10 @@ module ActiveSupport assert_equal("x", number_helper.number_to_delimited("x")) assert_equal("x.", number_helper.number_to_rounded("x.")) assert_equal("x", number_helper.number_to_rounded("x")) - assert_equal "x", number_helper.number_to_human_size('x') - assert_equal "x", number_helper.number_to_human('x') + assert_equal "x", number_helper.number_to_human_size("x") + assert_equal "x", number_helper.number_to_human("x") end end - end end end diff --git a/activesupport/test/option_merger_test.rb b/activesupport/test/option_merger_test.rb index 4c0364e68b..c5a6d304ee 100644 --- a/activesupport/test/option_merger_test.rb +++ b/activesupport/test/option_merger_test.rb @@ -1,13 +1,13 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/with_options' +require "abstract_unit" +require "active_support/core_ext/object/with_options" class OptionMergerTest < ActiveSupport::TestCase def setup - @options = {:hello => 'world'} + @options = { hello: "world" } end def test_method_with_options_merges_options_when_options_are_present - local_options = {:cool => true} + local_options = { cool: true } with_options(@options) do |o| assert_equal local_options, method_with_options(local_options) @@ -24,7 +24,7 @@ class OptionMergerTest < ActiveSupport::TestCase end def test_method_with_options_allows_to_overwrite_options - local_options = {:hello => 'moon'} + local_options = { hello: "moon" } assert_equal @options.keys, local_options.keys with_options(@options) do |o| @@ -40,34 +40,34 @@ class OptionMergerTest < ActiveSupport::TestCase end def test_nested_method_with_options_containing_hashes_merge - with_options :conditions => { :method => :get } do |outer| - outer.with_options :conditions => { :domain => "www" } do |inner| - expected = { :conditions => { :method => :get, :domain => "www" } } + with_options conditions: { method: :get } do |outer| + outer.with_options conditions: { domain: "www" } do |inner| + expected = { conditions: { method: :get, domain: "www" } } assert_equal expected, inner.method_with_options end end end def test_nested_method_with_options_containing_hashes_overwrite - with_options :conditions => { :method => :get, :domain => "www" } do |outer| - outer.with_options :conditions => { :method => :post } do |inner| - expected = { :conditions => { :method => :post, :domain => "www" } } + with_options conditions: { method: :get, domain: "www" } do |outer| + outer.with_options conditions: { method: :post } do |inner| + expected = { conditions: { method: :post, domain: "www" } } assert_equal expected, inner.method_with_options end end end def test_nested_method_with_options_containing_hashes_going_deep - with_options :html => { :class => "foo", :style => { :margin => 0, :display => "block" } } do |outer| - outer.with_options :html => { :title => "bar", :style => { :margin => "1em", :color => "#fff" } } do |inner| - expected = { :html => { :class => "foo", :title => "bar", :style => { :margin => "1em", :display => "block", :color => "#fff" } } } + with_options html: { class: "foo", style: { margin: 0, display: "block" } } do |outer| + outer.with_options html: { title: "bar", style: { margin: "1em", color: "#fff" } } do |inner| + expected = { html: { class: "foo", title: "bar", style: { margin: "1em", display: "block", color: "#fff" } } } assert_equal expected, inner.method_with_options end end end def test_nested_method_with_options_using_lambda - local_lambda = lambda { { :lambda => true } } + local_lambda = lambda { { lambda: true } } with_options(@options) do |o| assert_equal @options.merge(local_lambda.call), o.method_with_options(local_lambda).call @@ -76,7 +76,7 @@ class OptionMergerTest < ActiveSupport::TestCase # Needed when counting objects with the ObjectSpace def test_option_merger_class_method - assert_equal ActiveSupport::OptionMerger, ActiveSupport::OptionMerger.new('', '').class + assert_equal ActiveSupport::OptionMerger, ActiveSupport::OptionMerger.new("", "").class end def test_option_merger_implicit_receiver diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb index 460a61613e..86da9f193a 100644 --- a/activesupport/test/ordered_hash_test.rb +++ b/activesupport/test/ordered_hash_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' -require 'active_support/json' -require 'active_support/core_ext/object/json' -require 'active_support/core_ext/hash/indifferent_access' -require 'active_support/core_ext/array/extract_options' +require "abstract_unit" +require "active_support/json" +require "active_support/core_ext/object/json" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/array/extract_options" class OrderedHashTest < ActiveSupport::TestCase def setup @@ -27,7 +27,7 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_assignment - key, value = 'purple', '5422a8' + key, value = "purple", "5422a8" @ordered_hash[key] = value assert_equal @keys.length + 1, @ordered_hash.length @@ -37,8 +37,8 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_delete - key, value = 'white', 'ffffff' - bad_key = 'black' + key, value = "white", "ffffff" + bad_key = "black" @ordered_hash[key] = value assert_equal @keys.length + 1, @ordered_hash.length @@ -60,22 +60,22 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_has_key - assert_equal true, @ordered_hash.has_key?('blue') - assert_equal true, @ordered_hash.key?('blue') - assert_equal true, @ordered_hash.include?('blue') - assert_equal true, @ordered_hash.member?('blue') + assert_equal true, @ordered_hash.has_key?("blue") + assert_equal true, @ordered_hash.key?("blue") + assert_equal true, @ordered_hash.include?("blue") + assert_equal true, @ordered_hash.member?("blue") - assert_equal false, @ordered_hash.has_key?('indigo') - assert_equal false, @ordered_hash.key?('indigo') - assert_equal false, @ordered_hash.include?('indigo') - assert_equal false, @ordered_hash.member?('indigo') + assert_equal false, @ordered_hash.has_key?("indigo") + assert_equal false, @ordered_hash.key?("indigo") + assert_equal false, @ordered_hash.include?("indigo") + assert_equal false, @ordered_hash.member?("indigo") end def test_has_value - assert_equal true, @ordered_hash.has_value?('000099') - assert_equal true, @ordered_hash.value?('000099') - assert_equal false, @ordered_hash.has_value?('ABCABC') - assert_equal false, @ordered_hash.value?('ABCABC') + assert_equal true, @ordered_hash.has_value?("000099") + assert_equal true, @ordered_hash.value?("000099") + assert_equal false, @ordered_hash.has_value?("ABCABC") + assert_equal false, @ordered_hash.value?("ABCABC") end def test_each_key @@ -94,13 +94,13 @@ class OrderedHashTest < ActiveSupport::TestCase def test_each values = [] - assert_equal @ordered_hash, @ordered_hash.each {|key, value| values << value} + assert_equal @ordered_hash, @ordered_hash.each { |key, value| values << value } assert_equal @values, values assert_kind_of Enumerator, @ordered_hash.each end def test_each_with_index - @ordered_hash.each_with_index { |pair, index| assert_equal [@keys[index], @values[index]], pair} + @ordered_hash.each_with_index { |pair, index| assert_equal [@keys[index], @values[index]], pair } end def test_each_pair @@ -127,24 +127,24 @@ class OrderedHashTest < ActiveSupport::TestCase def test_delete_if copy = @ordered_hash.dup - copy.delete('pink') - assert_equal copy, @ordered_hash.delete_if { |k, _| k == 'pink' } - assert !@ordered_hash.keys.include?('pink') + copy.delete("pink") + assert_equal copy, @ordered_hash.delete_if { |k, _| k == "pink" } + assert_not_includes @ordered_hash.keys, "pink" end def test_reject! - (copy = @ordered_hash.dup).delete('pink') - @ordered_hash.reject! { |k, _| k == 'pink' } + (copy = @ordered_hash.dup).delete("pink") + @ordered_hash.reject! { |k, _| k == "pink" } assert_equal copy, @ordered_hash - assert !@ordered_hash.keys.include?('pink') + assert_not_includes @ordered_hash.keys, "pink" end def test_reject copy = @ordered_hash.dup - new_ordered_hash = @ordered_hash.reject { |k, _| k == 'pink' } + new_ordered_hash = @ordered_hash.reject { |k, _| k == "pink" } assert_equal copy, @ordered_hash - assert !new_ordered_hash.keys.include?('pink') - assert @ordered_hash.keys.include?('pink') + assert_not_includes new_ordered_hash.keys, "pink" + assert_includes @ordered_hash.keys, "pink" assert_instance_of ActiveSupport::OrderedHash, new_ordered_hash end @@ -155,18 +155,18 @@ class OrderedHashTest < ActiveSupport::TestCase def test_merge other_hash = ActiveSupport::OrderedHash.new - other_hash['purple'] = '800080' - other_hash['violet'] = 'ee82ee' + other_hash["purple"] = "800080" + other_hash["violet"] = "ee82ee" merged = @ordered_hash.merge other_hash assert_equal merged.length, @ordered_hash.length + other_hash.length - assert_equal @keys + ['purple', 'violet'], merged.keys + assert_equal @keys + ["purple", "violet"], merged.keys end def test_merge_with_block hash = ActiveSupport::OrderedHash.new hash[:a] = 0 hash[:b] = 0 - merged = hash.merge(:b => 2, :c => 7) do |key, old_value, new_value| + merged = hash.merge(b: 2, c: 7) do |key, old_value, new_value| new_value + 1 end @@ -179,7 +179,7 @@ class OrderedHashTest < ActiveSupport::TestCase hash = ActiveSupport::OrderedHash.new hash[:a] = 0 hash[:b] = 0 - hash.merge!(:a => 1, :c => 7) do |key, old_value, new_value| + hash.merge!(a: 1, c: 7) do |key, old_value, new_value| new_value + 3 end @@ -191,7 +191,7 @@ class OrderedHashTest < ActiveSupport::TestCase def test_shift pair = @ordered_hash.shift assert_equal [@keys.first, @values.first], pair - assert !@ordered_hash.keys.include?(pair.first) + assert_not_includes @ordered_hash.keys, pair.first end def test_keys @@ -201,7 +201,7 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_inspect - assert @ordered_hash.inspect.include?(@hash.inspect) + assert_includes @ordered_hash.inspect, @hash.inspect end def test_json @@ -220,11 +220,11 @@ class OrderedHashTest < ActiveSupport::TestCase alternate = ActiveSupport::OrderedHash[ [ [1, 2], [3, 4], - [ 'missing value' ] + [ "missing value" ] ]] assert_kind_of ActiveSupport::OrderedHash, alternate - assert_equal [1, 3, 'missing value'], alternate.keys + assert_equal [1, 3, "missing value"], alternate.keys assert_equal [2, 4, nil ], alternate.values end @@ -235,14 +235,14 @@ class OrderedHashTest < ActiveSupport::TestCase end def test_replace_updates_keys - @other_ordered_hash = ActiveSupport::OrderedHash[:black, '000000', :white, '000000'] + @other_ordered_hash = ActiveSupport::OrderedHash[:black, "000000", :white, "000000"] original = @ordered_hash.replace(@other_ordered_hash) assert_same original, @ordered_hash assert_equal @other_ordered_hash.keys, @ordered_hash.keys end def test_nested_under_indifferent_access - flash = {:a => ActiveSupport::OrderedHash[:b, 1, :c, 2]}.with_indifferent_access + flash = { a: ActiveSupport::OrderedHash[:b, 1, :c, 2] }.with_indifferent_access assert_kind_of ActiveSupport::OrderedHash, flash[:a] end @@ -295,17 +295,17 @@ class OrderedHashTest < ActiveSupport::TestCase def test_psych_serialize_tag yaml = Psych.dump(@ordered_hash) - assert_match '!omap', yaml + assert_match "!omap", yaml end def test_has_yaml_tag @ordered_hash[:array] = %w(a b c) - assert_match '!omap', YAML.dump(@ordered_hash) + assert_match "!omap", YAML.dump(@ordered_hash) end def test_update_sets_keys @updated_ordered_hash = ActiveSupport::OrderedHash.new - @updated_ordered_hash.update(:name => "Bob") + @updated_ordered_hash.update(name: "Bob") assert_equal [:name], @updated_ordered_hash.keys end diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb index 18767a3536..0417911289 100644 --- a/activesupport/test/ordered_options_test.rb +++ b/activesupport/test/ordered_options_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/ordered_options' +require "abstract_unit" +require "active_support/ordered_options" class OrderedOptionsTest < ActiveSupport::TestCase def test_usage diff --git a/activesupport/test/reloader_test.rb b/activesupport/test/reloader_test.rb index 958cb49993..67d8c4b0e3 100644 --- a/activesupport/test/reloader_test.rb +++ b/activesupport/test/reloader_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class ReloaderTest < ActiveSupport::TestCase def test_prepare_callback @@ -21,13 +21,13 @@ class ReloaderTest < ActiveSupport::TestCase r = new_reloader { true } invoked = false r.to_run { invoked = true } - r.wrap { } + r.wrap {} assert invoked r = new_reloader { false } invoked = false r.to_run { invoked = true } - r.wrap { } + r.wrap {} assert !invoked end @@ -39,7 +39,7 @@ class ReloaderTest < ActiveSupport::TestCase reloader.executor.to_run { called << :executor_run } reloader.executor.to_complete { called << :executor_complete } - reloader.wrap { } + reloader.wrap {} assert_equal [:executor_run, :reloader_run, :prepare, :reloader_complete, :executor_complete], called called = [] @@ -49,7 +49,7 @@ class ReloaderTest < ActiveSupport::TestCase reloader.check = lambda { false } called = [] - reloader.wrap { } + reloader.wrap {} assert_equal [:executor_run, :executor_complete], called called = [] diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb index e42e6d2973..7e5c3d1a8f 100644 --- a/activesupport/test/rescuable_test.rb +++ b/activesupport/test/rescuable_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class WraithAttack < StandardError end @@ -24,12 +24,12 @@ class Stargate include ActiveSupport::Rescuable - rescue_from WraithAttack, :with => :sos_first + rescue_from WraithAttack, with: :sos_first - rescue_from WraithAttack, :with => :sos + rescue_from WraithAttack, with: :sos - rescue_from 'NuclearExplosion' do - @result = 'alldead' + rescue_from "NuclearExplosion" do + @result = "alldead" end rescue_from MadRonon do |e| @@ -37,7 +37,7 @@ class Stargate end rescue_from WeirdError do - @result = 'weird' + @result = "weird" end def dispatch(method) @@ -63,7 +63,7 @@ class Stargate ronanize rescue # This is the exception we'll handle that doesn't have a cause. - raise 'unhandled RuntimeError with a handleable cause' + raise "unhandled RuntimeError with a handleable cause" end def weird @@ -77,11 +77,11 @@ class Stargate end def sos - @result = 'killed' + @result = "killed" end def sos_first - @result = 'sos_first' + @result = "sos_first" end end @@ -90,14 +90,13 @@ class CoolStargate < Stargate include ActiveSupport::Rescuable - rescue_from CoolError, :with => :sos_cool_error + rescue_from CoolError, with: :sos_cool_error def sos_cool_error - @result = 'sos_cool_error' + @result = "sos_cool_error" end end - class RescuableTest < ActiveSupport::TestCase def setup @stargate = Stargate.new @@ -106,22 +105,22 @@ class RescuableTest < ActiveSupport::TestCase def test_rescue_from_with_method @stargate.dispatch :attack - assert_equal 'killed', @stargate.result + assert_equal "killed", @stargate.result end def test_rescue_from_with_block @stargate.dispatch :nuke - assert_equal 'alldead', @stargate.result + assert_equal "alldead", @stargate.result end def test_rescue_from_with_block_with_args @stargate.dispatch :ronanize - assert_equal 'dex', @stargate.result + assert_equal "dex", @stargate.result end def test_rescue_from_error_dispatchers_with_case_operator @stargate.dispatch :weird - assert_equal 'weird', @stargate.result + assert_equal "weird", @stargate.result end def test_rescues_defined_later_are_added_at_end_of_the_rescue_handlers_array @@ -138,6 +137,6 @@ class RescuableTest < ActiveSupport::TestCase def test_rescue_falls_back_to_exception_cause @stargate.dispatch :fall_back_to_cause - assert_equal 'unhandled RuntimeError with a handleable cause', @stargate.result + assert_equal "unhandled RuntimeError with a handleable cause", @stargate.result end end diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index 18fb6d2fbf..4d083ab773 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/string/inflections' -require 'yaml' +require "abstract_unit" +require "active_support/core_ext/string/inflections" +require "yaml" class SafeBufferTest < ActiveSupport::TestCase def setup @@ -8,7 +8,7 @@ class SafeBufferTest < ActiveSupport::TestCase end def test_titleize - assert_equal 'Foo', "foo".html_safe.titleize + assert_equal "Foo", "foo".html_safe.titleize end test "Should look like a string" do @@ -46,26 +46,26 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should be converted to_yaml" do - str = 'hello!' + str = "hello!" buf = ActiveSupport::SafeBuffer.new str yaml = buf.to_yaml assert_match(/^--- #{str}/, yaml) - assert_equal 'hello!', YAML.load(yaml) + assert_equal "hello!", YAML.load(yaml) end test "Should work in nested to_yaml conversion" do - str = 'hello!' - data = { 'str' => ActiveSupport::SafeBuffer.new(str) } + str = "hello!" + data = { "str" => ActiveSupport::SafeBuffer.new(str) } yaml = YAML.dump data - assert_equal({'str' => str}, YAML.load(yaml)) + assert_equal({ "str" => str }, YAML.load(yaml)) end test "Should work with primitive-like-strings in to_yaml conversion" do - assert_equal 'true', YAML.load(ActiveSupport::SafeBuffer.new('true').to_yaml) - assert_equal 'false', YAML.load(ActiveSupport::SafeBuffer.new('false').to_yaml) - assert_equal '1', YAML.load(ActiveSupport::SafeBuffer.new('1').to_yaml) - assert_equal '1.1', YAML.load(ActiveSupport::SafeBuffer.new('1.1').to_yaml) + assert_equal "true", YAML.load(ActiveSupport::SafeBuffer.new("true").to_yaml) + assert_equal "false", YAML.load(ActiveSupport::SafeBuffer.new("false").to_yaml) + assert_equal "1", YAML.load(ActiveSupport::SafeBuffer.new("1").to_yaml) + assert_equal "1.1", YAML.load(ActiveSupport::SafeBuffer.new("1.1").to_yaml) end test "Should work with underscore" do @@ -74,31 +74,31 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should not return safe buffer from gsub" do - altered_buffer = @buffer.gsub('', 'asdf') - assert_equal 'asdf', altered_buffer + altered_buffer = @buffer.gsub("", "asdf") + assert_equal "asdf", altered_buffer assert !altered_buffer.html_safe? end test "Should not return safe buffer from gsub!" do - @buffer.gsub!('', 'asdf') - assert_equal 'asdf', @buffer + @buffer.gsub!("", "asdf") + assert_equal "asdf", @buffer assert !@buffer.html_safe? end test "Should escape dirty buffers on add" do clean = "hello".html_safe - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert_equal "hello<>", clean + @buffer end test "Should concat as a normal string when safe" do clean = "hello".html_safe - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert_equal "<>hello", @buffer + clean end test "Should preserve html_safe? status on copy" do - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert !@buffer.dup.html_safe? end @@ -110,7 +110,7 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should raise an error when safe_concat is called on unsafe buffers" do - @buffer.gsub!('', '<>') + @buffer.gsub!("", "<>") assert_raise ActiveSupport::SafeBuffer::SafeConcatError do @buffer.safe_concat "BUSTED" end @@ -121,12 +121,12 @@ class SafeBufferTest < ActiveSupport::TestCase end test "clone_empty returns an empty buffer" do - assert_equal '', ActiveSupport::SafeBuffer.new('foo').clone_empty + assert_equal "", ActiveSupport::SafeBuffer.new("foo").clone_empty end test "clone_empty keeps the original dirtyness" do assert @buffer.clone_empty.html_safe? - assert !@buffer.gsub!('', '').clone_empty.html_safe? + assert !@buffer.gsub!("", "").clone_empty.html_safe? end test "Should be safe when sliced if original value was safe" do @@ -136,7 +136,7 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should continue unsafe on slice" do - x = 'foo'.html_safe.gsub!('f', '<script>alert("lolpwnd");</script>') + x = "foo".html_safe.gsub!("f", '<script>alert("lolpwnd");</script>') # calling gsub! makes the dirty flag true assert !x.html_safe?, "should not be safe" @@ -148,33 +148,33 @@ class SafeBufferTest < ActiveSupport::TestCase assert !y.html_safe?, "should not be safe" end - test 'Should work with interpolation (array argument)' do - x = 'foo %s bar'.html_safe % ['qux'] - assert_equal 'foo qux bar', x + test "Should work with interpolation (array argument)" do + x = "foo %s bar".html_safe % ["qux"] + assert_equal "foo qux bar", x end - test 'Should work with interpolation (hash argument)' do - x = 'foo %{x} bar'.html_safe % { x: 'qux' } - assert_equal 'foo qux bar', x + test "Should work with interpolation (hash argument)" do + x = "foo %{x} bar".html_safe % { x: "qux" } + assert_equal "foo qux bar", x end - test 'Should escape unsafe interpolated args' do - x = 'foo %{x} bar'.html_safe % { x: '<br/>' } - assert_equal 'foo <br/> bar', x + test "Should escape unsafe interpolated args" do + x = "foo %{x} bar".html_safe % { x: "<br/>" } + assert_equal "foo <br/> bar", x end - test 'Should not escape safe interpolated args' do - x = 'foo %{x} bar'.html_safe % { x: '<br/>'.html_safe } - assert_equal 'foo <br/> bar', x + test "Should not escape safe interpolated args" do + x = "foo %{x} bar".html_safe % { x: "<br/>".html_safe } + assert_equal "foo <br/> bar", x end - test 'Should interpolate to a safe string' do - x = 'foo %{x} bar'.html_safe % { x: 'qux' } - assert x.html_safe?, 'should be safe' + test "Should interpolate to a safe string" do + x = "foo %{x} bar".html_safe % { x: "qux" } + assert x.html_safe?, "should be safe" end - test 'Should not affect frozen objects when accessing characters' do - x = 'Hello'.html_safe + test "Should not affect frozen objects when accessing characters" do + x = "Hello".html_safe assert_equal x[/a/, 1], nil end end diff --git a/activesupport/test/security_utils_test.rb b/activesupport/test/security_utils_test.rb index 08d2e3baa6..842bdd469d 100644 --- a/activesupport/test/security_utils_test.rb +++ b/activesupport/test/security_utils_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/security_utils' +require "abstract_unit" +require "active_support/security_utils" class SecurityUtilsTest < ActiveSupport::TestCase def test_secure_compare_should_perform_string_comparison - assert ActiveSupport::SecurityUtils.secure_compare('a', 'a') - assert !ActiveSupport::SecurityUtils.secure_compare('a', 'b') + assert ActiveSupport::SecurityUtils.secure_compare("a", "a") + assert !ActiveSupport::SecurityUtils.secure_compare("a", "b") end end diff --git a/activesupport/test/share_lock_test.rb b/activesupport/test/share_lock_test.rb index acefa185a8..a5970591fa 100644 --- a/activesupport/test/share_lock_test.rb +++ b/activesupport/test/share_lock_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'concurrent/atomic/count_down_latch' -require 'active_support/concurrency/share_lock' +require "abstract_unit" +require "concurrent/atomic/count_down_latch" +require "active_support/concurrency/share_lock" class ShareLockTest < ActiveSupport::TestCase def setup @@ -17,7 +17,7 @@ class ShareLockTest < ActiveSupport::TestCase def test_sharing_doesnt_block with_thread_waiting_in_lock_section(:sharing) do |sharing_thread_latch| - assert_threads_not_stuck(Thread.new {@lock.sharing {} }) + assert_threads_not_stuck(Thread.new { @lock.sharing {} }) end end @@ -489,90 +489,90 @@ class ShareLockTest < ActiveSupport::TestCase private - module CustomAssertions - SUFFICIENT_TIMEOUT = 0.2 + module CustomAssertions + SUFFICIENT_TIMEOUT = 0.2 - private + private - def assert_threads_stuck_but_releasable_by_latch(threads, latch) - assert_threads_stuck threads - latch.count_down - assert_threads_not_stuck threads - end + def assert_threads_stuck_but_releasable_by_latch(threads, latch) + assert_threads_stuck threads + latch.count_down + assert_threads_not_stuck threads + end - def assert_threads_stuck(threads) - sleep(SUFFICIENT_TIMEOUT) # give threads time to do their business - assert(Array(threads).all? { |t| t.join(0.001).nil? }) - end + def assert_threads_stuck(threads) + sleep(SUFFICIENT_TIMEOUT) # give threads time to do their business + assert(Array(threads).all? { |t| t.join(0.001).nil? }) + end - def assert_threads_not_stuck(threads) - assert(Array(threads).all? { |t| t.join(SUFFICIENT_TIMEOUT) }) + def assert_threads_not_stuck(threads) + assert(Array(threads).all? { |t| t.join(SUFFICIENT_TIMEOUT) }) + end end - end - class CustomAssertionsTest < ActiveSupport::TestCase - include CustomAssertions + class CustomAssertionsTest < ActiveSupport::TestCase + include CustomAssertions - def setup - @latch = Concurrent::CountDownLatch.new - @thread = Thread.new { @latch.wait } - end + def setup + @latch = Concurrent::CountDownLatch.new + @thread = Thread.new { @latch.wait } + end - def teardown - @latch.count_down - @thread.join - end + def teardown + @latch.count_down + @thread.join + end - def test_happy_path - assert_threads_stuck_but_releasable_by_latch @thread, @latch - end + def test_happy_path + assert_threads_stuck_but_releasable_by_latch @thread, @latch + end - def test_detects_stuck_thread - assert_raises(Minitest::Assertion) do - assert_threads_not_stuck @thread + def test_detects_stuck_thread + assert_raises(Minitest::Assertion) do + assert_threads_not_stuck @thread + end end - end - def test_detects_free_thread - @latch.count_down - assert_raises(Minitest::Assertion) do - assert_threads_stuck @thread + def test_detects_free_thread + @latch.count_down + assert_raises(Minitest::Assertion) do + assert_threads_stuck @thread + end end - end - def test_detects_already_released - @latch.count_down - assert_raises(Minitest::Assertion) do - assert_threads_stuck_but_releasable_by_latch @thread, @latch + def test_detects_already_released + @latch.count_down + assert_raises(Minitest::Assertion) do + assert_threads_stuck_but_releasable_by_latch @thread, @latch + end end - end - def test_detects_remains_latched - another_latch = Concurrent::CountDownLatch.new - assert_raises(Minitest::Assertion) do - assert_threads_stuck_but_releasable_by_latch @thread, another_latch + def test_detects_remains_latched + another_latch = Concurrent::CountDownLatch.new + assert_raises(Minitest::Assertion) do + assert_threads_stuck_but_releasable_by_latch @thread, another_latch + end end end - end - include CustomAssertions + include CustomAssertions - def with_thread_waiting_in_lock_section(lock_section) - in_section = Concurrent::CountDownLatch.new - section_release = Concurrent::CountDownLatch.new + def with_thread_waiting_in_lock_section(lock_section) + in_section = Concurrent::CountDownLatch.new + section_release = Concurrent::CountDownLatch.new - stuck_thread = Thread.new do - @lock.send(lock_section) do - in_section.count_down - section_release.wait + stuck_thread = Thread.new do + @lock.send(lock_section) do + in_section.count_down + section_release.wait + end end - end - in_section.wait + in_section.wait - yield section_release - ensure - section_release.count_down - stuck_thread.join # clean up - end + yield section_release + ensure + section_release.count_down + stuck_thread.join # clean up + end end diff --git a/activesupport/test/string_inquirer_test.rb b/activesupport/test/string_inquirer_test.rb index a2ed577eb0..d41e4d6800 100644 --- a/activesupport/test/string_inquirer_test.rb +++ b/activesupport/test/string_inquirer_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' +require "abstract_unit" class StringInquirerTest < ActiveSupport::TestCase def setup - @string_inquirer = ActiveSupport::StringInquirer.new('production') + @string_inquirer = ActiveSupport::StringInquirer.new("production") end def test_match diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb index a88d8d9eba..9127da35d4 100644 --- a/activesupport/test/subscriber_test.rb +++ b/activesupport/test/subscriber_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/subscriber' +require "abstract_unit" +require "active_support/subscriber" class TestSubscriber < ActiveSupport::Subscriber attach_to :doodle @@ -16,9 +16,9 @@ class TestSubscriber < ActiveSupport::Subscriber private - def private_party(event) - events << event - end + def private_party(event) + events << event + end end # Monkey patch subscriber to test that only one subscriber per method is added. diff --git a/activesupport/test/tagged_logging_test.rb b/activesupport/test/tagged_logging_test.rb index 917fa46c96..2469e827d4 100644 --- a/activesupport/test/tagged_logging_test.rb +++ b/activesupport/test/tagged_logging_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/logger' -require 'active_support/tagged_logging' +require "abstract_unit" +require "active_support/logger" +require "active_support/tagged_logging" class TaggedLoggingTest < ActiveSupport::TestCase class MyLogger < ::ActiveSupport::Logger @@ -14,7 +14,7 @@ class TaggedLoggingTest < ActiveSupport::TestCase @logger = ActiveSupport::TaggedLogging.new(MyLogger.new(@output)) end - test 'sets logger.formatter if missing and extends it with a tagging API' do + test "sets logger.formatter if missing and extends it with a tagging API" do logger = Logger.new(StringIO.new) assert_nil logger.formatter ActiveSupport::TaggedLogging.new(logger) @@ -43,14 +43,14 @@ class TaggedLoggingTest < ActiveSupport::TestCase end test "push and pop tags directly" do - assert_equal %w(A B C), @logger.push_tags('A', ['B', ' ', ['C']]) - @logger.info 'a' + assert_equal %w(A B C), @logger.push_tags("A", ["B", " ", ["C"]]) + @logger.info "a" assert_equal %w(C), @logger.pop_tags - @logger.info 'b' + @logger.info "b" assert_equal %w(B), @logger.pop_tags(1) - @logger.info 'c' + @logger.info "c" assert_equal [], @logger.clear_tags! - @logger.info 'd' + @logger.info "d" assert_equal "[A] [B] [C] a\n[A] [B] b\n[A] c\nd\n", @output.string end diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb index 18228a2ac5..d769a8c145 100644 --- a/activesupport/test/test_case_test.rb +++ b/activesupport/test/test_case_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class AssertDifferenceTest < ActiveSupport::TestCase def setup @@ -20,21 +20,21 @@ class AssertDifferenceTest < ActiveSupport::TestCase assert_equal true, assert_not(false) e = assert_raises(Minitest::Assertion) { assert_not true } - assert_equal 'Expected true to be nil or false', e.message + assert_equal "Expected true to be nil or false", e.message - e = assert_raises(Minitest::Assertion) { assert_not true, 'custom' } - assert_equal 'custom', e.message + e = assert_raises(Minitest::Assertion) { assert_not true, "custom" } + assert_equal "custom", e.message end def test_assert_no_difference_pass - assert_no_difference '@object.num' do + assert_no_difference "@object.num" do # ... end end def test_assert_no_difference_fail error = assert_raises(Minitest::Assertion) do - assert_no_difference '@object.num' do + assert_no_difference "@object.num" do @object.increment end end @@ -43,7 +43,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_assert_no_difference_with_message_fail error = assert_raises(Minitest::Assertion) do - assert_no_difference '@object.num', 'Object Changed' do + assert_no_difference "@object.num", "Object Changed" do @object.increment end end @@ -51,13 +51,13 @@ class AssertDifferenceTest < ActiveSupport::TestCase end def test_assert_difference - assert_difference '@object.num', +1 do + assert_difference "@object.num", +1 do @object.increment end end def test_assert_difference_retval - incremented = assert_difference '@object.num', +1 do + incremented = assert_difference "@object.num", +1 do @object.increment end @@ -65,40 +65,40 @@ class AssertDifferenceTest < ActiveSupport::TestCase end def test_assert_difference_with_implicit_difference - assert_difference '@object.num' do + assert_difference "@object.num" do @object.increment end end def test_arbitrary_expression - assert_difference '@object.num + 1', +2 do + assert_difference "@object.num + 1", +2 do @object.increment @object.increment end end def test_negative_differences - assert_difference '@object.num', -1 do + assert_difference "@object.num", -1 do @object.decrement end end def test_expression_is_evaluated_in_the_appropriate_scope silence_warnings do - local_scope = local_scope = 'foo' - assert_difference('local_scope; @object.num') { @object.increment } + local_scope = local_scope = "foo" + assert_difference("local_scope; @object.num") { @object.increment } end end def test_array_of_expressions - assert_difference [ '@object.num', '@object.num + 1' ], +1 do + assert_difference [ "@object.num", "@object.num + 1" ], +1 do @object.increment end end def test_array_of_expressions_identify_failure assert_raises(Minitest::Assertion) do - assert_difference ['@object.num', '1 + 1'] do + assert_difference ["@object.num", "1 + 1"] do @object.increment end end @@ -106,11 +106,135 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_array_of_expressions_identify_failure_when_message_provided assert_raises(Minitest::Assertion) do - assert_difference ['@object.num', '1 + 1'], 1, 'something went wrong' do + assert_difference ["@object.num", "1 + 1"], 1, "something went wrong" do @object.increment end end end + + def test_assert_changes_pass + assert_changes "@object.num" do + @object.increment + end + end + + def test_assert_changes_pass_with_lambda + assert_changes -> { @object.num } do + @object.increment + end + end + + def test_assert_changes_with_from_option + assert_changes "@object.num", from: 0 do + @object.increment + end + end + + def test_assert_changes_with_from_option_with_wrong_value + assert_raises Minitest::Assertion do + assert_changes "@object.num", from: -1 do + @object.increment + end + end + end + + def test_assert_changes_with_from_option_with_nil + error = assert_raises Minitest::Assertion do + assert_changes "@object.num", from: nil do + @object.increment + end + end + assert_equal "\"@object.num\" isn't nil", error.message + end + + def test_assert_changes_with_to_option + assert_changes "@object.num", to: 1 do + @object.increment + end + end + + def test_assert_changes_with_wrong_to_option + assert_raises Minitest::Assertion do + assert_changes "@object.num", to: 2 do + @object.increment + end + end + end + + def test_assert_changes_with_from_option_and_to_option + assert_changes "@object.num", from: 0, to: 1 do + @object.increment + end + end + + def test_assert_changes_with_from_and_to_options_and_wrong_to_value + assert_raises Minitest::Assertion do + assert_changes "@object.num", from: 0, to: 2 do + @object.increment + end + end + end + + def test_assert_changes_works_with_any_object + retval = silence_warnings do + assert_changes :@new_object, from: nil, to: 42 do + @new_object = 42 + end + end + + assert_equal 42, retval + end + + def test_assert_changes_works_with_nil + oldval = @object + + retval = assert_changes :@object, from: oldval, to: nil do + @object = nil + end + + assert_nil retval + end + + def test_assert_changes_with_to_and_case_operator + token = nil + + assert_changes "token", to: /\w{32}/ do + token = SecureRandom.hex + end + end + + def test_assert_changes_with_to_and_from_and_case_operator + token = SecureRandom.hex + + assert_changes "token", from: /\w{32}/, to: /\w{32}/ do + token = SecureRandom.hex + end + end + + def test_assert_changes_with_message + error = assert_raises Minitest::Assertion do + assert_changes "@object.num", "@object.num should 1", to: 1 do + end + end + + assert_equal "@object.num should 1.\n\"@object.num\" didn't change to 1", error.message + end + + def test_assert_no_changes_pass + assert_no_changes "@object.num" do + # ... + end + end + + def test_assert_no_changes_with_message + error = assert_raises Minitest::Assertion do + assert_no_changes "@object.num", "@object.num should not change" do + @object.increment + end + end + + assert_equal "@object.num should not change.\n\"@object.num\" did change to 1.\nExpected: 0\n Actual: 1", error.message + end end class AlsoDoingNothingTest < ActiveSupport::TestCase @@ -170,7 +294,7 @@ end class TestCaseTaggedLoggingTest < ActiveSupport::TestCase def before_setup - require 'stringio' + require "stringio" @out = StringIO.new self.tagged_logger = ActiveSupport::TaggedLogging.new(Logger.new(@out)) super diff --git a/activesupport/test/testing/constant_lookup_test.rb b/activesupport/test/testing/constant_lookup_test.rb index 0f16419c8b..00e69fcdb5 100644 --- a/activesupport/test/testing/constant_lookup_test.rb +++ b/activesupport/test/testing/constant_lookup_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'dependencies_test_helpers' +require "abstract_unit" +require "dependencies_test_helpers" class Foo; end class Bar < Foo @@ -69,7 +69,7 @@ class ConstantLookupTest < ActiveSupport::TestCase def test_does_not_swallow_exception_on_no_name_error_within_constant assert_raises(NameError) do with_autoloading_fixtures do - self.class.determine_constant_from_test_name('RaisesNameError') + self.class.determine_constant_from_test_name("RaisesNameError") end end end diff --git a/activesupport/test/testing/file_fixtures_test.rb b/activesupport/test/testing/file_fixtures_test.rb index 91b8a9071c..e44fe58ce9 100644 --- a/activesupport/test/testing/file_fixtures_test.rb +++ b/activesupport/test/testing/file_fixtures_test.rb @@ -1,4 +1,6 @@ -require 'abstract_unit' +require "abstract_unit" + +require "pathname" class FileFixturesTest < ActiveSupport::TestCase self.file_fixture_path = File.expand_path("../../file_fixtures", __FILE__) @@ -6,7 +8,7 @@ class FileFixturesTest < ActiveSupport::TestCase test "#file_fixture returns Pathname to file fixture" do path = file_fixture("sample.txt") assert_kind_of Pathname, path - assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s + assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s end test "raises an exception when the fixture file does not exist" do @@ -23,6 +25,6 @@ class FileFixturesPathnameDirectoryTest < ActiveSupport::TestCase test "#file_fixture_path returns Pathname to file fixture" do path = file_fixture("sample.txt") assert_kind_of Pathname, path - assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s + assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s end end diff --git a/activesupport/test/testing/method_call_assertions_test.rb b/activesupport/test/testing/method_call_assertions_test.rb index 3e5ba7c079..7887933b15 100644 --- a/activesupport/test/testing/method_call_assertions_test.rb +++ b/activesupport/test/testing/method_call_assertions_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/testing/method_call_assertions' +require "abstract_unit" +require "active_support/testing/method_call_assertions" class MethodCallAssertionsTest < ActiveSupport::TestCase include ActiveSupport::Testing::MethodCallAssertions @@ -51,7 +51,7 @@ class MethodCallAssertionsTest < ActiveSupport::TestCase def test_assert_called_with_message error = assert_raises(Minitest::Assertion) do - assert_called(@object, :increment, 'dang it') do + assert_called(@object, :increment, "dang it") do # Call nothing... end end diff --git a/activesupport/test/time_travel_test.rb b/activesupport/test/time_travel_test.rb index 59c3e52c2f..c68be329bc 100644 --- a/activesupport/test/time_travel_test.rb +++ b/activesupport/test/time_travel_test.rb @@ -1,20 +1,20 @@ -require 'abstract_unit' -require 'active_support/core_ext/date_time' -require 'active_support/core_ext/numeric/time' +require "abstract_unit" +require "active_support/core_ext/date_time" +require "active_support/core_ext/numeric/time" class TimeTravelTest < ActiveSupport::TestCase - teardown do - travel_back - end - def test_time_helper_travel Time.stub(:now, Time.now) do - expected_time = Time.now + 1.day - travel 1.day + begin + expected_time = Time.now + 1.day + travel 1.day - assert_equal expected_time.to_s(:db), Time.now.to_s(:db) - assert_equal expected_time.to_date, Date.today - assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db) + assert_equal expected_time.to_s(:db), Time.now.to_s(:db) + assert_equal expected_time.to_date, Date.today + assert_equal expected_time.to_datetime.to_s(:db), DateTime.now.to_s(:db) + ensure + travel_back + end end end @@ -36,12 +36,16 @@ class TimeTravelTest < ActiveSupport::TestCase def test_time_helper_travel_to Time.stub(:now, Time.now) do - expected_time = Time.new(2004, 11, 24, 01, 04, 44) - travel_to expected_time + begin + expected_time = Time.new(2004, 11, 24, 01, 04, 44) + travel_to expected_time - assert_equal expected_time, Time.now - assert_equal Date.new(2004, 11, 24), Date.today - assert_equal expected_time.to_datetime, DateTime.now + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + assert_equal expected_time.to_datetime, DateTime.now + ensure + travel_back + end end end @@ -63,17 +67,68 @@ class TimeTravelTest < ActiveSupport::TestCase def test_time_helper_travel_back Time.stub(:now, Time.now) do - expected_time = Time.new(2004, 11, 24, 01, 04, 44) + begin + expected_time = Time.new(2004, 11, 24, 01, 04, 44) - travel_to expected_time - assert_equal expected_time, Time.now - assert_equal Date.new(2004, 11, 24), Date.today - assert_equal expected_time.to_datetime, DateTime.now - travel_back + travel_to expected_time + assert_equal expected_time, Time.now + assert_equal Date.new(2004, 11, 24), Date.today + assert_equal expected_time.to_datetime, DateTime.now + travel_back - assert_not_equal expected_time, Time.now - assert_not_equal Date.new(2004, 11, 24), Date.today - assert_not_equal expected_time.to_datetime, DateTime.now + assert_not_equal expected_time, Time.now + assert_not_equal Date.new(2004, 11, 24), Date.today + assert_not_equal expected_time.to_datetime, DateTime.now + ensure + travel_back + end + end + end + + def test_time_helper_travel_to_with_nested_calls_with_blocks + Time.stub(:now, Time.now) do + outer_expected_time = Time.new(2004, 11, 24, 01, 04, 44) + inner_expected_time = Time.new(2004, 10, 24, 01, 04, 44) + travel_to outer_expected_time do + assert_raises(RuntimeError, /Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing./) do + travel_to(inner_expected_time) do + #noop + end + end + end + end + end + + def test_time_helper_travel_to_with_nested_calls + Time.stub(:now, Time.now) do + outer_expected_time = Time.new(2004, 11, 24, 01, 04, 44) + inner_expected_time = Time.new(2004, 10, 24, 01, 04, 44) + travel_to outer_expected_time do + assert_nothing_raised do + travel_to(inner_expected_time) + + assert_equal inner_expected_time, Time.now + end + end + end + end + + def test_time_helper_travel_to_with_subsequent_calls + Time.stub(:now, Time.now) do + begin + initial_expected_time = Time.new(2004, 11, 24, 01, 04, 44) + subsequent_expected_time = Time.new(2004, 10, 24, 01, 04, 44) + assert_nothing_raised do + travel_to initial_expected_time + travel_to subsequent_expected_time + + assert_equal subsequent_expected_time, Time.now + + travel_back + end + ensure + travel_back + end end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index a15d5c6a0e..bd29584478 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -1,25 +1,25 @@ -require 'abstract_unit' -require 'active_support/time' -require 'time_zone_test_helpers' -require 'yaml' +require "abstract_unit" +require "active_support/time" +require "time_zone_test_helpers" +require "yaml" class TimeZoneTest < ActiveSupport::TestCase include TimeZoneTestHelpers def test_utc_to_local - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal Time.utc(1999, 12, 31, 19), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500 assert_equal Time.utc(2000, 6, 30, 20), zone.utc_to_local(Time.utc(2000, 7)) # dst offset -0400 end def test_local_to_utc - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal Time.utc(2000, 1, 1, 5), zone.local_to_utc(Time.utc(2000, 1)) # standard offset -0500 assert_equal Time.utc(2000, 7, 1, 4), zone.local_to_utc(Time.utc(2000, 7)) # dst offset -0400 end def test_period_for_local - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_instance_of TZInfo::TimezonePeriod, zone.period_for_local(Time.utc(2000)) end @@ -39,7 +39,7 @@ class TimeZoneTest < ActiveSupport::TestCase end ActiveSupport::TimeZone.all.each do |zone| - name = zone.name.downcase.gsub(/[^a-z]/, '_') + name = zone.name.downcase.gsub(/[^a-z]/, "_") define_method("test_from_#{name}_to_map") do assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[zone.name] end @@ -51,8 +51,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_now - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'].dup + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].dup def zone.time_now; Time.local(2000); end assert_instance_of ActiveSupport::TimeWithZone, zone.now assert_equal Time.utc(2000,1,1,5), zone.now.utc @@ -62,8 +62,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_now_enforces_spring_dst_rules - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'].dup + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].dup def zone.time_now Time.local(2006,4,2,2) # 2AM springs forward to 3AM end @@ -74,8 +74,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_now_enforces_fall_dst_rules - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'].dup + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"].dup def zone.time_now Time.at(1162098000) # equivalent to 1AM DST end @@ -85,52 +85,52 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_unknown_timezones_delegation_to_tzinfo - zone = ActiveSupport::TimeZone['America/Montevideo'] + zone = ActiveSupport::TimeZone["America/Montevideo"] assert_equal ActiveSupport::TimeZone, zone.class - assert_equal zone.object_id, ActiveSupport::TimeZone['America/Montevideo'].object_id + assert_equal zone.object_id, ActiveSupport::TimeZone["America/Montevideo"].object_id assert_equal Time.utc(2010, 1, 31, 22), zone.utc_to_local(Time.utc(2010, 2)) # daylight saving offset -0200 assert_equal Time.utc(2010, 3, 31, 21), zone.utc_to_local(Time.utc(2010, 4)) # standard offset -0300 end def test_today travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].today + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_back end def test_tomorrow travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST - assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 3), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].tomorrow + assert_equal Date.new(2000, 1, 3), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_back end def test_yesterday travel_to(Time.utc(2000, 1, 1, 4, 59, 59)) # 1 sec before midnight Jan 1 EST - assert_equal Date.new(1999, 12, 30), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(1999, 12, 30), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_to(Time.utc(2000, 1, 1, 5)) # midnight Jan 1 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_to(Time.utc(2000, 1, 2, 4, 59, 59)) # 1 sec before midnight Jan 2 EST - assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST - assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone['Eastern Time (US & Canada)'].yesterday + assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_back end def test_travel_to_a_date with_env_tz do - Time.use_zone('Hawaii') do + Time.use_zone("Hawaii") do date = Date.new(2014, 2, 18) time = date.midnight @@ -167,37 +167,37 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_local_enforces_spring_dst_rules - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.local(2006,4,2,1,59,59) # 1 second before DST start assert_equal Time.utc(2006,4,2,1,59,59), twz.time assert_equal Time.utc(2006,4,2,6,59,59), twz.utc assert_equal false, twz.dst? - assert_equal 'EST', twz.zone + assert_equal "EST", twz.zone twz2 = zone.local(2006,4,2,2) # 2AM does not exist because at 2AM, time springs forward to 3AM assert_equal Time.utc(2006,4,2,3), twz2.time # twz is created for 3AM assert_equal Time.utc(2006,4,2,7), twz2.utc assert_equal true, twz2.dst? - assert_equal 'EDT', twz2.zone + assert_equal "EDT", twz2.zone twz3 = zone.local(2006,4,2,2,30) # 2:30AM does not exist because at 2AM, time springs forward to 3AM assert_equal Time.utc(2006,4,2,3,30), twz3.time # twz is created for 3:30AM assert_equal Time.utc(2006,4,2,7,30), twz3.utc assert_equal true, twz3.dst? - assert_equal 'EDT', twz3.zone + assert_equal "EDT", twz3.zone end def test_local_enforces_fall_dst_rules # 1AM during fall DST transition is ambiguous, it could be either DST or non-DST 1AM # Mirroring Time.local behavior, this method selects the DST time - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.local(2006,10,29,1) assert_equal Time.utc(2006,10,29,1), twz.time assert_equal Time.utc(2006,10,29,5), twz.utc assert_equal true, twz.dst? - assert_equal 'EDT', twz.zone + assert_equal "EDT", twz.zone end def test_at - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] secs = 946684800.0 twz = zone.at(secs) assert_equal Time.utc(1999,12,31,19), twz.time @@ -207,7 +207,7 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_at_with_old_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] secs = DateTime.civil(1850).to_f twz = zone.at(secs) assert_equal [1850, 1, 1, 0], [twz.utc.year, twz.utc.mon, twz.utc.day, twz.utc.hour] @@ -216,8 +216,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_parse - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('1999-12-31 19:00:00') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("1999-12-31 19:00:00") assert_equal Time.utc(1999,12,31,19), twz.time assert_equal Time.utc(2000), twz.utc assert_equal zone, twz.time_zone @@ -226,97 +226,97 @@ class TimeZoneTest < ActiveSupport::TestCase def test_parse_string_with_timezone (-11..13).each do |timezone_offset| zone = ActiveSupport::TimeZone[timezone_offset] - twz = zone.parse('1999-12-31 19:00:00') + twz = zone.parse("1999-12-31 19:00:00") assert_equal twz, zone.parse(twz.to_s) end end def test_parse_with_old_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('1883-12-31 19:00:00') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("1883-12-31 19:00:00") assert_equal [0,0,19,31,12,1883], twz.to_a[0,6] assert_equal zone, twz.time_zone end def test_parse_far_future_date_with_time_zone_offset_in_string - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('2050-12-31 19:00:00 -10:00') # i.e., 2050-01-01 05:00:00 UTC + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("2050-12-31 19:00:00 -10:00") # i.e., 2050-01-01 05:00:00 UTC assert_equal [0,0,0,1,1,2051], twz.to_a[0,6] assert_equal zone, twz.time_zone end def test_parse_returns_nil_when_string_without_date_information_is_passed_in - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - assert_nil zone.parse('foobar') - assert_nil zone.parse(' ') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_nil zone.parse("foobar") + assert_nil zone.parse(" ") end def test_parse_with_incomplete_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] zone.stub(:now, zone.local(1999,12,31)) do - twz = zone.parse('19:00:00') + twz = zone.parse("19:00:00") assert_equal Time.utc(1999,12,31,19), twz.time end end def test_parse_with_day_omitted - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - assert_equal Time.local(2000, 2, 1), zone.parse('Feb', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 1), zone.parse('Feb 2005', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 2), zone.parse('2 Feb 2005', Time.local(2000, 1, 1)) + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_equal Time.local(2000, 2, 1), zone.parse("Feb", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 1), zone.parse("Feb 2005", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 2), zone.parse("2 Feb 2005", Time.local(2000, 1, 1)) end end def test_parse_should_not_black_out_system_timezone_dst_jump - with_env_tz('EET') do - zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)'] - twz = zone.parse('2012-03-25 03:29:00') + with_env_tz("EET") do + zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"] + twz = zone.parse("2012-03-25 03:29:00") assert_equal [0, 29, 3, 25, 3, 2012], twz.to_a[0,6] end end def test_parse_should_black_out_app_timezone_dst_jump - with_env_tz('EET') do - zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)'] - twz = zone.parse('2012-03-11 02:29:00') + with_env_tz("EET") do + zone = ActiveSupport::TimeZone["Pacific Time (US & Canada)"] + twz = zone.parse("2012-03-11 02:29:00") assert_equal [0, 29, 3, 11, 3, 2012], twz.to_a[0,6] end end def test_parse_with_missing_time_components - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] zone.stub(:now, zone.local(1999, 12, 31, 12, 59, 59)) do - twz = zone.parse('2012-12-01') + twz = zone.parse("2012-12-01") assert_equal Time.utc(2012, 12, 1), twz.time end end def test_parse_with_javascript_date - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.parse("Mon May 28 2012 00:00:00 GMT-0700 (PDT)") assert_equal Time.utc(2012, 5, 28, 7, 0, 0), twz.utc end def test_parse_doesnt_use_local_dst - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['UTC'] - twz = zone.parse('2013-03-10 02:00:00') + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["UTC"] + twz = zone.parse("2013-03-10 02:00:00") assert_equal Time.utc(2013, 3, 10, 2, 0, 0), twz.time end end def test_parse_handles_dst_jump - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.parse('2013-03-10 02:00:00') + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.parse("2013-03-10 02:00:00") assert_equal Time.utc(2013, 3, 10, 3, 0, 0), twz.time end end def test_strptime - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00', '%Y-%m-%d %H:%M:%S') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00", "%Y-%m-%d %H:%M:%S") assert_equal Time.utc(1999,12,31,17), twz assert_equal Time.utc(1999,12,31,12), twz.time assert_equal Time.utc(1999,12,31,17), twz.utc @@ -324,9 +324,9 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_nondefault_time_zone - with_tz_default ActiveSupport::TimeZone['Pacific Time (US & Canada)'] do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00', '%Y-%m-%d %H:%M:%S') + with_tz_default ActiveSupport::TimeZone["Pacific Time (US & Canada)"] do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00", "%Y-%m-%d %H:%M:%S") assert_equal Time.utc(1999,12,31,17), twz assert_equal Time.utc(1999,12,31,12), twz.time assert_equal Time.utc(1999,12,31,17), twz.utc @@ -335,8 +335,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_abbrev - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 PST', '%Y-%m-%d %H:%M:%S %Z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 PST", "%Y-%m-%d %H:%M:%S %Z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -344,8 +344,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_h_offset - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 -08', '%Y-%m-%d %H:%M:%S %:::z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 -08", "%Y-%m-%d %H:%M:%S %:::z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -353,8 +353,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_hm_offset - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 -08:00', '%Y-%m-%d %H:%M:%S %:z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 -08:00", "%Y-%m-%d %H:%M:%S %:z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -362,8 +362,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_explicit_time_zone_as_hms_offset - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 -08:00:00', '%Y-%m-%d %H:%M:%S %::z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 -08:00:00", "%Y-%m-%d %H:%M:%S %::z") assert_equal Time.utc(1999,12,31,20), twz assert_equal Time.utc(1999,12,31,15), twz.time assert_equal Time.utc(1999,12,31,20), twz.utc @@ -371,8 +371,8 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_almost_explicit_time_zone - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = zone.strptime('1999-12-31 12:00:00 %Z', '%Y-%m-%d %H:%M:%S %%Z') + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + twz = zone.strptime("1999-12-31 12:00:00 %Z", "%Y-%m-%d %H:%M:%S %%Z") assert_equal Time.utc(1999,12,31,17), twz assert_equal Time.utc(1999,12,31,12), twz.time assert_equal Time.utc(1999,12,31,17), twz.utc @@ -380,29 +380,54 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_strptime_with_day_omitted - with_env_tz 'US/Eastern' do - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - assert_equal Time.local(2000, 2, 1), zone.strptime('Feb', '%b', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 1), zone.strptime('Feb 2005', '%b %Y', Time.local(2000, 1, 1)) - assert_equal Time.local(2005, 2, 2), zone.strptime('2 Feb 2005', '%e %b %Y', Time.local(2000, 1, 1)) + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_equal Time.local(2000, 2, 1), zone.strptime("Feb", "%b", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 1), zone.strptime("Feb 2005", "%b %Y", Time.local(2000, 1, 1)) + assert_equal Time.local(2005, 2, 2), zone.strptime("2 Feb 2005", "%e %b %Y", Time.local(2000, 1, 1)) + end + end + + def test_strptime_with_malformed_string + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + assert_raise(ArgumentError) { zone.strptime("1999-12-31", "%Y/%m/%d") } + end + end + + def test_strptime_with_timestamp_seconds + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + time_str = "1470272280" + time = zone.strptime(time_str, "%s") + assert_equal Time.at(1470272280), time + end + end + + def test_strptime_with_timestamp_milliseconds + with_env_tz "US/Eastern" do + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] + time_str = "1470272280000" + time = zone.strptime(time_str, "%Q") + assert_equal Time.at(1470272280), time end end def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize - tzinfo = TZInfo::Timezone.get('America/New_York') + tzinfo = TZInfo::Timezone.get("America/New_York") zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo) - assert_equal nil, zone.instance_variable_get('@utc_offset') + assert_equal nil, zone.instance_variable_get("@utc_offset") assert_equal(-18_000, zone.utc_offset) end def test_utc_offset_is_not_cached_when_current_period_gets_stale - tz = ActiveSupport::TimeZone.create('Moscow') + tz = ActiveSupport::TimeZone.create("Moscow") travel_to(Time.utc(2014, 10, 25, 21)) do # 1 hour before TZ change - assert_equal 14400, tz.utc_offset, 'utc_offset should be initialized according to current_period' + assert_equal 14400, tz.utc_offset, "utc_offset should be initialized according to current_period" end travel_to(Time.utc(2014, 10, 25, 22)) do # after TZ change - assert_equal 10800, tz.utc_offset, 'utc_offset should not be cached when current_period gets stale' + assert_equal 10800, tz.utc_offset, "utc_offset should not be cached when current_period gets stale" end end @@ -425,48 +450,48 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_formatted_offset_positive - zone = ActiveSupport::TimeZone['New Delhi'] + zone = ActiveSupport::TimeZone["New Delhi"] assert_equal "+05:30", zone.formatted_offset assert_equal "+0530", zone.formatted_offset(false) end def test_formatted_offset_negative - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert_equal "-05:00", zone.formatted_offset assert_equal "-0500", zone.formatted_offset(false) end def test_z_format_strings - zone = ActiveSupport::TimeZone['Tokyo'] + zone = ActiveSupport::TimeZone["Tokyo"] twz = zone.now - assert_equal '+0900', twz.strftime('%z') - assert_equal '+09:00', twz.strftime('%:z') - assert_equal '+09:00:00', twz.strftime('%::z') + assert_equal "+0900", twz.strftime("%z") + assert_equal "+09:00", twz.strftime("%:z") + assert_equal "+09:00:00", twz.strftime("%::z") end def test_formatted_offset_zero - zone = ActiveSupport::TimeZone['London'] + zone = ActiveSupport::TimeZone["London"] assert_equal "+00:00", zone.formatted_offset - assert_equal "UTC", zone.formatted_offset(true, 'UTC') + assert_equal "UTC", zone.formatted_offset(true, "UTC") end def test_zone_compare - zone1 = ActiveSupport::TimeZone['Central Time (US & Canada)'] # offset -0600 - zone2 = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] # offset -0500 + zone1 = ActiveSupport::TimeZone["Central Time (US & Canada)"] # offset -0600 + zone2 = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] # offset -0500 assert zone1 < zone2 assert zone2 > zone1 assert zone1 == zone1 end def test_zone_match - zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] assert zone =~ /Eastern/ assert zone =~ /New_York/ assert zone !~ /Nonexistent_Place/ end def test_to_s - assert_equal "(GMT+05:30) New Delhi", ActiveSupport::TimeZone['New Delhi'].to_s + assert_equal "(GMT+05:30) New Delhi", ActiveSupport::TimeZone["New Delhi"].to_s end def test_all_sorted @@ -498,13 +523,13 @@ class TimeZoneTest < ActiveSupport::TestCase end def test_us_zones - assert ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Hawaii"]) - assert !ActiveSupport::TimeZone.us_zones.include?(ActiveSupport::TimeZone["Kuala Lumpur"]) + assert_includes ActiveSupport::TimeZone.us_zones, ActiveSupport::TimeZone["Hawaii"] + assert_not_includes ActiveSupport::TimeZone.us_zones, ActiveSupport::TimeZone["Kuala Lumpur"] end def test_country_zones - assert ActiveSupport::TimeZone.country_zones("ru").include?(ActiveSupport::TimeZone["Moscow"]) - assert !ActiveSupport::TimeZone.country_zones(:ru).include?(ActiveSupport::TimeZone["Kuala Lumpur"]) + assert_includes ActiveSupport::TimeZone.country_zones("ru"), ActiveSupport::TimeZone["Moscow"] + assert_not_includes ActiveSupport::TimeZone.country_zones(:ru), ActiveSupport::TimeZone["Kuala Lumpur"] end def test_to_yaml diff --git a/activesupport/test/time_zone_test_helpers.rb b/activesupport/test/time_zone_test_helpers.rb index eb6f7d0f85..e1d615d154 100644 --- a/activesupport/test/time_zone_test_helpers.rb +++ b/activesupport/test/time_zone_test_helpers.rb @@ -7,11 +7,11 @@ module TimeZoneTestHelpers Time.zone = old_tz end - def with_env_tz(new_tz = 'US/Eastern') - old_tz, ENV['TZ'] = ENV['TZ'], new_tz + def with_env_tz(new_tz = "US/Eastern") + old_tz, ENV["TZ"] = ENV["TZ"], new_tz yield ensure - old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + old_tz ? ENV["TZ"] = old_tz : ENV.delete("TZ") end def with_preserve_timezone(value) diff --git a/activesupport/test/transliterate_test.rb b/activesupport/test/transliterate_test.rb index 378421fedd..040ddd25fc 100644 --- a/activesupport/test/transliterate_test.rb +++ b/activesupport/test/transliterate_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/inflector/transliterate' +require "abstract_unit" +require "active_support/inflector/transliterate" class TransliterateTest < ActiveSupport::TestCase def test_transliterate_should_not_change_ascii_chars @@ -13,7 +13,7 @@ class TransliterateTest < ActiveSupport::TestCase # create string with range of Unicode's western characters with # diacritics, excluding the division and multiplication signs which for # some reason or other are floating in the middle of all the letters. - string = (0xC0..0x17E).to_a.reject {|c| [0xD7, 0xF7].include?(c)}.pack("U*") + string = (0xC0..0x17E).to_a.reject { |c| [0xD7, 0xF7].include?(c) }.pack("U*") string.each_char do |char| assert_match %r{^[a-zA-Z']*$}, ActiveSupport::Inflector.transliterate(char) end @@ -21,7 +21,7 @@ class TransliterateTest < ActiveSupport::TestCase def test_transliterate_should_work_with_custom_i18n_rules_and_uncomposed_utf8 char = [117, 776].pack("U*") # "ü" as ASCII "u" plus COMBINING DIAERESIS - I18n.backend.store_translations(:de, :i18n => {:transliterate => {:rule => {"ü" => "ue"}}}) + I18n.backend.store_translations(:de, i18n: { transliterate: { rule: { "ü" => "ue" } } }) default_locale, I18n.locale = I18n.locale, :de assert_equal "ue", ActiveSupport::Inflector.transliterate(char) ensure diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb index ed4de8aba2..816d57972c 100644 --- a/activesupport/test/xml_mini/jdom_engine_test.rb +++ b/activesupport/test/xml_mini/jdom_engine_test.rb @@ -1,17 +1,16 @@ -if RUBY_PLATFORM =~ /java/ - require 'abstract_unit' - require 'active_support/xml_mini' - require 'active_support/core_ext/hash/conversions' - +if RUBY_PLATFORM.include?("java") + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" class JDOMEngineTest < ActiveSupport::TestCase include ActiveSupport - FILES_DIR = File.dirname(__FILE__) + '/../fixtures/xml' + FILES_DIR = File.dirname(__FILE__) + "/../fixtures/xml" def setup @default_backend = XmlMini.backend - XmlMini.backend = 'JDOM' + XmlMini.backend = "JDOM" end def teardown @@ -19,18 +18,18 @@ if RUBY_PLATFORM =~ /java/ end def test_file_from_xml - hash = Hash.from_xml(<<-eoxml) + hash = Hash.from_xml(<<-eoxml) <blog> <logo type="file" name="logo.png" content_type="image/png"> </logo> </blog> eoxml - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type end def test_not_allowed_to_expand_entities_to_files @@ -40,7 +39,7 @@ if RUBY_PLATFORM =~ /java/ ]> <member>x&a;</member> EOT - assert_equal 'x', Hash.from_xml(attack_xml)["member"] + assert_equal "x", Hash.from_xml(attack_xml)["member"] end def test_not_allowed_to_expand_parameter_entities_to_files @@ -52,17 +51,16 @@ if RUBY_PLATFORM =~ /java/ <member>x&a;</member> EOT assert_raise Java::OrgXmlSax::SAXParseException do - assert_equal 'x', Hash.from_xml(attack_xml)["member"] + assert_equal "x", Hash.from_xml(attack_xml)["member"] end end - def test_not_allowed_to_load_external_doctypes attack_xml = <<-EOT <!DOCTYPE member SYSTEM "file://#{FILES_DIR}/jdom_doctype.dtd"> <member>x&a;</member> EOT - assert_equal 'x', Hash.from_xml(attack_xml)["member"] + assert_equal "x", Hash.from_xml(attack_xml)["member"] end def test_exception_thrown_on_expansion_attack @@ -86,13 +84,13 @@ if RUBY_PLATFORM =~ /java/ end def test_setting_JDOM_as_backend - XmlMini.backend = 'JDOM' + XmlMini.backend = "JDOM" assert_equal XmlMini_JDOM, XmlMini.backend end def test_blank_returns_empty_hash assert_equal({}, XmlMini.parse(nil)) - assert_equal({}, XmlMini.parse('')) + assert_equal({}, XmlMini.parse("")) end def test_array_type_makes_an_array @@ -178,11 +176,8 @@ if RUBY_PLATFORM =~ /java/ private def assert_equal_rexml(xml) parsed_xml = XmlMini.parse(xml) - hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } + hash = XmlMini.with_backend("REXML") { XmlMini.parse(xml) } assert_equal(hash, parsed_xml) end end - -else - # don't run these test because we aren't running in JRuby end diff --git a/activesupport/test/xml_mini/libxml_engine_test.rb b/activesupport/test/xml_mini/libxml_engine_test.rb index a8df2e1f7b..81b0d3c407 100644 --- a/activesupport/test/xml_mini/libxml_engine_test.rb +++ b/activesupport/test/xml_mini/libxml_engine_test.rb @@ -1,58 +1,58 @@ begin - require 'libxml' + require "libxml" rescue LoadError # Skip libxml tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" -class LibxmlEngineTest < ActiveSupport::TestCase - include ActiveSupport + class LibxmlEngineTest < ActiveSupport::TestCase + include ActiveSupport - def setup - @default_backend = XmlMini.backend - XmlMini.backend = 'LibXML' + def setup + @default_backend = XmlMini.backend + XmlMini.backend = "LibXML" - LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do - end + LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do + end - def teardown - XmlMini.backend = @default_backend - end + def teardown + XmlMini.backend = @default_backend + end - def test_exception_thrown_on_expansion_attack - assert_raise LibXML::XML::Error do - attack_xml = %{<?xml version="1.0" encoding="UTF-8"?> - <!DOCTYPE member [ - <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> - <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;"> - <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;"> - <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;"> - <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;"> - <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;"> - <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"> - ]> - <member> - &a; - </member> - } - Hash.from_xml(attack_xml) + def test_exception_thrown_on_expansion_attack + assert_raise LibXML::XML::Error do + attack_xml = %{<?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE member [ + <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> + <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;"> + <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;"> + <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;"> + <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;"> + <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;"> + <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"> + ]> + <member> + &a; + </member> + } + Hash.from_xml(attack_xml) + end end - end - def test_setting_libxml_as_backend - XmlMini.backend = 'LibXML' - assert_equal XmlMini_LibXML, XmlMini.backend - end + def test_setting_libxml_as_backend + XmlMini.backend = "LibXML" + assert_equal XmlMini_LibXML, XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, XmlMini.parse(nil)) - assert_equal({}, XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -60,67 +60,67 @@ class LibxmlEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -129,10 +129,10 @@ class LibxmlEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -141,31 +141,31 @@ class LibxmlEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -173,32 +173,31 @@ class LibxmlEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end + end - def test_children_with_blank_text_and_attribute - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text_and_attribute + assert_equal_rexml(<<-eoxml) <root> <products type="file"> </products> </root> eoxml - end - - - private - def assert_equal_rexml(xml) - parsed_xml = XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend("REXML") { XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/libxmlsax_engine_test.rb b/activesupport/test/xml_mini/libxmlsax_engine_test.rb index d6d90639e2..e25fa2813c 100644 --- a/activesupport/test/xml_mini/libxmlsax_engine_test.rb +++ b/activesupport/test/xml_mini/libxmlsax_engine_test.rb @@ -1,27 +1,27 @@ begin - require 'libxml' + require "libxml" rescue LoadError # Skip libxml tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" -class LibXMLSAXEngineTest < ActiveSupport::TestCase - include ActiveSupport + class LibXMLSAXEngineTest < ActiveSupport::TestCase + include ActiveSupport - def setup - @default_backend = XmlMini.backend - XmlMini.backend = 'LibXMLSAX' - end + def setup + @default_backend = XmlMini.backend + XmlMini.backend = "LibXMLSAX" + end - def teardown - XmlMini.backend = @default_backend - end + def teardown + XmlMini.backend = @default_backend + end - def test_exception_thrown_on_expansion_attack - assert_raise LibXML::XML::Error do - attack_xml = <<-EOT + def test_exception_thrown_on_expansion_attack + assert_raise LibXML::XML::Error do + attack_xml = <<-EOT <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE member [ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> @@ -37,22 +37,22 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase </member> EOT - Hash.from_xml(attack_xml) + Hash.from_xml(attack_xml) + end end - end - def test_setting_libxml_as_backend - XmlMini.backend = 'LibXMLSAX' - assert_equal XmlMini_LibXMLSAX, XmlMini.backend - end + def test_setting_libxml_as_backend + XmlMini.backend = "LibXMLSAX" + assert_equal XmlMini_LibXMLSAX, XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, XmlMini.parse(nil)) - assert_equal({}, XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -60,67 +60,67 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -129,10 +129,10 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -141,31 +141,31 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -173,23 +173,23 @@ class LibXMLSAXEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end - - private - def assert_equal_rexml(xml) - parsed_xml = XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = XmlMini.with_backend("REXML") { XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/nokogiri_engine_test.rb b/activesupport/test/xml_mini/nokogiri_engine_test.rb index 1314c9065a..44b82da4e4 100644 --- a/activesupport/test/xml_mini/nokogiri_engine_test.rb +++ b/activesupport/test/xml_mini/nokogiri_engine_test.rb @@ -1,40 +1,40 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError # Skip nokogiri tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' - -class NokogiriEngineTest < ActiveSupport::TestCase - def setup - @default_backend = ActiveSupport::XmlMini.backend - ActiveSupport::XmlMini.backend = 'Nokogiri' - end + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" + + class NokogiriEngineTest < ActiveSupport::TestCase + def setup + @default_backend = ActiveSupport::XmlMini.backend + ActiveSupport::XmlMini.backend = "Nokogiri" + end - def teardown - ActiveSupport::XmlMini.backend = @default_backend - end + def teardown + ActiveSupport::XmlMini.backend = @default_backend + end - def test_file_from_xml - hash = Hash.from_xml(<<-eoxml) + def test_file_from_xml + hash = Hash.from_xml(<<-eoxml) <blog> <logo type="file" name="logo.png" content_type="image/png"> </logo> </blog> eoxml - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type - end + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type + end - def test_exception_thrown_on_expansion_attack - assert_raise Nokogiri::XML::SyntaxError do - attack_xml = <<-EOT + def test_exception_thrown_on_expansion_attack + assert_raise Nokogiri::XML::SyntaxError do + attack_xml = <<-EOT <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE member [ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> @@ -49,22 +49,22 @@ class NokogiriEngineTest < ActiveSupport::TestCase &a; </member> EOT - Hash.from_xml(attack_xml) + Hash.from_xml(attack_xml) + end end - end - def test_setting_nokogiri_as_backend - ActiveSupport::XmlMini.backend = 'Nokogiri' - assert_equal ActiveSupport::XmlMini_Nokogiri, ActiveSupport::XmlMini.backend - end + def test_setting_nokogiri_as_backend + ActiveSupport::XmlMini.backend = "Nokogiri" + assert_equal ActiveSupport::XmlMini_Nokogiri, ActiveSupport::XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, ActiveSupport::XmlMini.parse(nil)) - assert_equal({}, ActiveSupport::XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, ActiveSupport::XmlMini.parse(nil)) + assert_equal({}, ActiveSupport::XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -72,67 +72,67 @@ class NokogiriEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -141,10 +141,10 @@ class NokogiriEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -153,31 +153,31 @@ class NokogiriEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -185,31 +185,31 @@ class NokogiriEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end + end - def test_children_with_blank_text_and_attribute - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text_and_attribute + assert_equal_rexml(<<-eoxml) <root> <products type="file"> </products> </root> eoxml - end - - private - def assert_equal_rexml(xml) - parsed_xml = ActiveSupport::XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = ActiveSupport::XmlMini.with_backend('REXML') { ActiveSupport::XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = ActiveSupport::XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = ActiveSupport::XmlMini.with_backend("REXML") { ActiveSupport::XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/nokogirisax_engine_test.rb b/activesupport/test/xml_mini/nokogirisax_engine_test.rb index 7978a50921..24b35cadf6 100644 --- a/activesupport/test/xml_mini/nokogirisax_engine_test.rb +++ b/activesupport/test/xml_mini/nokogirisax_engine_test.rb @@ -1,40 +1,40 @@ begin - require 'nokogiri' + require "nokogiri" rescue LoadError # Skip nokogiri tests else -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/core_ext/hash/conversions' - -class NokogiriSAXEngineTest < ActiveSupport::TestCase - def setup - @default_backend = ActiveSupport::XmlMini.backend - ActiveSupport::XmlMini.backend = 'NokogiriSAX' - end + require "abstract_unit" + require "active_support/xml_mini" + require "active_support/core_ext/hash/conversions" + + class NokogiriSAXEngineTest < ActiveSupport::TestCase + def setup + @default_backend = ActiveSupport::XmlMini.backend + ActiveSupport::XmlMini.backend = "NokogiriSAX" + end - def teardown - ActiveSupport::XmlMini.backend = @default_backend - end + def teardown + ActiveSupport::XmlMini.backend = @default_backend + end - def test_file_from_xml - hash = Hash.from_xml(<<-eoxml) + def test_file_from_xml + hash = Hash.from_xml(<<-eoxml) <blog> <logo type="file" name="logo.png" content_type="image/png"> </logo> </blog> eoxml - assert hash.has_key?('blog') - assert hash['blog'].has_key?('logo') + assert hash.has_key?("blog") + assert hash["blog"].has_key?("logo") - file = hash['blog']['logo'] - assert_equal 'logo.png', file.original_filename - assert_equal 'image/png', file.content_type - end + file = hash["blog"]["logo"] + assert_equal "logo.png", file.original_filename + assert_equal "image/png", file.content_type + end - def test_exception_thrown_on_expansion_attack - assert_raise RuntimeError do - attack_xml = <<-EOT + def test_exception_thrown_on_expansion_attack + assert_raise RuntimeError do + attack_xml = <<-EOT <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE member [ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> @@ -50,22 +50,22 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase </member> EOT - Hash.from_xml(attack_xml) + Hash.from_xml(attack_xml) + end end - end - def test_setting_nokogirisax_as_backend - ActiveSupport::XmlMini.backend = 'NokogiriSAX' - assert_equal ActiveSupport::XmlMini_NokogiriSAX, ActiveSupport::XmlMini.backend - end + def test_setting_nokogirisax_as_backend + ActiveSupport::XmlMini.backend = "NokogiriSAX" + assert_equal ActiveSupport::XmlMini_NokogiriSAX, ActiveSupport::XmlMini.backend + end - def test_blank_returns_empty_hash - assert_equal({}, ActiveSupport::XmlMini.parse(nil)) - assert_equal({}, ActiveSupport::XmlMini.parse('')) - end + def test_blank_returns_empty_hash + assert_equal({}, ActiveSupport::XmlMini.parse(nil)) + assert_equal({}, ActiveSupport::XmlMini.parse("")) + end - def test_array_type_makes_an_array - assert_equal_rexml(<<-eoxml) + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) <blog> <posts type="array"> <post>a post</post> @@ -73,67 +73,67 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase </posts> </blog> eoxml - end + end - def test_one_node_document_as_hash - assert_equal_rexml(<<-eoxml) - <products/> - eoxml - end + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end - def test_one_node_with_attributes_document_as_hash - assert_equal_rexml(<<-eoxml) - <products foo="bar"/> - eoxml - end + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end - def test_products_node_with_book_node_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> </products> eoxml - end + end - def test_products_node_with_two_book_nodes_as_hash - assert_equal_rexml(<<-eoxml) + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) <products> <book name="awesome" id="12345" /> <book name="america" id="67890" /> </products> eoxml - end + end - def test_single_node_with_content_as_hash - assert_equal_rexml(<<-eoxml) + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) <products> hello world </products> eoxml - end + end - def test_children_with_children - assert_equal_rexml(<<-eoxml) + def test_children_with_children + assert_equal_rexml(<<-eoxml) <root> <products> <book name="america" id="67890" /> </products> </root> eoxml - end + end - def test_children_with_text - assert_equal_rexml(<<-eoxml) + def test_children_with_text + assert_equal_rexml(<<-eoxml) <root> <products> hello everyone </products> </root> eoxml - end + end - def test_children_with_non_adjacent_text - assert_equal_rexml(<<-eoxml) + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) <root> good <products> @@ -142,10 +142,10 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - end + end - def test_parse_from_io - io = StringIO.new(<<-eoxml) + def test_parse_from_io + io = StringIO.new(<<-eoxml) <root> good <products> @@ -154,31 +154,31 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase morning </root> eoxml - assert_equal_rexml(io) - end + assert_equal_rexml(io) + end - def test_children_with_simple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock]]> </products> </root> eoxml - end + end - def test_children_with_multiple_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) <root> <products> <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> </products> </root> eoxml - end + end - def test_children_with_text_and_cdata - assert_equal_rexml(<<-eoxml) + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) <root> <products> hello <![CDATA[cdatablock]]> @@ -186,31 +186,31 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase </products> </root> eoxml - end + end - def test_children_with_blank_text - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) <root> <products> </products> </root> eoxml - end + end - def test_children_with_blank_text_and_attribute - assert_equal_rexml(<<-eoxml) + def test_children_with_blank_text_and_attribute + assert_equal_rexml(<<-eoxml) <root> <products type="file"> </products> </root> eoxml - end - - private - def assert_equal_rexml(xml) - parsed_xml = ActiveSupport::XmlMini.parse(xml) - xml.rewind if xml.respond_to?(:rewind) - hash = ActiveSupport::XmlMini.with_backend('REXML') { ActiveSupport::XmlMini.parse(xml) } - assert_equal(hash, parsed_xml) end -end + + private + def assert_equal_rexml(xml) + parsed_xml = ActiveSupport::XmlMini.parse(xml) + xml.rewind if xml.respond_to?(:rewind) + hash = ActiveSupport::XmlMini.with_backend("REXML") { ActiveSupport::XmlMini.parse(xml) } + assert_equal(hash, parsed_xml) + end + end end diff --git a/activesupport/test/xml_mini/rexml_engine_test.rb b/activesupport/test/xml_mini/rexml_engine_test.rb index 6e9ce7ac11..dc62f3f671 100644 --- a/activesupport/test/xml_mini/rexml_engine_test.rb +++ b/activesupport/test/xml_mini/rexml_engine_test.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'active_support/xml_mini' +require "abstract_unit" +require "active_support/xml_mini" class REXMLEngineTest < ActiveSupport::TestCase def test_default_is_rexml @@ -7,12 +7,12 @@ class REXMLEngineTest < ActiveSupport::TestCase end def test_set_rexml_as_backend - ActiveSupport::XmlMini.backend = 'REXML' + ActiveSupport::XmlMini.backend = "REXML" assert_equal ActiveSupport::XmlMini_REXML, ActiveSupport::XmlMini.backend end def test_parse_from_io - ActiveSupport::XmlMini.backend = 'REXML' + ActiveSupport::XmlMini.backend = "REXML" io = StringIO.new(<<-eoxml) <root> good @@ -23,23 +23,22 @@ class REXMLEngineTest < ActiveSupport::TestCase </root> eoxml hash = ActiveSupport::XmlMini.parse(io) - assert hash.has_key?('root') - assert hash['root'].has_key?('products') - assert_match "good", hash['root']['__content__'] - products = hash['root']['products'] - assert products.has_key?("__content__") - assert_match 'hello everyone', products['__content__'] + assert hash.has_key?("root") + assert hash["root"].has_key?("products") + assert_match "good", hash["root"]["__content__"] + products = hash["root"]["products"] + assert products.has_key?("__content__") + assert_match "hello everyone", products["__content__"] end def test_parse_from_empty_string - ActiveSupport::XmlMini.backend = 'REXML' + ActiveSupport::XmlMini.backend = "REXML" assert_equal({}, ActiveSupport::XmlMini.parse("")) end def test_parse_from_frozen_string - ActiveSupport::XmlMini.backend = 'REXML' + ActiveSupport::XmlMini.backend = "REXML" xml_string = "<root></root>".freeze - assert_equal({"root" => {}}, ActiveSupport::XmlMini.parse(xml_string)) + assert_equal({ "root" => {} }, ActiveSupport::XmlMini.parse(xml_string)) end - end diff --git a/activesupport/test/xml_mini_test.rb b/activesupport/test/xml_mini_test.rb index 55e8181b54..b15ccfb764 100644 --- a/activesupport/test/xml_mini_test.rb +++ b/activesupport/test/xml_mini_test.rb @@ -1,9 +1,9 @@ -require 'abstract_unit' -require 'active_support/xml_mini' -require 'active_support/builder' -require 'active_support/core_ext/hash' -require 'active_support/core_ext/big_decimal' -require 'yaml' +require "abstract_unit" +require "active_support/xml_mini" +require "active_support/builder" +require "active_support/core_ext/hash" +require "active_support/core_ext/big_decimal" +require "yaml" module XmlMiniTest class RenameKeyTest < ActiveSupport::TestCase @@ -12,23 +12,23 @@ module XmlMiniTest end def test_rename_key_dasherizes_with_dasherize_true - assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => true) + assert_equal "my-key", ActiveSupport::XmlMini.rename_key("my_key", dasherize: true) end def test_rename_key_does_nothing_with_dasherize_false - assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => false) + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", dasherize: false) end def test_rename_key_camelizes_with_camelize_true - assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) + assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", camelize: true) end def test_rename_key_lower_camelizes_with_camelize_lower - assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :lower) + assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", camelize: :lower) end def test_rename_key_lower_camelizes_with_camelize_upper - assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :upper) + assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", camelize: :upper) end def test_rename_key_does_not_dasherize_leading_underscores @@ -63,16 +63,16 @@ module XmlMiniTest def setup @xml = ActiveSupport::XmlMini - @options = {:skip_instruct => true, :builder => Builder::XmlMarkup.new} + @options = { skip_instruct: true, builder: Builder::XmlMarkup.new } end test "#to_tag accepts a callable object and passes options with the builder" do - @xml.to_tag(:some_tag, lambda {|o| o[:builder].br }, @options) + @xml.to_tag(:some_tag, lambda { |o| o[:builder].br }, @options) assert_xml "<br/>" end test "#to_tag accepts a callable object and passes options and tag name" do - @xml.to_tag(:tag, lambda {|o, t| o[:builder].b(t) }, @options) + @xml.to_tag(:tag, lambda { |o, t| o[:builder].b(t) }, @options) assert_xml "<b>tag</b>" end @@ -92,7 +92,7 @@ module XmlMiniTest end test "#to_tag should use the type value in the options hash" do - @xml.to_tag(:b, "blue", @options.merge(type: 'color')) + @xml.to_tag(:b, "blue", @options.merge(type: "color")) assert_xml( "<b type=\"color\">blue</b>" ) end @@ -122,7 +122,7 @@ module XmlMiniTest end test "#to_tag accepts datetime types" do - @xml.to_tag(:b, DateTime.new(2001,2,3,4,5,6,'+7'), @options) + @xml.to_tag(:b, DateTime.new(2001,2,3,4,5,6,"+7"), @options) assert_xml( "<b type=\"dateTime\">2001-02-03T04:05:06+07:00</b>") end @@ -233,22 +233,22 @@ module XmlMiniTest end def test_symbol - parser = @parsing['symbol'] - assert_equal :symbol, parser.call('symbol') + parser = @parsing["symbol"] + assert_equal :symbol, parser.call("symbol") assert_equal :symbol, parser.call(:symbol) assert_equal :'123', parser.call(123) assert_raises(ArgumentError) { parser.call(Date.new(2013,11,12,02,11)) } end def test_date - parser = @parsing['date'] + parser = @parsing["date"] assert_equal Date.new(2013,11,12), parser.call("2013-11-12T0211Z") assert_raises(TypeError) { parser.call(1384190018) } assert_raises(ArgumentError) { parser.call("not really a date") } end def test_datetime - parser = @parsing['datetime'] + parser = @parsing["datetime"] assert_equal Time.new(2013,11,12,02,11,00,0), parser.call("2013-11-12T02:11:00Z") assert_equal DateTime.new(2013,11,12), parser.call("2013-11-12T0211Z") assert_equal DateTime.new(2013,11,12,02,11), parser.call("2013-11-12T02:11Z") @@ -257,7 +257,7 @@ module XmlMiniTest end def test_integer - parser = @parsing['integer'] + parser = @parsing["integer"] assert_equal 123, parser.call(123) assert_equal 123, parser.call(123.003) assert_equal 123, parser.call("123") @@ -266,7 +266,7 @@ module XmlMiniTest end def test_float - parser = @parsing['float'] + parser = @parsing["float"] assert_equal 123, parser.call("123") assert_equal 123.003, parser.call("123.003") assert_equal 123.0, parser.call("123,003") @@ -277,7 +277,7 @@ module XmlMiniTest end def test_decimal - parser = @parsing['decimal'] + parser = @parsing["decimal"] assert_equal 123, parser.call("123") assert_equal 123.003, parser.call("123.003") assert_equal 123.0, parser.call("123,003") @@ -288,7 +288,7 @@ module XmlMiniTest end def test_boolean - parser = @parsing['boolean'] + parser = @parsing["boolean"] [1, true, "1"].each do |value| assert parser.call(value) end @@ -299,7 +299,7 @@ module XmlMiniTest end def test_string - parser = @parsing['string'] + parser = @parsing["string"] assert_equal "123", parser.call(123) assert_equal "123", parser.call("123") assert_equal "[]", parser.call("[]") @@ -317,13 +317,13 @@ product: YAML expected = { "product"=> [ - {"sku"=>"BL394D", "quantity"=>4, "description"=>"Basketball"} + { "sku"=>"BL394D", "quantity"=>4, "description"=>"Basketball" } ] } - parser = @parsing['yaml'] + parser = @parsing["yaml"] assert_equal(expected, parser.call(yaml)) - assert_equal({1 => 'test'}, parser.call({1 => 'test'})) - assert_equal({"1 => 'test'"=>nil}, parser.call("{1 => 'test'}")) + assert_equal({ 1 => "test" }, parser.call(1 => "test")) + assert_equal({ "1 => 'test'"=>nil }, parser.call("{1 => 'test'}")) end def test_base64Binary_and_binary @@ -341,12 +341,12 @@ in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure. EXPECTED - parser = @parsing['base64Binary'] + parser = @parsing["base64Binary"] assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64) parser.call("NON BASE64 INPUT") - parser = @parsing['binary'] - assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64, 'encoding' => 'base64') + parser = @parsing["binary"] + assert_equal expected_base64.gsub(/\n/," ").strip, parser.call(base64, "encoding" => "base64") assert_equal "IGNORED INPUT", parser.call("IGNORED INPUT", {}) end end diff --git a/ci/travis.rb b/ci/travis.rb index b8891d6889..1d658bae47 100755 --- a/ci/travis.rb +++ b/ci/travis.rb @@ -1,5 +1,5 @@ #!/usr/bin/env ruby -require 'fileutils' +require "fileutils" include FileUtils commands = [ @@ -15,16 +15,16 @@ end class Build MAP = { - 'railties' => 'railties', - 'ap' => 'actionpack', - 'am' => 'actionmailer', - 'amo' => 'activemodel', - 'as' => 'activesupport', - 'ar' => 'activerecord', - 'av' => 'actionview', - 'aj' => 'activejob', - 'ac' => 'actioncable', - 'guides' => 'guides' + "railties" => "railties", + "ap" => "actionpack", + "am" => "actionmailer", + "amo" => "activemodel", + "as" => "activesupport", + "ar" => "activerecord", + "av" => "actionview", + "aj" => "activejob", + "ac" => "actioncable", + "guides" => "guides" } attr_reader :component, :options @@ -55,41 +55,41 @@ class Build heading << "with #{adapter}" if activerecord? heading << "in isolation" if isolated? heading << "integration" if integration? - heading.join(' ') + heading.join(" ") end def tasks if activerecord? tasks = ["#{adapter}:#{'isolated_' if isolated?}test"] case adapter - when 'mysql2' - tasks.unshift 'db:mysql:rebuild' - when 'postgresql' - tasks.unshift 'db:postgresql:rebuild' + when "mysql2" + tasks.unshift "db:mysql:rebuild" + when "postgresql" + tasks.unshift "db:postgresql:rebuild" end tasks else - ["test", ('isolated' if isolated?), ('integration' if integration?)].compact.join(":") + ["test", ("isolated" if isolated?), ("integration" if integration?)].compact.join(":") end end def key key = [gem] key << adapter if activerecord? - key << 'isolated' if isolated? - key.join(':') + key << "isolated" if isolated? + key.join(":") end def activesupport? - gem == 'activesupport' + gem == "activesupport" end def activerecord? - gem == 'activerecord' + gem == "activerecord" end def guides? - gem == 'guides' + gem == "guides" end def isolated? @@ -97,16 +97,16 @@ class Build end def integration? - component.split(':').last == 'integration' + component.split(":").last == "integration" end def gem - MAP[component.split(':').first] + MAP[component.split(":").first] end alias :dir :gem def adapter - component.split(':').last + component.split(":").last end def rake(*tasks) @@ -123,36 +123,36 @@ class Build # There is a known issue with the listen tests that causes files to be # incorrectly GC'ed even when they are still in-use. The current solution # is to only run them in isolation to avoid randomly failing our test suite. - { 'LISTEN' => '0' } + { "LISTEN" => "0" } else {} end end def run_bug_report_templates - Dir.glob('bug_report_templates/*.rb').all? do |file| - system(Gem.ruby, '-w', file) + Dir.glob("bug_report_templates/*.rb").all? do |file| + system(Gem.ruby, "-w", file) end end end -if ENV['GEM']=='aj:integration' - ENV['QC_DATABASE_URL'] = 'postgres://postgres@localhost/active_jobs_qc_int_test' - ENV['QUE_DATABASE_URL'] = 'postgres://postgres@localhost/active_jobs_que_int_test' +if ENV["GEM"]=="aj:integration" + ENV["QC_DATABASE_URL"] = "postgres://postgres@localhost/active_jobs_qc_int_test" + ENV["QUE_DATABASE_URL"] = "postgres://postgres@localhost/active_jobs_que_int_test" end results = {} -ENV['GEM'].split(',').each do |gem| +ENV["GEM"].split(",").each do |gem| [false, true].each do |isolated| - next if ENV['TRAVIS_PULL_REQUEST'] && ENV['TRAVIS_PULL_REQUEST'] != 'false' && isolated - next if gem == 'railties' && isolated - next if gem == 'ac' && isolated - next if gem == 'ac:integration' && isolated - next if gem == 'aj:integration' && isolated - next if gem == 'guides' && isolated - - build = Build.new(gem, :isolated => isolated) + next if ENV["TRAVIS_PULL_REQUEST"] && ENV["TRAVIS_PULL_REQUEST"] != "false" && isolated + next if gem == "railties" && isolated + next if gem == "ac" && isolated + next if gem == "ac:integration" && isolated + next if gem == "aj:integration" && isolated + next if gem == "guides" && isolated + + build = Build.new(gem, isolated: isolated) results[build.key] = build.run! end diff --git a/guides/Rakefile b/guides/Rakefile index 00577377d7..bf501f6a64 100644 --- a/guides/Rakefile +++ b/guides/Rakefile @@ -1,7 +1,7 @@ namespace :guides do desc 'Generate guides (for authors), use ONLY=foo to process just "foo.md"' - task :generate => 'generate:html' + task generate: "generate:html" namespace :generate do @@ -13,14 +13,14 @@ namespace :guides do desc "Generate .mobi file. The kindlegen executable must be in your PATH. You can get it for free from http://www.amazon.com/gp/feature.html?docId=1000765211" task :kindle do - unless `kindlerb -v 2> /dev/null` =~ /kindlerb 0.1.1/ + unless `kindlerb -v 2> /dev/null` =~ /kindlerb 1.0.1/ abort "Please `gem install kindlerb` and make sure you have `kindlegen` in your PATH" end - unless `convert` =~ /convert/ + unless `convert` =~ /convert/ abort "Please install ImageMagick`" end - ENV['KINDLE'] = '1' - Rake::Task['guides:generate:html'].invoke + ENV["KINDLE"] = "1" + Rake::Task["guides:generate:html"].invoke end end @@ -76,4 +76,4 @@ Examples: end end -task :default => 'guides:help' +task default: "guides:help" diff --git a/guides/assets/images/getting_started/template_is_missing_articles_new.png b/guides/assets/images/getting_started/template_is_missing_articles_new.png Binary files differindex 4e636d09ff..f4f054f3c6 100644 --- a/guides/assets/images/getting_started/template_is_missing_articles_new.png +++ b/guides/assets/images/getting_started/template_is_missing_articles_new.png diff --git a/guides/assets/javascripts/guides.js b/guides/assets/javascripts/guides.js index a9c7f0d016..e4d25dfb21 100644 --- a/guides/assets/javascripts/guides.js +++ b/guides/assets/javascripts/guides.js @@ -51,9 +51,3 @@ var guidesIndex = { window.location = url; } }; - -// Disable autolink inside example code blocks of guides. -$(document).ready(function() { - SyntaxHighlighter.defaults['auto-links'] = false; - SyntaxHighlighter.all(); -}); diff --git a/guides/assets/javascripts/syntaxhighlighter.js b/guides/assets/javascripts/syntaxhighlighter.js new file mode 100644 index 0000000000..584aaed716 --- /dev/null +++ b/guides/assets/javascripts/syntaxhighlighter.js @@ -0,0 +1,20 @@ +/*! + * SyntaxHighlighter + * https://github.com/syntaxhighlighter/syntaxhighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 4.0.1 (Sun, 03 Jul 2016 06:45:54 GMT) + * + * @copyright + * Copyright (C) 2004-2016 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ + + +!function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t["default"]=e,t}function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(1);Object.keys(a).forEach(function(e){"default"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return a[e]}})});var s=n(28),o=i(s),l=i(a),u=n(29),c=r(u);n(30),(0,o["default"])(function(){return l["default"].highlight(c.object(window.syntaxhighlighterConfig||{}))})},function(e,t,n){"use strict";function r(e){window.alert("SyntaxHighlighter\n\n"+e)}function i(e,t){var n=h.vars.discoveredBrushes,i=null;if(null==n){n={};for(var a in h.brushes){var s=h.brushes[a],o=s.aliases;if(null!=o){s.className=s.className||s.aliases[0],s.brushName=s.className||a.toLowerCase();for(var l=0,u=o.length;u>l;l++)n[o[l]]=a}}h.vars.discoveredBrushes=n}return i=h.brushes[n[e]],null==i&&t&&r(h.config.strings.noBrush+e),i}function a(e){var t="<![CDATA[",n="]]>",r=u.trim(e),i=!1,a=t.length,s=n.length;0==r.indexOf(t)&&(r=r.substring(a),i=!0);var o=r.length;return r.indexOf(n)==o-s&&(r=r.substring(0,o-s),i=!0),i?r:e}Object.defineProperty(t,"__esModule",{value:!0});var s=n(2),o=n(5),l=n(9)["default"],u=n(10),c=n(11),f=n(17),g=n(18),p=n(19),d=n(20),h={Match:o.Match,Highlighter:n(22),config:n(18),regexLib:n(3).commonRegExp,vars:{discoveredBrushes:null,highlighters:{}},brushes:{},findElements:function(e,t){var n=t?[t]:u.toArray(document.getElementsByTagName(h.config.tagName)),r=(h.config,[]);if(n=n.concat(f.getSyntaxHighlighterScriptTags()),0===n.length)return r;for(var i=0,a=n.length;a>i;i++){var o={target:n[i],params:s.defaults(s.parse(n[i].className),e)};null!=o.params.brush&&r.push(o)}return r},highlight:function(e,t){var n,r=h.findElements(e,t),u="innerHTML",m=null,x=h.config;if(0!==r.length)for(var v=0,y=r.length;y>v;v++){var m,w,b,t=r[v],E=t.target,S=t.params,C=S.brush;null!=C&&(m=i(C),m&&(S=s.defaults(S||{},p),S=s.defaults(S,g),1==S["html-script"]||1==p["html-script"]?(m=new d(i("xml"),m),C="htmlscript"):m=new m,b=E[u],x.useScriptTags&&(b=a(b)),""!=(E.title||"")&&(S.title=E.title),S.brush=C,b=c(b,S),w=o.applyRegexList(b,m.regexList,S),n=new l(b,w,S),t=f.create("div"),t.innerHTML=n.getHtml(),S.quickCode&&f.attachEvent(f.findElement(t,".code"),"dblclick",f.quickCodeHandler),""!=(E.id||"")&&(t.id=E.id),E.parentNode.replaceChild(t,E)))}}},m=0;t["default"]=h;var x=t.registerBrush=function(e){return h.brushes["brush"+m++]=e["default"]||e};t.clearRegisteredBrushes=function(){h.brushes={},m=0};x(n(23)),x(n(24)),x(n(25)),x(n(26)),x(n(27))},function(e,t,n){"use strict";function r(e){return e.replace(/-(\w+)/g,function(e,t){return t.charAt(0).toUpperCase()+t.substr(1)})}function i(e){var t=s[e];return null==t?e:t}var a=n(3).XRegExp,s={"true":!0,"false":!1};e.exports={defaults:function(e,t){for(var n in t||{})e.hasOwnProperty(n)||(e[n]=e[r(n)]=t[n]);return e},parse:function(e){for(var t,n={},s=a("^\\[(?<values>(.*?))\\]$"),o=0,l=a("(?<name>[\\w-]+)\\s*:\\s*(?<value>[\\w%#-]+|\\[.*?\\]|\".*?\"|'.*?')\\s*;?","g");null!=(t=a.exec(e,l,o));){var u=t.value.replace(/^['"]|['"]$/g,"");if(null!=u&&s.test(u)){var c=a.exec(u,s);u=c.values.length>0?c.values.split(/\s*,\s*/):[]}u=i(u),n[t.name]=n[r(t.name)]=u,o=t.index+t[0].length}return n}}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0}),t.commonRegExp=t.XRegExp=void 0;var i=n(4),a=r(i);t.XRegExp=a["default"];t.commonRegExp={multiLineCComments:(0,a["default"])("/\\*.*?\\*/","gs"),singleLineCComments:/\/\/.*$/gm,singleLinePerlComments:/#.*$/gm,doubleQuotedString:/"([^\\"\n]|\\.)*"/g,singleQuotedString:/'([^\\'\n]|\\.)*'/g,multiLineDoubleQuotedString:(0,a["default"])('"([^\\\\"]|\\\\.)*"',"gs"),multiLineSingleQuotedString:(0,a["default"])("'([^\\\\']|\\\\.)*'","gs"),xmlComments:(0,a["default"])("(<|<)!--.*?--(>|>)","gs"),url:/\w+:\/\/[\w-.\/?%&=:@;#]*/g,phpScriptTags:{left:/(<|<)\?(?:=|php)?/g,right:/\?(>|>)/g,eof:!0},aspScriptTags:{left:/(<|<)%=?/g,right:/%(>|>)/g},scriptScriptTags:{left:/(<|<)\s*script.*?(>|>)/gi,right:/(<|<)\/\s*script\s*(>|>)/gi}}},function(e,t){"use strict";function n(e,t,n,r,i){var a;if(e[b]={captureNames:t},i)return e;if(e.__proto__)e.__proto__=w.prototype;else for(a in w.prototype)e[a]=w.prototype[a];return e[b].source=n,e[b].flags=r?r.split("").sort().join(""):r,e}function r(e){return S.replace.call(e,/([\s\S])(?=[\s\S]*\1)/g,"")}function i(e,t){if(!w.isRegExp(e))throw new TypeError("Type RegExp expected");var i=e[b]||{},a=s(e),l="",u="",c=null,f=null;return t=t||{},t.removeG&&(u+="g"),t.removeY&&(u+="y"),u&&(a=S.replace.call(a,new RegExp("["+u+"]+","g"),"")),t.addG&&(l+="g"),t.addY&&(l+="y"),l&&(a=r(a+l)),t.isInternalOnly||(void 0!==i.source&&(c=i.source),null!=i.flags&&(f=l?r(i.flags+l):i.flags)),e=n(new RegExp(e.source,a),o(e)?i.captureNames.slice(0):null,c,f,t.isInternalOnly)}function a(e){return parseInt(e,16)}function s(e){return M?e.flags:S.exec.call(/\/([a-z]*)$/i,RegExp.prototype.toString.call(e))[1]}function o(e){return!(!e[b]||!e[b].captureNames)}function l(e){return parseInt(e,10).toString(16)}function u(e,t){var n,r=e.length;for(n=0;r>n;++n)if(e[n]===t)return n;return-1}function c(e,t){return $.call(e)==="[object "+t+"]"}function f(e,t,n){return S.test.call(n.indexOf("x")>-1?/^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/:/^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/,e.slice(t))}function g(e){for(;e.length<4;)e="0"+e;return e}function p(e,t){var n;if(r(t)!==t)throw new SyntaxError("Invalid duplicate regex flag "+t);for(e=S.replace.call(e,/^\(\?([\w$]+)\)/,function(e,n){if(S.test.call(/[gy]/,n))throw new SyntaxError("Cannot use flag g or y in mode modifier "+e);return t=r(t+n),""}),n=0;n<t.length;++n)if(!H[t.charAt(n)])throw new SyntaxError("Unknown regex flag "+t.charAt(n));return{pattern:e,flags:t}}function d(e){var t={};return c(e,"String")?(w.forEach(e,/[^\s,]+/,function(e){t[e]=!0}),t):e}function h(e){if(!/^[\w$]$/.test(e))throw new Error("Flag must be a single character A-Za-z0-9_$");H[e]=!0}function m(e,t,n,r,i){for(var a,s,o=L.length,l=e.charAt(n),u=null;o--;)if(s=L[o],!(s.leadChar&&s.leadChar!==l||s.scope!==r&&"all"!==s.scope||s.flag&&-1===t.indexOf(s.flag))&&(a=w.exec(e,s.regex,n,"sticky"))){u={matchLength:a[0].length,output:s.handler.call(i,a,r,t),reparse:s.reparse};break}return u}function x(e){E.astral=e}function v(e){RegExp.prototype.exec=(e?C:S).exec,RegExp.prototype.test=(e?C:S).test,String.prototype.match=(e?C:S).match,String.prototype.replace=(e?C:S).replace,String.prototype.split=(e?C:S).split,E.natives=e}function y(e){if(null==e)throw new TypeError("Cannot convert null or undefined to object");return e}function w(e,t){var r,a,s,o,l,u={hasNamedCapture:!1,captureNames:[]},c=R,f="",g=0;if(w.isRegExp(e)){if(void 0!==t)throw new TypeError("Cannot supply flags when copying a RegExp");return i(e)}if(e=void 0===e?"":String(e),t=void 0===t?"":String(t),w.isInstalled("astral")&&-1===t.indexOf("A")&&(t+="A"),k[e]||(k[e]={}),!k[e][t]){for(r=p(e,t),o=r.pattern,l=r.flags;g<o.length;){do r=m(o,l,g,c,u),r&&r.reparse&&(o=o.slice(0,g)+r.output+o.slice(g+r.matchLength));while(r&&r.reparse);r?(f+=r.output,g+=r.matchLength||1):(a=w.exec(o,_[c],g,"sticky")[0],f+=a,g+=a.length,"["===a&&c===R?c=T:"]"===a&&c===T&&(c=R))}k[e][t]={pattern:S.replace.call(f,/\(\?:\)(?:[*+?]|\{\d+(?:,\d*)?})?\??(?=\(\?:\))|^\(\?:\)(?:[*+?]|\{\d+(?:,\d*)?})?\??|\(\?:\)(?:[*+?]|\{\d+(?:,\d*)?})?\??$/g,""),flags:S.replace.call(l,/[^gimuy]+/g,""),captures:u.hasNamedCapture?u.captureNames:null}}return s=k[e][t],n(new RegExp(s.pattern,s.flags),s.captures,e,t)}var b="xregexp",E={astral:!1,natives:!1},S={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},C={},N={},k={},L=[],R="default",T="class",_={"default":/\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/,"class":/\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u(?:[\dA-Fa-f]{4}|{[\dA-Fa-f]+})|c[A-Za-z]|[\s\S])|[\s\S]/},O=/\$(?:{([\w$]+)}|(\d\d?|[\s\S]))/g,j=void 0===S.exec.call(/()??/,"")[1],I=function(){var e=!0;try{new RegExp("","u")}catch(t){e=!1}return e}(),A=function(){var e=!0;try{new RegExp("","y")}catch(t){e=!1}return e}(),M=void 0!==/a/.flags,H={g:!0,i:!0,m:!0,u:I,y:A},$={}.toString;w.prototype=new RegExp,w.version="3.1.0-dev",w.addToken=function(e,t,n){n=n||{};var r,a=n.optionalFlags;if(n.flag&&h(n.flag),a)for(a=S.split.call(a,""),r=0;r<a.length;++r)h(a[r]);L.push({regex:i(e,{addG:!0,addY:A,isInternalOnly:!0}),handler:t,scope:n.scope||R,flag:n.flag,reparse:n.reparse,leadChar:n.leadChar}),w.cache.flush("patterns")},w.cache=function(e,t){return N[e]||(N[e]={}),N[e][t]||(N[e][t]=w(e,t))},w.cache.flush=function(e){"patterns"===e?k={}:N={}},w.escape=function(e){return S.replace.call(y(e),/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},w.exec=function(e,t,n,r){var a,s,o="g",l=!1;return l=A&&!!(r||t.sticky&&r!==!1),l&&(o+="y"),t[b]=t[b]||{},s=t[b][o]||(t[b][o]=i(t,{addG:!0,addY:l,removeY:r===!1,isInternalOnly:!0})),s.lastIndex=n=n||0,a=C.exec.call(s,e),r&&a&&a.index!==n&&(a=null),t.global&&(t.lastIndex=a?s.lastIndex:0),a},w.forEach=function(e,t,n){for(var r,i=0,a=-1;r=w.exec(e,t,i);)n(r,++a,e,t),i=r.index+(r[0].length||1)},w.globalize=function(e){return i(e,{addG:!0})},w.install=function(e){e=d(e),!E.astral&&e.astral&&x(!0),!E.natives&&e.natives&&v(!0)},w.isInstalled=function(e){return!!E[e]},w.isRegExp=function(e){return"[object RegExp]"===$.call(e)},w.match=function(e,t,n){var r,a,s=t.global&&"one"!==n||"all"===n,o=(s?"g":"")+(t.sticky?"y":"")||"noGY";return t[b]=t[b]||{},a=t[b][o]||(t[b][o]=i(t,{addG:!!s,addY:!!t.sticky,removeG:"one"===n,isInternalOnly:!0})),r=S.match.call(y(e),a),t.global&&(t.lastIndex="one"===n&&r?r.index+r[0].length:0),s?r||[]:r&&r[0]},w.matchChain=function(e,t){return function n(e,r){var i,a=t[r].regex?t[r]:{regex:t[r]},s=[],o=function(e){if(a.backref){if(!(e.hasOwnProperty(a.backref)||+a.backref<e.length))throw new ReferenceError("Backreference to undefined group: "+a.backref);s.push(e[a.backref]||"")}else s.push(e[0])};for(i=0;i<e.length;++i)w.forEach(e[i],a.regex,o);return r!==t.length-1&&s.length?n(s,r+1):s}([e],0)},w.replace=function(e,t,n,r){var a,s=w.isRegExp(t),o=t.global&&"one"!==r||"all"===r,l=(o?"g":"")+(t.sticky?"y":"")||"noGY",u=t;return s?(t[b]=t[b]||{},u=t[b][l]||(t[b][l]=i(t,{addG:!!o,addY:!!t.sticky,removeG:"one"===r,isInternalOnly:!0}))):o&&(u=new RegExp(w.escape(String(t)),"g")),a=C.replace.call(y(e),u,n),s&&t.global&&(t.lastIndex=0),a},w.replaceEach=function(e,t){var n,r;for(n=0;n<t.length;++n)r=t[n],e=w.replace(e,r[0],r[1],r[2]);return e},w.split=function(e,t,n){return C.split.call(y(e),t,n)},w.test=function(e,t,n,r){return!!w.exec(e,t,n,r)},w.uninstall=function(e){e=d(e),E.astral&&e.astral&&x(!1),E.natives&&e.natives&&v(!1)},w.union=function(e,t){var n,r,i,a,s=/(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g,o=[],l=0,u=function(e,t,i){var a=r[l-n];if(t){if(++l,a)return"(?<"+a+">"}else if(i)return"\\"+(+i+n);return e};if(!c(e,"Array")||!e.length)throw new TypeError("Must provide a nonempty array of patterns to merge");for(a=0;a<e.length;++a)i=e[a],w.isRegExp(i)?(n=l,r=i[b]&&i[b].captureNames||[],o.push(S.replace.call(w(i.source).source,s,u))):o.push(w.escape(i));return w(o.join("|"),t)},C.exec=function(e){var t,n,r,a=this.lastIndex,s=S.exec.apply(this,arguments);if(s){if(!j&&s.length>1&&u(s,"")>-1&&(n=i(this,{removeG:!0,isInternalOnly:!0}),S.replace.call(String(e).slice(s.index),n,function(){var e,t=arguments.length;for(e=1;t-2>e;++e)void 0===arguments[e]&&(s[e]=void 0)})),this[b]&&this[b].captureNames)for(r=1;r<s.length;++r)t=this[b].captureNames[r-1],t&&(s[t]=s[r]);this.global&&!s[0].length&&this.lastIndex>s.index&&(this.lastIndex=s.index)}return this.global||(this.lastIndex=a),s},C.test=function(e){return!!C.exec.call(this,e)},C.match=function(e){var t;if(w.isRegExp(e)){if(e.global)return t=S.match.apply(this,arguments),e.lastIndex=0,t}else e=new RegExp(e);return C.exec.call(e,y(this))},C.replace=function(e,t){var n,r,i,a=w.isRegExp(e);return a?(e[b]&&(r=e[b].captureNames),n=e.lastIndex):e+="",i=c(t,"Function")?S.replace.call(String(this),e,function(){var n,i=arguments;if(r)for(i[0]=new String(i[0]),n=0;n<r.length;++n)r[n]&&(i[0][r[n]]=i[n+1]);return a&&e.global&&(e.lastIndex=i[i.length-2]+i[0].length),t.apply(void 0,i)}):S.replace.call(null==this?this:String(this),e,function(){var e=arguments;return S.replace.call(String(t),O,function(t,n,i){var a;if(n){if(a=+n,a<=e.length-3)return e[a]||"";if(a=r?u(r,n):-1,0>a)throw new SyntaxError("Backreference to undefined group "+t);return e[a+1]||""}if("$"===i)return"$";if("&"===i||0===+i)return e[0];if("`"===i)return e[e.length-1].slice(0,e[e.length-2]);if("'"===i)return e[e.length-1].slice(e[e.length-2]+e[0].length);if(i=+i,!isNaN(i)){if(i>e.length-3)throw new SyntaxError("Backreference to undefined group "+t);return e[i]||""}throw new SyntaxError("Invalid token "+t)})}),a&&(e.global?e.lastIndex=0:e.lastIndex=n),i},C.split=function(e,t){if(!w.isRegExp(e))return S.split.apply(this,arguments);var n,r=String(this),i=[],a=e.lastIndex,s=0;return t=(void 0===t?-1:t)>>>0,w.forEach(r,e,function(e){e.index+e[0].length>s&&(i.push(r.slice(s,e.index)),e.length>1&&e.index<r.length&&Array.prototype.push.apply(i,e.slice(1)),n=e[0].length,s=e.index+n)}),s===r.length?(!S.test.call(e,"")||n)&&i.push(""):i.push(r.slice(s)),e.lastIndex=a,i.length>t?i.slice(0,t):i},w.addToken(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4}|{[\dA-Fa-f]+})|x(?![\dA-Fa-f]{2}))/,function(e,t){if("B"===e[1]&&t===R)return e[0];throw new SyntaxError("Invalid escape "+e[0])},{scope:"all",leadChar:"\\"}),w.addToken(/\\u{([\dA-Fa-f]+)}/,function(e,t,n){var r=a(e[1]);if(r>1114111)throw new SyntaxError("Invalid Unicode code point "+e[0]);if(65535>=r)return"\\u"+g(l(r));if(I&&n.indexOf("u")>-1)return e[0];throw new SyntaxError("Cannot use Unicode code point above \\u{FFFF} without flag u")},{scope:"all",leadChar:"\\"}),w.addToken(/\[(\^?)]/,function(e){return e[1]?"[\\s\\S]":"\\b\\B"},{leadChar:"["}),w.addToken(/\(\?#[^)]*\)/,function(e,t,n){return f(e.input,e.index+e[0].length,n)?"":"(?:)"},{leadChar:"("}),w.addToken(/\s+|#.*/,function(e,t,n){return f(e.input,e.index+e[0].length,n)?"":"(?:)"},{flag:"x"}),w.addToken(/\./,function(){return"[\\s\\S]"},{flag:"s",leadChar:"."}),w.addToken(/\\k<([\w$]+)>/,function(e){var t=isNaN(e[1])?u(this.captureNames,e[1])+1:+e[1],n=e.index+e[0].length;if(!t||t>this.captureNames.length)throw new SyntaxError("Backreference to undefined group "+e[0]);return"\\"+t+(n===e.input.length||isNaN(e.input.charAt(n))?"":"(?:)")},{leadChar:"\\"}),w.addToken(/\\(\d+)/,function(e,t){if(!(t===R&&/^[1-9]/.test(e[1])&&+e[1]<=this.captureNames.length)&&"0"!==e[1])throw new SyntaxError("Cannot use octal escape or backreference to undefined group "+e[0]);return e[0]},{scope:"all",leadChar:"\\"}),w.addToken(/\(\?P?<([\w$]+)>/,function(e){if(!isNaN(e[1]))throw new SyntaxError("Cannot use integer as capture name "+e[0]);if("length"===e[1]||"__proto__"===e[1])throw new SyntaxError("Cannot use reserved word as capture name "+e[0]);if(u(this.captureNames,e[1])>-1)throw new SyntaxError("Cannot use same name for multiple groups "+e[0]);return this.captureNames.push(e[1]),this.hasNamedCapture=!0,"("},{leadChar:"("}),w.addToken(/\((?!\?)/,function(e,t,n){return n.indexOf("n")>-1?"(?:":(this.captureNames.push(null),"(")},{optionalFlags:"n",leadChar:"("}),e.exports=w},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(6);Object.keys(r).forEach(function(e){"default"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return r[e]}})});var i=n(7);Object.keys(i).forEach(function(e){"default"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return i[e]}})})},function(e,t){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}();t.Match=function(){function e(t,r,i){n(this,e),this.value=t,this.index=r,this.length=t.length,this.css=i,this.brushName=null}return r(e,[{key:"toString",value:function(){return this.value}}]),e}()},function(e,t,n){"use strict";function r(e,t){var n=[];t=t||[];for(var r=0,s=t.length;s>r;r++)"object"===i(t[r])&&(n=n.concat((0,a.find)(e,t[r])));return n=(0,a.sort)(n),n=(0,a.removeNested)(n),n=(0,a.compact)(n)}Object.defineProperty(t,"__esModule",{value:!0});var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};t.applyRegexList=r;var a=n(8)},function(e,t,n){"use strict";function r(e,t){function n(e,t){return e[0]}for(var r=null,i=[],a=t.func?t.func:n,s=0;r=l.XRegExp.exec(e,t.regex,s);){var u=a(r,t);"string"==typeof u&&(u=[new o.Match(u,r.index,t.css)]),i=i.concat(u),s=r.index+r[0].length}return i}function i(e){function t(e,t){return e.index<t.index?-1:e.index>t.index?1:e.length<t.length?-1:e.length>t.length?1:0}return e.sort(t)}function a(e){var t,n,r=[];for(t=0,n=e.length;n>t;t++)e[t]&&r.push(e[t]);return r}function s(e){for(var t=0,n=e.length;n>t;t++)if(null!==e[t])for(var r=e[t],i=r.index+r.length,a=t+1,n=e.length;n>a&&null!==e[t];a++){var s=e[a];if(null!==s){if(s.index>i)break;s.index==r.index&&s.length>r.length?e[t]=null:s.index>=r.index&&s.index<i&&(e[a]=null)}}return e}Object.defineProperty(t,"__esModule",{value:!0}),t.find=r,t.sort=i,t.compact=a,t.removeNested=s;var o=n(6),l=n(3)},function(e,t){"use strict";function n(e,t){for(var n=e.toString();n.length<t;)n="0"+n;return n}function r(e){return e.split(/\r?\n/)}function i(e){var t,n,r,i={};for(t=e.highlight||[],"function"!=typeof t.push&&(t=[t]),r=0,n=t.length;n>r;r++)i[t[r]]=!0;return i}function a(e,t,n){var a=this;a.opts=n,a.code=e,a.matches=t,a.lines=r(e),a.linesToHighlight=i(n)}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=a,a.prototype={wrapLinesWithCode:function(e,t){if(null==e||0==e.length||"\n"==e||null==t)return e;var n,i,a,s,o,l=this,u=[];for(e=e.replace(/</g,"<"),e=e.replace(/ {2,}/g,function(e){for(a="",s=0,o=e.length;o-1>s;s++)a+=l.opts.space;return a+" "}),n=r(e),s=0,o=n.length;o>s;s++)i=n[s],a="",i.length>0&&(i=i.replace(/^( | )+/,function(e){return a=e,""}),i=0===i.length?a:a+'<code class="'+t+'">'+i+"</code>"),u.push(i);return u.join("\n")},processUrls:function(e){var t=/(.*)((>|<).*)/,n=/\w+:\/\/[\w-.\/?%&=:@;#]*/g;return e.replace(n,function(e){var n="",r=null;return(r=t.exec(e))&&(e=r[1],n=r[2]),'<a href="'+e+'">'+e+"</a>"+n})},figureOutLineNumbers:function(e){var t,n,r=[],i=this.lines,a=parseInt(this.opts.firstLine||1);for(t=0,n=i.length;n>t;t++)r.push(t+a);return r},wrapLine:function(e,t,n){var r=["line","number"+t,"index"+e,"alt"+(t%2==0?1:2).toString()];return this.linesToHighlight[t]&&r.push("highlighted"),0==t&&r.push("break"),'<div class="'+r.join(" ")+'">'+n+"</div>"},renderLineNumbers:function(e,t){var r,i,a=this,s=a.opts,o="",l=a.lines.length,u=parseInt(s.firstLine||1),c=s.padLineNumbers;for(1==c?c=(u+l-1).toString().length:1==isNaN(c)&&(c=0),i=0;l>i;i++)r=t?t[i]:u+i,e=0==r?s.space:n(r,c),o+=a.wrapLine(i,r,e);return o},getCodeLinesHtml:function(e,t){for(var n=this,i=n.opts,a=r(e),s=(i.padLineNumbers,parseInt(i.firstLine||1)),o=i.brush,e="",l=0,u=a.length;u>l;l++){var c=a[l],f=/^( |\s)+/.exec(c),g=null,p=t?t[l]:s+l;null!=f&&(g=f[0].toString(),c=c.substr(g.length),g=g.replace(" ",i.space)),0==c.length&&(c=i.space),e+=n.wrapLine(l,p,(null!=g?'<code class="'+o+' spaces">'+g+"</code>":"")+c)}return e},getTitleHtml:function(e){return e?"<caption>"+e+"</caption>":""},getMatchesHtml:function(e,t){function n(e){var t=e?e.brushName||c:c;return t?t+" ":""}var r,i,a,s,o=this,l=0,u="",c=o.opts.brush||"";for(a=0,s=t.length;s>a;a++)r=t[a],null!==r&&0!==r.length&&(i=n(r),u+=o.wrapLinesWithCode(e.substr(l,r.index-l),i+"plain")+o.wrapLinesWithCode(r.value,i+r.css),l=r.index+r.length+(r.offset||0));return u+=o.wrapLinesWithCode(e.substr(l),n()+"plain")},getHtml:function(){var e,t,n,r=this,i=r.opts,a=r.code,s=r.matches,o=["syntaxhighlighter"];return i.collapse===!0&&o.push("collapsed"),t=i.gutter!==!1,t||o.push("nogutter"),o.push(i.className),o.push(i.brush),t&&(e=r.figureOutLineNumbers(a)),n=r.getMatchesHtml(a,s),n=r.getCodeLinesHtml(n,e),i.autoLinks&&(n=r.processUrls(n)),n='\n <div class="'+o.join(" ")+'">\n <table border="0" cellpadding="0" cellspacing="0">\n '+r.getTitleHtml(i.title)+"\n <tbody>\n <tr>\n "+(t?'<td class="gutter">'+r.renderLineNumbers(a)+"</td>":"")+'\n <td class="code">\n <div class="container">'+n+"</div>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n "}}},function(e,t){"use strict";function n(e){return e.split(/\r?\n/)}function r(e,t){for(var r=n(e),i=0,a=r.length;a>i;i++)r[i]=t(r[i],i);return r.join("\n")}function i(e){return(e||"")+Math.round(1e6*Math.random()).toString()}function a(e,t){var n,r={};for(n in e)r[n]=e[n];for(n in t)r[n]=t[n];return r}function s(e){return e.replace(/^\s+|\s+$/g,"")}function o(e){return Array.prototype.slice.apply(e)}function l(e){var t={"true":!0,"false":!1}[e];return null==t?e:t}e.exports={splitLines:n,eachLine:r,guid:i,merge:a,trim:s,toArray:o,toBoolean:l}},function(e,t,n){"use strict";var r=n(12),i=n(13),a=n(14),s=n(15),o=n(16);e.exports=function(e,t){e=r(e,t),e=i(e,t),e=a(e,t),e=s.unindent(e,t);var n=t["tab-size"];return e=t["smart-tabs"]===!0?o.smart(e,n):o.regular(e,n)}},function(e,t){"use strict";e.exports=function(e,t){return e.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g,"").replace(/\r/g," ")}},function(e,t){"use strict";e.exports=function(e,t){var n=/<br\s*\/?>|<br\s*\/?>/gi;return t.bloggerMode===!0&&(e=e.replace(n,"\n")),e}},function(e,t){"use strict";e.exports=function(e,t){var n=/<br\s*\/?>|<br\s*\/?>/gi;return t.stripBrs===!0&&(e=e.replace(n,"")),e}},function(e,t){"use strict";function n(e){return/^\s*$/.test(e)}e.exports={unindent:function(e){var t,r,i,a,s=e.split(/\r?\n/),o=/^\s*/,l=1e3;for(i=0,a=s.length;a>i&&l>0;i++)if(t=s[i],!n(t)){if(r=o.exec(t),null==r)return e;l=Math.min(r[0].length,l)}if(l>0)for(i=0,a=s.length;a>i;i++)n(s[i])||(s[i]=s[i].substr(l));return s.join("\n")}}},function(e,t){"use strict";function n(e,t,n){return e.substr(0,t)+r.substr(0,n)+e.substr(t+1,e.length)}for(var r="",i=0;50>i;i++)r+=" ";e.exports={smart:function(e,t){var r,i,a,s,o=e.split(/\r?\n/),l=" ";for(a=0,s=o.length;s>a;a++)if(r=o[a],-1!==r.indexOf(l)){for(i=0;-1!==(i=r.indexOf(l));)r=n(r,i,t-i%t);o[a]=r}return o.join("\n")},regular:function(e,t){return e.replace(/\t/g,r.substr(0,t))}}},function(e,t){"use strict";function n(){for(var e=document.getElementsByTagName("script"),t=[],n=0;n<e.length;n++)("text/syntaxhighlighter"==e[n].type||"syntaxhighlighter"==e[n].type)&&t.push(e[n]);return t}function r(e,t){return-1!=e.className.indexOf(t)}function i(e,t){r(e,t)||(e.className+=" "+t)}function a(e,t){e.className=e.className.replace(t,"")}function s(e,t,n,r){function i(e){e=e||window.event,e.target||(e.target=e.srcElement,e.preventDefault=function(){this.returnValue=!1}),n.call(r||window,e)}e.attachEvent?e.attachEvent("on"+t,i):e.addEventListener(t,i,!1)}function o(e,t,n){if(null==e)return null;var r,i,a=1!=n?e.childNodes:[e.parentNode],s={"#":"id",".":"className"}[t.substr(0,1)]||"nodeName";if(r="nodeName"!=s?t.substr(1):t.toUpperCase(),-1!=(e[s]||"").indexOf(r))return e;for(var l=0,u=a.length;a&&u>l&&null==i;l++)i=o(a[l],t,n);return i}function l(e,t){return o(e,t,!0)}function u(e,t,n,r,i){var a=(screen.width-n)/2,s=(screen.height-r)/2;i+=", left="+a+", top="+s+", width="+n+", height="+r,i=i.replace(/^,/,"");var o=window.open(e,t,i);return o.focus(),o}function c(e){return document.getElementsByTagName(e)}function f(e){var t,n,r=c(e.tagName);if(e.useScriptTags)for(t=c("script"),n=0;n<t.length;n++)t[n].type.match(/^(text\/)?syntaxhighlighter$/)&&r.push(t[n]);return r}function g(e){return document.createElement(e)}function p(e){var t=e.target,n=l(t,".syntaxhighlighter"),r=l(t,".container"),u=document.createElement("textarea");if(r&&n&&!o(r,"textarea")){i(n,"source");for(var c=r.childNodes,f=[],g=0,p=c.length;p>g;g++)f.push(c[g].innerText||c[g].textContent);f=f.join("\r"),f=f.replace(/\u00a0/g," "),u.readOnly=!0,u.appendChild(document.createTextNode(f)),r.appendChild(u),u.focus(),u.select(),s(u,"blur",function(e){u.parentNode.removeChild(u),a(n,"source")})}}e.exports={quickCodeHandler:p,create:g,popup:u,hasClass:r,addClass:i,removeClass:a,attachEvent:s,findElement:o,findParentElement:l,getSyntaxHighlighterScriptTags:n,findElementsToHighlight:f}},function(e,t){"use strict";e.exports={space:" ",useScriptTags:!0,bloggerMode:!1,stripBrs:!1,tagName:"pre"}},function(e,t){"use strict";e.exports={"class-name":"","first-line":1,"pad-line-numbers":!1,highlight:null,title:null,"smart-tabs":!0,"tab-size":4,gutter:!0,"quick-code":!0,collapse:!1,"auto-links":!0,unindent:!0,"html-script":!1}},function(e,t,n){(function(t){"use strict";function r(e,t){function n(e,t){for(var n=0,r=e.length;r>n;n++)e[n].index+=t}function r(e,r){function s(e){u=u.concat(e)}var o,l=e.code,u=[],c=a.regexList,f=e.index+e.left.length,g=a.htmlScript;o=i(l,c),n(o,f),s(o),null!=g.left&&null!=e.left&&(o=i(e.left,[g.left]),n(o,e.index),s(o)),null!=g.right&&null!=e.right&&(o=i(e.right,[g.right]),n(o,e.index+e[0].lastIndexOf(e.right)),s(o));for(var p=0,d=u.length;d>p;p++)u[p].brushName=t.brushName;return u}var a,s=new e;if(null!=t){if(a=new t,null==a.htmlScript)throw new Error("Brush wasn't configured for html-script option: "+t.brushName);s.regexList.push({regex:a.htmlScript.code,func:r}),this.regexList=s.regexList}}var i=n(5).applyRegexList;e.exports=r}).call(t,n(21))},function(e,t){"use strict";function n(){f&&u&&(f=!1,u.length?c=u.concat(c):g=-1,c.length&&r())}function r(){if(!f){var e=s(n);f=!0;for(var t=c.length;t;){for(u=c,c=[];++g<t;)u&&u[g].run();g=-1,t=c.length}u=null,f=!1,o(e)}}function i(e,t){this.fun=e,this.array=t}function a(){}var s,o,l=e.exports={};!function(){try{s=setTimeout}catch(e){s=function(){throw new Error("setTimeout is not defined")}}try{o=clearTimeout}catch(e){o=function(){throw new Error("clearTimeout is not defined")}}}();var u,c=[],f=!1,g=-1;l.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];c.push(new i(e,t)),1!==c.length||f||s(r,0)},i.prototype.run=function(){this.fun.apply(null,this.array)},l.title="browser",l.browser=!0,l.env={},l.argv=[],l.version="",l.versions={},l.on=a,l.addListener=a,l.once=a,l.off=a,l.removeListener=a,l.removeAllListeners=a,l.emit=a,l.binding=function(e){throw new Error("process.binding is not supported")},l.cwd=function(){return"/"},l.chdir=function(e){throw new Error("process.chdir is not supported")},l.umask=function(){return 0}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var a=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),s=n(9),o=r(s),l=n(3),u=n(5);e.exports=function(){function e(){i(this,e)}return a(e,[{key:"getKeywords",value:function(e){var t=e.replace(/^\s+|\s+$/g,"").replace(/\s+/g,"|");return"\\b(?:"+t+")\\b"}},{key:"forHtmlScript",value:function(e){var t={end:e.right.source};e.eof&&(t.end="(?:(?:"+t.end+")|$)"),this.htmlScript={left:{regex:e.left,css:"script"},right:{regex:e.right,css:"script"},code:(0,l.XRegExp)("(?<left>"+e.left.source+")(?<code>.*?)(?<right>"+t.end+")","sgi")}}},{key:"getHtml",value:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],n=(0,u.applyRegexList)(e,this.regexList),r=new o["default"](e,n,t);return r.getHtml()}}]),e}()},function(e,t,n){"use strict";function r(){var e="break case catch class continue default delete do else enum export extends false for from as function if implements import in instanceof interface let new null package private protected static return super switch this throw true try typeof var while with yield";this.regexList=[{regex:a.multiLineDoubleQuotedString,css:"string"},{regex:a.multiLineSingleQuotedString,css:"string"},{regex:a.singleLineCComments,css:"comments"},{regex:a.multiLineCComments,css:"comments"},{regex:/\s*#.*/gm,css:"preprocessor"},{regex:new RegExp(this.getKeywords(e),"gm"),css:"keyword"}],this.forHtmlScript(a.scriptScriptTags)}var i=n(22),a=n(3).commonRegExp;r.prototype=new i,r.aliases=["js","jscript","javascript","json"],e.exports=r},function(e,t,n){"use strict";function r(){var e="alias and BEGIN begin break case class def define_method defined do each else elsif END end ensure false for if in module new next nil not or raise redo rescue retry return self super then throw true undef unless until when while yield",t="Array Bignum Binding Class Continuation Dir Exception FalseClass File::Stat File Fixnum Fload Hash Integer IO MatchData Method Module NilClass Numeric Object Proc Range Regexp String Struct::TMS Symbol ThreadGroup Thread Time TrueClass";this.regexList=[{regex:a.singleLinePerlComments,css:"comments"},{regex:a.doubleQuotedString,css:"string"},{regex:a.singleQuotedString,css:"string"},{regex:/\b[A-Z0-9_]+\b/g,css:"constants"},{regex:/:[a-z][A-Za-z0-9_]*/g,css:"color2"},{regex:/(\$|@@|@)\w+/g,css:"variable bold"},{regex:new RegExp(this.getKeywords(e),"gm"),css:"keyword"},{regex:new RegExp(this.getKeywords(t),"gm"),css:"color1"}],this.forHtmlScript(a.aspScriptTags)}var i=n(22),a=n(3).commonRegExp;r.prototype=new i,r.aliases=["ruby","rails","ror","rb"],e.exports=r},function(e,t,n){"use strict";function r(){function e(e,t){var n=e[0],r=s.exec(n,s("(<|<)[\\s\\/\\?!]*(?<name>[:\\w-\\.]+)","xg")),i=[];if(null!=e.attributes)for(var a,l=0,u=s("(?<name> [\\w:.-]+)\\s*=\\s*(?<value> \".*?\"|'.*?'|\\w+)","xg");null!=(a=s.exec(n,u,l));)i.push(new o(a.name,e.index+a.index,"color1")),i.push(new o(a.value,e.index+a.index+a[0].indexOf(a.value),"string")),l=a.index+a[0].length;return null!=r&&i.push(new o(r.name,e.index+r[0].indexOf(r.name),"keyword")),i}this.regexList=[{regex:s("(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)","gm"),css:"color2"},{regex:a.xmlComments,css:"comments"},{regex:s("(<|<)[\\s\\/\\?!]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(>|>)","sg"),func:e}]}var i=n(22),a=n(3).commonRegExp,s=n(3).XRegExp,o=n(5).Match;r.prototype=new i,r.aliases=["xml","xhtml","xslt","html","plist"],e.exports=r},function(e,t,n){"use strict";function r(){var e="abs avg case cast coalesce convert count current_timestamp current_user day isnull left lower month nullif replace right session_user space substring sum system_user upper user year",t="absolute action add after alter as asc at authorization begin bigint binary bit by cascade char character check checkpoint close collate column commit committed connect connection constraint contains continue create cube current current_date current_time cursor database date deallocate dec decimal declare default delete desc distinct double drop dynamic else end end-exec escape except exec execute false fetch first float for force foreign forward free from full function global goto grant group grouping having hour ignore index inner insensitive insert instead int integer intersect into is isolation key last level load local max min minute modify move name national nchar next no numeric of off on only open option order out output partial password precision prepare primary prior privileges procedure public read real references relative repeatable restrict return returns revoke rollback rollup rows rule schema scroll second section select sequence serializable set size smallint static statistics table temp temporary then time timestamp to top transaction translation trigger true truncate uncommitted union unique update values varchar varying view when where with work",n="all and any between cross in join like not null or outer some"; + this.regexList=[{regex:/--(.*)$/gm,css:"comments"},{regex:/\/\*([^\*][\s\S]*?)?\*\//gm,css:"comments"},{regex:a.multiLineDoubleQuotedString,css:"string"},{regex:a.multiLineSingleQuotedString,css:"string"},{regex:new RegExp(this.getKeywords(e),"gmi"),css:"color2"},{regex:new RegExp(this.getKeywords(n),"gmi"),css:"color1"},{regex:new RegExp(this.getKeywords(t),"gmi"),css:"keyword"}]}var i=n(22),a=n(3).commonRegExp;r.prototype=new i,r.aliases=["sql"],e.exports=r},function(e,t,n){"use strict";function r(){this.regexList=[]}var i=n(22);n(3).commonRegExp;r.prototype=new i,r.aliases=["text","plain"],e.exports=r},function(e,t,n){"use strict";"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(t,n){e.exports=n()}("domready",function(){var e,t=[],n=document,r=n.documentElement.doScroll,i="DOMContentLoaded",a=(r?/^loaded|^c/:/^loaded|^i|^c/).test(n.readyState);return a||n.addEventListener(i,e=function(){for(n.removeEventListener(i,e),a=1;e=t.shift();)e()}),function(e){a?setTimeout(e,0):t.push(e)}})},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=t.string=function(e){return e.replace(/^([A-Z])/g,function(e,t){return t.toLowerCase()}).replace(/([A-Z])/g,function(e,t){return"-"+t.toLowerCase()})};t.object=function(e){var t={};return Object.keys(e).forEach(function(r){return t[n(r)]=e[r]}),t}},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}var i=n(1),a=r(i);window.SyntaxHighlighter=a["default"],"undefined"==typeof window.XRegExp&&(window.XRegExp=n(3).XRegExp)}]); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushAS3.js b/guides/assets/javascripts/syntaxhighlighter/shBrushAS3.js deleted file mode 100644 index 8aa3ed2732..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushAS3.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Created by Peter Atoria @ http://iAtoria.com - - var inits = 'class interface function package'; - - var keywords = '-Infinity ...rest Array as AS3 Boolean break case catch const continue Date decodeURI ' + - 'decodeURIComponent default delete do dynamic each else encodeURI encodeURIComponent escape ' + - 'extends false final finally flash_proxy for get if implements import in include Infinity ' + - 'instanceof int internal is isFinite isNaN isXMLName label namespace NaN native new null ' + - 'Null Number Object object_proxy override parseFloat parseInt private protected public ' + - 'return set static String super switch this throw true try typeof uint undefined unescape ' + - 'use void while with' - ; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings - { regex: /\b([\d]+(\.[\d]+)?|0x[a-f0-9]+)\b/gi, css: 'value' }, // numbers - { regex: new RegExp(this.getKeywords(inits), 'gm'), css: 'color3' }, // initializations - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords - { regex: new RegExp('var', 'gm'), css: 'variable' }, // variable - { regex: new RegExp('trace', 'gm'), css: 'color1' } // trace - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.scriptScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['actionscript3', 'as3']; - - SyntaxHighlighter.brushes.AS3 = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushAppleScript.js b/guides/assets/javascripts/syntaxhighlighter/shBrushAppleScript.js deleted file mode 100644 index d40bbd7dd2..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushAppleScript.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // AppleScript brush by David Chambers - // http://davidchambersdesign.com/ - var keywords = 'after before beginning continue copy each end every from return get global in local named of set some that the then times to where whose with without'; - var ordinals = 'first second third fourth fifth sixth seventh eighth ninth tenth last front back middle'; - var specials = 'activate add alias AppleScript ask attachment boolean class constant delete duplicate empty exists false id integer list make message modal modified new no paragraph pi properties quit real record remove rest result reveal reverse run running save string true word yes'; - - this.regexList = [ - - { regex: /(--|#).*$/gm, - css: 'comments' }, - - { regex: /\(\*(?:[\s\S]*?\(\*[\s\S]*?\*\))*[\s\S]*?\*\)/gm, // support nested comments - css: 'comments' }, - - { regex: /"[\s\S]*?"/gm, - css: 'string' }, - - { regex: /(?:,|:|¬|'s\b|\(|\)|\{|\}|«|\b\w*»)/g, - css: 'color1' }, - - { regex: /(-)?(\d)+(\.(\d)?)?(E\+(\d)+)?/g, // numbers - css: 'color1' }, - - { regex: /(?:&(amp;|gt;|lt;)?|=|� |>|<|≥|>=|≤|<=|\*|\+|-|\/|÷|\^)/g, - css: 'color2' }, - - { regex: /\b(?:and|as|div|mod|not|or|return(?!\s&)(ing)?|equals|(is(n't| not)? )?equal( to)?|does(n't| not) equal|(is(n't| not)? )?(greater|less) than( or equal( to)?)?|(comes|does(n't| not) come) (after|before)|is(n't| not)?( in)? (back|front) of|is(n't| not)? behind|is(n't| not)?( (in|contained by))?|does(n't| not) contain|contain(s)?|(start|begin|end)(s)? with|((but|end) )?(consider|ignor)ing|prop(erty)?|(a )?ref(erence)?( to)?|repeat (until|while|with)|((end|exit) )?repeat|((else|end) )?if|else|(end )?(script|tell|try)|(on )?error|(put )?into|(of )?(it|me)|its|my|with (timeout( of)?|transaction)|end (timeout|transaction))\b/g, - css: 'keyword' }, - - { regex: /\b\d+(st|nd|rd|th)\b/g, // ordinals - css: 'keyword' }, - - { regex: /\b(?:about|above|against|around|at|below|beneath|beside|between|by|(apart|aside) from|(instead|out) of|into|on(to)?|over|since|thr(ough|u)|under)\b/g, - css: 'color3' }, - - { regex: /\b(?:adding folder items to|after receiving|choose( ((remote )?application|color|folder|from list|URL))?|clipboard info|set the clipboard to|(the )?clipboard|entire contents|display(ing| (alert|dialog|mode))?|document( (edited|file|nib name))?|file( (name|type))?|(info )?for|giving up after|(name )?extension|quoted form|return(ed)?|second(?! item)(s)?|list (disks|folder)|text item(s| delimiters)?|(Unicode )?text|(disk )?item(s)?|((current|list) )?view|((container|key) )?window|with (data|icon( (caution|note|stop))?|parameter(s)?|prompt|properties|seed|title)|case|diacriticals|hyphens|numeric strings|punctuation|white space|folder creation|application(s( folder)?| (processes|scripts position|support))?|((desktop )?(pictures )?|(documents|downloads|favorites|home|keychain|library|movies|music|public|scripts|sites|system|users|utilities|workflows) )folder|desktop|Folder Action scripts|font(s| panel)?|help|internet plugins|modem scripts|(system )?preferences|printer descriptions|scripting (additions|components)|shared (documents|libraries)|startup (disk|items)|temporary items|trash|on server|in AppleTalk zone|((as|long|short) )?user name|user (ID|locale)|(with )?password|in (bundle( with identifier)?|directory)|(close|open for) access|read|write( permission)?|(g|s)et eof|using( delimiters)?|starting at|default (answer|button|color|country code|entr(y|ies)|identifiers|items|name|location|script editor)|hidden( answer)?|open(ed| (location|untitled))?|error (handling|reporting)|(do( shell)?|load|run|store) script|administrator privileges|altering line endings|get volume settings|(alert|boot|input|mount|output|set) volume|output muted|(fax|random )?number|round(ing)?|up|down|toward zero|to nearest|as taught in school|system (attribute|info)|((AppleScript( Studio)?|system) )?version|(home )?directory|(IPv4|primary Ethernet) address|CPU (type|speed)|physical memory|time (stamp|to GMT)|replacing|ASCII (character|number)|localized string|from table|offset|summarize|beep|delay|say|(empty|multiple) selections allowed|(of|preferred) type|invisibles|showing( package contents)?|editable URL|(File|FTP|News|Media|Web) [Ss]ervers|Telnet hosts|Directory services|Remote applications|waiting until completion|saving( (in|to))?|path (for|to( (((current|frontmost) )?application|resource))?)|POSIX (file|path)|(background|RGB) color|(OK|cancel) button name|cancel button|button(s)?|cubic ((centi)?met(re|er)s|yards|feet|inches)|square ((kilo)?met(re|er)s|miles|yards|feet)|(centi|kilo)?met(re|er)s|miles|yards|feet|inches|lit(re|er)s|gallons|quarts|(kilo)?grams|ounces|pounds|degrees (Celsius|Fahrenheit|Kelvin)|print( (dialog|settings))?|clos(e(able)?|ing)|(de)?miniaturized|miniaturizable|zoom(ed|able)|attribute run|action (method|property|title)|phone|email|((start|end)ing|home) page|((birth|creation|current|custom|modification) )?date|((((phonetic )?(first|last|middle))|computer|host|maiden|related) |nick)?name|aim|icq|jabber|msn|yahoo|address(es)?|save addressbook|should enable action|city|country( code)?|formatte(r|d address)|(palette )?label|state|street|zip|AIM [Hh]andle(s)?|my card|select(ion| all)?|unsaved|(alpha )?value|entr(y|ies)|group|(ICQ|Jabber|MSN) handle|person|people|company|department|icon image|job title|note|organization|suffix|vcard|url|copies|collating|pages (across|down)|request print time|target( printer)?|((GUI Scripting|Script menu) )?enabled|show Computer scripts|(de)?activated|awake from nib|became (key|main)|call method|of (class|object)|center|clicked toolbar item|closed|for document|exposed|(can )?hide|idle|keyboard (down|up)|event( (number|type))?|launch(ed)?|load (image|movie|nib|sound)|owner|log|mouse (down|dragged|entered|exited|moved|up)|move|column|localization|resource|script|register|drag (info|types)|resigned (active|key|main)|resiz(e(d)?|able)|right mouse (down|dragged|up)|scroll wheel|(at )?index|should (close|open( untitled)?|quit( after last window closed)?|zoom)|((proposed|screen) )?bounds|show(n)?|behind|in front of|size (mode|to fit)|update(d| toolbar item)?|was (hidden|miniaturized)|will (become active|close|finish launching|hide|miniaturize|move|open|quit|(resign )?active|((maximum|minimum|proposed) )?size|show|zoom)|bundle|data source|movie|pasteboard|sound|tool(bar| tip)|(color|open|save) panel|coordinate system|frontmost|main( (bundle|menu|window))?|((services|(excluded from )?windows) )?menu|((executable|frameworks|resource|scripts|shared (frameworks|support)) )?path|(selected item )?identifier|data|content(s| view)?|character(s)?|click count|(command|control|option|shift) key down|context|delta (x|y|z)|key( code)?|location|pressure|unmodified characters|types|(first )?responder|playing|(allowed|selectable) identifiers|allows customization|(auto saves )?configuration|visible|image( name)?|menu form representation|tag|user(-| )defaults|associated file name|(auto|needs) display|current field editor|floating|has (resize indicator|shadow)|hides when deactivated|level|minimized (image|title)|opaque|position|release when closed|sheet|title(d)?)\b/g, - css: 'color3' }, - - { regex: new RegExp(this.getKeywords(specials), 'gm'), css: 'color3' }, - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, - { regex: new RegExp(this.getKeywords(ordinals), 'gm'), css: 'keyword' } - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['applescript']; - - SyntaxHighlighter.brushes.AppleScript = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushBash.js b/guides/assets/javascripts/syntaxhighlighter/shBrushBash.js deleted file mode 100644 index 8c296969ff..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushBash.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var keywords = 'if fi then elif else for do done until while break continue case function return in eq ne ge le'; - var commands = 'alias apropos awk basename bash bc bg builtin bzip2 cal cat cd cfdisk chgrp chmod chown chroot' + - 'cksum clear cmp comm command cp cron crontab csplit cut date dc dd ddrescue declare df ' + - 'diff diff3 dig dir dircolors dirname dirs du echo egrep eject enable env ethtool eval ' + - 'exec exit expand export expr false fdformat fdisk fg fgrep file find fmt fold format ' + - 'free fsck ftp gawk getopts grep groups gzip hash head history hostname id ifconfig ' + - 'import install join kill less let ln local locate logname logout look lpc lpr lprint ' + - 'lprintd lprintq lprm ls lsof make man mkdir mkfifo mkisofs mknod more mount mtools ' + - 'mv netstat nice nl nohup nslookup open op passwd paste pathchk ping popd pr printcap ' + - 'printenv printf ps pushd pwd quota quotacheck quotactl ram rcp read readonly renice ' + - 'remsync rm rmdir rsync screen scp sdiff sed select seq set sftp shift shopt shutdown ' + - 'sleep sort source split ssh strace su sudo sum symlink sync tail tar tee test time ' + - 'times touch top traceroute trap tr true tsort tty type ulimit umask umount unalias ' + - 'uname unexpand uniq units unset unshar useradd usermod users uuencode uudecode v vdir ' + - 'vi watch wc whereis which who whoami Wget xargs yes' - ; - - this.regexList = [ - { regex: /^#!.*$/gm, css: 'preprocessor bold' }, - { regex: /\/[\w-\/]+/gm, css: 'plain' }, - { regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords - { regex: new RegExp(this.getKeywords(commands), 'gm'), css: 'functions' } // commands - ]; - } - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['bash', 'shell']; - - SyntaxHighlighter.brushes.Bash = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushCSharp.js b/guides/assets/javascripts/syntaxhighlighter/shBrushCSharp.js deleted file mode 100644 index 079214efe1..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushCSharp.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var keywords = 'abstract as base bool break byte case catch char checked class const ' + - 'continue decimal default delegate do double else enum event explicit ' + - 'extern false finally fixed float for foreach get goto if implicit in int ' + - 'interface internal is lock long namespace new null object operator out ' + - 'override params private protected public readonly ref return sbyte sealed set ' + - 'short sizeof stackalloc static string struct switch this throw true try ' + - 'typeof uint ulong unchecked unsafe ushort using virtual void while'; - - function fixComments(match, regexInfo) - { - var css = (match[0].indexOf("///") == 0) - ? 'color1' - : 'comments' - ; - - return [new SyntaxHighlighter.Match(match[0], match.index, css)]; - } - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, func : fixComments }, // one line comments - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: /@"(?:[^"]|"")*"/g, css: 'string' }, // @-quoted strings - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings - { regex: /^\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // c# keyword - { regex: /\bpartial(?=\s+(?:class|interface|struct)\b)/g, css: 'keyword' }, // contextual keyword: 'partial' - { regex: /\byield(?=\s+(?:return|break)\b)/g, css: 'keyword' } // contextual keyword: 'yield' - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['c#', 'c-sharp', 'csharp']; - - SyntaxHighlighter.brushes.CSharp = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); - diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushColdFusion.js b/guides/assets/javascripts/syntaxhighlighter/shBrushColdFusion.js deleted file mode 100644 index 627dbb9b76..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushColdFusion.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by Jen - // http://www.jensbits.com/2009/05/14/coldfusion-brush-for-syntaxhighlighter-plus - - var funcs = 'Abs ACos AddSOAPRequestHeader AddSOAPResponseHeader AjaxLink AjaxOnLoad ArrayAppend ArrayAvg ArrayClear ArrayDeleteAt ' + - 'ArrayInsertAt ArrayIsDefined ArrayIsEmpty ArrayLen ArrayMax ArrayMin ArraySet ArraySort ArraySum ArraySwap ArrayToList ' + - 'Asc ASin Atn BinaryDecode BinaryEncode BitAnd BitMaskClear BitMaskRead BitMaskSet BitNot BitOr BitSHLN BitSHRN BitXor ' + - 'Ceiling CharsetDecode CharsetEncode Chr CJustify Compare CompareNoCase Cos CreateDate CreateDateTime CreateObject ' + - 'CreateODBCDate CreateODBCDateTime CreateODBCTime CreateTime CreateTimeSpan CreateUUID DateAdd DateCompare DateConvert ' + - 'DateDiff DateFormat DatePart Day DayOfWeek DayOfWeekAsString DayOfYear DaysInMonth DaysInYear DE DecimalFormat DecrementValue ' + - 'Decrypt DecryptBinary DeleteClientVariable DeserializeJSON DirectoryExists DollarFormat DotNetToCFType Duplicate Encrypt ' + - 'EncryptBinary Evaluate Exp ExpandPath FileClose FileCopy FileDelete FileExists FileIsEOF FileMove FileOpen FileRead ' + - 'FileReadBinary FileReadLine FileSetAccessMode FileSetAttribute FileSetLastModified FileWrite Find FindNoCase FindOneOf ' + - 'FirstDayOfMonth Fix FormatBaseN GenerateSecretKey GetAuthUser GetBaseTagData GetBaseTagList GetBaseTemplatePath ' + - 'GetClientVariablesList GetComponentMetaData GetContextRoot GetCurrentTemplatePath GetDirectoryFromPath GetEncoding ' + - 'GetException GetFileFromPath GetFileInfo GetFunctionList GetGatewayHelper GetHttpRequestData GetHttpTimeString ' + - 'GetK2ServerDocCount GetK2ServerDocCountLimit GetLocale GetLocaleDisplayName GetLocalHostIP GetMetaData GetMetricData ' + - 'GetPageContext GetPrinterInfo GetProfileSections GetProfileString GetReadableImageFormats GetSOAPRequest GetSOAPRequestHeader ' + - 'GetSOAPResponse GetSOAPResponseHeader GetTempDirectory GetTempFile GetTemplatePath GetTickCount GetTimeZoneInfo GetToken ' + - 'GetUserRoles GetWriteableImageFormats Hash Hour HTMLCodeFormat HTMLEditFormat IIf ImageAddBorder ImageBlur ImageClearRect ' + - 'ImageCopy ImageCrop ImageDrawArc ImageDrawBeveledRect ImageDrawCubicCurve ImageDrawLine ImageDrawLines ImageDrawOval ' + - 'ImageDrawPoint ImageDrawQuadraticCurve ImageDrawRect ImageDrawRoundRect ImageDrawText ImageFlip ImageGetBlob ImageGetBufferedImage ' + - 'ImageGetEXIFTag ImageGetHeight ImageGetIPTCTag ImageGetWidth ImageGrayscale ImageInfo ImageNegative ImageNew ImageOverlay ImagePaste ' + - 'ImageRead ImageReadBase64 ImageResize ImageRotate ImageRotateDrawingAxis ImageScaleToFit ImageSetAntialiasing ImageSetBackgroundColor ' + - 'ImageSetDrawingColor ImageSetDrawingStroke ImageSetDrawingTransparency ImageSharpen ImageShear ImageShearDrawingAxis ImageTranslate ' + - 'ImageTranslateDrawingAxis ImageWrite ImageWriteBase64 ImageXORDrawingMode IncrementValue InputBaseN Insert Int IsArray IsBinary ' + - 'IsBoolean IsCustomFunction IsDate IsDDX IsDebugMode IsDefined IsImage IsImageFile IsInstanceOf IsJSON IsLeapYear IsLocalHost ' + - 'IsNumeric IsNumericDate IsObject IsPDFFile IsPDFObject IsQuery IsSimpleValue IsSOAPRequest IsStruct IsUserInAnyRole IsUserInRole ' + - 'IsUserLoggedIn IsValid IsWDDX IsXML IsXmlAttribute IsXmlDoc IsXmlElem IsXmlNode IsXmlRoot JavaCast JSStringFormat LCase Left Len ' + - 'ListAppend ListChangeDelims ListContains ListContainsNoCase ListDeleteAt ListFind ListFindNoCase ListFirst ListGetAt ListInsertAt ' + - 'ListLast ListLen ListPrepend ListQualify ListRest ListSetAt ListSort ListToArray ListValueCount ListValueCountNoCase LJustify Log ' + - 'Log10 LSCurrencyFormat LSDateFormat LSEuroCurrencyFormat LSIsCurrency LSIsDate LSIsNumeric LSNumberFormat LSParseCurrency LSParseDateTime ' + - 'LSParseEuroCurrency LSParseNumber LSTimeFormat LTrim Max Mid Min Minute Month MonthAsString Now NumberFormat ParagraphFormat ParseDateTime ' + - 'Pi PrecisionEvaluate PreserveSingleQuotes Quarter QueryAddColumn QueryAddRow QueryConvertForGrid QueryNew QuerySetCell QuotedValueList Rand ' + - 'Randomize RandRange REFind REFindNoCase ReleaseComObject REMatch REMatchNoCase RemoveChars RepeatString Replace ReplaceList ReplaceNoCase ' + - 'REReplace REReplaceNoCase Reverse Right RJustify Round RTrim Second SendGatewayMessage SerializeJSON SetEncoding SetLocale SetProfileString ' + - 'SetVariable Sgn Sin Sleep SpanExcluding SpanIncluding Sqr StripCR StructAppend StructClear StructCopy StructCount StructDelete StructFind ' + - 'StructFindKey StructFindValue StructGet StructInsert StructIsEmpty StructKeyArray StructKeyExists StructKeyList StructKeyList StructNew ' + - 'StructSort StructUpdate Tan TimeFormat ToBase64 ToBinary ToScript ToString Trim UCase URLDecode URLEncodedFormat URLSessionFormat Val ' + - 'ValueList VerifyClient Week Wrap Wrap WriteOutput XmlChildPos XmlElemNew XmlFormat XmlGetNodeType XmlNew XmlParse XmlSearch XmlTransform ' + - 'XmlValidate Year YesNoFormat'; - - var keywords = 'cfabort cfajaximport cfajaxproxy cfapplet cfapplication cfargument cfassociate cfbreak cfcache cfcalendar ' + - 'cfcase cfcatch cfchart cfchartdata cfchartseries cfcol cfcollection cfcomponent cfcontent cfcookie cfdbinfo ' + - 'cfdefaultcase cfdirectory cfdiv cfdocument cfdocumentitem cfdocumentsection cfdump cfelse cfelseif cferror ' + - 'cfexchangecalendar cfexchangeconnection cfexchangecontact cfexchangefilter cfexchangemail cfexchangetask ' + - 'cfexecute cfexit cffeed cffile cfflush cfform cfformgroup cfformitem cfftp cffunction cfgrid cfgridcolumn ' + - 'cfgridrow cfgridupdate cfheader cfhtmlhead cfhttp cfhttpparam cfif cfimage cfimport cfinclude cfindex ' + - 'cfinput cfinsert cfinterface cfinvoke cfinvokeargument cflayout cflayoutarea cfldap cflocation cflock cflog ' + - 'cflogin cfloginuser cflogout cfloop cfmail cfmailparam cfmailpart cfmenu cfmenuitem cfmodule cfNTauthenticate ' + - 'cfobject cfobjectcache cfoutput cfparam cfpdf cfpdfform cfpdfformparam cfpdfparam cfpdfsubform cfpod cfpop ' + - 'cfpresentation cfpresentationslide cfpresenter cfprint cfprocessingdirective cfprocparam cfprocresult ' + - 'cfproperty cfquery cfqueryparam cfregistry cfreport cfreportparam cfrethrow cfreturn cfsavecontent cfschedule ' + - 'cfscript cfsearch cfselect cfset cfsetting cfsilent cfslider cfsprydataset cfstoredproc cfswitch cftable ' + - 'cftextarea cfthread cfthrow cftimer cftooltip cftrace cftransaction cftree cftreeitem cftry cfupdate cfwddx ' + - 'cfwindow cfxml cfzip cfzipparam'; - - var operators = 'all and any between cross in join like not null or outer some'; - - this.regexList = [ - { regex: new RegExp('--(.*)$', 'gm'), css: 'comments' }, // one line and multiline comments - { regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // single quoted strings - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings - { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' }, // functions - { regex: new RegExp(this.getKeywords(operators), 'gmi'), css: 'color1' }, // operators and such - { regex: new RegExp(this.getKeywords(keywords), 'gmi'), css: 'keyword' } // keyword - ]; - } - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['coldfusion','cf']; - - SyntaxHighlighter.brushes.ColdFusion = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushCpp.js b/guides/assets/javascripts/syntaxhighlighter/shBrushCpp.js deleted file mode 100644 index 9f70d3aed6..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushCpp.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Copyright 2006 Shin, YoungJin - - var datatypes = 'ATOM BOOL BOOLEAN BYTE CHAR COLORREF DWORD DWORDLONG DWORD_PTR ' + - 'DWORD32 DWORD64 FLOAT HACCEL HALF_PTR HANDLE HBITMAP HBRUSH ' + - 'HCOLORSPACE HCONV HCONVLIST HCURSOR HDC HDDEDATA HDESK HDROP HDWP ' + - 'HENHMETAFILE HFILE HFONT HGDIOBJ HGLOBAL HHOOK HICON HINSTANCE HKEY ' + - 'HKL HLOCAL HMENU HMETAFILE HMODULE HMONITOR HPALETTE HPEN HRESULT ' + - 'HRGN HRSRC HSZ HWINSTA HWND INT INT_PTR INT32 INT64 LANGID LCID LCTYPE ' + - 'LGRPID LONG LONGLONG LONG_PTR LONG32 LONG64 LPARAM LPBOOL LPBYTE LPCOLORREF ' + - 'LPCSTR LPCTSTR LPCVOID LPCWSTR LPDWORD LPHANDLE LPINT LPLONG LPSTR LPTSTR ' + - 'LPVOID LPWORD LPWSTR LRESULT PBOOL PBOOLEAN PBYTE PCHAR PCSTR PCTSTR PCWSTR ' + - 'PDWORDLONG PDWORD_PTR PDWORD32 PDWORD64 PFLOAT PHALF_PTR PHANDLE PHKEY PINT ' + - 'PINT_PTR PINT32 PINT64 PLCID PLONG PLONGLONG PLONG_PTR PLONG32 PLONG64 POINTER_32 ' + - 'POINTER_64 PSHORT PSIZE_T PSSIZE_T PSTR PTBYTE PTCHAR PTSTR PUCHAR PUHALF_PTR ' + - 'PUINT PUINT_PTR PUINT32 PUINT64 PULONG PULONGLONG PULONG_PTR PULONG32 PULONG64 ' + - 'PUSHORT PVOID PWCHAR PWORD PWSTR SC_HANDLE SC_LOCK SERVICE_STATUS_HANDLE SHORT ' + - 'SIZE_T SSIZE_T TBYTE TCHAR UCHAR UHALF_PTR UINT UINT_PTR UINT32 UINT64 ULONG ' + - 'ULONGLONG ULONG_PTR ULONG32 ULONG64 USHORT USN VOID WCHAR WORD WPARAM WPARAM WPARAM ' + - 'char bool short int __int32 __int64 __int8 __int16 long float double __wchar_t ' + - 'clock_t _complex _dev_t _diskfree_t div_t ldiv_t _exception _EXCEPTION_POINTERS ' + - 'FILE _finddata_t _finddatai64_t _wfinddata_t _wfinddatai64_t __finddata64_t ' + - '__wfinddata64_t _FPIEEE_RECORD fpos_t _HEAPINFO _HFILE lconv intptr_t ' + - 'jmp_buf mbstate_t _off_t _onexit_t _PNH ptrdiff_t _purecall_handler ' + - 'sig_atomic_t size_t _stat __stat64 _stati64 terminate_function ' + - 'time_t __time64_t _timeb __timeb64 tm uintptr_t _utimbuf ' + - 'va_list wchar_t wctrans_t wctype_t wint_t signed'; - - var keywords = 'break case catch class const __finally __exception __try ' + - 'const_cast continue private public protected __declspec ' + - 'default delete deprecated dllexport dllimport do dynamic_cast ' + - 'else enum explicit extern if for friend goto inline ' + - 'mutable naked namespace new noinline noreturn nothrow ' + - 'register reinterpret_cast return selectany ' + - 'sizeof static static_cast struct switch template this ' + - 'thread throw true false try typedef typeid typename union ' + - 'using uuid virtual void volatile whcar_t while'; - - var functions = 'assert isalnum isalpha iscntrl isdigit isgraph islower isprint' + - 'ispunct isspace isupper isxdigit tolower toupper errno localeconv ' + - 'setlocale acos asin atan atan2 ceil cos cosh exp fabs floor fmod ' + - 'frexp ldexp log log10 modf pow sin sinh sqrt tan tanh jmp_buf ' + - 'longjmp setjmp raise signal sig_atomic_t va_arg va_end va_start ' + - 'clearerr fclose feof ferror fflush fgetc fgetpos fgets fopen ' + - 'fprintf fputc fputs fread freopen fscanf fseek fsetpos ftell ' + - 'fwrite getc getchar gets perror printf putc putchar puts remove ' + - 'rename rewind scanf setbuf setvbuf sprintf sscanf tmpfile tmpnam ' + - 'ungetc vfprintf vprintf vsprintf abort abs atexit atof atoi atol ' + - 'bsearch calloc div exit free getenv labs ldiv malloc mblen mbstowcs ' + - 'mbtowc qsort rand realloc srand strtod strtol strtoul system ' + - 'wcstombs wctomb memchr memcmp memcpy memmove memset strcat strchr ' + - 'strcmp strcoll strcpy strcspn strerror strlen strncat strncmp ' + - 'strncpy strpbrk strrchr strspn strstr strtok strxfrm asctime ' + - 'clock ctime difftime gmtime localtime mktime strftime time'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings - { regex: /^ *#.*/gm, css: 'preprocessor' }, - { regex: new RegExp(this.getKeywords(datatypes), 'gm'), css: 'color1 bold' }, - { regex: new RegExp(this.getKeywords(functions), 'gm'), css: 'functions bold' }, - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword bold' } - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['cpp', 'c']; - - SyntaxHighlighter.brushes.Cpp = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushCss.js b/guides/assets/javascripts/syntaxhighlighter/shBrushCss.js deleted file mode 100644 index 4297a9a648..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushCss.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - function getKeywordsCSS(str) - { - return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b'; - }; - - function getValuesCSS(str) - { - return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b'; - }; - - var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' + - 'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' + - 'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' + - 'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' + - 'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' + - 'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' + - 'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' + - 'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' + - 'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' + - 'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' + - 'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' + - 'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' + - 'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' + - 'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index'; - - var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+ - 'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+ - 'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double '+ - 'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+ - 'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+ - 'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+ - 'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+ - 'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+ - 'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+ - 'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+ - 'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+ - 'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+ - 'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+ - 'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow'; - - var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings - { regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors - { regex: /(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)/g, css: 'value' }, // sizes - { regex: /!important/g, css: 'color3' }, // !important - { regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords - { regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values - { regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts - ]; - - this.forHtmlScript({ - left: /(<|<)\s*style.*?(>|>)/gi, - right: /(<|<)\/\s*style\s*(>|>)/gi - }); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['css']; - - SyntaxHighlighter.brushes.CSS = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushDelphi.js b/guides/assets/javascripts/syntaxhighlighter/shBrushDelphi.js deleted file mode 100644 index e1060d4468..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushDelphi.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var keywords = 'abs addr and ansichar ansistring array as asm begin boolean byte cardinal ' + - 'case char class comp const constructor currency destructor div do double ' + - 'downto else end except exports extended false file finalization finally ' + - 'for function goto if implementation in inherited int64 initialization ' + - 'integer interface is label library longint longword mod nil not object ' + - 'of on or packed pansichar pansistring pchar pcurrency pdatetime pextended ' + - 'pint64 pointer private procedure program property pshortstring pstring ' + - 'pvariant pwidechar pwidestring protected public published raise real real48 ' + - 'record repeat set shl shortint shortstring shr single smallint string then ' + - 'threadvar to true try type unit until uses val var varirnt while widechar ' + - 'widestring with word write writeln xor'; - - this.regexList = [ - { regex: /\(\*[\s\S]*?\*\)/gm, css: 'comments' }, // multiline comments (* *) - { regex: /{(?!\$)[\s\S]*?}/gm, css: 'comments' }, // multiline comments { } - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings - { regex: /\{\$[a-zA-Z]+ .+\}/g, css: 'color1' }, // compiler Directives and Region tags - { regex: /\b[\d\.]+\b/g, css: 'value' }, // numbers 12345 - { regex: /\$[a-zA-Z0-9]+\b/g, css: 'value' }, // numbers $F5D3 - { regex: new RegExp(this.getKeywords(keywords), 'gmi'), css: 'keyword' } // keyword - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['delphi', 'pascal', 'pas']; - - SyntaxHighlighter.brushes.Delphi = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushDiff.js b/guides/assets/javascripts/syntaxhighlighter/shBrushDiff.js deleted file mode 100644 index e9b14fc580..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushDiff.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - this.regexList = [ - { regex: /^\+\+\+.*$/gm, css: 'color2' }, - { regex: /^\-\-\-.*$/gm, css: 'color2' }, - { regex: /^\s.*$/gm, css: 'color1' }, - { regex: /^@@.*@@$/gm, css: 'variable' }, - { regex: /^\+[^\+]{1}.*$/gm, css: 'string' }, - { regex: /^\-[^\-]{1}.*$/gm, css: 'comments' } - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['diff', 'patch']; - - SyntaxHighlighter.brushes.Diff = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushErlang.js b/guides/assets/javascripts/syntaxhighlighter/shBrushErlang.js deleted file mode 100644 index 6ba7d9da87..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushErlang.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by Jean-Lou Dupont - // http://jldupont.blogspot.com/2009/06/erlang-syntax-highlighter.html - - // According to: http://erlang.org/doc/reference_manual/introduction.html#1.5 - var keywords = 'after and andalso band begin bnot bor bsl bsr bxor '+ - 'case catch cond div end fun if let not of or orelse '+ - 'query receive rem try when xor'+ - // additional - ' module export import define'; - - this.regexList = [ - { regex: new RegExp("[A-Z][A-Za-z0-9_]+", 'g'), css: 'constants' }, - { regex: new RegExp("\\%.+", 'gm'), css: 'comments' }, - { regex: new RegExp("\\?[A-Za-z0-9_]+", 'g'), css: 'preprocessor' }, - { regex: new RegExp("[a-z0-9_]+:[a-z0-9_]+", 'g'), css: 'functions' }, - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['erl', 'erlang']; - - SyntaxHighlighter.brushes.Erland = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushGroovy.js b/guides/assets/javascripts/syntaxhighlighter/shBrushGroovy.js deleted file mode 100644 index 6ec5c18521..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushGroovy.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by Andres Almiray - // http://jroller.com/aalmiray/entry/nice_source_code_syntax_highlighter - - var keywords = 'as assert break case catch class continue def default do else extends finally ' + - 'if in implements import instanceof interface new package property return switch ' + - 'throw throws try while public protected private static'; - var types = 'void boolean byte char short int long float double'; - var constants = 'null'; - var methods = 'allProperties count get size '+ - 'collect each eachProperty eachPropertyName eachWithIndex find findAll ' + - 'findIndexOf grep inject max min reverseEach sort ' + - 'asImmutable asSynchronized flatten intersect join pop reverse subMap toList ' + - 'padRight padLeft contains eachMatch toCharacter toLong toUrl tokenize ' + - 'eachFile eachFileRecurse eachB yte eachLine readBytes readLine getText ' + - 'splitEachLine withReader append encodeBase64 decodeBase64 filterLine ' + - 'transformChar transformLine withOutputStream withPrintWriter withStream ' + - 'withStreams withWriter withWriterAppend write writeLine '+ - 'dump inspect invokeMethod print println step times upto use waitForOrKill '+ - 'getText'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings - { regex: /""".*"""/g, css: 'string' }, // GStrings - { regex: new RegExp('\\b([\\d]+(\\.[\\d]+)?|0x[a-f0-9]+)\\b', 'gi'), css: 'value' }, // numbers - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // goovy keyword - { regex: new RegExp(this.getKeywords(types), 'gm'), css: 'color1' }, // goovy/java type - { regex: new RegExp(this.getKeywords(constants), 'gm'), css: 'constants' }, // constants - { regex: new RegExp(this.getKeywords(methods), 'gm'), css: 'functions' } // methods - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags); - } - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['groovy']; - - SyntaxHighlighter.brushes.Groovy = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushJScript.js b/guides/assets/javascripts/syntaxhighlighter/shBrushJScript.js deleted file mode 100644 index ff98daba16..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushJScript.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var keywords = 'break case catch continue ' + - 'default delete do else false ' + - 'for function if in instanceof ' + - 'new null return super switch ' + - 'this throw true try typeof var while with' - ; - - var r = SyntaxHighlighter.regexLib; - - this.regexList = [ - { regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings - { regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings - { regex: r.singleLineCComments, css: 'comments' }, // one line comments - { regex: r.multiLineCComments, css: 'comments' }, // multiline comments - { regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords - ]; - - this.forHtmlScript(r.scriptScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['js', 'jscript', 'javascript']; - - SyntaxHighlighter.brushes.JScript = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushJava.js b/guides/assets/javascripts/syntaxhighlighter/shBrushJava.js deleted file mode 100644 index d692fd6382..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushJava.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var keywords = 'abstract assert boolean break byte case catch char class const ' + - 'continue default do double else enum extends ' + - 'false final finally float for goto if implements import ' + - 'instanceof int interface long native new null ' + - 'package private protected public return ' + - 'short static strictfp super switch synchronized this throw throws true ' + - 'transient try void volatile while'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments - { regex: /\/\*([^\*][\s\S]*)?\*\//gm, css: 'comments' }, // multiline comments - { regex: /\/\*(?!\*\/)\*[\s\S]*?\*\//gm, css: 'preprocessor' }, // documentation comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings - { regex: /\b([\d]+(\.[\d]+)?|0x[a-f0-9]+)\b/gi, css: 'value' }, // numbers - { regex: /(?!\@interface\b)\@[\$\w]+\b/g, css: 'color1' }, // annotation @anno - { regex: /\@interface\b/g, css: 'color2' }, // @interface keyword - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // java keyword - ]; - - this.forHtmlScript({ - left : /(<|<)%[@!=]?/g, - right : /%(>|>)/g - }); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['java']; - - SyntaxHighlighter.brushes.Java = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushJavaFX.js b/guides/assets/javascripts/syntaxhighlighter/shBrushJavaFX.js deleted file mode 100644 index 1a150a6ad3..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushJavaFX.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by Patrick Webster - // http://patrickwebster.blogspot.com/2009/04/javafx-brush-for-syntaxhighlighter.html - var datatypes = 'Boolean Byte Character Double Duration ' - + 'Float Integer Long Number Short String Void' - ; - - var keywords = 'abstract after and as assert at before bind bound break catch class ' - + 'continue def delete else exclusive extends false finally first for from ' - + 'function if import in indexof init insert instanceof into inverse last ' - + 'lazy mixin mod nativearray new not null on or override package postinit ' - + 'protected public public-init public-read replace return reverse sizeof ' - + 'step super then this throw true try tween typeof var where while with ' - + 'attribute let private readonly static trigger' - ; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, - { regex: /(-?\.?)(\b(\d*\.?\d+|\d+\.?\d*)(e[+-]?\d+)?|0x[a-f\d]+)\b\.?/gi, css: 'color2' }, // numbers - { regex: new RegExp(this.getKeywords(datatypes), 'gm'), css: 'variable' }, // datatypes - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } - ]; - this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['jfx', 'javafx']; - - SyntaxHighlighter.brushes.JavaFX = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushPerl.js b/guides/assets/javascripts/syntaxhighlighter/shBrushPerl.js deleted file mode 100644 index d94a2e0ec5..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushPerl.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by David Simmons-Duffin and Marty Kube - - var funcs = - 'abs accept alarm atan2 bind binmode chdir chmod chomp chop chown chr ' + - 'chroot close closedir connect cos crypt defined delete each endgrent ' + - 'endhostent endnetent endprotoent endpwent endservent eof exec exists ' + - 'exp fcntl fileno flock fork format formline getc getgrent getgrgid ' + - 'getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr ' + - 'getnetbyname getnetent getpeername getpgrp getppid getpriority ' + - 'getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid ' + - 'getservbyname getservbyport getservent getsockname getsockopt glob ' + - 'gmtime grep hex index int ioctl join keys kill lc lcfirst length link ' + - 'listen localtime lock log lstat map mkdir msgctl msgget msgrcv msgsnd ' + - 'oct open opendir ord pack pipe pop pos print printf prototype push ' + - 'quotemeta rand read readdir readline readlink readpipe recv rename ' + - 'reset reverse rewinddir rindex rmdir scalar seek seekdir select semctl ' + - 'semget semop send setgrent sethostent setnetent setpgrp setpriority ' + - 'setprotoent setpwent setservent setsockopt shift shmctl shmget shmread ' + - 'shmwrite shutdown sin sleep socket socketpair sort splice split sprintf ' + - 'sqrt srand stat study substr symlink syscall sysopen sysread sysseek ' + - 'system syswrite tell telldir time times tr truncate uc ucfirst umask ' + - 'undef unlink unpack unshift utime values vec wait waitpid warn write'; - - var keywords = - 'bless caller continue dbmclose dbmopen die do dump else elsif eval exit ' + - 'for foreach goto if import last local my next no our package redo ref ' + - 'require return sub tie tied unless untie until use wantarray while'; - - this.regexList = [ - { regex: new RegExp('#[^!].*$', 'gm'), css: 'comments' }, - { regex: new RegExp('^\\s*#!.*$', 'gm'), css: 'preprocessor' }, // shebang - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, - { regex: new RegExp('(\\$|@|%)\\w+', 'g'), css: 'variable' }, - { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' }, - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.phpScriptTags); - } - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['perl', 'Perl', 'pl']; - - SyntaxHighlighter.brushes.Perl = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushPhp.js b/guides/assets/javascripts/syntaxhighlighter/shBrushPhp.js deleted file mode 100644 index 95e6e4325b..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushPhp.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var funcs = 'abs acos acosh addcslashes addslashes ' + - 'array_change_key_case array_chunk array_combine array_count_values array_diff '+ - 'array_diff_assoc array_diff_key array_diff_uassoc array_diff_ukey array_fill '+ - 'array_filter array_flip array_intersect array_intersect_assoc array_intersect_key '+ - 'array_intersect_uassoc array_intersect_ukey array_key_exists array_keys array_map '+ - 'array_merge array_merge_recursive array_multisort array_pad array_pop array_product '+ - 'array_push array_rand array_reduce array_reverse array_search array_shift '+ - 'array_slice array_splice array_sum array_udiff array_udiff_assoc '+ - 'array_udiff_uassoc array_uintersect array_uintersect_assoc '+ - 'array_uintersect_uassoc array_unique array_unshift array_values array_walk '+ - 'array_walk_recursive atan atan2 atanh base64_decode base64_encode base_convert '+ - 'basename bcadd bccomp bcdiv bcmod bcmul bindec bindtextdomain bzclose bzcompress '+ - 'bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite ceil chdir '+ - 'checkdate checkdnsrr chgrp chmod chop chown chr chroot chunk_split class_exists '+ - 'closedir closelog copy cos cosh count count_chars date decbin dechex decoct '+ - 'deg2rad delete ebcdic2ascii echo empty end ereg ereg_replace eregi eregi_replace error_log '+ - 'error_reporting escapeshellarg escapeshellcmd eval exec exit exp explode extension_loaded '+ - 'feof fflush fgetc fgetcsv fgets fgetss file_exists file_get_contents file_put_contents '+ - 'fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype '+ - 'floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv fputs fread fscanf '+ - 'fseek fsockopen fstat ftell ftok getallheaders getcwd getdate getenv gethostbyaddr gethostbyname '+ - 'gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid getmyuid getopt '+ - 'getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext '+ - 'gettimeofday gettype glob gmdate gmmktime ini_alter ini_get ini_get_all ini_restore ini_set '+ - 'interface_exists intval ip2long is_a is_array is_bool is_callable is_dir is_double '+ - 'is_executable is_file is_finite is_float is_infinite is_int is_integer is_link is_long '+ - 'is_nan is_null is_numeric is_object is_readable is_real is_resource is_scalar is_soap_fault '+ - 'is_string is_subclass_of is_uploaded_file is_writable is_writeable mkdir mktime nl2br '+ - 'parse_ini_file parse_str parse_url passthru pathinfo print readlink realpath rewind rewinddir rmdir '+ - 'round str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split '+ - 'str_word_count strcasecmp strchr strcmp strcoll strcspn strftime strip_tags stripcslashes '+ - 'stripos stripslashes stristr strlen strnatcasecmp strnatcmp strncasecmp strncmp strpbrk '+ - 'strpos strptime strrchr strrev strripos strrpos strspn strstr strtok strtolower strtotime '+ - 'strtoupper strtr strval substr substr_compare'; - - var keywords = 'abstract and array as break case catch cfunction class clone const continue declare default die do ' + - 'else elseif enddeclare endfor endforeach endif endswitch endwhile extends final for foreach ' + - 'function include include_once global goto if implements interface instanceof namespace new ' + - 'old_function or private protected public return require require_once static switch ' + - 'throw try use var while xor '; - - var constants = '__FILE__ __LINE__ __METHOD__ __FUNCTION__ __CLASS__'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings - { regex: /\$\w+/g, css: 'variable' }, // variables - { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' }, // common functions - { regex: new RegExp(this.getKeywords(constants), 'gmi'), css: 'constants' }, // constants - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keyword - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.phpScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['php']; - - SyntaxHighlighter.brushes.Php = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushPlain.js b/guides/assets/javascripts/syntaxhighlighter/shBrushPlain.js deleted file mode 100644 index 9f7d9e90c3..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushPlain.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['text', 'plain']; - - SyntaxHighlighter.brushes.Plain = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushPowerShell.js b/guides/assets/javascripts/syntaxhighlighter/shBrushPowerShell.js deleted file mode 100644 index 0be1752968..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushPowerShell.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributes by B.v.Zanten, Getronics - // http://confluence.atlassian.com/display/CONFEXT/New+Code+Macro - - var keywords = 'Add-Content Add-History Add-Member Add-PSSnapin Clear(-Content)? Clear-Item ' + - 'Clear-ItemProperty Clear-Variable Compare-Object ConvertFrom-SecureString Convert-Path ' + - 'ConvertTo-Html ConvertTo-SecureString Copy(-Item)? Copy-ItemProperty Export-Alias ' + - 'Export-Clixml Export-Console Export-Csv ForEach(-Object)? Format-Custom Format-List ' + - 'Format-Table Format-Wide Get-Acl Get-Alias Get-AuthenticodeSignature Get-ChildItem Get-Command ' + - 'Get-Content Get-Credential Get-Culture Get-Date Get-EventLog Get-ExecutionPolicy ' + - 'Get-Help Get-History Get-Host Get-Item Get-ItemProperty Get-Location Get-Member ' + - 'Get-PfxCertificate Get-Process Get-PSDrive Get-PSProvider Get-PSSnapin Get-Service ' + - 'Get-TraceSource Get-UICulture Get-Unique Get-Variable Get-WmiObject Group-Object ' + - 'Import-Alias Import-Clixml Import-Csv Invoke-Expression Invoke-History Invoke-Item ' + - 'Join-Path Measure-Command Measure-Object Move(-Item)? Move-ItemProperty New-Alias ' + - 'New-Item New-ItemProperty New-Object New-PSDrive New-Service New-TimeSpan ' + - 'New-Variable Out-Default Out-File Out-Host Out-Null Out-Printer Out-String Pop-Location ' + - 'Push-Location Read-Host Remove-Item Remove-ItemProperty Remove-PSDrive Remove-PSSnapin ' + - 'Remove-Variable Rename-Item Rename-ItemProperty Resolve-Path Restart-Service Resume-Service ' + - 'Select-Object Select-String Set-Acl Set-Alias Set-AuthenticodeSignature Set-Content ' + - 'Set-Date Set-ExecutionPolicy Set-Item Set-ItemProperty Set-Location Set-PSDebug ' + - 'Set-Service Set-TraceSource Set(-Variable)? Sort-Object Split-Path Start-Service ' + - 'Start-Sleep Start-Transcript Stop-Process Stop-Service Stop-Transcript Suspend-Service ' + - 'Tee-Object Test-Path Trace-Command Update-FormatData Update-TypeData Where(-Object)? ' + - 'Write-Debug Write-Error Write(-Host)? Write-Output Write-Progress Write-Verbose Write-Warning'; - var alias = 'ac asnp clc cli clp clv cpi cpp cvpa diff epal epcsv fc fl ' + - 'ft fw gal gc gci gcm gdr ghy gi gl gm gp gps group gsv ' + - 'gsnp gu gv gwmi iex ihy ii ipal ipcsv mi mp nal ndr ni nv oh rdr ' + - 'ri rni rnp rp rsnp rv rvpa sal sasv sc select si sl sleep sort sp ' + - 'spps spsv sv tee cat cd cp h history kill lp ls ' + - 'mount mv popd ps pushd pwd r rm rmdir echo cls chdir del dir ' + - 'erase rd ren type % \\?'; - - this.regexList = [ - { regex: /#.*$/gm, css: 'comments' }, // one line comments - { regex: /\$[a-zA-Z0-9]+\b/g, css: 'value' }, // variables $Computer1 - { regex: /\-[a-zA-Z]+\b/g, css: 'keyword' }, // Operators -not -and -eq - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings - { regex: new RegExp(this.getKeywords(keywords), 'gmi'), css: 'keyword' }, - { regex: new RegExp(this.getKeywords(alias), 'gmi'), css: 'keyword' } - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['powershell', 'ps']; - - SyntaxHighlighter.brushes.PowerShell = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushPython.js b/guides/assets/javascripts/syntaxhighlighter/shBrushPython.js deleted file mode 100644 index ce77462975..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushPython.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by Gheorghe Milas and Ahmad Sherif - - var keywords = 'and assert break class continue def del elif else ' + - 'except exec finally for from global if import in is ' + - 'lambda not or pass print raise return try yield while'; - - var funcs = '__import__ abs all any apply basestring bin bool buffer callable ' + - 'chr classmethod cmp coerce compile complex delattr dict dir ' + - 'divmod enumerate eval execfile file filter float format frozenset ' + - 'getattr globals hasattr hash help hex id input int intern ' + - 'isinstance issubclass iter len list locals long map max min next ' + - 'object oct open ord pow print property range raw_input reduce ' + - 'reload repr reversed round set setattr slice sorted staticmethod ' + - 'str sum super tuple type type unichr unicode vars xrange zip'; - - var special = 'None True False self cls class_'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' }, - { regex: /^\s*@\w+/gm, css: 'decorator' }, - { regex: /(['\"]{3})([^\1])*?\1/gm, css: 'comments' }, - { regex: /"(?!")(?:\.|\\\"|[^\""\n])*"/gm, css: 'string' }, - { regex: /'(?!')(?:\.|(\\\')|[^\''\n])*'/gm, css: 'string' }, - { regex: /\+|\-|\*|\/|\%|=|==/gm, css: 'keyword' }, - { regex: /\b\d+\.?\w*/g, css: 'value' }, - { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' }, - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, - { regex: new RegExp(this.getKeywords(special), 'gm'), css: 'color1' } - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['py', 'python']; - - SyntaxHighlighter.brushes.Python = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushRuby.js b/guides/assets/javascripts/syntaxhighlighter/shBrushRuby.js deleted file mode 100644 index ff82130a7a..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushRuby.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by Erik Peterson. - - var keywords = 'alias and BEGIN begin break case class def define_method defined do each else elsif ' + - 'END end ensure false for if in module new next nil not or raise redo rescue retry return ' + - 'self super then throw true undef unless until when while yield'; - - var builtins = 'Array Bignum Binding Class Continuation Dir Exception FalseClass File::Stat File Fixnum Fload ' + - 'Hash Integer IO MatchData Method Module NilClass Numeric Object Proc Range Regexp String Struct::TMS Symbol ' + - 'ThreadGroup Thread Time TrueClass'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings - { regex: /\b[A-Z0-9_]+\b/g, css: 'constants' }, // constants - { regex: /:[a-z][A-Za-z0-9_]*/g, css: 'color2' }, // symbols - { regex: /(\$|@@|@)\w+/g, css: 'variable bold' }, // $global, @instance, and @@class variables - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords - { regex: new RegExp(this.getKeywords(builtins), 'gm'), css: 'color1' } // builtins - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['ruby', 'rails', 'ror', 'rb']; - - SyntaxHighlighter.brushes.Ruby = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushSass.js b/guides/assets/javascripts/syntaxhighlighter/shBrushSass.js deleted file mode 100644 index aa04da0996..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushSass.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - function getKeywordsCSS(str) - { - return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b'; - }; - - function getValuesCSS(str) - { - return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b'; - }; - - var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' + - 'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' + - 'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' + - 'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' + - 'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' + - 'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' + - 'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' + - 'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' + - 'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' + - 'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' + - 'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' + - 'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' + - 'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' + - 'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index'; - - var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+ - 'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+ - 'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero digits disc dotted double '+ - 'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+ - 'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+ - 'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+ - 'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+ - 'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+ - 'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+ - 'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+ - 'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+ - 'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+ - 'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+ - 'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow'; - - var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif'; - - var statements = '!important !default'; - var preprocessor = '@import @extend @debug @warn @if @for @while @mixin @include'; - - var r = SyntaxHighlighter.regexLib; - - this.regexList = [ - { regex: r.multiLineCComments, css: 'comments' }, // multiline comments - { regex: r.singleLineCComments, css: 'comments' }, // singleline comments - { regex: r.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: r.singleQuotedString, css: 'string' }, // single quoted strings - { regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors - { regex: /\b(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)\b/g, css: 'value' }, // sizes - { regex: /\$\w+/g, css: 'variable' }, // variables - { regex: new RegExp(this.getKeywords(statements), 'g'), css: 'color3' }, // statements - { regex: new RegExp(this.getKeywords(preprocessor), 'g'), css: 'preprocessor' }, // preprocessor - { regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords - { regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values - { regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['sass', 'scss']; - - SyntaxHighlighter.brushes.Sass = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushScala.js b/guides/assets/javascripts/syntaxhighlighter/shBrushScala.js deleted file mode 100644 index 4b0b6f04d2..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushScala.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - // Contributed by Yegor Jbanov and David Bernard. - - var keywords = 'val sealed case def true trait implicit forSome import match object null finally super ' + - 'override try lazy for var catch throw type extends class while with new final yield abstract ' + - 'else do if return protected private this package false'; - - var keyops = '[_:=><%#@]+'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: SyntaxHighlighter.regexLib.multiLineSingleQuotedString, css: 'string' }, // multi-line strings - { regex: SyntaxHighlighter.regexLib.multiLineDoubleQuotedString, css: 'string' }, // double-quoted string - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings - { regex: /0x[a-f0-9]+|\d+(\.\d+)?/gi, css: 'value' }, // numbers - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords - { regex: new RegExp(keyops, 'gm'), css: 'keyword' } // scala keyword - ]; - } - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['scala']; - - SyntaxHighlighter.brushes.Scala = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushSql.js b/guides/assets/javascripts/syntaxhighlighter/shBrushSql.js deleted file mode 100644 index 5c2cd8806f..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushSql.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var funcs = 'abs avg case cast coalesce convert count current_timestamp ' + - 'current_user day isnull left lower month nullif replace right ' + - 'session_user space substring sum system_user upper user year'; - - var keywords = 'absolute action add after alter as asc at authorization begin bigint ' + - 'binary bit by cascade char character check checkpoint close collate ' + - 'column commit committed connect connection constraint contains continue ' + - 'create cube current current_date current_time cursor database date ' + - 'deallocate dec decimal declare default delete desc distinct double drop ' + - 'dynamic else end end-exec escape except exec execute false fetch first ' + - 'float for force foreign forward free from full function global goto grant ' + - 'group grouping having hour ignore index inner insensitive insert instead ' + - 'int integer intersect into is isolation key last level load local max min ' + - 'minute modify move name national nchar next no numeric of off on only ' + - 'open option order out output partial password precision prepare primary ' + - 'prior privileges procedure public read real references relative repeatable ' + - 'restrict return returns revoke rollback rollup rows rule schema scroll ' + - 'second section select sequence serializable set size smallint static ' + - 'statistics table temp temporary then time timestamp to top transaction ' + - 'translation trigger true truncate uncommitted union unique update values ' + - 'varchar varying view when where with work'; - - var operators = 'all and any between cross in join like not null or outer some'; - - this.regexList = [ - { regex: /--(.*)$/gm, css: 'comments' }, // one line and multiline comments - { regex: SyntaxHighlighter.regexLib.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.multiLineSingleQuotedString, css: 'string' }, // single quoted strings - { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'color2' }, // functions - { regex: new RegExp(this.getKeywords(operators), 'gmi'), css: 'color1' }, // operators and such - { regex: new RegExp(this.getKeywords(keywords), 'gmi'), css: 'keyword' } // keyword - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['sql']; - - SyntaxHighlighter.brushes.Sql = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); - diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushVb.js b/guides/assets/javascripts/syntaxhighlighter/shBrushVb.js deleted file mode 100644 index be845dc0b3..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushVb.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - var keywords = 'AddHandler AddressOf AndAlso Alias And Ansi As Assembly Auto ' + - 'Boolean ByRef Byte ByVal Call Case Catch CBool CByte CChar CDate ' + - 'CDec CDbl Char CInt Class CLng CObj Const CShort CSng CStr CType ' + - 'Date Decimal Declare Default Delegate Dim DirectCast Do Double Each ' + - 'Else ElseIf End Enum Erase Error Event Exit False Finally For Friend ' + - 'Function Get GetType GoSub GoTo Handles If Implements Imports In ' + - 'Inherits Integer Interface Is Let Lib Like Long Loop Me Mod Module ' + - 'MustInherit MustOverride MyBase MyClass Namespace New Next Not Nothing ' + - 'NotInheritable NotOverridable Object On Option Optional Or OrElse ' + - 'Overloads Overridable Overrides ParamArray Preserve Private Property ' + - 'Protected Public RaiseEvent ReadOnly ReDim REM RemoveHandler Resume ' + - 'Return Select Set Shadows Shared Short Single Static Step Stop String ' + - 'Structure Sub SyncLock Then Throw To True Try TypeOf Unicode Until ' + - 'Variant When While With WithEvents WriteOnly Xor'; - - this.regexList = [ - { regex: /'.*$/gm, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings - { regex: /^\s*#.*$/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // vb keyword - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags); - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['vb', 'vbnet']; - - SyntaxHighlighter.brushes.Vb = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shBrushXml.js b/guides/assets/javascripts/syntaxhighlighter/shBrushXml.js deleted file mode 100644 index 69d9fd0b1f..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shBrushXml.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -;(function() -{ - // CommonJS - typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; - - function Brush() - { - function process(match, regexInfo) - { - var constructor = SyntaxHighlighter.Match, - code = match[0], - tag = new XRegExp('(<|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code), - result = [] - ; - - if (match.attributes != null) - { - var attributes, - regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' + - '\\s*=\\s*' + - '(?<value> ".*?"|\'.*?\'|\\w+)', - 'xg'); - - while ((attributes = regex.exec(code)) != null) - { - result.push(new constructor(attributes.name, match.index + attributes.index, 'color1')); - result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string')); - } - } - - if (tag != null) - result.push( - new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword') - ); - - return result; - } - - this.regexList = [ - { regex: new XRegExp('(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)', 'gm'), css: 'color2' }, // <![ ... [ ... ]]> - { regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // <!-- ... --> - { regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process } - ]; - }; - - Brush.prototype = new SyntaxHighlighter.Highlighter(); - Brush.aliases = ['xml', 'xhtml', 'xslt', 'html']; - - SyntaxHighlighter.brushes.Xml = Brush; - - // CommonJS - typeof(exports) != 'undefined' ? exports.Brush = Brush : null; -})(); diff --git a/guides/assets/javascripts/syntaxhighlighter/shCore.js b/guides/assets/javascripts/syntaxhighlighter/shCore.js deleted file mode 100644 index b47b645472..0000000000 --- a/guides/assets/javascripts/syntaxhighlighter/shCore.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('K M;I(M)1S 2U("2a\'t 4k M 4K 2g 3l 4G 4H");(6(){6 r(f,e){I(!M.1R(f))1S 3m("3s 15 4R");K a=f.1w;f=M(f.1m,t(f)+(e||""));I(a)f.1w={1m:a.1m,19:a.19?a.19.1a(0):N};H f}6 t(f){H(f.1J?"g":"")+(f.4s?"i":"")+(f.4p?"m":"")+(f.4v?"x":"")+(f.3n?"y":"")}6 B(f,e,a,b){K c=u.L,d,h,g;v=R;5K{O(;c--;){g=u[c];I(a&g.3r&&(!g.2p||g.2p.W(b))){g.2q.12=e;I((h=g.2q.X(f))&&h.P===e){d={3k:g.2b.W(b,h,a),1C:h};1N}}}}5v(i){1S i}5q{v=11}H d}6 p(f,e,a){I(3b.Z.1i)H f.1i(e,a);O(a=a||0;a<f.L;a++)I(f[a]===e)H a;H-1}M=6(f,e){K a=[],b=M.1B,c=0,d,h;I(M.1R(f)){I(e!==1d)1S 3m("2a\'t 5r 5I 5F 5B 5C 15 5E 5p");H r(f)}I(v)1S 2U("2a\'t W 3l M 59 5m 5g 5x 5i");e=e||"";O(d={2N:11,19:[],2K:6(g){H e.1i(g)>-1},3d:6(g){e+=g}};c<f.L;)I(h=B(f,c,b,d)){a.U(h.3k);c+=h.1C[0].L||1}Y I(h=n.X.W(z[b],f.1a(c))){a.U(h[0]);c+=h[0].L}Y{h=f.3a(c);I(h==="[")b=M.2I;Y I(h==="]")b=M.1B;a.U(h);c++}a=15(a.1K(""),n.Q.W(e,w,""));a.1w={1m:f,19:d.2N?d.19:N};H a};M.3v="1.5.0";M.2I=1;M.1B=2;K C=/\\$(?:(\\d\\d?|[$&`\'])|{([$\\w]+)})/g,w=/[^5h]+|([\\s\\S])(?=[\\s\\S]*\\1)/g,A=/^(?:[?*+]|{\\d+(?:,\\d*)?})\\??/,v=11,u=[],n={X:15.Z.X,1A:15.Z.1A,1C:1r.Z.1C,Q:1r.Z.Q,1e:1r.Z.1e},x=n.X.W(/()??/,"")[1]===1d,D=6(){K f=/^/g;n.1A.W(f,"");H!f.12}(),y=6(){K f=/x/g;n.Q.W("x",f,"");H!f.12}(),E=15.Z.3n!==1d,z={};z[M.2I]=/^(?:\\\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\\29-26-f]{2}|u[\\29-26-f]{4}|c[A-3o-z]|[\\s\\S]))/;z[M.1B]=/^(?:\\\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\\d*|x[\\29-26-f]{2}|u[\\29-26-f]{4}|c[A-3o-z]|[\\s\\S])|\\(\\?[:=!]|[?*+]\\?|{\\d+(?:,\\d*)?}\\??)/;M.1h=6(f,e,a,b){u.U({2q:r(f,"g"+(E?"y":"")),2b:e,3r:a||M.1B,2p:b||N})};M.2n=6(f,e){K a=f+"/"+(e||"");H M.2n[a]||(M.2n[a]=M(f,e))};M.3c=6(f){H r(f,"g")};M.5l=6(f){H f.Q(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g,"\\\\$&")};M.5e=6(f,e,a,b){e=r(e,"g"+(b&&E?"y":""));e.12=a=a||0;f=e.X(f);H b?f&&f.P===a?f:N:f};M.3q=6(){M.1h=6(){1S 2U("2a\'t 55 1h 54 3q")}};M.1R=6(f){H 53.Z.1q.W(f)==="[2m 15]"};M.3p=6(f,e,a,b){O(K c=r(e,"g"),d=-1,h;h=c.X(f);){a.W(b,h,++d,f,c);c.12===h.P&&c.12++}I(e.1J)e.12=0};M.57=6(f,e){H 6 a(b,c){K d=e[c].1I?e[c]:{1I:e[c]},h=r(d.1I,"g"),g=[],i;O(i=0;i<b.L;i++)M.3p(b[i],h,6(k){g.U(d.3j?k[d.3j]||"":k[0])});H c===e.L-1||!g.L?g:a(g,c+1)}([f],0)};15.Z.1p=6(f,e){H J.X(e[0])};15.Z.W=6(f,e){H J.X(e)};15.Z.X=6(f){K e=n.X.1p(J,14),a;I(e){I(!x&&e.L>1&&p(e,"")>-1){a=15(J.1m,n.Q.W(t(J),"g",""));n.Q.W(f.1a(e.P),a,6(){O(K c=1;c<14.L-2;c++)I(14[c]===1d)e[c]=1d})}I(J.1w&&J.1w.19)O(K b=1;b<e.L;b++)I(a=J.1w.19[b-1])e[a]=e[b];!D&&J.1J&&!e[0].L&&J.12>e.P&&J.12--}H e};I(!D)15.Z.1A=6(f){(f=n.X.W(J,f))&&J.1J&&!f[0].L&&J.12>f.P&&J.12--;H!!f};1r.Z.1C=6(f){M.1R(f)||(f=15(f));I(f.1J){K e=n.1C.1p(J,14);f.12=0;H e}H f.X(J)};1r.Z.Q=6(f,e){K a=M.1R(f),b,c;I(a&&1j e.58()==="3f"&&e.1i("${")===-1&&y)H n.Q.1p(J,14);I(a){I(f.1w)b=f.1w.19}Y f+="";I(1j e==="6")c=n.Q.W(J,f,6(){I(b){14[0]=1f 1r(14[0]);O(K d=0;d<b.L;d++)I(b[d])14[0][b[d]]=14[d+1]}I(a&&f.1J)f.12=14[14.L-2]+14[0].L;H e.1p(N,14)});Y{c=J+"";c=n.Q.W(c,f,6(){K d=14;H n.Q.W(e,C,6(h,g,i){I(g)5b(g){24"$":H"$";24"&":H d[0];24"`":H d[d.L-1].1a(0,d[d.L-2]);24"\'":H d[d.L-1].1a(d[d.L-2]+d[0].L);5a:i="";g=+g;I(!g)H h;O(;g>d.L-3;){i=1r.Z.1a.W(g,-1)+i;g=1Q.3i(g/10)}H(g?d[g]||"":"$")+i}Y{g=+i;I(g<=d.L-3)H d[g];g=b?p(b,i):-1;H g>-1?d[g+1]:h}})})}I(a&&f.1J)f.12=0;H c};1r.Z.1e=6(f,e){I(!M.1R(f))H n.1e.1p(J,14);K a=J+"",b=[],c=0,d,h;I(e===1d||+e<0)e=5D;Y{e=1Q.3i(+e);I(!e)H[]}O(f=M.3c(f);d=f.X(a);){I(f.12>c){b.U(a.1a(c,d.P));d.L>1&&d.P<a.L&&3b.Z.U.1p(b,d.1a(1));h=d[0].L;c=f.12;I(b.L>=e)1N}f.12===d.P&&f.12++}I(c===a.L){I(!n.1A.W(f,"")||h)b.U("")}Y b.U(a.1a(c));H b.L>e?b.1a(0,e):b};M.1h(/\\(\\?#[^)]*\\)/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"});M.1h(/\\((?!\\?)/,6(){J.19.U(N);H"("});M.1h(/\\(\\?<([$\\w]+)>/,6(f){J.19.U(f[1]);J.2N=R;H"("});M.1h(/\\\\k<([\\w$]+)>/,6(f){K e=p(J.19,f[1]);H e>-1?"\\\\"+(e+1)+(3R(f.2S.3a(f.P+f[0].L))?"":"(?:)"):f[0]});M.1h(/\\[\\^?]/,6(f){H f[0]==="[]"?"\\\\b\\\\B":"[\\\\s\\\\S]"});M.1h(/^\\(\\?([5A]+)\\)/,6(f){J.3d(f[1]);H""});M.1h(/(?:\\s+|#.*)+/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"},M.1B,6(){H J.2K("x")});M.1h(/\\./,6(){H"[\\\\s\\\\S]"},M.1B,6(){H J.2K("s")})})();1j 2e!="1d"&&(2e.M=M);K 1v=6(){6 r(a,b){a.1l.1i(b)!=-1||(a.1l+=" "+b)}6 t(a){H a.1i("3e")==0?a:"3e"+a}6 B(a){H e.1Y.2A[t(a)]}6 p(a,b,c){I(a==N)H N;K d=c!=R?a.3G:[a.2G],h={"#":"1c",".":"1l"}[b.1o(0,1)]||"3h",g,i;g=h!="3h"?b.1o(1):b.5u();I((a[h]||"").1i(g)!=-1)H a;O(a=0;d&&a<d.L&&i==N;a++)i=p(d[a],b,c);H i}6 C(a,b){K c={},d;O(d 2g a)c[d]=a[d];O(d 2g b)c[d]=b[d];H c}6 w(a,b,c,d){6 h(g){g=g||1P.5y;I(!g.1F){g.1F=g.52;g.3N=6(){J.5w=11}}c.W(d||1P,g)}a.3g?a.3g("4U"+b,h):a.4y(b,h,11)}6 A(a,b){K c=e.1Y.2j,d=N;I(c==N){c={};O(K h 2g e.1U){K g=e.1U[h];d=g.4x;I(d!=N){g.1V=h.4w();O(g=0;g<d.L;g++)c[d[g]]=h}}e.1Y.2j=c}d=e.1U[c[a]];d==N&&b!=11&&1P.1X(e.13.1x.1X+(e.13.1x.3E+a));H d}6 v(a,b){O(K c=a.1e("\\n"),d=0;d<c.L;d++)c[d]=b(c[d],d);H c.1K("\\n")}6 u(a,b){I(a==N||a.L==0||a=="\\n")H a;a=a.Q(/</g,"&1y;");a=a.Q(/ {2,}/g,6(c){O(K d="",h=0;h<c.L-1;h++)d+=e.13.1W;H d+" "});I(b!=N)a=v(a,6(c){I(c.L==0)H"";K d="";c=c.Q(/^(&2s;| )+/,6(h){d=h;H""});I(c.L==0)H d;H d+\'<17 1g="\'+b+\'">\'+c+"</17>"});H a}6 n(a,b){a.1e("\\n");O(K c="",d=0;d<50;d++)c+=" ";H a=v(a,6(h){I(h.1i("\\t")==-1)H h;O(K g=0;(g=h.1i("\\t"))!=-1;)h=h.1o(0,g)+c.1o(0,b-g%b)+h.1o(g+1,h.L);H h})}6 x(a){H a.Q(/^\\s+|\\s+$/g,"")}6 D(a,b){I(a.P<b.P)H-1;Y I(a.P>b.P)H 1;Y I(a.L<b.L)H-1;Y I(a.L>b.L)H 1;H 0}6 y(a,b){6 c(k){H k[0]}O(K d=N,h=[],g=b.2D?b.2D:c;(d=b.1I.X(a))!=N;){K i=g(d,b);I(1j i=="3f")i=[1f e.2L(i,d.P,b.23)];h=h.1O(i)}H h}6 E(a){K b=/(.*)((&1G;|&1y;).*)/;H a.Q(e.3A.3M,6(c){K d="",h=N;I(h=b.X(c)){c=h[1];d=h[2]}H\'<a 2h="\'+c+\'">\'+c+"</a>"+d})}6 z(){O(K a=1E.36("1k"),b=[],c=0;c<a.L;c++)a[c].3s=="20"&&b.U(a[c]);H b}6 f(a){a=a.1F;K b=p(a,".20",R);a=p(a,".3O",R);K c=1E.4i("3t");I(!(!a||!b||p(a,"3t"))){B(b.1c);r(b,"1m");O(K d=a.3G,h=[],g=0;g<d.L;g++)h.U(d[g].4z||d[g].4A);h=h.1K("\\r");c.39(1E.4D(h));a.39(c);c.2C();c.4C();w(c,"4u",6(){c.2G.4E(c);b.1l=b.1l.Q("1m","")})}}I(1j 3F!="1d"&&1j M=="1d")M=3F("M").M;K e={2v:{"1g-27":"","2i-1s":1,"2z-1s-2t":11,1M:N,1t:N,"42-45":R,"43-22":4,1u:R,16:R,"3V-17":R,2l:11,"41-40":R,2k:11,"1z-1k":11},13:{1W:"&2s;",2M:R,46:11,44:11,34:"4n",1x:{21:"4o 1m",2P:"?",1X:"1v\\n\\n",3E:"4r\'t 4t 1D O: ",4g:"4m 4B\'t 51 O 1z-1k 4F: ",37:\'<!4T 1z 4S "-//4V//3H 4W 1.0 4Z//4Y" "1Z://2y.3L.3K/4X/3I/3H/3I-4P.4J"><1z 4I="1Z://2y.3L.3K/4L/5L"><3J><4N 1Z-4M="5G-5M" 6K="2O/1z; 6J=6I-8" /><1t>6L 1v</1t></3J><3B 1L="25-6M:6Q,6P,6O,6N-6F;6y-2f:#6x;2f:#6w;25-22:6v;2O-3D:3C;"><T 1L="2O-3D:3C;3w-32:1.6z;"><T 1L="25-22:6A-6E;">1v</T><T 1L="25-22:.6C;3w-6B:6R;"><T>3v 3.0.76 (72 73 3x)</T><T><a 2h="1Z://3u.2w/1v" 1F="38" 1L="2f:#3y">1Z://3u.2w/1v</a></T><T>70 17 6U 71.</T><T>6T 6X-3x 6Y 6D.</T></T><T>6t 61 60 J 1k, 5Z <a 2h="6u://2y.62.2w/63-66/65?64=5X-5W&5P=5O" 1L="2f:#3y">5R</a> 5V <2R/>5U 5T 5S!</T></T></3B></1z>\'}},1Y:{2j:N,2A:{}},1U:{},3A:{6n:/\\/\\*[\\s\\S]*?\\*\\//2c,6m:/\\/\\/.*$/2c,6l:/#.*$/2c,6k:/"([^\\\\"\\n]|\\\\.)*"/g,6o:/\'([^\\\\\'\\n]|\\\\.)*\'/g,6p:1f M(\'"([^\\\\\\\\"]|\\\\\\\\.)*"\',"3z"),6s:1f M("\'([^\\\\\\\\\']|\\\\\\\\.)*\'","3z"),6q:/(&1y;|<)!--[\\s\\S]*?--(&1G;|>)/2c,3M:/\\w+:\\/\\/[\\w-.\\/?%&=:@;]*/g,6a:{18:/(&1y;|<)\\?=?/g,1b:/\\?(&1G;|>)/g},69:{18:/(&1y;|<)%=?/g,1b:/%(&1G;|>)/g},6d:{18:/(&1y;|<)\\s*1k.*?(&1G;|>)/2T,1b:/(&1y;|<)\\/\\s*1k\\s*(&1G;|>)/2T}},16:{1H:6(a){6 b(i,k){H e.16.2o(i,k,e.13.1x[k])}O(K c=\'<T 1g="16">\',d=e.16.2x,h=d.2X,g=0;g<h.L;g++)c+=(d[h[g]].1H||b)(a,h[g]);c+="</T>";H c},2o:6(a,b,c){H\'<2W><a 2h="#" 1g="6e 6h\'+b+" "+b+\'">\'+c+"</a></2W>"},2b:6(a){K b=a.1F,c=b.1l||"";b=B(p(b,".20",R).1c);K d=6(h){H(h=15(h+"6f(\\\\w+)").X(c))?h[1]:N}("6g");b&&d&&e.16.2x[d].2B(b);a.3N()},2x:{2X:["21","2P"],21:{1H:6(a){I(a.V("2l")!=R)H"";K b=a.V("1t");H e.16.2o(a,"21",b?b:e.13.1x.21)},2B:6(a){a=1E.6j(t(a.1c));a.1l=a.1l.Q("47","")}},2P:{2B:6(){K a="68=0";a+=", 18="+(31.30-33)/2+", 32="+(31.2Z-2Y)/2+", 30=33, 2Z=2Y";a=a.Q(/^,/,"");a=1P.6Z("","38",a);a.2C();K b=a.1E;b.6W(e.13.1x.37);b.6V();a.2C()}}}},35:6(a,b){K c;I(b)c=[b];Y{c=1E.36(e.13.34);O(K d=[],h=0;h<c.L;h++)d.U(c[h]);c=d}c=c;d=[];I(e.13.2M)c=c.1O(z());I(c.L===0)H d;O(h=0;h<c.L;h++){O(K g=c[h],i=a,k=c[h].1l,j=3W 0,l={},m=1f M("^\\\\[(?<2V>(.*?))\\\\]$"),s=1f M("(?<27>[\\\\w-]+)\\\\s*:\\\\s*(?<1T>[\\\\w-%#]+|\\\\[.*?\\\\]|\\".*?\\"|\'.*?\')\\\\s*;?","g");(j=s.X(k))!=N;){K o=j.1T.Q(/^[\'"]|[\'"]$/g,"");I(o!=N&&m.1A(o)){o=m.X(o);o=o.2V.L>0?o.2V.1e(/\\s*,\\s*/):[]}l[j.27]=o}g={1F:g,1n:C(i,l)};g.1n.1D!=N&&d.U(g)}H d},1M:6(a,b){K c=J.35(a,b),d=N,h=e.13;I(c.L!==0)O(K g=0;g<c.L;g++){b=c[g];K i=b.1F,k=b.1n,j=k.1D,l;I(j!=N){I(k["1z-1k"]=="R"||e.2v["1z-1k"]==R){d=1f e.4l(j);j="4O"}Y I(d=A(j))d=1f d;Y 6H;l=i.3X;I(h.2M){l=l;K m=x(l),s=11;I(m.1i("<![6G[")==0){m=m.4h(9);s=R}K o=m.L;I(m.1i("]]\\>")==o-3){m=m.4h(0,o-3);s=R}l=s?m:l}I((i.1t||"")!="")k.1t=i.1t;k.1D=j;d.2Q(k);b=d.2F(l);I((i.1c||"")!="")b.1c=i.1c;i.2G.74(b,i)}}},2E:6(a){w(1P,"4k",6(){e.1M(a)})}};e.2E=e.2E;e.1M=e.1M;e.2L=6(a,b,c){J.1T=a;J.P=b;J.L=a.L;J.23=c;J.1V=N};e.2L.Z.1q=6(){H J.1T};e.4l=6(a){6 b(j,l){O(K m=0;m<j.L;m++)j[m].P+=l}K c=A(a),d,h=1f e.1U.5Y,g=J,i="2F 1H 2Q".1e(" ");I(c!=N){d=1f c;O(K k=0;k<i.L;k++)(6(){K j=i[k];g[j]=6(){H h[j].1p(h,14)}})();d.28==N?1P.1X(e.13.1x.1X+(e.13.1x.4g+a)):h.2J.U({1I:d.28.17,2D:6(j){O(K l=j.17,m=[],s=d.2J,o=j.P+j.18.L,F=d.28,q,G=0;G<s.L;G++){q=y(l,s[G]);b(q,o);m=m.1O(q)}I(F.18!=N&&j.18!=N){q=y(j.18,F.18);b(q,j.P);m=m.1O(q)}I(F.1b!=N&&j.1b!=N){q=y(j.1b,F.1b);b(q,j.P+j[0].5Q(j.1b));m=m.1O(q)}O(j=0;j<m.L;j++)m[j].1V=c.1V;H m}})}};e.4j=6(){};e.4j.Z={V:6(a,b){K c=J.1n[a];c=c==N?b:c;K d={"R":R,"11":11}[c];H d==N?c:d},3Y:6(a){H 1E.4i(a)},4c:6(a,b){K c=[];I(a!=N)O(K d=0;d<a.L;d++)I(1j a[d]=="2m")c=c.1O(y(b,a[d]));H J.4e(c.6b(D))},4e:6(a){O(K b=0;b<a.L;b++)I(a[b]!==N)O(K c=a[b],d=c.P+c.L,h=b+1;h<a.L&&a[b]!==N;h++){K g=a[h];I(g!==N)I(g.P>d)1N;Y I(g.P==c.P&&g.L>c.L)a[b]=N;Y I(g.P>=c.P&&g.P<d)a[h]=N}H a},4d:6(a){K b=[],c=2u(J.V("2i-1s"));v(a,6(d,h){b.U(h+c)});H b},3U:6(a){K b=J.V("1M",[]);I(1j b!="2m"&&b.U==N)b=[b];a:{a=a.1q();K c=3W 0;O(c=c=1Q.6c(c||0,0);c<b.L;c++)I(b[c]==a){b=c;1N a}b=-1}H b!=-1},2r:6(a,b,c){a=["1s","6i"+b,"P"+a,"6r"+(b%2==0?1:2).1q()];J.3U(b)&&a.U("67");b==0&&a.U("1N");H\'<T 1g="\'+a.1K(" ")+\'">\'+c+"</T>"},3Q:6(a,b){K c="",d=a.1e("\\n").L,h=2u(J.V("2i-1s")),g=J.V("2z-1s-2t");I(g==R)g=(h+d-1).1q().L;Y I(3R(g)==R)g=0;O(K i=0;i<d;i++){K k=b?b[i]:h+i,j;I(k==0)j=e.13.1W;Y{j=g;O(K l=k.1q();l.L<j;)l="0"+l;j=l}a=j;c+=J.2r(i,k,a)}H c},49:6(a,b){a=x(a);K c=a.1e("\\n");J.V("2z-1s-2t");K d=2u(J.V("2i-1s"));a="";O(K h=J.V("1D"),g=0;g<c.L;g++){K i=c[g],k=/^(&2s;|\\s)+/.X(i),j=N,l=b?b[g]:d+g;I(k!=N){j=k[0].1q();i=i.1o(j.L);j=j.Q(" ",e.13.1W)}i=x(i);I(i.L==0)i=e.13.1W;a+=J.2r(g,l,(j!=N?\'<17 1g="\'+h+\' 5N">\'+j+"</17>":"")+i)}H a},4f:6(a){H a?"<4a>"+a+"</4a>":""},4b:6(a,b){6 c(l){H(l=l?l.1V||g:g)?l+" ":""}O(K d=0,h="",g=J.V("1D",""),i=0;i<b.L;i++){K k=b[i],j;I(!(k===N||k.L===0)){j=c(k);h+=u(a.1o(d,k.P-d),j+"48")+u(k.1T,j+k.23);d=k.P+k.L+(k.75||0)}}h+=u(a.1o(d),c()+"48");H h},1H:6(a){K b="",c=["20"],d;I(J.V("2k")==R)J.1n.16=J.1n.1u=11;1l="20";J.V("2l")==R&&c.U("47");I((1u=J.V("1u"))==11)c.U("6S");c.U(J.V("1g-27"));c.U(J.V("1D"));a=a.Q(/^[ ]*[\\n]+|[\\n]*[ ]*$/g,"").Q(/\\r/g," ");b=J.V("43-22");I(J.V("42-45")==R)a=n(a,b);Y{O(K h="",g=0;g<b;g++)h+=" ";a=a.Q(/\\t/g,h)}a=a;a:{b=a=a;h=/<2R\\s*\\/?>|&1y;2R\\s*\\/?&1G;/2T;I(e.13.46==R)b=b.Q(h,"\\n");I(e.13.44==R)b=b.Q(h,"");b=b.1e("\\n");h=/^\\s*/;g=4Q;O(K i=0;i<b.L&&g>0;i++){K k=b[i];I(x(k).L!=0){k=h.X(k);I(k==N){a=a;1N a}g=1Q.4q(k[0].L,g)}}I(g>0)O(i=0;i<b.L;i++)b[i]=b[i].1o(g);a=b.1K("\\n")}I(1u)d=J.4d(a);b=J.4c(J.2J,a);b=J.4b(a,b);b=J.49(b,d);I(J.V("41-40"))b=E(b);1j 2H!="1d"&&2H.3S&&2H.3S.1C(/5s/)&&c.U("5t");H b=\'<T 1c="\'+t(J.1c)+\'" 1g="\'+c.1K(" ")+\'">\'+(J.V("16")?e.16.1H(J):"")+\'<3Z 5z="0" 5H="0" 5J="0">\'+J.4f(J.V("1t"))+"<3T><3P>"+(1u?\'<2d 1g="1u">\'+J.3Q(a)+"</2d>":"")+\'<2d 1g="17"><T 1g="3O">\'+b+"</T></2d></3P></3T></3Z></T>"},2F:6(a){I(a===N)a="";J.17=a;K b=J.3Y("T");b.3X=J.1H(a);J.V("16")&&w(p(b,".16"),"5c",e.16.2b);J.V("3V-17")&&w(p(b,".17"),"56",f);H b},2Q:6(a){J.1c=""+1Q.5d(1Q.5n()*5k).1q();e.1Y.2A[t(J.1c)]=J;J.1n=C(e.2v,a||{});I(J.V("2k")==R)J.1n.16=J.1n.1u=11},5j:6(a){a=a.Q(/^\\s+|\\s+$/g,"").Q(/\\s+/g,"|");H"\\\\b(?:"+a+")\\\\b"},5f:6(a){J.28={18:{1I:a.18,23:"1k"},1b:{1I:a.1b,23:"1k"},17:1f M("(?<18>"+a.18.1m+")(?<17>.*?)(?<1b>"+a.1b.1m+")","5o")}}};H e}();1j 2e!="1d"&&(2e.1v=1v);',62,441,'||||||function|||||||||||||||||||||||||||||||||||||return|if|this|var|length|XRegExp|null|for|index|replace|true||div|push|getParam|call|exec|else|prototype||false|lastIndex|config|arguments|RegExp|toolbar|code|left|captureNames|slice|right|id|undefined|split|new|class|addToken|indexOf|typeof|script|className|source|params|substr|apply|toString|String|line|title|gutter|SyntaxHighlighter|_xregexp|strings|lt|html|test|OUTSIDE_CLASS|match|brush|document|target|gt|getHtml|regex|global|join|style|highlight|break|concat|window|Math|isRegExp|throw|value|brushes|brushName|space|alert|vars|http|syntaxhighlighter|expandSource|size|css|case|font|Fa|name|htmlScript|dA|can|handler|gm|td|exports|color|in|href|first|discoveredBrushes|light|collapse|object|cache|getButtonHtml|trigger|pattern|getLineHtml|nbsp|numbers|parseInt|defaults|com|items|www|pad|highlighters|execute|focus|func|all|getDiv|parentNode|navigator|INSIDE_CLASS|regexList|hasFlag|Match|useScriptTags|hasNamedCapture|text|help|init|br|input|gi|Error|values|span|list|250|height|width|screen|top|500|tagName|findElements|getElementsByTagName|aboutDialog|_blank|appendChild|charAt|Array|copyAsGlobal|setFlag|highlighter_|string|attachEvent|nodeName|floor|backref|output|the|TypeError|sticky|Za|iterate|freezeTokens|scope|type|textarea|alexgorbatchev|version|margin|2010|005896|gs|regexLib|body|center|align|noBrush|require|childNodes|DTD|xhtml1|head|org|w3|url|preventDefault|container|tr|getLineNumbersHtml|isNaN|userAgent|tbody|isLineHighlighted|quick|void|innerHTML|create|table|links|auto|smart|tab|stripBrs|tabs|bloggerMode|collapsed|plain|getCodeLinesHtml|caption|getMatchesHtml|findMatches|figureOutLineNumbers|removeNestedMatches|getTitleHtml|brushNotHtmlScript|substring|createElement|Highlighter|load|HtmlScript|Brush|pre|expand|multiline|min|Can|ignoreCase|find|blur|extended|toLowerCase|aliases|addEventListener|innerText|textContent|wasn|select|createTextNode|removeChild|option|same|frame|xmlns|dtd|twice|1999|equiv|meta|htmlscript|transitional|1E3|expected|PUBLIC|DOCTYPE|on|W3C|XHTML|TR|EN|Transitional||configured|srcElement|Object|after|run|dblclick|matchChain|valueOf|constructor|default|switch|click|round|execAt|forHtmlScript|token|gimy|functions|getKeywords|1E6|escape|within|random|sgi|another|finally|supply|MSIE|ie|toUpperCase|catch|returnValue|definition|event|border|imsx|constructing|one|Infinity|from|when|Content|cellpadding|flags|cellspacing|try|xhtml|Type|spaces|2930402|hosted_button_id|lastIndexOf|donate|active|development|keep|to|xclick|_s|Xml|please|like|you|paypal|cgi|cmd|webscr|bin|highlighted|scrollbars|aspScriptTags|phpScriptTags|sort|max|scriptScriptTags|toolbar_item|_|command|command_|number|getElementById|doubleQuotedString|singleLinePerlComments|singleLineCComments|multiLineCComments|singleQuotedString|multiLineDoubleQuotedString|xmlComments|alt|multiLineSingleQuotedString|If|https|1em|000|fff|background|5em|xx|bottom|75em|Gorbatchev|large|serif|CDATA|continue|utf|charset|content|About|family|sans|Helvetica|Arial|Geneva|3em|nogutter|Copyright|syntax|close|write|2004|Alex|open|JavaScript|highlighter|July|02|replaceChild|offset|83'.split('|'),0,{})) diff --git a/guides/assets/stylesheets/main.css b/guides/assets/stylesheets/main.css index ed558e4793..b56699a0d0 100644 --- a/guides/assets/stylesheets/main.css +++ b/guides/assets/stylesheets/main.css @@ -16,7 +16,6 @@ .large {font-size: larger;} .hide {display: none;} -li ul, li ol { margin:0 1.5em; } ul, ol { margin: 0 1.5em 1.5em 1.5em; } ul { list-style-type: disc; } @@ -602,6 +601,8 @@ h6 { font-weight: normal; } +#subCol li ul, li ol { margin:0 1.5em; } + div.code_container { background: #EEE url(../images/tab_grey.gif) no-repeat left top; padding: 0.25em 1em 0.5em 48px; diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCore.css b/guides/assets/stylesheets/syntaxhighlighter/shCore.css index 34f6864a15..7e1e199343 100644 --- a/guides/assets/stylesheets/syntaxhighlighter/shCore.css +++ b/guides/assets/stylesheets/syntaxhighlighter/shCore.css @@ -33,7 +33,7 @@ height: auto !important; left: auto !important; line-height: 1.1em !important; - margin: 0 !important; + margin: 0 0 0.5px 0 !important; outline: 0 !important; overflow: visible !important; padding: 0 !important; diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreDefault.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreDefault.css deleted file mode 100644 index 08f9e10e4e..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreDefault.css +++ /dev/null @@ -1,328 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: white !important; -} -.syntaxhighlighter .line.alt1 { - background-color: white !important; -} -.syntaxhighlighter .line.alt2 { - background-color: white !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #e0e0e0 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: black !important; -} -.syntaxhighlighter table caption { - color: black !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #6ce26c !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #6ce26c !important; - color: white !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: blue !important; - background: white !important; - border: 1px solid #6ce26c !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: blue !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: red !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #6ce26c !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: black !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: black !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #008200 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: blue !important; -} -.syntaxhighlighter .keyword { - color: #006699 !important; -} -.syntaxhighlighter .preprocessor { - color: gray !important; -} -.syntaxhighlighter .variable { - color: #aa7700 !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #ff1493 !important; -} -.syntaxhighlighter .constants { - color: #0066cc !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #006699 !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: gray !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: red !important; -} - -.syntaxhighlighter .keyword { - font-weight: bold !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreDjango.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreDjango.css deleted file mode 100644 index 1db1f70cb0..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreDjango.css +++ /dev/null @@ -1,331 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: #0a2b1d !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #0a2b1d !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #0a2b1d !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #233729 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: #f8f8f8 !important; -} -.syntaxhighlighter .gutter { - color: #497958 !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #41a83e !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #41a83e !important; - color: #0a2b1d !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #96dd3b !important; - background: black !important; - border: 1px solid #41a83e !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #96dd3b !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: white !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #41a83e !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #ffe862 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #f8f8f8 !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #336442 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #9df39f !important; -} -.syntaxhighlighter .keyword { - color: #96dd3b !important; -} -.syntaxhighlighter .preprocessor { - color: #91bb9e !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #f7e741 !important; -} -.syntaxhighlighter .functions { - color: #ffaa3e !important; -} -.syntaxhighlighter .constants { - color: #e0e8ff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #96dd3b !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #eb939a !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #91bb9e !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #edef7d !important; -} - -.syntaxhighlighter .comments { - font-style: italic !important; -} -.syntaxhighlighter .keyword { - font-weight: bold !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreEclipse.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreEclipse.css deleted file mode 100644 index a45de9fd8e..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreEclipse.css +++ /dev/null @@ -1,339 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: white !important; -} -.syntaxhighlighter .line.alt1 { - background-color: white !important; -} -.syntaxhighlighter .line.alt2 { - background-color: white !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #c3defe !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: black !important; -} -.syntaxhighlighter .gutter { - color: #787878 !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #d4d0c8 !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #d4d0c8 !important; - color: white !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #3f5fbf !important; - background: white !important; - border: 1px solid #d4d0c8 !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #3f5fbf !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #aa7700 !important; -} -.syntaxhighlighter .toolbar { - color: #a0a0a0 !important; - background: #d4d0c8 !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: #a0a0a0 !important; -} -.syntaxhighlighter .toolbar a:hover { - color: red !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: black !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #3f5fbf !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #2a00ff !important; -} -.syntaxhighlighter .keyword { - color: #7f0055 !important; -} -.syntaxhighlighter .preprocessor { - color: #646464 !important; -} -.syntaxhighlighter .variable { - color: #aa7700 !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #ff1493 !important; -} -.syntaxhighlighter .constants { - color: #0066cc !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #7f0055 !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: gray !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: red !important; -} - -.syntaxhighlighter .keyword { - font-weight: bold !important; -} -.syntaxhighlighter .xml .keyword { - color: #3f7f7f !important; - font-weight: normal !important; -} -.syntaxhighlighter .xml .color1, .syntaxhighlighter .xml .color1 a { - color: #7f007f !important; -} -.syntaxhighlighter .xml .string { - font-style: italic !important; - color: #2a00ff !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreEmacs.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreEmacs.css deleted file mode 100644 index 706c77a0a8..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreEmacs.css +++ /dev/null @@ -1,324 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: black !important; -} -.syntaxhighlighter .line.alt1 { - background-color: black !important; -} -.syntaxhighlighter .line.alt2 { - background-color: black !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #2a3133 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: #d3d3d3 !important; -} -.syntaxhighlighter .gutter { - color: #d3d3d3 !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #990000 !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #990000 !important; - color: black !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #ebdb8d !important; - background: black !important; - border: 1px solid #990000 !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #ebdb8d !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #ff7d27 !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #990000 !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #9ccff4 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #d3d3d3 !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #ff7d27 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #ff9e7b !important; -} -.syntaxhighlighter .keyword { - color: aqua !important; -} -.syntaxhighlighter .preprocessor { - color: #aec4de !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #81cef9 !important; -} -.syntaxhighlighter .constants { - color: #ff9e7b !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: aqua !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #ebdb8d !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #ff7d27 !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #aec4de !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreFadeToGrey.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreFadeToGrey.css deleted file mode 100644 index 6101eba51f..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreFadeToGrey.css +++ /dev/null @@ -1,328 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: #121212 !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #121212 !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #121212 !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #2c2c29 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: white !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #3185b9 !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #3185b9 !important; - color: #121212 !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #3185b9 !important; - background: black !important; - border: 1px solid #3185b9 !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #3185b9 !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #d01d33 !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #3185b9 !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #96daff !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: white !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #696854 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #e3e658 !important; -} -.syntaxhighlighter .keyword { - color: #d01d33 !important; -} -.syntaxhighlighter .preprocessor { - color: #435a5f !important; -} -.syntaxhighlighter .variable { - color: #898989 !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #aaaaaa !important; -} -.syntaxhighlighter .constants { - color: #96daff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #d01d33 !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #ffc074 !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #4a8cdb !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #96daff !important; -} - -.syntaxhighlighter .functions { - font-weight: bold !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreMDUltra.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreMDUltra.css deleted file mode 100644 index 2923ce7367..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreMDUltra.css +++ /dev/null @@ -1,324 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: #222222 !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #222222 !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #222222 !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #253e5a !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: lime !important; -} -.syntaxhighlighter .gutter { - color: #38566f !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #435a5f !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #435a5f !important; - color: #222222 !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #428bdd !important; - background: black !important; - border: 1px solid #435a5f !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #428bdd !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: lime !important; -} -.syntaxhighlighter .toolbar { - color: #aaaaff !important; - background: #435a5f !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: #aaaaff !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #9ccff4 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: lime !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #428bdd !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: lime !important; -} -.syntaxhighlighter .keyword { - color: #aaaaff !important; -} -.syntaxhighlighter .preprocessor { - color: #8aa6c1 !important; -} -.syntaxhighlighter .variable { - color: aqua !important; -} -.syntaxhighlighter .value { - color: #f7e741 !important; -} -.syntaxhighlighter .functions { - color: #ff8000 !important; -} -.syntaxhighlighter .constants { - color: yellow !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #aaaaff !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: red !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: yellow !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #ffaa3e !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreMidnight.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreMidnight.css deleted file mode 100644 index e3733eed56..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreMidnight.css +++ /dev/null @@ -1,324 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: #0f192a !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #0f192a !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #0f192a !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #253e5a !important; -} -.syntaxhighlighter .line.highlighted.number { - color: #38566f !important; -} -.syntaxhighlighter table caption { - color: #d1edff !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #435a5f !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #435a5f !important; - color: #0f192a !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #428bdd !important; - background: black !important; - border: 1px solid #435a5f !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #428bdd !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #1dc116 !important; -} -.syntaxhighlighter .toolbar { - color: #d1edff !important; - background: #435a5f !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: #d1edff !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #8aa6c1 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #d1edff !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #428bdd !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #1dc116 !important; -} -.syntaxhighlighter .keyword { - color: #b43d3d !important; -} -.syntaxhighlighter .preprocessor { - color: #8aa6c1 !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #f7e741 !important; -} -.syntaxhighlighter .functions { - color: #ffaa3e !important; -} -.syntaxhighlighter .constants { - color: #e0e8ff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #b43d3d !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #f8bb00 !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: white !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #ffaa3e !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shCoreRDark.css b/guides/assets/stylesheets/syntaxhighlighter/shCoreRDark.css deleted file mode 100644 index d09368384d..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shCoreRDark.css +++ /dev/null @@ -1,324 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter a, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody, -.syntaxhighlighter table thead, -.syntaxhighlighter table caption, -.syntaxhighlighter textarea { - -moz-border-radius: 0 0 0 0 !important; - -webkit-border-radius: 0 0 0 0 !important; - background: none !important; - border: 0 !important; - bottom: auto !important; - float: none !important; - height: auto !important; - left: auto !important; - line-height: 1.1em !important; - margin: 0 !important; - outline: 0 !important; - overflow: visible !important; - padding: 0 !important; - position: static !important; - right: auto !important; - text-align: left !important; - top: auto !important; - vertical-align: baseline !important; - width: auto !important; - box-sizing: content-box !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; - min-height: auto !important; -} - -.syntaxhighlighter { - width: 100% !important; - margin: 1em 0 1em 0 !important; - position: relative !important; - overflow: auto !important; - font-size: 1em !important; -} -.syntaxhighlighter.source { - overflow: hidden !important; -} -.syntaxhighlighter .bold { - font-weight: bold !important; -} -.syntaxhighlighter .italic { - font-style: italic !important; -} -.syntaxhighlighter .line { - white-space: pre !important; -} -.syntaxhighlighter table { - width: 100% !important; -} -.syntaxhighlighter table caption { - text-align: left !important; - padding: .5em 0 0.5em 1em !important; -} -.syntaxhighlighter table td.code { - width: 100% !important; -} -.syntaxhighlighter table td.code .container { - position: relative !important; -} -.syntaxhighlighter table td.code .container textarea { - box-sizing: border-box !important; - position: absolute !important; - left: 0 !important; - top: 0 !important; - width: 100% !important; - height: 100% !important; - border: none !important; - background: white !important; - padding-left: 1em !important; - overflow: hidden !important; - white-space: pre !important; -} -.syntaxhighlighter table td.gutter .line { - text-align: right !important; - padding: 0 0.5em 0 1em !important; -} -.syntaxhighlighter table td.code .line { - padding: 0 1em !important; -} -.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { - padding-left: 0em !important; -} -.syntaxhighlighter.show { - display: block !important; -} -.syntaxhighlighter.collapsed table { - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar { - padding: 0.1em 0.8em 0em 0.8em !important; - font-size: 1em !important; - position: static !important; - width: auto !important; - height: auto !important; -} -.syntaxhighlighter.collapsed .toolbar span { - display: inline !important; - margin-right: 1em !important; -} -.syntaxhighlighter.collapsed .toolbar span a { - padding: 0 !important; - display: none !important; -} -.syntaxhighlighter.collapsed .toolbar span a.expandSource { - display: inline !important; -} -.syntaxhighlighter .toolbar { - position: absolute !important; - right: 1px !important; - top: 1px !important; - width: 11px !important; - height: 11px !important; - font-size: 10px !important; - z-index: 10 !important; -} -.syntaxhighlighter .toolbar span.title { - display: inline !important; -} -.syntaxhighlighter .toolbar a { - display: block !important; - text-align: center !important; - text-decoration: none !important; - padding-top: 1px !important; -} -.syntaxhighlighter .toolbar a.expandSource { - display: none !important; -} -.syntaxhighlighter.ie { - font-size: .9em !important; - padding: 1px 0 1px 0 !important; -} -.syntaxhighlighter.ie .toolbar { - line-height: 8px !important; -} -.syntaxhighlighter.ie .toolbar a { - padding-top: 0px !important; -} -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content { - background: none !important; -} -.syntaxhighlighter.printing .line .number { - color: #bbbbbb !important; -} -.syntaxhighlighter.printing .line .content { - color: black !important; -} -.syntaxhighlighter.printing .toolbar { - display: none !important; -} -.syntaxhighlighter.printing a { - text-decoration: none !important; -} -.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { - color: black !important; -} -.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { - color: #008200 !important; -} -.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { - color: blue !important; -} -.syntaxhighlighter.printing .keyword { - color: #006699 !important; - font-weight: bold !important; -} -.syntaxhighlighter.printing .preprocessor { - color: gray !important; -} -.syntaxhighlighter.printing .variable { - color: #aa7700 !important; -} -.syntaxhighlighter.printing .value { - color: #009900 !important; -} -.syntaxhighlighter.printing .functions { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .constants { - color: #0066cc !important; -} -.syntaxhighlighter.printing .script { - font-weight: bold !important; -} -.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { - color: gray !important; -} -.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { - color: red !important; -} -.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { - color: black !important; -} - -.syntaxhighlighter { - background-color: #1b2426 !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #1b2426 !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #1b2426 !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #323e41 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: #b9bdb6 !important; -} -.syntaxhighlighter table caption { - color: #b9bdb6 !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #435a5f !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #435a5f !important; - color: #1b2426 !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #5ba1cf !important; - background: black !important; - border: 1px solid #435a5f !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #5ba1cf !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #5ce638 !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #435a5f !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #e0e8ff !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #b9bdb6 !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #878a85 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #5ce638 !important; -} -.syntaxhighlighter .keyword { - color: #5ba1cf !important; -} -.syntaxhighlighter .preprocessor { - color: #435a5f !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #ffaa3e !important; -} -.syntaxhighlighter .constants { - color: #e0e8ff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #5ba1cf !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #e0e8ff !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: white !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #ffaa3e !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeDefault.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeDefault.css deleted file mode 100644 index 136541172d..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeDefault.css +++ /dev/null @@ -1,117 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: white !important; -} -.syntaxhighlighter .line.alt1 { - background-color: white !important; -} -.syntaxhighlighter .line.alt2 { - background-color: white !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #e0e0e0 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: black !important; -} -.syntaxhighlighter table caption { - color: black !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #6ce26c !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #6ce26c !important; - color: white !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: blue !important; - background: white !important; - border: 1px solid #6ce26c !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: blue !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: red !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #6ce26c !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: black !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: black !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #008200 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: blue !important; -} -.syntaxhighlighter .keyword { - color: #006699 !important; -} -.syntaxhighlighter .preprocessor { - color: gray !important; -} -.syntaxhighlighter .variable { - color: #aa7700 !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #ff1493 !important; -} -.syntaxhighlighter .constants { - color: #0066cc !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #006699 !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: gray !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: red !important; -} - -.syntaxhighlighter .keyword { - font-weight: bold !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeDjango.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeDjango.css deleted file mode 100644 index d8b4313433..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeDjango.css +++ /dev/null @@ -1,120 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: #0a2b1d !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #0a2b1d !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #0a2b1d !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #233729 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: #f8f8f8 !important; -} -.syntaxhighlighter .gutter { - color: #497958 !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #41a83e !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #41a83e !important; - color: #0a2b1d !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #96dd3b !important; - background: black !important; - border: 1px solid #41a83e !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #96dd3b !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: white !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #41a83e !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #ffe862 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #f8f8f8 !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #336442 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #9df39f !important; -} -.syntaxhighlighter .keyword { - color: #96dd3b !important; -} -.syntaxhighlighter .preprocessor { - color: #91bb9e !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #f7e741 !important; -} -.syntaxhighlighter .functions { - color: #ffaa3e !important; -} -.syntaxhighlighter .constants { - color: #e0e8ff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #96dd3b !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #eb939a !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #91bb9e !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #edef7d !important; -} - -.syntaxhighlighter .comments { - font-style: italic !important; -} -.syntaxhighlighter .keyword { - font-weight: bold !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeEclipse.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeEclipse.css deleted file mode 100644 index 77377d9533..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeEclipse.css +++ /dev/null @@ -1,128 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: white !important; -} -.syntaxhighlighter .line.alt1 { - background-color: white !important; -} -.syntaxhighlighter .line.alt2 { - background-color: white !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #c3defe !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: black !important; -} -.syntaxhighlighter .gutter { - color: #787878 !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #d4d0c8 !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #d4d0c8 !important; - color: white !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #3f5fbf !important; - background: white !important; - border: 1px solid #d4d0c8 !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #3f5fbf !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #aa7700 !important; -} -.syntaxhighlighter .toolbar { - color: #a0a0a0 !important; - background: #d4d0c8 !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: #a0a0a0 !important; -} -.syntaxhighlighter .toolbar a:hover { - color: red !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: black !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #3f5fbf !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #2a00ff !important; -} -.syntaxhighlighter .keyword { - color: #7f0055 !important; -} -.syntaxhighlighter .preprocessor { - color: #646464 !important; -} -.syntaxhighlighter .variable { - color: #aa7700 !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #ff1493 !important; -} -.syntaxhighlighter .constants { - color: #0066cc !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #7f0055 !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: gray !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #ff1493 !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: red !important; -} - -.syntaxhighlighter .keyword { - font-weight: bold !important; -} -.syntaxhighlighter .xml .keyword { - color: #3f7f7f !important; - font-weight: normal !important; -} -.syntaxhighlighter .xml .color1, .syntaxhighlighter .xml .color1 a { - color: #7f007f !important; -} -.syntaxhighlighter .xml .string { - font-style: italic !important; - color: #2a00ff !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeEmacs.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeEmacs.css deleted file mode 100644 index dae5053fea..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeEmacs.css +++ /dev/null @@ -1,113 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: black !important; -} -.syntaxhighlighter .line.alt1 { - background-color: black !important; -} -.syntaxhighlighter .line.alt2 { - background-color: black !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #2a3133 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: #d3d3d3 !important; -} -.syntaxhighlighter .gutter { - color: #d3d3d3 !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #990000 !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #990000 !important; - color: black !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #ebdb8d !important; - background: black !important; - border: 1px solid #990000 !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #ebdb8d !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #ff7d27 !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #990000 !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #9ccff4 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #d3d3d3 !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #ff7d27 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #ff9e7b !important; -} -.syntaxhighlighter .keyword { - color: aqua !important; -} -.syntaxhighlighter .preprocessor { - color: #aec4de !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #81cef9 !important; -} -.syntaxhighlighter .constants { - color: #ff9e7b !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: aqua !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #ebdb8d !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #ff7d27 !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #aec4de !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeFadeToGrey.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeFadeToGrey.css deleted file mode 100644 index 8fbd871fb5..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeFadeToGrey.css +++ /dev/null @@ -1,117 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: #121212 !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #121212 !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #121212 !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #2c2c29 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: white !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #3185b9 !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #3185b9 !important; - color: #121212 !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #3185b9 !important; - background: black !important; - border: 1px solid #3185b9 !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #3185b9 !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #d01d33 !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #3185b9 !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #96daff !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: white !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #696854 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #e3e658 !important; -} -.syntaxhighlighter .keyword { - color: #d01d33 !important; -} -.syntaxhighlighter .preprocessor { - color: #435a5f !important; -} -.syntaxhighlighter .variable { - color: #898989 !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #aaaaaa !important; -} -.syntaxhighlighter .constants { - color: #96daff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #d01d33 !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #ffc074 !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: #4a8cdb !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #96daff !important; -} - -.syntaxhighlighter .functions { - font-weight: bold !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeMDUltra.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeMDUltra.css deleted file mode 100755 index f4db39cd83..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeMDUltra.css +++ /dev/null @@ -1,113 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: #222222 !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #222222 !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #222222 !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #253e5a !important; -} -.syntaxhighlighter .line.highlighted.number { - color: white !important; -} -.syntaxhighlighter table caption { - color: lime !important; -} -.syntaxhighlighter .gutter { - color: #38566f !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #435a5f !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #435a5f !important; - color: #222222 !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #428bdd !important; - background: black !important; - border: 1px solid #435a5f !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #428bdd !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: lime !important; -} -.syntaxhighlighter .toolbar { - color: #aaaaff !important; - background: #435a5f !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: #aaaaff !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #9ccff4 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: lime !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #428bdd !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: lime !important; -} -.syntaxhighlighter .keyword { - color: #aaaaff !important; -} -.syntaxhighlighter .preprocessor { - color: #8aa6c1 !important; -} -.syntaxhighlighter .variable { - color: aqua !important; -} -.syntaxhighlighter .value { - color: #f7e741 !important; -} -.syntaxhighlighter .functions { - color: #ff8000 !important; -} -.syntaxhighlighter .constants { - color: yellow !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #aaaaff !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: red !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: yellow !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #ffaa3e !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeMidnight.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeMidnight.css deleted file mode 100644 index c49563cc9d..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeMidnight.css +++ /dev/null @@ -1,113 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: #0f192a !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #0f192a !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #0f192a !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #253e5a !important; -} -.syntaxhighlighter .line.highlighted.number { - color: #38566f !important; -} -.syntaxhighlighter table caption { - color: #d1edff !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #435a5f !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #435a5f !important; - color: #0f192a !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #428bdd !important; - background: black !important; - border: 1px solid #435a5f !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #428bdd !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #1dc116 !important; -} -.syntaxhighlighter .toolbar { - color: #d1edff !important; - background: #435a5f !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: #d1edff !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #8aa6c1 !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #d1edff !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #428bdd !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #1dc116 !important; -} -.syntaxhighlighter .keyword { - color: #b43d3d !important; -} -.syntaxhighlighter .preprocessor { - color: #8aa6c1 !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #f7e741 !important; -} -.syntaxhighlighter .functions { - color: #ffaa3e !important; -} -.syntaxhighlighter .constants { - color: #e0e8ff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #b43d3d !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #f8bb00 !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: white !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #ffaa3e !important; -} diff --git a/guides/assets/stylesheets/syntaxhighlighter/shThemeRDark.css b/guides/assets/stylesheets/syntaxhighlighter/shThemeRDark.css deleted file mode 100644 index 6305a10e4e..0000000000 --- a/guides/assets/stylesheets/syntaxhighlighter/shThemeRDark.css +++ /dev/null @@ -1,113 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -.syntaxhighlighter { - background-color: #1b2426 !important; -} -.syntaxhighlighter .line.alt1 { - background-color: #1b2426 !important; -} -.syntaxhighlighter .line.alt2 { - background-color: #1b2426 !important; -} -.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { - background-color: #323e41 !important; -} -.syntaxhighlighter .line.highlighted.number { - color: #b9bdb6 !important; -} -.syntaxhighlighter table caption { - color: #b9bdb6 !important; -} -.syntaxhighlighter .gutter { - color: #afafaf !important; -} -.syntaxhighlighter .gutter .line { - border-right: 3px solid #435a5f !important; -} -.syntaxhighlighter .gutter .line.highlighted { - background-color: #435a5f !important; - color: #1b2426 !important; -} -.syntaxhighlighter.printing .line .content { - border: none !important; -} -.syntaxhighlighter.collapsed { - overflow: visible !important; -} -.syntaxhighlighter.collapsed .toolbar { - color: #5ba1cf !important; - background: black !important; - border: 1px solid #435a5f !important; -} -.syntaxhighlighter.collapsed .toolbar a { - color: #5ba1cf !important; -} -.syntaxhighlighter.collapsed .toolbar a:hover { - color: #5ce638 !important; -} -.syntaxhighlighter .toolbar { - color: white !important; - background: #435a5f !important; - border: none !important; -} -.syntaxhighlighter .toolbar a { - color: white !important; -} -.syntaxhighlighter .toolbar a:hover { - color: #e0e8ff !important; -} -.syntaxhighlighter .plain, .syntaxhighlighter .plain a { - color: #b9bdb6 !important; -} -.syntaxhighlighter .comments, .syntaxhighlighter .comments a { - color: #878a85 !important; -} -.syntaxhighlighter .string, .syntaxhighlighter .string a { - color: #5ce638 !important; -} -.syntaxhighlighter .keyword { - color: #5ba1cf !important; -} -.syntaxhighlighter .preprocessor { - color: #435a5f !important; -} -.syntaxhighlighter .variable { - color: #ffaa3e !important; -} -.syntaxhighlighter .value { - color: #009900 !important; -} -.syntaxhighlighter .functions { - color: #ffaa3e !important; -} -.syntaxhighlighter .constants { - color: #e0e8ff !important; -} -.syntaxhighlighter .script { - font-weight: bold !important; - color: #5ba1cf !important; - background-color: none !important; -} -.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { - color: #e0e8ff !important; -} -.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { - color: white !important; -} -.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { - color: #ffaa3e !important; -} diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb index 604cf4be41..960d269d90 100644 --- a/guides/bug_report_templates/action_controller_gem.rb +++ b/guides/bug_report_templates/action_controller_gem.rb @@ -1,30 +1,30 @@ begin - require 'bundler/inline' + require "bundler/inline" rescue LoadError => e - $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" raise e end gemfile(true) do - source 'https://rubygems.org' + source "https://rubygems.org" # Activate the gem you are reporting the issue against. - gem 'rails', '5.0.0.rc1' + gem "rails", "5.0.0" end -require 'rack/test' -require 'action_controller/railtie' +require "rack/test" +require "action_controller/railtie" class TestApp < Rails::Application config.root = File.dirname(__FILE__) - config.session_store :cookie_store, key: 'cookie_store_key' - secrets.secret_token = 'secret_token' - secrets.secret_key_base = 'secret_key_base' + config.session_store :cookie_store, key: "cookie_store_key" + secrets.secret_token = "secret_token" + secrets.secret_key_base = "secret_key_base" config.logger = Logger.new($stdout) Rails.logger = config.logger routes.draw do - get '/' => 'test#index' + get "/" => "test#index" end end @@ -32,11 +32,11 @@ class TestController < ActionController::Base include Rails.application.routes.url_helpers def index - render plain: 'Home' + render plain: "Home" end end -require 'minitest/autorun' +require "minitest/autorun" # Ensure backward compatibility with Minitest 4 Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) @@ -45,7 +45,7 @@ class BugTest < Minitest::Test include Rack::Test::Methods def test_returns_success - get '/' + get "/" assert last_response.ok? end diff --git a/guides/bug_report_templates/action_controller_master.rb b/guides/bug_report_templates/action_controller_master.rb index 8322707495..486c7243ad 100644 --- a/guides/bug_report_templates/action_controller_master.rb +++ b/guides/bug_report_templates/action_controller_master.rb @@ -1,28 +1,27 @@ begin - require 'bundler/inline' + require "bundler/inline" rescue LoadError => e - $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" raise e end gemfile(true) do - source 'https://rubygems.org' - gem 'rails', github: 'rails/rails' + source "https://rubygems.org" + gem "rails", github: "rails/rails" end -require 'action_controller/railtie' +require "action_controller/railtie" class TestApp < Rails::Application config.root = File.dirname(__FILE__) - config.session_store :cookie_store, key: 'cookie_store_key' - secrets.secret_token = 'secret_token' - secrets.secret_key_base = 'secret_key_base' + secrets.secret_token = "secret_token" + secrets.secret_key_base = "secret_key_base" config.logger = Logger.new($stdout) Rails.logger = config.logger routes.draw do - get '/' => 'test#index' + get "/" => "test#index" end end @@ -30,18 +29,18 @@ class TestController < ActionController::Base include Rails.application.routes.url_helpers def index - render plain: 'Home' + render plain: "Home" end end -require 'minitest/autorun' -require 'rack/test' +require "minitest/autorun" +require "rack/test" class BugTest < Minitest::Test include Rack::Test::Methods def test_returns_success - get '/' + get "/" assert last_response.ok? end diff --git a/guides/bug_report_templates/active_job_gem.rb b/guides/bug_report_templates/active_job_gem.rb new file mode 100644 index 0000000000..debc46ad54 --- /dev/null +++ b/guides/bug_report_templates/active_job_gem.rb @@ -0,0 +1,32 @@ +begin + require "bundler/inline" +rescue LoadError => e + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" + raise e +end + +gemfile(true) do + source "https://rubygems.org" + # Activate the gem you are reporting the issue against. + gem "activejob", "5.0.0" +end + +require "minitest/autorun" +require "active_job" + +# Ensure backward compatibility with Minitest 4 +Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) + +class BuggyJob < ActiveJob::Base + def perform + puts "performed" + end +end + +class BuggyJobTest < ActiveJob::TestCase + def test_stuff + assert_enqueued_with(job: BuggyJob) do + BuggyJob.perform_later + end + end +end diff --git a/guides/bug_report_templates/active_job_master.rb b/guides/bug_report_templates/active_job_master.rb new file mode 100644 index 0000000000..f61518713f --- /dev/null +++ b/guides/bug_report_templates/active_job_master.rb @@ -0,0 +1,31 @@ +begin + require "bundler/inline" +rescue LoadError => e + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" + raise e +end + +gemfile(true) do + source "https://rubygems.org" + gem "rails", github: "rails/rails" +end + +require "active_job" +require "minitest/autorun" + +# Ensure backward compatibility with Minitest 4 +Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) + +class BuggyJob < ActiveJob::Base + def perform + puts "performed" + end +end + +class BuggyJobTest < ActiveJob::TestCase + def test_stuff + assert_enqueued_with(job: BuggyJob) do + BuggyJob.perform_later + end + end +end diff --git a/guides/bug_report_templates/active_record_gem.rb b/guides/bug_report_templates/active_record_gem.rb index d4ede4e2c1..e18302fe65 100644 --- a/guides/bug_report_templates/active_record_gem.rb +++ b/guides/bug_report_templates/active_record_gem.rb @@ -1,26 +1,26 @@ begin - require 'bundler/inline' + require "bundler/inline" rescue LoadError => e - $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" raise e end gemfile(true) do - source 'https://rubygems.org' + source "https://rubygems.org" # Activate the gem you are reporting the issue against. - gem 'activerecord', '5.0.0.rc1' - gem 'sqlite3' + gem "activerecord", "5.0.0" + gem "sqlite3" end -require 'active_record' -require 'minitest/autorun' -require 'logger' +require "active_record" +require "minitest/autorun" +require "logger" # Ensure backward compatibility with Minitest 4 Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) # This connection will do for database-independent bug reports. -ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') +ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Base.logger = Logger.new(STDOUT) ActiveRecord::Schema.define do diff --git a/guides/bug_report_templates/active_record_master.rb b/guides/bug_report_templates/active_record_master.rb index 6fd401bd50..7265a671b0 100644 --- a/guides/bug_report_templates/active_record_master.rb +++ b/guides/bug_report_templates/active_record_master.rb @@ -1,22 +1,22 @@ begin - require 'bundler/inline' + require "bundler/inline" rescue LoadError => e - $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" raise e end gemfile(true) do - source 'https://rubygems.org' - gem 'rails', github: 'rails/rails' - gem 'sqlite3' + source "https://rubygems.org" + gem "rails", github: "rails/rails" + gem "sqlite3" end -require 'active_record' -require 'minitest/autorun' -require 'logger' +require "active_record" +require "minitest/autorun" +require "logger" # This connection will do for database-independent bug reports. -ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') +ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Base.logger = Logger.new(STDOUT) ActiveRecord::Schema.define do diff --git a/guides/bug_report_templates/active_record_migrations_gem.rb b/guides/bug_report_templates/active_record_migrations_gem.rb new file mode 100644 index 0000000000..f568a111f6 --- /dev/null +++ b/guides/bug_report_templates/active_record_migrations_gem.rb @@ -0,0 +1,65 @@ +begin + require "bundler/inline" +rescue LoadError => e + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" + raise e +end + +gemfile(true) do + source "https://rubygems.org" + # Activate the gem you are reporting the issue against. + gem "activerecord", "5.0.0.1" + gem "sqlite3" +end + +require "active_record" +require "minitest/autorun" +require "logger" + +# Ensure backward compatibility with Minitest 4 +Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) + +# This connection will do for database-independent bug reports. +ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") +ActiveRecord::Base.logger = Logger.new(STDOUT) + +ActiveRecord::Schema.define do + create_table :payments, force: true do |t| + t.decimal :amount, precision: 10, scale: 0, default: 0, null: false + end +end + +class Payment < ActiveRecord::Base +end + +class ChangeAmountToAddScale < ActiveRecord::Migration[5.0] + def change + reversible do |dir| + dir.up do + change_column :payments, :amount, :decimal, precision: 10, scale: 2, default: 0, null: false + end + + dir.down do + change_column :payments, :amount, :decimal, precision: 10, scale: 0, default: 0, null: false + end + end + end +end + +class BugTest < Minitest::Test + def test_migration_up + migrator = ActiveRecord::Migrator.new(:up, [ChangeAmountToAddScale]) + migrator.run + Payment.reset_column_information + + assert_equal "decimal(10,2)", Payment.columns.last.sql_type + end + + def test_migration_down + migrator = ActiveRecord::Migrator.new(:down, [ChangeAmountToAddScale]) + migrator.run + Payment.reset_column_information + + assert_equal "decimal(10,0)", Payment.columns.last.sql_type + end +end
\ No newline at end of file diff --git a/guides/bug_report_templates/active_record_migrations_master.rb b/guides/bug_report_templates/active_record_migrations_master.rb new file mode 100644 index 0000000000..ef7b42e0a6 --- /dev/null +++ b/guides/bug_report_templates/active_record_migrations_master.rb @@ -0,0 +1,64 @@ +begin + require "bundler/inline" +rescue LoadError => e + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" + raise e +end + +gemfile(true) do + source "https://rubygems.org" + gem "rails", github: "rails/rails" + gem "sqlite3" +end + +require "active_record" +require "minitest/autorun" +require "logger" + +# Ensure backward compatibility with Minitest 4 +Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) + +# This connection will do for database-independent bug reports. +ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") +ActiveRecord::Base.logger = Logger.new(STDOUT) + +ActiveRecord::Schema.define do + create_table :payments, force: true do |t| + t.decimal :amount, precision: 10, scale: 0, default: 0, null: false + end +end + +class Payment < ActiveRecord::Base +end + +class ChangeAmountToAddScale < ActiveRecord::Migration[5.0] + def change + reversible do |dir| + dir.up do + change_column :payments, :amount, :decimal, precision: 10, scale: 2, default: 0, null: false + end + + dir.down do + change_column :payments, :amount, :decimal, precision: 10, scale: 0, default: 0, null: false + end + end + end +end + +class BugTest < Minitest::Test + def test_migration_up + migrator = ActiveRecord::Migrator.new(:up, [ChangeAmountToAddScale]) + migrator.run + Payment.reset_column_information + + assert_equal "decimal(10,2)", Payment.columns.last.sql_type + end + + def test_migration_down + migrator = ActiveRecord::Migrator.new(:down, [ChangeAmountToAddScale]) + migrator.run + Payment.reset_column_information + + assert_equal "decimal(10,0)", Payment.columns.last.sql_type + end +end
\ No newline at end of file diff --git a/guides/bug_report_templates/benchmark.rb b/guides/bug_report_templates/benchmark.rb new file mode 100644 index 0000000000..ae51d7027f --- /dev/null +++ b/guides/bug_report_templates/benchmark.rb @@ -0,0 +1,49 @@ +begin + require "bundler/inline" +rescue LoadError => e + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" + raise e +end + +gemfile(true) do + source "https://rubygems.org" + gem "rails", github: "rails/rails" + gem "benchmark-ips" +end + +require "active_support" +require "active_support/core_ext/object/blank" + +# Your patch goes here. +class String + def fast_blank? + true + end +end + +# Enumerate some representative scenarios here. +# +# It is very easy to make an optimization that improves performance for a +# specific scenario you care about but regresses on other common cases. +# Therefore, you should test your change against a list of representative +# scenarios. Ideally, they should be based on real-world scenarios extracted +# from production applications. +SCENARIOS = { + "Empty" => "", + "Single Space" => " ", + "Two Spaces" => " ", + "Mixed Whitspaces" => " \t\r\n", + "Very Long String" => " " * 100 +} + +SCENARIOS.each_pair do |name, value| + puts + puts " #{name} ".center(80, "=") + puts + + Benchmark.ips do |x| + x.report('blank?') { value.blank? } + x.report('fast_blank?') { value.fast_blank? } + x.compare! + end +end diff --git a/guides/bug_report_templates/generic_gem.rb b/guides/bug_report_templates/generic_gem.rb index bb8af3be18..a94848e25b 100644 --- a/guides/bug_report_templates/generic_gem.rb +++ b/guides/bug_report_templates/generic_gem.rb @@ -1,18 +1,18 @@ begin - require 'bundler/inline' + require "bundler/inline" rescue LoadError => e - $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" raise e end gemfile(true) do - source 'https://rubygems.org' + source "https://rubygems.org" # Activate the gem you are reporting the issue against. - gem 'activesupport', '5.0.0.rc1' + gem "activesupport", "5.0.0" end -require 'active_support/core_ext/object/blank' -require 'minitest/autorun' +require "active_support/core_ext/object/blank" +require "minitest/autorun" # Ensure backward compatibility with Minitest 4 Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) diff --git a/guides/bug_report_templates/generic_master.rb b/guides/bug_report_templates/generic_master.rb index 70cf931f34..d3a7ae4ac4 100644 --- a/guides/bug_report_templates/generic_master.rb +++ b/guides/bug_report_templates/generic_master.rb @@ -1,18 +1,18 @@ begin - require 'bundler/inline' + require "bundler/inline" rescue LoadError => e - $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' + $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" raise e end gemfile(true) do - source 'https://rubygems.org' - gem 'rails', github: 'rails/rails' + source "https://rubygems.org" + gem "rails", github: "rails/rails" end -require 'active_support' -require 'active_support/core_ext/object/blank' -require 'minitest/autorun' +require "active_support" +require "active_support/core_ext/object/blank" +require "minitest/autorun" class BugTest < Minitest::Test def test_stuff diff --git a/guides/rails_guides.rb b/guides/rails_guides.rb index 367ed0b12e..557d23f78c 100644 --- a/guides/rails_guides.rb +++ b/guides/rails_guides.rb @@ -10,7 +10,7 @@ begin $:.unshift ap_lib if File.directory?(ap_lib) rescue LoadError # Guides generation from gems. - gem "actionpack", '>= 3.0' + gem "actionpack", ">= 3.0" end require "rails_guides/generator" diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb index 7618fce2c8..39a57191eb 100644 --- a/guides/rails_guides/generator.rb +++ b/guides/rails_guides/generator.rb @@ -28,12 +28,12 @@ # enough: # # # generates only association_basics.html -# ONLY=assoc ruby rails_guides.rb +# ONLY=assoc rake guides:generate # # Separate many using commas: # -# # generates only association_basics.html and migrations.html -# ONLY=assoc,migrations ruby rails_guides.rb +# # generates only association_basics.html and command_line.html +# ONLY=assoc,command rake guides:generate # # Note that if you are working on a guide generation will by default process # only that one, so ONLY is rarely used nowadays. @@ -49,18 +49,18 @@ # # --------------------------------------------------------------------------- -require 'set' -require 'fileutils' +require "set" +require "fileutils" -require 'active_support/core_ext/string/output_safety' -require 'active_support/core_ext/object/blank' -require 'action_controller' -require 'action_view' +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/object/blank" +require "action_controller" +require "action_view" -require 'rails_guides/markdown' -require 'rails_guides/indexer' -require 'rails_guides/helpers' -require 'rails_guides/levenshtein' +require "rails_guides/markdown" +require "rails_guides/indexer" +require "rails_guides/helpers" +require "rails_guides/levenshtein" module RailsGuides class Generator @@ -81,12 +81,12 @@ module RailsGuides end def set_flags_from_environment - @edge = ENV['EDGE'] == '1' - @warnings = ENV['WARNINGS'] == '1' - @all = ENV['ALL'] == '1' - @kindle = ENV['KINDLE'] == '1' - @version = ENV['RAILS_VERSION'] || 'local' - @lang = ENV['GUIDES_LANGUAGE'] + @edge = ENV["EDGE"] == "1" + @warnings = ENV["WARNINGS"] == "1" + @all = ENV["ALL"] == "1" + @kindle = ENV["KINDLE"] == "1" + @version = ENV["RAILS_VERSION"] || "local" + @lang = ENV["GUIDES_LANGUAGE"] end def register_kindle_mime_types @@ -102,148 +102,148 @@ module RailsGuides private - def kindle? - @kindle - end + def kindle? + @kindle + end - def check_for_kindlegen - if `which kindlegen`.blank? - raise "Can't create a kindle version without `kindlegen`." + def check_for_kindlegen + if `which kindlegen`.blank? + raise "Can't create a kindle version without `kindlegen`." + end end - end - def generate_mobi - require 'rails_guides/kindle' - out = "#{output_dir}/kindlegen.out" - Kindle.generate(output_dir, mobi, out) - puts "(kindlegen log at #{out})." - end + def generate_mobi + require "rails_guides/kindle" + out = "#{output_dir}/kindlegen.out" + Kindle.generate(output_dir, mobi, out) + puts "(kindlegen log at #{out})." + end - def mobi - "ruby_on_rails_guides_#@version%s.mobi" % (@lang.present? ? ".#@lang" : '') - end + def mobi + "ruby_on_rails_guides_#@version%s.mobi" % (@lang.present? ? ".#@lang" : "") + end - def initialize_dirs(output) - @guides_dir = File.join(File.dirname(__FILE__), '..') - @source_dir = "#@guides_dir/source/#@lang" - @output_dir = if output - output - elsif kindle? - "#@guides_dir/output/kindle/#@lang" - else - "#@guides_dir/output/#@lang" - end.sub(%r</$>, '') - end + def initialize_dirs(output) + @guides_dir = File.join(File.dirname(__FILE__), "..") + @source_dir = "#@guides_dir/source/#@lang" + @output_dir = if output + output + elsif kindle? + "#@guides_dir/output/kindle/#@lang" + else + "#@guides_dir/output/#@lang" + end.sub(%r</$>, "") + end - def create_output_dir_if_needed - FileUtils.mkdir_p(output_dir) - end + def create_output_dir_if_needed + FileUtils.mkdir_p(output_dir) + end - def generate_guides - guides_to_generate.each do |guide| - output_file = output_file_for(guide) - generate_guide(guide, output_file) if generate?(guide, output_file) + def generate_guides + guides_to_generate.each do |guide| + output_file = output_file_for(guide) + generate_guide(guide, output_file) if generate?(guide, output_file) + end end - end - def guides_to_generate - guides = Dir.entries(source_dir).grep(GUIDES_RE) + def guides_to_generate + guides = Dir.entries(source_dir).grep(GUIDES_RE) - if kindle? - Dir.entries("#{source_dir}/kindle").grep(GUIDES_RE).map do |entry| - next if entry == 'KINDLE.md' - guides << "kindle/#{entry}" + if kindle? + Dir.entries("#{source_dir}/kindle").grep(GUIDES_RE).map do |entry| + next if entry == "KINDLE.md" + guides << "kindle/#{entry}" + end end + + ENV.key?("ONLY") ? select_only(guides) : guides end - ENV.key?('ONLY') ? select_only(guides) : guides - end + def select_only(guides) + prefixes = ENV["ONLY"].split(",").map(&:strip) + guides.select do |guide| + guide.start_with?("kindle".freeze, *prefixes) + end + end - def select_only(guides) - prefixes = ENV['ONLY'].split(",").map(&:strip) - guides.select do |guide| - guide.start_with?('kindle'.freeze, *prefixes) + def copy_assets + FileUtils.cp_r(Dir.glob("#{guides_dir}/assets/*"), output_dir) end - end - def copy_assets - FileUtils.cp_r(Dir.glob("#{guides_dir}/assets/*"), output_dir) - end + def output_file_for(guide) + if guide.end_with?(".md") + guide.sub(/md\z/, "html") + else + guide.sub(/\.erb\z/, "") + end + end - def output_file_for(guide) - if guide.end_with?('.md') - guide.sub(/md\z/, 'html') - else - guide.sub(/\.erb\z/, '') + def output_path_for(output_file) + File.join(output_dir, File.basename(output_file)) end - end - def output_path_for(output_file) - File.join(output_dir, File.basename(output_file)) - end + def generate?(source_file, output_file) + fin = File.join(source_dir, source_file) + fout = output_path_for(output_file) + all || !File.exist?(fout) || File.mtime(fout) < File.mtime(fin) + end - def generate?(source_file, output_file) - fin = File.join(source_dir, source_file) - fout = output_path_for(output_file) - all || !File.exist?(fout) || File.mtime(fout) < File.mtime(fin) - end + def generate_guide(guide, output_file) + output_path = output_path_for(output_file) + puts "Generating #{guide} as #{output_file}" + layout = kindle? ? "kindle/layout" : "layout" - def generate_guide(guide, output_file) - output_path = output_path_for(output_file) - puts "Generating #{guide} as #{output_file}" - layout = kindle? ? 'kindle/layout' : 'layout' + File.open(output_path, "w") do |f| + view = ActionView::Base.new(source_dir, edge: @edge, version: @version, mobi: "kindle/#{mobi}", lang: @lang) + view.extend(Helpers) - File.open(output_path, 'w') do |f| - view = ActionView::Base.new(source_dir, :edge => @edge, :version => @version, :mobi => "kindle/#{mobi}", :lang => @lang) - view.extend(Helpers) + if guide =~ /\.(\w+)\.erb$/ + # Generate the special pages like the home. + # Passing a template handler in the template name is deprecated. So pass the file name without the extension. + result = view.render(layout: layout, formats: [$1], file: $`) + else + body = File.read(File.join(source_dir, guide)) + result = RailsGuides::Markdown.new(view, layout).render(body) - if guide =~ /\.(\w+)\.erb$/ - # Generate the special pages like the home. - # Passing a template handler in the template name is deprecated. So pass the file name without the extension. - result = view.render(:layout => layout, :formats => [$1], :file => $`) - else - body = File.read(File.join(source_dir, guide)) - result = RailsGuides::Markdown.new(view, layout).render(body) + warn_about_broken_links(result) if @warnings + end - warn_about_broken_links(result) if @warnings + f.write(result) end - - f.write(result) end - end - def warn_about_broken_links(html) - anchors = extract_anchors(html) - check_fragment_identifiers(html, anchors) - end + def warn_about_broken_links(html) + anchors = extract_anchors(html) + check_fragment_identifiers(html, anchors) + end - def extract_anchors(html) - # Markdown generates headers with IDs computed from titles. - anchors = Set.new - html.scan(/<h\d\s+id="([^"]+)/).flatten.each do |anchor| - if anchors.member?(anchor) - puts "*** DUPLICATE ID: #{anchor}, please make sure that there're no headings with the same name at the same level." - else - anchors << anchor + def extract_anchors(html) + # Markdown generates headers with IDs computed from titles. + anchors = Set.new + html.scan(/<h\d\s+id="([^"]+)/).flatten.each do |anchor| + if anchors.member?(anchor) + puts "*** DUPLICATE ID: #{anchor}, please make sure that there're no headings with the same name at the same level." + else + anchors << anchor + end end - end - # Footnotes. - anchors += Set.new(html.scan(/<p\s+class="footnote"\s+id="([^"]+)/).flatten) - anchors += Set.new(html.scan(/<sup\s+class="footnote"\s+id="([^"]+)/).flatten) - return anchors - end + # Footnotes. + anchors += Set.new(html.scan(/<p\s+class="footnote"\s+id="([^"]+)/).flatten) + anchors += Set.new(html.scan(/<sup\s+class="footnote"\s+id="([^"]+)/).flatten) + return anchors + end - def check_fragment_identifiers(html, anchors) - html.scan(/<a\s+href="#([^"]+)/).flatten.each do |fragment_identifier| - next if fragment_identifier == 'mainCol' # in layout, jumps to some DIV - unless anchors.member?(fragment_identifier) - guess = anchors.min { |a, b| - Levenshtein.distance(fragment_identifier, a) <=> Levenshtein.distance(fragment_identifier, b) - } - puts "*** BROKEN LINK: ##{fragment_identifier}, perhaps you meant ##{guess}." + def check_fragment_identifiers(html, anchors) + html.scan(/<a\s+href="#([^"]+)/).flatten.each do |fragment_identifier| + next if fragment_identifier == "mainCol" # in layout, jumps to some DIV + unless anchors.member?(fragment_identifier) + guess = anchors.min { |a, b| + Levenshtein.distance(fragment_identifier, a) <=> Levenshtein.distance(fragment_identifier, b) + } + puts "*** BROKEN LINK: ##{fragment_identifier}, perhaps you meant ##{guess}." + end end end - end end end diff --git a/guides/rails_guides/helpers.rb b/guides/rails_guides/helpers.rb index 5bf73da16c..888b51b1ef 100644 --- a/guides/rails_guides/helpers.rb +++ b/guides/rails_guides/helpers.rb @@ -1,13 +1,13 @@ -require 'yaml' +require "yaml" module RailsGuides module Helpers def guide(name, url, options = {}, &block) - link = content_tag(:a, :href => url) { name } + link = content_tag(:a, href: url) { name } result = content_tag(:dt, link) if options[:work_in_progress] - result << content_tag(:dd, 'Work in progress', :class => 'work-in-progress') + result << content_tag(:dd, "Work in progress", class: "work-in-progress") end result << content_tag(:dd, capture(&block)) @@ -19,30 +19,30 @@ module RailsGuides end def documents_flat - documents_by_section.flat_map {|section| section['documents']} + documents_by_section.flat_map { |section| section["documents"] } end def finished_documents(documents) - documents.reject { |document| document['work_in_progress'] } + documents.reject { |document| document["work_in_progress"] } end def docs_for_menu(position=nil) if position.nil? documents_by_section - elsif position == 'L' + elsif position == "L" documents_by_section.to(3) else documents_by_section.from(4) end end - def author(name, nick, image = 'credits_pic_blank.gif', &block) + def author(name, nick, image = "credits_pic_blank.gif", &block) image = "images/#{image}" - result = tag(:img, :src => image, :class => 'left pic', :alt => name, :width => 91, :height => 91) + result = tag(:img, src: image, class: "left pic", alt: name, width: 91, height: 91) result << content_tag(:h3, name) result << content_tag(:p, capture(&block)) - content_tag(:div, result, :class => 'clearfix', :id => nick) + content_tag(:div, result, class: "clearfix", id: nick) end def code(&block) diff --git a/guides/rails_guides/indexer.rb b/guides/rails_guides/indexer.rb index 89fbccbb1d..56df6a5842 100644 --- a/guides/rails_guides/indexer.rb +++ b/guides/rails_guides/indexer.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/string/inflections' +require "active_support/core_ext/object/blank" +require "active_support/core_ext/string/inflections" module RailsGuides class Indexer @@ -17,52 +17,52 @@ module RailsGuides private - def process(string, current_level=3, counters=[1]) - s = StringScanner.new(string) + def process(string, current_level=3, counters=[1]) + s = StringScanner.new(string) - level_hash = {} + level_hash = {} - while !s.eos? - re = %r{^h(\d)(?:\((#.*?)\))?\s*\.\s*(.*)$} - s.match?(re) - if matched = s.matched - matched =~ re - level, idx, title = $1.to_i, $2, $3.strip + while !s.eos? + re = %r{^h(\d)(?:\((#.*?)\))?\s*\.\s*(.*)$} + s.match?(re) + if matched = s.matched + matched =~ re + level, idx, title = $1.to_i, $2, $3.strip - if level < current_level - # This is needed. Go figure. - return level_hash - elsif level == current_level - index = counters.join(".") - idx ||= '#' + title_to_idx(title) + if level < current_level + # This is needed. Go figure. + return level_hash + elsif level == current_level + index = counters.join(".") + idx ||= "#" + title_to_idx(title) - raise "Parsing Fail" unless @result.sub!(matched, "h#{level}(#{idx}). #{index} #{title}") + raise "Parsing Fail" unless @result.sub!(matched, "h#{level}(#{idx}). #{index} #{title}") - key = { - :title => title, - :id => idx - } - # Recurse - counters << 1 - level_hash[key] = process(s.post_match, current_level + 1, counters) - counters.pop + key = { + title: title, + id: idx + } + # Recurse + counters << 1 + level_hash[key] = process(s.post_match, current_level + 1, counters) + counters.pop - # Increment the current level - last = counters.pop - counters << last + 1 + # Increment the current level + last = counters.pop + counters << last + 1 + end end + s.getch end - s.getch + level_hash end - level_hash - end - def title_to_idx(title) - idx = title.strip.parameterize.sub(/^\d+/, '') - if warnings && idx.blank? - puts "BLANK ID: please put an explicit ID for section #{title}, as in h5(#my-id)" + def title_to_idx(title) + idx = title.strip.parameterize.sub(/^\d+/, "") + if warnings && idx.blank? + puts "BLANK ID: please put an explicit ID for section #{title}, as in h5(#my-id)" + end + idx end - idx - end end end diff --git a/guides/rails_guides/kindle.rb b/guides/rails_guides/kindle.rb index 081afcb09f..6fb8183cb1 100644 --- a/guides/rails_guides/kindle.rb +++ b/guides/rails_guides/kindle.rb @@ -1,26 +1,26 @@ #!/usr/bin/env ruby -unless `which kindlerb` +unless `which kindlerb` abort "Please gem install kindlerb" end -require 'nokogiri' -require 'fileutils' -require 'yaml' -require 'date' +require "nokogiri" +require "fileutils" +require "yaml" +require "date" module Kindle extend self def generate(output_dir, mobi_outfile, logfile) output_dir = File.absolute_path(output_dir) - Dir.chdir output_dir do + Dir.chdir output_dir do puts "=> Using output dir: #{output_dir}" puts "=> Arranging html pages in document order" toc = File.read("toc.ncx") - doc = Nokogiri::XML(toc).xpath("//ncx:content", 'ncx' => "http://www.daisy.org/z3986/2005/ncx/") - html_pages = doc.select {|c| c[:src]}.map {|c| c[:src]}.uniq - + doc = Nokogiri::XML(toc).xpath("//ncx:content", "ncx" => "http://www.daisy.org/z3986/2005/ncx/") + html_pages = doc.select { |c| c[:src] }.map { |c| c[:src] }.uniq + generate_front_matter(html_pages) generate_sections(html_pages) @@ -37,26 +37,26 @@ module Kindle def generate_front_matter(html_pages) frontmatter = [] - html_pages.delete_if {|x| + html_pages.delete_if { |x| if x =~ /(toc|welcome|credits|copyright).html/ frontmatter << x unless x =~ /toc/ true end } - html = frontmatter.map {|x| + html = frontmatter.map { |x| Nokogiri::HTML(File.open(x)).at("body").inner_html }.join("\n") fdoc = Nokogiri::HTML(html) fdoc.search("h3").each do |h3| - h3.name = 'h4' + h3.name = "h4" end - fdoc.search("h2").each do |h2| - h2.name = 'h3' - h2['id'] = h2.inner_text.gsub(/\s/, '-') + fdoc.search("h2").each do |h2| + h2.name = "h3" + h2["id"] = h2.inner_text.gsub(/\s/, "-") end add_head_section fdoc, "Front Matter" - File.open("frontmatter.html",'w') {|f| f.puts fdoc.to_html} + File.open("frontmatter.html","w") { |f| f.puts fdoc.to_html } html_pages.unshift "frontmatter.html" end @@ -65,20 +65,20 @@ module Kindle html_pages.each_with_index do |page, section_idx| FileUtils::mkdir_p("sections/%03d" % section_idx) doc = Nokogiri::HTML(File.open(page)) - title = doc.at("title").inner_text.gsub("Ruby on Rails Guides: ", '') - title = page.capitalize.gsub('.html', '') if title.strip == '' - File.open("sections/%03d/_section.txt" % section_idx, 'w') {|f| f.puts title} + title = doc.at("title").inner_text.gsub("Ruby on Rails Guides: ", "") + title = page.capitalize.gsub(".html", "") if title.strip == "" + File.open("sections/%03d/_section.txt" % section_idx, "w") { |f| f.puts title } doc.xpath("//h3[@id]").each_with_index do |h3,item_idx| subsection = h3.inner_text - content = h3.xpath("./following-sibling::*").take_while {|x| x.name != "h3"}.map(&:to_html) + content = h3.xpath("./following-sibling::*").take_while { |x| x.name != "h3" }.map(&:to_html) item = Nokogiri::HTML(h3.to_html + content.join("\n")) - item_path = "sections/%03d/%03d.html" % [section_idx, item_idx] + item_path = "sections/%03d/%03d.html" % [section_idx, item_idx] add_head_section(item, subsection) item.search("img").each do |img| - img['src'] = "#{Dir.pwd}/#{img['src']}" + img["src"] = "#{Dir.pwd}/#{img['src']}" end - item.xpath("//li/p").each {|p| p.swap(p.children); p.remove} - File.open(item_path, 'w') {|f| f.puts item.to_html} + item.xpath("//li/p").each { |p| p.swap(p.children); p.remove } + File.open(item_path, "w") { |f| f.puts item.to_html } end end end @@ -87,21 +87,21 @@ module Kindle puts "=> Generating _document.yml" x = Nokogiri::XML(File.open("rails_guides.opf")).remove_namespaces! cover_jpg = "#{Dir.pwd}/images/rails_guides_kindle_cover.jpg" - cover_gif = cover_jpg.sub(/jpg$/, 'gif') + cover_gif = cover_jpg.sub(/jpg$/, "gif") puts `convert #{cover_jpg} #{cover_gif}` document = { - 'doc_uuid' => x.at("package")['unique-identifier'], - 'title' => x.at("title").inner_text.gsub(/\(.*$/, " v2"), - 'publisher' => x.at("publisher").inner_text, - 'author' => x.at("creator").inner_text, - 'subject' => x.at("subject").inner_text, - 'date' => x.at("date").inner_text, - 'cover' => cover_gif, - 'masthead' => nil, - 'mobi_outfile' => mobi_outfile + "doc_uuid" => x.at("package")["unique-identifier"], + "title" => x.at("title").inner_text.gsub(/\(.*$/, " v2"), + "publisher" => x.at("publisher").inner_text, + "author" => x.at("creator").inner_text, + "subject" => x.at("subject").inner_text, + "date" => x.at("date").inner_text, + "cover" => cover_gif, + "masthead" => nil, + "mobi_outfile" => mobi_outfile } puts document.to_yaml - File.open("_document.yml", 'w'){|f| f.puts document.to_yaml} + File.open("_document.yml", "w") { |f| f.puts document.to_yaml } end def add_head_section(doc, title) @@ -110,9 +110,9 @@ module Kindle title_node.content = title title_node.parent = head css = Nokogiri::XML::Node.new "link", doc - css['rel'] = 'stylesheet' - css['type'] = 'text/css' - css['href'] = "#{Dir.pwd}/stylesheets/kindle.css" + css["rel"] = "stylesheet" + css["type"] = "text/css" + css["href"] = "#{Dir.pwd}/stylesheets/kindle.css" css.parent = head doc.at("body").before head end diff --git a/guides/rails_guides/levenshtein.rb b/guides/rails_guides/levenshtein.rb index 049f633258..e947150364 100644 --- a/guides/rails_guides/levenshtein.rb +++ b/guides/rails_guides/levenshtein.rb @@ -1,8 +1,10 @@ module RailsGuides module Levenshtein - # This code is based directly on the Text gem implementation + # This code is based directly on the Text gem implementation. + # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher. + # # Returns a value representing the "cost" of transforming str1 into str2 - def self.distance str1, str2 + def self.distance(str1, str2) s = str1 t = str2 n = s.length diff --git a/guides/rails_guides/markdown.rb b/guides/rails_guides/markdown.rb index 69c7cd5136..009e5aff99 100644 --- a/guides/rails_guides/markdown.rb +++ b/guides/rails_guides/markdown.rb @@ -1,6 +1,6 @@ -require 'redcarpet' -require 'nokogiri' -require 'rails_guides/markdown/renderer' +require "redcarpet" +require "nokogiri" +require "rails_guides/markdown/renderer" module RailsGuides class Markdown @@ -8,7 +8,7 @@ module RailsGuides @view = view @layout = layout @index_counter = Hash.new(0) - @raw_header = '' + @raw_header = "" @node_ids = {} end @@ -47,21 +47,20 @@ module RailsGuides def dom_id_text(text) escaped_chars = Regexp.escape('\\/`*_{}[]()#+-.!:,;|&<>^~=\'"') - text.downcase.gsub(/\?/, '-questionmark') - .gsub(/!/, '-bang') - .gsub(/[#{escaped_chars}]+/, ' ').strip - .gsub(/\s+/, '-') + text.downcase.gsub(/\?/, "-questionmark") + .gsub(/!/, "-bang") + .gsub(/[#{escaped_chars}]+/, " ").strip + .gsub(/\s+/, "-") end def engine - @engine ||= Redcarpet::Markdown.new(Renderer, { + @engine ||= Redcarpet::Markdown.new(Renderer, no_intra_emphasis: true, fenced_code_blocks: true, autolink: true, strikethrough: true, superscript: true, - tables: true - }) + tables: true) end def extract_raw_header_and_body @@ -87,15 +86,15 @@ module RailsGuides doc.children.each do |node| if node.name =~ /^h[3-6]$/ case node.name - when 'h3' + when "h3" hierarchy = [node] @headings_for_index << [1, node, node.inner_html] - when 'h4' + when "h4" hierarchy = hierarchy[0, 1] + [node] @headings_for_index << [2, node, node.inner_html] - when 'h5' + when "h5" hierarchy = hierarchy[0, 2] + [node] - when 'h6' + when "h6" hierarchy = hierarchy[0, 3] + [node] end @@ -109,7 +108,7 @@ module RailsGuides def generate_index if @headings_for_index.present? - raw_index = '' + raw_index = "" @headings_for_index.each do |level, node, label| if level == 1 raw_index += "1. [#{label}](##{node[:id]})\n" @@ -119,7 +118,7 @@ module RailsGuides end @index = Nokogiri::HTML.fragment(engine.render(raw_index)).tap do |doc| - doc.at('ol')[:class] = 'chapters' + doc.at("ol")[:class] = "chapters" end.to_html @index = <<-INDEX.html_safe @@ -159,7 +158,7 @@ module RailsGuides @view.content_for(:header_section) { @header } @view.content_for(:page_title) { @title } @view.content_for(:index_section) { @index } - @view.render(:layout => @layout, :text => @body) + @view.render(layout: @layout, html: @body.html_safe) end end end diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb index 73ca600361..eebd9ac730 100644 --- a/guides/rails_guides/markdown/renderer.rb +++ b/guides/rails_guides/markdown/renderer.rb @@ -25,7 +25,7 @@ HTML def paragraph(text) if text =~ /^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:]/ convert_notes(text) - elsif text.include?('DO NOT READ THIS FILE ON GITHUB') + elsif text.include?("DO NOT READ THIS FILE ON GITHUB") elsif text =~ /^\[<sup>(\d+)\]:<\/sup> (.+)$/ linkback = %(<a href="#footnote-#{$1}-ref"><sup>#{$1}</sup></a>) %(<p class="footnote" id="footnote-#{$1}">#{linkback} #{$2}</p>) @@ -46,14 +46,14 @@ HTML def brush_for(code_type) case code_type - when 'ruby', 'sql', 'plain' - code_type - when 'erb', 'html+erb' - 'ruby; html-script: true' - when 'html' - 'xml' # HTML is understood, but there are .xml rules in the CSS - else - 'plain' + when "ruby", "sql", "plain" + code_type + when "erb", "html+erb" + "ruby; html-script: true" + when "html" + "xml" # HTML is understood, but there are .xml rules in the CSS + else + "plain" end end @@ -67,14 +67,15 @@ HTML # as a list item, but as a paragraph starting with a plain # asterisk. body.gsub(/^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:](.*?)(\n(?=\n)|\Z)/m) do - css_class = case $1 - when 'CAUTION', 'IMPORTANT' - 'warning' - when 'TIP' - 'info' - else - $1.downcase - end + css_class = \ + case $1 + when "CAUTION", "IMPORTANT" + "warning" + when "TIP" + "info" + else + $1.downcase + end %(<div class="#{css_class}"><p>#{$2.strip}</p></div>) end end diff --git a/guides/source/2_2_release_notes.md b/guides/source/2_2_release_notes.md index 79634d8760..ac5833e069 100644 --- a/guides/source/2_2_release_notes.md +++ b/guides/source/2_2_release_notes.md @@ -34,7 +34,7 @@ Documentation The internal documentation of Rails, in the form of code comments, has been improved in numerous places. In addition, the [Ruby on Rails Guides](http://guides.rubyonrails.org/) project is the definitive source for information on major Rails components. In its first official release, the Guides page includes: * [Getting Started with Rails](getting_started.html) -* [Rails Database Migrations](migrations.html) +* [Rails Database Migrations](active_record_migrations.html) * [Active Record Associations](association_basics.html) * [Active Record Query Interface](active_record_querying.html) * [Layouts and Rendering in Rails](layouts_and_rendering.html) @@ -45,7 +45,6 @@ The internal documentation of Rails, in the form of code comments, has been impr * [A Guide to Testing Rails Applications](testing.html) * [Securing Rails Applications](security.html) * [Debugging Rails Applications](debugging_rails_applications.html) -* [Performance Testing Rails Applications](performance_testing.html) * [The Basics of Creating Rails Plugins](plugins.html) All told, the Guides provide tens of thousands of words of guidance for beginning and intermediate Rails developers. diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 06761b67bb..6976848e95 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -54,7 +54,7 @@ Documentation The [Ruby on Rails guides](http://guides.rubyonrails.org/) project has published several additional guides for Rails 2.3. In addition, a [separate site](http://edgeguides.rubyonrails.org/) maintains updated copies of the Guides for Edge Rails. Other documentation efforts include a relaunch of the [Rails wiki](http://newwiki.rubyonrails.org/) and early planning for a Rails Book. -* More Information: [Rails Documentation Projects](http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects.) +* More Information: [Rails Documentation Projects](http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects) Ruby 1.9.1 Support ------------------ diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index 49d37ba489..517b38be07 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -155,7 +155,7 @@ Documentation The documentation in the Rails tree is being updated with all the API changes, additionally, the [Rails Edge Guides](http://edgeguides.rubyonrails.org/) are being updated one by one to reflect the changes in Rails 3.0. The guides at [guides.rubyonrails.org](http://guides.rubyonrails.org/) however will continue to contain only the stable version of Rails (at this point, version 2.3.5, until 3.0 is released). -More Information: - [Rails Documentation Projects](http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects.) +More Information: - [Rails Documentation Projects](http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects) Internationalization diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md index feee0f9920..fd90cf9886 100644 --- a/guides/source/3_1_release_notes.md +++ b/guides/source/3_1_release_notes.md @@ -99,7 +99,7 @@ gem 'jquery-rails' # config.assets.manifest = YOUR_PATH # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) - # config.assets.precompile `= %w( search.js ) + # config.assets.precompile `= %w( admin.js admin.css ) # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md index 8bd2074e82..a98f7be067 100644 --- a/guides/source/5_0_release_notes.md +++ b/guides/source/5_0_release_notes.md @@ -49,13 +49,38 @@ client-side JavaScript framework and a server-side Ruby framework. You have access to your full domain model written with Active Record or your ORM of choice. -See the [Active Cable Overview](action_cable_overview.html) guide for more +See the [Action Cable Overview](action_cable_overview.html) guide for more information. -### Rails API -[Pull Request](https://github.com/rails/rails/pull/19832) +### API Applications -ToDo... +Rails can now be used to create slimmed down API only applications. +This is useful for creating and serving APIs similar to [Twitter](https://dev.twitter.com) or [GitHub](http://developer.github.com) API, +that can be used to serve public facing, as well as, for custom applications. + +You can generate a new api Rails app using: + +```bash +$ rails new my_api --api +``` + +This will do three main things: + +- Configure your application to start with a more limited set of middleware + than normal. Specifically, it will not include any middleware primarily useful + for browser applications (like cookies support) by default. +- Make `ApplicationController` inherit from `ActionController::API` instead of + `ActionController::Base`. As with middleware, this will leave out any Action + Controller modules that provide functionalities primarily used by browser + applications. +- Configure the generators to skip generating views, helpers and assets when + you generate a new resource. + +The application provides a base for APIs, +that can then be [configured to pull in functionality](api_app.html) as suitable for the application's needs. + +See the [Using Rails for API-only Applications](api_app.html) guide for more +information. ### Active Record attributes API @@ -65,9 +90,10 @@ It also changes the behavior of values passed to `ActiveRecord::Base.where`, whi without having to rely on implementation details or monkey patching. Some things that you can achieve with this: -* The type detected by Active Record can be overridden. -* A default can also be provided. -* Attributes do not need to be backed by a database column. + +- The type detected by Active Record can be overridden. +- A default can also be provided. +- Attributes do not need to be backed by a database column. ```ruby @@ -99,14 +125,14 @@ store_listing.price_in_cents # => 10 StoreListing.new.my_string # => "new default" StoreListing.new.my_default_proc # => 2015-05-30 11:04:48 -0600 model = StoreListing.new(field_without_db_column: ["1", "2", "3"]) -model.attributes #=> {field_without_db_column: [1, 2, 3]} +model.attributes # => {field_without_db_column: [1, 2, 3]} ``` **Creating Custom Types:** You can define your own custom types, as long as they respond -to the methods defined on the value type. The method +deserialize+ or -+cast+ will be called on your type object, with raw input from the +to the methods defined on the value type. The method `deserialize` or +`cast` will be called on your type object, with raw input from the database or from your controllers. This is useful, for example, when doing custom conversion, like Money data. @@ -114,7 +140,7 @@ like Money data. When `ActiveRecord::Base.where` is called, it will use the type defined by the model class to convert the value to SQL, -calling +serialize+ on your type object. +calling `serialize` on your type object. This gives the objects ability to specify, how to convert values when performing SQL queries. @@ -129,10 +155,23 @@ for a detailed write up. ### Test Runner -[Pull Request](https://github.com/rails/rails/pull/19216) -ToDo... +A new test runner has been introduced to enhance the capabilities of running tests from Rails. +To use this test runner simply type `bin/rails test`. +Test Runner is inspired from `RSpec`, `minitest-reporters`, `maxitest` and others. +It includes some of these notable advancements: + +- Run a single test using line number of test. +- Run multiple tests pinpointing to line number of tests. +- Improved failure messages, which also add ease of re-running failed tests. +- Fail fast using `-f` option, to stop tests immediately on occurrence of failure, +instead of waiting for the suite to complete. +- Defer test output until the end of a full test run using the `-d` option. +- Complete exception backtrace output using `-b` option. +- Integration with `Minitest` to allow options like `-s` for test seed data, +`-n` for running specific test by name, `-v` for better verbose output and so forth. +- Colored test output. Railties -------- @@ -167,13 +206,13 @@ Please refer to the [Changelog][railties] for detailed changes. * Deprecated `config.static_cache_control` in favor of `config.public_file_server.headers`. - ([Pull Request](https://github.com/rails/rails/pull/22173)) + ([Pull Request](https://github.com/rails/rails/pull/19135)) * Deprecated `config.serve_static_files` in favor of `config.public_file_server.enabled`. ([Pull Request](https://github.com/rails/rails/pull/22173)) * Deprecated the tasks in the `rails` task namespace in favor of the `app` namespace. - (e.g. `rails:update` and `rails:template` tasks is renamed to `app:update` and `app:template`.) + (e.g. `rails:update` and `rails:template` tasks are renamed to `app:update` and `app:template`.) ([Pull Request](https://github.com/rails/rails/pull/23439)) ### Notable changes @@ -219,7 +258,6 @@ Please refer to the [Changelog][railties] for detailed changes. Spring to watch additional common files. ([commit](https://github.com/rails/rails/commit/b04d07337fd7bc17e88500e9d6bcd361885a45f8)) - * Added `--skip-action-mailer` to skip Action Mailer while generating new app. ([Pull Request](https://github.com/rails/rails/pull/18288)) @@ -229,6 +267,9 @@ Please refer to the [Changelog][railties] for detailed changes. * Changed `_form.html.erb` generated by scaffold generator to use local variables. ([Pull Request](https://github.com/rails/rails/pull/13434)) +* Disabled autoloading of classes in production environment. + ([commit](https://github.com/rails/rails/commit/a71350cae0082193ad8c66d65ab62e8bb0b7853b)) + Action Pack ----------- @@ -320,6 +361,15 @@ Please refer to the [Changelog][action-pack] for detailed changes. * Deprecated `:controller` and `:action` path parameters. ([Pull Request](https://github.com/rails/rails/pull/23980)) +* Deprecated env method on controller instances. + ([commit](https://github.com/rails/rails/commit/05934d24aff62d66fc62621aa38dae6456e276be)) + +* `ActionDispatch::ParamsParser` is deprecated and was removed from the + middleware stack. To configure the parameter parsers use + `ActionDispatch::Request.parameter_parsers=`. + ([commit](https://github.com/rails/rails/commit/38d2bf5fd1f3e014f2397898d371c339baa627b1), + [commit](https://github.com/rails/rails/commit/5ed38014811d4ce6d6f957510b9153938370173b)) + ### Notable changes * Added `ActionController::Renderer` to render arbitrary templates @@ -367,7 +417,7 @@ Please refer to the [Changelog][action-pack] for detailed changes. `ActionDispatch::IntegrationTest` instead. ([commit](https://github.com/rails/rails/commit/4414c5d1795e815b102571425974a8b1d46d932d)) -* Rails will only generate "weak", instead of strong ETags. +* Rails generates weak ETags by default. ([Pull Request](https://github.com/rails/rails/pull/17573)) * Controller actions without an explicit `render` call and with no @@ -382,11 +432,6 @@ Please refer to the [Changelog][action-pack] for detailed changes. * Added request encoding and response parsing to integration tests. ([Pull Request](https://github.com/rails/rails/pull/21671)) -* Update default rendering policies when the controller action did - not explicitly indicate a response. - ([Pull Request](https://github.com/rails/rails/pull/23827)) - - * Add `ActionController#helpers` to get access to the view context at the controller level. ([Pull Request](https://github.com/rails/rails/pull/24866)) @@ -394,6 +439,24 @@ Please refer to the [Changelog][action-pack] for detailed changes. * Discarded flash messages get removed before storing into session. ([Pull Request](https://github.com/rails/rails/pull/18721)) +* Added support for passing collection of records to `fresh_when` and + `stale?`. + ([Pull Request](https://github.com/rails/rails/pull/18374)) + +* `ActionController::Live` became an `ActiveSupport::Concern`. That + means it can't be just included in other modules without extending + them with `ActiveSupport::Concern` or `ActionController::Live` + won't take effect in production. Some people may be using another + module to include some special `Warden`/`Devise` authentication + failure handling code as well since the middleware can't catch a + `:warden` thrown by a spawned thread which is the case when using + `ActionController::Live`. + ([More details in this issue](https://github.com/rails/rails/issues/25581)) + +* Introduce `Response#strong_etag=` and `#weak_etag=` and analogous + options for `fresh_when` and `stale?`. + ([Pull Request](https://github.com/rails/rails/pull/24387)) + Action View ------------- @@ -413,13 +476,6 @@ Please refer to the [Changelog][action-view] for detailed changes. supported by I18n. ([Pull Request](https://github.com/rails/rails/pull/20019)) -### Deprecations - -* Deprecated `datetime_field` and `datetime_field_tag` helpers. - Datetime input type was removed from HTML specification. - One can use `datetime_local_field` and `datetime_local_field_tag` instead. - ([Pull Request](https://github.com/rails/rails/pull/24385)) - ### Notable Changes * Changed the default template handler from `ERB` to `Raw`. @@ -439,6 +495,10 @@ Please refer to the [Changelog][action-view] for detailed changes. * Partial template name no longer has to be a valid Ruby identifier. ([commit](https://github.com/rails/rails/commit/da9038e)) +* The `datetime_tag` helper now generates an input tag with the type of + `datetime-local`. + ([Pull Request](https://github.com/rails/rails/pull/25469)) + Action Mailer ------------- @@ -524,8 +584,10 @@ Please refer to the [Changelog][active-record] for detailed changes. [activemodel-serializers-xml](https://github.com/rails/activemodel-serializers-xml) gem. ([Pull Request](https://github.com/rails/rails/pull/21161)) -* Removed support for the legacy `mysql` database adapter from core. It will - live on in a separate gem for now, but most users should just use `mysql2`. +* Removed support for the legacy `mysql` database adapter from core. Most users should + be able to use `mysql2`. It will be converted to a separate gem when when we find someone + to maintain it. ([Pull Request 1](https://github.com/rails/rails/pull/22642), + [Pull Request 2](https://github.com/rails/rails/pull/22715)) * Removed support for the `protected_attributes` gem. ([commit](https://github.com/rails/rails/commit/f4fbc0301021f13ae05c8e941c8efc4ae351fdf9)) @@ -536,6 +598,9 @@ Please refer to the [Changelog][active-record] for detailed changes. * Removed support for `activerecord-deprecated_finders` gem. ([commit](https://github.com/rails/rails/commit/78dab2a8569408658542e462a957ea5a35aa4679)) +* Removed `ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES` constant. + ([commit](https://github.com/rails/rails/commit/a502703c3d2151d4d3b421b29fefdac5ad05df61)) + ### Deprecations * Deprecated passing a class as a value in a query. Users should pass strings @@ -597,6 +662,14 @@ Please refer to the [Changelog][active-record] for detailed changes. `use_transactional_tests` for more clarity. ([Pull Request](https://github.com/rails/rails/pull/19282)) +* Deprecated passing a column to `ActiveRecord::Connection#quote`. + ([commit](https://github.com/rails/rails/commit/7bb620869725ad6de603f6a5393ee17df13aa96c)) + +* Added an option `end` to `find_in_batches` that complements the `start` + parameter to specify where to stop batch processing. + ([Pull Request](https://github.com/rails/rails/pull/12257)) + + ### Notable changes * Added a `foreign_key` option to `references` while creating the table. @@ -631,9 +704,6 @@ Please refer to the [Changelog][active-record] for detailed changes. operator to combine WHERE or HAVING clauses. ([commit](https://github.com/rails/rails/commit/b0b37942d729b6bdcd2e3178eda7fa1de203b3d0)) -* Added `:time` option added for `#touch`. - ([Pull Request](https://github.com/rails/rails/pull/18956)) - * Added `ActiveRecord::Base.suppress` to prevent the receiver from being saved during the given block. ([Pull Request](https://github.com/rails/rails/pull/18910)) @@ -719,6 +789,29 @@ Please refer to the [Changelog][active-record] for detailed changes. * Added `:index_errors` option to add indexes to errors of nested attributes. ([Pull Request](https://github.com/rails/rails/pull/19686)) +* Added support for bidirectional destroy dependencies. + ([Pull Request](https://github.com/rails/rails/pull/18548)) + +* Added support for `after_commit` callbacks in transactional tests. + ([Pull Request](https://github.com/rails/rails/pull/18458)) + +* Added `foreign_key_exists?` method to see if a foreign key exists on a table + or not. + ([Pull Request](https://github.com/rails/rails/pull/18662)) + +* Added `:time` option to `touch` method to touch records with different time + than the current time. + ([Pull Request](https://github.com/rails/rails/pull/18956)) + +* Change transaction callbacks to not swallow errors. + Before this change any errors raised inside a transaction callback + were getting rescued and printed in the logs, unless you used + the (newly deprecated) `raise_in_transactional_callbacks = true` option. + + Now these errors are not rescued anymore and just bubble up, matching the + behavior of other callbacks. + ([commit](https://github.com/rails/rails/commit/07d3d402341e81ada0214f2cb2be1da69eadfe72)) + Active Model ------------ @@ -772,6 +865,9 @@ Please refer to the [Changelog][active-model] for detailed changes. * Validate multiple contexts on `valid?` and `invalid?` at once. ([Pull Request](https://github.com/rails/rails/pull/21069)) +* Change `validates_acceptance_of` to accept `true` as default value + apart from `1`. + ([Pull Request](https://github.com/rails/rails/pull/18439)) Active Job ----------- @@ -873,8 +969,10 @@ Please refer to the [Changelog][active-support] for detailed changes. `ActiveSupport::Cache::MemCachedStore#escape_key`, and `ActiveSupport::Cache::FileStore#key_file_path`. Use `normalize_key` instead. + ([Pull Request](https://github.com/rails/rails/pull/22215), + [commit](https://github.com/rails/rails/commit/a8f773b0)) - Deprecated `ActiveSupport::Cache::LocaleCache#set_cache_value` in favor of `write_cache_value`. +* Deprecated `ActiveSupport::Cache::LocaleCache#set_cache_value` in favor of `write_cache_value`. ([Pull Request](https://github.com/rails/rails/pull/22215)) * Deprecated passing arguments to `assert_nothing_raised`. @@ -905,7 +1003,8 @@ Please refer to the [Changelog][active-support] for detailed changes. * Added `#on_weekend?`, `#on_weekday?`, `#next_weekday`, `#prev_weekday` methods to `Date`, `Time`, and `DateTime`. - ([Pull Request](https://github.com/rails/rails/pull/18335)) + ([Pull Request](https://github.com/rails/rails/pull/18335), + [Pull Request](https://github.com/rails/rails/pull/23687)) * Added `same_time` option to `#next_week` and `#prev_week` for `Date`, `Time`, and `DateTime`. @@ -913,7 +1012,7 @@ Please refer to the [Changelog][active-support] for detailed changes. * Added `#prev_day` and `#next_day` counterparts to `#yesterday` and `#tomorrow` for `Date`, `Time`, and `DateTime`. - ([Pull Request](httpshttps://github.com/rails/rails/pull/18335)) + ([Pull Request](https://github.com/rails/rails/pull/18335)) * Added `SecureRandom.base58` for generation of random base58 strings. ([commit](https://github.com/rails/rails/commit/b1093977110f18ae0cafe56c3d99fc22a7d54d1b)) @@ -956,9 +1055,6 @@ Please refer to the [Changelog][active-support] for detailed changes. * Added `Array#second_to_last` and `Array#third_to_last` methods. ([Pull Request](https://github.com/rails/rails/pull/23583)) -* Added `#on_weekday?` method to `Date`, `Time`, and `DateTime`. - ([Pull Request](https://github.com/rails/rails/pull/23687)) - * Publish `ActiveSupport::Executor` and `ActiveSupport::Reloader` APIs to allow components and libraries to manage, and participate in, the execution of application code, and the application reloading process. @@ -967,6 +1063,13 @@ Please refer to the [Changelog][active-support] for detailed changes. * `ActiveSupport::Duration` now supports ISO8601 formatting and parsing. ([Pull Request](https://github.com/rails/rails/pull/16917)) +* `ActiveSupport::JSON.decode` now supports parsing ISO8601 local times when + `parse_json_times` is enabled. + ([Pull Request](https://github.com/rails/rails/pull/23011)) + +* `ActiveSupport::JSON.decode` now return `Date` objects for date strings. + ([Pull Request](https://github.com/rails/rails/pull/23011)) + * Added ability to `TaggedLogging` to allow loggers to be instantiated multiple times so that they don't share tags with each other. ([Pull Request](https://github.com/rails/rails/pull/9065)) diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md index 16aa9438a2..3716aa0ecb 100644 --- a/guides/source/action_cable_overview.md +++ b/guides/source/action_cable_overview.md @@ -6,8 +6,12 @@ incorporate real-time features into your Rails application. After reading this guide, you will know: +* What Action Cable is and its integration on backend and frontend * How to setup Action Cable * How to setup channels +* Deployment and Architecture setup for running Action Cable + +-------------------------------------------------------------------------------- Introduction ------------ @@ -236,12 +240,12 @@ WebNotificationsChannel.broadcast_to( ``` The `WebNotificationsChannel.broadcast_to` call places a message in the current -subscription adapter (Redis by default)'s pubsub queue under a separate -broadcasting name for each user. For a user with an ID of 1, the broadcasting -name would be `web_notifications_1`. +subscription adapter (by default `redis` for production and `async` for development and +test environments)'s pubsub queue under a separate broadcasting name for each user. +For a user with an ID of 1, the broadcasting name would be `web_notifications:1`. The channel has been instructed to stream everything that arrives at -`web_notifications_1` directly to the client by invoking the `received` +`web_notifications:1` directly to the client by invoking the `received` callback. ### Subscriptions @@ -309,7 +313,7 @@ App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" }, ```ruby # Somewhere in your app this is called, perhaps # from a NewCommentJob. -ChatChannel.broadcast_to( +ActionCable.server.broadcast( "chat_#{room}", sent_by: 'Paul', body: 'This is a cool chat app.' @@ -329,7 +333,7 @@ class ChatChannel < ApplicationCable::Channel end def receive(data) - ChatChannel.broadcast_to("chat_#{params[:room]}", data) + ActionCable.server.broadcast("chat_#{params[:room]}", data) end end ``` @@ -418,7 +422,7 @@ App.cable.subscriptions.create "AppearanceChannel", buttonSelector = "[data-behavior~=appear_away]" install: -> - $(document).on "page:change.appearance", => + $(document).on "turbolinks:load.appearance", => @appear() $(document).on "click.appearance", buttonSelector, => @@ -506,10 +510,10 @@ WebNotificationsChannel.broadcast_to( The `WebNotificationsChannel.broadcast_to` call places a message in the current subscription adapter's pubsub queue under a separate broadcasting name for each user. For a user with an ID of 1, the broadcasting name would be -"web_notifications_1". +`web_notifications:1`. The channel has been instructed to stream everything that arrives at -"web_notifications_1" directly to the client by invoking the `received` +`web_notifications:1` directly to the client by invoking the `received` callback. The data passed as argument is the hash sent as the second parameter to the server-side broadcast call, JSON encoded for the trip across the wire, and unpacked for the data argument arriving to `received`. @@ -568,12 +572,13 @@ environment configuration files. ### Other Configurations -The other common option to configure is the log tags applied to the -per-connection logger. Here's close to what we're using in Basecamp: +The other common option to configure, is the log tags applied to the +per-connection logger. Here's an example that uses +the user account id if available, else "no-account" while tagging: ```ruby config.action_cable.log_tags = [ - -> request { request.env['bc.account_id'] || "no-account" }, + -> request { request.env['user_account_id'] || "no-account" }, :action_cable, -> request { request.uuid } ] diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 58362fea58..7b1138c7d4 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -362,7 +362,7 @@ If your user sessions don't store critical data or don't need to be around for l Read more about session storage in the [Security Guide](security.html). -If you need a different session storage mechanism, you can change it in the `config/initializers/session_store.rb` file: +If you need a different session storage mechanism, you can change it in an initializer: ```ruby # Use the database for sessions instead of the cookie-based default, @@ -371,7 +371,7 @@ If you need a different session storage mechanism, you can change it in the `con # Rails.application.config.session_store :active_record_store ``` -Rails sets up a session key (the name of the cookie) when signing the session data. These can also be changed in `config/initializers/session_store.rb`: +Rails sets up a session key (the name of the cookie) when signing the session data. These can also be changed in an initializer: ```ruby # Be sure to restart your server when you modify this file. diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index 7359438025..34847832fd 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -735,7 +735,7 @@ files (environment.rb, production.rb, etc...) |---------------|-------------| |`logger`|Generates information on the mailing run if available. Can be set to `nil` for no logging. Compatible with both Ruby's own `Logger` and `Log4r` loggers.| |`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default `"localhost"` setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain` (will send the password in the clear), `:login` (will send password Base64 encoded) or `:cram_md5` (combines a Challenge/Response mechanism to exchange information and a cryptographic Message Digest 5 algorithm to hash important information)</li><li>`:enable_starttls_auto` - Detects if STARTTLS is enabled in your SMTP server and starts to use it. Defaults to `true`.</li><li>`:openssl_verify_mode` - When using TLS, you can set how OpenSSL checks the certificate. This is really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name of an OpenSSL verify constant ('none' or 'peer') or directly the constant (`OpenSSL::SSL::VERIFY_NONE` or `OpenSSL::SSL::VERIFY_PEER`).</li></ul>| -|`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i -t`.</li></ul>| +|`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i`.</li></ul>| |`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered. This only works if the external email server is configured for immediate delivery.| |`delivery_method`|Defines a delivery method. Possible values are:<ul><li>`:smtp` (default), can be configured by using `config.action_mailer.smtp_settings`.</li><li>`:sendmail`, can be configured by using `config.action_mailer.sendmail_settings`.</li><li>`:file`: save emails to files; can be configured by using `config.action_mailer.file_settings`.</li><li>`:test`: save emails to `ActionMailer::Base.deliveries` array.</li></ul>See [API docs](http://api.rubyonrails.org/classes/ActionMailer/Base.html) for more info.| |`perform_deliveries`|Determines whether deliveries are actually carried out when the `deliver` method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| @@ -756,7 +756,7 @@ config.action_mailer.delivery_method = :sendmail # Defaults to: # config.action_mailer.sendmail_settings = { # location: '/usr/sbin/sendmail', -# arguments: '-i -t' +# arguments: '-i' # } config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index f68abbae3c..ff0127522b 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -254,12 +254,6 @@ as if we had written: <%= render partial: "product", locals: { product: @product } %> ``` -With the `as` option we can specify a different name for the local variable. For example, if we wanted it to be `item` instead of `product` we would do: - -```erb -<%= render partial: "product", as: "item" %> -``` - The `object` option can be used to directly specify which object is rendered into the partial; useful when the template's object is elsewhere (e.g. in a different instance variable or in a local variable). For example, instead of: @@ -274,12 +268,18 @@ we would do: <%= render partial: "product", object: @item %> ``` -The `object` and `as` options can also be used together: +With the `as` option we can specify a different name for the said local variable. For example, if we wanted it to be `item` instead of `product` we would do: ```erb <%= render partial: "product", object: @item, as: "item" %> ``` +This is equivalent to + +```erb +<%= render partial: "product", locals: { item: @item } %> +``` + #### Rendering Collections It is very common that a template will need to iterate over a collection and render a sub-template for each of the elements. This pattern has been implemented as a single method that accepts an array and renders a partial for each one of the elements in the array. @@ -1439,7 +1439,7 @@ Formats a number with the specified level of `precision`, which defaults to 3. ```ruby number_with_precision(111.2345) # => 111.235 -number_with_precision(111.2345, 2) # => 111.23 +number_with_precision(111.2345, precision: 2) # => 111.23 ``` ### SanitizeHelper diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md index c9f70dc87b..c65d1e6de5 100644 --- a/guides/source/active_job_basics.md +++ b/guides/source/active_job_basics.md @@ -34,8 +34,9 @@ Delayed Job and Resque. Picking your queuing backend becomes more of an operatio concern, then. And you'll be able to switch between them without having to rewrite your jobs. -NOTE: Rails by default comes with an "immediate runner" queuing implementation. -That means that each job that has been enqueued will run immediately. +NOTE: Rails by default comes with an asynchronous queuing implementation that +runs jobs with an in-process thread pool. Jobs will run asynchronously, but any +jobs in the queue will be dropped upon restart. Creating a Job @@ -109,7 +110,7 @@ That's it! Job Execution ------------- -For enqueuing and executing jobs in production you need to set up a queuing backend, +For enqueuing and executing jobs in production you need to set up a queuing backend, that is to say you need to decide for a 3rd-party queuing library that Rails should use. Rails itself only provides an in-process queuing system, which only keeps the jobs in RAM. If the process crashes or the machine is reset, then all outstanding jobs are lost with the diff --git a/guides/source/active_model_basics.md b/guides/source/active_model_basics.md index e834aeadb1..732e553c62 100644 --- a/guides/source/active_model_basics.md +++ b/guides/source/active_model_basics.md @@ -416,7 +416,6 @@ the Active Model API. ```ruby class Person include ActiveModel::Model - end ``` @@ -467,7 +466,7 @@ In order to make this work, the model must have an accessor named `password_dige The `has_secure_password` will add the following validations on the `password` accessor: 1. Password should be present. -2. Password should be equal to its confirmation. +2. Password should be equal to its confirmation (provided +password_confirmation+ is passed along). 3. The maximum length of a password is 72 (required by `bcrypt` on which ActiveModel::SecurePassword depends) #### Examples @@ -493,6 +492,10 @@ person.valid? # => false person.password = person.password_confirmation = 'a' * 100 person.valid? # => false +# When only password is supplied with no password_confirmation. +person.password = 'aditya' +person.valid? # => true + # When all validations are passed. person.password = person.password_confirmation = 'aditya' person.valid? # => true diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index d9e9466a33..6b3aa471f9 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -104,7 +104,7 @@ depending on the purpose of these columns. your models. * **Primary keys** - By default, Active Record will use an integer column named `id` as the table's primary key. When using [Active Record - Migrations](migrations.html) to create your tables, this column will be + Migrations](active_record_migrations.html) to create your tables, this column will be automatically created. There are also some optional column names that will add additional features @@ -374,4 +374,4 @@ and to roll it back, `rails db:rollback`. Note that the above code is database-agnostic: it will run in MySQL, PostgreSQL, Oracle and others. You can learn more about migrations in the -[Active Record Migrations guide](migrations.html). +[Active Record Migrations guide](active_record_migrations.html). diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index a7975c7772..2a1c960887 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -431,4 +431,4 @@ class PictureFile < ApplicationRecord end ``` -WARNING. The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback. +WARNING. The `after_commit` and `after_rollback` callbacks are called for all models created, updated, or destroyed within a transaction block. However, if an exception is raised within one of these callbacks, the exception will bubble up and any remaining `after_commit` or `after_rollback` methods will _not_ be executed. As such, if your callback code could raise an exception, you'll need to rescue it and handle it within the callback in order to allow other callbacks to run. diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index f914122242..d91c9bd606 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -241,7 +241,7 @@ generates ```ruby class AddUserRefToProducts < ActiveRecord::Migration[5.0] def change - add_reference :products, :user, index: true, foreign_key: true + add_reference :products, :user, foreign_key: true end end ``` @@ -313,7 +313,7 @@ will produce a migration that looks like this class AddDetailsToProducts < ActiveRecord::Migration[5.0] def change add_column :products, :price, :decimal, precision: 5, scale: 2 - add_reference :products, :supplier, polymorphic: true, index: true + add_reference :products, :supplier, polymorphic: true end end ``` @@ -467,6 +467,8 @@ the first time (i.e. on the date the migration is applied). Some adapters may support additional options; see the adapter specific API docs for further information. +NOTE: `null` and `default` cannot be specified via command line. + ### Foreign Keys While it's not required you might want to add foreign key constraints to @@ -1018,10 +1020,10 @@ such features, the `execute` method can be used to execute arbitrary SQL. Migrations and Seed Data ------------------------ -The main purpose of Rails' migration feature is to issue commands that modify the -schema using a consistent process. Migrations can also be used -to add or modify data. This is useful in an existing database that can't be destroyed -and recreated, such as a production database. +The main purpose of Rails' migration feature is to issue commands that modify the +schema using a consistent process. Migrations can also be used +to add or modify data. This is useful in an existing database that can't be destroyed +and recreated, such as a production database. ```ruby class AddInitialProducts < ActiveRecord::Migration[5.0] @@ -1037,10 +1039,10 @@ class AddInitialProducts < ActiveRecord::Migration[5.0] end ``` -To add initial data after a database is created, Rails has a built-in -'seeds' feature that makes the process quick and easy. This is especially -useful when reloading the database frequently in development and test environments. -It's easy to get started with this feature: just fill up `db/seeds.rb` with some +To add initial data after a database is created, Rails has a built-in +'seeds' feature that makes the process quick and easy. This is especially +useful when reloading the database frequently in development and test environments. +It's easy to get started with this feature: just fill up `db/seeds.rb` with some Ruby code, and run `rails db:seed`: ```ruby diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 928ab43b3b..38b1ffc4c8 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -50,7 +50,7 @@ class Role < ApplicationRecord end ``` -Active Record will perform queries on the database for you and is compatible with most database systems, including MySQL, MariaDB, PostgreSQL and SQLite. Regardless of which database system you're using, the Active Record method format will always be the same. +Active Record will perform queries on the database for you and is compatible with most database systems, including MySQL, MariaDB, PostgreSQL, and SQLite. Regardless of which database system you're using, the Active Record method format will always be the same. Retrieving Objects from the Database ------------------------------------ @@ -81,10 +81,9 @@ The methods are: * `reorder` * `reverse_order` * `select` -* `distinct` * `where` -All of the above methods return an instance of `ActiveRecord::Relation`. +Finder methods that return a collection, such as `where` and `group`, return an instance of `ActiveRecord::Relation`. Methods that find a single entity, such as `find` and `first`, return a single instance of the model. The primary operation of `Model.find(options)` can be summarized as: @@ -204,7 +203,7 @@ The SQL equivalent of the above is: SELECT * FROM clients ORDER BY clients.id ASC LIMIT 3 ``` -On a collection that is ordered using `order`, `first` will return the first record ordered by the specified attribute for `order`. +On a collection that is ordered using `order`, `first` will return the first record ordered by the specified attribute for `order`. ```ruby client = Client.order(:first_name).first @@ -255,7 +254,7 @@ The SQL equivalent of the above is: SELECT * FROM clients ORDER BY clients.id DESC LIMIT 3 ``` -On a collection that is ordered using `order`, `last` will return the last record ordered by the specified attribute for `order`. +On a collection that is ordered using `order`, `last` will return the last record ordered by the specified attribute for `order`. ```ruby client = Client.order(:first_name).last @@ -314,7 +313,7 @@ We often need to iterate over a large set of records, as when we send a newslett This may appear straightforward: ```ruby -# This is very inefficient when the users table has thousands of rows. +# This may consume too much memory if the table is big. User.all.each do |user| NewsMailer.weekly(user).deliver_now end @@ -328,7 +327,7 @@ TIP: The `find_each` and `find_in_batches` methods are intended for use in the b #### `find_each` -The `find_each` method retrieves a batch of records and then yields _each_ record to the block individually as a model. In the following example, `find_each` will retrieve 1000 records (the current default for both `find_each` and `find_in_batches`) and then yield each record individually to the block as a model. This process is repeated until all of the records have been processed: +The `find_each` method retrieves records in batches and then yields _each_ one to the block. In the following example, `find_each` retrieves users in batches of 1000 and yields them to the block one by one: ```ruby User.find_each do |user| @@ -336,7 +335,9 @@ User.find_each do |user| end ``` -To add conditions to a `find_each` operation you can chain other Active Record methods such as `where`: +This process is repeated, fetching more batches as needed, until all of the records have been processed. + +`find_each` works on model classes, as seen above, and also on relations: ```ruby User.where(weekly_subscriber: true).find_each do |user| @@ -344,11 +345,16 @@ User.where(weekly_subscriber: true).find_each do |user| end ``` -##### Options for `find_each` +as long as they have no ordering, since the method needs to force an order +internally to iterate. -The `find_each` method accepts most of the options allowed by the regular `find` method, except for `:order` and `:limit`, which are reserved for internal use by `find_each`. +If an order is present in the receiver the behaviour depends on the flag +`config.active_record.error_on_ignored_order`. If true, `ArgumentError` is +raised, otherwise the order is ignored and a warning issued, which is the +default. This can be overridden with the option `:error_on_ignore`, explained +below. -Three additional options, `:batch_size`, `:start` and `:finish`, are available as well. +##### Options for `find_each` **`:batch_size`** @@ -364,10 +370,10 @@ end By default, records are fetched in ascending order of the primary key, which must be an integer. The `:start` option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint. -For example, to send newsletters only to users with the primary key starting from 2000, and to retrieve them in batches of 5000: +For example, to send newsletters only to users with the primary key starting from 2000: ```ruby -User.find_each(start: 2000, batch_size: 5000) do |user| +User.find_each(start: 2000) do |user| NewsMailer.weekly(user).deliver_now end ``` @@ -375,12 +381,12 @@ end **`:finish`** Similar to the `:start` option, `:finish` allows you to configure the last ID of the sequence whenever the highest ID is not the one you need. -This would be useful, for example, if you wanted to run a batch process, using a subset of records based on `:start` and `:finish` +This would be useful, for example, if you wanted to run a batch process using a subset of records based on `:start` and `:finish`. -For example, to send newsletters only to users with the primary key starting from 2000 up to 10000 and to retrieve them in batches of 5000: +For example, to send newsletters only to users with the primary key starting from 2000 up to 10000: ```ruby -User.find_each(start: 2000, finish: 10000, batch_size: 5000) do |user| +User.find_each(start: 2000, finish: 10000) do |user| NewsMailer.weekly(user).deliver_now end ``` @@ -389,20 +395,36 @@ Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate `:start` and `:finish` options on each worker. +**`:error_on_ignore`** + +Overrides the application config to specify if an error should be raised when an +order is present in the relation. + #### `find_in_batches` The `find_in_batches` method is similar to `find_each`, since both retrieve batches of records. The difference is that `find_in_batches` yields _batches_ to the block as an array of models, instead of individually. The following example will yield to the supplied block an array of up to 1000 invoices at a time, with the final block containing any remaining invoices: ```ruby -# Give add_invoices an array of 1000 invoices at a time +# Give add_invoices an array of 1000 invoices at a time. Invoice.find_in_batches do |invoices| export.add_invoices(invoices) end ``` +`find_in_batches` works on model classes, as seen above, and also on relations: + +```ruby +Invoice.pending.find_in_batches do |invoice| + pending_invoices_export.add_invoices(invoices) +end +``` + +as long as they have no ordering, since the method needs to force an order +internally to iterate. + ##### Options for `find_in_batches` -The `find_in_batches` method accepts the same `:batch_size`, `:start` and `:finish` options as `find_each`. +The `find_in_batches` method accepts the same options as `find_each`. Conditions ---------- @@ -578,6 +600,7 @@ If you want to call `order` multiple times, subsequent orders will be appended t Client.order("orders_count ASC").order("created_at DESC") # SELECT * FROM clients ORDER BY orders_count ASC, created_at DESC ``` +WARNING: If you are using **MySQL 5.7.5** and above, then on selecting fields from a result set using methods like `select`, `pluck` and `ids`; the `order` method will raise an `ActiveRecord::StatementInvalid` exception unless the field(s) used in `order` clause are included in the select list. See the next section for selecting fields from the result set. Selecting Specific Fields ------------------------- @@ -990,13 +1013,13 @@ There are multiple ways to use the `joins` method. You can just supply the raw SQL specifying the `JOIN` clause to `joins`: ```ruby -Author.joins("INNER JOIN posts ON posts.author_id = author.id AND posts.published = 't'") +Author.joins("INNER JOIN posts ON posts.author_id = authors.id AND posts.published = 't'") ``` This will result in the following SQL: ```sql -SELECT clients.* FROM clients INNER JOIN posts ON posts.author_id = author.id AND posts.published = 't' +SELECT authors.* FROM authors INNER JOIN posts ON posts.author_id = authors.id AND posts.published = 't' ``` #### Using Array/Hash of Named Associations @@ -1227,7 +1250,8 @@ articles, all the articles would still be loaded. By using `joins` (an INNER JOIN), the join conditions **must** match, otherwise no records will be returned. - +NOTE: If an association is eager loaded as part of a join, any fields from a custom select clause will not present be on the loaded models. +This is because it is ambiguous whether they should appear on the parent record, or the child. Scopes ------ diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index 2737237c1a..665e97c470 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -290,7 +290,7 @@ You can also pass custom message via the `message` option. ```ruby class Person < ApplicationRecord - validates :terms_of_service, acceptance: true, message: 'must be abided' + validates :terms_of_service, acceptance: { message: 'must be abided' } end ``` diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 565c87c4b5..70b04a9695 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -368,7 +368,7 @@ account.to_query('company[name]') so its output is ready to be used in a query string. -Arrays return the result of applying `to_query` to each element with `_key_[]` as key, and join the result with "&": +Arrays return the result of applying `to_query` to each element with `key[]` as key, and join the result with "&": ```ruby [3.4, -45.6].to_query('sample') @@ -954,7 +954,8 @@ class A class_attribute :x, instance_reader: false end -A.new.x = 1 # NoMethodError +A.new.x = 1 +A.new.x # NoMethodError ``` For convenience `class_attribute` also defines an instance predicate which is the double negation of what the instance reader returns. In the examples above it would be called `x?`. @@ -2035,7 +2036,7 @@ Addition only assumes the elements respond to `+`: ```ruby [[1, 2], [2, 3], [3, 4]].sum # => [1, 2, 2, 3, 3, 4] %w(foo bar baz).sum # => "foobarbaz" -{a: 1, b: 2, c: 3}.sum # => [:b, 2, :c, 3, :a, 1] +{a: 1, b: 2, c: 3}.sum # => [:b, 2, :c, 3, :a, 1] ``` The sum of an empty collection is zero by default, but this is customizable: @@ -2660,7 +2661,7 @@ The method `transform_keys` accepts a block and returns a hash that has applied ```ruby {nil => nil, 1 => 1, a: :a}.transform_keys { |key| key.to_s.upcase } -# => {"" => nil, "A" => :a, "1" => 1} +# => {"" => nil, "1" => 1, "A" => :a} ``` In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: @@ -2702,7 +2703,7 @@ The method `stringify_keys` returns a hash that has a stringified version of the ```ruby {nil => nil, 1 => 1, a: :a}.stringify_keys -# => {"" => nil, "a" => :a, "1" => 1} +# => {"" => nil, "1" => 1, "a" => :a} ``` In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: @@ -2744,7 +2745,7 @@ The method `symbolize_keys` returns a hash that has a symbolized version of the ```ruby {nil => nil, 1 => 1, "a" => "a"}.symbolize_keys -# => {1=>1, nil=>nil, :a=>"a"} +# => {nil=>nil, 1=>1, :a=>"a"} ``` WARNING. Note in the previous example only one key was symbolized. @@ -2821,7 +2822,7 @@ Ruby has built-in support for taking slices out of strings and arrays. Active Su ```ruby {a: 1, b: 2, c: 3}.slice(:a, :c) -# => {:c=>3, :a=>1} +# => {:a=>1, :c=>3} {a: 1, b: 2, c: 3}.slice(:b, :X) # => {:b=>2} # non-existing keys are ignored @@ -2915,6 +2916,24 @@ end NOTE: Defined in `active_support/core_ext/regexp.rb`. +### `match?` + +Rails implements `Regexp#match?` for Ruby versions prior to 2.4: + +```ruby +/oo/.match?('foo') # => true +/oo/.match?('bar') # => false +/oo/.match?('foo', 1) # => true +``` + +The backport has the same interface and lack of side-effects in the caller like +not setting `$1` and friends, but it does not have the speed benefits. Its +purpose is to be able to write 2.4 compatible code. Rails itself uses this +predicate internally for example. + +Active Support defines `Regexp#match?` only if not present, so code running +under 2.4 or later does run the original one and gets the performance boost. + Extensions to `Range` --------------------- diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index 03af3cf819..3fc9d9bfa9 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -231,12 +231,13 @@ Active Record ### sql.active_record -| Key | Value | -| ---------------- | --------------------- | -| `:sql` | SQL statement | -| `:name` | Name of the operation | -| `:connection_id` | `self.object_id` | -| `:binds` | Bind parameters | +| Key | Value | +| ---------------- | ---------------------------------------- | +| `:sql` | SQL statement | +| `:name` | Name of the operation | +| `:connection_id` | `self.object_id` | +| `:binds` | Bind parameters | +| `:cached` | `true` is added when cached queries used | INFO. The adapters will add their own data as well. diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index 5b34330936..34b9c0d2ca 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -20,7 +20,7 @@ The [Rails API documentation](http://api.rubyonrails.org) is generated with in the rails root directory, run `bundle install` and execute: ```bash - ./bin/rails rdoc + bundle exec rake rdoc ``` Resulting HTML files can be found in the ./doc/rdoc directory. diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index e6631a513c..41dfeea84d 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -485,7 +485,7 @@ which contains these lines: Rails creates both `app/assets/javascripts/application.js` and `app/assets/stylesheets/application.css` regardless of whether the ---skip-sprockets option is used when creating a new rails application. This is +--skip-sprockets option is used when creating a new Rails application. This is so you can easily add asset pipelining later if you like. The directives that work in JavaScript files also work in stylesheets @@ -586,6 +586,19 @@ in your application are included in the `config.assets.precompile` list. If `config.assets.digest` is also true, the asset pipeline will require that all requests for assets include digests. +### Raise an Error When an Asset is Not Found + +If you are using sprockets-rails >= 3.2.0 you can configure what happens +when an asset lookup is performed and nothing is found. If you turn off "asset fallback" +then an error will be raised when an asset cannot be found. + +```ruby +config.assets.unknown_asset_fallback = false +``` + +If "asset fallback" is enabled then when an asset cannot be found the path will be +output instead and no error raised. The asset fallback behavior is enabled by default. + ### Turning Digests Off You can turn off digests by updating `config/environments/development.rb` to @@ -724,7 +737,7 @@ If you have other manifests or individual stylesheets and JavaScript files to include, you can add them to the `precompile` array in `config/initializers/assets.rb`: ```ruby -Rails.application.config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js'] +Rails.application.config.assets.precompile += %w( admin.js admin.css ) ``` NOTE. Always specify an expected compiled filename that ends with .js or .css, @@ -1024,7 +1037,7 @@ to tell our CDN (and browser) that the asset is "public", that means any cache can store the request. Also we commonly want to set `max-age` which is how long the cache will store the object before invalidating the cache. The `max-age` value is set to seconds with a maximum possible value of `31536000` which is one -year. You can do this in your rails application by setting +year. You can do this in your Rails application by setting ``` config.public_file_server.headers = { @@ -1109,9 +1122,9 @@ Windows you have a JavaScript runtime installed in your operating system. ### Serving GZipped version of assets -By default, gzipped version of compiled assets will be generated, along -with the non-gzipped version of assets. Gzipped assets help reduce the transmission of -data over the wire. You can configure this by setting the `gzip` flag. +By default, gzipped version of compiled assets will be generated, along with +the non-gzipped version of assets. Gzipped assets help reduce the transmission +of data over the wire. You can configure this by setting the `gzip` flag. ```ruby config.assets.gzip = false # disable gzipped assets generation @@ -1291,7 +1304,7 @@ config.assets.digest = true # Precompile additional assets (application.js, application.css, and all # non-JS/CSS are already added) -# config.assets.precompile += %w( search.js ) +# config.assets.precompile += %w( admin.js admin.css ) ``` Rails 4 and above no longer set default config values for Sprockets in `test.rb`, so diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 3993fdb1dd..3837cda553 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -387,7 +387,7 @@ The corresponding migration might look like this: class CreateSuppliers < ActiveRecord::Migration[5.0] def change create_table :suppliers do |t| - t.string :name + t.string :name t.timestamps end @@ -550,8 +550,8 @@ But what if you want to reload the cache, because data might have been changed b ```ruby author.books # retrieves books from the database author.books.size # uses the cached copy of books -author.books.reload.empty? # discards the cached copy of books - # and goes back to the database +author.books.reload.empty? # discards the cached copy of books + # and goes back to the database ``` ### Avoiding Name Collisions @@ -1007,7 +1007,7 @@ class Author < ApplicationRecord end ``` -In this case, saving or destroying an book will update the timestamp on the associated author. You can also specify a particular timestamp attribute to update: +In this case, saving or destroying a book will update the timestamp on the associated author. You can also specify a particular timestamp attribute to update: ```ruby class Book < ApplicationRecord @@ -1841,7 +1841,7 @@ article = Article.create(name: 'a1') person.articles << article person.articles << article person.articles.inspect # => [#<Article id: 5, name: "a1">, #<Article id: 5, name: "a1">] -Reading.all.inspect # => [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>] +Reading.all.inspect # => [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>] ``` In the above case there are two readings and `person.articles` brings out both of @@ -1860,7 +1860,7 @@ article = Article.create(name: 'a1') person.articles << article person.articles << article person.articles.inspect # => [#<Article id: 7, name: "a1">] -Reading.all.inspect # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>] +Reading.all.inspect # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>] ``` In the above case there are still two readings. However `person.articles` shows diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index 6c734c1d78..fd7626250c 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -198,11 +198,11 @@ render "comments/comments" render 'comments/comments' render('comments/comments') -render "header" => render("comments/header") +render "header" translates to render("comments/header") -render(@topic) => render("topics/topic") -render(topics) => render("topics/topic") -render(message.topics) => render("topics/topic") +render(@topic) translates to render("topics/topic") +render(topics) translates to render("topics/topic") +render(message.topics) translates to render("topics/topic") ``` On the other hand, some calls need to be changed to make caching work properly. @@ -270,7 +270,7 @@ simply be explicit in a comment, like: Sometimes you need to cache a particular value or query result instead of caching view fragments. Rails' caching mechanism works great for storing __any__ kind of information. -The most efficient way to implement low-level caching is using the `Rails.cache.fetch` method. This method does both reading and writing to the cache. When passed only a single argument, the key is fetched and value from the cache is returned. If a block is passed, the result of the block will be cached to the given key and the result is returned. +The most efficient way to implement low-level caching is using the `Rails.cache.fetch` method. This method does both reading and writing to the cache. When passed only a single argument, the key is fetched and value from the cache is returned. If a block is passed, that block will be executed in the event of a cache miss. The return value of the block will be written to the cache under the given cache key, and that return value will be returned. In case of cache hit, the cached value will be returned without executing the block. Consider the following example. An application has a `Product` model with an instance method that looks up the product’s price on a competing website. The data returned by this method would be perfect for low-level caching: @@ -381,7 +381,7 @@ config.cache_store = :memory_store, { size: 64.megabytes } ``` If you're running multiple Ruby on Rails server processes (which is the case -if you're using mongrel_cluster or Phusion Passenger), then your Rails server +if you're using Phusion Passenger or puma clustered mode), then your Rails server process instances won't be able to share cache data with each other. This cache store is not appropriate for large application deployments. However, it can work well for small, low traffic sites with only a couple of server processes, @@ -512,6 +512,30 @@ class ProductsController < ApplicationController end ``` +Sometimes we want to cache response, for example a static page, that never gets +expired. To achieve this, we can use `http_cache_forever` helper and by doing +so browser and proxies will cache it indefinitely. + +By default cached responses will be private, cached only on the user's web +browser. To allow proxies to cache the response, set `public: true` to indicate +that they can serve the cached response to all users. + +Using this helper, `last_modified` header is set to `Time.new(2011, 1, 1).utc` +and `expires` header is set to a 100 years. + +WARNING: Use this method carefully as browser/proxy won't be able to invalidate +the cached response unless browser cache is forcefully cleared. + +```ruby +class HomeController < ApplicationController + def index + http_cache_forever(public: true) do + render + end + end +end +``` + ### Strong v/s Weak ETags Rails generates weak ETags by default. Weak ETags allow semantically equivalent diff --git a/guides/source/command_line.md b/guides/source/command_line.md index f766403228..9d7ecce947 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -209,7 +209,7 @@ Description: Create rails files for model generator. ``` -NOTE: For a list of available field types, refer to the [API documentation](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column) for the column method for the `TableDefinition` class. +NOTE: For a list of available field types for the `type` parameter, refer to the [API documentation](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column) for the add_column method for the `SchemaStatements` module. The `index` parameter generates a corresponding index for the column. But instead of generating a model directly (which we'll be doing later), let's set up a scaffold. A **scaffold** in Rails is a full set of model, database migration for that model, controller to manipulate it, views to view and manipulate the data, and a test suite for each of the above. @@ -497,7 +497,13 @@ app/models/article.rb: NOTE. When using specific annotations and custom annotations, the annotation name (FIXME, BUG etc) is not displayed in the output lines. -By default, `rails notes` will look in the `app`, `config`, `db`, `lib` and `test` directories. If you would like to search other directories, you can provide them as a comma separated list in an environment variable `SOURCE_ANNOTATION_DIRECTORIES`. +By default, `rails notes` will look in the `app`, `config`, `db`, `lib` and `test` directories. If you would like to search other directories, you can configure them using `config.annotations.register_directories` option. + +```ruby +config.annotations.register_directories("spec", "vendor") +``` + +You can also provide them as a comma separated list in the environment variable `SOURCE_ANNOTATION_DIRECTORIES`. ```bash $ export SOURCE_ANNOTATION_DIRECTORIES='spec,vendor' diff --git a/guides/source/configuring.md b/guides/source/configuring.md index b3d3b2c681..79ded19c27 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -71,7 +71,7 @@ These configuration methods are to be called on a `Rails::Railtie` object, such * `config.beginning_of_week` sets the default beginning of week for the application. Accepts a valid week day symbol (e.g. `:monday`). -* `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, or an object that implements the cache API. Defaults to `:file_store` if the directory `tmp/cache` exists, and to `:memory_store` otherwise. +* `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, or an object that implements the cache API. Defaults to `:file_store`. * `config.colorize_logging` specifies whether or not to use ANSI color codes when logging information. Defaults to `true`. @@ -94,6 +94,8 @@ application. Accepts a valid week day symbol (e.g. `:monday`). * `config.eager_load_paths` accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the `app` directory of the application. +* `config.enable_dependency_loading`: when true, enables autoloading, even if the application is eager loaded and `config.cache_classes` is set as true. Defaults to false. + * `config.encoding` sets up the application-wide encoding. Defaults to UTF-8. * `config.exceptions_app` sets the exceptions application invoked by the ShowException middleware when an exception happens. Defaults to `ActionDispatch::PublicExceptions.new(Rails.public_path)`. @@ -108,7 +110,7 @@ numbers. By default, Rails filters out passwords by adding `Rails.application.co * `config.force_ssl` forces all requests to be served over HTTPS by using the `ActionDispatch::SSL` middleware, and sets `config.action_mailer.default_url_options` to be `{ protocol: 'https' }`. This can be configured by setting `config.ssl_options` - see the [ActionDispatch::SSL documentation](http://edgeapi.rubyonrails.org/classes/ActionDispatch/SSL.html) for details. -* `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes except production, where it defaults to `Logger::Formatter`. If you are setting a value for `config.logger` you must manually pass the value of your formatter to your logger before it is wrapped in an `ActiveSupport::TaggedLogging` instance, Rails will not do it for you. +* `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes. If you are setting a value for `config.logger` you must manually pass the value of your formatter to your logger before it is wrapped in an `ActiveSupport::TaggedLogging` instance, Rails will not do it for you. * `config.log_level` defines the verbosity of the Rails logger. This option defaults to `:debug` for all environments. The available log levels are: `:debug`, @@ -129,7 +131,7 @@ defaults to `:debug` for all environments. The available log levels are: `:debug mylogger = MyLogger.new(STDOUT) mylogger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(mylogger) + config.logger = ActiveSupport::TaggedLogging.new(mylogger) ``` * `config.middleware` allows you to configure the application's middleware. This is covered in depth in the [Configuring Middleware](#configuring-middleware) section below. @@ -140,7 +142,7 @@ defaults to `:debug` for all environments. The available log levels are: `:debug * `config.public_file_server.enabled` configures Rails to serve static files from the public directory. This option defaults to `true`, but in the production environment it is set to `false` because the server software (e.g. NGINX or Apache) used to run the application should serve static files instead. If you are running or testing your app in production mode using WEBrick (it is not recommended to use WEBrick in production) set the option to `true.` Otherwise, you won't be able to use page caching and request for files that exist under the public directory. -* `config.session_store` is usually set up in `config/initializers/session_store.rb` and specifies what class to use to store the session. Possible values are `:cookie_store` which is the default, `:mem_cache_store`, and `:disabled`. The last one tells Rails not to deal with sessions. Custom session stores can also be specified: +* `config.session_store` specifies what class to use to store the session. Possible values are `:cookie_store` which is the default, `:mem_cache_store`, and `:disabled`. The last one tells Rails not to deal with sessions. Defaults to a cookie store with application name as the session key. Custom session stores can also be specified: ```ruby config.session_store :my_custom_store @@ -161,12 +163,14 @@ pipeline is enabled. It is set to `true` by default. * `config.assets.js_compressor` defines the JavaScript compressor to use. Possible values are `:closure`, `:uglifier` and `:yui` which require the use of the `closure-compiler`, `uglifier` or `yui-compressor` gems respectively. -* `config.assets.gzip` a flag that enables the creation of gzipped version of compiled assets, along with non-gzipped assets. Set to `true` by default. +* `config.assets.gzip` a flag that enables the creation of gzipped version of compiled assets, along with non-gzipped assets. Set to `true` by default. * `config.assets.paths` contains the paths which are used to look for assets. Appending paths to this configuration option will cause those paths to be used in the search for assets. * `config.assets.precompile` allows you to specify additional assets (other than `application.css` and `application.js`) which are to be precompiled when `rake assets:precompile` is run. +* `config.assets.unknown_asset_fallback` allows you to modify the behavior of the asset pipeline when an asset is not in the pipeline, if you use sprockets-rails 3.2.0 or newer. Defaults to `true`. + * `config.assets.prefix` defines the prefix where assets are served from. Defaults to `/assets`. * `config.assets.manifest` defines the full path to be used for the asset precompiler's manifest file. Defaults to a file named `manifest-<random>.json` in the `config.assets.prefix` directory within the public folder. @@ -179,6 +183,8 @@ pipeline is enabled. It is set to `true` by default. * `config.assets.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to the same configured at `config.logger`. Setting `config.assets.logger` to `false` will turn off served assets logging. +* `config.assets.quiet` disables logging of assets requests. Set to `true` by default in `development.rb`. + ### Configuring Generators Rails allows you to alter what generators are used with the `config.generators` method. This method takes a block: @@ -296,6 +302,8 @@ All these configuration options are delegated to the `I18n` library. ```ruby config.i18n.fallbacks = { az: :tr, da: [:de, :en] } + #or + config.i18n.fallbacks.map = { az: :tr, da: [:de, :en] } ``` ### Configuring Active Record @@ -320,7 +328,7 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.schema_format` controls the format for dumping the database schema to a file. The options are `:ruby` (the default) for a database-independent version that depends on migrations, or `:sql` for a set of (potentially database-dependent) SQL statements. -* `config.active_record.error_on_ignored_order_or_limit` specifies if an error should be raised if the order or limit of a query is ignored during a batch query. The options are `true` (raise error) or `false` (warn). Default is `false`. +* `config.active_record.error_on_ignored_order` specifies if an error should be raised if the order of a query is ignored during a batch query. The options are `true` (raise error) or `false` (warn). Default is `false`. * `config.active_record.timestamped_migrations` controls whether migrations are numbered with serial integers or with timestamps. The default is `true`, to use timestamps, which are preferred if there are multiple developers working on the same application. @@ -396,6 +404,22 @@ The schema dumper adds one additional configuration option: * `config.action_controller.always_permitted_parameters` sets a list of whitelisted parameters that are permitted by default. The default values are `['controller', 'action']`. +* `config.action_controller.enable_fragment_cache_logging` determines whether to log fragment cache reads and writes in verbose format as follows: + + ``` + Read fragment views/v1/2914079/v1/2914079/recordings/70182313-20160225015037000000/d0bdf2974e1ef6d31685c3b392ad0b74 (0.6ms) + Rendered messages/_message.html.erb in 1.2 ms [cache hit] + Write fragment views/v1/2914079/v1/2914079/recordings/70182313-20160225015037000000/3b4e249ac9d168c617e32e84b99218b5 (1.1ms) + Rendered recordings/threads/_thread.html.erb in 1.5 ms [cache miss] + ``` + + By default it is set to `false` which results in following output: + + ``` + Rendered messages/_message.html.erb in 1.2 ms [cache hit] + Rendered recordings/threads/_thread.html.erb in 1.5 ms [cache miss] + ``` + ### Configuring Action Dispatch * `config.action_dispatch.session_store` sets the name of the store for session data. The default is `:cookie_store`; other valid options include `:active_record_store`, `:mem_cache_store` or the name of your own custom class. @@ -438,21 +462,23 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. ```ruby config.action_dispatch.rescue_responses = { - 'ActionController::RoutingError' => :not_found, - 'AbstractController::ActionNotFound' => :not_found, - 'ActionController::MethodNotAllowed' => :method_not_allowed, - 'ActionController::UnknownHttpMethod' => :method_not_allowed, - 'ActionController::NotImplemented' => :not_implemented, - 'ActionController::UnknownFormat' => :not_acceptable, - 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity, - 'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity, - 'ActionDispatch::ParamsParser::ParseError' => :bad_request, - 'ActionController::BadRequest' => :bad_request, - 'ActionController::ParameterMissing' => :bad_request, - 'ActiveRecord::RecordNotFound' => :not_found, - 'ActiveRecord::StaleObjectError' => :conflict, - 'ActiveRecord::RecordInvalid' => :unprocessable_entity, - 'ActiveRecord::RecordNotSaved' => :unprocessable_entity + 'ActionController::RoutingError' => :not_found, + 'AbstractController::ActionNotFound' => :not_found, + 'ActionController::MethodNotAllowed' => :method_not_allowed, + 'ActionController::UnknownHttpMethod' => :method_not_allowed, + 'ActionController::NotImplemented' => :not_implemented, + 'ActionController::UnknownFormat' => :not_acceptable, + 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity, + 'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity, + 'ActionDispatch::Http::Parameters::ParseError' => :bad_request, + 'ActionController::BadRequest' => :bad_request, + 'ActionController::ParameterMissing' => :bad_request, + 'Rack::QueryParser::ParameterTypeError' => :bad_request, + 'Rack::QueryParser::InvalidParameterError' => :bad_request, + 'ActiveRecord::RecordNotFound' => :not_found, + 'ActiveRecord::StaleObjectError' => :conflict, + 'ActiveRecord::RecordInvalid' => :unprocessable_entity, + 'ActiveRecord::RecordNotSaved' => :unprocessable_entity } ``` @@ -525,11 +551,11 @@ There are a number of settings available on `config.action_mailer`: * `:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`. * `:enable_starttls_auto` - Detects if STARTTLS is enabled in your SMTP server and starts to use it. It defaults to `true`. * `:openssl_verify_mode` - When using TLS, you can set how OpenSSL checks the certificate. This is useful if you need to validate a self-signed and/or a wildcard certificate. This can be one of the OpenSSL verify constants, `:none` or `:peer` -- or the constant directly `OpenSSL::SSL::VERIFY_NONE` or `OpenSSL::SSL::VERIFY_PEER`, respectively. - * `:ssl/:tls` - Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection). + * `:ssl/:tls` - Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection). * `config.action_mailer.sendmail_settings` allows detailed configuration for the `sendmail` delivery method. It accepts a hash of options, which can include any of these options: * `:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`. - * `:arguments` - The command line arguments. Defaults to `-i -t`. + * `:arguments` - The command line arguments. Defaults to `-i`. * `config.action_mailer.raise_delivery_errors` specifies whether to raise an error if email delivery cannot be completed. It defaults to `true`. @@ -590,7 +616,7 @@ There are a few configuration options available in Active Support: * `config.active_support.bare` enables or disables the loading of `active_support/all` when booting Rails. Defaults to `nil`, which means `active_support/all` is loaded. -* `config.active_support.test_order` sets the order that test cases are executed. Possible values are `:random` and `:sorted`. This option is set to `:random` in `config/environments/test.rb` in newly-generated applications. If you have an application that does not specify a `test_order`, it will default to `:sorted`, *until* Rails 5.0, when the default will become `:random`. +* `config.active_support.test_order` sets the order in which the test cases are executed. Possible values are `:random` and `:sorted`. Defaults to `:random`. * `config.active_support.escape_html_entities_in_json` enables or disables the escaping of HTML entities in JSON serialization. Defaults to `true`. @@ -598,7 +624,7 @@ There are a few configuration options available in Active Support: * `config.active_support.time_precision` sets the precision of JSON encoded time values. Defaults to `3`. -* `ActiveSupport.halt_callback_chains_on_return_false` specifies whether Active Record and Active Model callback chains can be halted by returning `false` in a 'before' callback. When set to `false`, callback chains are halted only when explicitly done so with `throw(:abort)`. When set to `true`, callback chains are halted when a callback returns `false` (the previous behavior before Rails 5) and a deprecation warning is given. Defaults to `true` during the deprecation period. New Rails 5 apps generate an initializer file called `callback_terminator.rb` which sets the value to `false`. This file is *not* added when running `rails app:update`, so returning `false` will still work on older apps ported to Rails 5 and display a deprecation warning to prompt users to update their code. +* `ActiveSupport.halt_callback_chains_on_return_false` specifies whether Active Record and Active Model callback chains can be halted by returning `false` in a 'before' callback. When set to `false`, callback chains are halted only when explicitly done so with `throw(:abort)`. When set to `true`, callback chains are halted when a callback returns `false` (the previous behavior before Rails 5) and a deprecation warning is given. Defaults to `true` during the deprecation period. New Rails 5 apps generate an initializer file called `new_framework_defaults.rb` which sets the value to `false`. This file is *not* added when running `rails app:update`, so returning `false` will still work on older apps ported to Rails 5 and display a deprecation warning to prompt users to update their code. * `ActiveSupport::Logger.silencer` is set to `false` to disable the ability to silence logging in a block. The default is `true`. @@ -1172,7 +1198,7 @@ development: timeout: 5000 ``` -Since the connection pooling is handled inside of Active Record by default, all application servers (Thin, mongrel, Unicorn etc.) should behave the same. The database connection pool is initially empty. As demand for connections increases it will create them until it reaches the connection pool limit. +Since the connection pooling is handled inside of Active Record by default, all application servers (Thin, Puma, Unicorn etc.) should behave the same. The database connection pool is initially empty. As demand for connections increases it will create them until it reaches the connection pool limit. Any one request will check out a connection the first time it requires access to the database. At the end of the request it will check the connection back in. This means that the additional connection slot will be available again for the next request in the queue. @@ -1193,21 +1219,25 @@ NOTE. If you are running in a multi-threaded environment, there could be a chanc Custom configuration -------------------- -You can configure your own code through the Rails configuration object with custom configuration. It works like this: +You can configure your own code through the Rails configuration object with +custom configuration under either the `config.x` namespace, or `config` directly. +The key difference between these two is that you should be using `config.x` if you +are defining _nested_ configuration (ex: `config.x.nested.nested.hi`), and just +`config` for _single level_ configuration (ex: `config.hello`). ```ruby - config.payment_processing.schedule = :daily - config.payment_processing.retries = 3 + config.x.payment_processing.schedule = :daily + config.x.payment_processing.retries = 3 config.super_debugger = true ``` These configuration points are then available through the configuration object: ```ruby - Rails.configuration.payment_processing.schedule # => :daily - Rails.configuration.payment_processing.retries # => 3 - Rails.configuration.super_debugger # => true - Rails.configuration.super_debugger.not_set # => nil + Rails.configuration.x.payment_processing.schedule # => :daily + Rails.configuration.x.payment_processing.retries # => 3 + Rails.configuration.x.payment_processing.not_set # => nil + Rails.configuration.super_debugger # => true ``` You can also use `Rails::Application.config_for` to load whole configuration files: @@ -1266,7 +1296,7 @@ evented file system monitor to detect changes when `config.cache_classes` is ```ruby group :development do - gem 'listen', '~> 3.0.4' + gem 'listen', '>= 3.0.5', '< 3.2' end ``` diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index ba8d085f79..830a546570 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -40,7 +40,9 @@ Then, don't get your hopes up! Unless you have a "Code Red, Mission Critical, th Having a way to reproduce your issue will be very helpful for others to help confirm, investigate and ultimately fix your issue. You can do this by providing an executable test case. To make this process easier, we have prepared several bug report templates for you to use as a starting point: * Template for Active Record (models, database) issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_master.rb) +* Template for testing Active Record (migration) issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_migrations_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_migrations_master.rb) * Template for Action Pack (controllers, routing) issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/action_controller_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/action_controller_master.rb) +* Template for Active Job issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_job_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_job_master.rb) * Generic template for other issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/generic_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/generic_master.rb) These templates include the boilerplate code to set up a test case against either a released version of Rails (`*_gem.rb`) or edge Rails (`*_master.rb`). @@ -268,33 +270,24 @@ The above are guidelines - please use your best judgment in using them. ### Benchmark Your Code -If your change has an impact on the performance of Rails, please use the -[benchmark-ips](https://github.com/evanphx/benchmark-ips) gem to provide -benchmark results for comparison. - -Here's an example of using benchmark-ips: - -```ruby -require 'benchmark/ips' - -Benchmark.ips do |x| - x.report('addition') { 1 + 2 } - x.report('addition with send') { 1.send(:+, 2) } -end -``` - -This will generate a report with the following information: - -``` -Calculating ------------------------------------- - addition 132.013k i/100ms - addition with send 125.413k i/100ms -------------------------------------------------- - addition 9.677M (± 1.7%) i/s - 48.449M - addition with send 6.794M (± 1.1%) i/s - 33.987M -``` - -Please see the benchmark/ips [README](https://github.com/evanphx/benchmark-ips/blob/master/README.md) for more information. +For changes that might have an impact on performance, please benchmark your +code and measure the impact. Please share the benchmark script you used as well +as the results. You should consider including this information in your commit +message, which allows future contributors to easily verify your findings and +determine if they are still relevant. (For example, future optimizations in the +Ruby VM might render certain optimizations unnecessary.) + +It is very easy to make an optimization that improves performance for a +specific scenario you care about but regresses on other common cases. +Therefore, you should test your change against a list of representative +scenarios. Ideally, they should be based on real-world scenarios extracted +from production applications. + +You can use the [benchmark template](https://github.com/rails/rails/blob/master/guides/bug_report_templates/benchmark.rb) +as a starting point. It includes the boilerplate code to setup a benchmark +using the [benchmark-ips](https://github.com/evanphx/benchmark-ips) gem. The +template is designed for testing relatively self-contained changes that can be +inlined into the script. ### Running Tests @@ -677,7 +670,7 @@ $ git format-patch master --stdout > ~/my_changes.patch Switch over to the target branch and apply your changes: ```bash -$ git checkout -b my_backport_branch 3-2-stable +$ git checkout -b my_backport_branch 4-2-stable $ git apply ~/my_changes.patch ``` diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb index 511d76041b..5adbd12ac0 100644 --- a/guides/source/credits.html.erb +++ b/guides/source/credits.html.erb @@ -22,7 +22,7 @@ Ruby on Rails Guides: Credits <h3 class="section">Rails Guides Designers</h3> <%= author('Jason Zimdars', 'jz') do %> - Jason Zimdars is an experienced creative director and web designer who has lead UI and UX design for numerous websites and web applications. You can see more of his design and writing at <a href="http://www.thinkcage.com/">Thinkcage.com</a> or follow him on <a href="http://twitter.com/JZ">Twitter</a>. + Jason Zimdars is an experienced creative director and web designer who has lead UI and UX design for numerous websites and web applications. You can see more of his design and writing at <a href="http://www.thinkcage.com/">Thinkcage.com</a> or follow him on <a href="https://twitter.com/jasonzimdars">Twitter</a>. <% end %> <h3 class="section">Rails Guides Authors</h3> @@ -32,7 +32,7 @@ Ruby on Rails Guides: Credits <% end %> <%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %> -Oscar Del Ben is a software engineer at <a href="http://www.wildfireapp.com/">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">GitHub account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>. +Oscar Del Ben is a software engineer at <a href="http://www.businessinsider.com/google-buys-wildfire-2012-8">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">GitHub account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>. <% end %> <%= author('Frederick Cheung', 'fcheung') do %> diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index f0d0f9753a..df3003a6a8 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -946,16 +946,10 @@ development that will end your tailing of development.log. Have all information about your Rails app requests in the browser — in the Developer Tools panel. Provides insight to db/rendering/total times, parameter list, rendered views and more. +* [Pry](https://github.com/pry/pry) An IRB alternative and runtime developer console. References ---------- -* [ruby-debug Homepage](http://bashdb.sourceforge.net/ruby-debug/home-page.html) -* [debugger Homepage](https://github.com/cldwalker/debugger) * [byebug Homepage](https://github.com/deivid-rodriguez/byebug) * [web-console Homepage](https://github.com/rails/web-console) -* [Article: Debugging a Rails application with ruby-debug](http://www.sitepoint.com/debug-rails-app-ruby-debug/) -* [Ryan Bates' debugging ruby (revised) screencast](http://railscasts.com/episodes/54-debugging-ruby-revised) -* [Ryan Bates' stack trace screencast](http://railscasts.com/episodes/24-the-stack-trace) -* [Ryan Bates' logger screencast](http://railscasts.com/episodes/56-the-logger) -* [Debugging with ruby-debug](http://bashdb.sourceforge.net/ruby-debug.html) diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index cc24e6f666..20cd34c182 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -288,3 +288,46 @@ NOTE: Using the rake task to create the test databases ensures they have the cor NOTE: You'll see the following warning (or localized warning) during activating HStore extension in PostgreSQL 9.1.x or earlier: "WARNING: => is deprecated as an operator". If you're using another database, check the file `activerecord/test/config.yml` or `activerecord/test/config.example.yml` for default connection information. You can edit `activerecord/test/config.yml` to provide different credentials on your machine if you must, but obviously you should not push any such changes back to Rails. + +### Action Cable Setup + +Action Cable uses Redis as its default subscriptions adapter ([read more](action_cable_overview.html#broadcasting)). Thus, in order to have Action Cable's tests passing you need to install and have Redis running. + +#### Install Redis From Source + +Redis' documentation discourage installations with package managers as those are usually outdated. Installing from source and bringing the server up is straight forward and well documented on [Redis' documentation](http://redis.io/download#installation). + +#### Install Redis From Package Manager + +On OS X, you can run: + +```bash +$ brew install redis +``` + +Follow the instructions given by Homebrew to start these. + +In Ubuntu just run: + +```bash +$ sudo apt-get install redis-server +``` + +On Fedora or CentOS (requires EPEL enabled), just run: + +```bash +$ sudo yum install redis +``` + +If you are running Arch Linux just run: + +```bash +$ sudo pacman -S redis +$ sudo systemctl start redis +``` + +FreeBSD users will have to run the following: + +```bash +# portmaster databases/redis +``` diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index a06a53b250..2925fb4b58 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -85,9 +85,8 @@ description: This guide provides you with all you need to get started creating, enqueuing, and executing background jobs. - name: Testing Rails Applications - work_in_progress: true url: testing.html - description: This is a rather comprehensive guide to the various testing facilities in Rails. It covers everything from 'What is a test?' to the testing APIs. Enjoy. + description: This is a rather comprehensive guide to the various testing facilities in Rails. It covers everything from 'What is a test?' to Integration Testing. Enjoy. - name: Securing Rails Applications url: security.html @@ -101,9 +100,9 @@ url: configuring.html description: This guide covers the basic configuration settings for a Rails application. - - name: Rails Command Line Tools and Rake Tasks + name: The Rails Command Line url: command_line.html - description: This guide covers the command line tools and rake tasks provided by Rails. + description: This guide covers the command line tools provided by Rails. - name: Asset Pipeline url: asset_pipeline.html @@ -198,7 +197,6 @@ name: Ruby on Rails 5.0 Release Notes url: 5_0_release_notes.html description: Release notes for Rails 5.0. - work_in_progress: true - name: Ruby on Rails 4.2 Release Notes url: 4_2_release_notes.html diff --git a/guides/source/engines.md b/guides/source/engines.md index f9a37e45ac..0020112a1c 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -46,7 +46,7 @@ see how to hook it into an application. Engines can also be isolated from their host applications. This means that an application is able to have a path provided by a routing helper such as -`articles_path` and use an engine also that provides a path also called +`articles_path` and use an engine that also provides a path also called `articles_path`, and the two would not clash. Along with this, controllers, models and table names are also namespaced. You'll see how to do this later in this guide. @@ -184,7 +184,7 @@ end By inheriting from the `Rails::Engine` class, this gem notifies Rails that there's an engine at the specified path, and will correctly mount the engine inside the application, performing tasks such as adding the `app` directory of -the engine to the load path for models, mailers, controllers and views. +the engine to the load path for models, mailers, controllers, and views. The `isolate_namespace` method here deserves special notice. This call is responsible for isolating the controllers, models, routes and other things into @@ -1364,7 +1364,7 @@ You can define assets for precompilation in `engine.rb`: ```ruby initializer "blorgh.assets.precompile" do |app| - app.config.assets.precompile += %w(admin.css admin.js) + app.config.assets.precompile += %w( admin.js admin.css ) end ``` diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 65fdd7ca0d..31d5c4f71d 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -68,7 +68,7 @@ The Rails philosophy includes two major guiding principles: again, our code is more maintainable, more extensible, and less buggy. * **Convention Over Configuration:** Rails has opinions about the best way to do many things in a web application, and defaults to this set of conventions, rather than - require that you specify every minutiae through endless configuration files. + require that you specify minutiae through endless configuration files. Creating a New Rails Project ---------------------------- @@ -148,6 +148,10 @@ This will create a Rails application called Blog in a `blog` directory and install the gem dependencies that are already mentioned in `Gemfile` using `bundle install`. +NOTE: If you're using Windows Subsystem for Linux then there are currently some +limitations on file system notifications that mean you should disable the `spring` +and `listen` gems which you can do by running `rails new blog --skip-spring --skip-listen`. + TIP: You can see all of the command line options that the Rails application builder accepts by running `rails new -h`. @@ -178,6 +182,7 @@ of the files and folders that Rails created by default: |test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html).| |tmp/|Temporary files (like cache and pid files).| |vendor/|A place for all third-party code. In a typical Rails application this includes vendored gems.| +|.gitignore|This file tells git which files (or patterns) it should ignore. See [Github - Ignoring files](https://help.github.com/articles/ignoring-files) for more info about ignoring files. Hello, Rails! ------------- @@ -299,9 +304,6 @@ Rails.application.routes.draw do get 'welcome/index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - - # Serve websocket cable requests in-process - # mount ActionCable.server => '/cable' end ``` @@ -316,10 +318,6 @@ It should look something like the following: Rails.application.routes.draw do get 'welcome/index' - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - - # Serve websocket cable requests in-process - # mount ActionCable.server => '/cable' root 'welcome#index' end ``` @@ -356,6 +354,7 @@ resource. You need to add the _article resource_ to the ```ruby Rails.application.routes.draw do + get 'welcome/index' resources :articles @@ -462,7 +461,7 @@ available, Rails will raise an exception. In the above image, the bottom line has been truncated. Let's see what the full error message looks like: ->Missing template articles/new, application/new with {locale:[:en], formats:[:html], handlers:[:erb, :builder, :coffee]}. Searched in: * "/path/to/blog/app/views" +>ArticlesController#new is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] NOTE! For XHR/Ajax or API requests, this action would normally respond with 204 No Content: an empty white screen. Since you're loading it in a web browser, we assume that you expected to actually render a template, not… nothing, so we're showing an error to be extra-clear. If you expect 204 No Content, carry on. That's what you'll get from an XHR or API request. Give it a shot. That's quite a lot of text! Let's quickly go through and understand what each part of it means. @@ -472,27 +471,24 @@ The first part identifies which template is missing. In this case, it's the then it will attempt to load a template called `application/new`. It looks for one here because the `ArticlesController` inherits from `ApplicationController`. -The next part of the message contains a hash. The `:locale` key in this hash -simply indicates which spoken language template should be retrieved. By default, -this is the English - or "en" - template. The next key, `:formats` specifies the -format of the template to be served in response. The default format is `:html`, and -so Rails is looking for an HTML template. The final key, `:handlers`, is telling -us what _template handlers_ could be used to render our template. `:erb` is most -commonly used for HTML templates, `:builder` is used for XML templates, and -`:coffee` uses CoffeeScript to build JavaScript templates. - -The final part of this message tells us where Rails has looked for the templates. -Templates within a basic Rails application like this are kept in a single -location, but in more complex applications it could be many different paths. +The next part of the message contains `request.formats` which specifies +the format of template to be served in response. It is set to `text/html` as we +requested this page via browser, so Rails is looking for an HTML template. +`request.variants` specifies what kind of physical devices would be served by +the response and helps Rails determine which template to use in the response. +It is empty because no information has been provided. The simplest template that would work in this case would be one located at `app/views/articles/new.html.erb`. The extension of this file name is important: the first extension is the _format_ of the template, and the second extension -is the _handler_ that will be used. Rails is attempting to find a template -called `articles/new` within `app/views` for the application. The format for -this template can only be `html` and the handler must be one of `erb`, -`builder` or `coffee`. Because you want to create a new HTML form, you will be -using the `ERB` language which is designed to embed Ruby in HTML. +is the _handler_ that will be used to render the template. Rails is attempting +to find a template called `articles/new` within `app/views` for the +application. The format for this template can only be `html` and the default +handler for HTML is `erb`. Rails uses other handlers for other formats. +`builder` handler is used to build XML templates and `coffee` handler uses +CoffeeScript to build JavaScript templates. Since you want to create a new +HTML form, you will be using the `ERB` language which is designed to embed Ruby +in HTML. Therefore the file should be called `articles/new.html.erb` and needs to be located inside the `app/views` directory of the application. @@ -533,7 +529,7 @@ method called `form_for`. To use this method, add this code into <% end %> ``` -If you refresh the page now, you'll see the exact same form as in the example. +If you refresh the page now, you'll see the exact same form from our example above. Building forms in Rails is really just that easy! When you call `form_for`, you pass it an identifying object for this @@ -611,9 +607,11 @@ class ArticlesController < ApplicationController end ``` -If you re-submit the form now, you'll see another familiar error: a template is -missing. That's ok, we can ignore that for now. What the `create` action should -be doing is saving our new article to the database. +If you re-submit the form now, you may not see any change on the page. Don't worry! +This is because Rails by default returns `204 No Content` response for an action if +we don't specify what the response should be. We just added the `create` action +but didn't specify anything about how the response should be. In this case, the +`create` action should save our new article to the database. When a form is submitted, the fields of the form are sent to Rails as _parameters_. These parameters can then be referenced inside the controller @@ -635,8 +633,7 @@ this situation, the only parameters that matter are the ones from the form. TIP: Ensure you have a firm grasp of the `params` method, as you'll use it fairly regularly. Let's consider an example URL: **http://www.example.com/?username=dhh&email=dhh@email.com**. In this URL, `params[:username]` would equal "dhh" and `params[:email]` would equal "dhh@email.com". -If you re-submit the form one more time you'll now no longer get the missing -template error. Instead, you'll see something that looks like the following: +If you re-submit the form one more time, you'll see something that looks like the following: ```ruby <ActionController::Parameters {"title"=>"First Article!", "text"=>"This is my first article."} permitted: false> @@ -703,8 +700,8 @@ in case you want to reverse it later. When you run this migration it will create an `articles` table with one string column and a text column. It also creates two timestamp fields to allow Rails to track article creation and update times. -TIP: For more information about migrations, refer to [Rails Database Migrations] -(migrations.html). +TIP: For more information about migrations, refer to [Active Record Migrations] +(active_record_migrations.html). At this point, you can use a bin/rails command to run the migration: @@ -1158,7 +1155,7 @@ new articles. Create a file called `app/views/articles/edit.html.erb` and make it look as follows: ```html+erb -<h1>Editing article</h1> +<h1>Edit article</h1> <%= form_for :article, url: article_path(@article), method: :patch do |f| %> diff --git a/guides/source/i18n.md b/guides/source/i18n.md index f3802a142f..887774961a 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -866,7 +866,7 @@ This way you can provide special translations for various error messages at diff #### Error Message Interpolation -The translated model name, translated attribute name, and value are always available for interpolation. +The translated model name, translated attribute name, and value are always available for interpolation as `model`, `attribute` and `value` respectively. So, for example, instead of the default error message `"cannot be blank"` you could use the attribute name like this : `"Please fill in your %{attribute}"`. @@ -888,6 +888,7 @@ So, for example, instead of the default error message `"cannot be blank"` you co | inclusion | - | :inclusion | - | | exclusion | - | :exclusion | - | | associated | - | :invalid | - | +| non-optional association | - | :required | - | | numericality | - | :not_a_number | - | | numericality | :greater_than | :greater_than | count | | numericality | :greater_than_or_equal_to | :greater_than_or_equal_to | count | @@ -1120,9 +1121,9 @@ Contributing to Rails I18n I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in gems and real applications first, and only then cherry-picking the best-of-breed of most widely useful features for inclusion in the core. -Thus we encourage everybody to experiment with new ideas and features in gems or other libraries and make them available to the community. (Don't forget to announce your work on our [mailing list](http://groups.google.com/group/rails-i18n!)) +Thus we encourage everybody to experiment with new ideas and features in gems or other libraries and make them available to the community. (Don't forget to announce your work on our [mailing list](http://groups.google.com/group/rails-i18n)!) -If you find your own locale (language) missing from our [example translations data](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) repository for Ruby on Rails, please [_fork_](https://github.com/guides/fork-a-project-and-submit-your-modifications) the repository, add your data and send a [pull request](https://github.com/guides/pull-requests). +If you find your own locale (language) missing from our [example translations data](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) repository for Ruby on Rails, please [_fork_](https://github.com/guides/fork-a-project-and-submit-your-modifications) the repository, add your data and send a [pull request](https://help.github.com/articles/about-pull-requests/). Resources diff --git a/guides/source/initialization.md b/guides/source/initialization.md index 89e5346d86..57ed35d0d8 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -16,7 +16,7 @@ After reading this guide, you will know: -------------------------------------------------------------------------------- This guide goes through every method call that is -required to boot up the Ruby on Rails stack for a default Rails 4 +required to boot up the Ruby on Rails stack for a default Rails application, explaining each part in detail along the way. For this guide, we will be focusing on what happens when you execute `rails server` to boot your app. @@ -318,7 +318,7 @@ def parse!(args) args, options = args.dup, {} opt_parser = OptionParser.new do |opts| - opts.banner = "Usage: rails server [mongrel, thin, etc] [options]" + opts.banner = "Usage: rails server [puma, thin, etc] [options]" opts.on("-p", "--port=port", Integer, "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v } ... @@ -464,7 +464,7 @@ The `options[:config]` value defaults to `config.ru` which contains this: ```ruby # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require_relative 'config/environment' run <%= app_const %> ``` @@ -485,7 +485,7 @@ end The `initialize` method of `Rack::Builder` will take the block here and execute it within an instance of `Rack::Builder`. This is where the majority of the initialization process of Rails happens. The `require` line for `config/environment.rb` in `config.ru` is the first to run: ```ruby -require ::File.expand_path('../config/environment', __FILE__) +require_relative 'config/environment' ``` ### `config/environment.rb` @@ -495,7 +495,7 @@ This file is the common file required by `config.ru` (`rails server`) and Passen This file begins with requiring `config/application.rb`: ```ruby -require File.expand_path('../application', __FILE__) +require_relative 'application' ``` ### `config/application.rb` @@ -503,7 +503,7 @@ require File.expand_path('../application', __FILE__) This file requires `config/boot.rb`: ```ruby -require File.expand_path('../boot', __FILE__) +require_relative 'boot' ``` But only if it hasn't been required before, which would be the case in `rails server` @@ -663,7 +663,7 @@ DEFAULT_OPTIONS = { } def self.run(app, options = {}) - options = DEFAULT_OPTIONS.merge(options) + options = DEFAULT_OPTIONS.merge(options) if options[:Verbose] app = Rack::CommonLogger.new(app, STDOUT) diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb index 9abb863da6..bb50761b30 100644 --- a/guides/source/layout.html.erb +++ b/guides/source/layout.html.erb @@ -88,7 +88,7 @@ <div id="container"> <div class="wrapper"> <div id="mainCol"> - <%= yield.html_safe %> + <%= yield %> <h3>Feedback</h3> <p> @@ -127,13 +127,11 @@ <script type="text/javascript" src="javascripts/jquery.min.js"></script> <script type="text/javascript" src="javascripts/responsive-tables.js"></script> <script type="text/javascript" src="javascripts/guides.js"></script> - <script type="text/javascript" src="javascripts/syntaxhighlighter/shCore.js"></script> - <script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushRuby.js"></script> - <script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushXml.js"></script> - <script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushSql.js"></script> - <script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushPlain.js"></script> + <script type="text/javascript" src="javascripts/syntaxhighlighter.js"></script> <script type="text/javascript"> - SyntaxHighlighter.all(); + syntaxhighlighterConfig = { + autoLinks: false, + }; $(guidesIndex.bind); </script> </body> diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index 2722789c49..7e4ec5ba7e 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -630,6 +630,8 @@ to use in this case. redirect_back(fallback_location: root_path) ``` +NOTE: `redirect_to` and `redirect_back` do not halt and return immediately from method execution, but simply set HTTP responses. Statements occurring after them in a method will be executed. You can halt by an explicit `return` or some other halting mechanism, if needed. + #### Getting a Different Redirect Status Code Rails uses HTTP status code 302, a temporary redirect, when you call `redirect_to`. If you'd like to use a different status code, perhaps 301, a permanent redirect, you can use the `:status` option: @@ -749,7 +751,7 @@ When Rails renders a view as a response, it does so by combining the view with t ### Asset Tag Helpers -Asset tag helpers provide methods for generating HTML that link views to feeds, JavaScript, stylesheets, images, videos and audios. There are six asset tag helpers available in Rails: +Asset tag helpers provide methods for generating HTML that link views to feeds, JavaScript, stylesheets, images, videos, and audios. There are six asset tag helpers available in Rails: * `auto_discovery_link_tag` * `javascript_include_tag` diff --git a/guides/source/maintenance_policy.md b/guides/source/maintenance_policy.md index f99b6ebd31..7ced3eab1c 100644 --- a/guides/source/maintenance_policy.md +++ b/guides/source/maintenance_policy.md @@ -44,7 +44,7 @@ from. In special situations, where someone from the Core Team agrees to support more series, they are included in the list of supported series. -**Currently included series:** `5.0.Z`. +**Currently included series:** `5.0.Z`, `4.2.Z`. Security Issues --------------- diff --git a/guides/source/plugins.md b/guides/source/plugins.md index 8f055f8fe3..760ff431c0 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -30,7 +30,7 @@ Setup ----- Currently, Rails plugins are built as gems, _gemified plugins_. They can be shared across -different rails applications using RubyGems and Bundler if desired. +different Rails applications using RubyGems and Bundler if desired. ### Generate a gemified plugin. @@ -67,7 +67,7 @@ This will tell you that everything got generated properly and you are ready to s Extending Core Classes ---------------------- -This section will explain how to add a method to String that will be available anywhere in your rails application. +This section will explain how to add a method to String that will be available anywhere in your Rails application. In this example you will add a method to String named `to_squawk`. To begin, create a new test file with a few assertions: diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index 8148f70c31..ed935e1008 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -64,7 +64,7 @@ To use `rackup` instead of Rails' `rails server`, you can put the following insi ```ruby # Rails.root/config.ru -require ::File.expand_path('../config/environment', __FILE__) +require_relative 'config/environment' run Rails.application ``` diff --git a/guides/source/routing.md b/guides/source/routing.md index 756e0fefd7..937e313663 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -553,29 +553,23 @@ In particular, simple routing makes it very easy to map legacy URLs to new Rails ### Bound Parameters -When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: `:controller` maps to the name of a controller in your application, and `:action` maps to the name of an action within that controller. For example, consider this route: +When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. For example, consider this route: ```ruby -get ':controller(/:action(/:id))' +get 'photos(/:id)', to: :display ``` -If an incoming request of `/photos/show/1` is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the `show` action of the `PhotosController`, and to make the final parameter `"1"` available as `params[:id]`. This route will also route the incoming request of `/photos` to `PhotosController#index`, since `:action` and `:id` are optional parameters, denoted by parentheses. +If an incoming request of `/photos/1` is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the `display` action of the `PhotosController`, and to make the final parameter `"1"` available as `params[:id]`. This route will also route the incoming request of `/photos` to `PhotosController#display`, since `:id` is an optional parameter, denoted by parentheses. ### Dynamic Segments -You can set up as many dynamic segments within a regular route as you like. Anything other than `:controller` or `:action` will be available to the action as part of `params`. If you set up this route: +You can set up as many dynamic segments within a regular route as you like. Any segment will be available to the action as part of `params`. If you set up this route: ```ruby -get ':controller/:action/:id/:user_id' +get 'photos/:id/:user_id', to: 'photos#show' ``` -An incoming path of `/photos/show/1/2` will be dispatched to the `show` action of the `PhotosController`. `params[:id]` will be `"1"`, and `params[:user_id]` will be `"2"`. - -NOTE: You can't use `:namespace` or `:module` with a `:controller` path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g: - -```ruby -get ':controller(/:action(/:id))', controller: /admin\/[^\/]+/ -``` +An incoming path of `/photos/1/2` will be dispatched to the `show` action of the `PhotosController`. `params[:id]` will be `"1"`, and `params[:user_id]` will be `"2"`. TIP: By default, dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, `id: /[^\/]+/` allows anything except a slash. @@ -584,32 +578,24 @@ TIP: By default, dynamic segments don't accept dots - this is because the dot is You can specify static segments when creating a route by not prepending a colon to a fragment: ```ruby -get ':controller/:action/:id/with_user/:user_id' +get 'photos/:id/with_user/:user_id', to: 'photos#show' ``` -This route would respond to paths such as `/photos/show/1/with_user/2`. In this case, `params` would be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`. +This route would respond to paths such as `/photos/1/with_user/2`. In this case, `params` would be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`. ### The Query String The `params` will also include any parameters from the query string. For example, with this route: ```ruby -get ':controller/:action/:id' +get 'photos/:id', to: 'photos#show' ``` -An incoming path of `/photos/show/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`. +An incoming path of `/photos/1?user_id=2` will be dispatched to the `show` action of the `Photos` controller. `params` will be `{ controller: 'photos', action: 'show', id: '1', user_id: '2' }`. ### Defining Defaults -You do not need to explicitly use the `:controller` and `:action` symbols within a route. You can supply them as defaults: - -```ruby -get 'photos/:id', to: 'photos#show' -``` - -With this route, Rails will match an incoming path of `/photos/12` to the `show` action of `PhotosController`. - -You can also define other defaults in a route by supplying a hash for the `:defaults` option. This even applies to parameters that you do not specify as dynamic segments. For example: +You can define defaults in a route by supplying a hash for the `:defaults` option. This even applies to parameters that you do not specify as dynamic segments. For example: ```ruby get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' } diff --git a/guides/source/security.md b/guides/source/security.md index ca985134e6..aea9728c10 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -131,7 +131,7 @@ It works like this: * The user takes the cookie from the first step (which they previously copied) and replaces the current cookie in the browser. * The user has their original credit back. -Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers (mongrels). Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database). +Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers. Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database). The best _solution against it is not to store this kind of data in a session, but in the database_. In this case store the credit in the database and the logged_in_user_id in the session. @@ -249,7 +249,7 @@ There are many other possibilities, like using a `<script>` tag to make a cross- Note: We can't distinguish a `<script>` tag's origin—whether it's a tag on your own site or on some other malicious site—so we must block all `<script>` across the board, even if it's actually a safe same-origin script served from your own site. In these cases, explicitly skip CSRF protection on actions that serve JavaScript meant for a `<script>` tag. -To protect against all other forged requests, we introduce a _required security token_ that our site knows but other sites don't know. We include the security token in requests and verify it on the server. This is a one-liner in your application controller, and is the default for newly created rails applications: +To protect against all other forged requests, we introduce a _required security token_ that our site knows but other sites don't know. We include the security token in requests and verify it on the server. This is a one-liner in your application controller, and is the default for newly created Rails applications: ```ruby protect_from_forgery with: :exception @@ -287,7 +287,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, they may also create a self-contained attack._ -Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to= www.attacker.com. Here is an example of a legacy action: +Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to=www.attacker.com. Here is an example of a legacy action: ```ruby def legacy @@ -965,7 +965,7 @@ When `params[:token]` is one of: `[nil]`, `[nil, nil, ...]` or `['foo', nil]` it will bypass the test for `nil`, but `IS NULL` or `IN ('foo', NULL)` where clauses still will be added to the SQL query. -To keep rails secure by default, `deep_munge` replaces some of the values with +To keep Rails secure by default, `deep_munge` replaces some of the values with `nil`. Below table shows what the parameters look like based on `JSON` sent in request: diff --git a/guides/source/testing.md b/guides/source/testing.md index 050bdda9e3..0ac5121b12 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -37,10 +37,12 @@ controllers/ helpers/ mailers/ test_helper.rb fixtures/ integration/ models/ ``` -The `models` directory is meant to hold tests for your models, the `controllers` directory is meant to hold tests for your controllers and the `integration` directory is meant to hold tests that involve any number of controllers interacting. There is also a directory for testing your mailers and one for testing view helpers. +The `helpers`, `mailers`, and `models` directories are meant to hold tests for view helpers, mailers, and models, respectively. The `controllers` directory is meant to hold tests for controllers, routes, and views. The `integration` directory is meant to hold tests for interactions between controllers. Fixtures are a way of organizing test data; they reside in the `fixtures` directory. +A `jobs` directory will also be created when an associated test is first generated. + The `test_helper.rb` file holds the default configuration for your tests. @@ -146,18 +148,28 @@ Let us run this newly added test (where `6` is the number of line where the test ```bash $ bin/rails test test/models/article_test.rb:6 +Run options: --seed 44656 + +# Running: + F -Finished tests in 0.044632s, 22.4054 tests/s, 22.4054 assertions/s. +Failure: +ArticleTest#test_should_not_save_article_without_title [/path/to/blog/test/models/article_test.rb:6]: +Expected true to be nil or false + + +bin/rails test test/models/article_test.rb:6 - 1) Failure: -test_should_not_save_article_without_title(ArticleTest) [test/models/article_test.rb:6]: -Failed assertion, no message given. -1 tests, 1 assertions, 1 failures, 0 errors, 0 skips + +Finished in 0.023918s, 41.8090 runs/s, 41.8090 assertions/s. + +1 runs, 1 assertions, 1 failures, 0 errors, 0 skips + ``` -In the output, `F` denotes a failure. You can see the corresponding trace shown under `1)` along with the name of the failing test. The next few lines contain the stack trace followed by a message that mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable, every assertion provides an optional message parameter, as shown here: +In the output, `F` denotes a failure. You can see the corresponding trace shown under `Failure` along with the name of the failing test. The next few lines contain the stack trace followed by a message that mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable, every assertion provides an optional message parameter, as shown here: ```ruby test "should not save article without title" do @@ -169,8 +181,8 @@ end Running this test shows the friendlier assertion message: ```bash - 1) Failure: -test_should_not_save_article_without_title(ArticleTest) [test/models/article_test.rb:6]: +Failure: +ArticleTest#test_should_not_save_article_without_title [/path/to/blog/test/models/article_test.rb:6]: Saved the article without a title ``` @@ -186,11 +198,15 @@ Now the test should pass. Let us verify by running the test again: ```bash $ bin/rails test test/models/article_test.rb:6 +Run options: --seed 31252 + +# Running: + . -Finished tests in 0.047721s, 20.9551 tests/s, 20.9551 assertions/s. +Finished in 0.027476s, 36.3952 runs/s, 36.3952 assertions/s. -1 tests, 1 assertions, 0 failures, 0 errors, 0 skips +1 runs, 1 assertions, 0 failures, 0 errors, 0 skips ``` Now, if you noticed, we first wrote a test which fails for a desired @@ -215,16 +231,25 @@ Now you can see even more output in the console from running the tests: ```bash $ bin/rails test test/models/article_test.rb -E +Run options: --seed 1808 + +# Running: + +.E + +Error: +ArticleTest#test_should_report_error: +NameError: undefined local variable or method 'some_undefined_variable' for #<ArticleTest:0x007fee3aa71798> + test/models/article_test.rb:11:in 'block in <class:ArticleTest>' + -Finished tests in 0.030974s, 32.2851 tests/s, 0.0000 assertions/s. +bin/rails test test/models/article_test.rb:9 - 1) Error: -test_should_report_error(ArticleTest): -NameError: undefined local variable or method `some_undefined_variable' for #<ArticleTest:0x007fe32e24afe0> - test/models/article_test.rb:10:in `block in <class:ArticleTest>' -1 tests, 0 assertions, 0 failures, 1 errors, 0 skips + +Finished in 0.040609s, 49.2500 runs/s, 24.6250 assertions/s. + +2 runs, 1 assertions, 0 failures, 1 errors, 0 skips ``` Notice the 'E' in the output. It denotes a test with error. @@ -287,7 +312,6 @@ specify to make your test failure messages clearer. | `assert_not_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are not within `delta` of each other.| | `assert_throws( symbol, [msg] ) { block }` | Ensures that the given block throws the symbol.| | `assert_raises( exception1, exception2, ... ) { block }` | Ensures that the given block raises one of the given exceptions.| -| `assert_nothing_raised { block }` | Ensures that the given block doesn't raise any exceptions.| | `assert_instance_of( class, obj, [msg] )` | Ensures that `obj` is an instance of `class`.| | `assert_not_instance_of( class, obj, [msg] )` | Ensures that `obj` is not an instance of `class`.| | `assert_kind_of( class, obj, [msg] )` | Ensures that `obj` is an instance of `class` or is descending from it.| @@ -318,6 +342,7 @@ Rails adds some custom assertions of its own to the `minitest` framework: | --------------------------------------------------------------------------------- | ------- | | [`assert_difference(expressions, difference = 1, message = nil) {...}`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html#method-i-assert_difference) | Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.| | [`assert_no_difference(expressions, message = nil, &block)`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html#method-i-assert_no_difference) | Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.| +| [`assert_nothing_raised { block }`](http://api.rubyonrails.org/classes/ActiveSupport/TestCase.html#method-i-assert_nothing_raised) | Ensures that the given block doesn't raise any exceptions.| | [`assert_recognizes(expected_options, path, extras={}, message=nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes) | Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.| | [`assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_generates) | Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.| | [`assert_response(type, message = nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/ResponseAssertions.html#method-i-assert_response) | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range. You can also pass an explicit status number or its symbolic equivalent. For more information, see [full list of status codes](http://rubydoc.info/github/rack/rack/master/Rack/Utils#HTTP_STATUS_CODES-constant) and how their [mapping](http://rubydoc.info/github/rack/rack/master/Rack/Utils#SYMBOL_TO_STATUS_CODE-constant) works.| @@ -342,17 +367,21 @@ documentation](http://docs.seattlerb.org/minitest). ### The Rails Test Runner -We can run all of our tests at once by using the `rails test` command. +We can run all of our tests at once by using the `bin/rails test` command. -Or we can run a single test by passing the `rails test` command the filename containing the test cases. +Or we can run a single test file by passing the `bin/rails test` command the filename containing the test cases. ```bash $ bin/rails test test/models/article_test.rb -. +Run options: --seed 1559 -Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s. +# Running: -1 tests, 1 assertions, 0 failures, 0 errors, 0 skips +.. + +Finished in 0.027034s, 73.9810 runs/s, 110.9715 assertions/s. + +2 runs, 3 assertions, 0 failures, 0 errors, 0 skips ``` This will run all test methods from the test case. @@ -362,6 +391,10 @@ You can also run a particular test method from the test case by providing the ```bash $ bin/rails test test/models/article_test.rb -n test_the_truth +Run options: -n test_the_truth --seed 43583 + +# Running: + . Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s. @@ -372,7 +405,7 @@ Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s. You can also run a test at a specific line by providing the line number. ```bash -$ bin/rails test test/models/post_test.rb:44 # run specific test and line +$ bin/rails test test/models/article_test.rb:6 # run specific test and line ``` You can also run an entire directory of tests by providing the path to the directory. @@ -381,6 +414,38 @@ You can also run an entire directory of tests by providing the path to the direc $ bin/rails test test/controllers # run all tests from specific directory ``` +The test runner provides lot of other features too like failing fast, deferring test output +at the end of test run and so on. Check the documentation of the test runner as follows: + +```bash +$ bin/rails test -h +minitest options: + -h, --help Display this help. + -s, --seed SEED Sets random seed. Also via env. Eg: SEED=n rake + -v, --verbose Verbose. Show progress processing files. + -n, --name PATTERN Filter run on /regexp/ or string. + --exclude PATTERN Exclude /regexp/ or string from run. + +Known extensions: rails, pride + +Usage: bin/rails test [options] [files or directories] +You can run a single test by appending a line number to a filename: + + bin/rails test test/models/user_test.rb:27 + +You can run multiple files and directories at the same time: + + bin/rails test test/controllers test/integration/login_test.rb + +By default test failures and errors are reported inline during a run. + +Rails options: + -e, --environment ENV Run tests in the ENV environment + -b, --backtrace Show the complete backtrace + -d, --defer-output Output test failures and errors after the test run + -f, --fail-fast Abort test run on first failure or error + -c, --[no-]color Enable color in the output +``` The Test Database ----------------- @@ -529,7 +594,7 @@ Integration Testing Integration tests are used to test how various parts of your application interact. They are generally used to test important workflows within our application. -For creating Rails integration tests, we use the 'test/integration' directory for our application. Rails provides a generator to create an integration test skeleton for us. +For creating Rails integration tests, we use the `test/integration` directory for our application. Rails provides a generator to create an integration test skeleton for us. ```bash $ bin/rails generate integration_test user_flows @@ -685,9 +750,8 @@ Let's take a look at one such test, `test_should_get_index` from the file `artic # articles_controller_test.rb class ArticlesControllerTest < ActionDispatch::IntegrationTest test "should get index" do - get '/articles' + get articles_url assert_response :success - assert_includes @response.body, 'Articles' end end ``` @@ -695,30 +759,29 @@ end In the `test_should_get_index` test, Rails simulates a request on the action called `index`, making sure the request was successful and also ensuring that the right response body has been generated. -The `get` method kicks off the web request and populates the results into the `@response`. It accepts 4 arguments: - -* The action of the controller you are requesting. - This can be in the form of a string or a route (i.e. `articles_url`). +The `get` method kicks off the web request and populates the results into the `@response`. It can accept up to 6 arguments: +* The URI of the controller action you are requesting. + This can be in the form of a string or a route helper (e.g. `articles_url`). * `params`: option with a hash of request parameters to pass into the action (e.g. query string parameters or article variables). - -* `session`: option with a hash of session variables to pass along with the request. - -* `flash`: option with a hash of flash values. +* `headers`: for setting the headers that will be passed with the request. +* `env`: for customizing the request environment as needed. +* `xhr`: whether the request is Ajax request or not. Can be set to true for marking the request as Ajax. +* `as`: for encoding the request with different content type. Supports `:json` by default. All of these keyword arguments are optional. -Example: Calling the `:show` action, passing an `id` of 12 as the `params` and setting a `user_id` of 5 in the session: +Example: Calling the `:show` action, passing an `id` of 12 as the `params` and setting `HTTP_REFERER` header: ```ruby -get(:show, params: { id: 12 }, session: { user_id: 5 }) +get article_url, params: { id: 12 }, headers: { "HTTP_REFERER" => "http://example.com/home" } ``` -Another example: Calling the `:view` action, passing an `id` of 12 as the `params`, this time with no session, but with a flash message. +Another example: Calling the `:update` action, passing an `id` of 12 as the `params` as an Ajax request. ```ruby -get(view_url, params: { id: 12 }, flash: { message: 'booya!' }) +patch article_url, params: { id: 12 }, xhr: true ``` NOTE: If you try running `test_should_create_article` test from `articles_controller_test.rb` it will fail on account of the newly added model level validation and rightly so. @@ -728,7 +791,7 @@ Let us modify `test_should_create_article` test in `articles_controller_test.rb` ```ruby test "should create article" do assert_difference('Article.count') do - post '/article', params: { article: { title: 'Some title' } } + post articles_url, params: { article: { body: 'Rails is awesome!', title: 'Hello Rails' } } end assert_redirected_to article_path(Article.last) @@ -759,7 +822,7 @@ To test AJAX requests, you can specify the `xhr: true` option to `get`, `post`, ```ruby test "ajax request" do - article = articles(:first) + article = articles(:one) get article_url(article), xhr: true assert_equal 'hello world', @response.body @@ -785,27 +848,38 @@ cookies["are_good_for_u"] cookies[:are_good_for_u] ### Instance Variables Available -You also have access to three instance variables in your functional tests: +You also have access to three instance variables in your functional tests, after a request is made: * `@controller` - The controller processing the request * `@request` - The request object * `@response` - The response object + +```ruby +class ArticlesControllerTest < ActionDispatch::IntegrationTest + test "should get index" do + get articles_url + + assert_equal "index", @controller.action_name + assert_equal "application/x-www-form-urlencoded", @request.media_type + assert_match "Articles", @response.body + end +end +``` + ### Setting Headers and CGI variables [HTTP headers](http://tools.ietf.org/search/rfc2616#section-5.3) and [CGI variables](http://tools.ietf.org/search/rfc3875#section-4.1) -can be set directly on the `@request` instance variable: +can be passed as headers: ```ruby # setting an HTTP Header -@request.headers["Accept"] = "text/plain, text/html" -get articles_url # simulate the request with custom header +get articles_url, headers: { "Content-Type": "text/plain" } # simulate the request with custom header # setting a CGI variable -@request.headers["HTTP_REFERER"] = "http://example.com/home" -post article_url # simulate the request with custom env variable +get articles_url, headers: { "HTTP_REFERER": "http://example.com/home" } # simulate the request with custom env variable ``` ### Testing `flash` notices @@ -841,7 +915,7 @@ F Finished in 0.114870s, 8.7055 runs/s, 34.8220 assertions/s. 1) Failure: -ArticlesControllerTest#test_should_create_article [/Users/zzak/code/bench/sharedapp/test/controllers/articles_controller_test.rb:16]: +ArticlesControllerTest#test_should_create_article [/test/controllers/articles_controller_test.rb:16]: --- expected +++ actual @@ -1 +1 @@ @@ -890,7 +964,7 @@ Let's write a test for the `:show` action: ```ruby test "should show article" do article = articles(:one) - get '/article', params: { id: article.id } + get article_url(article) assert_response :success end ``` @@ -916,7 +990,7 @@ We can also add a test for updating an existing Article. test "should update article" do article = articles(:one) - patch '/article', params: { id: article.id, article: { title: "updated" } } + patch article_url(article), params: { article: { title: "updated" } } assert_redirected_to article_path(article) # Reload association to fetch updated data and assert that title is updated. @@ -959,7 +1033,7 @@ class ArticlesControllerTest < ActionDispatch::IntegrationTest end test "should update article" do - patch '/article', params: { id: @article.id, article: { title: "updated" } } + patch article_url(@article), params: { article: { title: "updated" } } assert_redirected_to article_path(@article) # Reload association to fetch updated data and assert that title is updated. @@ -977,11 +1051,11 @@ To avoid code duplication, you can add your own test helpers. Sign in helper can be a good example: ```ruby -#test/test_helper.rb +# test/test_helper.rb module SignInHelper - def sign_in(user) - session[:user_id] = user.id + def sign_in_as(user) + post sign_in_url(email: user.email, password: user.password) end end @@ -997,7 +1071,7 @@ class ProfileControllerTest < ActionDispatch::IntegrationTest test "should show profile" do # helper is now reusable from any controller test case - sign_in users(:david) + sign_in_as users(:david) get profile_url assert_response :success @@ -1008,7 +1082,7 @@ end Testing Routes -------------- -Like everything else in your Rails application, you can test your routes. +Like everything else in your Rails application, you can test your routes. Route tests reside in `test/controllers/` or are part of controller tests. NOTE: If your application has complex routes, Rails provides a number of useful helpers to test them. @@ -1283,7 +1357,7 @@ Here is an example using the [`travel_to`](http://api.rubyonrails.org/classes/Ac user = User.create(name: 'Gaurish', activation_date: Date.new(2004, 10, 24)) assert_not user.applicable_for_gifting? travel_to Date.new(2004, 11, 24) do - assert_equal Date.new(2004, 10, 24), user.activation_date # inside the travel_to block `Date.current` is mocked + assert_equal Date.new(2004, 10, 24), user.activation_date # inside the `travel_to` block `Date.current` is mocked assert user.applicable_for_gifting? end assert_equal Date.new(2004, 10, 24), user.activation_date # The change was visible only inside the `travel_to` block. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 82080c4def..dda2b12a3a 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -44,7 +44,7 @@ TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterp ### The Update Task -Rails provides the `app:update` task (`rails:update` on 4.2 and earlier). After updating the Rails version +Rails provides the `app:update` task (`rake rails:update` on 4.2 and earlier). After updating the Rails version in the Gemfile, run this task. This will help you with the creation of new files and changes of old files in an interactive session. @@ -68,14 +68,16 @@ Don't forget to review the difference, to see if there were any unexpected chang Upgrading from Rails 4.2 to Rails 5.0 ------------------------------------- -### Ruby 2.2.2+ +For more information on changes made to Rails 5.0 please see the [release notes](5_0_release_notes.html). -From Ruby on Rails 5.0 onwards, Ruby 2.2.2+ is the only supported version. -Make sure you are on Ruby 2.2.2 version or greater, before you proceed. +### Ruby 2.2.2+ required -### Active Record models now inherit from ApplicationRecord by default +From Ruby on Rails 5.0 onwards, Ruby 2.2.2+ is the only supported Ruby version. +Make sure you are on Ruby 2.2.2 version or greater, before you proceed. -In Rails 4.2 an Active Record model inherits from `ActiveRecord::Base`. In Rails 5.0, +### Active Record Models Now Inherit from ApplicationRecord by Default + +In Rails 4.2, an Active Record model inherits from `ActiveRecord::Base`. In Rails 5.0, all models inherit from `ApplicationRecord`. `ApplicationRecord` is a new superclass for all app models, analogous to app @@ -83,7 +85,7 @@ controllers subclassing `ApplicationController` instead of `ActionController::Base`. This gives apps a single spot to configure app-wide model behavior. -When upgrading from Rails 4.2 to Rails 5.0 you need to create an +When upgrading from Rails 4.2 to Rails 5.0, you need to create an `application_record.rb` file in `app/models/` and add the following content: ``` @@ -92,7 +94,9 @@ class ApplicationRecord < ActiveRecord::Base end ``` -### Halting callback chains via `throw(:abort)` +Then make sure that all your models inherit from it. + +### Halting Callback Chains via `throw(:abort)` In Rails 4.2, when a 'before' callback returns `false` in Active Record and Active Model, then the entire callback chain is halted. In other words, @@ -117,12 +121,12 @@ halted the chain when any value was returned. See [#17227](https://github.com/rails/rails/pull/17227) for more details. -### ActiveJob jobs now inherit from ApplicationJob by default +### ActiveJob Now Inherits from ApplicationJob by Default -In Rails 4.2 an ActiveJob inherits from `ActiveJob::Base`. In Rails 5.0 this +In Rails 4.2, an Active Job inherits from `ActiveJob::Base`. In Rails 5.0, this behavior has changed to now inherit from `ApplicationJob`. -When upgrading from Rails 4.2 to Rails 5.0 you need to create an +When upgrading from Rails 4.2 to Rails 5.0, you need to create an `application_job.rb` file in `app/jobs/` and add the following content: ``` @@ -134,6 +138,210 @@ Then make sure that all your job classes inherit from it. See [#19034](https://github.com/rails/rails/pull/19034) for more details. +### Rails Controller Testing + +`assigns` and `assert_template` have been extracted to the `rails-controller-testing` gem. To +continue using these methods in your controller tests, add `gem 'rails-controller-testing'` to +your Gemfile. + +If you are using Rspec for testing, please see the extra configuration required in the gem's +documentation. + +### Autoloading is Disabled After Booting in the Production Environment + +Autoloading is now disabled after booting in the production environment by +default. + +Eager loading the application is part of the boot process, so top-level +constants are fine and are still autoloaded, no need to require their files. + +Constants in deeper places only executed at runtime, like regular method bodies, +are also fine because the file defining them will have been eager loaded while booting. + +For the vast majority of applications this change needs no action. But in the +very rare event that your application needs autoloading while running in +production mode, set `Rails.application.config.enable_dependency_loading` to +true. + +### XML Serialization + +`ActiveModel::Serializers::Xml` has been extracted from Rails to the `activemodel-serializers-xml` +gem. To continue using XML serialization in your application, add `gem 'activemodel-serializers-xml'` +to your Gemfile. + +### Removed Support for Legacy `mysql` Database Adapter + +Rails 5 removes support for the legacy `mysql` database adapter. Most users should be able to +use `mysql2` instead. It will be converted to a separate gem when we find someone to maintain +it. + +### Removed Support for Debugger + +`debugger` is not supported by Ruby 2.2 which is required by Rails 5. Use `byebug` instead. + +### Use bin/rails for running tasks and tests + +Rails 5 adds the ability to run tasks and tests through `bin/rails` instead of rake. Generally +these changes are in parallel with rake, but some were ported over altogether. + +To use the new test runner simply type `bin/rails test`. + +`rake dev:cache` is now `rails dev:cache`. + +Run `bin/rails` to see the list of commands available. + +### `ActionController::Parameters` No Longer Inherits from `HashWithIndifferentAccess` + +Calling `params` in your application will now return an object instead of a hash. If your +parameters are already permitted, then you will not need to make any changes. If you are using `slice` +and other methods that depend on being able to read the hash regardless of `permitted?` you will +need to upgrade your application to first permit and then convert to a hash. + + params.permit([:proceed_to, :return_to]).to_h + +### `protect_from_forgery` Now Defaults to `prepend: false` + +`protect_from_forgery` defaults to `prepend: false` which means that it will be inserted into +the callback chain at the point in which you call it in your application. If you want +`protect_from_forgery` to always run first, then you should change your application to use +`protect_from_forgery prepend: true`. + +### Default Template Handler is Now RAW + +Files without a template handler in their extension will be rendered using the raw handler. +Previously Rails would render files using the ERB template handler. + +If you do not want your file to be handled via the raw handler, you should add an extension +to your file that can be parsed by the appropriate template handler. + +### Added Wildcard Matching for Template Dependencies + +You can now use wildcard matching for your template dependencies. For example, if you were +defining your templates as such: + +```erb +<% # Template Dependency: recordings/threads/events/subscribers_changed %> +<% # Template Dependency: recordings/threads/events/completed %> +<% # Template Dependency: recordings/threads/events/uncompleted %> +``` + +You can now just call the dependency once with a wildcard. + +```erb +<% # Template Dependency: recordings/threads/events/* %> +``` + +### Removed Support for `protected_attributes` Gem + +The `protected_attributes` gem is no longer supported in Rails 5. + +### Removed support for `activerecord-deprecated_finders` gem + +The `activerecord-deprecated_finders` gem is no longer supported in Rails 5. + +### `ActiveSupport::TestCase` Default Test Order is Now Random + +When tests are run in your application, the default order is now `:random` +instead of `:sorted`. Use the following config option to set it back to `:sorted`. + +```ruby +# config/environments/test.rb +Rails.application.configure do + config.active_support.test_order = :sorted +end +``` + +### `ActionController::Live` became a `Concern` + +If you include `ActionController::Live` in another module that is included in your controller, then you +should also extend the module with `ActiveSupport::Concern`. Alternatively, you can use the `self.included` hook +to include `ActionController::Live` directly to the controller once the `StreamingSupport` is included. + +This means that if your application used to have its own streaming module, the following code +would break in production mode: + +```ruby +# This is a work-around for streamed controllers performing authentication with Warden/Devise. +# See https://github.com/plataformatec/devise/issues/2332 +# Authenticating in the router is another solution as suggested in that issue +class StreamingSupport + include ActionController::Live # this won't work in production for Rails 5 + # extend ActiveSupport::Concern # unless you uncomment this line. + + def process(name) + super(name) + rescue ArgumentError => e + if e.message == 'uncaught throw :warden' + throw :warden + else + raise e + end + end +end +``` + +### New Framework Defaults + +#### Active Record `belongs_to` Required by Default Option + +`belongs_to` will now trigger a validation error by default if the association is not present. + +This can be turned off per-association with `optional: true`. + +This default will be automatically configured in new applications. If existing application +want to add this feature it will need to be turned on in an initializer. + + config.active_record.belongs_to_required_by_default = true + +#### Per-form CSRF Tokens + +Rails 5 now supports per-form CSRF tokens to mitigate against code-injection attacks with forms +created by JavaScript. With this option turned on, forms in your application will each have their +own CSRF token that is specified to the action and method for that form. + + config.action_controller.per_form_csrf_tokens = true + +#### Forgery Protection with Origin Check + +You can now configure your application to check if the HTTP `Origin` header should be checked +against the site's origin as an additional CSRF defense. Set the following in your config to +true: + + config.action_controller.forgery_protection_origin_check = true + +#### Allow Configuration of Action Mailer Queue Name + +The default mailer queue name is `mailers`. This configuration option allows you to globally change +the queue name. Set the following in your config: + + config.action_mailer.deliver_later_queue_name = :new_queue_name + +#### Support Fragment Caching in Action Mailer Views + +Set `config.action_mailer.perform_caching` in your config to determine whether your Action Mailer views +should support caching. + + config.action_mailer.perform_caching = true + +#### Configure the Output of `db:structure:dump` + +If you're using `schema_search_path` or other PostgreSQL extensions, you can control how the schema is +dumped. Set to `:all` to generate all dumps, or to `:schema_search_path` to generate from schema search path. + + config.active_record.dump_schemas = :all + +#### Configure SSL Options to Enable HSTS with Subdomains + +Set the following in your config to enable HSTS when using subdomains: + + config.ssl_options = { hsts: { subdomains: true } } + +#### Preserve Timezone of the Receiver + +When using Ruby 2.4, you can preserve the timezone of the receiver when calling `to_time`. + + ActiveSupport.to_time_preserves_timezone = false + Upgrading from Rails 4.1 to Rails 4.2 ------------------------------------- @@ -979,7 +1187,7 @@ Please read [Pull Request #9978](https://github.com/rails/rails/pull/9978) for d * Rails 4.0 has deprecated `ActionController::Base.page_cache_extension` option. Use `ActionController::Base.default_static_extension` instead. -* Rails 4.0 has removed Action and Page caching from Action Pack. You will need to add the `actionpack-action_caching` gem in order to use `caches_action` and the `actionpack-page_caching` to use `caches_pages` in your controllers. +* Rails 4.0 has removed Action and Page caching from Action Pack. You will need to add the `actionpack-action_caching` gem in order to use `caches_action` and the `actionpack-page_caching` to use `caches_page` in your controllers. * Rails 4.0 has removed the XML parameters parser. You will need to add the `actionpack-xml_parser` gem if you require this feature. @@ -1218,7 +1426,7 @@ config.assets.digest = true # config.assets.manifest = YOUR_PATH # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) -# config.assets.precompile += %w( search.js ) +# config.assets.precompile += %w( admin.js admin.css ) # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true diff --git a/guides/w3c_validator.rb b/guides/w3c_validator.rb index 71f044b9c4..2ce27e2e16 100644 --- a/guides/w3c_validator.rb +++ b/guides/w3c_validator.rb @@ -21,17 +21,16 @@ # # Separate many using commas: # -# # validates only association_basics.html and migrations.html -# rake guides:validate ONLY=assoc,migrations +# # validates only association_basics.html and command_line.html +# rake guides:validate ONLY=assoc,command # # --------------------------------------------------------------------------- -require 'w3c_validators' +require "w3c_validators" include W3CValidators module RailsGuides class Validator - def validate validator = MarkupValidator.new STDOUT.sync = true @@ -57,40 +56,39 @@ module RailsGuides end private - def guides_to_validate - guides = Dir["./output/*.html"] - guides.delete("./output/layout.html") - guides.delete("./output/_license.html") - guides.delete("./output/_welcome.html") - ENV.key?('ONLY') ? select_only(guides) : guides - end + def guides_to_validate + guides = Dir["./output/*.html"] + guides.delete("./output/layout.html") + guides.delete("./output/_license.html") + guides.delete("./output/_welcome.html") + ENV.key?("ONLY") ? select_only(guides) : guides + end - def select_only(guides) - prefixes = ENV['ONLY'].split(",").map(&:strip) - guides.select do |guide| - prefixes.any? {|p| guide.start_with?("./output/#{p}")} + def select_only(guides) + prefixes = ENV["ONLY"].split(",").map(&:strip) + guides.select do |guide| + prefixes.any? { |p| guide.start_with?("./output/#{p}") } + end end - end - def show_results(error_list) - if error_list.size == 0 - puts "\n\nAll checked guides validate OK!" - else - error_summary = error_detail = "" + def show_results(error_list) + if error_list.size == 0 + puts "\n\nAll checked guides validate OK!" + else + error_summary = error_detail = "" - error_list.each_pair do |name, errors| - error_summary += "\n #{name}" - error_detail += "\n\n #{name} has #{errors.size} validation error(s):\n" - errors.each do |error| - error_detail += "\n "+error.to_s.delete("\n") + error_list.each_pair do |name, errors| + error_summary += "\n #{name}" + error_detail += "\n\n #{name} has #{errors.size} validation error(s):\n" + errors.each do |error| + error_detail += "\n "+error.to_s.delete("\n") + end end - end - puts "\n\nThere are #{error_list.size} guides with validation errors:\n" + error_summary - puts "\nHere are the detailed errors for each guide:" + error_detail + puts "\n\nThere are #{error_list.size} guides with validation errors:\n" + error_summary + puts "\nHere are the detailed errors for each guide:" + error_detail + end end - end - end end diff --git a/rails.gemspec b/rails.gemspec index 8f9cc181a0..2d5be58c17 100644 --- a/rails.gemspec +++ b/rails.gemspec @@ -1,33 +1,33 @@ -version = File.read(File.expand_path('../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'rails' + s.name = "rails" s.version = version - s.summary = 'Full-stack web application framework.' - s.description = 'Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.' + s.summary = "Full-stack web application framework." + s.description = "Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration." - s.required_ruby_version = '>= 2.2.2' - s.required_rubygems_version = '>= 1.8.11' + s.required_ruby_version = ">= 2.2.2" + s.required_rubygems_version = ">= 1.8.11" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = ['README.md'] + s.files = ["README.md"] - s.add_dependency 'activesupport', version - s.add_dependency 'actionpack', version - s.add_dependency 'actionview', version - s.add_dependency 'activemodel', version - s.add_dependency 'activerecord', version - s.add_dependency 'actionmailer', version - s.add_dependency 'activejob', version - s.add_dependency 'actioncable', version - s.add_dependency 'railties', version + s.add_dependency "activesupport", version + s.add_dependency "actionpack", version + s.add_dependency "actionview", version + s.add_dependency "activemodel", version + s.add_dependency "activerecord", version + s.add_dependency "actionmailer", version + s.add_dependency "activejob", version + s.add_dependency "actioncable", version + s.add_dependency "railties", version - s.add_dependency 'bundler', '>= 1.3.0', '< 2.0' - s.add_dependency 'sprockets-rails', '>= 2.0.0' + s.add_dependency "bundler", ">= 1.3.0", "< 2.0" + s.add_dependency "sprockets-rails", ">= 2.0.0" end diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 982385438b..b488e4ed8e 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,61 @@ +* Allow the use of listen's 3.1.x branch + + *Esteban Santana Santana* + +* Run `Minitest.after_run` hooks when running `rails test`. + + *Michael Grosser* + +* Run `before_configuration` callbacks as soon as application constant + inherits from `Rails::Application`. + + Fixes #19880. + + *Yuji Yaginuma* + +* A generated app should not include Uglifier with `--skip-javascript` option. + + *Ben Pickles* + +* Set session store to cookie store internally and remove the initializer from + the generated app. + + *Prathamesh Sonpatki* + +* Set the server host using the `HOST` environment variable. + + *mahnunchik* + +* Add public API to register new folders for `rake notes`: + + config.annotations.register_directories('spec', 'features') + + *John Meehan* + +* Display name of the class defining the initializer along with the initializer + name in the output of `rails initializers`. + + Before: + disable_dependency_loading + + After: + DemoApp::Application.disable_dependency_loading + + *ta1kt0me* + +* Do not run `bundle install` when generating a new plugin. + + Since bundler 1.12.0, the gemspec is validated so the `bundle install` + command will fail just after the gem is created causing confusion to the + users. This change was a bug fix to correctly validate gemspecs. + + *Rafael Mendonça França* + +* Default `config.assets.quiet = true` in the development environment. Suppress + logging of assets requests by default. + + *Kevin McPhillips* + * Ensure `/rails/info` routes match in development for apps with a catch-all globbing route. *Nicholas Firth-McCoy* diff --git a/railties/Rakefile b/railties/Rakefile index db23bbabaa..202644fb26 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -1,11 +1,11 @@ -require 'rake/testtask' +require "rake/testtask" -task :default => :test +task default: :test task :package desc "Run all unit tests" -task :test => 'test:isolated' +task test: "test:isolated" namespace :test do task :isolated do @@ -14,8 +14,8 @@ namespace :test do Dir[*test_files].each do |file| next true if file.include?("fixtures") dash_i = [ - 'test', - 'lib', + "test", + "lib", "#{File.dirname(__FILE__)}/../activesupport/lib", "#{File.dirname(__FILE__)}/../actionpack/lib", "#{File.dirname(__FILE__)}/../activemodel/lib" @@ -25,9 +25,9 @@ namespace :test do end end -Rake::TestTask.new('test:regular') do |t| - t.libs << 'test' << "#{File.dirname(__FILE__)}/../activesupport/lib" - t.pattern = 'test/**/*_test.rb' +Rake::TestTask.new("test:regular") do |t| + t.libs << "test" << "#{File.dirname(__FILE__)}/../activesupport/lib" + t.pattern = "test/**/*_test.rb" t.warning = false t.verbose = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) diff --git a/railties/exe/rails b/railties/exe/rails index 82c17cabce..7e791c1f99 100755 --- a/railties/exe/rails +++ b/railties/exe/rails @@ -1,9 +1,9 @@ #!/usr/bin/env ruby -git_path = File.expand_path('../../../.git', __FILE__) +git_path = File.expand_path("../../../.git", __FILE__) if File.exist?(git_path) - railties_path = File.expand_path('../../lib', __FILE__) + railties_path = File.expand_path("../../lib", __FILE__) $:.unshift(railties_path) end require "rails/cli" diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index fe789f3c2a..5d862e3fec 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -1,18 +1,18 @@ -require 'rails/ruby_version_check' +require "rails/ruby_version_check" -require 'pathname' +require "pathname" -require 'active_support' -require 'active_support/dependencies/autoload' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/array/extract_options' +require "active_support" +require "active_support/dependencies/autoload" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/array/extract_options" -require 'rails/application' -require 'rails/version' +require "rails/application" +require "rails/version" -require 'active_support/railtie' -require 'action_dispatch/railtie' +require "active_support/railtie" +require "action_dispatch/railtie" # UTF-8 is the default internal and external encoding. silence_warnings do @@ -46,13 +46,13 @@ module Rails def backtrace_cleaner @backtrace_cleaner ||= begin - # Relies on Active Support, so we have to lazy load to postpone definition until AS has been loaded - require 'rails/backtrace_cleaner' + # Relies on Active Support, so we have to lazy load to postpone definition until Active Support has been loaded + require "rails/backtrace_cleaner" Rails::BacktraceCleaner.new end end - # Returns a Pathname object of the current rails project, + # Returns a Pathname object of the current Rails project, # otherwise it returns nil if there is no project: # # Rails.root @@ -77,7 +77,7 @@ module Rails @_env = ActiveSupport::StringInquirer.new(environment) end - # Returns all rails groups for loading based on: + # Returns all Rails groups for loading based on: # # * The Rails environment; # * The environment variable RAILS_GROUPS; @@ -100,7 +100,7 @@ module Rails end # Returns a Pathname object of the public folder of the current - # rails project, otherwise it returns nil if there is no project: + # Rails project, otherwise it returns nil if there is no project: # # Rails.public_path # # => #<Pathname:/Users/someuser/some/path/project/public> diff --git a/railties/lib/rails/all.rb b/railties/lib/rails/all.rb index 1a7f7855f1..7606ea0e46 100644 --- a/railties/lib/rails/all.rb +++ b/railties/lib/rails/all.rb @@ -1,4 +1,4 @@ -require 'rails' +require "rails" %w( active_record/railtie diff --git a/railties/lib/rails/api/task.rb b/railties/lib/rails/api/task.rb index d478bbf9e8..bc670b1d75 100644 --- a/railties/lib/rails/api/task.rb +++ b/railties/lib/rails/api/task.rb @@ -1,33 +1,33 @@ -require 'rdoc/task' +require "rdoc/task" module Rails module API class Task < RDoc::Task RDOC_FILES = { - 'activesupport' => { - :include => %w( + "activesupport" => { + include: %w( README.rdoc lib/active_support/**/*.rb ), - :exclude => 'lib/active_support/vendor/*' + exclude: "lib/active_support/vendor/*" }, - 'activerecord' => { - :include => %w( + "activerecord" => { + include: %w( README.rdoc lib/active_record/**/*.rb ) }, - 'activemodel' => { - :include => %w( + "activemodel" => { + include: %w( README.rdoc lib/active_model/**/*.rb ) }, - 'actionpack' => { - :include => %w( + "actionpack" => { + include: %w( README.rdoc lib/abstract_controller/**/*.rb lib/action_controller/**/*.rb @@ -35,41 +35,41 @@ module Rails ) }, - 'actionview' => { - :include => %w( + "actionview" => { + include: %w( README.rdoc lib/action_view/**/*.rb ), - :exclude => 'lib/action_view/vendor/*' + exclude: "lib/action_view/vendor/*" }, - 'actionmailer' => { - :include => %w( + "actionmailer" => { + include: %w( README.rdoc lib/action_mailer/**/*.rb ) }, - 'activejob' => { - :include => %w( + "activejob" => { + include: %w( README.md lib/active_job/**/*.rb ) }, - 'actioncable' => { - :include => %w( + "actioncable" => { + include: %w( README.md lib/action_cable/**/*.rb ) }, - 'railties' => { - :include => %w( + "railties" => { + include: %w( README.rdoc lib/**/*.rb ), - :exclude => 'lib/rails/generators/rails/**/templates/**/*.rb' + exclude: "lib/rails/generators/rails/**/templates/**/*.rb" } } @@ -92,16 +92,16 @@ module Rails end def load_and_configure_sdoc - require 'sdoc' + require "sdoc" - self.title = 'Ruby on Rails API' + self.title = "Ruby on Rails API" self.rdoc_dir = api_dir - options << '-m' << api_main - options << '-e' << 'UTF-8' + options << "-m" << api_main + options << "-e" << "UTF-8" - options << '-f' << 'sdoc' - options << '-T' << 'rails' + options << "-f" << "sdoc" + options << "-T" << "rails" rescue LoadError $stderr.puts %(Unable to load SDoc, please add\n\n gem 'sdoc', require: false\n\nto the Gemfile.) exit 1 @@ -121,22 +121,35 @@ module Rails rdoc_files.exclude("#{cdr}/#{pattern}") end end + + # Only generate documentation for files that have been + # changed since the API was generated. + if Dir.exist?("doc/rdoc") && !ENV["ALL"] + last_generation = DateTime.rfc2822(File.open("doc/rdoc/created.rid", &:readline)) + + rdoc_files.keep_if do |file| + File.mtime(file).to_datetime > last_generation + end + + # Nothing to do + exit(0) if rdoc_files.empty? + end end def setup_horo_variables - ENV['HORO_PROJECT_NAME'] = 'Ruby on Rails' - ENV['HORO_PROJECT_VERSION'] = rails_version + ENV["HORO_PROJECT_NAME"] = "Ruby on Rails" + ENV["HORO_PROJECT_VERSION"] = rails_version end def api_main - component_root_dir('railties') + '/RDOC_MAIN.rdoc' + component_root_dir("railties") + "/RDOC_MAIN.rdoc" end end class RepoTask < Task def load_and_configure_sdoc super - options << '-g' # link to GitHub, SDoc flag + options << "-g" # link to GitHub, SDoc flag end def component_root_dir(component) @@ -144,7 +157,7 @@ module Rails end def api_dir - 'doc/rdoc' + "doc/rdoc" end end @@ -156,7 +169,7 @@ module Rails class StableTask < RepoTask def rails_version - File.read('RAILS_VERSION').strip + File.read("RAILS_VERSION").strip end end end diff --git a/railties/lib/rails/app_loader.rb b/railties/lib/rails/app_loader.rb index af004d85bf..525d5f0161 100644 --- a/railties/lib/rails/app_loader.rb +++ b/railties/lib/rails/app_loader.rb @@ -1,12 +1,12 @@ -require 'pathname' -require 'rails/version' +require "pathname" +require "rails/version" module Rails module AppLoader # :nodoc: extend self RUBY = Gem.ruby - EXECUTABLES = ['bin/rails', 'script/rails'] + EXECUTABLES = ["bin/rails", "script/rails"] BUNDLER_WARNING = <<EOS Looks like your app's ./bin/rails is a stub that was generated by Bundler. @@ -39,21 +39,21 @@ EOS if contents =~ /(APP|ENGINE)_PATH/ exec RUBY, exe, *ARGV break # non reachable, hack to be able to stub exec in the test suite - elsif exe.end_with?('bin/rails') && contents.include?('This file was generated by Bundler') + elsif exe.end_with?("bin/rails") && contents.include?("This file was generated by Bundler") $stderr.puts(BUNDLER_WARNING) - Object.const_set(:APP_PATH, File.expand_path('config/application', Dir.pwd)) - require File.expand_path('../boot', APP_PATH) - require 'rails/commands' + Object.const_set(:APP_PATH, File.expand_path("config/application", Dir.pwd)) + require File.expand_path("../boot", APP_PATH) + require "rails/commands" break end end # If we exhaust the search there is no executable, this could be a # call to generate a new application, so restore the original cwd. - Dir.chdir(original_cwd) and return if Pathname.new(Dir.pwd).root? + Dir.chdir(original_cwd) && return if Pathname.new(Dir.pwd).root? # Otherwise keep moving upwards in search of an executable. - Dir.chdir('..') + Dir.chdir("..") end end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index c383de3e06..b01196e3ed 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,9 +1,9 @@ -require 'yaml' -require 'active_support/core_ext/hash/keys' -require 'active_support/core_ext/object/blank' -require 'active_support/key_generator' -require 'active_support/message_verifier' -require 'rails/engine' +require "yaml" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/object/blank" +require "active_support/key_generator" +require "active_support/message_verifier" +require "rails/engine" module Rails # An Engine with the responsibility of coordinating the whole boot process. @@ -75,18 +75,19 @@ module Rails # If you decide to define rake tasks, runners, or initializers in an # application other than +Rails.application+, then you must run them manually. class Application < Engine - autoload :Bootstrap, 'rails/application/bootstrap' - autoload :Configuration, 'rails/application/configuration' - autoload :DefaultMiddlewareStack, 'rails/application/default_middleware_stack' - autoload :Finisher, 'rails/application/finisher' - autoload :Railties, 'rails/engine/railties' - autoload :RoutesReloader, 'rails/application/routes_reloader' + autoload :Bootstrap, "rails/application/bootstrap" + autoload :Configuration, "rails/application/configuration" + autoload :DefaultMiddlewareStack, "rails/application/default_middleware_stack" + autoload :Finisher, "rails/application/finisher" + autoload :Railties, "rails/engine/railties" + autoload :RoutesReloader, "rails/application/routes_reloader" class << self def inherited(base) super Rails.app_class = base add_lib_to_load_path!(find_root(base.called_from)) + ActiveSupport.run_load_hooks(:before_configuration, base) end def instance @@ -146,7 +147,6 @@ module Rails def run_load_hooks! # :nodoc: return self if @ran_load_hooks @ran_load_hooks = true - ActiveSupport.run_load_hooks(:before_configuration, self) @initial_variable_values.each do |variable_name, value| if INITIAL_VARIABLES.include?(variable_name) @@ -317,7 +317,7 @@ module Rails # Rails application, you will need to add lib to $LOAD_PATH on your own in case # you need to load files in lib/ during the application configuration as well. def self.add_lib_to_load_path!(root) #:nodoc: - path = File.join root, 'lib' + path = File.join root, "lib" if File.exist?(path) && !$LOAD_PATH.include?(path) $LOAD_PATH.unshift(path) end @@ -391,7 +391,7 @@ module Rails require "erb" all_secrets = YAML.load(ERB.new(IO.read(yaml)).result) || {} - shared_secrets = all_secrets['shared'] + shared_secrets = all_secrets["shared"] env_secrets = all_secrets[Rails.env] secrets.merge!(shared_secrets.symbolize_keys) if shared_secrets @@ -522,15 +522,15 @@ module Rails private - def build_request(env) - req = super - env["ORIGINAL_FULLPATH"] = req.fullpath - env["ORIGINAL_SCRIPT_NAME"] = req.script_name - req - end + def build_request(env) + req = super + env["ORIGINAL_FULLPATH"] = req.fullpath + env["ORIGINAL_SCRIPT_NAME"] = req.script_name + req + end - def build_middleware - config.app_middleware + super - end + def build_middleware + config.app_middleware + super + end end end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index f615f22b26..11da271501 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -1,7 +1,7 @@ -require 'fileutils' -require 'active_support/notifications' -require 'active_support/dependencies' -require 'active_support/descendants_tracker' +require "fileutils" +require "active_support/notifications" +require "active_support/dependencies" +require "active_support/descendants_tracker" module Rails class Application @@ -36,7 +36,7 @@ INFO FileUtils.mkdir_p File.dirname path end - f = File.open path, 'a' + f = File.open path, "a" f.binmode f.sync = config.autoflush_log # if true make sure every write flushes diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index f415a20833..810750ed35 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,10 +1,10 @@ -require 'active_support/core_ext/kernel/reporting' -require 'active_support/file_update_checker' -require 'rails/engine/configuration' -require 'rails/source_annotation_extractor' +require "active_support/core_ext/kernel/reporting" +require "active_support/file_update_checker" +require "rails/engine/configuration" +require "rails/source_annotation_extractor" -require 'active_support/deprecation' -require 'active_support/core_ext/string/strip' # for strip_heredoc +require "active_support/deprecation" +require "active_support/core_ext/string/strip" # for strip_heredoc module Rails class Application @@ -16,7 +16,7 @@ module Rails :railties_order, :relative_url_root, :secret_key_base, :secret_token, :ssl_options, :public_file_server, :session_options, :time_zone, :reload_classes_only_on_change, - :beginning_of_week, :filter_redirect, :x + :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading attr_writer :log_level attr_reader :encoding, :api_only, :static_cache_control @@ -34,8 +34,7 @@ module Rails @public_file_server.index_name = "index" @force_ssl = false @ssl_options = {} - @session_store = :cookie_store - @session_options = {} + @session_store = nil @time_zone = "UTC" @beginning_of_week = :monday @log_level = nil @@ -54,6 +53,7 @@ module Rails @api_only = false @debug_exception_response_format = nil @x = Custom.new + @enable_dependency_loading = false end def static_cache_control=(value) @@ -134,7 +134,7 @@ module Rails require "yaml" require "erb" YAML.load(ERB.new(yaml.read).result) || {} - elsif ENV['DATABASE_URL'] + elsif ENV["DATABASE_URL"] # Value from ENV['DATABASE_URL'] is set to default database connection # by Active Record. {} @@ -164,29 +164,37 @@ module Rails self.generators.colorize_logging = val end - def session_store(*args) - if args.empty? - case @session_store - when :disabled - nil - when :active_record_store + def session_store(new_session_store = nil, **options) + if new_session_store + if new_session_store == :active_record_store begin ActionDispatch::Session::ActiveRecordStore rescue NameError raise "`ActiveRecord::SessionStore` is extracted out of Rails into a gem. " \ "Please add `activerecord-session_store` to your Gemfile to use it." end + end + + @session_store = new_session_store + @session_options = options || {} + else + case @session_store + when :disabled + nil + when :active_record_store + ActionDispatch::Session::ActiveRecordStore when Symbol ActionDispatch::Session.const_get(@session_store.to_s.camelize) else @session_store end - else - @session_store = args.shift - @session_options = args.shift || {} end end + def session_store? #:nodoc: + @session_store + end + def annotations SourceAnnotationExtractor::Annotation end @@ -205,6 +213,10 @@ module Rails } end end + + def respond_to_missing?(symbol, *) + true + end end end end diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb index 381e548730..14c0a8cbe4 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -19,7 +19,7 @@ module Rails if config.public_file_server.enabled headers = config.public_file_server.headers || {} - headers['Cache-Control'.freeze] = config.static_cache_control if config.static_cache_control + headers["Cache-Control".freeze] = config.static_cache_control if config.static_cache_control middleware.use ::ActionDispatch::Static, paths["public"].first, index: config.public_file_server.index_name, headers: headers end @@ -76,9 +76,9 @@ module Rails return unless rack_cache begin - require 'rack/cache' + require "rack/cache" rescue LoadError => error - error.message << ' Be sure to add rack-cache to your Gemfile' + error.message << " Be sure to add rack-cache to your Gemfile" raise end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 97dde9a3e9..a855e8fab0 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -22,17 +22,25 @@ module Rails initializer :add_builtin_route do |app| if Rails.env.development? app.routes.prepend do - get '/rails/info/properties' => "rails/info#properties", internal: true - get '/rails/info/routes' => "rails/info#routes", internal: true - get '/rails/info' => "rails/info#index", internal: true + get "/rails/info/properties" => "rails/info#properties", internal: true + get "/rails/info/routes" => "rails/info#routes", internal: true + get "/rails/info" => "rails/info#index", internal: true end app.routes.append do - get '/' => "rails/welcome#index", internal: true + get "/" => "rails/welcome#index", internal: true end end end + # Setup default session store if not already set in config/application.rb + initializer :setup_default_session_store, before: :build_middleware_stack do |app| + unless app.config.session_store? + app_name = app.class.name ? app.railtie_name.chomp("_application") : "" + app.config.session_store :cookie_store, key: "_#{app_name}_session" + end + end + initializer :build_middleware_stack do build_middleware_stack end @@ -117,7 +125,7 @@ module Rails initializer :set_routes_reloader_hook do |app| reloader = routes_reloader reloader.execute_if_updated - self.reloaders << reloader + reloaders << reloader app.reloader.to_run do # We configure #execute rather than #execute_if_updated because if # autoloaded constants are cleared we need to reload routes also in @@ -153,7 +161,7 @@ module Rails if config.reload_classes_only_on_change reloader = config.file_watcher.new(*watchable_args, &callback) - self.reloaders << reloader + reloaders << reloader # Prepend this callback to have autoloaded constants cleared before # any other possible reloading, in case they need to autoload fresh @@ -176,7 +184,7 @@ module Rails # Disable dependency loading during request cycle initializer :disable_dependency_loading do - if config.eager_load && config.cache_classes + if config.eager_load && config.cache_classes && !config.enable_dependency_loading ActiveSupport::Dependencies.unhook! end end diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb index 618a09a5b3..f8394b8e0a 100644 --- a/railties/lib/rails/application_controller.rb +++ b/railties/lib/rails/application_controller.rb @@ -1,16 +1,16 @@ class Rails::ApplicationController < ActionController::Base # :nodoc: - self.view_paths = File.expand_path('../templates', __FILE__) - layout 'application' + self.view_paths = File.expand_path("../templates", __FILE__) + layout "application" protected - def require_local! - unless local_request? - render html: '<p>For security purposes, this information is only available to local requests.</p>'.html_safe, status: :forbidden + def require_local! + unless local_request? + render html: "<p>For security purposes, this information is only available to local requests.</p>".html_safe, status: :forbidden + end end - end - def local_request? - Rails.application.config.consider_all_requests_local || request.local? - end + def local_request? + Rails.application.config.consider_all_requests_local || request.local? + end end diff --git a/railties/lib/rails/backtrace_cleaner.rb b/railties/lib/rails/backtrace_cleaner.rb index 5276eb33c9..5c833e12ba 100644 --- a/railties/lib/rails/backtrace_cleaner.rb +++ b/railties/lib/rails/backtrace_cleaner.rb @@ -1,12 +1,12 @@ -require 'active_support/backtrace_cleaner' +require "active_support/backtrace_cleaner" module Rails class BacktraceCleaner < ActiveSupport::BacktraceCleaner - APP_DIRS_PATTERN = /^\/?(app|config|lib|test)/ + APP_DIRS_PATTERN = /^\/?(app|config|lib|test|\(\w*\))/ RENDER_TEMPLATE_PATTERN = /:in `_render_template_\w*'/ - EMPTY_STRING = ''.freeze - SLASH = '/'.freeze - DOT_SLASH = './'.freeze + EMPTY_STRING = "".freeze + SLASH = "/".freeze + DOT_SLASH = "./".freeze def initialize super diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb index a8794bc0de..973b746068 100644 --- a/railties/lib/rails/cli.rb +++ b/railties/lib/rails/cli.rb @@ -1,15 +1,17 @@ -require 'rails/app_loader' +require "rails/app_loader" # If we are inside a Rails application this method performs an exec and thus # the rest of this script is not run. Rails::AppLoader.exec_app -require 'rails/ruby_version_check' +require "rails/ruby_version_check" Signal.trap("INT") { puts; exit(1) } -if ARGV.first == 'plugin' +require "rails/command" + +if ARGV.first == "plugin" ARGV.shift - require 'rails/commands/plugin' + Rails::Command.invoke :plugin, ARGV else - require 'rails/commands/application' + Rails::Command.invoke :application, ARGV end diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index 7a8f42fe94..b3d88147a5 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -1,16 +1,15 @@ -require 'rails/code_statistics_calculator' -require 'active_support/core_ext/enumerable' +require "rails/code_statistics_calculator" +require "active_support/core_ext/enumerable" class CodeStatistics #:nodoc: + TEST_TYPES = ["Controller tests", + "Helper tests", + "Model tests", + "Mailer tests", + "Job tests", + "Integration tests"] - TEST_TYPES = ['Controller tests', - 'Helper tests', - 'Model tests', - 'Mailer tests', - 'Job tests', - 'Integration tests'] - - HEADERS = {lines: ' Lines', code_lines: ' LOC', classes: 'Classes', methods: 'Methods'} + HEADERS = { lines: " Lines", code_lines: " LOC", classes: "Classes", methods: "Methods" } def initialize(*pairs) @pairs = pairs @@ -33,7 +32,7 @@ class CodeStatistics #:nodoc: private def calculate_statistics - Hash[@pairs.map{|pair| [pair.first, calculate_directory_statistics(pair.last)]}] + Hash[@pairs.map { |pair| [pair.first, calculate_directory_statistics(pair.last)] }] end def calculate_directory_statistics(directory, pattern = /^(?!\.).*?\.(rb|js|coffee|rake)$/) @@ -71,25 +70,25 @@ class CodeStatistics #:nodoc: end def width_for(label) - [@statistics.values.sum {|s| s.send(label) }.to_s.size, HEADERS[label].length].max + [@statistics.values.sum { |s| s.send(label) }.to_s.size, HEADERS[label].length].max end def print_header print_splitter - print '| Name ' + print "| Name " HEADERS.each do |k, v| print " | #{v.rjust(width_for(k))}" end - puts ' | M/C | LOC/M |' + puts " | M/C | LOC/M |" print_splitter end def print_splitter - print '+----------------------' + print "+----------------------" HEADERS.each_key do |k| print "+#{'-' * (width_for(k) + 2)}" end - puts '+-----+-------+' + puts "+-----+-------+" end def print_line(name, statistics) diff --git a/railties/lib/rails/code_statistics_calculator.rb b/railties/lib/rails/code_statistics_calculator.rb index fad13e8517..d0194af197 100644 --- a/railties/lib/rails/code_statistics_calculator.rb +++ b/railties/lib/rails/code_statistics_calculator.rb @@ -43,7 +43,7 @@ class CodeStatisticsCalculator #:nodoc: def add_by_file_path(file_path) File.open(file_path) do |f| - self.add_by_io(f, file_type(file_path)) + add_by_io(f, file_type(file_path)) end end @@ -77,10 +77,10 @@ class CodeStatisticsCalculator #:nodoc: private def file_type(file_path) - if file_path.end_with? '_test.rb' + if file_path.end_with? "_test.rb" :minitest else - File.extname(file_path).sub(/\A\./, '').downcase.to_sym + File.extname(file_path).sub(/\A\./, "").downcase.to_sym end end end diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb new file mode 100644 index 0000000000..6065e78fd1 --- /dev/null +++ b/railties/lib/rails/command.rb @@ -0,0 +1,99 @@ +require "active_support" +require "active_support/dependencies/autoload" +require "active_support/core_ext/enumerable" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/transform_values" + +require "thor" + +module Rails + module Command + extend ActiveSupport::Autoload + + autoload :Behavior + autoload :Base + + include Behavior + + class << self + def hidden_commands # :nodoc: + @hidden_commands ||= [] + end + + def environment # :nodoc: + ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" + end + + # Receives a namespace, arguments and the behavior to invoke the command. + def invoke(namespace, args = [], **config) + namespace = namespace.to_s + namespace = "help" if namespace.blank? || Thor::HELP_MAPPINGS.include?(namespace) + namespace = "version" if %w( -v --version ).include? namespace + + if command = find_by_namespace(namespace) + command.perform(namespace, args, config) + else + find_by_namespace("rake").perform(namespace, args, config) + end + end + + # Rails finds namespaces similar to thor, it only adds one rule: + # + # Command names must end with "_command.rb". This is required because Rails + # looks in load paths and loads the command just before it's going to be used. + # + # find_by_namespace :webrat, :rails, :integration + # + # Will search for the following commands: + # + # "rails:webrat", "webrat:integration", "webrat" + # + # Notice that "rails:commands:webrat" could be loaded as well, what + # Rails looks for is the first and last parts of the namespace. + def find_by_namespace(name) # :nodoc: + lookups = [ name, "rails:#{name}" ] + + lookup(lookups) + + namespaces = subclasses.index_by(&:namespace) + namespaces[(lookups & namespaces.keys).first] + end + + # Returns the root of the Rails engine or app running the command. + def root + if defined?(ENGINE_ROOT) + Pathname.new(ENGINE_ROOT) + elsif defined?(APP_PATH) + Pathname.new(File.expand_path("../..", APP_PATH)) + end + end + + def print_commands # :nodoc: + sorted_groups.each { |b, n| print_list(b, n) } + end + + def sorted_groups # :nodoc: + lookup! + + groups = (subclasses - hidden_commands).group_by { |c| c.namespace.split(":").first } + groups.transform_values! { |commands| commands.flat_map(&:printing_commands).sort } + + rails = groups.delete("rails") + [[ "rails", rails ]] + groups.sort.to_a + end + + protected + def command_type + @command_type ||= "command" + end + + def lookup_paths + @lookup_paths ||= %w( rails/commands commands ) + end + + def file_lookup_paths + @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_command.rb" ] + end + end + end +end diff --git a/railties/lib/rails/command/actions.rb b/railties/lib/rails/command/actions.rb new file mode 100644 index 0000000000..31b656ec31 --- /dev/null +++ b/railties/lib/rails/command/actions.rb @@ -0,0 +1,42 @@ +module Rails + module Command + module Actions + # Change to the application's path if there is no config.ru file in current directory. + # This allows us to run `rails server` from other directories, but still get + # the main config.ru and properly set the tmp directory. + def set_application_directory! + Dir.chdir(File.expand_path("../../", APP_PATH)) unless File.exist?(File.expand_path("config.ru")) + end + + if defined?(ENGINE_PATH) + def require_application_and_environment! + require ENGINE_PATH + end + + def load_tasks + Rake.application.init("rails") + Rake.application.load_rakefile + end + + def load_generators + engine = ::Rails::Engine.find(ENGINE_ROOT) + Rails::Generators.namespace = engine.railtie_namespace + engine.load_generators + end + else + def require_application_and_environment! + require APP_PATH + Rails.application.require_environment! + end + + def load_tasks + Rails.application.load_tasks + end + + def load_generators + Rails.application.load_generators + end + end + end + end +end diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb new file mode 100644 index 0000000000..1efcd69e63 --- /dev/null +++ b/railties/lib/rails/command/base.rb @@ -0,0 +1,135 @@ +require "thor" +require "erb" + +require "active_support/core_ext/string/filters" +require "active_support/core_ext/string/inflections" + +require "rails/command/actions" + +module Rails + module Command + class Base < Thor + class Error < Thor::Error # :nodoc: + end + + include Actions + + class << self + # Returns true when the app is a Rails engine. + def engine? + defined?(ENGINE_ROOT) + end + + # Tries to get the description from a USAGE file one folder above the command + # root. + def desc(usage = nil, description = nil) + if usage + super + else + @desc ||= ERB.new(File.read(usage_path)).result(binding) if usage_path + end + end + + # Convenience method to get the namespace from the class name. It's the + # same as Thor default except that the Command at the end of the class + # is removed. + def namespace(name = nil) + if name + super + else + @namespace ||= super.chomp("_command").sub(/:command:/, ":") + end + end + + # Convenience method to hide this command from the available ones when + # running rails command. + def hide_command! + Rails::Command.hidden_commands << self + end + + def inherited(base) #:nodoc: + super + + if base.name && base.name !~ /Base$/ + Rails::Command.subclasses << base + end + end + + def perform(command, args, config) # :nodoc: + command = nil if Thor::HELP_MAPPINGS.include?(args.first) + + dispatch(command, args.dup, nil, config) + end + + def printing_commands + namespace.sub(/^rails:/, "") + end + + def executable + "bin/rails #{command_name}" + end + + # Use Rails' default banner. + def banner(*) + "#{executable} #{arguments.map(&:usage).join(' ')} [options]".squish! + end + + # Sets the base_name taking into account the current class namespace. + # + # Rails::Command::TestCommand.base_name # => 'rails' + def base_name + @base_name ||= begin + if base = name.to_s.split("::").first + base.underscore + end + end + end + + # Return command name without namespaces. + # + # Rails::Command::TestCommand.command_name # => 'test' + def command_name + @command_name ||= begin + if command = name.to_s.split("::").last + command.chomp!("Command") + command.underscore + end + end + end + + # Path to lookup a USAGE description in a file. + def usage_path + if default_command_root + path = File.join(default_command_root, "USAGE") + path if File.exist?(path) + end + end + + # Default file root to place extra files a command might need, placed + # one folder above the command file. + # + # For a `Rails::Command::TestCommand` placed in `rails/command/test_command.rb` + # would return `rails/test`. + def default_command_root + path = File.expand_path(File.join("../commands", command_name), __dir__) + path if File.exist?(path) + end + + private + # Allow the command method to be called perform. + def create_command(meth) + if meth == "perform" + alias_method command_name, meth + else + # Prevent exception about command without usage. + # Some commands define their documentation differently. + @usage ||= "" + @desc ||= "" + + super + end + end + end + end + end +end diff --git a/railties/lib/rails/command/behavior.rb b/railties/lib/rails/command/behavior.rb new file mode 100644 index 0000000000..ce994746a4 --- /dev/null +++ b/railties/lib/rails/command/behavior.rb @@ -0,0 +1,123 @@ +require "active_support" + +module Rails + module Command + module Behavior #:nodoc: + extend ActiveSupport::Concern + + class_methods do + # Remove the color from output. + def no_color! + Thor::Base.shell = Thor::Shell::Basic + end + + # Track all command subclasses. + def subclasses + @subclasses ||= [] + end + + protected + + # This code is based directly on the Text gem implementation. + # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher. + # + # Returns a value representing the "cost" of transforming str1 into str2. + def levenshtein_distance(str1, str2) + s = str1 + t = str2 + n = s.length + m = t.length + + return m if (0 == n) + return n if (0 == m) + + d = (0..m).to_a + x = nil + + # avoid duplicating an enumerable object in the loop + str2_codepoint_enumerable = str2.each_codepoint + + str1.each_codepoint.with_index do |char1, i| + e = i+1 + + str2_codepoint_enumerable.with_index do |char2, j| + cost = (char1 == char2) ? 0 : 1 + x = [ + d[j+1] + 1, # insertion + e + 1, # deletion + d[j] + cost # substitution + ].min + d[j] = e + e = x + end + + d[m] = x + end + + x + end + + # Prints a list of generators. + def print_list(base, namespaces) #:nodoc: + return if namespaces.empty? + puts "#{base.camelize}:" + + namespaces.each do |namespace| + puts(" #{namespace}") + end + + puts + end + + # Receives namespaces in an array and tries to find matching generators + # in the load path. + def lookup(namespaces) #:nodoc: + paths = namespaces_to_paths(namespaces) + + paths.each do |raw_path| + lookup_paths.each do |base| + path = "#{base}/#{raw_path}_#{command_type}" + + begin + require path + return + rescue LoadError => e + raise unless e.message =~ /#{Regexp.escape(path)}$/ + rescue Exception => e + warn "[WARNING] Could not load #{command_type} #{path.inspect}. Error: #{e.message}.\n#{e.backtrace.join("\n")}" + end + end + end + end + + # This will try to load any command in the load path to show in help. + def lookup! #:nodoc: + $LOAD_PATH.each do |base| + Dir[File.join(base, *file_lookup_paths)].each do |path| + begin + path = path.sub("#{base}/", "") + require path + rescue Exception + # No problem + end + end + end + end + + # Convert namespaces to paths by replacing ":" for "/" and adding + # an extra lookup. For example, "rails:model" should be searched + # in both: "rails/model/model_generator" and "rails/model_generator". + def namespaces_to_paths(namespaces) #:nodoc: + paths = [] + namespaces.each do |namespace| + pieces = namespace.split(":") + paths << pieces.dup.push(pieces.last).join("/") + paths << pieces.join("/") + end + paths.uniq! + paths + end + end + end + end +end diff --git a/railties/lib/rails/command/environment_argument.rb b/railties/lib/rails/command/environment_argument.rb new file mode 100644 index 0000000000..05eac34155 --- /dev/null +++ b/railties/lib/rails/command/environment_argument.rb @@ -0,0 +1,34 @@ +require "active_support" + +module Rails + module Command + module EnvironmentArgument #:nodoc: + extend ActiveSupport::Concern + + included do + argument :environment, optional: true, banner: "environment" + end + + private + def extract_environment_option_from_argument + if environment + self.options = options.merge(environment: acceptable_environment(environment)) + elsif !options[:environment] + self.options = options.merge(environment: Rails::Command.environment) + end + end + + def acceptable_environment(env = nil) + if available_environments.include? env + env + else + %w( production development test ).detect { |e| e =~ /^#{env}/ } || env + end + end + + def available_environments + Dir["config/environments/*.rb"].map { |fname| File.basename(fname, ".*") } + end + end + end +end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index 5a66b78a92..fff0119c65 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -1,4 +1,4 @@ -ARGV << '--help' if ARGV.empty? +require "rails/command" aliases = { "g" => "generate", @@ -13,6 +13,4 @@ aliases = { command = ARGV.shift command = aliases[command] || command -require 'rails/commands/commands_tasks' - -Rails::CommandsTasks.new(ARGV).run_command!(command) +Rails::Command.invoke command, ARGV diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb deleted file mode 100644 index c998e6b6a8..0000000000 --- a/railties/lib/rails/commands/application.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'rails/generators' -require 'rails/generators/rails/app/app_generator' - -module Rails - module Generators - class AppGenerator # :nodoc: - # We want to exit on failure to be kind to other libraries - # This is only when accessing via CLI - def self.exit_on_failure? - true - end - end - end -end - -args = Rails::Generators::ARGVScrubber.new(ARGV).prepare! -Rails::Generators::AppGenerator.start args diff --git a/railties/lib/rails/commands/application/application_command.rb b/railties/lib/rails/commands/application/application_command.rb new file mode 100644 index 0000000000..7e3a2b011d --- /dev/null +++ b/railties/lib/rails/commands/application/application_command.rb @@ -0,0 +1,29 @@ +require "rails/generators" +require "rails/generators/rails/app/app_generator" + +module Rails + module Generators + class AppGenerator # :nodoc: + # We want to exit on failure to be kind to other libraries + # This is only when accessing via CLI + def self.exit_on_failure? + true + end + end + end + + module Command + class ApplicationCommand < Base + hide_command! + + def help + perform # Punt help output to the generator. + end + + def perform(*args) + Rails::Generators::AppGenerator.start \ + Rails::Generators::ARGVScrubber.new(args).prepare! + end + end + end +end diff --git a/railties/lib/rails/commands/commands_tasks.rb b/railties/lib/rails/commands/commands_tasks.rb deleted file mode 100644 index da3b9452d5..0000000000 --- a/railties/lib/rails/commands/commands_tasks.rb +++ /dev/null @@ -1,180 +0,0 @@ -require 'rails/commands/rake_proxy' - -module Rails - # This is a class which takes in a rails command and initiates the appropriate - # initiation sequence. - # - # Warning: This class mutates ARGV because some commands require manipulating - # it before they are run. - class CommandsTasks # :nodoc: - include Rails::RakeProxy - - attr_reader :argv - - HELP_MESSAGE = <<-EOT -Usage: rails COMMAND [ARGS] - -The most common rails commands are: - generate Generate new code (short-cut alias: "g") - console Start the Rails console (short-cut alias: "c") - server Start the Rails server (short-cut alias: "s") - test Run tests (short-cut alias: "t") - dbconsole Start a console for the database specified in config/database.yml - (short-cut alias: "db") - new Create a new Rails application. "rails new my_app" creates a - new application called MyApp in "./my_app" - -All commands can be run with -h (or --help) for more information. - -In addition to those commands, there are: -EOT - - ADDITIONAL_COMMANDS = [ - [ 'destroy', 'Undo code generated with "generate" (short-cut alias: "d")' ], - [ 'plugin new', 'Generates skeleton for developing a Rails plugin' ], - [ 'runner', - 'Run a piece of code in the application environment (short-cut alias: "r")' ] - ] - - COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help test) - - def initialize(argv) - @argv = argv - end - - def run_command!(command) - command = parse_command(command) - - if COMMAND_WHITELIST.include?(command) - send(command) - else - run_rake_task(command) - end - end - - def plugin - require_command!("plugin") - end - - def generate - generate_or_destroy(:generate) - end - - def destroy - generate_or_destroy(:destroy) - end - - def console - require_command!("console") - options = Rails::Console.parse_arguments(argv) - - # RAILS_ENV needs to be set before config/application is required - ENV['RAILS_ENV'] = options[:environment] if options[:environment] - - # shift ARGV so IRB doesn't freak - shift_argv! - - require_application_and_environment! - Rails::Console.start(Rails.application, options) - end - - def server - set_application_directory! - require_command!("server") - - Rails::Server.new.tap do |server| - # We need to require application after the server sets environment, - # otherwise the --environment option given to the server won't propagate. - require APP_PATH - Dir.chdir(Rails.application.root) - server.start - end - end - - def test - require_command!("test") - end - - def dbconsole - require_command!("dbconsole") - Rails::DBConsole.start - end - - def runner - require_command!("runner") - end - - def new - if %w(-h --help).include?(argv.first) - require_command!("application") - else - exit_with_initialization_warning! - end - end - - def version - argv.unshift '--version' - require_command!("application") - end - - def help - write_help_message - write_commands ADDITIONAL_COMMANDS + formatted_rake_tasks - end - - private - - def exit_with_initialization_warning! - puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n" - puts "Type 'rails' for help." - exit(1) - end - - def shift_argv! - argv.shift if argv.first && argv.first[0] != '-' - end - - def require_command!(command) - require "rails/commands/#{command}" - end - - def generate_or_destroy(command) - require 'rails/generators' - require_application_and_environment! - Rails.application.load_generators - require_command!(command) - end - - # Change to the application's path if there is no config.ru file in current directory. - # This allows us to run `rails server` from other directories, but still get - # the main config.ru and properly set the tmp directory. - def set_application_directory! - Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru")) - end - - def require_application_and_environment! - require APP_PATH - Rails.application.require_environment! - end - - def write_help_message - puts HELP_MESSAGE - end - - def write_commands(commands) - width = commands.map { |name, _| name.size }.max || 10 - commands.each { |command| printf(" %-#{width}s %s\n", *command) } - end - - def parse_command(command) - case command - when '--version', '-v' - 'version' - when '--help', '-h' - 'help' - else - command - end - end - end -end diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb deleted file mode 100644 index ea5d20ea24..0000000000 --- a/railties/lib/rails/commands/console.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'optparse' -require 'irb' -require 'irb/completion' -require 'rails/commands/console_helper' - -module Rails - class Console - include ConsoleHelper - - class << self - def parse_arguments(arguments) - options = {} - - OptionParser.new do |opt| - opt.banner = "Usage: rails console [environment] [options]" - opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v } - opt.on("-e", "--environment=name", String, - "Specifies the environment to run this console under (test/development/production).", - "Default: development") { |v| options[:environment] = v.strip } - opt.parse!(arguments) - end - - set_options_env(arguments, options) - end - end - - attr_reader :options, :app, :console - - def initialize(app, options={}) - @app = app - @options = options - - app.sandbox = sandbox? - app.load_console - - @console = app.config.console || IRB - end - - def sandbox? - options[:sandbox] - end - - def environment - options[:environment] ||= super - end - alias_method :environment?, :environment - - def set_environment! - Rails.env = environment - end - - def start - set_environment! if environment? - - if sandbox? - puts "Loading #{Rails.env} environment in sandbox (Rails #{Rails.version})" - puts "Any modifications you make will be rolled back on exit" - else - puts "Loading #{Rails.env} environment (Rails #{Rails.version})" - end - - if defined?(console::ExtendCommandBundle) - console::ExtendCommandBundle.include(Rails::ConsoleMethods) - end - console.start - end - end -end diff --git a/railties/lib/rails/commands/console/console_command.rb b/railties/lib/rails/commands/console/console_command.rb new file mode 100644 index 0000000000..617066f575 --- /dev/null +++ b/railties/lib/rails/commands/console/console_command.rb @@ -0,0 +1,89 @@ +require "irb" +require "irb/completion" + +require "rails/command/environment_argument" + +module Rails + class Console + module BacktraceCleaner + def filter_backtrace(bt) + if result = super + Rails.backtrace_cleaner.filter([result]).first + end + end + end + + def self.start(*args) + new(*args).start + end + + attr_reader :options, :app, :console + + def initialize(app, options = {}) + @app = app + @options = options + + app.sandbox = sandbox? + app.load_console + + @console = app.config.console || IRB + + if @console == IRB + IRB::WorkSpace.prepend(BacktraceCleaner) + end + end + + def sandbox? + options[:sandbox] + end + + def environment + options[:environment] + end + alias_method :environment?, :environment + + def set_environment! + Rails.env = environment + end + + def start + set_environment! if environment? + + if sandbox? + puts "Loading #{Rails.env} environment in sandbox (Rails #{Rails.version})" + puts "Any modifications you make will be rolled back on exit" + else + puts "Loading #{Rails.env} environment (Rails #{Rails.version})" + end + + if defined?(console::ExtendCommandBundle) + console::ExtendCommandBundle.include(Rails::ConsoleMethods) + end + console.start + end + end + + module Command + class ConsoleCommand < Base + include EnvironmentArgument + + class_option :sandbox, aliases: "-s", type: :boolean, default: false, + desc: "Rollback database modifications on exit." + + class_option :environment, aliases: "-e", type: :string, + desc: "Specifies the environment to run this console under (test/development/production)." + + def perform + extract_environment_option_from_argument + + # RAILS_ENV needs to be set before config/application is required. + ENV["RAILS_ENV"] = options[:environment] + + ARGV.clear # Clear ARGV so IRB doesn't freak. + + require_application_and_environment! + Rails::Console.start(Rails.application, options) + end + end + end +end diff --git a/railties/lib/rails/commands/console_helper.rb b/railties/lib/rails/commands/console_helper.rb deleted file mode 100644 index 8ee0b60012..0000000000 --- a/railties/lib/rails/commands/console_helper.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'active_support/concern' - -module Rails - module ConsoleHelper # :nodoc: - extend ActiveSupport::Concern - - module ClassMethods - def start(*args) - new(*args).start - end - - private - def set_options_env(arguments, options) - if arguments.first && arguments.first[0] != '-' - env = arguments.first - if available_environments.include? env - options[:environment] = env - else - options[:environment] = %w(production development test).detect { |e| e =~ /^#{env}/ } || env - end - end - options - end - - def available_environments - Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') } - end - end - - def environment - ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" - end - end -end
\ No newline at end of file diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb deleted file mode 100644 index 2c36edfa3f..0000000000 --- a/railties/lib/rails/commands/dbconsole.rb +++ /dev/null @@ -1,173 +0,0 @@ -require 'erb' -require 'yaml' -require 'optparse' -require 'rails/commands/console_helper' - -module Rails - class DBConsole - include ConsoleHelper - - attr_reader :arguments - - class << self - def parse_arguments(arguments) - options = {} - - OptionParser.new do |opt| - opt.banner = "Usage: rails dbconsole [environment] [options]" - opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v| - options['include_password'] = true - end - - opt.on("--mode [MODE]", ['html', 'list', 'line', 'column'], - "Automatically put the sqlite3 database in the specified mode (html, list, line, column).") do |mode| - options['mode'] = mode - end - - opt.on("--header") do |h| - options['header'] = h - end - - opt.on("-h", "--help", "Show this help message.") do - puts opt - exit - end - - opt.on("-e", "--environment=name", String, - "Specifies the environment to run this console under (test/development/production).", - "Default: development" - ) { |v| options[:environment] = v.strip } - - opt.parse!(arguments) - abort opt.to_s unless (0..1).include?(arguments.size) - end - - set_options_env(arguments, options) - end - end - - def initialize(arguments = ARGV) - @arguments = arguments - end - - def start - options = self.class.parse_arguments(arguments) - ENV['RAILS_ENV'] = options[:environment] || environment - - case config["adapter"] - when /^(jdbc)?mysql/ - args = { - 'host' => '--host', - 'port' => '--port', - 'socket' => '--socket', - 'username' => '--user', - 'encoding' => '--default-character-set', - 'sslca' => '--ssl-ca', - 'sslcert' => '--ssl-cert', - 'sslcapath' => '--ssl-capath', - 'sslcipher' => '--ssl-cipher', - 'sslkey' => '--ssl-key' - }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact - - if config['password'] && options['include_password'] - args << "--password=#{config['password']}" - elsif config['password'] && !config['password'].to_s.empty? - args << "-p" - end - - args << config['database'] - - find_cmd_and_exec(['mysql', 'mysql5'], *args) - - when /^postgres|^postgis/ - ENV['PGUSER'] = config["username"] if config["username"] - ENV['PGHOST'] = config["host"] if config["host"] - ENV['PGPORT'] = config["port"].to_s if config["port"] - ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && options['include_password'] - find_cmd_and_exec('psql', config["database"]) - - when "sqlite3" - args = [] - - args << "-#{options['mode']}" if options['mode'] - args << "-header" if options['header'] - args << File.expand_path(config['database'], Rails.respond_to?(:root) ? Rails.root : nil) - - find_cmd_and_exec('sqlite3', *args) - - when "oracle", "oracle_enhanced" - logon = "" - - if config['username'] - logon = config['username'] - logon << "/#{config['password']}" if config['password'] && options['include_password'] - logon << "@#{config['database']}" if config['database'] - end - - find_cmd_and_exec('sqlplus', logon) - - when "sqlserver" - args = [] - - args += ["-D", "#{config['database']}"] if config['database'] - args += ["-U", "#{config['username']}"] if config['username'] - args += ["-P", "#{config['password']}"] if config['password'] - - if config['host'] - host_arg = "#{config['host']}" - host_arg << ":#{config['port']}" if config['port'] - args += ["-S", host_arg] - end - - find_cmd_and_exec("sqsh", *args) - - else - abort "Unknown command-line client for #{config['database']}." - end - end - - def config - @config ||= begin - if configurations[environment].blank? - raise ActiveRecord::AdapterNotSpecified, "'#{environment}' database is not configured. Available configuration: #{configurations.inspect}" - else - configurations[environment] - end - end - end - - def environment - Rails.respond_to?(:env) ? Rails.env : super - end - - protected - def configurations - require APP_PATH - ActiveRecord::Base.configurations = Rails.application.config.database_configuration - ActiveRecord::Base.configurations - end - - def find_cmd_and_exec(commands, *args) - commands = Array(commands) - - dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR) - unless (ext = RbConfig::CONFIG['EXEEXT']).empty? - commands = commands.map{|cmd| "#{cmd}#{ext}"} - end - - full_path_command = nil - found = commands.detect do |cmd| - dirs_on_path.detect do |path| - full_path_command = File.join(path, cmd) - File.file?(full_path_command) && File.executable?(full_path_command) - end - end - - if found - exec full_path_command, *args - else - abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.") - end - end - end -end diff --git a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb new file mode 100644 index 0000000000..d3c80da89b --- /dev/null +++ b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb @@ -0,0 +1,158 @@ +require "erb" +require "yaml" + +require "rails/command/environment_argument" + +module Rails + class DBConsole + def self.start(*args) + new(*args).start + end + + def initialize(options = {}) + @options = options + end + + def start + ENV["RAILS_ENV"] = @options[:environment] || environment + + case config["adapter"] + when /^(jdbc)?mysql/ + args = { + "host" => "--host", + "port" => "--port", + "socket" => "--socket", + "username" => "--user", + "encoding" => "--default-character-set", + "sslca" => "--ssl-ca", + "sslcert" => "--ssl-cert", + "sslcapath" => "--ssl-capath", + "sslcipher" => "--ssl-cipher", + "sslkey" => "--ssl-key" + }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact + + if config["password"] && @options["include_password"] + args << "--password=#{config['password']}" + elsif config["password"] && !config["password"].to_s.empty? + args << "-p" + end + + args << config["database"] + + find_cmd_and_exec(["mysql", "mysql5"], *args) + + when /^postgres|^postgis/ + ENV["PGUSER"] = config["username"] if config["username"] + ENV["PGHOST"] = config["host"] if config["host"] + ENV["PGPORT"] = config["port"].to_s if config["port"] + ENV["PGPASSWORD"] = config["password"].to_s if config["password"] && @options["include_password"] + find_cmd_and_exec("psql", config["database"]) + + when "sqlite3" + args = [] + + args << "-#{@options['mode']}" if @options["mode"] + args << "-header" if @options["header"] + args << File.expand_path(config["database"], Rails.respond_to?(:root) ? Rails.root : nil) + + find_cmd_and_exec("sqlite3", *args) + + when "oracle", "oracle_enhanced" + logon = "" + + if config["username"] + logon = config["username"] + logon << "/#{config['password']}" if config["password"] && @options["include_password"] + logon << "@#{config['database']}" if config["database"] + end + + find_cmd_and_exec("sqlplus", logon) + + when "sqlserver" + args = [] + + args += ["-D", "#{config['database']}"] if config["database"] + args += ["-U", "#{config['username']}"] if config["username"] + args += ["-P", "#{config['password']}"] if config["password"] + + if config["host"] + host_arg = "#{config['host']}" + host_arg << ":#{config['port']}" if config["port"] + args += ["-S", host_arg] + end + + find_cmd_and_exec("sqsh", *args) + + else + abort "Unknown command-line client for #{config['database']}." + end + end + + def config + @config ||= begin + if configurations[environment].blank? + raise ActiveRecord::AdapterNotSpecified, "'#{environment}' database is not configured. Available configuration: #{configurations.inspect}" + else + configurations[environment] + end + end + end + + def environment + Rails.respond_to?(:env) ? Rails.env : Rails::Command.environment + end + + protected + def configurations + require APP_PATH + ActiveRecord::Base.configurations = Rails.application.config.database_configuration + ActiveRecord::Base.configurations + end + + def find_cmd_and_exec(commands, *args) + commands = Array(commands) + + dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR) + unless (ext = RbConfig::CONFIG["EXEEXT"]).empty? + commands = commands.map { |cmd| "#{cmd}#{ext}" } + end + + full_path_command = nil + found = commands.detect do |cmd| + dirs_on_path.detect do |path| + full_path_command = File.join(path, cmd) + File.file?(full_path_command) && File.executable?(full_path_command) + end + end + + if found + exec full_path_command, *args + else + abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.") + end + end + end + + module Command + class DbconsoleCommand < Base + include EnvironmentArgument + + class_option :include_password, aliases: "-p", type: :boolean, + desc: "Automatically provide the password from database.yml" + + class_option :mode, enum: %w( html list line column ), type: :string, + desc: "Automatically put the sqlite3 database in the specified mode (html, list, line, column)." + + class_option :header, type: :string + + class_option :environment, aliases: "-e", type: :string, + desc: "Specifies the environment to run this console under (test/development/production)." + + def perform + extract_environment_option_from_argument + + Rails::DBConsole.start(options) + end + end + end +end diff --git a/railties/lib/rails/commands/destroy.rb b/railties/lib/rails/commands/destroy.rb deleted file mode 100644 index ce26cc3fde..0000000000 --- a/railties/lib/rails/commands/destroy.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'rails/generators' - -#if no argument/-h/--help is passed to rails destroy command, then -#it generates the help associated. -if [nil, "-h", "--help"].include?(ARGV.first) - Rails::Generators.help 'destroy' - exit -end - -name = ARGV.shift -Rails::Generators.invoke name, ARGV, behavior: :revoke, destination_root: Rails.root diff --git a/railties/lib/rails/commands/destroy/destroy_command.rb b/railties/lib/rails/commands/destroy/destroy_command.rb new file mode 100644 index 0000000000..5e6b7f9371 --- /dev/null +++ b/railties/lib/rails/commands/destroy/destroy_command.rb @@ -0,0 +1,21 @@ +require "rails/generators" + +module Rails + module Command + class DestroyCommand < Base + def help # :nodoc: + Rails::Generators.help self.class.command_name + end + + def perform(*) + generator = args.shift + return help unless generator + + require_application_and_environment! + Rails.application.load_generators + + Rails::Generators.invoke generator, args, behavior: :revoke, destination_root: Rails.root + end + end + end +end diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb deleted file mode 100644 index 926c36b967..0000000000 --- a/railties/lib/rails/commands/generate.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'rails/generators' - -#if no argument/-h/--help is passed to rails generate command, then -#it generates the help associated. -if [nil, "-h", "--help"].include?(ARGV.first) - Rails::Generators.help 'generate' - exit -end - -name = ARGV.shift - -root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root -Rails::Generators.invoke name, ARGV, behavior: :invoke, destination_root: root diff --git a/railties/lib/rails/commands/generate/generate_command.rb b/railties/lib/rails/commands/generate/generate_command.rb new file mode 100644 index 0000000000..b381ca85b9 --- /dev/null +++ b/railties/lib/rails/commands/generate/generate_command.rb @@ -0,0 +1,21 @@ +require "rails/generators" + +module Rails + module Command + class GenerateCommand < Base + def help # :nodoc: + Rails::Generators.help self.class.command_name + end + + def perform(*) + generator = args.shift + return help unless generator + + require_application_and_environment! + load_generators + + Rails::Generators.invoke generator, args, behavior: :invoke, destination_root: Rails::Command.root + end + end + end +end diff --git a/railties/lib/rails/commands/help/USAGE b/railties/lib/rails/commands/help/USAGE new file mode 100644 index 0000000000..348f41861f --- /dev/null +++ b/railties/lib/rails/commands/help/USAGE @@ -0,0 +1,27 @@ +Usage: bin/rails COMMAND [args] [options] +<% if engine? %> +The common Rails commands available for engines are: + generate Generate new code (short-cut alias: "g") + destroy Undo code generated with "generate" (short-cut alias: "d") + test Run tests (short-cut alias: "t") + +All commands can be run with -h for more information. + +If you want to run any commands that need to be run in context +of the application, like `bin/rails server` or `bin/rails console`, +you should do it from the application's directory (typically test/dummy). +<% else %> +The most common rails commands are: + generate Generate new code (short-cut alias: "g") + console Start the Rails console (short-cut alias: "c") + server Start the Rails server (short-cut alias: "s") + test Run tests (short-cut alias: "t") + dbconsole Start a console for the database specified in config/database.yml + (short-cut alias: "db") + new Create a new Rails application. "rails new my_app" creates a + new application called MyApp in "./my_app" + +All commands can be run with -h (or --help) for more information. +<% end %> +In addition to those commands, there are: + diff --git a/railties/lib/rails/commands/help/help_command.rb b/railties/lib/rails/commands/help/help_command.rb new file mode 100644 index 0000000000..5bcc4c8eee --- /dev/null +++ b/railties/lib/rails/commands/help/help_command.rb @@ -0,0 +1,13 @@ +module Rails + module Command + class HelpCommand < Base + hide_command! + + def help(*) + puts self.class.desc + + Rails::Command.print_commands + end + end + end +end diff --git a/railties/lib/rails/commands/new/new_command.rb b/railties/lib/rails/commands/new/new_command.rb new file mode 100644 index 0000000000..13eedfc479 --- /dev/null +++ b/railties/lib/rails/commands/new/new_command.rb @@ -0,0 +1,15 @@ +module Rails + module Command + class NewCommand < Base + def help + Rails::Command.invoke :application, [ "--help" ] + end + + def perform(*) + puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n" + puts "Type 'rails' for help." + exit 1 + end + end + end +end diff --git a/railties/lib/rails/commands/plugin.rb b/railties/lib/rails/commands/plugin.rb deleted file mode 100644 index 52d8966ead..0000000000 --- a/railties/lib/rails/commands/plugin.rb +++ /dev/null @@ -1,23 +0,0 @@ -if ARGV.first != "new" - ARGV[0] = "--help" -else - ARGV.shift - unless ARGV.delete("--no-rc") - customrc = ARGV.index{ |x| x.include?("--rc=") } - railsrc = if customrc - File.expand_path(ARGV.delete_at(customrc).gsub(/--rc=/, "")) - else - File.join(File.expand_path("~"), '.railsrc') - end - if File.exist?(railsrc) - extra_args_string = File.read(railsrc) - extra_args = extra_args_string.split(/\n+/).flat_map(&:split) - puts "Using #{extra_args.join(" ")} from #{railsrc}" - ARGV.insert(1, *extra_args) - end - end -end - -require 'rails/generators' -require 'rails/generators/rails/plugin/plugin_generator' -Rails::Generators::PluginGenerator.start diff --git a/railties/lib/rails/commands/plugin/plugin_command.rb b/railties/lib/rails/commands/plugin/plugin_command.rb new file mode 100644 index 0000000000..d6d9fe4400 --- /dev/null +++ b/railties/lib/rails/commands/plugin/plugin_command.rb @@ -0,0 +1,43 @@ +module Rails + module Command + class PluginCommand < Base + hide_command! + + def help + run_plugin_generator %w( --help ) + end + + def self.banner(*) # :nodoc: + "#{executable} new [options]" + end + + class_option :rc, type: :boolean, default: File.join("~", ".railsrc"), + desc: "Initialize the plugin command with previous defaults. Uses .railsrc in your home directory by default." + + class_option :no_rc, desc: "Skip evaluating .railsrc." + + def perform(type = nil, *plugin_args) + plugin_args << "--help" unless type == "new" + + unless options.key?("no_rc") # Thor's not so indifferent access hash. + railsrc = File.expand_path(options[:rc]) + + if File.exist?(railsrc) + extra_args = File.read(railsrc).split(/\n+/).flat_map(&:split) + puts "Using #{extra_args.join(" ")} from #{railsrc}" + plugin_args.insert(1, *extra_args) + end + end + + run_plugin_generator plugin_args + end + + private + def run_plugin_generator(plugin_args) + require "rails/generators" + require "rails/generators/rails/plugin/plugin_generator" + Rails::Generators::PluginGenerator.start plugin_args + end + end + end +end diff --git a/railties/lib/rails/commands/rake/rake_command.rb b/railties/lib/rails/commands/rake/rake_command.rb new file mode 100644 index 0000000000..a43c884170 --- /dev/null +++ b/railties/lib/rails/commands/rake/rake_command.rb @@ -0,0 +1,51 @@ +module Rails + module Command + class RakeCommand < Base + extend Rails::Command::Actions + + namespace "rake" + + class << self + def printing_commands + formatted_rake_tasks.map(&:first) + end + + def perform(task, *) + require_rake + + ARGV.unshift(task) # Prepend the task, so Rake knows how to run it. + + Rake.application.standard_exception_handling do + Rake.application.init("rails") + Rake.application.load_rakefile + Rake.application.top_level + end + end + + private + def rake_tasks + require_rake + + return @rake_tasks if defined?(@rake_tasks) + + ActiveSupport::Deprecation.silence do + require_application_and_environment! + end + + Rake::TaskManager.record_task_metadata = true + Rake.application.instance_variable_set(:@name, "rails") + load_tasks + @rake_tasks = Rake.application.tasks.select(&:comment) + end + + def formatted_rake_tasks + rake_tasks.map { |t| [ t.name_with_args, t.comment ] } + end + + def require_rake + require "rake" # Defer booting Rake until we know it's needed. + end + end + end + end +end diff --git a/railties/lib/rails/commands/rake_proxy.rb b/railties/lib/rails/commands/rake_proxy.rb deleted file mode 100644 index f7d5df6b2f..0000000000 --- a/railties/lib/rails/commands/rake_proxy.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'rake' -require 'active_support' - -module Rails - module RakeProxy #:nodoc: - private - def run_rake_task(command) - ARGV.unshift(command) # Prepend the command, so Rake knows how to run it. - - Rake.application.standard_exception_handling do - Rake.application.init('rails') - Rake.application.load_rakefile - Rake.application.top_level - end - end - - def rake_tasks - return @rake_tasks if defined?(@rake_tasks) - - ActiveSupport::Deprecation.silence do - require_application_and_environment! - end - - Rake::TaskManager.record_task_metadata = true - Rake.application.instance_variable_set(:@name, 'rails') - Rails.application.load_tasks - @rake_tasks = Rake.application.tasks.select(&:comment) - end - - def formatted_rake_tasks - rake_tasks.map { |t| [ t.name_with_args, t.comment ] } - end - end -end diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb deleted file mode 100644 index f9c183ac86..0000000000 --- a/railties/lib/rails/commands/runner.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'optparse' - -options = { environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup } -code_or_file = nil -command = 'bin/rails runner' - -if ARGV.first.nil? - ARGV.push "-h" -end - -ARGV.clone.options do |opts| - opts.banner = "Usage: rails runner [options] [<'Some.ruby(code)'> | <filename.rb>]" - - opts.separator "" - - opts.on("-e", "--environment=name", String, - "Specifies the environment for the runner to operate under (test/development/production).", - "Default: development") { |v| options[:environment] = v } - - opts.separator "" - - opts.on("-h", "--help", - "Show this help message.") { $stdout.puts opts; exit } - - opts.separator "" - opts.separator "Examples: " - - opts.separator " rails runner 'puts Rails.env'" - opts.separator " This runs the code `puts Rails.env` after loading the app" - opts.separator "" - opts.separator " rails runner path/to/filename.rb" - opts.separator " This runs the Ruby file located at `path/to/filename.rb` after loading the app" - - if RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ - opts.separator "" - opts.separator "You can also use runner as a shebang line for your executables:" - opts.separator " -------------------------------------------------------------" - opts.separator " #!/usr/bin/env #{File.expand_path(command)}" - opts.separator "" - opts.separator " Product.all.each { |p| p.price *= 2 ; p.save! }" - opts.separator " -------------------------------------------------------------" - end - - opts.order! { |o| code_or_file ||= o } rescue retry -end - -ARGV.delete(code_or_file) - -ENV["RAILS_ENV"] = options[:environment] - -require APP_PATH -Rails.application.require_environment! -Rails.application.load_runner - -if code_or_file.nil? - $stderr.puts "Run '#{command} -h' for help." - exit 1 -elsif File.exist?(code_or_file) - $0 = code_or_file - Kernel.load code_or_file -else - begin - eval(code_or_file, binding, __FILE__, __LINE__) - rescue SyntaxError, NameError - $stderr.puts "Please specify a valid ruby command or the path of a script to run." - $stderr.puts "Run '#{command} -h' for help." - exit 1 - end -end diff --git a/railties/lib/rails/commands/runner/USAGE b/railties/lib/rails/commands/runner/USAGE new file mode 100644 index 0000000000..dc47a35ff3 --- /dev/null +++ b/railties/lib/rails/commands/runner/USAGE @@ -0,0 +1,17 @@ +Examples: + +Run `puts Rails.env` after loading the app: + + <%= executable %> 'puts Rails.env' + +Run the Ruby file located at `path/to/filename.rb` after loading the app: + + <%= executable %> path/to/filename.rb + +<% if RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ %> +You can also use the runner command as a shebang line for your executables: + + #!/usr/bin/env <%= File.expand_path(executable) %> + + Product.all.each { |p| p.price *= 2 ; p.save! } +<% end %> diff --git a/railties/lib/rails/commands/runner/runner_command.rb b/railties/lib/rails/commands/runner/runner_command.rb new file mode 100644 index 0000000000..8db6da8759 --- /dev/null +++ b/railties/lib/rails/commands/runner/runner_command.rb @@ -0,0 +1,45 @@ +module Rails + module Command + class RunnerCommand < Base + class_option :environment, aliases: "-e", type: :string, + default: Rails::Command.environment.dup, + desc: "The environment for the runner to operate under (test/development/production)" + + def help + super + puts self.class.desc + end + + def self.banner(*) + "#{super} [<'Some.ruby(code)'> | <filename.rb>]" + end + + def perform(code_or_file = nil) + unless code_or_file + help + exit 1 + end + + ENV["RAILS_ENV"] = options[:environment] + + require_application_and_environment! + Rails.application.load_runner + + if File.exist?(code_or_file) + $0 = code_or_file + Kernel.load code_or_file + else + begin + eval(code_or_file, binding, __FILE__, __LINE__) + rescue SyntaxError, NameError => error + $stderr.puts "Please specify a valid ruby command or the path of a script to run." + $stderr.puts "Run '#{self.class.executable} -h' for help." + $stderr.puts + $stderr.puts error + exit 1 + end + end + end + end + end +end diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server/server_command.rb index 7418dff18b..14cf72f483 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server/server_command.rb @@ -1,8 +1,8 @@ -require 'fileutils' -require 'optparse' -require 'action_dispatch' -require 'rails' -require 'rails/dev_caching' +require "fileutils" +require "optparse" +require "action_dispatch" +require "rails" +require "rails/dev_caching" module Rails class Server < ::Rack::Server @@ -19,11 +19,13 @@ module Rails options end - private - - def option_parser(options) + def option_parser(options) # :nodoc: OptionParser.new do |opts| - opts.banner = "Usage: rails server [mongrel, thin etc] [options]" + opts.banner = "Usage: rails server [puma, thin etc] [options]" + + opts.separator "" + opts.separator "Options:" + opts.on("-p", "--port=port", Integer, "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v } opts.on("-b", "--binding=IP", String, @@ -80,7 +82,7 @@ module Rails ensure # The '-h' option calls exit before @options is set. # If we call 'options' with it unset, we get double help banners. - puts 'Exiting' unless @options && options[:daemonize] + puts "Exiting" unless @options && options[:daemonize] end def middleware @@ -88,19 +90,18 @@ module Rails end def default_options - super.merge({ - Port: ENV.fetch('PORT', 3000).to_i, + super.merge( + Port: ENV.fetch("PORT", 3000).to_i, + Host: ENV.fetch("HOST", "localhost").dup, DoNotReverseLookup: true, - environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup, + environment: (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup, daemonize: false, caching: nil, pid: Options::DEFAULT_PID_PATH, - restart_cmd: restart_command - }) + restart_cmd: restart_command) end private - def setup_dev_caching if options[:environment] == "development" Rails::DevCaching.enable_by_argument(options[:caching]) @@ -116,7 +117,7 @@ module Rails def create_tmp_directories %w(cache pids sockets).each do |dir_to_make| - FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make)) + FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make)) end end @@ -136,4 +137,24 @@ module Rails "bin/rails server #{ARGV.join(' ')}" end end + + module Command + class ServerCommand < Base + def help # :nodoc: + puts Rails::Server::Options.new.option_parser(Hash.new) + end + + def perform + set_application_directory! + + Rails::Server.new.tap do |server| + # Require application after server sets environment to propagate + # the --environment option. + require APP_PATH + Dir.chdir(Rails.application.root) + server.start + end + end + end + end end diff --git a/railties/lib/rails/commands/test.rb b/railties/lib/rails/commands/test.rb deleted file mode 100644 index dd069f081f..0000000000 --- a/railties/lib/rails/commands/test.rb +++ /dev/null @@ -1,9 +0,0 @@ -require "rails/test_unit/minitest_plugin" - -if defined?(ENGINE_ROOT) - $: << File.expand_path('test', ENGINE_ROOT) -else - $: << File.expand_path('../../test', APP_PATH) -end - -exit Minitest.run(ARGV) diff --git a/railties/lib/rails/commands/test/test_command.rb b/railties/lib/rails/commands/test/test_command.rb new file mode 100644 index 0000000000..1b2e3af9cc --- /dev/null +++ b/railties/lib/rails/commands/test/test_command.rb @@ -0,0 +1,20 @@ +require "rails/command" +require "rails/test_unit/minitest_plugin" + +module Rails + module Command + class TestCommand < Base + def help # :nodoc: + perform # Hand over help printing to minitest. + end + + def perform(*) + $LOAD_PATH << Rails::Command.root.join("test") + + Minitest.run_via[:rails] = true + + require "active_support/testing/autorun" + end + end + end +end diff --git a/railties/lib/rails/commands/version/version_command.rb b/railties/lib/rails/commands/version/version_command.rb new file mode 100644 index 0000000000..4f3fbfca1b --- /dev/null +++ b/railties/lib/rails/commands/version/version_command.rb @@ -0,0 +1,9 @@ +module Rails + module Command + class VersionCommand < Base + def perform + Rails::Command.invoke :application, [ "--version" ] + end + end + end +end diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 30eafd59f2..7dfab969e8 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -1,7 +1,7 @@ -require 'active_support/ordered_options' -require 'active_support/core_ext/object' -require 'rails/paths' -require 'rails/rack' +require "active_support/ordered_options" +require "active_support/core_ext/object" +require "rails/paths" +require "rails/rack" module Rails module Configuration @@ -112,7 +112,7 @@ module Rails end def method_missing(method, *args) - method = method.to_s.sub(/=$/, '').to_sym + method = method.to_s.sub(/=$/, "").to_sym return @options[method] if args.empty? diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb index 9ad77e0a80..541d5e3dad 100644 --- a/railties/lib/rails/console/app.rb +++ b/railties/lib/rails/console/app.rb @@ -1,5 +1,5 @@ -require 'active_support/all' -require 'action_controller' +require "active_support/all" +require "action_controller" module Rails module ConsoleMethods diff --git a/railties/lib/rails/dev_caching.rb b/railties/lib/rails/dev_caching.rb index f2a53d6417..f69275a34a 100644 --- a/railties/lib/rails/dev_caching.rb +++ b/railties/lib/rails/dev_caching.rb @@ -1,27 +1,27 @@ -require 'fileutils' +require "fileutils" module Rails module DevCaching # :nodoc: class << self - FILE = 'tmp/caching-dev.txt' + FILE = "tmp/caching-dev.txt" def enable_by_file - FileUtils.mkdir_p('tmp') + FileUtils.mkdir_p("tmp") if File.exist?(FILE) delete_cache_file - puts 'Development mode is no longer being cached.' + puts "Development mode is no longer being cached." else create_cache_file - puts 'Development mode is now being cached.' + puts "Development mode is now being cached." end - FileUtils.touch 'tmp/restart.txt' - FileUtils.rm_f('tmp/pids/server.pid') + FileUtils.touch "tmp/restart.txt" + FileUtils.rm_f("tmp/pids/server.pid") end def enable_by_argument(caching) - FileUtils.mkdir_p('tmp') + FileUtils.mkdir_p("tmp") if caching create_cache_file diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 9701409755..90e7c04d7c 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -1,8 +1,8 @@ -require 'rails/railtie' -require 'rails/engine/railties' -require 'active_support/core_ext/module/delegation' -require 'pathname' -require 'thread' +require "rails/railtie" +require "rails/engine/railties" +require "active_support/core_ext/module/delegation" +require "pathname" +require "thread" module Rails # <tt>Rails::Engine</tt> allows you to wrap a specific Rails application or subset of @@ -337,7 +337,7 @@ module Rails # == Loading priority # # In order to change engine's priority you can use +config.railties_order+ in the main application. - # It will affect the priority of loading views, helpers, assets and all the other files + # It will affect the priority of loading views, helpers, assets, and all the other files # related to engine or application. # # # load Blog::Engine with highest priority, followed by application and other railties @@ -402,7 +402,7 @@ module Rails end unless mod.respond_to?(:railtie_routes_url_helpers) - define_method(:railtie_routes_url_helpers) {|include_path_helpers = true| railtie.routes.url_helpers(include_path_helpers) } + define_method(:railtie_routes_url_helpers) { |include_path_helpers = true| railtie.routes.url_helpers(include_path_helpers) } end end end @@ -590,8 +590,8 @@ module Rails initializer :add_view_paths do views = paths["app/views"].existent unless views.empty? - ActiveSupport.on_load(:action_controller){ prepend_view_path(views) if respond_to?(:prepend_view_path) } - ActiveSupport.on_load(:action_mailer){ prepend_view_path(views) } + ActiveSupport.on_load(:action_controller) { prepend_view_path(views) if respond_to?(:prepend_view_path) } + ActiveSupport.on_load(:action_mailer) { prepend_view_path(views) } end end @@ -619,7 +619,7 @@ module Rails end rake_tasks do - next if self.is_a?(Rails::Application) + next if is_a?(Rails::Application) next unless has_migrations? namespace railtie_name do @@ -643,62 +643,62 @@ module Rails protected - def load_config_initializer(initializer) - ActiveSupport::Notifications.instrument('load_config_initializer.railties', initializer: initializer) do - load(initializer) + def load_config_initializer(initializer) + ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do + load(initializer) + end end - end - def run_tasks_blocks(*) #:nodoc: - super - paths["lib/tasks"].existent.sort.each { |ext| load(ext) } - end + def run_tasks_blocks(*) #:nodoc: + super + paths["lib/tasks"].existent.sort.each { |ext| load(ext) } + end - def has_migrations? #:nodoc: - paths["db/migrate"].existent.any? - end + def has_migrations? #:nodoc: + paths["db/migrate"].existent.any? + end - def self.find_root_with_flag(flag, root_path, default=nil) #:nodoc: + def self.find_root_with_flag(flag, root_path, default=nil) #:nodoc: - while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}") - parent = File.dirname(root_path) - root_path = parent != root_path && parent - end + while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}") + parent = File.dirname(root_path) + root_path = parent != root_path && parent + end - root = File.exist?("#{root_path}/#{flag}") ? root_path : default - raise "Could not find root path for #{self}" unless root + root = File.exist?("#{root_path}/#{flag}") ? root_path : default + raise "Could not find root path for #{self}" unless root - Pathname.new File.realpath root - end + Pathname.new File.realpath root + end - def default_middleware_stack #:nodoc: - ActionDispatch::MiddlewareStack.new - end + def default_middleware_stack #:nodoc: + ActionDispatch::MiddlewareStack.new + end - def _all_autoload_once_paths #:nodoc: - config.autoload_once_paths - end + def _all_autoload_once_paths #:nodoc: + config.autoload_once_paths + end - def _all_autoload_paths #:nodoc: - @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq - end + def _all_autoload_paths #:nodoc: + @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq + end - def _all_load_paths #:nodoc: - @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq - end + def _all_load_paths #:nodoc: + @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq + end private - def build_request(env) - env.merge!(env_config) - req = ActionDispatch::Request.new env - req.routes = routes - req.engine_script_name = req.script_name - req - end + def build_request(env) + env.merge!(env_config) + req = ActionDispatch::Request.new env + req.routes = routes + req.engine_script_name = req.script_name + req + end - def build_middleware - config.middleware - end + def build_middleware + config.middleware + end end end diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb index 7bbd9ef744..a23ae44b0b 100644 --- a/railties/lib/rails/engine/commands.rb +++ b/railties/lib/rails/engine/commands.rb @@ -1,6 +1,4 @@ -require 'rails/engine/commands_tasks' - -ARGV << '--help' if ARGV.empty? +require "rails/command" aliases = { "g" => "generate", @@ -11,4 +9,4 @@ aliases = { command = ARGV.shift command = aliases[command] || command -Rails::Engine::CommandsTasks.new(ARGV).run_command!(command) +Rails::Command.invoke command, ARGV diff --git a/railties/lib/rails/engine/commands_tasks.rb b/railties/lib/rails/engine/commands_tasks.rb deleted file mode 100644 index fa3ee59b7d..0000000000 --- a/railties/lib/rails/engine/commands_tasks.rb +++ /dev/null @@ -1,116 +0,0 @@ -require 'rails/commands/rake_proxy' - -module Rails - class Engine - class CommandsTasks # :nodoc: - include Rails::RakeProxy - - attr_reader :argv - - HELP_MESSAGE = <<-EOT -Usage: rails COMMAND [ARGS] - -The common Rails commands available for engines are: - generate Generate new code (short-cut alias: "g") - destroy Undo code generated with "generate" (short-cut alias: "d") - test Run tests (short-cut alias: "t") - -All commands can be run with -h for more information. - -If you want to run any commands that need to be run in context -of the application, like `rails server` or `rails console`, -you should do it from application's directory (typically test/dummy). - -In addition to those commands, there are: - EOT - - COMMAND_WHITELIST = %w(generate destroy version help test) - - def initialize(argv) - @argv = argv - end - - def run_command!(command) - command = parse_command(command) - - if COMMAND_WHITELIST.include?(command) - send(command) - else - run_rake_task(command) - end - end - - def generate - generate_or_destroy(:generate) - end - - def destroy - generate_or_destroy(:destroy) - end - - def test - require_command!("test") - end - - def version - argv.unshift '--version' - require_command!("application") - end - - def help - write_help_message - write_commands(formatted_rake_tasks) - end - - private - - def require_command!(command) - require "rails/commands/#{command}" - end - - def generate_or_destroy(command) - load_generators - require_command!(command) - end - - def load_generators - require 'rails/generators' - require ENGINE_PATH - - engine = ::Rails::Engine.find(ENGINE_ROOT) - Rails::Generators.namespace = engine.railtie_namespace - engine.load_generators - end - - def write_help_message - puts HELP_MESSAGE - end - - def write_commands(commands) - width = commands.map { |name, _| name.size }.max || 10 - commands.each { |command| printf(" %-#{width}s %s\n", *command) } - end - - def parse_command(command) - case command - when '--version', '-v' - 'version' - when '--help', '-h' - 'help' - else - command - end - end - - def rake_tasks - return @rake_tasks if defined?(@rake_tasks) - - load_generators - Rake::TaskManager.record_task_metadata = true - Rake.application.init('rails') - Rake.application.load_rakefile - @rake_tasks = Rake.application.tasks.select(&:comment) - end - end - end -end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 294d07446f..147b904679 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -1,4 +1,4 @@ -require 'rails/railtie/configuration' +require "rails/railtie/configuration" module Rails class Engine diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 330bd7ec5d..dd16b44786 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -1,45 +1,48 @@ -activesupport_path = File.expand_path('../../../../activesupport/lib', __FILE__) +activesupport_path = File.expand_path("../../../../activesupport/lib", __FILE__) $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) -require 'thor/group' +require "thor/group" +require "rails/command" -require 'active_support' -require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/array/extract_options' -require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/module/attribute_accessors' -require 'active_support/core_ext/string/inflections' +require "active_support" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/string/inflections" module Rails module Generators - autoload :Actions, 'rails/generators/actions' - autoload :ActiveModel, 'rails/generators/active_model' - autoload :Base, 'rails/generators/base' - autoload :Migration, 'rails/generators/migration' - autoload :NamedBase, 'rails/generators/named_base' - autoload :ResourceHelpers, 'rails/generators/resource_helpers' - autoload :TestCase, 'rails/generators/test_case' + include Rails::Command::Behavior + + autoload :Actions, "rails/generators/actions" + autoload :ActiveModel, "rails/generators/active_model" + autoload :Base, "rails/generators/base" + autoload :Migration, "rails/generators/migration" + autoload :NamedBase, "rails/generators/named_base" + autoload :ResourceHelpers, "rails/generators/resource_helpers" + autoload :TestCase, "rails/generators/test_case" mattr_accessor :namespace DEFAULT_ALIASES = { rails: { - actions: '-a', - orm: '-o', - javascripts: '-j', - javascript_engine: '-je', - resource_controller: '-c', - scaffold_controller: '-c', - stylesheets: '-y', - stylesheet_engine: '-se', - scaffold_stylesheet: '-ss', - template_engine: '-e', - test_framework: '-t' + actions: "-a", + orm: "-o", + javascripts: "-j", + javascript_engine: "-je", + resource_controller: "-c", + scaffold_controller: "-c", + stylesheets: "-y", + stylesheet_engine: "-se", + scaffold_stylesheet: "-ss", + template_engine: "-e", + test_framework: "-t" }, test_unit: { - fixture_replacement: '-r', + fixture_replacement: "-r", } } @@ -117,7 +120,7 @@ module Rails template_engine: nil ) - if ARGV.first == 'mailer' + if ARGV.first == "mailer" options[:rails].merge!(template_engine: :erb) end end @@ -127,67 +130,6 @@ module Rails Thor::Base.shell = Thor::Shell::Basic end - # Track all generators subclasses. - def self.subclasses - @subclasses ||= [] - end - - # Rails finds namespaces similar to thor, it only adds one rule: - # - # Generators names must end with "_generator.rb". This is required because Rails - # looks in load paths and loads the generator just before it's going to be used. - # - # find_by_namespace :webrat, :rails, :integration - # - # Will search for the following generators: - # - # "rails:webrat", "webrat:integration", "webrat" - # - # Notice that "rails:generators:webrat" could be loaded as well, what - # Rails looks for is the first and last parts of the namespace. - def self.find_by_namespace(name, base=nil, context=nil) #:nodoc: - lookups = [] - lookups << "#{base}:#{name}" if base - lookups << "#{name}:#{context}" if context - - unless base || context - unless name.to_s.include?(?:) - lookups << "#{name}:#{name}" - lookups << "rails:#{name}" - end - lookups << "#{name}" - end - - lookup(lookups) - - namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }] - - lookups.each do |namespace| - klass = namespaces[namespace] - return klass if klass - end - - invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name) - end - - # Receives a namespace, arguments and the behavior to invoke the generator. - # It's used as the default entry point for generate, destroy and update - # commands. - def self.invoke(namespace, args=ARGV, config={}) - names = namespace.to_s.split(':') - if klass = find_by_namespace(names.pop, names.any? && names.join(':')) - args << "--help" if args.empty? && klass.arguments.any?(&:required?) - klass.start(args, config) - else - options = sorted_groups.flat_map(&:last) - suggestions = options.sort_by {|suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3) - msg = "Could not find generator '#{namespace}'. " - msg << "Maybe you meant #{ suggestions.map {|s| "'#{s}'"}.to_sentence(last_word_connector: " or ", locale: :en) }\n" - msg << "Run `rails generate --help` for more options." - puts msg - end - end - # Returns an array of generator namespaces that are hidden. # Generator namespaces may be hidden for a variety of reasons. # Some are aliased such as "rails:migration" and can be @@ -232,7 +174,7 @@ module Rails end # Show help message with available generators. - def self.help(command = 'generate') + def self.help(command = "generate") puts "Usage: rails #{command} GENERATOR [args] [options]" puts puts "General options:" @@ -260,74 +202,83 @@ module Rails def self.sorted_groups namespaces = public_namespaces namespaces.sort! + groups = Hash.new { |h,k| h[k] = [] } namespaces.each do |namespace| - base = namespace.split(':').first + base = namespace.split(":").first groups[base] << namespace end + rails = groups.delete("rails") - rails.map! { |n| n.sub(/^rails:/, '') } + rails.map! { |n| n.sub(/^rails:/, "") } rails.delete("app") rails.delete("plugin") hidden_namespaces.each { |n| groups.delete(n.to_s) } - [["rails", rails]] + groups.sort.to_a + [[ "rails", rails ]] + groups.sort.to_a end - protected + # Rails finds namespaces similar to thor, it only adds one rule: + # + # Generators names must end with "_generator.rb". This is required because Rails + # looks in load paths and loads the generator just before it's going to be used. + # + # find_by_namespace :webrat, :rails, :integration + # + # Will search for the following generators: + # + # "rails:webrat", "webrat:integration", "webrat" + # + # Notice that "rails:generators:webrat" could be loaded as well, what + # Rails looks for is the first and last parts of the namespace. + def self.find_by_namespace(name, base = nil, context = nil) #:nodoc: + lookups = [] + lookups << "#{base}:#{name}" if base + lookups << "#{name}:#{context}" if context - # This code is based directly on the Text gem implementation - # Returns a value representing the "cost" of transforming str1 into str2 - def self.levenshtein_distance str1, str2 - s = str1 - t = str2 - n = s.length - m = t.length - - return m if (0 == n) - return n if (0 == m) - - d = (0..m).to_a - x = nil - - # avoid duplicating an enumerable object in the loop - str2_codepoint_enumerable = str2.each_codepoint - - str1.each_codepoint.with_index do |char1, i| - e = i+1 - - str2_codepoint_enumerable.with_index do |char2, j| - cost = (char1 == char2) ? 0 : 1 - x = [ - d[j+1] + 1, # insertion - e + 1, # deletion - d[j] + cost # substitution - ].min - d[j] = e - e = x - end - - d[m] = x + unless base || context + unless name.to_s.include?(?:) + lookups << "#{name}:#{name}" + lookups << "rails:#{name}" end - - x + lookups << "#{name}" end - # Prints a list of generators. - def self.print_list(base, namespaces) #:nodoc: - namespaces = namespaces.reject do |n| - hidden_namespaces.include?(n) - end + lookup(lookups) - return if namespaces.empty? - puts "#{base.camelize}:" + namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }] + lookups.each do |namespace| - namespaces.each do |namespace| - puts(" #{namespace}") - end + klass = namespaces[namespace] + return klass if klass + end + + invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name) + end - puts + # Receives a namespace, arguments and the behavior to invoke the generator. + # It's used as the default entry point for generate, destroy and update + # commands. + def self.invoke(namespace, args=ARGV, config={}) + names = namespace.to_s.split(":") + if klass = find_by_namespace(names.pop, names.any? && names.join(":")) + args << "--help" if args.empty? && klass.arguments.any?(&:required?) + klass.start(args, config) + else + options = sorted_groups.flat_map(&:last) + suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3) + msg = "Could not find generator '#{namespace}'. " + msg << "Maybe you meant #{ suggestions.map { |s| "'#{s}'" }.to_sentence(last_word_connector: " or ", locale: :en) }\n" + msg << "Run `rails generate --help` for more options." + puts msg + end + end + + protected + def self.print_list(base, namespaces) + namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) } + super end # Try fallbacks for the given base. @@ -346,53 +297,16 @@ module Rails nil end - # Receives namespaces in an array and tries to find matching generators - # in the load path. - def self.lookup(namespaces) #:nodoc: - paths = namespaces_to_paths(namespaces) - - paths.each do |raw_path| - ["rails/generators", "generators"].each do |base| - path = "#{base}/#{raw_path}_generator" - - begin - require path - return - rescue LoadError => e - raise unless e.message =~ /#{Regexp.escape(path)}$/ - rescue Exception => e - warn "[WARNING] Could not load generator #{path.inspect}. Error: #{e.message}.\n#{e.backtrace.join("\n")}" - end - end - end + def self.command_type + @command_type ||= "generator" end - # This will try to load any generator in the load path to show in help. - def self.lookup! #:nodoc: - $LOAD_PATH.each do |base| - Dir[File.join(base, "{rails/generators,generators}", "**", "*_generator.rb")].each do |path| - begin - path = path.sub("#{base}/", "") - require path - rescue Exception - # No problem - end - end - end + def self.lookup_paths + @lookup_paths ||= %w( rails/generators generators ) end - # Convert namespaces to paths by replacing ":" for "/" and adding - # an extra lookup. For example, "rails:model" should be searched - # in both: "rails/model/model_generator" and "rails/model_generator". - def self.namespaces_to_paths(namespaces) #:nodoc: - paths = [] - namespaces.each do |namespace| - pieces = namespace.split(":") - paths << pieces.dup.push(pieces.last).join("/") - paths << pieces.join("/") - end - paths.uniq! - paths + def self.file_lookup_paths + @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_generator.rb" ] end end end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index c947c062fa..ab9dc019e2 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -103,7 +103,7 @@ module Rails in_root do if options[:env].nil? - inject_into_file 'config/application.rb', "\n #{data}", after: sentinel, verbose: false + inject_into_file "config/application.rb", "\n #{data}", after: sentinel, verbose: false else Array(options[:env]).each do |env| inject_into_file "config/environments/#{env}.rb", "\n #{data}", after: env_file_sentinel, verbose: false @@ -239,7 +239,7 @@ module Rails sentinel = /\.routes\.draw do\s*\n/m in_root do - inject_into_file 'config/routes.rb', " #{routing_code}\n", { after: sentinel, verbose: false, force: false } + inject_into_file "config/routes.rb", " #{routing_code}\n", after: sentinel, verbose: false, force: false end end @@ -274,19 +274,18 @@ module Rails end end - # Runs the supplied command using either "rake ..." or "rails ..." # based on the executor parameter provided. def execute_command(executor, command, options={}) log executor, command - env = options[:env] || ENV["RAILS_ENV"] || 'development' - sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : '' + env = options[:env] || ENV["RAILS_ENV"] || "development" + sudo = options[:sudo] && RbConfig::CONFIG["host_os"] !~ /mswin|mingw/ ? "sudo " : "" in_root { run("#{sudo}#{extify(executor)} #{command} RAILS_ENV=#{env}", verbose: false) } end # Add an extension to the given name based on the platform. def extify(name) - if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ "#{name}.bat" else name diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb index 6c5b55466d..587c61fd42 100644 --- a/railties/lib/rails/generators/actions/create_migration.rb +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -1,11 +1,10 @@ -require 'fileutils' -require 'thor/actions' +require "fileutils" +require "thor/actions" module Rails module Generators module Actions class CreateMigration < Thor::Actions::CreateFile #:nodoc: - def migration_dir File.dirname(@destination) end @@ -40,30 +39,30 @@ module Rails protected - def on_conflict_behavior - options = base.options.merge(config) - if identical? - say_status :identical, :blue, relative_existing_migration - elsif options[:force] - say_status :remove, :green, relative_existing_migration - say_status :create, :green - unless pretend? - ::FileUtils.rm_rf(existing_migration) - yield + def on_conflict_behavior + options = base.options.merge(config) + if identical? + say_status :identical, :blue, relative_existing_migration + elsif options[:force] + say_status :remove, :green, relative_existing_migration + say_status :create, :green + unless pretend? + ::FileUtils.rm_rf(existing_migration) + yield + end + elsif options[:skip] + say_status :skip, :yellow + else + say_status :conflict, :red + raise Error, "Another migration is already named #{migration_file_name}: " + + "#{existing_migration}. Use --force to replace this migration " + + "or --skip to ignore conflicted file." end - elsif options[:skip] - say_status :skip, :yellow - else - say_status :conflict, :red - raise Error, "Another migration is already named #{migration_file_name}: " + - "#{existing_migration}. Use --force to replace this migration " + - "or --skip to ignore conflicted file." end - end - def say_status(status, color, message = relative_destination) - base.shell.say_status(status, message, color) if config[:verbose] - end + def say_status(status, color, message = relative_destination) + base.shell.say_status(status, message, color) if config[:verbose] + end end end end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index f0a3289563..91342c592c 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -1,16 +1,16 @@ -require 'fileutils' -require 'digest/md5' -require 'active_support/core_ext/string/strip' -require 'rails/version' unless defined?(Rails::VERSION) -require 'open-uri' -require 'uri' -require 'rails/generators' -require 'active_support/core_ext/array/extract_options' +require "fileutils" +require "digest/md5" +require "active_support/core_ext/string/strip" +require "rails/version" unless defined?(Rails::VERSION) +require "open-uri" +require "uri" +require "rails/generators" +require "active_support/core_ext/array/extract_options" module Rails module Generators class AppBase < Base # :nodoc: - DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver ) + DATABASES = %w( mysql postgresql sqlite3 oracle frontbase ibm_db sqlserver ) JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc ) DATABASES.concat(JDBC_DATABASES) @@ -24,42 +24,42 @@ module Rails end def self.add_shared_options_for(name) - class_option :template, type: :string, aliases: '-m', + class_option :template, type: :string, aliases: "-m", desc: "Path to some #{name} template (can be a filesystem path or URL)" - class_option :database, type: :string, aliases: '-d', default: 'sqlite3', + class_option :database, type: :string, aliases: "-d", default: "sqlite3", desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})" - class_option :javascript, type: :string, aliases: '-j', default: 'jquery', - desc: 'Preconfigure for selected JavaScript library' + class_option :javascript, type: :string, aliases: "-j", default: "jquery", + desc: "Preconfigure for selected JavaScript library" class_option :skip_gemfile, type: :boolean, default: false, desc: "Don't create a Gemfile" - class_option :skip_bundle, type: :boolean, aliases: '-B', default: false, + class_option :skip_bundle, type: :boolean, aliases: "-B", default: false, desc: "Don't run bundle install" - class_option :skip_git, type: :boolean, aliases: '-G', default: false, - desc: 'Skip .gitignore file' + class_option :skip_git, type: :boolean, aliases: "-G", default: false, + desc: "Skip .gitignore file" class_option :skip_keeps, type: :boolean, default: false, - desc: 'Skip source control .keep files' + desc: "Skip source control .keep files" class_option :skip_action_mailer, type: :boolean, aliases: "-M", default: false, desc: "Skip Action Mailer files" - class_option :skip_active_record, type: :boolean, aliases: '-O', default: false, - desc: 'Skip Active Record files' + class_option :skip_active_record, type: :boolean, aliases: "-O", default: false, + desc: "Skip Active Record files" - class_option :skip_puma, type: :boolean, aliases: '-P', default: false, - desc: 'Skip Puma related files' + class_option :skip_puma, type: :boolean, aliases: "-P", default: false, + desc: "Skip Puma related files" - class_option :skip_action_cable, type: :boolean, aliases: '-C', default: false, - desc: 'Skip Action Cable files' + class_option :skip_action_cable, type: :boolean, aliases: "-C", default: false, + desc: "Skip Action Cable files" - class_option :skip_sprockets, type: :boolean, aliases: '-S', default: false, - desc: 'Skip Sprockets files' + class_option :skip_sprockets, type: :boolean, aliases: "-S", default: false, + desc: "Skip Sprockets files" class_option :skip_spring, type: :boolean, default: false, desc: "Don't install Spring application preloader" @@ -67,14 +67,14 @@ module Rails class_option :skip_listen, type: :boolean, default: false, desc: "Don't generate configuration that depends on the listen gem" - class_option :skip_javascript, type: :boolean, aliases: '-J', default: false, - desc: 'Skip JavaScript files' + class_option :skip_javascript, type: :boolean, aliases: "-J", default: false, + desc: "Skip JavaScript files" class_option :skip_turbolinks, type: :boolean, default: false, - desc: 'Skip turbolinks gem' + desc: "Skip turbolinks gem" - class_option :skip_test, type: :boolean, aliases: '-T', default: false, - desc: 'Skip test files' + class_option :skip_test, type: :boolean, aliases: "-T", default: false, + desc: "Skip test files" class_option :dev, type: :boolean, default: false, desc: "Setup the #{name} with Gemfile pointing to your Rails checkout" @@ -86,10 +86,10 @@ module Rails desc: "Path to file containing extra configuration options for rails command" class_option :no_rc, type: :boolean, default: false, - desc: 'Skip loading of extra configuration options from .railsrc file' + desc: "Skip loading of extra configuration options from .railsrc file" - class_option :help, type: :boolean, aliases: '-h', group: :rails, - desc: 'Show this help message and quit' + class_option :help, type: :boolean, aliases: "-h", group: :rails, + desc: "Show this help message and quit" end def initialize(*args) @@ -150,7 +150,7 @@ module Rails def create_root valid_const? - empty_directory '.' + empty_directory "." FileUtils.cd(destination_root) unless options[:pretend] end @@ -162,14 +162,15 @@ module Rails def set_default_accessors! self.destination_root = File.expand_path(app_path, destination_root) - self.rails_template = case options[:template] + self.rails_template = \ + case options[:template] when /^https?:\/\// options[:template] when String File.expand_path(options[:template], Dir.pwd) else options[:template] - end + end end def database_gemfile_entry @@ -181,8 +182,8 @@ module Rails def webserver_gemfile_entry return [] if options[:skip_puma] - comment = 'Use Puma as the app server' - GemfileEntry.new('puma', '~> 3.0', comment) + comment = "Use Puma as the app server" + GemfileEntry.new("puma", "~> 3.0", comment) end def include_all_railties? @@ -190,7 +191,7 @@ module Rails end def comment_if(value) - options[value] ? '# ' : '' + options[value] ? "# " : "" end def keeps? @@ -198,7 +199,7 @@ module Rails end def sqlite3? - !options[:skip_active_record] && options[:database] == 'sqlite3' + !options[:skip_active_record] && options[:database] == "sqlite3" end class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out) @@ -238,14 +239,14 @@ module Rails ] if options.dev? [ - GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH) + GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH) ] + dev_edge_common elsif options.edge? [ - GemfileEntry.github('rails', 'rails/rails') + GemfileEntry.github("rails", "rails/rails") ] + dev_edge_common else - [GemfileEntry.version('rails', + [GemfileEntry.version("rails", rails_version_specifier, "Bundle edge Rails instead: gem 'rails', github: 'rails/rails'")] end @@ -266,12 +267,12 @@ module Rails end def gem_for_database - # %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql ) + # %w( mysql postgresql sqlite3 oracle frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql ) case options[:database] - when "oracle" then ["ruby-oci8", nil] + when "mysql" then ["mysql2", [">= 0.3.18", "< 0.5"]] when "postgresql" then ["pg", ["~> 0.18"]] + when "oracle" then ["ruby-oci8", nil] when "frontbase" then ["ruby-frontbase", nil] - when "mysql" then ["mysql2", [">= 0.3.18", "< 0.5"]] when "sqlserver" then ["activerecord-sqlserver-adapter", nil] when "jdbcmysql" then ["activerecord-jdbcmysql-adapter", nil] when "jdbcsqlite3" then ["activerecord-jdbcsqlite3-adapter", nil] @@ -284,9 +285,9 @@ module Rails def convert_database_option_for_jruby if defined?(JRUBY_VERSION) case options[:database] - when "oracle" then options[:database].replace "jdbc" when "postgresql" then options[:database].replace "jdbcpostgresql" when "mysql" then options[:database].replace "jdbcmysql" + when "oracle" then options[:database].replace "jdbc" when "sqlite3" then options[:database].replace "jdbcsqlite3" end end @@ -296,23 +297,25 @@ module Rails return [] if options[:skip_sprockets] gems = [] - gems << GemfileEntry.github('sass-rails', 'rails/sass-rails', nil, - 'Use SCSS for stylesheets') + gems << GemfileEntry.github("sass-rails", "rails/sass-rails", nil, + "Use SCSS for stylesheets") - gems << GemfileEntry.version('uglifier', - '>= 1.3.0', - 'Use Uglifier as compressor for JavaScript assets') + if !options[:skip_javascript] + gems << GemfileEntry.version("uglifier", + ">= 1.3.0", + "Use Uglifier as compressor for JavaScript assets") + end gems end def jbuilder_gemfile_entry - comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder' - GemfileEntry.new 'jbuilder', '~> 2.5', comment, {}, options[:api] + comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder" + GemfileEntry.new "jbuilder", "~> 2.5", comment, {}, options[:api] end def coffee_gemfile_entry - GemfileEntry.github 'coffee-rails', 'rails/coffee-rails', nil, 'Use CoffeeScript for .coffee assets and views' + GemfileEntry.version "coffee-rails", "~> 4.2", "Use CoffeeScript for .coffee assets and views" end def javascript_gemfile_entry @@ -324,7 +327,7 @@ module Rails "Use #{options[:javascript]} as the JavaScript library") unless options[:skip_turbolinks] - gems << GemfileEntry.version("turbolinks", "~> 5.x", + gems << GemfileEntry.version("turbolinks", "~> 5", "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") end @@ -333,27 +336,27 @@ module Rails end def javascript_runtime_gemfile_entry - comment = 'See https://github.com/rails/execjs#readme for more supported runtimes' + comment = "See https://github.com/rails/execjs#readme for more supported runtimes" if defined?(JRUBY_VERSION) - GemfileEntry.version 'therubyrhino', nil, comment + GemfileEntry.version "therubyrhino", nil, comment else - GemfileEntry.new 'therubyracer', nil, comment, { platforms: :ruby }, true + GemfileEntry.new "therubyracer", nil, comment, { platforms: :ruby }, true end end def psych_gemfile_entry return [] unless defined?(Rubinius) - comment = 'Use Psych as the YAML engine, instead of Syck, so serialized ' \ - 'data can be read safely from different rubies (see http://git.io/uuLVag)' - GemfileEntry.new('psych', '~> 2.0', comment, platforms: :rbx) + comment = "Use Psych as the YAML engine, instead of Syck, so serialized " \ + "data can be read safely from different rubies (see http://git.io/uuLVag)" + GemfileEntry.new("psych", "~> 2.0", comment, platforms: :rbx) end def cable_gemfile_entry return [] if options[:skip_action_cable] - comment = 'Use Redis adapter to run Action Cable in production' + comment = "Use Redis adapter to run Action Cable in production" gems = [] - gems << GemfileEntry.new("redis", '~> 3.0', comment, {}, true) + gems << GemfileEntry.new("redis", "~> 3.0", comment, {}, true) gems end @@ -368,9 +371,9 @@ module Rails # We unset temporary bundler variables to load proper bundler and Gemfile. # # Thanks to James Tucker for the Gem tricks involved in this call. - _bundle_command = Gem.bin_path('bundler', 'bundle') + _bundle_command = Gem.bin_path("bundler", "bundle") - require 'bundler' + require "bundler" Bundler.with_clean_env do full_command = %Q["#{Gem.ruby}" "#{_bundle_command}" #{command}] if options[:quiet] @@ -394,11 +397,11 @@ module Rails end def os_supports_listen_out_of_the_box? - RbConfig::CONFIG['host_os'] =~ /darwin|linux/ + RbConfig::CONFIG["host_os"] =~ /darwin|linux/ end def run_bundle - bundle_command('install') if bundle_install? + bundle_command("install") if bundle_install? end def generate_spring_binstubs diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index c72ec400a0..1a0420c769 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -1,5 +1,5 @@ begin - require 'thor/group' + require "thor/group" rescue LoadError puts "Thor is not available.\nIf you ran this command from a git checkout " \ "of Rails, please make sure thor is installed,\nand run this command " \ @@ -42,13 +42,13 @@ module Rails # is removed. def self.namespace(name=nil) return super if name - @namespace ||= super.sub(/_generator$/, '').sub(/:generators:/, ':') + @namespace ||= super.sub(/_generator$/, "").sub(/:generators:/, ":") end # Convenience method to hide this generator from the available ones when # running rails generator command. def self.hide! - Rails::Generators.hide_namespace self.namespace + Rails::Generators.hide_namespace(namespace) end # Invoke a generator based on the value supplied by the user to the @@ -168,7 +168,7 @@ module Rails names.each do |name| unless class_options.key?(name) defaults = if options[:type] == :boolean - { } + {} elsif [true, false].include?(default_value_for_option(name, options)) { banner: "" } else @@ -208,7 +208,7 @@ module Rails def self.default_source_root return unless base_name && generator_name return unless default_generator_root - path = File.join(default_generator_root, 'templates') + path = File.join(default_generator_root, "templates") path if File.exist?(path) end @@ -230,7 +230,7 @@ module Rails Rails::Generators.subclasses << base Rails::Generators.templates_path.each do |path| - if base.name.include?('::') + if base.name.include?("::") base.source_paths << File.join(path, base.base_name, base.generator_name) else base.source_paths << File.join(path, base.generator_name) @@ -251,7 +251,7 @@ module Rails next if class_name.strip.empty? # Split the class from its module nesting - nesting = class_name.split('::') + nesting = class_name.split("::") last_name = nesting.pop last = extract_last_module(nesting) @@ -273,13 +273,13 @@ module Rails # Use Rails default banner. def self.banner - "rails generate #{namespace.sub(/^rails:/,'')} #{self.arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, ' ') + "rails generate #{namespace.sub(/^rails:/,'')} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ") end # Sets the base_name taking into account the current class namespace. def self.base_name @base_name ||= begin - if base = name.to_s.split('::').first + if base = name.to_s.split("::").first base.underscore end end @@ -289,8 +289,8 @@ module Rails # Rails::Generators::ModelGenerator will return "model" as generator name. def self.generator_name @generator_name ||= begin - if generator = name.to_s.split('::').last - generator.sub!(/Generator$/, '') + if generator = name.to_s.split("::").last + generator.sub!(/Generator$/, "") generator.underscore end end @@ -310,9 +310,9 @@ module Rails # Returns default for the option name given doing a lookup in config. def self.default_for_option(config, name, options, default) - if generator_name and c = config[generator_name.to_sym] and c.key?(name) + if generator_name && (c = config[generator_name.to_sym]) && c.key?(name) c[name] - elsif base_name and c = config[base_name.to_sym] and c.key?(name) + elsif base_name && (c = config[base_name.to_sym]) && c.key?(name) c[name] elsif config[:rails].key?(name) config[:rails][name] @@ -373,7 +373,6 @@ module Rails path = File.expand_path(File.join(base_name, generator_name), base_root) path if File.exist?(path) end - end end end diff --git a/railties/lib/rails/generators/css/assets/assets_generator.rb b/railties/lib/rails/generators/css/assets/assets_generator.rb index e4a305f4b3..20baf31a34 100644 --- a/railties/lib/rails/generators/css/assets/assets_generator.rb +++ b/railties/lib/rails/generators/css/assets/assets_generator.rb @@ -6,7 +6,7 @@ module Css # :nodoc: source_root File.expand_path("../templates", __FILE__) def copy_stylesheet - copy_file "stylesheet.css", File.join('app/assets/stylesheets', class_path, "#{file_name}.css") + copy_file "stylesheet.css", File.join("app/assets/stylesheets", class_path, "#{file_name}.css") end end end diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index 0755ac335c..d01502002f 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -1,25 +1,25 @@ -require 'rails/generators/named_base' +require "rails/generators/named_base" module Erb # :nodoc: module Generators # :nodoc: class Base < Rails::Generators::NamedBase #:nodoc: protected - def formats - [format] - end + def formats + [format] + end - def format - :html - end + def format + :html + end - def handler - :erb - end + def handler + :erb + end - def filename_with_extensions(name, format = self.format) - [name, format, handler].compact.join(".") - end + def filename_with_extensions(name, format = self.format) + [name, format, handler].compact.join(".") + end end end end diff --git a/railties/lib/rails/generators/erb/controller/controller_generator.rb b/railties/lib/rails/generators/erb/controller/controller_generator.rb index 94c1b835d1..36ecfea09b 100644 --- a/railties/lib/rails/generators/erb/controller/controller_generator.rb +++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/erb' +require "rails/generators/erb" module Erb # :nodoc: module Generators # :nodoc: diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index 97f3657070..f150240908 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/erb' +require "rails/generators/erb" module Erb # :nodoc: module Generators # :nodoc: @@ -6,12 +6,12 @@ module Erb # :nodoc: argument :actions, type: :array, default: [], banner: "method method" def copy_view_files - view_base_path = File.join("app/views", class_path, file_name + '_mailer') + view_base_path = File.join("app/views", class_path, file_name + "_mailer") empty_directory view_base_path if self.behavior == :invoke formats.each do |format| - layout_path = File.join('app/views/layouts', class_path, filename_with_extensions('mailer', format)) + layout_path = File.join("app/views/layouts", class_path, filename_with_extensions("mailer", format)) template filename_with_extensions(:layout, format), layout_path end end @@ -28,13 +28,13 @@ module Erb # :nodoc: protected - def formats - [:text, :html] - end + def formats + [:text, :html] + end - def file_name - @_file_name ||= super.gsub(/_mailer/i, '') - end + def file_name + @_file_name ||= super.gsub(/_mailer/i, "") + end end end end diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index c94829a0ae..154d85f381 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -1,5 +1,5 @@ -require 'rails/generators/erb' -require 'rails/generators/resource_helpers' +require "rails/generators/erb" +require "rails/generators/resource_helpers" module Erb # :nodoc: module Generators # :nodoc: diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 7e437e7344..61181b7b97 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -1,4 +1,4 @@ -require 'active_support/time' +require "active_support/time" module Rails module Generators @@ -12,7 +12,7 @@ module Rails class << self def parse(column_definition) - name, type, has_index = column_definition.split(':') + name, type, has_index = column_definition.split(":") # if user provided "name:index" instead of "name:string:index" # type should be set blank so GeneratedAttribute's constructor @@ -66,40 +66,40 @@ module Rails def field_type @field_type ||= case type - when :integer then :number_field - when :float, :decimal then :text_field - when :time then :time_select - when :datetime, :timestamp then :datetime_select - when :date then :date_select - when :text then :text_area - when :boolean then :check_box + when :integer then :number_field + when :float, :decimal then :text_field + when :time then :time_select + when :datetime, :timestamp then :datetime_select + when :date then :date_select + when :text then :text_area + when :boolean then :check_box else - :text_field + :text_field end end def default @default ||= case type - when :integer then 1 - when :float then 1.5 - when :decimal then "9.99" - when :datetime, :timestamp, :time then Time.now.to_s(:db) - when :date then Date.today.to_s(:db) - when :string then name == "type" ? "" : "MyString" - when :text then "MyText" - when :boolean then false - when :references, :belongs_to then nil + when :integer then 1 + when :float then 1.5 + when :decimal then "9.99" + when :datetime, :timestamp, :time then Time.now.to_s(:db) + when :date then Date.today.to_s(:db) + when :string then name == "type" ? "" : "MyString" + when :text then "MyText" + when :boolean then false + when :references, :belongs_to then nil else - "" + "" end end def plural_name - name.sub(/_id$/, '').pluralize + name.sub(/_id$/, "").pluralize end def singular_name - name.sub(/_id$/, '').singularize + name.sub(/_id$/, "").singularize end def human_name @@ -127,11 +127,11 @@ module Rails end def polymorphic? - self.attr_options[:polymorphic] + attr_options[:polymorphic] end def required? - self.attr_options[:required] + attr_options[:required] end def has_index? @@ -143,7 +143,7 @@ module Rails end def password_digest? - name == 'password' && type == :digest + name == "password" && type == :digest end def token? diff --git a/railties/lib/rails/generators/js/assets/assets_generator.rb b/railties/lib/rails/generators/js/assets/assets_generator.rb index 1e925b2cd2..64d706ec91 100644 --- a/railties/lib/rails/generators/js/assets/assets_generator.rb +++ b/railties/lib/rails/generators/js/assets/assets_generator.rb @@ -6,7 +6,7 @@ module Js # :nodoc: source_root File.expand_path("../templates", __FILE__) def copy_javascript - copy_file "javascript.js", File.join('app/assets/javascripts', class_path, "#{file_name}.js") + copy_file "javascript.js", File.join("app/assets/javascripts", class_path, "#{file_name}.js") end end end diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb index 87f2e1d42b..7290e235a1 100644 --- a/railties/lib/rails/generators/migration.rb +++ b/railties/lib/rails/generators/migration.rb @@ -1,5 +1,5 @@ -require 'active_support/concern' -require 'rails/generators/actions/create_migration' +require "active_support/concern" +require "rails/generators/actions/create_migration" module Rails module Generators @@ -39,7 +39,7 @@ module Rails migration_dir = File.dirname(destination) @migration_number = self.class.next_migration_number(migration_dir) - @migration_file_name = File.basename(destination, '.rb') + @migration_file_name = File.basename(destination, ".rb") @migration_class_name = @migration_file_name.camelize end @@ -55,13 +55,13 @@ module Rails source = File.expand_path(find_in_source_paths(source.to_s)) set_migration_assigns!(destination) - context = instance_eval('binding') + context = instance_eval("binding") dir, base = File.split(destination) - numbered_destination = File.join(dir, ["%migration_number%", base].join('_')) + numbered_destination = File.join(dir, ["%migration_number%", base].join("_")) create_migration numbered_destination, nil, config do - ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context) + ERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context) end end end diff --git a/railties/lib/rails/generators/model_helpers.rb b/railties/lib/rails/generators/model_helpers.rb index 42c646543e..6f87a18660 100644 --- a/railties/lib/rails/generators/model_helpers.rb +++ b/railties/lib/rails/generators/model_helpers.rb @@ -1,4 +1,4 @@ -require 'rails/generators/active_model' +require "rails/generators/active_model" module Rails module Generators @@ -8,7 +8,7 @@ module Rails mattr_accessor :skip_warn def self.included(base) #:nodoc: - base.class_option :force_plural, type: :boolean, default: false, desc: 'Forces the use of the given model name' + base.class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of the given model name" end def initialize(args, *_options) diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index ee076eb711..c39ea24935 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/module/introspection' -require 'rails/generators/base' -require 'rails/generators/generated_attribute' +require "active_support/core_ext/module/introspection" +require "rails/generators/base" +require "rails/generators/generated_attribute" module Rails module Generators @@ -14,7 +14,7 @@ module Rails # Unfreeze name in case it's given as a frozen string args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen? super - assign_names!(self.name) + assign_names!(name) parse_attributes! if respond_to?(:attributes) end @@ -28,7 +28,7 @@ module Rails end def js_template(source, destination) - template(source + '.js', destination + '.js') + template(source + ".js", destination + ".js") end end @@ -51,7 +51,7 @@ module Rails def indent(content, multiplier = 2) spaces = " " * multiplier - content.each_line.map {|line| line.blank? ? line : "#{spaces}#{line}" }.join + content.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join end def wrap_with_namespace(content) @@ -79,7 +79,7 @@ module Rails end def file_path - @file_path ||= (class_path + [file_name]).join('/') + @file_path ||= (class_path + [file_name]).join("/") end def class_path @@ -103,7 +103,7 @@ module Rails end def class_name - (class_path + [file_name]).map!(&:camelize).join('::') + (class_path + [file_name]).map!(&:camelize).join("::") end def human_name @@ -115,13 +115,13 @@ module Rails end def i18n_scope - @i18n_scope ||= file_path.tr('/', '.') + @i18n_scope ||= file_path.tr("/", ".") end def table_name @table_name ||= begin base = pluralize_table_names? ? plural_name : singular_name - (class_path + [base]).join('_') + (class_path + [base]).join("_") end end @@ -162,24 +162,24 @@ module Rails end def route_url - @route_url ||= class_path.collect {|dname| "/" + dname }.join + "/" + plural_file_name + @route_url ||= class_path.collect { |dname| "/" + dname }.join + "/" + plural_file_name end def url_helper_prefix - @url_helper_prefix ||= (class_path + [file_name]).join('_') + @url_helper_prefix ||= (class_path + [file_name]).join("_") end # Tries to retrieve the application name or simply return application. def application_name if defined?(Rails) && Rails.application - Rails.application.class.name.split('::').first.underscore + Rails.application.class.name.split("::").first.underscore else "application" end end def assign_names!(name) #:nodoc: - @class_path = name.include?('/') ? name.split('/') : name.split('::') + @class_path = name.include?("/") ? name.split("/") : name.split("::") @class_path.map!(&:underscore) @file_name = @class_path.pop end @@ -194,7 +194,7 @@ module Rails def attributes_names @attributes_names ||= attributes.each_with_object([]) do |a, names| names << a.column_name - names << 'password_confirmation' if a.password_digest? + names << "password_confirmation" if a.password_digest? names << "#{a.name}_type" if a.polymorphic? end end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 448dce06af..03573b274d 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/app_base' +require "rails/generators/app_base" module Rails module ActionMethods # :nodoc: @@ -54,13 +54,13 @@ module Rails end def app - directory 'app' + directory "app" - keep_file 'app/assets/images' - empty_directory_with_keep_file 'app/assets/javascripts/channels' unless options[:skip_action_cable] + keep_file "app/assets/images" + empty_directory_with_keep_file "app/assets/javascripts/channels" unless options[:skip_action_cable] - keep_file 'app/controllers/concerns' - keep_file 'app/models/concerns' + keep_file "app/controllers/concerns" + keep_file "app/models/concerns" end def bin @@ -89,24 +89,24 @@ module Rails end def config_when_updating - cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb') - action_cable_config_exist = File.exist?('config/cable.yml') - rack_cors_config_exist = File.exist?('config/initializers/cors.rb') + cookie_serializer_config_exist = File.exist?("config/initializers/cookies_serializer.rb") + action_cable_config_exist = File.exist?("config/cable.yml") + rack_cors_config_exist = File.exist?("config/initializers/cors.rb") config - gsub_file 'config/environments/development.rb', /^(\s+)config\.file_watcher/, '\1# config.file_watcher' + gsub_file "config/environments/development.rb", /^(\s+)config\.file_watcher/, '\1# config.file_watcher' unless cookie_serializer_config_exist - gsub_file 'config/initializers/cookies_serializer.rb', /json(?!,)/, 'marshal' + gsub_file "config/initializers/cookies_serializer.rb", /json(?!,)/, "marshal" end unless action_cable_config_exist - template 'config/cable.yml' + template "config/cable.yml" end unless rack_cors_config_exist - remove_file 'config/initializers/cors.rb' + remove_file "config/initializers/cors.rb" end end @@ -119,13 +119,13 @@ module Rails end def lib - empty_directory 'lib' - empty_directory_with_keep_file 'lib/tasks' - empty_directory_with_keep_file 'lib/assets' + empty_directory "lib" + empty_directory_with_keep_file "lib/tasks" + empty_directory_with_keep_file "lib/assets" end def log - empty_directory_with_keep_file 'log' + empty_directory_with_keep_file "log" end def public_directory @@ -133,15 +133,15 @@ module Rails end def test - empty_directory_with_keep_file 'test/fixtures' - empty_directory_with_keep_file 'test/fixtures/files' - empty_directory_with_keep_file 'test/controllers' - empty_directory_with_keep_file 'test/mailers' - empty_directory_with_keep_file 'test/models' - empty_directory_with_keep_file 'test/helpers' - empty_directory_with_keep_file 'test/integration' - - template 'test/test_helper.rb' + empty_directory_with_keep_file "test/fixtures" + empty_directory_with_keep_file "test/fixtures/files" + empty_directory_with_keep_file "test/controllers" + empty_directory_with_keep_file "test/mailers" + empty_directory_with_keep_file "test/models" + empty_directory_with_keep_file "test/helpers" + empty_directory_with_keep_file "test/integration" + + template "test/test_helper.rb" end def tmp @@ -157,12 +157,12 @@ module Rails def vendor_javascripts unless options[:skip_javascript] - empty_directory_with_keep_file 'vendor/assets/javascripts' + empty_directory_with_keep_file "vendor/assets/javascripts" end end def vendor_stylesheets - empty_directory_with_keep_file 'vendor/assets/stylesheets' + empty_directory_with_keep_file "vendor/assets/stylesheets" end end @@ -226,6 +226,11 @@ module Rails end remove_task :update_config_files + def display_upgrade_guide_info + say "\nAfter this, check Rails upgrade guide at http://guides.rubyonrails.org/upgrading_ruby_on_rails.html for more details about upgrading your app." + end + remove_task :display_upgrade_guide_info + def create_boot_file template "config/boot.rb" end @@ -236,6 +241,7 @@ module Rails end def create_db_files + return if options[:skip_active_record] build(:db) end @@ -265,81 +271,82 @@ module Rails def delete_app_assets_if_api_option if options[:api] - remove_dir 'app/assets' - remove_dir 'lib/assets' - remove_dir 'tmp/cache/assets' - remove_dir 'vendor/assets' + remove_dir "app/assets" + remove_dir "lib/assets" + remove_dir "tmp/cache/assets" + remove_dir "vendor/assets" end end def delete_app_helpers_if_api_option if options[:api] - remove_dir 'app/helpers' - remove_dir 'test/helpers' + remove_dir "app/helpers" + remove_dir "test/helpers" end end def delete_application_layout_file_if_api_option if options[:api] - remove_file 'app/views/layouts/application.html.erb' + remove_file "app/views/layouts/application.html.erb" end end def delete_public_files_if_api_option if options[:api] - remove_file 'public/404.html' - remove_file 'public/422.html' - remove_file 'public/500.html' - remove_file 'public/apple-touch-icon-precomposed.png' - remove_file 'public/apple-touch-icon.png' - remove_file 'public/favicon.ico' + remove_file "public/404.html" + remove_file "public/422.html" + remove_file "public/500.html" + remove_file "public/apple-touch-icon-precomposed.png" + remove_file "public/apple-touch-icon.png" + remove_file "public/favicon.ico" end end def delete_js_folder_skipping_javascript if options[:skip_javascript] - remove_dir 'app/assets/javascripts' + remove_dir "app/assets/javascripts" end end def delete_assets_initializer_skipping_sprockets if options[:skip_sprockets] - remove_file 'config/initializers/assets.rb' + remove_file "config/initializers/assets.rb" end end def delete_application_record_skipping_active_record if options[:skip_active_record] - remove_file 'app/models/application_record.rb' + remove_file "app/models/application_record.rb" end end def delete_action_mailer_files_skipping_action_mailer if options[:skip_action_mailer] - remove_file 'app/mailers/application_mailer.rb' - remove_file 'app/views/layouts/mailer.html.erb' - remove_file 'app/views/layouts/mailer.text.erb' + remove_file "app/mailers/application_mailer.rb" + remove_file "app/views/layouts/mailer.html.erb" + remove_file "app/views/layouts/mailer.text.erb" + remove_dir "app/mailers" + remove_dir "test/mailers" end end def delete_action_cable_files_skipping_action_cable if options[:skip_action_cable] - remove_file 'config/cable.yml' - remove_file 'app/assets/javascripts/cable.js' - remove_dir 'app/channels' + remove_file "config/cable.yml" + remove_file "app/assets/javascripts/cable.js" + remove_dir "app/channels" end end def delete_non_api_initializers_if_api_option if options[:api] - remove_file 'config/initializers/session_store.rb' - remove_file 'config/initializers/cookies_serializer.rb' + remove_file "config/initializers/cookies_serializer.rb" end end def delete_api_initializers unless options[:api] - remove_file 'config/initializers/cors.rb' + remove_file "config/initializers/cors.rb" end end @@ -357,7 +364,7 @@ module Rails protected def self.banner - "rails new #{self.arguments.map(&:usage).join(' ')} [options]" + "rails new #{arguments.map(&:usage).join(' ')} [options]" end # Define file as an alias to create_file for backwards compatibility. @@ -366,7 +373,7 @@ module Rails end def app_name - @app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', '').tr(". ", "_") + @app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', "").tr(". ", "_") end def defined_app_name @@ -381,7 +388,7 @@ module Rails alias :defined_app_const_base? :defined_app_const_base def app_const_base - @app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, '_').squeeze('_').camelize + @app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, "_").squeeze("_").camelize end alias :camelized :app_const_base @@ -416,7 +423,7 @@ module Rails "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4 "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5 "/opt/lampp/var/mysql/mysql.sock" # xampp for linux - ].find { |f| File.exist?(f) } unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + ].find { |f| File.exist?(f) } unless RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ end def get_builder_class @@ -444,14 +451,14 @@ module Rails end def self.default_rc_file - File.expand_path('~/.railsrc') + File.expand_path("~/.railsrc") end private def handle_version_request!(argument) - if ['--version', '-v'].include?(argument) - require 'rails/version' + if ["--version", "-v"].include?(argument) + require "rails/version" puts "Rails #{Rails::VERSION::STRING}" exit(0) end @@ -461,20 +468,20 @@ module Rails if argument == "new" yield else - ['--help'] + argv.drop(1) + ["--help"] + argv.drop(1) end end def handle_rails_rc!(argv) - if argv.find { |arg| arg == '--no-rc' } - argv.reject { |arg| arg == '--no-rc' } + if argv.find { |arg| arg == "--no-rc" } + argv.reject { |arg| arg == "--no-rc" } else railsrc(argv) { |rc_argv, rc| insert_railsrc_into_argv!(rc_argv, rc) } end end def railsrc(argv) - if (customrc = argv.index{ |x| x.include?("--rc=") }) + if (customrc = argv.index { |x| x.include?("--rc=") }) fname = File.expand_path(argv[customrc].gsub(/--rc=/, "")) yield(argv.take(customrc) + argv.drop(customrc + 1), fname) else diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 86143ca1f1..422217286c 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -35,11 +35,11 @@ group :development do <%- if options.dev? || options.edge? -%> gem 'web-console', github: 'rails/web-console' <%- else -%> - gem 'web-console' + gem 'web-console', '>= 3.3.0' <%- end -%> <%- end -%> <% if depend_on_listen? -%> - gem 'listen', '~> 3.0.5' + gem 'listen', '>= 3.0.5', '< 3.2' <% end -%> <% if spring_install? -%> # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js index 71ee1e66de..739aa5f022 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js @@ -1,5 +1,5 @@ // Action Cable provides the framework to deal with WebSockets in Rails. -// You can generate new channels where WebSocket features live using the rails generate channel command. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. // //= require action_cable //= require_self diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml index bd5c0b10f6..145cfb7f74 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml @@ -17,7 +17,7 @@ default: &default adapter: postgresql encoding: unicode - # For details on connection pooling, see rails configuration guide + # For details on connection pooling, see Rails configuration guide # http://guides.rubyonrails.org/configuring.html#database-pooling pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index f3ccf95045..511b4a82eb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -18,7 +18,7 @@ Rails.application.configure do config.cache_store = :memory_store config.public_file_server.headers = { - 'Cache-Control' => 'public, max-age=172800' + 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}" } else config.action_controller.perform_caching = false diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 363af05459..7deab5dbb1 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -19,8 +19,12 @@ Rails.application.configure do config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? <%- unless options.skip_sprockets? -%> + <%- if options.skip_javascript? -%> + # Compress CSS. + <%- else -%> # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier + <%- end -%> # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 42fee3b036..56416b3075 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -15,7 +15,7 @@ Rails.application.configure do # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - 'Cache-Control' => 'public, max-age=3600' + 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" } # Show full error reports and disable caching. diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt index 01ef3e6630..2318cf59ff 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt @@ -7,5 +7,6 @@ Rails.application.config.assets.version = '1.0' # Rails.application.config.assets.paths << Emoji.images_path # Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. -# Rails.application.config.assets.precompile += %w( search.js ) +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt index 991963b65e..3ad3eba98a 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt @@ -6,7 +6,7 @@ # Once upgraded flip defaults one by one to migrate to the new default. # <%- end -%> -# Read the Rails 5.0 release notes for more info on each option. +# Read the Guide for Upgrading Ruby on Rails for more info on each option. <%- unless options[:api] -%> # Enable per-form CSRF tokens. Previous versions had false. @@ -32,3 +32,9 @@ ActiveSupport.halt_callback_chains_on_return_false = <%= options[:update] ? true # Configure SSL options to enable HSTS with subdomains. Previous versions had false. Rails.application.config.ssl_options = { hsts: { subdomains: true } } <%- end -%> +<%- unless options[:skip_sprockets] -%> + +# Unknown asset fallback will return the path passed in when the given +# asset is not present in the asset pipeline. +Rails.application.config.assets.unknown_asset_fallback = <%= options[:update] ? true : false %> +<%- end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt deleted file mode 100644 index 2bb9b82c61..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +++ /dev/null @@ -1,3 +0,0 @@ -# Be sure to restart your server when you modify this file. - -Rails.application.config.session_store :cookie_store, key: <%= "'_#{app_name}_session'" %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb b/railties/lib/rails/generators/rails/app/templates/config/puma.rb index c7f311f811..7ee948002e 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb @@ -4,7 +4,7 @@ # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum, this matches the default thread size of Active Record. # -threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads threads_count, threads_count # Specifies the `port` that Puma will listen on to receive requests, default is 3000. @@ -32,6 +32,14 @@ environment ENV.fetch("RAILS_ENV") { "development" } # # preload_app! +# If you are preloading your application and using Active Record, it's +# recommended that you close any connections to the database before workers +# are forked to prevent connection leakage. +# +# before_fork do +# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) +# end + # The code in the `on_worker_boot` will be called if you are using # clustered mode by specifying a number of `workers`. After each worker # process is booted this block will be run, if you are using `preload_app!` @@ -42,6 +50,7 @@ environment ENV.fetch("RAILS_ENV") { "development" } # on_worker_boot do # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) # end +# # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart diff --git a/railties/lib/rails/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt index 3c9c7c01f3..37b576a4a0 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/robots.txt +++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt @@ -1,5 +1 @@ # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file -# -# To ban all spiders from the entire site uncomment the next two lines: -# User-agent: * -# Disallow: / diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 87b8fe3516..2f92168eef 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -1,4 +1,3 @@ -ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' diff --git a/railties/lib/rails/generators/rails/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb index 6f4b86e708..265dada2ca 100644 --- a/railties/lib/rails/generators/rails/assets/assets_generator.rb +++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb @@ -9,17 +9,17 @@ module Rails protected - def asset_name - file_name - end + def asset_name + file_name + end - hook_for :javascript_engine do |javascript_engine| - invoke javascript_engine, [name] if options[:javascripts] - end + hook_for :javascript_engine do |javascript_engine| + invoke javascript_engine, [name] if options[:javascripts] + end - hook_for :stylesheet_engine do |stylesheet_engine| - invoke stylesheet_engine, [name] if options[:stylesheets] - end + hook_for :stylesheet_engine do |stylesheet_engine| + invoke stylesheet_engine, [name] if options[:stylesheets] + end end end end diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index 6c583e5811..213de37cce 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -7,7 +7,7 @@ module Rails check_class_collision suffix: "Controller" def create_controller_files - template 'controller.rb', File.join('app/controllers', class_path, "#{file_name}_controller.rb") + template "controller.rb", File.join("app/controllers", class_path, "#{file_name}_controller.rb") end def add_routes diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb index 15d88f06ac..8040ec5e7b 100644 --- a/railties/lib/rails/generators/rails/generator/generator_generator.rb +++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb @@ -7,7 +7,7 @@ module Rails desc: "Namespace generator under lib/generators/name" def create_generator_files - directory '.', generator_dir + directory ".", generator_dir end hook_for :test_framework @@ -21,7 +21,6 @@ module Rails File.join("lib", "generators", regular_class_path) end end - end end end diff --git a/railties/lib/rails/generators/rails/helper/helper_generator.rb b/railties/lib/rails/generators/rails/helper/helper_generator.rb index 5ff38e4111..e48b1b6fb3 100644 --- a/railties/lib/rails/generators/rails/helper/helper_generator.rb +++ b/railties/lib/rails/generators/rails/helper/helper_generator.rb @@ -4,7 +4,7 @@ module Rails check_class_collision suffix: "Helper" def create_helper_files - template 'helper.rb', File.join('app/helpers', class_path, "#{file_name}_helper.rb") + template "helper.rb", File.join("app/helpers", class_path, "#{file_name}_helper.rb") end hook_for :test_framework diff --git a/railties/lib/rails/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb index ec78fd855d..c32a8a079a 100644 --- a/railties/lib/rails/generators/rails/model/model_generator.rb +++ b/railties/lib/rails/generators/rails/model/model_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/model_helpers' +require "rails/generators/model_helpers" module Rails module Generators diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index 56efd35a95..9ffeab4fbe 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -1,6 +1,6 @@ -require 'active_support/core_ext/hash/slice' +require "active_support/core_ext/hash/slice" require "rails/generators/rails/app/app_generator" -require 'date' +require "date" module Rails # The plugin builder allows you to override elements of the plugin @@ -18,20 +18,20 @@ module Rails def app if mountable? if api? - directory 'app', exclude_pattern: %r{app/(views|helpers)} + directory "app", exclude_pattern: %r{app/(views|helpers)} else - directory 'app' + directory "app" empty_directory_with_keep_file "app/assets/images/#{namespaced_name}" end elsif full? - empty_directory_with_keep_file 'app/models' - empty_directory_with_keep_file 'app/controllers' - empty_directory_with_keep_file 'app/mailers' + empty_directory_with_keep_file "app/models" + empty_directory_with_keep_file "app/controllers" + empty_directory_with_keep_file "app/mailers" unless api? empty_directory_with_keep_file "app/assets/images/#{namespaced_name}" - empty_directory_with_keep_file 'app/helpers' - empty_directory_with_keep_file 'app/views' + empty_directory_with_keep_file "app/helpers" + empty_directory_with_keep_file "app/views" end end end @@ -149,7 +149,7 @@ task default: :test end def bin(force = false) - bin_file = engine? ? 'bin/rails.tt' : 'bin/test.tt' + bin_file = engine? ? "bin/rails.tt" : "bin/test.tt" template bin_file, force: force do |content| "#{shebang}\n" + content end @@ -258,7 +258,7 @@ task default: :test build(:leftovers) end - public_task :apply_rails_template, :run_bundle + public_task :apply_rails_template def run_after_bundle_callbacks @after_bundle_callbacks.each do |callback| @@ -283,7 +283,7 @@ task default: :test end def namespaced_name - @namespaced_name ||= name.gsub('-', '/') + @namespaced_name ||= name.gsub("-", "/") end protected @@ -320,7 +320,7 @@ task default: :test end def with_dummy_app? - options[:skip_test].blank? || options[:dummy_path] != 'test/dummy' + options[:skip_test].blank? || options[:dummy_path] != "test/dummy" end def api? @@ -328,7 +328,7 @@ task default: :test end def self.banner - "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" + "rails plugin new #{arguments.map(&:usage).join(' ')} [options]" end def original_name @@ -340,7 +340,7 @@ task default: :test end def wrap_in_modules(unwrapped_code) - unwrapped_code = "#{unwrapped_code}".strip.gsub(/\s$\n/, '') + unwrapped_code = "#{unwrapped_code}".strip.gsub(/\s$\n/, "") modules.reverse.inject(unwrapped_code) do |content, mod| str = "module #{mod}\n" str += content.lines.map { |line| " #{line}" }.join @@ -357,7 +357,7 @@ task default: :test end def camelized - @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize + @camelized ||= name.gsub(/\W/, "_").squeeze("_").camelize end def author @@ -442,7 +442,7 @@ end def relative_path return unless inside_application? - app_path.sub(/^#{rails_app_path}\//, '') + app_path.sub(/^#{rails_app_path}\//, "") end end end diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt index 62b94618fd..c0fbb84a93 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt @@ -5,4 +5,6 @@ require 'rails/test_unit/minitest_plugin' Rails::TestUnitReporter.executable = 'bin/test' -exit Minitest.run(ARGV) +Minitest.run_via[:rails] = true + +require "active_support/testing/autorun" diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb index a5eebcb19f..e84e403018 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb @@ -1,6 +1,3 @@ -# Configure Rails Environment -ENV["RAILS_ENV"] = "test" - require File.expand_path("../../<%= options[:dummy_path] -%>/config/environment.rb", __FILE__) <% unless options[:skip_active_record] -%> ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../<%= options[:dummy_path] -%>/db/migrate", __FILE__)] diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index 3acf21df13..5ac5164af0 100644 --- a/railties/lib/rails/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -1,5 +1,5 @@ -require 'rails/generators/resource_helpers' -require 'rails/generators/rails/model/model_generator' +require "rails/generators/resource_helpers" +require "rails/generators/rails/model/model_generator" module Rails module Generators diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb index 17c32bfdb3..ed6bf7f7d7 100644 --- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/rails/resource/resource_generator' +require "rails/generators/rails/resource/resource_generator" module Rails module Generators diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb index d0b8cad896..e4f3161ffd 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/resource_helpers' +require "rails/generators/resource_helpers" module Rails module Generators @@ -17,7 +17,7 @@ module Rails def create_controller_files template_file = options.api? ? "api_controller.rb" : "controller.rb" - template template_file, File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") + template template_file, File.join("app/controllers", controller_class_path, "#{controller_file_name}_controller.rb") end hook_for :template_engine, :test_framework, as: :scaffold diff --git a/railties/lib/rails/generators/rails/task/task_generator.rb b/railties/lib/rails/generators/rails/task/task_generator.rb index 754824ca0c..bb96bdf0dd 100644 --- a/railties/lib/rails/generators/rails/task/task_generator.rb +++ b/railties/lib/rails/generators/rails/task/task_generator.rb @@ -4,9 +4,8 @@ module Rails argument :actions, type: :array, default: [], banner: "action action" def create_task_files - template 'task.rb', File.join('lib/tasks', "#{file_name}.rake") + template "task.rb", File.join("lib/tasks", "#{file_name}.rake") end - end end end diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 9c2037783e..6d80003271 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -1,12 +1,11 @@ -require 'rails/generators/active_model' -require 'rails/generators/model_helpers' +require "rails/generators/active_model" +require "rails/generators/model_helpers" module Rails module Generators # Deal with controller names on scaffold and add some helpers to deal with # ActiveModel. module ResourceHelpers # :nodoc: - def self.included(base) #:nodoc: base.include(Rails::Generators::ModelHelpers) base.class_option :model_name, type: :string, desc: "ModelName to be used" @@ -18,7 +17,7 @@ module Rails controller_name = name if options[:model_name] self.name = options[:model_name] - assign_names!(self.name) + assign_names!(name) end assign_controller_names!(controller_name.pluralize) @@ -38,21 +37,21 @@ module Rails def assign_controller_names!(name) @controller_name = name - @controller_class_path = name.include?('/') ? name.split('/') : name.split('::') + @controller_class_path = name.include?("/") ? name.split("/") : name.split("::") @controller_class_path.map!(&:underscore) @controller_file_name = @controller_class_path.pop end def controller_file_path - @controller_file_path ||= (controller_class_path + [controller_file_name]).join('/') + @controller_file_path ||= (controller_class_path + [controller_file_name]).join("/") end def controller_class_name - (controller_class_path + [controller_file_name]).map!(&:camelize).join('::') + (controller_class_path + [controller_file_name]).map!(&:camelize).join("::") end def controller_i18n_scope - @controller_i18n_scope ||= controller_file_path.tr('/', '.') + @controller_i18n_scope ||= controller_file_path.tr("/", ".") end # Loads the ORM::Generators::ActiveModel class. This class is responsible diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 58592b4f8e..3eec929aeb 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -1,8 +1,8 @@ -require 'rails/generators' -require 'rails/generators/testing/behaviour' -require 'rails/generators/testing/setup_and_teardown' -require 'rails/generators/testing/assertions' -require 'fileutils' +require "rails/generators" +require "rails/generators/testing/behaviour" +require "rails/generators/testing/setup_and_teardown" +require "rails/generators/testing/assertions" +require "fileutils" module Rails module Generators @@ -30,7 +30,6 @@ module Rails include Rails::Generators::Testing::SetupAndTeardown include Rails::Generators::Testing::Assertions include FileUtils - end end end diff --git a/railties/lib/rails/generators/test_unit.rb b/railties/lib/rails/generators/test_unit.rb index fe45c9e15d..722efcf492 100644 --- a/railties/lib/rails/generators/test_unit.rb +++ b/railties/lib/rails/generators/test_unit.rb @@ -1,4 +1,4 @@ -require 'rails/generators/named_base' +require "rails/generators/named_base" module TestUnit # :nodoc: module Generators # :nodoc: diff --git a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb index b5aa581769..ac528d94f1 100644 --- a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb +++ b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -7,8 +7,8 @@ module TestUnit # :nodoc: check_class_collision suffix: "ControllerTest" def create_test_files - template 'functional_test.rb', - File.join('test/controllers', class_path, "#{file_name}_controller_test.rb") + template "functional_test.rb", + File.join("test/controllers", class_path, "#{file_name}_controller_test.rb") end end end diff --git a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb index d7307398ce..59f8d40343 100644 --- a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb +++ b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -9,7 +9,7 @@ module TestUnit # :nodoc: desc: "Namespace generator under lib/generators/name" def create_generator_files - template 'generator_test.rb', File.join('test/lib/generators', class_path, "#{file_name}_generator_test.rb") + template "generator_test.rb", File.join("test/lib/generators", class_path, "#{file_name}_generator_test.rb") end protected diff --git a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb index bde4e88915..6674a15fa3 100644 --- a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb +++ b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: diff --git a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb index e004835bd5..9d065c1297 100644 --- a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb +++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -6,7 +6,7 @@ module TestUnit # :nodoc: check_class_collision suffix: "Test" def create_test_files - template 'integration_test.rb', File.join('test/integration', class_path, "#{file_name}_test.rb") + template "integration_test.rb", File.join("test/integration", class_path, "#{file_name}_test.rb") end end end diff --git a/railties/lib/rails/generators/test_unit/job/job_generator.rb b/railties/lib/rails/generators/test_unit/job/job_generator.rb index 566b61ca66..6975252b99 100644 --- a/railties/lib/rails/generators/test_unit/job/job_generator.rb +++ b/railties/lib/rails/generators/test_unit/job/job_generator.rb @@ -1,12 +1,12 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: class JobGenerator < Base # :nodoc: - check_class_collision suffix: 'JobTest' + check_class_collision suffix: "JobTest" def create_test_file - template 'unit_test.rb.erb', File.join('test/jobs', class_path, "#{file_name}_job_test.rb") + template "unit_test.rb.erb", File.join("test/jobs", class_path, "#{file_name}_job_test.rb") end end end diff --git a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb index 76a0b79654..806279788e 100644 --- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -10,16 +10,16 @@ module TestUnit # :nodoc: end def create_test_files - template "functional_test.rb", File.join('test/mailers', class_path, "#{file_name}_mailer_test.rb") + template "functional_test.rb", File.join("test/mailers", class_path, "#{file_name}_mailer_test.rb") end def create_preview_files - template "preview.rb", File.join('test/mailers/previews', class_path, "#{file_name}_mailer_preview.rb") + template "preview.rb", File.join("test/mailers/previews", class_path, "#{file_name}_mailer_preview.rb") end protected def file_name - @_file_name ||= super.gsub(/_mailer/i, '') + @_file_name ||= super.gsub(/_mailer/i, "") end end end diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb index 086588750e..99495d5247 100644 --- a/railties/lib/rails/generators/test_unit/model/model_generator.rb +++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb @@ -1,9 +1,8 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: class ModelGenerator < Base # :nodoc: - RESERVED_YAML_KEYWORDS = %w(y yes n no true false on off null) argument :attributes, type: :array, default: [], banner: "field:type field:type" @@ -12,14 +11,14 @@ module TestUnit # :nodoc: check_class_collision suffix: "Test" def create_test_file - template 'unit_test.rb', File.join('test/models', class_path, "#{file_name}_test.rb") + template "unit_test.rb", File.join("test/models", class_path, "#{file_name}_test.rb") end hook_for :fixture_replacement def create_fixture_file if options[:fixture] && options[:fixture_replacement].nil? - template 'fixtures.yml', File.join('test/fixtures', class_path, "#{fixture_file_name}.yml") + template "fixtures.yml", File.join("test/fixtures", class_path, "#{fixture_file_name}.yml") end end diff --git a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb index b5d4f38444..f1c9b6da5b 100644 --- a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/test_unit' +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -6,7 +6,7 @@ module TestUnit # :nodoc: check_class_collision suffix: "Test" def create_test_files - directory '.', 'test' + directory ".", "test" end end end diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index 0171da7cc7..8840a86d0d 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -1,5 +1,5 @@ -require 'rails/generators/test_unit' -require 'rails/generators/resource_helpers' +require "rails/generators/test_unit" +require "rails/generators/resource_helpers" module TestUnit # :nodoc: module Generators # :nodoc: @@ -39,7 +39,7 @@ module TestUnit # :nodoc: else "#{name}: @#{singular_table_name}.#{name}" end - end.sort.join(', ') + end.sort.join(", ") end end end diff --git a/railties/lib/rails/generators/testing/assertions.rb b/railties/lib/rails/generators/testing/assertions.rb index 76758df86d..1cabf4e28c 100644 --- a/railties/lib/rails/generators/testing/assertions.rb +++ b/railties/lib/rails/generators/testing/assertions.rb @@ -29,10 +29,10 @@ module Rails contents.each do |content| case content - when String - assert_equal content, read - when Regexp - assert_match content, read + when String + assert_equal content, read + when Regexp + assert_match content, read end end end diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb index 94b5e52224..a1e5a233b9 100644 --- a/railties/lib/rails/generators/testing/behaviour.rb +++ b/railties/lib/rails/generators/testing/behaviour.rb @@ -1,10 +1,10 @@ -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/testing/stream' -require 'active_support/concern' -require 'rails/generators' +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/kernel/reporting" +require "active_support/testing/stream" +require "active_support/concern" +require "rails/generators" module Rails module Generators @@ -62,24 +62,24 @@ module Rails # # You can provide a configuration hash as second argument. This method returns the output # printed by the generator. - def run_generator(args=self.default_arguments, config={}) + def run_generator(args = default_arguments, config = {}) capture(:stdout) do - args += ['--skip-bundle'] unless args.include? '--dev' - self.generator_class.start(args, config.reverse_merge(destination_root: destination_root)) + args += ["--skip-bundle"] unless args.include? "--dev" + generator_class.start(args, config.reverse_merge(destination_root: destination_root)) end end # Instantiate the generator. - def generator(args=self.default_arguments, options={}, config={}) - @generator ||= self.generator_class.new(args, options, config.reverse_merge(destination_root: destination_root)) + def generator(args = default_arguments, options = {}, config = {}) + @generator ||= generator_class.new(args, options, config.reverse_merge(destination_root: destination_root)) end # Create a Rails::Generators::GeneratedAttribute by supplying the # attribute type and, optionally, the attribute name: # # create_generated_attribute(:string, 'name') - def create_generated_attribute(attribute_type, name = 'test', index = nil) - Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':')) + def create_generated_attribute(attribute_type, name = "test", index = nil) + Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(":")) end protected @@ -100,10 +100,9 @@ module Rails def migration_file_name(relative) # :nodoc: absolute = File.expand_path(relative, destination_root) - dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '') + dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, "") Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first end - end end end diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index 5909446b66..5d4acd6f6b 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -38,64 +38,64 @@ module Rails alias inspect to_s def to_html - '<table>'.tap do |table| + "<table>".tap do |table| properties.each do |(name, value)| table << %(<tr><td class="name">#{CGI.escapeHTML(name.to_s)}</td>) formatted_value = if value.kind_of?(Array) - "<ul>" + value.map { |v| "<li>#{CGI.escapeHTML(v.to_s)}</li>" }.join + "</ul>" - else - CGI.escapeHTML(value.to_s) - end + "<ul>" + value.map { |v| "<li>#{CGI.escapeHTML(v.to_s)}</li>" }.join + "</ul>" + else + CGI.escapeHTML(value.to_s) + end table << %(<td class="value">#{formatted_value}</td></tr>) end - table << '</table>' + table << "</table>" end end end # The Rails version. - property 'Rails version' do + property "Rails version" do Rails.version.to_s end # The Ruby version and platform, e.g. "2.0.0-p247 (x86_64-darwin12.4.0)". - property 'Ruby version' do + property "Ruby version" do "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})" end # The RubyGems version, if it's installed. - property 'RubyGems version' do + property "RubyGems version" do Gem::RubyGemsVersion end - property 'Rack version' do + property "Rack version" do ::Rack.release end - property 'JavaScript Runtime' do + property "JavaScript Runtime" do ExecJS.runtime.name end - property 'Middleware' do + property "Middleware" do Rails.configuration.middleware.map(&:inspect) end # The application's location on the filesystem. - property 'Application root' do + property "Application root" do File.expand_path(Rails.root) end # The current Rails environment (development, test, or production). - property 'Environment' do + property "Environment" do Rails.env end # The name of the database adapter for the current environment. - property 'Database adapter' do - ActiveRecord::Base.configurations[Rails.env]['adapter'] + property "Database adapter" do + ActiveRecord::Base.configurations[Rails.env]["adapter"] end - property 'Database schema version' do + property "Database schema version" do ActiveRecord::Migrator.current_version rescue nil end end diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index 778105c5f7..8b553aea79 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -1,9 +1,9 @@ -require 'rails/application_controller' -require 'action_dispatch/routing/inspector' +require "rails/application_controller" +require "action_dispatch/routing/inspector" class Rails::InfoController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH - layout -> { request.xhr? ? false : 'application' } + layout -> { request.xhr? ? false : "application" } before_action :require_local! @@ -13,7 +13,7 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc: def properties @info = Rails::Info.to_html - @page_title = 'Properties' + @page_title = "Properties" end def routes @@ -21,24 +21,24 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc: path = URI.parser.escape path normalized_path = with_leading_slash path render json: { - exact: match_route {|it| it.match normalized_path }, - fuzzy: match_route {|it| it.spec.to_s.match path } + exact: match_route { |it| it.match normalized_path }, + fuzzy: match_route { |it| it.spec.to_s.match path } } else @routes_inspector = ActionDispatch::Routing::RoutesInspector.new(_routes.routes) - @page_title = 'Routes' + @page_title = "Routes" end end private - def match_route - _routes.routes.select {|route| - yield route.path - }.map {|route| route.path.spec.to_s } - end + def match_route + _routes.routes.select { |route| + yield route.path + }.map { |route| route.path.spec.to_s } + end - def with_leading_slash(path) - ('/' + path).squeeze('/') - end + def with_leading_slash(path) + ("/" + path).squeeze("/") + end end diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 1a0b6d1e1a..81b1cd8110 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -1,4 +1,4 @@ -require 'tsort' +require "tsort" module Rails module Initializable @@ -34,6 +34,10 @@ module Rails return self if @context Initializer.new(@name, context, @options, &block) end + + def context_class + @context.class + end end class Collection < Array diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index 6143cf2dd9..95de998208 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -1,4 +1,4 @@ -require 'rails/application_controller' +require "rails/application_controller" class Rails::MailersController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH @@ -14,7 +14,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: def preview if params[:path] == @preview.preview_name @page_title = "Mailer Previews for #{@preview.preview_name}" - render action: 'mailer' + render action: "mailer" else @email_action = File.basename(params[:path]) @@ -32,7 +32,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: end else @part = find_preferred_part(request.format, Mime[:html], Mime[:text]) - render action: 'email', layout: false, formats: %w[html] + render action: "email", layout: false, formats: %w[html] end else raise AbstractController::ActionNotFound, "Email '#{@email_action}' not found in #{@preview.name}" @@ -47,8 +47,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: def find_preview candidates = [] - params[:path].to_s.scan(%r{/|$}){ candidates << $` } - preview = candidates.detect{ |candidate| ActionMailer::Preview.exists?(candidate) } + params[:path].to_s.scan(%r{/|$}) { candidates << $` } + preview = candidates.detect { |candidate| ActionMailer::Preview.exists?(candidate) } if preview @preview = ActionMailer::Preview.find(preview) @@ -64,7 +64,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: end end - if formats.any?{ |f| @email.mime_type == f } + if formats.any? { |f| @email.mime_type == f } @email end end diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index e47616a87f..1c1810dde6 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -30,7 +30,7 @@ module Rails # root["config/routes"].inspect # => ["config/routes.rb"] # # The +add+ method accepts the following options as arguments: - # eager_load, autoload, autoload_once and glob. + # eager_load, autoload, autoload_once, and glob. # # Finally, the +Path+ object also provides a few helpers: # @@ -180,7 +180,7 @@ module Rails end def extensions # :nodoc: - $1.split(',') if @glob =~ /\{([\S]+)\}/ + $1.split(",") if @glob =~ /\{([\S]+)\}/ end # Expands all paths against the root and return all unique values. diff --git a/railties/lib/rails/rack/debugger.rb b/railties/lib/rails/rack/debugger.rb index 1fde3db070..dccfa3e9bb 100644 --- a/railties/lib/rails/rack/debugger.rb +++ b/railties/lib/rails/rack/debugger.rb @@ -1,3 +1,3 @@ -require 'active_support/deprecation' +require "active_support/deprecation" ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.") diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index b63d3a58d2..e3fee75603 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -1,8 +1,8 @@ -require 'active_support/core_ext/time/conversions' -require 'active_support/core_ext/object/blank' -require 'active_support/log_subscriber' -require 'action_dispatch/http/request' -require 'rack/body_proxy' +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/object/blank" +require "active_support/log_subscriber" +require "action_dispatch/http/request" +require "rack/body_proxy" module Rails module Rack @@ -31,7 +31,7 @@ module Rails def call_app(request, env) instrumenter = ActiveSupport::Notifications.instrumenter - instrumenter.start 'request.action_dispatch', request: request + instrumenter.start "request.action_dispatch", request: request logger.info { started_request_message(request) } resp = @app.call(env) resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) } @@ -67,14 +67,14 @@ module Rails private - def finish(request) - instrumenter = ActiveSupport::Notifications.instrumenter - instrumenter.finish 'request.action_dispatch', request: request - end + def finish(request) + instrumenter = ActiveSupport::Notifications.instrumenter + instrumenter.finish "request.action_dispatch", request: request + end - def logger - Rails.logger - end + def logger + Rails.logger + end end end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 492c519222..eb3f5d4ee9 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -1,7 +1,7 @@ -require 'rails/initializable' -require 'active_support/inflector' -require 'active_support/core_ext/module/introspection' -require 'active_support/core_ext/module/delegation' +require "rails/initializable" +require "active_support/inflector" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/delegation" module Rails # <tt>Rails::Railtie</tt> is the core of the Rails framework and provides @@ -111,7 +111,7 @@ module Rails # # Be sure to look at the documentation of those specific classes for more information. class Railtie - autoload :Configuration, 'rails/railtie/configuration' + autoload :Configuration, "rails/railtie/configuration" include Initializable @@ -222,31 +222,31 @@ module Rails protected - def run_console_blocks(app) #:nodoc: - each_registered_block(:console) { |block| block.call(app) } - end + def run_console_blocks(app) #:nodoc: + each_registered_block(:console) { |block| block.call(app) } + end - def run_generators_blocks(app) #:nodoc: - each_registered_block(:generators) { |block| block.call(app) } - end + def run_generators_blocks(app) #:nodoc: + each_registered_block(:generators) { |block| block.call(app) } + end - def run_runner_blocks(app) #:nodoc: - each_registered_block(:runner) { |block| block.call(app) } - end + def run_runner_blocks(app) #:nodoc: + each_registered_block(:runner) { |block| block.call(app) } + end - def run_tasks_blocks(app) #:nodoc: - extend Rake::DSL - each_registered_block(:rake_tasks) { |block| instance_exec(app, &block) } - end + def run_tasks_blocks(app) #:nodoc: + extend Rake::DSL + each_registered_block(:rake_tasks) { |block| instance_exec(app, &block) } + end private - def each_registered_block(type, &block) - klass = self.class - while klass.respond_to?(type) - klass.public_send(type).each(&block) - klass = klass.superclass + def each_registered_block(type, &block) + klass = self.class + while klass.respond_to?(type) + klass.public_send(type).each(&block) + klass = klass.superclass + end end - end end end diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb index 1572af0b2a..39f1f87575 100644 --- a/railties/lib/rails/railtie/configurable.rb +++ b/railties/lib/rails/railtie/configurable.rb @@ -1,4 +1,4 @@ -require 'active_support/concern' +require "active_support/concern" module Rails class Railtie @@ -9,7 +9,7 @@ module Rails delegate :config, to: :instance def inherited(base) - raise "You cannot inherit from a #{self.superclass.name} child" + raise "You cannot inherit from a #{superclass.name} child" end def instance @@ -26,9 +26,9 @@ module Rails protected - def method_missing(*args, &block) - instance.send(*args, &block) - end + def method_missing(*args, &block) + instance.send(*args, &block) + end end end end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index eb3b2d8ef4..aecc81c491 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -1,4 +1,4 @@ -require 'rails/configuration' +require "rails/configuration" module Rails class Railtie diff --git a/railties/lib/rails/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb index 67a19d8a94..b212835df7 100644 --- a/railties/lib/rails/ruby_version_check.rb +++ b/railties/lib/rails/ruby_version_check.rb @@ -1,4 +1,4 @@ -if RUBY_VERSION < '2.2.2' && RUBY_ENGINE == 'ruby' +if RUBY_VERSION < "2.2.2" && RUBY_ENGINE == "ruby" desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" abort <<-end_message diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 8dd87b6cc5..f0df76d3f3 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -1,9 +1,9 @@ # Implements the logic behind the rake tasks for annotations like # -# rake notes -# rake notes:optimize +# rails notes +# rails notes:optimize # -# and friends. See <tt>rake -T notes</tt> and <tt>railties/lib/rails/tasks/annotations.rake</tt>. +# and friends. See <tt>rails -T notes</tt> and <tt>railties/lib/rails/tasks/annotations.rake</tt>. # # Annotation objects are triplets <tt>:line</tt>, <tt>:tag</tt>, <tt>:text</tt> that # represent the line where the annotation lives, its tag, and its text. Note @@ -15,7 +15,13 @@ class SourceAnnotationExtractor class Annotation < Struct.new(:line, :tag, :text) def self.directories - @@directories ||= %w(app config db lib test) + (ENV['SOURCE_ANNOTATION_DIRECTORIES'] || '').split(',') + @@directories ||= %w(app config db lib test) + (ENV["SOURCE_ANNOTATION_DIRECTORIES"] || "").split(",") + end + + # Registers additional directories to be included + # SourceAnnotationExtractor::Annotation.register_directories("spec","another") + def self.register_directories(*dirs) + directories.push(*dirs) end def self.extensions diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb index d3e33584d7..48675b3845 100644 --- a/railties/lib/rails/tasks.rb +++ b/railties/lib/rails/tasks.rb @@ -1,4 +1,4 @@ -require 'rake' +require "rake" # Load Rails Rakefile extensions %w( @@ -13,7 +13,7 @@ require 'rake' routes tmp ).tap { |arr| - arr << 'statistics' if Rake.application.current_scope.empty? + arr << "statistics" if Rake.application.current_scope.empty? }.each do |task| load "rails/tasks/#{task}.rake" end diff --git a/railties/lib/rails/tasks/annotations.rake b/railties/lib/rails/tasks/annotations.rake index 386ecf44be..9a69eb9934 100644 --- a/railties/lib/rails/tasks/annotations.rake +++ b/railties/lib/rails/tasks/annotations.rake @@ -1,4 +1,4 @@ -require 'rails/source_annotation_extractor' +require "rails/source_annotation_extractor" desc "Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)" task :notes do @@ -15,6 +15,6 @@ namespace :notes do desc "Enumerate a custom annotation, specify with ANNOTATION=CUSTOM" task :custom do - SourceAnnotationExtractor.enumerate ENV['ANNOTATION'] + SourceAnnotationExtractor.enumerate ENV["ANNOTATION"] end -end
\ No newline at end of file +end diff --git a/railties/lib/rails/tasks/dev.rake b/railties/lib/rails/tasks/dev.rake index d2ceaacc0c..334e968123 100644 --- a/railties/lib/rails/tasks/dev.rake +++ b/railties/lib/rails/tasks/dev.rake @@ -1,7 +1,7 @@ -require 'rails/dev_caching' +require "rails/dev_caching" namespace :dev do - desc 'Toggle development mode caching on/off' + desc "Toggle development mode caching on/off" task :cache do Rails::DevCaching.enable_by_file end diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake index e678103f63..c92b42f6c1 100644 --- a/railties/lib/rails/tasks/engine.rake +++ b/railties/lib/rails/tasks/engine.rake @@ -2,7 +2,7 @@ task "load_app" do namespace :app do load APP_RAKEFILE end - task :environment => "app:environment" + task environment: "app:environment" if !defined?(ENGINE_ROOT) || !ENGINE_ROOT ENGINE_ROOT = find_engine_path(APP_RAKEFILE) @@ -26,11 +26,11 @@ namespace :db do desc "Display status of migrations" app_task "migrate:status" - desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)' + desc "Create the database from config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)" app_task "create" app_task "create:all" - desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)' + desc "Drops the database for the current Rails.env (use db:drop:all to drop all databases)" app_task "drop" app_task "drop:all" @@ -65,7 +65,7 @@ def find_engine_path(path) if Rails::Engine.find(path) path else - find_engine_path(File.expand_path('..', path)) + find_engine_path(File.expand_path("..", path)) end end diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index 51d9daaaa9..a2167796eb 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -1,16 +1,16 @@ -require 'active_support/deprecation' +require "active_support/deprecation" namespace :app do desc "Update configs and some other initially generated files (or use just update:configs or update:bin)" - task update: [ "update:configs", "update:bin" ] + task update: [ "update:configs", "update:bin", "update:upgrade_guide_info" ] desc "Applies the template supplied by LOCATION=(/path/to/template) or URL" task template: :environment do template = ENV["LOCATION"] raise "No LOCATION value given. Please set LOCATION either as path to a file or a URL" if template.blank? template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} - require 'rails/generators' - require 'rails/generators/rails/app/app_generator' + require "rails/generators" + require "rails/generators/rails/app/app_generator" generator = Rails::Generators::AppGenerator.new [Rails.root], {}, destination_root: Rails.root generator.apply template, verbose: false end @@ -45,8 +45,8 @@ namespace :app do def self.app_generator @app_generator ||= begin - require 'rails/generators' - require 'rails/generators/rails/app/app_generator' + require "rails/generators" + require "rails/generators/rails/app/app_generator" gen = Rails::Generators::AppGenerator.new ["rails"], { api: !!Rails.application.config.api_only, update: true }, destination_root: Rails.root @@ -67,6 +67,10 @@ namespace :app do task :bin do RailsUpdate.invoke_from_app_generator :create_bin_files end + + task :upgrade_guide_info do + RailsUpdate.invoke_from_app_generator :display_upgrade_guide_info + end end end diff --git a/railties/lib/rails/tasks/initializers.rake b/railties/lib/rails/tasks/initializers.rake index 2968b5cb53..6522f2ae5a 100644 --- a/railties/lib/rails/tasks/initializers.rake +++ b/railties/lib/rails/tasks/initializers.rake @@ -1,6 +1,6 @@ desc "Print out all defined initializers in the order they are invoked by Rails." task initializers: :environment do Rails.application.initializers.tsort_each do |initializer| - puts initializer.name + puts "#{initializer.context_class}.#{initializer.name}" end end diff --git a/railties/lib/rails/tasks/log.rake b/railties/lib/rails/tasks/log.rake index 073f235ec5..c376234fee 100644 --- a/railties/lib/rails/tasks/log.rake +++ b/railties/lib/rails/tasks/log.rake @@ -1,8 +1,8 @@ namespace :log do - - ## + + ## # Truncates all/specified log files - # ENV['LOGS'] + # ENV['LOGS'] # - defaults to standard environment log files i.e. 'development,test,production' # - ENV['LOGS']=all truncates all files i.e. log/*.log # - ENV['LOGS']='test,development' truncates only specified files @@ -14,21 +14,21 @@ namespace :log do end def log_files - if ENV['LOGS'] == 'all' + if ENV["LOGS"] == "all" FileList["log/*.log"] - elsif ENV['LOGS'] - log_files_to_truncate(ENV['LOGS']) + elsif ENV["LOGS"] + log_files_to_truncate(ENV["LOGS"]) else log_files_to_truncate("development,test,production") end end def log_files_to_truncate(envs) - envs.split(',') + envs.split(",") .map { |file| "log/#{file.strip}.log" } .select { |file| File.exist?(file) } end - + def clear_log_file(file) f = File.open(file, "w") f.close diff --git a/railties/lib/rails/tasks/middleware.rake b/railties/lib/rails/tasks/middleware.rake index 31e961b483..fd98be1ea9 100644 --- a/railties/lib/rails/tasks/middleware.rake +++ b/railties/lib/rails/tasks/middleware.rake @@ -1,4 +1,4 @@ -desc 'Prints out your Rack middleware stack' +desc "Prints out your Rack middleware stack" task middleware: :environment do Rails.configuration.middleware.each do |middleware| puts "use #{middleware.inspect}" diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake index e6b13cc077..29ea0ff804 100644 --- a/railties/lib/rails/tasks/misc.rake +++ b/railties/lib/rails/tasks/misc.rake @@ -1,16 +1,16 @@ -desc 'Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions).' +desc "Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions)." task :secret do - require 'securerandom' + require "securerandom" puts SecureRandom.hex(64) end -desc 'List versions of all Rails frameworks and the environment' +desc "List versions of all Rails frameworks and the environment" task about: :environment do puts Rails::Info end namespace :time do - desc 'List all time zones, list by two-letter country code (`rails time:zones[US]`), or list by UTC offset (`rails time:zones[-8]`)' + desc "List all time zones, list by two-letter country code (`rails time:zones[US]`), or list by UTC offset (`rails time:zones[-8]`)" task :zones, :country_or_offset do |t, args| zones, offset = ActiveSupport::TimeZone.all, nil @@ -38,8 +38,8 @@ namespace :time do # desc 'Displays names of time zones recognized by the Rails TimeZone class with the same offset as the system local time' task :local do - require 'active_support' - require 'active_support/time' + require "active_support" + require "active_support/time" jan_offset = Time.now.beginning_of_year.utc_offset jul_offset = Time.now.beginning_of_year.change(month: 7).utc_offset @@ -49,12 +49,12 @@ namespace :time do end # to find UTC -06:00 zones, OFFSET can be set to either -6, -6:00 or 21600 - def build_time_zone_list(zones, offset = ENV['OFFSET']) - require 'active_support' - require 'active_support/time' + def build_time_zone_list(zones, offset = ENV["OFFSET"]) + require "active_support" + require "active_support/time" if offset offset = if offset.to_s.match(/(\+|-)?(\d+):(\d+)/) - sign = $1 == '-' ? -1 : 1 + sign = $1 == "-" ? -1 : 1 hours, minutes = $2.to_f, $3.to_f ((hours * 3600) + (minutes.to_f * 60)) * sign elsif offset.to_f.abs <= 13 diff --git a/railties/lib/rails/tasks/restart.rake b/railties/lib/rails/tasks/restart.rake index 3f98cbe51f..03177d9954 100644 --- a/railties/lib/rails/tasks/restart.rake +++ b/railties/lib/rails/tasks/restart.rake @@ -1,8 +1,8 @@ -desc 'Restart app by touching tmp/restart.txt' +desc "Restart app by touching tmp/restart.txt" task :restart do verbose(false) do - mkdir_p 'tmp' - touch 'tmp/restart.txt' - rm_f 'tmp/pids/server.pid' + mkdir_p "tmp" + touch "tmp/restart.txt" + rm_f "tmp/pids/server.pid" end end diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index ff7233cae9..f5e5b9ae87 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -1,13 +1,13 @@ -require 'active_support/deprecation' -require 'active_support/core_ext/string/strip' # for strip_heredoc -require 'optparse' +require "active_support/deprecation" +require "active_support/core_ext/string/strip" # for strip_heredoc +require "optparse" -desc 'Print out all defined routes in match order, with names. Target specific controller with -c option, or grep routes using -g option' +desc "Print out all defined routes in match order, with names. Target specific controller with -c option, or grep routes using -g option" task routes: :environment do all_routes = Rails.application.routes.routes - require 'action_dispatch/routing/inspector' + require "action_dispatch/routing/inspector" inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes) - if ARGV.any?{ |argv| argv.start_with? 'CONTROLLER' } + if ARGV.any? { |argv| argv.start_with? "CONTROLLER" } puts <<-eow.strip_heredoc Passing `CONTROLLER` to `bin/rails routes` is deprecated and will be removed in Rails 5.1. Please use `bin/rails routes -c controller_name` instead. @@ -15,7 +15,7 @@ task routes: :environment do end routes_filter = nil - routes_filter = { controller: ENV['CONTROLLER'] } if ENV['CONTROLLER'] + routes_filter = { controller: ENV["CONTROLLER"] } if ENV["CONTROLLER"] OptionParser.new do |opts| opts.banner = "Usage: rails routes [options]" diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake index 3e40d3b037..a6cdd1e99c 100644 --- a/railties/lib/rails/tasks/statistics.rake +++ b/railties/lib/rails/tasks/statistics.rake @@ -24,6 +24,6 @@ end.select { |name, dir| File.directory?(dir) } desc "Report code statistics (KLOCs, etc) from the application or engine" task :stats do - require 'rails/code_statistics' + require "rails/code_statistics" CodeStatistics.new(*STATS_DIRECTORIES).to_s end diff --git a/railties/lib/rails/tasks/tmp.rake b/railties/lib/rails/tasks/tmp.rake index c74a17a0ca..d42a890cb6 100644 --- a/railties/lib/rails/tasks/tmp.rake +++ b/railties/lib/rails/tasks/tmp.rake @@ -2,10 +2,10 @@ namespace :tmp do desc "Clear cache and socket files from tmp/ (narrow w/ tmp:cache:clear, tmp:sockets:clear)" task clear: ["tmp:cache:clear", "tmp:sockets:clear"] - tmp_dirs = [ 'tmp/cache', - 'tmp/sockets', - 'tmp/pids', - 'tmp/cache/assets' ] + tmp_dirs = [ "tmp/cache", + "tmp/sockets", + "tmp/pids", + "tmp/cache/assets" ] tmp_dirs.each { |d| directory d } @@ -15,21 +15,21 @@ namespace :tmp do namespace :cache do # desc "Clears all files and directories in tmp/cache" task :clear do - rm_rf Dir['tmp/cache/[^.]*'], verbose: false + rm_rf Dir["tmp/cache/[^.]*"], verbose: false end end namespace :sockets do # desc "Clears all files in tmp/sockets" task :clear do - rm Dir['tmp/sockets/[^.]*'], verbose: false + rm Dir["tmp/sockets/[^.]*"], verbose: false end end namespace :pids do # desc "Clears all files in tmp/pids" task :clear do - rm Dir['tmp/pids/[^.]*'], verbose: false + rm Dir["tmp/pids/[^.]*"], verbose: false end end end diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb index fed96fbc85..c63781ed0c 100644 --- a/railties/lib/rails/templates/rails/mailers/email.html.erb +++ b/railties/lib/rails/templates/rails/mailers/email.html.erb @@ -88,7 +88,10 @@ <% unless @email.attachments.nil? || @email.attachments.empty? %> <dt>Attachments:</dt> <dd> - <%= @email.attachments.map { |a| a.respond_to?(:original_filename) ? a.original_filename : a.filename }.join(', ') %> + <% @email.attachments.each do |a| %> + <% filename = a.respond_to?(:original_filename) ? a.original_filename : a.filename %> + <%= link_to filename, "data:application/octet-stream;charset=utf-8;base64,#{Base64.encode64(a.body.to_s)}", download: filename %> + <% end %> </dd> <% end %> diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 5cc1b5b219..db341dd847 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -3,13 +3,13 @@ abort("Abort testing: Your Rails environment is running in production mode!") if Rails.env.production? require "rails/test_unit/minitest_plugin" -require 'active_support/test_case' -require 'action_controller' -require 'action_controller/test_case' -require 'action_dispatch/testing/integration' -require 'rails/generators/test_case' +require "active_support/test_case" +require "action_controller" +require "action_controller/test_case" +require "action_dispatch/testing/integration" +require "rails/generators/test_case" -require 'active_support/testing/autorun' +require "active_support/testing/autorun" if defined?(ActiveRecord::Base) ActiveRecord::Migration.maintain_test_schema! diff --git a/railties/lib/rails/test_unit/line_filtering.rb b/railties/lib/rails/test_unit/line_filtering.rb index dd9732bb12..32ba744701 100644 --- a/railties/lib/rails/test_unit/line_filtering.rb +++ b/railties/lib/rails/test_unit/line_filtering.rb @@ -1,4 +1,4 @@ -require 'method_source' +require "method_source" module Rails module LineFiltering # :nodoc: @@ -39,7 +39,7 @@ module Rails def derive_line_filters(patterns) patterns.flat_map do |file_and_line| - file, *lines = file_and_line.split(':') + file, *lines = file_and_line.split(":") if lines.empty? Filter.new(@runnable, file, nil) if file diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb index 076ab536be..6e196a32ab 100644 --- a/railties/lib/rails/test_unit/minitest_plugin.rb +++ b/railties/lib/rails/test_unit/minitest_plugin.rb @@ -1,7 +1,7 @@ require "active_support/core_ext/module/attribute_accessors" require "rails/test_unit/reporter" require "rails/test_unit/test_requirer" -require 'shellwords' +require "shellwords" module Minitest class SuppressedSummaryReporter < SummaryReporter @@ -61,19 +61,30 @@ module Minitest # as the patterns would also contain the other Rake tasks. def self.rake_run(patterns) # :nodoc: @rake_patterns = patterns - passed = run(Shellwords.split(ENV['TESTOPTS'] || '')) - exit passed unless passed - passed + autorun end + module RunRespectingRakeTestopts + def run(args = []) + if defined?(@rake_patterns) + args = Shellwords.split(ENV["TESTOPTS"] || "") + end + + super + end + end + + singleton_class.prepend RunRespectingRakeTestopts + # Owes great inspiration to test runner trailblazers like RSpec, # minitest-reporters, maxitest and others. def self.plugin_rails_init(options) - self.run_with_rails_extension = true - ENV["RAILS_ENV"] = options[:environment] || "test" - ::Rails::TestRequirer.require_files(options[:patterns]) unless run_with_autorun + # If run via `ruby` we've been passed the files to run directly. + unless run_via[:ruby] + ::Rails::TestRequirer.require_files(options[:patterns]) + end unless options[:full_backtrace] || ENV["BACKTRACE"] # Plugin can run without Rails loaded, check before filtering. @@ -86,8 +97,7 @@ module Minitest reporter << ::Rails::TestUnitReporter.new(options[:io], options) end - mattr_accessor(:run_with_autorun) { false } - mattr_accessor(:run_with_rails_extension) { false } + mattr_accessor(:run_via) { Hash.new } end # Put Rails as the first plugin minitest initializes so other plugins @@ -95,4 +105,4 @@ end # Since minitest only loads plugins if its extensions are empty we have # to call `load_plugins` first. Minitest.load_plugins -Minitest.extensions.unshift 'rails' +Minitest.extensions.unshift "rails" diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index 511cee33bd..746120e6a1 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -1,7 +1,7 @@ -require 'rails/test_unit/line_filtering' +require "rails/test_unit/line_filtering" if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any? - ENV['RAILS_ENV'] ||= 'test' + ENV["RAILS_ENV"] ||= "test" end module Rails @@ -14,7 +14,9 @@ module Rails end initializer "test_unit.line_filtering" do - ActiveSupport::TestCase.extend Rails::LineFiltering + ActiveSupport.on_load(:active_support_test_case) { + ActiveSupport::TestCase.extend Rails::LineFiltering + } end rake_tasks do diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index 4086d5b731..fe11664d5e 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -50,7 +50,7 @@ module Rails end def relative_path_for(file) - file.sub(/^#{app_root}\/?/, '') + file.sub(/^#{app_root}\/?/, "") end private @@ -68,7 +68,7 @@ module Rails def format_rerun_snippet(result) location, line = result.method(result.name).source_location - "#{self.executable} #{relative_path_for(location)}:#{line}" + "#{executable} #{relative_path_for(location)}:#{line}" end def app_root diff --git a/railties/lib/rails/test_unit/test_requirer.rb b/railties/lib/rails/test_unit/test_requirer.rb index 8b211ce130..fe35934abc 100644 --- a/railties/lib/rails/test_unit/test_requirer.rb +++ b/railties/lib/rails/test_unit/test_requirer.rb @@ -1,5 +1,5 @@ -require 'active_support/core_ext/object/blank' -require 'rake/file_list' +require "active_support/core_ext/object/blank" +require "rake/file_list" module Rails class TestRequirer # :nodoc: @@ -7,7 +7,7 @@ module Rails def require_files(patterns) patterns = expand_patterns(patterns) - Rake::FileList[patterns.compact.presence || 'test/**/*_test.rb'].to_a.each do |file| + Rake::FileList[patterns.compact.presence || "test/**/*_test.rb"].to_a.each do |file| require File.expand_path(file) end end @@ -15,7 +15,7 @@ module Rails private def expand_patterns(patterns) patterns.map do |arg| - arg = arg.gsub(/(:\d+)+?$/, '') + arg = arg.gsub(/(:\d+)+?$/, "") if Dir.exist?(arg) "#{arg}/**/*_test.rb" else diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 41921e43f3..4c157c1262 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -1,17 +1,17 @@ -gem 'minitest' -require 'minitest' -require 'rails/test_unit/minitest_plugin' +gem "minitest" +require "minitest" +require "rails/test_unit/minitest_plugin" task default: :test desc "Runs all tests in test folder" task :test do $: << "test" - pattern = if ENV.key?('TEST') - ENV['TEST'] - else - "test" - end + pattern = if ENV.key?("TEST") + ENV["TEST"] + else + "test" + end Minitest.rake_run([pattern]) end @@ -21,10 +21,10 @@ namespace :test do # If used with Active Record, this task runs before the database schema is synchronized. end - task :run => %w[test] + task run: %w[test] desc "Run tests quickly, but also reset db" - task :db => %w[db:test:prepare test] + task db: %w[db:test:prepare test] ["models", "helpers", "controllers", "mailers", "integration", "jobs"].each do |name| task name => "test:prepare" do @@ -33,17 +33,17 @@ namespace :test do end end - task :generators => "test:prepare" do + task generators: "test:prepare" do $: << "test" Minitest.rake_run(["test/lib/generators"]) end - task :units => "test:prepare" do + task units: "test:prepare" do $: << "test" Minitest.rake_run(["test/models", "test/helpers", "test/unit"]) end - task :functionals => "test:prepare" do + task functionals: "test:prepare" do $: << "test" Minitest.rake_run(["test/controllers", "test/mailers", "test/functional"]) end diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index df351c4238..3d8e8291d1 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -1,4 +1,4 @@ -require_relative 'gem_version' +require_relative "gem_version" module Rails # Returns the version of the currently loaded Rails as a string. diff --git a/railties/lib/rails/welcome_controller.rb b/railties/lib/rails/welcome_controller.rb index de9cd18b01..b757dc72ef 100644 --- a/railties/lib/rails/welcome_controller.rb +++ b/railties/lib/rails/welcome_controller.rb @@ -1,4 +1,4 @@ -require 'rails/application_controller' +require "rails/application_controller" class Rails::WelcomeController < Rails::ApplicationController # :nodoc: layout false diff --git a/railties/railties.gemspec b/railties/railties.gemspec index fa417816eb..76de2b4639 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -1,34 +1,34 @@ -version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY - s.name = 'railties' + s.name = "railties" s.version = version - s.summary = 'Tools for creating, working with, and running Rails applications.' - s.description = 'Rails internals: application bootup, plugins, generators, and rake tasks.' + s.summary = "Tools for creating, working with, and running Rails applications." + s.description = "Rails internals: application bootup, plugins, generators, and rake tasks." - s.required_ruby_version = '>= 2.2.2' + s.required_ruby_version = ">= 2.2.2" - s.license = 'MIT' + s.license = "MIT" - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://rubyonrails.org' + s.author = "David Heinemeier Hansson" + s.email = "david@loudthinking.com" + s.homepage = "http://rubyonrails.org" - s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'RDOC_MAIN.rdoc', 'exe/**/*', 'lib/**/{*,.[a-z]*}'] - s.require_path = 'lib' + s.files = Dir["CHANGELOG.md", "README.rdoc", "MIT-LICENSE", "RDOC_MAIN.rdoc", "exe/**/*", "lib/**/{*,.[a-z]*}"] + s.require_path = "lib" - s.bindir = 'exe' - s.executables = ['rails'] + s.bindir = "exe" + s.executables = ["rails"] - s.rdoc_options << '--exclude' << '.' + s.rdoc_options << "--exclude" << "." - s.add_dependency 'activesupport', version - s.add_dependency 'actionpack', version + s.add_dependency "activesupport", version + s.add_dependency "actionpack", version - s.add_dependency 'rake', '>= 0.8.7' - s.add_dependency 'thor', '>= 0.18.1', '< 2.0' - s.add_dependency 'method_source' + s.add_dependency "rake", ">= 0.8.7" + s.add_dependency "thor", ">= 0.18.1", "< 2.0" + s.add_dependency "method_source" - s.add_development_dependency 'actionview', version + s.add_development_dependency "actionview", version end diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index 2a5a731fe2..fd1e1b9662 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -1,28 +1,28 @@ ENV["RAILS_ENV"] ||= "test" -require 'stringio' -require 'active_support/testing/autorun' -require 'active_support/testing/stream' -require 'fileutils' +require "stringio" +require "active_support/testing/autorun" +require "active_support/testing/stream" +require "fileutils" -require 'active_support' -require 'action_controller' -require 'action_view' -require 'rails/all' +require "active_support" +require "action_controller" +require "action_view" +require "rails/all" module TestApp class Application < Rails::Application config.root = File.dirname(__FILE__) - secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" end end # Skips the current run on Rubinius using Minitest::Assertions#skip -def rubinius_skip(message = '') - skip message if RUBY_ENGINE == 'rbx' +def rubinius_skip(message = "") + skip message if RUBY_ENGINE == "rbx" end # Skips the current run on JRuby using Minitest::Assertions#skip -def jruby_skip(message = '') +def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end diff --git a/railties/test/app_loader_test.rb b/railties/test/app_loader_test.rb index 5946c8fd4c..7fd5c72c1c 100644 --- a/railties/test/app_loader_test.rb +++ b/railties/test/app_loader_test.rb @@ -1,6 +1,6 @@ -require 'tmpdir' -require 'abstract_unit' -require 'rails/app_loader' +require "tmpdir" +require "abstract_unit" +require "rails/app_loader" class AppLoaderTest < ActiveSupport::TestCase def loader @@ -27,12 +27,12 @@ class AppLoaderTest < ActiveSupport::TestCase end setup do - @tmp = Dir.mktmpdir('railties-rails-loader-test-suite') + @tmp = Dir.mktmpdir("railties-rails-loader-test-suite") @cwd = Dir.pwd Dir.chdir(@tmp) end - ['bin', 'script'].each do |script_dir| + ["bin", "script"].each do |script_dir| exe = "#{script_dir}/rails" test "is not in a Rails application if #{exe} is not found in the current or parent directories" do @@ -47,7 +47,7 @@ class AppLoaderTest < ActiveSupport::TestCase assert !loader.exec_app end - ['APP_PATH', 'ENGINE_PATH'].each do |keyword| + ["APP_PATH", "ENGINE_PATH"].each do |keyword| test "is in a Rails application if #{exe} exists and contains #{keyword}" do write exe, keyword @@ -66,7 +66,7 @@ class AppLoaderTest < ActiveSupport::TestCase write "foo/bar/#{exe}" write "foo/#{exe}", keyword - Dir.chdir('foo/bar') + Dir.chdir("foo/bar") loader.exec_app diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb index bcb6aff0d7..3e17a1efa5 100644 --- a/railties/test/application/asset_debugging_test.rb +++ b/railties/test/application/asset_debugging_test.rb @@ -1,5 +1,5 @@ -require 'isolation/abstract_unit' -require 'rack/test' +require "isolation/abstract_unit" +require "rack/test" module ApplicationTests class AssetDebuggingTest < ActiveSupport::TestCase @@ -28,8 +28,6 @@ module ApplicationTests RUBY ENV["RAILS_ENV"] = "production" - - boot_rails end def teardown @@ -44,7 +42,7 @@ module ApplicationTests test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do # config.assets.debug and config.assets.compile are false for production environment ENV["RAILS_ENV"] = "production" - output = Dir.chdir(app_path){ `bin/rails assets:precompile --trace 2>&1` } + output = Dir.chdir(app_path) { `bin/rails assets:precompile --trace 2>&1` } assert $?.success?, output # Load app env @@ -53,7 +51,7 @@ module ApplicationTests class ::PostsController < ActionController::Base ; end # the debug_assets params isn't used if compile is off - get '/posts?debug_assets=true' + get "/posts?debug_assets=true" assert_match(/<script src="\/assets\/application-([0-z]+)\.js"><\/script>/, last_response.body) assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js"><\/script>/, last_response.body) end @@ -66,9 +64,106 @@ module ApplicationTests class ::PostsController < ActionController::Base ; end - get '/posts?debug_assets=true' + get "/posts?debug_assets=true" assert_match(/<script src="\/assets\/application(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body) assert_match(/<script src="\/assets\/xmlhr(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body) end + + test "public path and tag methods are not over-written by the asset pipeline" do + contents = "doesnotexist" + cases = { + asset_path: %r{/#{contents}}, + image_path: %r{/images/#{contents}}, + video_path: %r{/videos/#{contents}}, + audio_path: %r{/audios/#{contents}}, + font_path: %r{/fonts/#{contents}}, + javascript_path: %r{/javascripts/#{contents}}, + stylesheet_path: %r{/stylesheets/#{contents}}, + image_tag: %r{<img src="/images/#{contents}"}, + favicon_link_tag: %r{<link rel="shortcut icon" type="image/x-icon" href="/images/#{contents}" />}, + stylesheet_link_tag: %r{<link rel="stylesheet" media="screen" href="/stylesheets/#{contents}.css" />}, + javascript_include_tag: %r{<script src="/javascripts/#{contents}.js">}, + audio_tag: %r{<audio src="/audios/#{contents}"></audio>}, + video_tag: %r{<video src="/videos/#{contents}"></video>} + } + + cases.each do |(view_method, tag_match)| + app_file "app/views/posts/index.html.erb", "<%= #{view_method} '#{contents}', skip_pipeline: true %>" + + app "development" + + class ::PostsController < ActionController::Base ; end + + get "/posts?debug_assets=true" + + body = last_response.body + assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{tag_match}, but did not: #{body}") + end + end + + test "public url methods are not over-written by the asset pipeline" do + contents = "doesnotexist" + cases = { + asset_url: %r{http://example.org/#{contents}}, + image_url: %r{http://example.org/images/#{contents}}, + video_url: %r{http://example.org/videos/#{contents}}, + audio_url: %r{http://example.org/audios/#{contents}}, + font_url: %r{http://example.org/fonts/#{contents}}, + javascript_url: %r{http://example.org/javascripts/#{contents}}, + stylesheet_url: %r{http://example.org/stylesheets/#{contents}}, + } + + cases.each do |(view_method, tag_match)| + app_file "app/views/posts/index.html.erb", "<%= #{view_method} '#{contents}', skip_pipeline: true %>" + + app "development" + + class ::PostsController < ActionController::Base ; end + + get "/posts?debug_assets=true" + + body = last_response.body + assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{tag_match}, but did not: #{body}") + end + end + + test "{ skip_pipeline: true } does not use the asset pipeline" do + cases = { + /\/assets\/application-.*.\.js/ => {}, + /application.js/ => { skip_pipeline: true }, + } + cases.each do |(tag_match, options_hash)| + app_file "app/views/posts/index.html.erb", "<%= asset_path('application.js', #{options_hash}) %>" + + app "development" + + class ::PostsController < ActionController::Base ; end + + get "/posts?debug_assets=true" + + body = last_response.body.strip + assert_match(tag_match, body, "Expected `asset_path` with `#{options_hash}` to produce a match to #{tag_match}, but did not: #{body}") + end + end + + test "public_compute_asset_path does not use the asset pipeline" do + cases = { + compute_asset_path: /\/assets\/application-.*.\.js/, + public_compute_asset_path: /application.js/, + } + + cases.each do |(view_method, tag_match)| + app_file "app/views/posts/index.html.erb", "<%= #{ view_method } 'application.js' %>" + + app "development" + + class ::PostsController < ActionController::Base ; end + + get "/posts?debug_assets=true" + + body = last_response.body.strip + assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{ tag_match }, but did not: #{ body }") + end + end end end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 9e8531b482..741ae543e0 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -1,6 +1,6 @@ -require 'isolation/abstract_unit' -require 'rack/test' -require 'active_support/json' +require "isolation/abstract_unit" +require "rack/test" +require "active_support/json" module ApplicationTests class AssetsTest < ActiveSupport::TestCase @@ -9,7 +9,6 @@ module ApplicationTests def setup build_app(initializers: true) - boot_rails end def teardown @@ -36,7 +35,7 @@ module ApplicationTests def clean_assets! quietly do - assert Dir.chdir(app_path) { system('bin/rails assets:clobber') } + assert Dir.chdir(app_path) { system("bin/rails assets:clobber") } end end @@ -53,7 +52,7 @@ module ApplicationTests app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;" - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, ["Not an asset"]] } end @@ -111,8 +110,8 @@ module ApplicationTests eoruby precompile! \ - RAILS_ENV: 'production', - DATABASE_URL: 'postgresql://baduser:badpass@127.0.0.1/dbname' + RAILS_ENV: "production", + DATABASE_URL: "postgresql://baduser:badpass@127.0.0.1/dbname" files = Dir["#{app_path}/public/assets/application-*.js"] files << Dir["#{app_path}/public/assets/foo/application-*.js"].first @@ -177,19 +176,19 @@ module ApplicationTests assert_file_exists("#{app_path}/public/assets/something/index-*.js") end - test 'precompile use assets defined in app env config' do - add_to_env_config 'production', 'config.assets.precompile = [ "something.js" ]' - app_file 'app/assets/javascripts/something.js.erb', 'alert();' + test "precompile use assets defined in app env config" do + add_to_env_config "production", 'config.assets.precompile = [ "something.js" ]' + app_file "app/assets/javascripts/something.js.erb", "alert();" - precompile! RAILS_ENV: 'production' + precompile! RAILS_ENV: "production" assert_file_exists("#{app_path}/public/assets/something-*.js") end - test 'sprockets cache is not shared between environments' do + test "sprockets cache is not shared between environments" do app_file "app/assets/images/rails.png", "notactuallyapng" - app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" - add_to_env_config 'production', 'config.assets.prefix = "production_assets"' + app_file "app/assets/stylesheets/application.css.erb", "body { background: '<%= asset_path('rails.png') %>'; }" + add_to_env_config "production", 'config.assets.prefix = "production_assets"' precompile! @@ -198,7 +197,7 @@ module ApplicationTests file = Dir["#{app_path}/public/assets/application-*.css"].first assert_match(/assets\/rails-([0-z]+)\.png/, File.read(file)) - precompile! RAILS_ENV: 'production' + precompile! RAILS_ENV: "production" assert_file_exists("#{app_path}/public/production_assets/application-*.css") @@ -206,17 +205,17 @@ module ApplicationTests assert_match(/production_assets\/rails-([0-z]+)\.png/, File.read(file)) end - test 'precompile use assets defined in app config and reassigned in app env config' do + test "precompile use assets defined in app config and reassigned in app env config" do add_to_config 'config.assets.precompile = [ "something_manifest.js" ]' - add_to_env_config 'production', 'config.assets.precompile += [ "another_manifest.js" ]' + add_to_env_config "production", 'config.assets.precompile += [ "another_manifest.js" ]' - app_file 'app/assets/config/something_manifest.js', '//= link something.js' - app_file 'app/assets/config/another_manifest.js', '//= link another.js' + app_file "app/assets/config/something_manifest.js", "//= link something.js" + app_file "app/assets/config/another_manifest.js", "//= link another.js" - app_file 'app/assets/javascripts/something.js.erb', 'alert();' - app_file 'app/assets/javascripts/another.js.erb', 'alert();' + app_file "app/assets/javascripts/something.js.erb", "alert();" + app_file "app/assets/javascripts/another.js.erb", "alert();" - precompile! RAILS_ENV: 'production' + precompile! RAILS_ENV: "production" assert_file_exists("#{app_path}/public/assets/something_manifest-*.js") assert_file_exists("#{app_path}/public/assets/something-*.js") @@ -262,7 +261,7 @@ module ApplicationTests app_file "app/assets/javascripts/application.js", "alert();" add_to_env_config "production", "config.public_file_server.enabled = true" - precompile! RAILS_ENV: 'production' + precompile! RAILS_ENV: "production" manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first assets = ActiveSupport::JSON.decode(File.read(manifest)) @@ -293,7 +292,7 @@ module ApplicationTests app_file "app/assets/stylesheets/application.css.erb", "p { background-image: url(<%= asset_path('rails.png') %>) }" - precompile! RAILS_ENV: 'production' + precompile! RAILS_ENV: "production" manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first assets = ActiveSupport::JSON.decode(File.read(manifest)) @@ -311,7 +310,7 @@ module ApplicationTests app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "p { background-image: url(<%= asset_path('rails.png') %>) }" - precompile! RAILS_ENV: 'production' + precompile! RAILS_ENV: "production" file = Dir["#{app_path}/public/assets/application-*.css"].first assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file)) @@ -376,12 +375,12 @@ module ApplicationTests class ::OmgController < ActionController::Base def index flash[:cool_story] = true - render text: "ok" + render plain: "ok" end end get "/omg" - assert_equal 'ok', last_response.body + assert_equal "ok", last_response.body get "/assets/demo.js" assert_match "alert()", last_response.body @@ -409,7 +408,7 @@ module ApplicationTests app_with_assets_in_view # config.assets.debug and config.assets.compile are false for production environment - precompile! RAILS_ENV: 'production' + precompile! RAILS_ENV: "production" # Load app env app "production" @@ -417,7 +416,7 @@ module ApplicationTests class ::PostsController < ActionController::Base ; end # the debug_assets params isn't used if compile is off - get '/posts?debug_assets=true' + get "/posts?debug_assets=true" assert_match(/<script src="\/assets\/application-([0-z]+)\.js"><\/script>/, last_response.body) assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js"><\/script>/, last_response.body) end @@ -476,9 +475,9 @@ module ApplicationTests class ::PostsController < ActionController::Base; end - get '/posts', {}, {'HTTPS'=>'off'} + get "/posts", {}, "HTTPS"=>"off" assert_match('src="http://example.com/assets/application.self.js', last_response.body) - get '/posts', {}, {'HTTPS'=>'on'} + get "/posts", {}, "HTTPS"=>"on" assert_match('src="https://example.com/assets/application.self.js', last_response.body) end @@ -508,16 +507,16 @@ module ApplicationTests private - def app_with_assets_in_view - app_file "app/assets/javascripts/application.js", "//= require_tree ." - app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }" - app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" + def app_with_assets_in_view + app_file "app/assets/javascripts/application.js", "//= require_tree ." + app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }" + app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>" - app_file "config/routes.rb", <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/posts', :to => "posts#index" end RUBY - end + end end end diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb index ba700df1d6..0bbd25db2b 100644 --- a/railties/test/application/bin_setup_test.rb +++ b/railties/test/application/bin_setup_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class BinSetupTest < ActiveSupport::TestCase @@ -6,15 +6,22 @@ module ApplicationTests def setup build_app + + create_gemfile + update_boot_file_to_use_bundler + @old_gemfile_env = ENV["BUNDLE_GEMFILE"] + ENV["BUNDLE_GEMFILE"] = app_path + "/Gemfile" end def teardown teardown_app + + ENV["BUNDLE_GEMFILE"] = @old_gemfile_env end def test_bin_setup Dir.chdir(app_path) do - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: 20140423102712) do create_table(:articles) {} end @@ -23,7 +30,7 @@ module ApplicationTests list_tables = lambda { `bin/rails runner 'p ActiveRecord::Base.connection.tables'`.strip } File.write("log/test.log", "zomg!") - assert_equal '[]', list_tables.call + assert_equal "[]", list_tables.call assert_equal 5, File.size("log/test.log") assert_not File.exist?("tmp/restart.txt") `bin/setup 2>&1` @@ -35,7 +42,7 @@ module ApplicationTests def test_bin_setup_output Dir.chdir(app_path) do - app_file 'db/schema.rb', "" + app_file "db/schema.rb", "" output = `bin/setup 2>&1` assert_equal(<<-OUTPUT, output) @@ -52,5 +59,16 @@ Created database 'db/test.sqlite3' OUTPUT end end + + private + def create_gemfile + app_file("Gemfile", "source 'https://rubygems.org'") + app_file("Gemfile", "gem 'rails', path: '#{RAILS_FRAMEWORK_ROOT}'", "a") + app_file("Gemfile", "gem 'sqlite3'", "a") + end + + def update_boot_file_to_use_bundler + app_file("config/boot.rb", "require 'bundler/setup'") + end end end diff --git a/railties/test/application/configuration/custom_test.rb b/railties/test/application/configuration/custom_test.rb index 28b3b2f2d6..13fc98f0d6 100644 --- a/railties/test/application/configuration/custom_test.rb +++ b/railties/test/application/configuration/custom_test.rb @@ -1,11 +1,10 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests module ConfigurationTests class CustomTest < ActiveSupport::TestCase def setup build_app - boot_rails FileUtils.rm_rf("#{app_path}/config/environments") end @@ -14,7 +13,7 @@ module ApplicationTests FileUtils.rm_rf(new_app) if File.directory?(new_app) end - test 'access custom configuration point' do + test "access custom configuration point" do add_to_config <<-RUBY config.x.payment_processing.schedule = :daily config.x.payment_processing.retries = 3 @@ -33,6 +32,13 @@ module ApplicationTests assert_nil x.i_do_not_exist.zomg end + test "custom configuration responds to all messages" do + x = Rails.configuration.x + assert_equal true, x.respond_to?(:i_do_not_exist) + assert_kind_of Method, x.method(:i_do_not_exist) + assert_kind_of ActiveSupport::OrderedOptions, x.i_do_not_exist + end + private def new_app File.expand_path("#{app_path}/../new_app") diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 7ec25aeca1..b0f5b30174 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -1,6 +1,6 @@ require "isolation/abstract_unit" -require 'rack/test' -require 'env_helpers' +require "rack/test" +require "env_helpers" class ::MyMailInterceptor def self.delivering_email(email); email; end @@ -34,9 +34,9 @@ module ApplicationTests FileUtils.cp_r(app_path, new_app) end - def app(env = 'development') + def app(env = "development") @app ||= begin - ENV['RAILS_ENV'] = env + ENV["RAILS_ENV"] = env # FIXME: shush Sass warning spam, not relevant to testing Railties Kernel.silence_warnings do @@ -45,13 +45,12 @@ module ApplicationTests Rails.application ensure - ENV.delete 'RAILS_ENV' + ENV.delete "RAILS_ENV" end end def setup build_app - boot_rails supress_default_config end @@ -75,7 +74,7 @@ module ApplicationTests switch_env "RAILS_ENV", nil do Rails.env = "development" assert_equal "development", Rails.env - assert_nil ENV['RAILS_ENV'] + assert_nil ENV["RAILS_ENV"] end end @@ -83,7 +82,7 @@ module ApplicationTests restore_default_config with_rails_env "development" do - app 'development' + app "development" assert Rails.application.config.log_tags.blank? end end @@ -92,13 +91,13 @@ module ApplicationTests restore_default_config with_rails_env "production" do - app 'production' + app "production" assert_equal [:request_id], Rails.application.config.log_tags end end test "lib dir is on LOAD_PATH during config" do - app_file 'lib/my_logger.rb', <<-RUBY + app_file "lib/my_logger.rb", <<-RUBY require "logger" class MyLogger < ::Logger end @@ -108,9 +107,9 @@ module ApplicationTests config.logger = MyLogger.new STDOUT RUBY - app 'development' + app "development" - assert_equal 'MyLogger', Rails.application.config.logger.class.name + assert_equal "MyLogger", Rails.application.config.logger.class.name end test "a renders exception on pending migration" do @@ -120,7 +119,7 @@ module ApplicationTests config.action_dispatch.show_exceptions = true RUBY - app_file 'db/migrate/20140708012246_create_user.rb', <<-RUBY + app_file "db/migrate/20140708012246_create_user.rb", <<-RUBY class CreateUser < ActiveRecord::Migration::Current def change create_table :users @@ -128,7 +127,7 @@ module ApplicationTests end RUBY - app 'development' + app "development" ActiveRecord::Migrator.migrations_paths = ["#{app_path}/db/migrate"] @@ -157,31 +156,31 @@ module ApplicationTests end test "Rails.application is nil until app is initialized" do - require 'rails' + require "rails" assert_nil Rails.application - app 'development' + app "development" assert_equal AppTemplate::Application.instance, Rails.application end test "Rails.application responds to all instance methods" do - app 'development' + app "development" assert_respond_to Rails.application, :routes_reloader assert_equal Rails.application.routes_reloader, AppTemplate::Application.routes_reloader end test "Rails::Application responds to paths" do - app 'development' + app "development" assert_respond_to AppTemplate::Application, :paths assert_equal ["#{app_path}/app/views"], AppTemplate::Application.paths["app/views"].expanded end test "the application root is set correctly" do - app 'development' + app "development" assert_equal Pathname.new(app_path), Rails.application.root end test "the application root can be seen from the application singleton" do - app 'development' + app "development" assert_equal Pathname.new(app_path), AppTemplate::Application.root end @@ -193,7 +192,7 @@ module ApplicationTests use_frameworks [] - app 'development' + app "development" assert_equal Pathname.new(new_app), Rails.application.root end @@ -204,7 +203,7 @@ module ApplicationTests use_frameworks [] Dir.chdir("#{app_path}") do - app 'development' + app "development" assert_equal Pathname.new("#{app_path}"), Rails.application.root end end @@ -214,7 +213,7 @@ module ApplicationTests config.root = "#{app_path}" RUBY - app 'development' + app "development" assert_instance_of Pathname, Rails.root end @@ -224,7 +223,7 @@ module ApplicationTests config.paths["public"] = "somewhere" RUBY - app 'development' + app "development" assert_instance_of Pathname, Rails.public_path end @@ -235,13 +234,13 @@ module ApplicationTests config.cache_classes = true RUBY - app 'development' + app "development" assert_equal :require, ActiveSupport::Dependencies.mechanism end test "application is always added to eager_load namespaces" do - app 'development' + app "development" assert_includes Rails.application.config.eager_load_namespaces, AppTemplate::Application end @@ -257,7 +256,7 @@ module ApplicationTests use_frameworks [] assert_nothing_raised do - app 'development' + app "development" end end @@ -269,18 +268,18 @@ module ApplicationTests RUBY assert_nothing_raised do - app 'development' + app "development" end end test "filter_parameters should be able to set via config.filter_parameters in an initializer" do - app_file 'config/initializers/filter_parameters_logging.rb', <<-RUBY + app_file "config/initializers/filter_parameters_logging.rb", <<-RUBY Rails.application.config.filter_parameters += [ :password, :foo, 'bar' ] RUBY - app 'development' + app "development" - assert_equal [:password, :foo, 'bar'], Rails.application.env_config['action_dispatch.parameter_filter'] + assert_equal [:password, :foo, "bar"], Rails.application.env_config["action_dispatch.parameter_filter"] end test "config.to_prepare is forwarded to ActionDispatch" do @@ -294,7 +293,7 @@ module ApplicationTests assert !$prepared - app 'development' + app "development" get "/" assert $prepared @@ -306,7 +305,7 @@ module ApplicationTests end test "skipping config.encoding still results in 'utf-8' as the default" do - app 'development' + app "development" assert_utf8 end @@ -315,7 +314,7 @@ module ApplicationTests config.encoding = "utf-8" RUBY - app 'development' + app "development" assert_utf8 end @@ -324,7 +323,7 @@ module ApplicationTests config.paths["public"] = "somewhere" RUBY - app 'development' + app "development" assert_equal Pathname.new(app_path).join("somewhere"), Rails.public_path end @@ -332,7 +331,7 @@ module ApplicationTests restore_default_config with_rails_env "production" do - app 'production' + app "production" assert_not app.config.public_file_server.enabled end end @@ -342,7 +341,7 @@ module ApplicationTests with_rails_env "production" do switch_env "RAILS_SERVE_STATIC_FILES", "1" do - app 'production' + app "production" assert app.config.public_file_server.enabled end end @@ -353,7 +352,7 @@ module ApplicationTests with_rails_env "production" do switch_env "RAILS_LOG_TO_STDOUT", "1" do - app 'production' + app "production" assert ActiveSupport::Logger.logger_outputs_to?(app.config.logger, STDOUT) end end @@ -364,7 +363,7 @@ module ApplicationTests with_rails_env "production" do switch_env "RAILS_SERVE_STATIC_FILES", " " do - app 'production' + app "production" assert_not app.config.public_file_server.enabled end end @@ -392,66 +391,66 @@ module ApplicationTests test "Use key_generator when secret_key_base is set" do make_basic_app do |application| - application.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + application.secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" application.config.session_store :disabled end class ::OmgController < ActionController::Base def index cookies.signed[:some_key] = "some_value" - render text: cookies[:some_key] + render plain: cookies[:some_key] end end get "/" - secret = app.key_generator.generate_key('signed cookie') + secret = app.key_generator.generate_key("signed cookie") verifier = ActiveSupport::MessageVerifier.new(secret) - assert_equal 'some_value', verifier.verify(last_response.body) + assert_equal "some_value", verifier.verify(last_response.body) end test "application verifier can be used in the entire application" do make_basic_app do |application| - application.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + application.secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" application.config.session_store :disabled end message = app.message_verifier(:sensitive_value).generate("some_value") - assert_equal 'some_value', Rails.application.message_verifier(:sensitive_value).verify(message) + assert_equal "some_value", Rails.application.message_verifier(:sensitive_value).verify(message) - secret = app.key_generator.generate_key('sensitive_value') + secret = app.key_generator.generate_key("sensitive_value") verifier = ActiveSupport::MessageVerifier.new(secret) - assert_equal 'some_value', verifier.verify(message) + assert_equal "some_value", verifier.verify(message) end test "application message verifier can be used when the key_generator is ActiveSupport::LegacyKeyGenerator" do - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" RUBY - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: YAML - app 'development' + app "development" - assert_equal app.env_config['action_dispatch.key_generator'], Rails.application.key_generator - assert_equal app.env_config['action_dispatch.key_generator'].class, ActiveSupport::LegacyKeyGenerator + assert_equal app.env_config["action_dispatch.key_generator"], Rails.application.key_generator + assert_equal app.env_config["action_dispatch.key_generator"].class, ActiveSupport::LegacyKeyGenerator message = app.message_verifier(:sensitive_value).generate("some_value") - assert_equal 'some_value', Rails.application.message_verifier(:sensitive_value).verify(message) + assert_equal "some_value", Rails.application.message_verifier(:sensitive_value).verify(message) end test "warns when secrets.secret_key_base is blank and config.secret_token is set" do - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" RUBY - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: YAML - app 'development' + app "development" assert_deprecated(/You didn't set `secret_key_base`./) do app.env_config @@ -459,12 +458,12 @@ module ApplicationTests end test "raise when secrets.secret_key_base is not a type of string" do - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: 123 YAML - app 'development' + app "development" assert_raise(ArgumentError) do app.key_generator @@ -472,31 +471,31 @@ module ApplicationTests end test "prefer secrets.secret_token over config.secret_token" do - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_token = "" RUBY - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_token: 3b7cd727ee24e8444053437c36cc66c3 YAML - app 'development' + app "development" - assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_token + assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secrets.secret_token end test "application verifier can build different verifiers" do make_basic_app do |application| - application.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + application.secrets.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33" application.config.session_store :disabled end default_verifier = app.message_verifier(:sensitive_value) text_verifier = app.message_verifier(:text) - message = text_verifier.generate('some_value') + message = text_verifier.generate("some_value") - assert_equal 'some_value', text_verifier.verify(message) + assert_equal "some_value", text_verifier.verify(message) assert_raises ActiveSupport::MessageVerifier::InvalidSignature do default_verifier.verify(message) end @@ -506,131 +505,131 @@ module ApplicationTests end test "secrets.secret_key_base is used when config/secrets.yml is present" do - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 YAML - app 'development' - assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base + app "development" + assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secrets.secret_key_base end test "secret_key_base is copied from config to secrets when not set" do remove_file "config/secrets.yml" - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c3" RUBY - app 'development' - assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base + app "development" + assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secrets.secret_key_base end test "config.secret_token over-writes a blank secrets.secret_token" do - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" RUBY - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: secret_token: YAML - app 'development' + app "development" - assert_equal 'b3c631c314c0bbca50c1b2843150fe33', app.secrets.secret_token - assert_equal 'b3c631c314c0bbca50c1b2843150fe33', app.config.secret_token + assert_equal "b3c631c314c0bbca50c1b2843150fe33", app.secrets.secret_token + assert_equal "b3c631c314c0bbca50c1b2843150fe33", app.config.secret_token end test "custom secrets saved in config/secrets.yml are loaded in app secrets" do - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 aws_access_key_id: myamazonaccesskeyid aws_secret_access_key: myamazonsecretaccesskey YAML - app 'development' + app "development" - assert_equal 'myamazonaccesskeyid', app.secrets.aws_access_key_id - assert_equal 'myamazonsecretaccesskey', app.secrets.aws_secret_access_key + assert_equal "myamazonaccesskeyid", app.secrets.aws_access_key_id + assert_equal "myamazonsecretaccesskey", app.secrets.aws_secret_access_key end test "shared secrets saved in config/secrets.yml are loaded in app secrets" do - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML shared: api_key: 3b7cd727 YAML - app 'development' + app "development" - assert_equal '3b7cd727', app.secrets.api_key + assert_equal "3b7cd727", app.secrets.api_key end test "shared secrets will yield to environment specific secrets" do - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML shared: api_key: 3b7cd727 - + development: api_key: abc12345 YAML - app 'development' + app "development" - assert_equal 'abc12345', app.secrets.api_key + assert_equal "abc12345", app.secrets.api_key end test "blank config/secrets.yml does not crash the loading process" do - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML YAML - app 'development' + app "development" assert_nil app.secrets.not_defined end test "config.secret_key_base over-writes a blank secrets.secret_key_base" do - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_key_base = "iaminallyoursecretkeybase" RUBY - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: YAML - app 'development' + app "development" assert_equal "iaminallyoursecretkeybase", app.secrets.secret_key_base end test "uses ActiveSupport::LegacyKeyGenerator as app.key_generator when secrets.secret_key_base is blank" do - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_token = "b3c631c314c0bbca50c1b2843150fe33" RUBY - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: YAML - app 'development' + app "development" - assert_equal 'b3c631c314c0bbca50c1b2843150fe33', app.config.secret_token + assert_equal "b3c631c314c0bbca50c1b2843150fe33", app.config.secret_token assert_equal nil, app.secrets.secret_key_base assert_equal app.key_generator.class, ActiveSupport::LegacyKeyGenerator end test "uses ActiveSupport::LegacyKeyGenerator with config.secret_token as app.key_generator when secrets.secret_key_base is blank" do - app_file 'config/initializers/secret_token.rb', <<-RUBY + app_file "config/initializers/secret_token.rb", <<-RUBY Rails.application.config.secret_token = "" RUBY - app_file 'config/secrets.yml', <<-YAML + app_file "config/secrets.yml", <<-YAML development: secret_key_base: YAML - app 'development' + app "development" - assert_equal '', app.config.secret_token + assert_equal "", app.config.secret_token assert_equal nil, app.secrets.secret_key_base assert_raise ArgumentError, /\AA secret is required/ do app.key_generator @@ -651,7 +650,7 @@ module ApplicationTests end test "default form builder specified as a string" do - app_file 'config/initializers/form_builder.rb', <<-RUBY + app_file "config/initializers/form_builder.rb", <<-RUBY class CustomFormBuilder < ActionView::Helpers::FormBuilder def text_field(attribute, *args) label(attribute) + super(attribute, *args) @@ -660,15 +659,14 @@ module ApplicationTests Rails.configuration.action_view.default_form_builder = "CustomFormBuilder" RUBY - app_file 'app/models/post.rb', <<-RUBY + app_file "app/models/post.rb", <<-RUBY class Post include ActiveModel::Model attr_accessor :name end RUBY - - app_file 'app/controllers/posts_controller.rb', <<-RUBY + app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ApplicationController def index render inline: "<%= begin; form_for(Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>" @@ -682,14 +680,14 @@ module ApplicationTests end RUBY - app 'development' + app "development" get "/posts" assert_match(/label/, last_response.body) end test "default method for update can be changed" do - app_file 'app/models/post.rb', <<-RUBY + app_file "app/models/post.rb", <<-RUBY class Post include ActiveModel::Model def to_key; [1]; end @@ -699,14 +697,14 @@ module ApplicationTests token = "cf50faa3fe97702ca1ae" - app_file 'app/controllers/posts_controller.rb', <<-RUBY + app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ApplicationController def show render inline: "<%= begin; form_for(Post.new) {}; rescue => e; e.to_s; end %>" end def update - render text: "update" + render plain: "update" end private @@ -721,7 +719,7 @@ module ApplicationTests end RUBY - app 'development' + app "development" params = { authenticity_token: token } @@ -743,7 +741,7 @@ module ApplicationTests test "request forgery token param can be changed" do make_basic_app do |application| - application.config.action_controller.request_forgery_protection_token = '_xsrf_token_here' + application.config.action_controller.request_forgery_protection_token = "_xsrf_token_here" end class ::OmgController < ActionController::Base @@ -774,12 +772,12 @@ module ApplicationTests config.action_mailer.interceptors = MyMailInterceptor RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base - assert_equal [::MyMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors") + assert_equal [::MyMailInterceptor], ::Mail.class_variable_get(:@@delivery_interceptors) end test "registers multiple interceptors with ActionMailer" do @@ -787,12 +785,12 @@ module ApplicationTests config.action_mailer.interceptors = [MyMailInterceptor, "MyOtherMailInterceptor"] RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base - assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors") + assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.class_variable_get(:@@delivery_interceptors) end test "registers preview interceptors with ActionMailer" do @@ -800,7 +798,7 @@ module ApplicationTests config.action_mailer.preview_interceptors = MyPreviewMailInterceptor RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base @@ -813,7 +811,7 @@ module ApplicationTests config.action_mailer.preview_interceptors = [MyPreviewMailInterceptor, "MyOtherPreviewMailInterceptor"] RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base @@ -822,11 +820,11 @@ module ApplicationTests end test "default preview interceptor can be removed" do - app_file 'config/initializers/preview_interceptors.rb', <<-RUBY + app_file "config/initializers/preview_interceptors.rb", <<-RUBY ActionMailer::Base.preview_interceptors.delete(ActionMailer::InlinePreviewInterceptor) RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base @@ -839,12 +837,12 @@ module ApplicationTests config.action_mailer.observers = MyMailObserver RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base - assert_equal [::MyMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers") + assert_equal [::MyMailObserver], ::Mail.class_variable_get(:@@delivery_notification_observers) end test "registers multiple observers with ActionMailer" do @@ -852,12 +850,12 @@ module ApplicationTests config.action_mailer.observers = [MyMailObserver, "MyOtherMailObserver"] RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base - assert_equal [::MyMailObserver, ::MyOtherMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers") + assert_equal [::MyMailObserver, ::MyOtherMailObserver], ::Mail.class_variable_get(:@@delivery_notification_observers) end test "allows setting the queue name for the ActionMailer::DeliveryJob" do @@ -865,12 +863,12 @@ module ApplicationTests config.action_mailer.deliver_later_queue_name = 'test_default' RUBY - app 'development' + app "development" require "mail" _ = ActionMailer::Base - assert_equal 'test_default', ActionMailer::Base.send(:class_variable_get, "@@deliver_later_queue_name") + assert_equal "test_default", ActionMailer::Base.class_variable_get(:@@deliver_later_queue_name) end test "valid timezone is setup correctly" do @@ -879,7 +877,7 @@ module ApplicationTests config.time_zone = "Wellington" RUBY - app 'development' + app "development" assert_equal "Wellington", Rails.application.config.time_zone end @@ -891,7 +889,7 @@ module ApplicationTests RUBY assert_raise(ArgumentError) do - app 'development' + app "development" end end @@ -901,7 +899,7 @@ module ApplicationTests config.beginning_of_week = :wednesday RUBY - app 'development' + app "development" assert_equal :wednesday, Rails.application.config.beginning_of_week end @@ -913,15 +911,15 @@ module ApplicationTests RUBY assert_raise(ArgumentError) do - app 'development' + app "development" end end test "config.action_view.cache_template_loading with cache_classes default" do add_to_config "config.cache_classes = true" - app 'development' - require 'action_view/base' + app "development" + require "action_view/base" assert_equal true, ActionView::Resolver.caching? end @@ -929,8 +927,8 @@ module ApplicationTests test "config.action_view.cache_template_loading without cache_classes default" do add_to_config "config.cache_classes = false" - app 'development' - require 'action_view/base' + app "development" + require "action_view/base" assert_equal false, ActionView::Resolver.caching? end @@ -941,8 +939,8 @@ module ApplicationTests config.action_view.cache_template_loading = false RUBY - app 'development' - require 'action_view/base' + app "development" + require "action_view/base" assert_equal false, ActionView::Resolver.caching? end @@ -953,8 +951,8 @@ module ApplicationTests config.action_view.cache_template_loading = true RUBY - app 'development' - require 'action_view/base' + app "development" + require "action_view/base" assert_equal true, ActionView::Resolver.caching? end @@ -964,11 +962,11 @@ module ApplicationTests add_to_env_config "development", "config.cache_classes = false" # These requires are to emulate an engine loading Action View before the application - require 'action_view' - require 'action_view/railtie' - require 'action_view/base' + require "action_view" + require "action_view/railtie" + require "action_view/base" - app 'development' + app "development" assert_equal false, ActionView::Resolver.caching? end @@ -980,20 +978,20 @@ module ApplicationTests class ::OmgController < ActionController::Base def index - render text: env["action_dispatch.show_exceptions"] + render plain: env["action_dispatch.show_exceptions"] end end get "/" - assert_equal 'true', last_response.body + assert_equal "true", last_response.body end test "config.action_controller.wrap_parameters is set in ActionController::Base" do - app_file 'config/initializers/wrap_parameters.rb', <<-RUBY + app_file "config/initializers/wrap_parameters.rb", <<-RUBY ActionController::Base.wrap_parameters format: [:json] RUBY - app_file 'app/models/post.rb', <<-RUBY + app_file "app/models/post.rb", <<-RUBY class Post def self.attribute_names %w(title) @@ -1001,16 +999,16 @@ module ApplicationTests end RUBY - app_file 'app/controllers/application_controller.rb', <<-RUBY + app_file "app/controllers/application_controller.rb", <<-RUBY class ApplicationController < ActionController::Base protect_from_forgery with: :reset_session # as we are testing API here end RUBY - app_file 'app/controllers/posts_controller.rb', <<-RUBY + app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ApplicationController def create - render text: params[:post].inspect + render plain: params[:post].inspect end end RUBY @@ -1021,17 +1019,17 @@ module ApplicationTests end RUBY - app 'development' + app "development" post "/posts.json", '{ "title": "foo", "name": "bar" }', "CONTENT_TYPE" => "application/json" assert_equal '<ActionController::Parameters {"title"=>"foo"} permitted: false>', last_response.body end test "config.action_controller.permit_all_parameters = true" do - app_file 'app/controllers/posts_controller.rb', <<-RUBY + app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ActionController::Base def create - render text: params[:post].permitted? ? "permitted" : "forbidden" + render plain: params[:post].permitted? ? "permitted" : "forbidden" end end RUBY @@ -1043,17 +1041,17 @@ module ApplicationTests config.action_controller.permit_all_parameters = true RUBY - app 'development' + app "development" - post "/posts", {post: {"title" =>"zomg"}} - assert_equal 'permitted', last_response.body + post "/posts", post: { "title" =>"zomg" } + assert_equal "permitted", last_response.body end test "config.action_controller.action_on_unpermitted_parameters = :raise" do - app_file 'app/controllers/posts_controller.rb', <<-RUBY + app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ActionController::Base def create - render text: params.require(:post).permit(:name) + render plain: params.require(:post).permit(:name) end end RUBY @@ -1065,16 +1063,16 @@ module ApplicationTests config.action_controller.action_on_unpermitted_parameters = :raise RUBY - app 'development' + app "development" assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters - post "/posts", {post: {"title" =>"zomg"}} + post "/posts", post: { "title" =>"zomg" } assert_match "We're sorry, but something went wrong", last_response.body end test "config.action_controller.always_permitted_parameters are: controller, action by default" do - app 'development' + app "development" assert_equal %w(controller action), ActionController::Parameters.always_permitted_parameters end @@ -1083,16 +1081,16 @@ module ApplicationTests config.action_controller.always_permitted_parameters = %w( controller action format ) RUBY - app 'development' + app "development" assert_equal %w( controller action format ), ActionController::Parameters.always_permitted_parameters end - test "config.action_controller.always_permitted_parameters = ['controller','action','format'] does not raise exeception" do - app_file 'app/controllers/posts_controller.rb', <<-RUBY + test "config.action_controller.always_permitted_parameters = ['controller','action','format'] does not raise exception" do + app_file "app/controllers/posts_controller.rb", <<-RUBY class PostsController < ActionController::Base def create - render text: params.permit(post: [:title]) + render plain: params.permit(post: [:title]) end end RUBY @@ -1105,28 +1103,28 @@ module ApplicationTests config.action_controller.action_on_unpermitted_parameters = :raise RUBY - app 'development' + app "development" assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters - post "/posts", {post: {"title" =>"zomg"}, format: "json"} + post "/posts", post: { "title" =>"zomg" }, format: "json" assert_equal 200, last_response.status end test "config.action_controller.action_on_unpermitted_parameters is :log by default on development" do - app 'development' + app "development" assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters end test "config.action_controller.action_on_unpermitted_parameters is :log by default on test" do - app 'test' + app "test" assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters end test "config.action_controller.action_on_unpermitted_parameters is false by default on production" do - app 'production' + app "production" assert_equal false, ActionController::Parameters.action_on_unpermitted_parameters end @@ -1139,28 +1137,28 @@ module ApplicationTests class ::OmgController < ActionController::Base def index respond_to do |format| - format.html { render text: "HTML" } - format.xml { render text: "XML" } + format.html { render plain: "HTML" } + format.xml { render plain: "XML" } end end end get "/", {}, "HTTP_ACCEPT" => "application/xml" - assert_equal 'HTML', last_response.body + assert_equal "HTML", last_response.body get "/", { format: :xml }, "HTTP_ACCEPT" => "application/xml" - assert_equal 'XML', last_response.body + assert_equal "XML", last_response.body end test "Rails.application#env_config exists and include some existing parameters" do make_basic_app assert_respond_to app, :env_config - assert_equal app.env_config['action_dispatch.parameter_filter'], app.config.filter_parameters - assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions - assert_equal app.env_config['action_dispatch.logger'], Rails.logger - assert_equal app.env_config['action_dispatch.backtrace_cleaner'], Rails.backtrace_cleaner - assert_equal app.env_config['action_dispatch.key_generator'], Rails.application.key_generator + assert_equal app.env_config["action_dispatch.parameter_filter"], app.config.filter_parameters + assert_equal app.env_config["action_dispatch.show_exceptions"], app.config.action_dispatch.show_exceptions + assert_equal app.env_config["action_dispatch.logger"], Rails.logger + assert_equal app.env_config["action_dispatch.backtrace_cleaner"], Rails.backtrace_cleaner + assert_equal app.env_config["action_dispatch.key_generator"], Rails.application.key_generator end test "config.colorize_logging default is true" do @@ -1187,6 +1185,22 @@ module ApplicationTests end end + test "default session store initializer does not overwrite the user defined session store even if it is disabled" do + make_basic_app do |application| + application.config.session_store :disabled + end + + assert_equal nil, app.config.session_store + end + + test "default session store initializer sets session store to cookie store" do + session_options = { key: "_myapp_session", cookie_only: true } + make_basic_app + + assert_equal ActionDispatch::Session::CookieStore, app.config.session_store + assert_equal session_options, app.config.session_options + end + test "config.log_level with custom logger" do make_basic_app do |application| application.config.logger = Logger.new(STDOUT) @@ -1205,13 +1219,13 @@ module ApplicationTests test "config.active_record.dump_schema_after_migration is false on production" do build_app - app 'production' + app "production" assert_not ActiveRecord::Base.dump_schema_after_migration end test "config.active_record.dump_schema_after_migration is true by default on development" do - app 'development' + app "development" assert ActiveRecord::Base.dump_schema_after_migration end @@ -1237,12 +1251,12 @@ module ApplicationTests end RUBY - app 'development' + app "development" assert_not Rails.configuration.ran_block - require 'rake' - require 'rake/testtask' - require 'rdoc/task' + require "rake" + require "rake/testtask" + require "rdoc/task" Rails.application.load_tasks assert Rails.configuration.ran_block @@ -1259,7 +1273,7 @@ module ApplicationTests end RUBY - app 'development' + app "development" assert_not Rails.configuration.ran_block Rails.application.load_generators @@ -1277,7 +1291,7 @@ module ApplicationTests end RUBY - app 'development' + app "development" assert_not Rails.configuration.ran_block Rails.application.load_console @@ -1295,7 +1309,7 @@ module ApplicationTests end RUBY - app 'development' + app "development" assert_not Rails.configuration.ran_block Rails.application.load_runner @@ -1303,7 +1317,7 @@ module ApplicationTests end test "loading the first existing database configuration available" do - app_file 'config/environments/development.rb', <<-RUBY + app_file "config/environments/development.rb", <<-RUBY Rails.application.configure do config.paths.add 'config/database', with: 'config/nonexistent.yml' @@ -1311,44 +1325,44 @@ module ApplicationTests end RUBY - app 'development' + app "development" assert_kind_of Hash, Rails.application.config.database_configuration end - test 'raises with proper error message if no database configuration found' do + test "raises with proper error message if no database configuration found" do FileUtils.rm("#{app_path}/config/database.yml") - app 'development' + app "development" err = assert_raises RuntimeError do Rails.application.config.database_configuration end - assert_match 'config/database', err.message + assert_match "config/database", err.message end - test 'config.action_mailer.show_previews defaults to true in development' do - app 'development' + test "config.action_mailer.show_previews defaults to true in development" do + app "development" assert Rails.application.config.action_mailer.show_previews end - test 'config.action_mailer.show_previews defaults to false in production' do - app 'production' + test "config.action_mailer.show_previews defaults to false in production" do + app "production" assert_equal false, Rails.application.config.action_mailer.show_previews end - test 'config.action_mailer.show_previews can be set in the configuration file' do + test "config.action_mailer.show_previews can be set in the configuration file" do add_to_config <<-RUBY config.action_mailer.show_previews = true RUBY - app 'production' + app "production" assert_equal true, Rails.application.config.action_mailer.show_previews end test "config_for loads custom configuration from yaml files" do - app_file 'config/custom.yml', <<-RUBY + app_file "config/custom.yml", <<-RUBY development: key: 'custom key' RUBY @@ -1357,13 +1371,13 @@ module ApplicationTests config.my_custom_config = config_for('custom') RUBY - app 'development' + app "development" - assert_equal 'custom key', Rails.application.config.my_custom_config['key'] + assert_equal "custom key", Rails.application.config.my_custom_config["key"] end test "config_for uses the Pathname object if it is provided" do - app_file 'config/custom.yml', <<-RUBY + app_file "config/custom.yml", <<-RUBY development: key: 'custom key' RUBY @@ -1372,9 +1386,9 @@ module ApplicationTests config.my_custom_config = config_for(Pathname.new(Rails.root.join("config/custom.yml"))) RUBY - app 'development' + app "development" - assert_equal 'custom key', Rails.application.config.my_custom_config['key'] + assert_equal "custom key", Rails.application.config.my_custom_config["key"] end test "config_for raises an exception if the file does not exist" do @@ -1383,14 +1397,14 @@ module ApplicationTests RUBY exception = assert_raises(RuntimeError) do - app 'development' + app "development" end assert_equal "Could not load configuration. No such file - #{app_path}/config/custom.yml", exception.message end test "config_for without the environment configured returns an empty hash" do - app_file 'config/custom.yml', <<-RUBY + app_file "config/custom.yml", <<-RUBY test: key: 'custom key' RUBY @@ -1399,26 +1413,26 @@ module ApplicationTests config.my_custom_config = config_for('custom') RUBY - app 'development' + app "development" assert_equal({}, Rails.application.config.my_custom_config) end test "config_for with empty file returns an empty hash" do - app_file 'config/custom.yml', <<-RUBY + app_file "config/custom.yml", <<-RUBY RUBY add_to_config <<-RUBY config.my_custom_config = config_for('custom') RUBY - app 'development' + app "development" assert_equal({}, Rails.application.config.my_custom_config) end test "config_for containing ERB tags should evaluate" do - app_file 'config/custom.yml', <<-RUBY + app_file "config/custom.yml", <<-RUBY development: key: <%= 'custom key' %> RUBY @@ -1427,13 +1441,13 @@ module ApplicationTests config.my_custom_config = config_for('custom') RUBY - app 'development' + app "development" - assert_equal 'custom key', Rails.application.config.my_custom_config['key'] + assert_equal "custom key", Rails.application.config.my_custom_config["key"] end test "config_for with syntax error show a more descriptive exception" do - app_file 'config/custom.yml', <<-RUBY + app_file "config/custom.yml", <<-RUBY development: key: foo: RUBY @@ -1443,14 +1457,14 @@ module ApplicationTests RUBY exception = assert_raises(RuntimeError) do - app 'development' + app "development" end - assert_match 'YAML syntax error occurred while parsing', exception.message + assert_match "YAML syntax error occurred while parsing", exception.message end test "config_for allows overriding the environment" do - app_file 'config/custom.yml', <<-RUBY + app_file "config/custom.yml", <<-RUBY test: key: 'walrus' production: @@ -1462,11 +1476,11 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert_equal 'unicorn', Rails.application.config.my_custom_config['key'] + assert_equal "unicorn", Rails.application.config.my_custom_config["key"] end test "api_only is false by default" do - app 'development' + app "development" refute Rails.application.config.api_only end @@ -1474,7 +1488,7 @@ module ApplicationTests add_to_config <<-RUBY config.api_only = true RUBY - app 'development' + app "development" Rails.application.load_generators assert Rails.configuration.api_only @@ -1484,7 +1498,7 @@ module ApplicationTests add_to_config <<-RUBY config.api_only = true RUBY - app 'development' + app "development" assert_equal :api, Rails.configuration.debug_exception_response_format end @@ -1494,13 +1508,13 @@ module ApplicationTests config.api_only = true RUBY - app_file 'config/environments/development.rb', <<-RUBY + app_file "config/environments/development.rb", <<-RUBY Rails.application.configure do config.debug_exception_response_format = :default end RUBY - app 'development' + app "development" assert_equal :default, Rails.configuration.debug_exception_response_format end diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index ea68e63f8f..72f340df34 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -1,11 +1,10 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" class ConsoleTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation def setup build_app - boot_rails end def teardown @@ -30,7 +29,7 @@ class ConsoleTest < ActiveSupport::TestCase end def test_app_can_access_path_helper_method - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', to: 'foo#index' end @@ -38,7 +37,7 @@ class ConsoleTest < ActiveSupport::TestCase load_environment console_session = irb_context.app - assert_equal '/foo', console_session.foo_path + assert_equal "/foo", console_session.foo_path end def test_new_session_should_return_integration_session @@ -89,8 +88,8 @@ class ConsoleTest < ActiveSupport::TestCase helper = irb_context.helper assert_not_nil helper assert_instance_of ActionView::Base, helper - assert_equal 'Once upon a time in a world...', - helper.truncate('Once upon a time in a world far far away') + assert_equal "Once upon a time in a world...", + helper.truncate("Once upon a time in a world far far away") end end @@ -104,7 +103,7 @@ class FullStackConsoleTest < ActiveSupport::TestCase skip "PTY unavailable" unless defined?(PTY) && PTY.respond_to?(:open) build_app - app_file 'app/models/post.rb', <<-CODE + app_file "app/models/post.rb", <<-CODE class Post < ActiveRecord::Base end CODE @@ -127,7 +126,7 @@ class FullStackConsoleTest < ActiveSupport::TestCase end end - assert output.include?(expected), "#{expected.inspect} expected, but got:\n\n#{output}" + assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}" end def write_prompt(command, expected_output = nil) diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index 644af0e737..0153f94504 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails end def teardown @@ -30,7 +29,7 @@ module ApplicationTests end test "allow running plugin new generator inside Rails app directory" do - FileUtils.cd(rails_root){ `ruby bin/rails plugin new vendor/plugins/bukkits` } + FileUtils.cd(rails_root) { `ruby bin/rails plugin new vendor/plugins/bukkits` } assert File.exist?(File.join(rails_root, "vendor/plugins/bukkits/test/dummy/config/application.rb")) end @@ -114,7 +113,7 @@ module ApplicationTests test "generators with string and hash for options should generate symbol keys" do with_bare_config do |c| c.generators do |g| - g.orm 'data_mapper', migration: false + g.orm "data_mapper", migration: false end expected = { @@ -135,10 +134,10 @@ module ApplicationTests require "#{app_path}/config/environment" Rails.application.load_generators - assert Rails::Generators.hidden_namespaces.include?("assets") - assert Rails::Generators.hidden_namespaces.include?("helper") - assert Rails::Generators.hidden_namespaces.include?("js") - assert Rails::Generators.hidden_namespaces.include?("css") + assert_includes Rails::Generators.hidden_namespaces, "assets" + assert_includes Rails::Generators.hidden_namespaces, "helper" + assert_includes Rails::Generators.hidden_namespaces, "js" + assert_includes Rails::Generators.hidden_namespaces, "css" assert Rails::Generators.options[:rails][:api] assert_equal false, Rails::Generators.options[:rails][:assets] assert_equal false, Rails::Generators.options[:rails][:helper] @@ -166,7 +165,7 @@ module ApplicationTests config.api_only = true RUBY - FileUtils.cd(rails_root){ `bin/rails generate mailer notifier foo` } + FileUtils.cd(rails_root) { `bin/rails generate mailer notifier foo` } assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.text.erb")) assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.html.erb")) end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 44209a52f7..b2cd339c1a 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf "#{app_path}/config/environments" end @@ -129,7 +128,7 @@ module ApplicationTests end RUBY - require 'rack/test' + require "rack/test" extend Rack::Test::Methods get "/foo/included_helpers" @@ -161,10 +160,10 @@ module ApplicationTests end RUBY - require 'rack/test' + require "rack/test" extend Rack::Test::Methods - get 'omg/show' + get "omg/show" assert_equal '{"omg":"omg"}', last_response.body end @@ -176,7 +175,7 @@ module ApplicationTests end test "assignment config.encoding to default_charset" do - charset = 'Shift_JIS' + charset = "Shift_JIS" add_to_config "config.encoding = '#{charset}'" require "#{app_path}/config/environment" assert_equal charset, ActionDispatch::Response.default_charset @@ -204,7 +203,7 @@ module ApplicationTests test "active_record extensions are applied to ActiveRecord" do add_to_config "config.active_record.table_name_prefix = 'tbl_'" require "#{app_path}/config/environment" - assert_equal 'tbl_', ActiveRecord::Base.table_name_prefix + assert_equal "tbl_", ActiveRecord::Base.table_name_prefix end test "database middleware doesn't initialize when activerecord is not in frameworks" do @@ -238,7 +237,7 @@ module ApplicationTests begin require "#{app_path}/config/environment" orig_database_url = ENV.delete("DATABASE_URL") - orig_rails_env, Rails.env = Rails.env, 'development' + orig_rails_env, Rails.env = Rails.env, "development" ActiveRecord::Base.establish_connection assert ActiveRecord::Base.connection assert_match(/#{ActiveRecord::Base.configurations[Rails.env]['database']}/, ActiveRecord::Base.connection_config[:database]) @@ -253,7 +252,7 @@ module ApplicationTests begin require "#{app_path}/config/environment" orig_database_url = ENV.delete("DATABASE_URL") - orig_rails_env, Rails.env = Rails.env, 'development' + orig_rails_env, Rails.env = Rails.env, "development" database_url_db_name = "db/database_url_db.sqlite3" ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" ActiveRecord::Base.establish_connection diff --git a/railties/test/application/initializers/hooks_test.rb b/railties/test/application/initializers/hooks_test.rb index b2cea0a8e1..0309d02730 100644 --- a/railties/test/application/initializers/hooks_test.rb +++ b/railties/test/application/initializers/hooks_test.rb @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf "#{app_path}/config/environments" end @@ -58,7 +57,7 @@ module ApplicationTests require "#{app_path}/config/environment" assert $activerecord_configurations - assert $activerecord_configurations['development'] + assert $activerecord_configurations["development"] end test "after_initialize happens after to_prepare in development" do diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 0f9bb41053..206e42703b 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf "#{app_path}/config/environments" require "rails/all" end @@ -31,7 +30,7 @@ module ApplicationTests end def assert_no_fallbacks - assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_not_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks end # Locales @@ -63,8 +62,8 @@ module ApplicationTests "#{app_path}/config/locales/en.yml", "#{app_path}/config/another_locale.yml" ], Rails.application.config.i18n.load_path - assert I18n.load_path.include?("#{app_path}/config/locales/en.yml") - assert I18n.load_path.include?("#{app_path}/config/another_locale.yml") + assert_includes I18n.load_path, "#{app_path}/config/locales/en.yml" + assert_includes I18n.load_path, "#{app_path}/config/another_locale.yml" end test "load_path is populated before eager loaded models" do @@ -77,19 +76,19 @@ en: foo: "1" YAML - app_file 'app/models/foo.rb', <<-RUBY + app_file "app/models/foo.rb", <<-RUBY class Foo < ActiveRecord::Base @foo = I18n.t(:foo) end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [Foo.instance_variable_get('@foo')]] } end RUBY - require 'rack/test' + require "rack/test" extend Rack::Test::Methods load_app @@ -107,13 +106,13 @@ en: foo: "1" YAML - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] } end RUBY - require 'rack/test' + require "rack/test" extend Rack::Test::Methods load_app @@ -142,13 +141,13 @@ en: foo: "1" YAML - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [I18n.t(:foo)]] } end RUBY - require 'rack/test' + require "rack/test" extend Rack::Test::Methods load_app @@ -178,13 +177,13 @@ en: foo: "1" YAML - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/i18n', :to => lambda { |env| [200, {}, [I18n.load_path.inspect]] } end RUBY - require 'rack/test' + require "rack/test" extend Rack::Test::Methods load_app @@ -215,7 +214,7 @@ fr: test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do I18n::Railtie.config.i18n.fallbacks = true load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks assert_fallbacks de: [:de, :en] end @@ -223,7 +222,7 @@ fr: I18n::Railtie.config.i18n.fallbacks = true I18n::Railtie.config.i18n.backend = Class.new(I18n::Backend::Simple).new load_app - assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks) + assert_includes I18n.backend.class.included_modules, I18n::Backend::Fallbacks assert_fallbacks de: [:de, :en] end @@ -234,7 +233,7 @@ fr: end test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do - I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } + I18n::Railtie.config.i18n.fallbacks.map = { ca: :'es-ES' } load_app assert_fallbacks ca: [:ca, :"es-ES", :es, :en] end @@ -246,13 +245,13 @@ fr: end test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping ca => es-ES" do - I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' } + I18n::Railtie.config.i18n.fallbacks.map = { ca: :'es-ES' } load_app assert_fallbacks ca: [:ca, :"es-ES", :es, :en] end test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do - I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] + I18n::Railtie.config.i18n.fallbacks = [:'en-US', { ca: :'es-ES' }] load_app assert_fallbacks ca: [:ca, :"es-ES", :es, :'en-US', :en] end diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb index cd05956356..dbefb22837 100644 --- a/railties/test/application/initializers/load_path_test.rb +++ b/railties/test/application/initializers/load_path_test.rb @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf "#{app_path}/config/environments" end @@ -20,7 +19,7 @@ module ApplicationTests RUBY require "#{app_path}/config/environment" - assert $:.include?("#{app_path}/app/models") + assert_includes $:, "#{app_path}/app/models" end test "initializing an application allows to load code on lib path inside application class definition" do @@ -37,7 +36,7 @@ module ApplicationTests require "#{app_path}/config/environment" end - assert $:.include?("#{app_path}/lib") + assert_includes $:, "#{app_path}/lib" end test "initializing an application eager load any path under app" do diff --git a/railties/test/application/initializers/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb index 95655b74cf..b847ac6b36 100644 --- a/railties/test/application/initializers/notifications_test.rb +++ b/railties/test/application/initializers/notifications_test.rb @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails end def teardown @@ -40,17 +39,17 @@ module ApplicationTests assert_match(/SHOW tables/, logger.logged(:debug).last) end - test 'rails load_config_initializer event is instrumented' do - app_file 'config/initializers/foo.rb', '' + test "rails load_config_initializer event is instrumented" do + app_file "config/initializers/foo.rb", "" events = [] callback = ->(*_) { events << _ } - ActiveSupport::Notifications.subscribed(callback, 'load_config_initializer.railties') do + ActiveSupport::Notifications.subscribed(callback, "load_config_initializer.railties") do app end assert_equal %w[load_config_initializer.railties], events.map(&:first) - assert_includes events.first.last[:initializer], 'config/initializers/foo.rb' + assert_includes events.first.last[:initializer], "config/initializers/foo.rb" end end end diff --git a/railties/test/application/integration_test_case_test.rb b/railties/test/application/integration_test_case_test.rb index d106d5159a..1118e5037a 100644 --- a/railties/test/application/integration_test_case_test.rb +++ b/railties/test/application/integration_test_case_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class IntegrationTestCaseTest < ActiveSupport::TestCase @@ -6,7 +6,6 @@ module ApplicationTests setup do build_app - boot_rails end teardown do @@ -14,9 +13,9 @@ module ApplicationTests end test "resets Action Mailer test deliveries" do - script('generate mailer BaseMailer welcome') + script("generate mailer BaseMailer welcome") - app_file 'test/integration/mailer_integration_test.rb', <<-RUBY + app_file "test/integration/mailer_integration_test.rb", <<-RUBY require 'test_helper' class MailerIntegrationTest < ActionDispatch::IntegrationTest @@ -43,4 +42,32 @@ module ApplicationTests assert_match(/0 failures, 0 errors/, output) end end + + class IntegrationTestDefaultApp < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + setup do + build_app + end + + teardown do + teardown_app + end + + test "app method of integration tests returns test_app by default" do + app_file "test/integration/default_app_test.rb", <<-RUBY + require 'test_helper' + + class DefaultAppIntegrationTest < ActionDispatch::IntegrationTest + def test_app_returns_action_dispatch_test_app_by_default + assert_equal ActionDispatch.test_app, app + end + end + RUBY + + output = Dir.chdir(app_path) { `bin/rails test 2>&1` } + assert_equal 0, $?.to_i, output + assert_match(/0 failures, 0 errors/, output) + end + end end diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index efb21ae473..38f96f3ab9 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -1,11 +1,10 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" class LoadingTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation def setup build_app - boot_rails end def teardown @@ -26,11 +25,11 @@ class LoadingTest < ActiveSupport::TestCase require "#{rails_root}/config/environment" setup_ar! - p = Post.create(title: 'omg') + p = Post.create(title: "omg") assert_equal 1, Post.count - assert_equal 'omg', p.title + assert_equal "omg", p.title p = Post.first - assert_equal 'omg', p.title + assert_equal "omg", p.title end test "concerns in app are autoloaded" do @@ -103,14 +102,14 @@ class LoadingTest < ActiveSupport::TestCase end MODEL - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/load', to: lambda { |env| [200, {}, Post.all] } get '/unload', to: lambda { |env| [200, {}, []] } end RUBY - require 'rack/test' + require "rack/test" extend Rack::Test::Methods require "#{rails_root}/config/environment" @@ -133,7 +132,7 @@ class LoadingTest < ActiveSupport::TestCase config.cache_classes = false RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end @@ -145,7 +144,7 @@ class LoadingTest < ActiveSupport::TestCase end MODEL - require 'rack/test' + require "rack/test" extend Rack::Test::Methods require "#{rails_root}/config/environment" @@ -174,7 +173,7 @@ class LoadingTest < ActiveSupport::TestCase end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] } end @@ -186,7 +185,7 @@ class LoadingTest < ActiveSupport::TestCase end MODEL - require 'rack/test' + require "rack/test" extend Rack::Test::Methods require "#{rails_root}/config/environment" @@ -209,7 +208,7 @@ class LoadingTest < ActiveSupport::TestCase config.cache_classes = false RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY $counter ||= 0 Rails.application.routes.draw do get '/c', to: lambda { |env| User.name; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] } @@ -222,7 +221,7 @@ class LoadingTest < ActiveSupport::TestCase end MODEL - require 'rack/test' + require "rack/test" extend Rack::Test::Methods require "#{rails_root}/config/environment" @@ -241,7 +240,7 @@ class LoadingTest < ActiveSupport::TestCase config.cache_classes = false RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY $counter ||= 1 $counter *= 2 Rails.application.routes.draw do @@ -255,7 +254,7 @@ class LoadingTest < ActiveSupport::TestCase end MODEL - require 'rack/test' + require "rack/test" extend Rack::Test::Methods require "#{rails_root}/config/environment" @@ -274,7 +273,7 @@ class LoadingTest < ActiveSupport::TestCase config.cache_classes = false RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/title', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.title]] } get '/body', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.body]] } @@ -286,7 +285,7 @@ class LoadingTest < ActiveSupport::TestCase end MODEL - require 'rack/test' + require "rack/test" extend Rack::Test::Methods app_file "db/migrate/1_create_posts.rb", <<-MIGRATION @@ -299,7 +298,7 @@ class LoadingTest < ActiveSupport::TestCase end MIGRATION - Dir.chdir(app_path) { `rake db:migrate`} + Dir.chdir(app_path) { `rake db:migrate` } require "#{rails_root}/config/environment" get "/title" @@ -341,11 +340,11 @@ class LoadingTest < ActiveSupport::TestCase require "#{rails_root}/config/environment" - require 'rack/test' + require "rack/test" extend Rack::Test::Methods - get '/omg/show' - assert_equal 'OK', last_response.body + get "/omg/show" + assert_equal "OK", last_response.body end def test_initialize_can_be_called_at_any_time @@ -360,13 +359,13 @@ class LoadingTest < ActiveSupport::TestCase protected - def setup_ar! - ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") - ActiveRecord::Migration.verbose = false - ActiveRecord::Schema.define(version: 1) do - create_table :posts do |t| - t.string :title + def setup_ar! + ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") + ActiveRecord::Migration.verbose = false + ActiveRecord::Schema.define(version: 1) do + create_table :posts do |t| + t.string :title + end end end - end end diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb index 643d876a26..790aca2aa4 100644 --- a/railties/test/application/mailer_previews_test.rb +++ b/railties/test/application/mailer_previews_test.rb @@ -1,6 +1,6 @@ -require 'isolation/abstract_unit' -require 'rack/test' -require 'base64' +require "isolation/abstract_unit" +require "rack/test" +require "base64" module ApplicationTests class MailerPreviewsTest < ActiveSupport::TestCase @@ -9,7 +9,6 @@ module ApplicationTests def setup build_app - boot_rails end def teardown @@ -28,10 +27,10 @@ module ApplicationTests assert_equal 404, last_response.status end - test "/rails/mailers is accessible with correct configuraiton" do + test "/rails/mailers is accessible with correct configuration" do add_to_config "config.action_mailer.show_previews = true" app("production") - get "/rails/mailers", {}, {"REMOTE_ADDR" => "4.2.42.42"} + get "/rails/mailers", {}, "REMOTE_ADDR" => "4.2.42.42" assert_equal 200, last_response.status end @@ -54,7 +53,7 @@ module ApplicationTests end test "mailer previews are loaded from the default preview_path" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -64,11 +63,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -76,7 +75,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers" assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body @@ -86,7 +85,7 @@ module ApplicationTests test "mailer previews are loaded from a custom preview_path" do add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -96,11 +95,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY + app_file "lib/mailer_previews/notifier_preview.rb", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -108,7 +107,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers" assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body @@ -116,12 +115,12 @@ module ApplicationTests end test "mailer previews are reloaded across requests" do - app('development') + app("development") get "/rails/mailers" assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -131,11 +130,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -146,7 +145,7 @@ module ApplicationTests get "/rails/mailers" assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body - remove_file 'test/mailers/previews/notifier_preview.rb' + remove_file "test/mailers/previews/notifier_preview.rb" sleep(1) get "/rails/mailers" @@ -154,7 +153,7 @@ module ApplicationTests end test "mailer preview actions are added and removed" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -164,11 +163,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -176,14 +175,14 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers" assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -197,15 +196,15 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - text_template 'notifier/bar', <<-RUBY + text_template "notifier/bar", <<-RUBY Goodbye, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -224,7 +223,7 @@ module ApplicationTests assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body assert_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -234,9 +233,9 @@ module ApplicationTests end RUBY - remove_file 'app/views/notifier/bar.text.erb' + remove_file "app/views/notifier/bar.text.erb" - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -255,12 +254,12 @@ module ApplicationTests test "mailer previews are reloaded from a custom preview_path" do add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" - app('development') + app("development") get "/rails/mailers" assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -270,11 +269,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY + app_file "lib/mailer_previews/notifier_preview.rb", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -285,7 +284,7 @@ module ApplicationTests get "/rails/mailers" assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body - remove_file 'lib/mailer_previews/notifier_preview.rb' + remove_file "lib/mailer_previews/notifier_preview.rb" sleep(1) get "/rails/mailers" @@ -293,14 +292,14 @@ module ApplicationTests end test "mailer preview not found" do - app('development') + app("development") get "/rails/mailers/notifier" assert last_response.not_found? assert_match "Mailer preview 'notifier' not found", last_response.body end test "mailer preview email not found" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -310,11 +309,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -322,7 +321,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/bar" assert last_response.not_found? @@ -330,7 +329,7 @@ module ApplicationTests end test "mailer preview NullMail" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -340,7 +339,7 @@ module ApplicationTests end RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -348,7 +347,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo" assert_match "You are trying to preview an email that does not have any content.", last_response.body @@ -356,7 +355,7 @@ module ApplicationTests end test "mailer preview email part not found" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -366,11 +365,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -378,7 +377,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo?part=text%2Fhtml" assert last_response.not_found? @@ -386,7 +385,7 @@ module ApplicationTests end test "message header uses full display names" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "Ruby on Rails <core@rubyonrails.org>" @@ -397,11 +396,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -409,7 +408,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo" assert_equal 200, last_response.status @@ -419,7 +418,7 @@ module ApplicationTests end test "part menu selects correct option" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -429,15 +428,15 @@ module ApplicationTests end RUBY - html_template 'notifier/foo', <<-RUBY + html_template "notifier/foo", <<-RUBY <p>Hello, World!</p> RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -445,7 +444,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo.html" assert_equal 200, last_response.status @@ -457,7 +456,7 @@ module ApplicationTests end test "mailer previews create correct links when loaded on a subdirectory" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -467,11 +466,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -479,9 +478,9 @@ module ApplicationTests end RUBY - app('development') + app("development") - get "/rails/mailers", {}, 'SCRIPT_NAME' => '/my_app' + get "/rails/mailers", {}, "SCRIPT_NAME" => "/my_app" assert_match '<h3><a href="/my_app/rails/mailers/notifier">Notifier</a></h3>', last_response.body assert_match '<li><a href="/my_app/rails/mailers/notifier/foo">foo</a></li>', last_response.body end @@ -489,7 +488,7 @@ module ApplicationTests test "plain text mailer preview with attachment" do image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo=" - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -500,11 +499,11 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -512,7 +511,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo" assert_equal 200, last_response.status @@ -526,7 +525,7 @@ module ApplicationTests test "multipart mailer preview with attachment" do image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo=" - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -537,15 +536,15 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - html_template 'notifier/foo', <<-RUBY + html_template "notifier/foo", <<-RUBY <p>Hello, World!</p> RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -553,7 +552,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo" assert_equal 200, last_response.status @@ -571,7 +570,7 @@ module ApplicationTests test "multipart mailer preview with inline attachment" do image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo=" - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -582,16 +581,16 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - html_template 'notifier/foo', <<-RUBY + html_template "notifier/foo", <<-RUBY <p>Hello, World!</p> <%= image_tag attachments['pixel.png'].url %> RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -599,7 +598,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo" assert_equal 200, last_response.status @@ -616,7 +615,7 @@ module ApplicationTests end test "multipart mailer preview with attached email" do - mailer 'notifier', <<-RUBY + mailer "notifier", <<-RUBY class Notifier < ActionMailer::Base default from: "from@example.com" @@ -641,15 +640,15 @@ module ApplicationTests end RUBY - text_template 'notifier/foo', <<-RUBY + text_template "notifier/foo", <<-RUBY Hello, World! RUBY - html_template 'notifier/foo', <<-RUBY + html_template "notifier/foo", <<-RUBY <p>Hello, World!</p> RUBY - mailer_preview 'notifier', <<-RUBY + mailer_preview "notifier", <<-RUBY class NotifierPreview < ActionMailer::Preview def foo Notifier.foo @@ -657,7 +656,7 @@ module ApplicationTests end RUBY - app('development') + app("development") get "/rails/mailers/notifier/foo" assert_equal 200, last_response.status @@ -695,7 +694,7 @@ module ApplicationTests end def image_file(name, contents) - app_file("public/images/#{name}", Base64.strict_decode64(contents), 'wb') + app_file("public/images/#{name}", Base64.strict_decode64(contents), "wb") end end end diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb index c951dabd6c..dc1d816dc5 100644 --- a/railties/test/application/middleware/cache_test.rb +++ b/railties/test/application/middleware/cache_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class CacheTest < ActiveSupport::TestCase @@ -6,8 +6,7 @@ module ApplicationTests def setup build_app - boot_rails - require 'rack/test' + require "rack/test" extend Rack::Test::Methods end @@ -20,7 +19,7 @@ module ApplicationTests class ExpiresController < ApplicationController def expires_header expires_in 10, public: !params[:private] - render text: SecureRandom.hex(16) + render plain: SecureRandom.hex(16) end def expires_etag @@ -33,18 +32,18 @@ module ApplicationTests end def keeps_if_modified_since - render :text => request.headers['If-Modified-Since'] + render plain: request.headers['If-Modified-Since'] end private def render_conditionally(headers) if stale?(headers.merge(public: !params[:private])) - render text: SecureRandom.hex(16) + render plain: SecureRandom.hex(16) end end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end @@ -66,12 +65,12 @@ module ApplicationTests app("development") get "/expires/expires_header" - assert_nil last_response.headers['X-Rack-Cache'] + assert_nil last_response.headers["X-Rack-Cache"] body = last_response.body get "/expires/expires_header" - assert_nil last_response.headers['X-Rack-Cache'] + assert_nil last_response.headers["X-Rack-Cache"] assert_not_equal body, last_response.body end @@ -138,7 +137,7 @@ module ApplicationTests body = last_response.body etag = last_response.headers["ETag"] - get "/expires/expires_etag", {private: true}, "If-None-Match" => etag + get "/expires/expires_etag", { private: true }, "If-None-Match" => etag assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_not_equal body, last_response.body end @@ -172,7 +171,7 @@ module ApplicationTests body = last_response.body last = last_response.headers["Last-Modified"] - get "/expires/expires_last_modified", {private: true}, "If-Modified-Since" => last + get "/expires/expires_last_modified", { private: true }, "If-Modified-Since" => last assert_equal "miss", last_response.headers["X-Rack-Cache"] assert_not_equal body, last_response.body end diff --git a/railties/test/application/middleware/cookies_test.rb b/railties/test/application/middleware/cookies_test.rb index bbb7627be9..1e4b5d086c 100644 --- a/railties/test/application/middleware/cookies_test.rb +++ b/railties/test/application/middleware/cookies_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class CookiesTest < ActiveSupport::TestCase @@ -10,7 +10,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf("#{app_path}/config/environments") end @@ -19,27 +18,27 @@ module ApplicationTests FileUtils.rm_rf(new_app) if File.directory?(new_app) end - test 'always_write_cookie is true by default in development' do - require 'rails' - Rails.env = 'development' + test "always_write_cookie is true by default in development" do + require "rails" + Rails.env = "development" require "#{app_path}/config/environment" assert_equal true, ActionDispatch::Cookies::CookieJar.always_write_cookie end - test 'always_write_cookie is false by default in production' do - require 'rails' - Rails.env = 'production' + test "always_write_cookie is false by default in production" do + require "rails" + Rails.env = "production" require "#{app_path}/config/environment" assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie end - test 'always_write_cookie can be overridden' do + test "always_write_cookie can be overridden" do add_to_config <<-RUBY config.action_dispatch.always_write_cookie = false RUBY - require 'rails' - Rails.env = 'development' + require "rails" + Rails.env = "development" require "#{app_path}/config/environment" assert_equal false, ActionDispatch::Cookies::CookieJar.always_write_cookie end diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index 639b01b562..cbb990f13b 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -1,5 +1,5 @@ -require 'isolation/abstract_unit' -require 'rack/test' +require "isolation/abstract_unit" +require "rack/test" module ApplicationTests class MiddlewareExceptionsTest < ActiveSupport::TestCase @@ -8,7 +8,6 @@ module ApplicationTests def setup build_app - boot_rails end def teardown @@ -70,7 +69,7 @@ module ApplicationTests app.config.action_dispatch.show_exceptions = true - get '/foo' + get "/foo" assert_equal 500, last_response.status end @@ -78,7 +77,7 @@ module ApplicationTests app.config.action_dispatch.show_exceptions = false assert_raise(ActionController::RoutingError) do - get '/foo' + get "/foo" end end @@ -86,7 +85,7 @@ module ApplicationTests app.config.action_dispatch.show_exceptions = true assert_nothing_raised do - get '/foo' + get "/foo" assert_match "The page you were looking for doesn't exist.", last_response.body end end @@ -96,7 +95,7 @@ module ApplicationTests app.config.consider_all_requests_local = true assert_nothing_raised do - get '/foo' + get "/foo" assert_match "No route matches", last_response.body end end @@ -112,12 +111,12 @@ module ApplicationTests app.config.action_dispatch.show_exceptions = true app.config.consider_all_requests_local = true - app_file 'app/views/foo/index.html.erb', <<-ERB + app_file "app/views/foo/index.html.erb", <<-ERB <% raise 'boooom' %> ✓測試テスト시험 ERB - get '/foo', :utf8 => '✓' + get "/foo", utf8: "✓" assert_match(/boooom/, last_response.body) assert_match(/測試テスト시험/, last_response.body) end diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb index 37bd8a25c1..c34d9d6ee7 100644 --- a/railties/test/application/middleware/remote_ip_test.rb +++ b/railties/test/application/middleware/remote_ip_test.rb @@ -1,6 +1,6 @@ -require 'ipaddr' -require 'isolation/abstract_unit' -require 'active_support/key_generator' +require "ipaddr" +require "isolation/abstract_unit" +require "active_support/key_generator" module ApplicationTests class RemoteIpTest < ActiveSupport::TestCase @@ -9,8 +9,8 @@ module ApplicationTests def remote_ip(env = {}) remote_ip = nil env = Rack::MockRequest.env_for("/").merge(env).merge!( - 'action_dispatch.show_exceptions' => false, - 'action_dispatch.key_generator' => ActiveSupport::LegacyKeyGenerator.new('b3c631c314c0bbca50c1b2843150fe33') + "action_dispatch.show_exceptions" => false, + "action_dispatch.key_generator" => ActiveSupport::LegacyKeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33") ) endpoint = Proc.new do |e| @@ -69,7 +69,7 @@ module ApplicationTests test "the user can set trusted proxies with an IPAddr argument" do make_basic_app do |app| - app.config.action_dispatch.trusted_proxies = IPAddr.new('4.2.42.0/24') + app.config.action_dispatch.trusted_proxies = IPAddr.new("4.2.42.0/24") end assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "10.0.0.0,4.2.42.42") diff --git a/railties/test/application/middleware/sendfile_test.rb b/railties/test/application/middleware/sendfile_test.rb index be86f1a3b8..4938402fdc 100644 --- a/railties/test/application/middleware/sendfile_test.rb +++ b/railties/test/application/middleware/sendfile_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class SendfileTest < ActiveSupport::TestCase @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf "#{app_path}/config/environments" end @@ -49,7 +48,7 @@ module ApplicationTests test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do make_basic_app do |app| - app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File' + app.config.action_dispatch.x_sendfile_header = "X-Lighttpd-Send-File" end simple_controller @@ -60,7 +59,7 @@ module ApplicationTests test "files handled by ActionDispatch::Static are handled by Rack::Sendfile" do make_basic_app do |app| - app.config.action_dispatch.x_sendfile_header = 'X-Sendfile' + app.config.action_dispatch.x_sendfile_header = "X-Sendfile" app.config.public_file_server.enabled = true app.paths["public"] = File.join(rails_root, "public") end diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 85e7761727..0e4acfdcec 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -1,5 +1,5 @@ -require 'isolation/abstract_unit' -require 'rack/test' +require "isolation/abstract_unit" +require "rack/test" module ApplicationTests class MiddlewareSessionTest < ActiveSupport::TestCase @@ -8,7 +8,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf "#{app_path}/config/environments" end @@ -54,7 +53,7 @@ module ApplicationTests end test "session is empty and isn't saved on unverified request when using :null_session protect method" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' post ':controller(/:action)' @@ -71,7 +70,7 @@ module ApplicationTests end def read_session - render text: session[:foo].inspect + render plain: session[:foo].inspect end end RUBY @@ -82,20 +81,20 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/foo/write_session' - get '/foo/read_session' - assert_equal '1', last_response.body + get "/foo/write_session" + get "/foo/read_session" + assert_equal "1", last_response.body - post '/foo/read_session' # Read session using POST request without CSRF token - assert_equal 'nil', last_response.body # Stored value shouldn't be accessible + post "/foo/read_session" # Read session using POST request without CSRF token + assert_equal "nil", last_response.body # Stored value shouldn't be accessible - post '/foo/write_session' # Write session using POST request without CSRF token - get '/foo/read_session' # Session shouldn't be changed - assert_equal '1', last_response.body + post "/foo/write_session" # Write session using POST request without CSRF token + get "/foo/read_session" # Session shouldn't be changed + assert_equal "1", last_response.body end test "cookie jar is empty and isn't saved on unverified request when using :null_session protect method" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' post ':controller(/:action)' @@ -112,7 +111,7 @@ module ApplicationTests end def read_cookie - render text: cookies[:foo].inspect + render plain: cookies[:foo].inspect end end RUBY @@ -123,20 +122,20 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/foo/write_cookie' - get '/foo/read_cookie' + get "/foo/write_cookie" + get "/foo/read_cookie" assert_equal '"1"', last_response.body - post '/foo/read_cookie' # Read cookie using POST request without CSRF token - assert_equal 'nil', last_response.body # Stored value shouldn't be accessible + post "/foo/read_cookie" # Read cookie using POST request without CSRF token + assert_equal "nil", last_response.body # Stored value shouldn't be accessible - post '/foo/write_cookie' # Write cookie using POST request without CSRF token - get '/foo/read_cookie' # Cookie shouldn't be changed + post "/foo/write_cookie" # Write cookie using POST request without CSRF token + get "/foo/read_cookie" # Cookie shouldn't be changed assert_equal '"1"', last_response.body end test "session using encrypted cookie store" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end @@ -150,38 +149,38 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_encrypted_cookie - render text: cookies.encrypted[:_myapp_session]['foo'] + render plain: cookies.encrypted[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY require "#{app_path}/config/environment" - get '/foo/write_session' - get '/foo/read_session' - assert_equal '1', last_response.body + get "/foo/write_session" + get "/foo/read_session" + assert_equal "1", last_response.body - get '/foo/read_encrypted_cookie' - assert_equal '1', last_response.body + get "/foo/read_encrypted_cookie" + assert_equal "1", last_response.body - secret = app.key_generator.generate_key('encrypted cookie') - sign_secret = app.key_generator.generate_key('signed encrypted cookie') + secret = app.key_generator.generate_key("encrypted cookie") + sign_secret = app.key_generator.generate_key("signed encrypted cookie") encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) - get '/foo/read_raw_cookie' - assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo'] + get "/foo/read_raw_cookie" + assert_equal 1, encryptor.decrypt_and_verify(last_response.body)["foo"] end test "session upgrading signature to encryption cookie store works the same way as encrypted cookie store" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end @@ -195,15 +194,15 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_encrypted_cookie - render text: cookies.encrypted[:_myapp_session]['foo'] + render plain: cookies.encrypted[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY @@ -214,23 +213,23 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/foo/write_session' - get '/foo/read_session' - assert_equal '1', last_response.body + get "/foo/write_session" + get "/foo/read_session" + assert_equal "1", last_response.body - get '/foo/read_encrypted_cookie' - assert_equal '1', last_response.body + get "/foo/read_encrypted_cookie" + assert_equal "1", last_response.body - secret = app.key_generator.generate_key('encrypted cookie') - sign_secret = app.key_generator.generate_key('signed encrypted cookie') + secret = app.key_generator.generate_key("encrypted cookie") + sign_secret = app.key_generator.generate_key("signed encrypted cookie") encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) - get '/foo/read_raw_cookie' - assert_equal 1, encryptor.decrypt_and_verify(last_response.body)['foo'] + get "/foo/read_raw_cookie" + assert_equal 1, encryptor.decrypt_and_verify(last_response.body)["foo"] end test "session upgrading signature to encryption cookie store upgrades session to encrypted mode" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end @@ -250,15 +249,15 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_encrypted_cookie - render text: cookies.encrypted[:_myapp_session]['foo'] + render plain: cookies.encrypted[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY @@ -269,27 +268,27 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/foo/write_raw_session' - get '/foo/read_session' - assert_equal '1', last_response.body + get "/foo/write_raw_session" + get "/foo/read_session" + assert_equal "1", last_response.body - get '/foo/write_session' - get '/foo/read_session' - assert_equal '2', last_response.body + get "/foo/write_session" + get "/foo/read_session" + assert_equal "2", last_response.body - get '/foo/read_encrypted_cookie' - assert_equal '2', last_response.body + get "/foo/read_encrypted_cookie" + assert_equal "2", last_response.body - secret = app.key_generator.generate_key('encrypted cookie') - sign_secret = app.key_generator.generate_key('signed encrypted cookie') + secret = app.key_generator.generate_key("encrypted cookie") + sign_secret = app.key_generator.generate_key("signed encrypted cookie") encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) - get '/foo/read_raw_cookie' - assert_equal 2, encryptor.decrypt_and_verify(last_response.body)['foo'] + get "/foo/read_raw_cookie" + assert_equal 2, encryptor.decrypt_and_verify(last_response.body)["foo"] end test "session upgrading legacy signed cookies to new signed cookies" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end @@ -309,15 +308,15 @@ module ApplicationTests end def read_session - render text: session[:foo] + render plain: session[:foo] end def read_signed_cookie - render text: cookies.signed[:_myapp_session]['foo'] + render plain: cookies.signed[:_myapp_session]['foo'] end def read_raw_cookie - render text: cookies[:_myapp_session] + render plain: cookies[:_myapp_session] end end RUBY @@ -329,25 +328,25 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/foo/write_raw_session' - get '/foo/read_session' - assert_equal '1', last_response.body + get "/foo/write_raw_session" + get "/foo/read_session" + assert_equal "1", last_response.body - get '/foo/write_session' - get '/foo/read_session' - assert_equal '2', last_response.body + get "/foo/write_session" + get "/foo/read_session" + assert_equal "2", last_response.body - get '/foo/read_signed_cookie' - assert_equal '2', last_response.body + get "/foo/read_signed_cookie" + assert_equal "2", last_response.body verifier = ActiveSupport::MessageVerifier.new(app.secrets.secret_token) - get '/foo/read_raw_cookie' - assert_equal 2, verifier.verify(last_response.body)['foo'] + get "/foo/read_raw_cookie" + assert_equal 2, verifier.verify(last_response.body)["foo"] end - test 'calling reset_session on request does not trigger an error for API apps' do - add_to_config 'config.api_only = true' + test "calling reset_session on request does not trigger an error for API apps" do + add_to_config "config.api_only = true" controller :test, <<-RUBY class TestController < ApplicationController @@ -358,7 +357,7 @@ module ApplicationTests end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/dump_flash' => "test#dump_flash" end @@ -366,12 +365,18 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/dump_flash' + get "/dump_flash" assert_equal 200, last_response.status - assert_equal 'It worked!', last_response.body + assert_equal "It worked!", last_response.body - refute Rails.application.middleware.include?(ActionDispatch::Flash) + assert_not_includes Rails.application.middleware, ActionDispatch::Flash + end + + test "cookie_only is set to true even if user tries to overwrite it" do + add_to_config "config.session_store :cookie_store, key: '_myapp_session', cookie_only: false" + require "#{app_path}/config/environment" + assert app.config.session_options[:cookie_only], "Expected cookie_only to be set to true" end end end diff --git a/railties/test/application/middleware/static_test.rb b/railties/test/application/middleware/static_test.rb index 1246e20d94..5cd3e4325e 100644 --- a/railties/test/application/middleware/static_test.rb +++ b/railties/test/application/middleware/static_test.rb @@ -1,5 +1,5 @@ -require 'isolation/abstract_unit' -require 'rack/test' +require "isolation/abstract_unit" +require "rack/test" module ApplicationTests class MiddlewareStaticTest < ActiveSupport::TestCase @@ -18,17 +18,17 @@ module ApplicationTests # Regression test to #8907 # See https://github.com/rails/rails/commit/9cc82b77196d21a5c7021f6dca59ab9b2b158a45#commitcomment-2416514 test "doesn't set Cache-Control header when it is nil" do - app_file "public/foo.html", 'static' + app_file "public/foo.html", "static" require "#{app_path}/config/environment" - get 'foo' + get "foo" - assert_not last_response.headers.has_key?('Cache-Control'), "Cache-Control should not be set" + assert_not last_response.headers.has_key?("Cache-Control"), "Cache-Control should not be set" end test "headers for static files are configurable" do - app_file "public/about.html", 'static' + app_file "public/about.html", "static" add_to_config <<-CONFIG config.public_file_server.headers = { "Access-Control-Allow-Origin" => "http://rubyonrails.org", @@ -38,19 +38,19 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/about.html' + get "/about.html" - assert_equal 'http://rubyonrails.org', last_response.headers["Access-Control-Allow-Origin"] - assert_equal 'public, max-age=60', last_response.headers["Cache-Control"] + assert_equal "http://rubyonrails.org", last_response.headers["Access-Control-Allow-Origin"] + assert_equal "public, max-age=60", last_response.headers["Cache-Control"] end test "public_file_server.index_name defaults to 'index'" do app_file "public/index.html", "/index.html" - + require "#{app_path}/config/environment" - get '/' - + get "/" + assert_equal "/index.html\n", last_response.body end @@ -60,7 +60,7 @@ module ApplicationTests require "#{app_path}/config/environment" - get '/' + get "/" assert_equal "/other-index.html\n", last_response.body end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 7a86a96e19..9baf7360a5 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class MiddlewareTest < ActiveSupport::TestCase @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf "#{app_path}/config/environments" end @@ -74,7 +73,7 @@ module ApplicationTests test "Rack::Cache is not included by default" do boot! - assert !middleware.include?("Rack::Cache"), "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache" + assert_not_includes middleware, "Rack::Cache", "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache" end test "Rack::Cache is present when action_dispatch.rack_cache is set" do @@ -82,7 +81,7 @@ module ApplicationTests boot! - assert middleware.include?("Rack::Cache") + assert_includes middleware, "Rack::Cache" end test "ActiveRecord::Migration::CheckPending is present when active_record.migration_error is set to :page_load" do @@ -90,27 +89,27 @@ module ApplicationTests boot! - assert middleware.include?("ActiveRecord::Migration::CheckPending") + assert_includes middleware, "ActiveRecord::Migration::CheckPending" end test "ActionDispatch::SSL is present when force_ssl is set" do add_to_config "config.force_ssl = true" boot! - assert middleware.include?("ActionDispatch::SSL") + assert_includes middleware, "ActionDispatch::SSL" end test "ActionDispatch::SSL is configured with options when given" do add_to_config "config.force_ssl = true" - add_to_config "config.ssl_options = { host: 'example.com' }" + add_to_config "config.ssl_options = { redirect: { host: 'example.com' } }" boot! - assert_equal [{host: 'example.com'}], Rails.application.middleware.first.args + assert_equal [{ redirect: { host: "example.com" } }], Rails.application.middleware.first.args end test "removing Active Record omits its middleware" do use_frameworks [] boot! - assert !middleware.include?("ActiveRecord::Migration::CheckPending") + assert_not_includes middleware, "ActiveRecord::Migration::CheckPending" end test "includes executor" do @@ -140,20 +139,20 @@ module ApplicationTests test "removes static asset server if public_file_server.enabled is disabled" do add_to_config "config.public_file_server.enabled = false" boot! - assert !middleware.include?("ActionDispatch::Static") + assert_not_includes middleware, "ActionDispatch::Static" end test "can delete a middleware from the stack" do add_to_config "config.middleware.delete ActionDispatch::Static" boot! - assert !middleware.include?("ActionDispatch::Static") + assert_not_includes middleware, "ActionDispatch::Static" end test "can delete a middleware from the stack even if insert_before is added after delete" do add_to_config "config.middleware.delete Rack::Runtime" add_to_config "config.middleware.insert_before(Rack::Runtime, Rack::Config)" boot! - assert middleware.include?("Rack::Config") + assert_includes middleware, "Rack::Config" assert_not middleware.include?("Rack::Runtime") end @@ -161,21 +160,21 @@ module ApplicationTests add_to_config "config.middleware.delete Rack::Runtime" add_to_config "config.middleware.insert_after(Rack::Runtime, Rack::Config)" boot! - assert middleware.include?("Rack::Config") + assert_includes middleware, "Rack::Config" assert_not middleware.include?("Rack::Runtime") end test "includes exceptions middlewares even if action_dispatch.show_exceptions is disabled" do add_to_config "config.action_dispatch.show_exceptions = false" boot! - assert middleware.include?("ActionDispatch::ShowExceptions") - assert middleware.include?("ActionDispatch::DebugExceptions") + assert_includes middleware, "ActionDispatch::ShowExceptions" + assert_includes middleware, "ActionDispatch::DebugExceptions" end test "removes ActionDispatch::Reloader if cache_classes is true" do add_to_config "config.cache_classes = true" boot! - assert !middleware.include?("ActionDispatch::Reloader") + assert_not_includes middleware, "ActionDispatch::Reloader" end test "use middleware" do @@ -191,10 +190,10 @@ module ApplicationTests assert_equal "Rack::Config", middleware.second end - test 'unshift middleware' do - add_to_config 'config.middleware.unshift Rack::Config' + test "unshift middleware" do + add_to_config "config.middleware.unshift Rack::Config" boot! - assert_equal 'Rack::Config', middleware.first + assert_equal "Rack::Config", middleware.first end test "Rails.cache does not respond to middleware" do @@ -228,9 +227,9 @@ module ApplicationTests class ::OmgController < ActionController::Base def index if params[:nothing] - render text: "" + render plain: "" else - render text: "OMG" + render plain: "OMG" end end end @@ -240,7 +239,7 @@ module ApplicationTests get "/" assert_equal 200, last_response.status assert_equal "OMG", last_response.body - assert_equal "text/html; charset=utf-8", last_response.headers["Content-Type"] + assert_equal "text/plain; charset=utf-8", last_response.headers["Content-Type"] assert_equal "max-age=0, private, must-revalidate", last_response.headers["Cache-Control"] assert_equal etag, last_response.headers["Etag"] @@ -254,7 +253,7 @@ module ApplicationTests get "/?nothing=true" assert_equal 200, last_response.status assert_equal "", last_response.body - assert_equal "text/html; charset=utf-8", last_response.headers["Content-Type"] + assert_equal "text/plain; charset=utf-8", last_response.headers["Content-Type"] assert_equal "no-cache", last_response.headers["Cache-Control"] assert_equal nil, last_response.headers["Etag"] end diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb index f2770a9cb4..26b810af73 100644 --- a/railties/test/application/multiple_applications_test.rb +++ b/railties/test/application/multiple_applications_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class MultipleApplicationsTest < ActiveSupport::TestCase @@ -6,9 +6,8 @@ module ApplicationTests def setup build_app(initializers: true) - boot_rails require "#{rails_root}/config/environment" - Rails.application.config.some_setting = 'something_or_other' + Rails.application.config.some_setting = "something_or_other" end def teardown @@ -88,9 +87,9 @@ module ApplicationTests require "#{app_path}/config/environment" assert_equal 0, run_count, "The count should stay at zero without any calls to the rake tasks" - require 'rake' - require 'rake/testtask' - require 'rdoc/task' + require "rake" + require "rake/testtask" + require "rdoc/task" Rails.application.load_tasks assert_equal 2, run_count, "Calling a rake task should result in two increments to the count" end diff --git a/railties/test/application/paths_test.rb b/railties/test/application/paths_test.rb index 4029984ce9..515205296c 100644 --- a/railties/test/application/paths_test.rb +++ b/railties/test/application/paths_test.rb @@ -6,7 +6,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf("#{app_path}/config/environments") app_file "config/environments/development.rb", "" add_to_config <<-RUBY @@ -56,9 +55,9 @@ module ApplicationTests test "booting up Rails yields a list of paths that are eager" do eager_load = @paths.eager_load - assert eager_load.include?(root("app/controllers")) - assert eager_load.include?(root("app/helpers")) - assert eager_load.include?(root("app/models")) + assert_includes eager_load, root("app/controllers") + assert_includes eager_load, root("app/helpers") + assert_includes eager_load, root("app/models") end test "environments has a glob equal to the current environment" do diff --git a/railties/test/application/per_request_digest_cache_test.rb b/railties/test/application/per_request_digest_cache_test.rb index dfe3fc9354..6c003e9bcc 100644 --- a/railties/test/application/per_request_digest_cache_test.rb +++ b/railties/test/application/per_request_digest_cache_test.rb @@ -1,9 +1,9 @@ -require 'isolation/abstract_unit' -require 'rack/test' -require 'minitest/mock' +require "isolation/abstract_unit" +require "rack/test" +require "minitest/mock" -require 'action_view' -require 'active_support/testing/method_call_assertions' +require "action_view" +require "active_support/testing/method_call_assertions" class PerRequestDigestCacheTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -12,22 +12,22 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase setup do build_app - add_to_config 'config.consider_all_requests_local = true' + add_to_config "config.consider_all_requests_local = true" - app_file 'app/models/customer.rb', <<-RUBY + app_file "app/models/customer.rb", <<-RUBY class Customer < Struct.new(:name, :id) extend ActiveModel::Naming include ActiveModel::Conversion end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do resources :customers, only: :index end RUBY - app_file 'app/controllers/customers_controller.rb', <<-RUBY + app_file "app/controllers/customers_controller.rb", <<-RUBY class CustomersController < ApplicationController self.perform_caching = true @@ -37,7 +37,7 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase end RUBY - app_file 'app/views/customers/_customer.html.erb', <<-RUBY + app_file "app/views/customers/_customer.html.erb", <<-RUBY <% cache customer do %> <%= customer.name %> <% end %> @@ -49,17 +49,17 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase teardown :teardown_app test "digests are reused when rendering the same template twice" do - get '/customers' + get "/customers" assert_equal 200, last_response.status values = ActionView::LookupContext::DetailsKey.digest_caches.first.values - assert_equal [ '8ba099b7749542fe765ff34a6824d548' ], values + assert_equal [ "8ba099b7749542fe765ff34a6824d548" ], values assert_equal %w(david dingus), last_response.body.split.map(&:strip) end test "template digests are cleared before a request" do assert_called(ActionView::LookupContext::DetailsKey, :clear) do - get '/customers' + get "/customers" assert_equal 200, last_response.status end end diff --git a/railties/test/application/rack/logger_test.rb b/railties/test/application/rack/logger_test.rb index 0082ec9cd2..e71bcbc536 100644 --- a/railties/test/application/rack/logger_test.rb +++ b/railties/test/application/rack/logger_test.rb @@ -41,13 +41,13 @@ module ApplicationTests end test "logger logs HTTP verb override" do - post "/", _method: 'put' + post "/", _method: "put" wait assert_match 'Started PUT "/"', logs end test "logger logs HEAD requests" do - post "/", _method: 'head' + post "/", _method: "head" wait assert_match 'Started HEAD "/"', logs end diff --git a/railties/test/application/rackup_test.rb b/railties/test/application/rackup_test.rb index 49ac9fc66c..2943e9ee5d 100644 --- a/railties/test/application/rackup_test.rb +++ b/railties/test/application/rackup_test.rb @@ -12,14 +12,13 @@ module ApplicationTests def setup build_app - boot_rails end def teardown teardown_app end - test "rails app is present" do + test "Rails app is present" do assert File.exist?(app_path("config")) end @@ -37,7 +36,7 @@ module ApplicationTests test "the config object is available on the application object" do rackup - assert_equal 'UTC', Rails.application.config.time_zone + assert_equal "UTC", Rails.application.config.time_zone end end end diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index cee9db5535..51db634b75 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -8,7 +8,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf("#{app_path}/config/environments") end @@ -21,7 +20,7 @@ module ApplicationTests end def set_database_url - ENV['DATABASE_URL'] = "sqlite3:#{database_url_db_name}" + ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" # ensure it's using the DATABASE_URL FileUtils.rm_rf("#{app_path}/config/database.yml") end @@ -38,12 +37,12 @@ module ApplicationTests end end - test 'db:create and db:drop without database url' do + test "db:create and db:drop without database url" do require "#{app_path}/config/environment" - db_create_and_drop ActiveRecord::Base.configurations[Rails.env]['database'] + db_create_and_drop ActiveRecord::Base.configurations[Rails.env]["database"] end - test 'db:create and db:drop with database url' do + test "db:create and db:drop with database url" do require "#{app_path}/config/environment" set_database_url db_create_and_drop database_url_db_name @@ -58,7 +57,7 @@ module ApplicationTests end end - test 'db:create failure because database exists' do + test "db:create failure because database exists" do with_database_existing do output = `bin/rails db:create 2>&1` assert_match(/already exists/, output) @@ -75,7 +74,7 @@ module ApplicationTests end end - test 'db:create failure because bad permissions' do + test "db:create failure because bad permissions" do with_bad_permissions do output = `bin/rails db:create 2>&1` assert_match(/Couldn't create database/, output) @@ -83,7 +82,7 @@ module ApplicationTests end end - test 'db:drop failure because database does not exist' do + test "db:drop failure because database does not exist" do Dir.chdir(app_path) do output = `bin/rails db:drop:_unsafe --trace 2>&1` assert_match(/does not exist/, output) @@ -91,7 +90,7 @@ module ApplicationTests end end - test 'db:drop failure because bad permissions' do + test "db:drop failure because bad permissions" do with_database_existing do with_bad_permissions do output = `bin/rails db:drop 2>&1` @@ -111,12 +110,12 @@ module ApplicationTests end end - test 'db:migrate and db:migrate:status without database_url' do + test "db:migrate and db:migrate:status without database_url" do require "#{app_path}/config/environment" - db_migrate_and_status ActiveRecord::Base.configurations[Rails.env]['database'] + db_migrate_and_status ActiveRecord::Base.configurations[Rails.env]["database"] end - test 'db:migrate and db:migrate:status with database_url' do + test "db:migrate and db:migrate:status with database_url" do require "#{app_path}/config/environment" set_database_url db_migrate_and_status database_url_db_name @@ -131,11 +130,11 @@ module ApplicationTests end end - test 'db:schema:dump without database_url' do + test "db:schema:dump without database_url" do db_schema_dump end - test 'db:schema:dump with database_url' do + test "db:schema:dump with database_url" do set_database_url db_schema_dump end @@ -150,18 +149,18 @@ module ApplicationTests end end - test 'db:fixtures:load without database_url' do + test "db:fixtures:load without database_url" do require "#{app_path}/config/environment" - db_fixtures_load ActiveRecord::Base.configurations[Rails.env]['database'] + db_fixtures_load ActiveRecord::Base.configurations[Rails.env]["database"] end - test 'db:fixtures:load with database_url' do + test "db:fixtures:load with database_url" do require "#{app_path}/config/environment" set_database_url db_fixtures_load database_url_db_name end - test 'db:fixtures:load with namespaced fixture' do + test "db:fixtures:load with namespaced fixture" do require "#{app_path}/config/environment" Dir.chdir(app_path) do `bin/rails generate model admin::book title:string; @@ -185,18 +184,18 @@ module ApplicationTests end end - test 'db:structure:dump and db:structure:load without database_url' do + test "db:structure:dump and db:structure:load without database_url" do require "#{app_path}/config/environment" - db_structure_dump_and_load ActiveRecord::Base.configurations[Rails.env]['database'] + db_structure_dump_and_load ActiveRecord::Base.configurations[Rails.env]["database"] end - test 'db:structure:dump and db:structure:load with database_url' do + test "db:structure:dump and db:structure:load with database_url" do require "#{app_path}/config/environment" set_database_url db_structure_dump_and_load database_url_db_name end - test 'db:structure:dump does not dump schema information when no migrations are used' do + test "db:structure:dump does not dump schema information when no migrations are used" do Dir.chdir(app_path) do # create table without migrations `bin/rails runner 'ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }'` @@ -208,11 +207,11 @@ module ApplicationTests end end - test 'db:schema:load and db:structure:load do not purge the existing database' do + test "db:schema:load and db:structure:load do not purge the existing database" do Dir.chdir(app_path) do `bin/rails runner 'ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }'` - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: 20140423102712) do create_table(:comments) {} end @@ -224,7 +223,7 @@ module ApplicationTests `bin/rails db:schema:load` assert_equal '["posts", "comments", "schema_migrations", "ar_internal_metadata"]', list_tables[] - app_file 'db/structure.sql', <<-SQL + app_file "db/structure.sql", <<-SQL CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)); SQL @@ -235,15 +234,15 @@ module ApplicationTests test "db:schema:load with inflections" do Dir.chdir(app_path) do - app_file 'config/initializers/inflection.rb', <<-RUBY + app_file "config/initializers/inflection.rb", <<-RUBY ActiveSupport::Inflector.inflections do |inflect| inflect.irregular 'goose', 'geese' end RUBY - app_file 'config/initializers/primary_key_table_name.rb', <<-RUBY + app_file "config/initializers/primary_key_table_name.rb", <<-RUBY ActiveRecord::Base.primary_key_prefix_type = :table_name RUBY - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: 20140423102712) do create_table("goose".pluralize) do |t| t.string :name @@ -270,24 +269,24 @@ module ApplicationTests require "#{app_path}/app/models/book" #if structure is not loaded correctly, exception would be raised assert_equal 0, Book.count - assert_match ActiveRecord::Base.configurations['test']['database'], + assert_match ActiveRecord::Base.configurations["test"]["database"], ActiveRecord::Base.connection_config[:database] end end - test 'db:test:load_structure without database_url' do + test "db:test:load_structure without database_url" do require "#{app_path}/config/environment" db_test_load_structure end - test 'db:setup loads schema and seeds database' do + test "db:setup loads schema and seeds database" do begin @old_rails_env = ENV["RAILS_ENV"] @old_rack_env = ENV["RACK_ENV"] ENV.delete "RAILS_ENV" ENV.delete "RACK_ENV" - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: "1") do create_table :users do |t| t.string :name @@ -295,7 +294,7 @@ module ApplicationTests end RUBY - app_file 'db/seeds.rb', <<-RUBY + app_file "db/seeds.rb", <<-RUBY puts ActiveRecord::Base.connection_config[:database] RUBY diff --git a/railties/test/application/rake/dev_test.rb b/railties/test/application/rake/dev_test.rb index 2330ad3535..4f992d9c8d 100644 --- a/railties/test/application/rake/dev_test.rb +++ b/railties/test/application/rake/dev_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests module RakeTests @@ -13,24 +13,24 @@ module ApplicationTests teardown_app end - test 'dev:cache creates file and outputs message' do + test "dev:cache creates file and outputs message" do Dir.chdir(app_path) do output = `rails dev:cache` - assert File.exist?('tmp/caching-dev.txt') + assert File.exist?("tmp/caching-dev.txt") assert_match(/Development mode is now being cached/, output) end end - test 'dev:cache deletes file and outputs message' do + test "dev:cache deletes file and outputs message" do Dir.chdir(app_path) do `rails dev:cache` # Create caching file. output = `rails dev:cache` # Delete caching file. - assert_not File.exist?('tmp/caching-dev.txt') + assert_not File.exist?("tmp/caching-dev.txt") assert_match(/Development mode is no longer being cached/, output) end end - test 'dev:cache removes server.pid also' do + test "dev:cache removes server.pid also" do Dir.chdir(app_path) do FileUtils.mkdir_p("tmp/pids") FileUtils.touch("tmp/pids/server.pid") diff --git a/railties/test/application/rake/framework_test.rb b/railties/test/application/rake/framework_test.rb index ec57af79f6..7ac37b7700 100644 --- a/railties/test/application/rake/framework_test.rb +++ b/railties/test/application/rake/framework_test.rb @@ -8,7 +8,6 @@ module ApplicationTests def setup build_app - boot_rails FileUtils.rm_rf("#{app_path}/config/environments") end @@ -17,14 +16,14 @@ module ApplicationTests end def load_tasks - require 'rake' - require 'rdoc/task' - require 'rake/testtask' + require "rake" + require "rdoc/task" + require "rake/testtask" Rails.application.load_tasks end - test 'requiring the rake task should not define method .app_generator on Object' do + test "requiring the rake task should not define method .app_generator on Object" do require "#{app_path}/config/environment" load_tasks @@ -34,7 +33,7 @@ module ApplicationTests end end - test 'requiring the rake task should not define method .invoke_from_app_generator on Object' do + test "requiring the rake task should not define method .invoke_from_app_generator on Object" do require "#{app_path}/config/environment" load_tasks diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb index 7e2519ae5a..76cb302c62 100644 --- a/railties/test/application/rake/migrations_test.rb +++ b/railties/test/application/rake/migrations_test.rb @@ -5,7 +5,6 @@ module ApplicationTests class RakeMigrationsTest < ActiveSupport::TestCase def setup build_app - boot_rails FileUtils.rm_rf("#{app_path}/config/environments") end @@ -13,7 +12,7 @@ module ApplicationTests teardown_app end - test 'running migrations with given scope' do + test "running migrations with given scope" do Dir.chdir(app_path) do `bin/rails generate model user username:string password:string` @@ -38,31 +37,31 @@ module ApplicationTests end end - test 'model and migration generator with change syntax' do + test "model and migration generator with change syntax" do Dir.chdir(app_path) do `bin/rails generate model user username:string password:string; bin/rails generate migration add_email_to_users email:string` - output = `bin/rails db:migrate` - assert_match(/create_table\(:users\)/, output) - assert_match(/CreateUsers: migrated/, output) - assert_match(/add_column\(:users, :email, :string\)/, output) - assert_match(/AddEmailToUsers: migrated/, output) - - output = `bin/rails db:rollback STEP=2` - assert_match(/drop_table\(:users\)/, output) - assert_match(/CreateUsers: reverted/, output) - assert_match(/remove_column\(:users, :email, :string\)/, output) - assert_match(/AddEmailToUsers: reverted/, output) + output = `bin/rails db:migrate` + assert_match(/create_table\(:users\)/, output) + assert_match(/CreateUsers: migrated/, output) + assert_match(/add_column\(:users, :email, :string\)/, output) + assert_match(/AddEmailToUsers: migrated/, output) + + output = `bin/rails db:rollback STEP=2` + assert_match(/drop_table\(:users\)/, output) + assert_match(/CreateUsers: reverted/, output) + assert_match(/remove_column\(:users, :email, :string\)/, output) + assert_match(/AddEmailToUsers: reverted/, output) end end - test 'migration status when schema migrations table is not present' do - output = Dir.chdir(app_path){ `bin/rails db:migrate:status 2>&1` } + test "migration status when schema migrations table is not present" do + output = Dir.chdir(app_path) { `bin/rails db:migrate:status 2>&1` } assert_equal "Schema migrations table does not exist yet.\n", output end - test 'test migration status' do + test "test migration status" do Dir.chdir(app_path) do `bin/rails generate model user username:string password:string; bin/rails generate migration add_email_to_users email:string; @@ -81,8 +80,8 @@ module ApplicationTests end end - test 'migration status without timestamps' do - add_to_config('config.active_record.timestamped_migrations = false') + test "migration status without timestamps" do + add_to_config("config.active_record.timestamped_migrations = false") Dir.chdir(app_path) do `bin/rails generate model user username:string password:string; @@ -102,59 +101,59 @@ module ApplicationTests end end - test 'test migration status after rollback and redo' do + test "test migration status after rollback and redo" do Dir.chdir(app_path) do `bin/rails generate model user username:string password:string; bin/rails generate migration add_email_to_users email:string; bin/rails db:migrate` - output = `bin/rails db:migrate:status` + output = `bin/rails db:migrate:status` - assert_match(/up\s+\d{14}\s+Create users/, output) - assert_match(/up\s+\d{14}\s+Add email to users/, output) + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/up\s+\d{14}\s+Add email to users/, output) - `bin/rails db:rollback STEP=2` - output = `bin/rails db:migrate:status` + `bin/rails db:rollback STEP=2` + output = `bin/rails db:migrate:status` - assert_match(/down\s+\d{14}\s+Create users/, output) - assert_match(/down\s+\d{14}\s+Add email to users/, output) + assert_match(/down\s+\d{14}\s+Create users/, output) + assert_match(/down\s+\d{14}\s+Add email to users/, output) - `bin/rails db:migrate:redo` - output = `bin/rails db:migrate:status` + `bin/rails db:migrate:redo` + output = `bin/rails db:migrate:status` - assert_match(/up\s+\d{14}\s+Create users/, output) - assert_match(/up\s+\d{14}\s+Add email to users/, output) + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/up\s+\d{14}\s+Add email to users/, output) end end - test 'migration status after rollback and redo without timestamps' do - add_to_config('config.active_record.timestamped_migrations = false') + test "migration status after rollback and redo without timestamps" do + add_to_config("config.active_record.timestamped_migrations = false") Dir.chdir(app_path) do `bin/rails generate model user username:string password:string; bin/rails generate migration add_email_to_users email:string; bin/rails db:migrate` - output = `bin/rails db:migrate:status` + output = `bin/rails db:migrate:status` - assert_match(/up\s+\d{3,}\s+Create users/, output) - assert_match(/up\s+\d{3,}\s+Add email to users/, output) + assert_match(/up\s+\d{3,}\s+Create users/, output) + assert_match(/up\s+\d{3,}\s+Add email to users/, output) - `bin/rails db:rollback STEP=2` - output = `bin/rails db:migrate:status` + `bin/rails db:rollback STEP=2` + output = `bin/rails db:migrate:status` - assert_match(/down\s+\d{3,}\s+Create users/, output) - assert_match(/down\s+\d{3,}\s+Add email to users/, output) + assert_match(/down\s+\d{3,}\s+Create users/, output) + assert_match(/down\s+\d{3,}\s+Add email to users/, output) - `bin/rails db:migrate:redo` - output = `bin/rails db:migrate:status` + `bin/rails db:migrate:redo` + output = `bin/rails db:migrate:status` - assert_match(/up\s+\d{3,}\s+Create users/, output) - assert_match(/up\s+\d{3,}\s+Add email to users/, output) + assert_match(/up\s+\d{3,}\s+Create users/, output) + assert_match(/up\s+\d{3,}\s+Add email to users/, output) end end - test 'running migrations with not timestamp head migration files' do + test "running migrations with not timestamp head migration files" do Dir.chdir(app_path) do app_file "db/migrate/1_one_migration.rb", <<-MIGRATION @@ -169,15 +168,15 @@ module ApplicationTests `bin/rails db:migrate` - output = `bin/rails db:migrate:status` + output = `bin/rails db:migrate:status` - assert_match(/up\s+001\s+One migration/, output) - assert_match(/up\s+002\s+Two migration/, output) + assert_match(/up\s+001\s+One migration/, output) + assert_match(/up\s+002\s+Two migration/, output) end end - test 'schema generation when dump_schema_after_migration is set' do - add_to_config('config.active_record.dump_schema_after_migration = false') + test "schema generation when dump_schema_after_migration is set" do + add_to_config("config.active_record.dump_schema_after_migration = false") Dir.chdir(app_path) do `bin/rails generate model book title:string` @@ -188,7 +187,7 @@ module ApplicationTests assert !File.exist?("db/schema.rb"), "should not dump schema when configured not to" end - add_to_config('config.active_record.dump_schema_after_migration = true') + add_to_config("config.active_record.dump_schema_after_migration = true") Dir.chdir(app_path) do `bin/rails generate model reviews book_id:integer` @@ -199,7 +198,7 @@ module ApplicationTests end end - test 'default schema generation after migration' do + test "default schema generation after migration" do Dir.chdir(app_path) do `bin/rails generate model book title:string; bin/rails db:migrate` @@ -209,7 +208,7 @@ module ApplicationTests end end - test 'test migration status migrated file is deleted' do + test "test migration status migrated file is deleted" do Dir.chdir(app_path) do `bin/rails generate model user username:string password:string; bin/rails generate migration add_email_to_users email:string; @@ -217,7 +216,7 @@ module ApplicationTests rm db/migrate/*email*.rb` output = `bin/rails db:migrate:status` - File.write('test.txt', output) + File.write("test.txt", output) assert_match(/up\s+\d{14}\s+Create users/, output) assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output) diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 50def9beb0..e7ffea2e71 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -1,5 +1,5 @@ require "isolation/abstract_unit" -require 'rails/source_annotation_extractor' +require "rails/source_annotation_extractor" module ApplicationTests module RakeTests @@ -17,15 +17,15 @@ module ApplicationTests teardown_app end - test 'notes finds notes for certain file_types' do + test "notes finds notes for certain file_types" do app_file "app/views/home/index.html.erb", "<% # TODO: note in erb %>" app_file "app/assets/javascripts/application.js", "// TODO: note in js" app_file "app/assets/stylesheets/application.css", "// TODO: note in css" app_file "app/controllers/application_controller.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in ruby" app_file "lib/tasks/task.rake", "# TODO: note in rake" - app_file 'app/views/home/index.html.builder', '# TODO: note in builder' - app_file 'config/locales/en.yml', '# TODO: note in yml' - app_file 'config/locales/en.yaml', '# TODO: note in yaml' + app_file "app/views/home/index.html.builder", "# TODO: note in builder" + app_file "config/locales/en.yml", "# TODO: note in yml" + app_file "config/locales/en.yaml", "# TODO: note in yaml" app_file "app/views/home/index.ruby", "# TODO: note in ruby" run_rake_notes do |output, lines| @@ -43,7 +43,7 @@ module ApplicationTests end end - test 'notes finds notes in default directories' do + test "notes finds notes in default directories" do app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" app_file "db/some_seeds.rb", "# TODO: note in db directory" @@ -65,7 +65,7 @@ module ApplicationTests end end - test 'notes finds notes in custom directories' do + test "notes finds notes in custom directories" do app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" app_file "config/initializers/some_initializer.rb", "# TODO: note in config directory" app_file "db/some_seeds.rb", "# TODO: note in db directory" @@ -88,7 +88,7 @@ module ApplicationTests end end - test 'custom rake task finds specific notes in specific directories' do + test "custom rake task finds specific notes in specific directories" do app_file "app/controllers/some_controller.rb", "# TODO: note in app directory" app_file "lib/some_file.rb", "# OPTIMIZE: note in lib directory\n" << "# FIXME: note in lib directory" app_file "test/some_test.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in test directory" @@ -113,7 +113,7 @@ module ApplicationTests end end - test 'register a new extension' do + test "register a new extension" do add_to_config "config.assets.precompile = []" add_to_config %q{ config.annotations.register_extensions("scss", "sass") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } } app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss" @@ -126,32 +126,43 @@ module ApplicationTests end end + test "register additional directories" do + app_file "spec/spec_helper.rb", "# TODO: note in spec" + app_file "spec/models/user_spec.rb", "# TODO: note in model spec" + add_to_config ' config.annotations.register_directories("spec") ' + + run_rake_notes do |output, lines| + assert_match(/note in spec/, output) + assert_match(/note in model spec/, output) + assert_equal 2, lines.size + end + end + private - def run_rake_notes(command = 'bin/rails notes') - boot_rails - load_tasks + def run_rake_notes(command = "bin/rails notes") + boot_rails + load_tasks - Dir.chdir(app_path) do - output = `#{command}` - lines = output.scan(/\[([0-9\s]+)\]\s/).flatten + Dir.chdir(app_path) do + output = `#{command}` + lines = output.scan(/\[([0-9\s]+)\]\s/).flatten - yield output, lines + yield output, lines + end end - end - def load_tasks - require 'rake' - require 'rdoc/task' - require 'rake/testtask' + def load_tasks + require "rake" + require "rdoc/task" + require "rake/testtask" - Rails.application.load_tasks - end + Rails.application.load_tasks + end - def boot_rails - super - require "#{app_path}/config/environment" - end + def boot_rails + require "#{app_path}/config/environment" + end end end end diff --git a/railties/test/application/rake/restart_test.rb b/railties/test/application/rake/restart_test.rb index 30f662a9be..6ebd2d5461 100644 --- a/railties/test/application/rake/restart_test.rb +++ b/railties/test/application/rake/restart_test.rb @@ -7,39 +7,38 @@ module ApplicationTests def setup build_app - boot_rails end def teardown teardown_app end - test 'rake restart touches tmp/restart.txt' do + test "rails restart touches tmp/restart.txt" do Dir.chdir(app_path) do - `rake restart` + `bin/rails restart` assert File.exist?("tmp/restart.txt") prev_mtime = File.mtime("tmp/restart.txt") sleep(1) - `rake restart` + `bin/rails restart` curr_mtime = File.mtime("tmp/restart.txt") assert_not_equal prev_mtime, curr_mtime end end - test 'rake restart should work even if tmp folder does not exist' do + test "rails restart should work even if tmp folder does not exist" do Dir.chdir(app_path) do - FileUtils.remove_dir('tmp') - `rake restart` - assert File.exist?('tmp/restart.txt') + FileUtils.remove_dir("tmp") + `bin/rails restart` + assert File.exist?("tmp/restart.txt") end end - test 'rake restart removes server.pid also' do + test "rails restart removes server.pid also" do Dir.chdir(app_path) do FileUtils.mkdir_p("tmp/pids") FileUtils.touch("tmp/pids/server.pid") - `rake restart` + `bin/rails restart` assert_not File.exist?("tmp/pids/server.pid") end end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index badb9ecdd6..5fd5507453 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -7,7 +7,6 @@ module ApplicationTests def setup build_app - boot_rails end def teardown @@ -55,7 +54,7 @@ module ApplicationTests Rails.application.initialize! RUBY - assert_match("SuperMiddleware", Dir.chdir(app_path){ `bin/rails middleware` }) + assert_match("SuperMiddleware", Dir.chdir(app_path) { `bin/rails middleware` }) end def test_initializers_are_executed_in_rake_tasks @@ -70,7 +69,7 @@ module ApplicationTests end RUBY - output = Dir.chdir(app_path){ `bin/rails do_nothing` } + output = Dir.chdir(app_path) { `bin/rails do_nothing` } assert_match "Doing something...", output end @@ -83,7 +82,7 @@ module ApplicationTests end RUBY - app_file 'app/models/hello.rb', <<-RUBY + app_file "app/models/hello.rb", <<-RUBY class Hello def world puts 'Hello world' @@ -92,7 +91,7 @@ module ApplicationTests RUBY output = Dir.chdir(app_path) { `bin/rails do_nothing` } - assert_match 'Hello world', output + assert_match "Hello world", output end def test_should_not_eager_load_model_for_rake @@ -103,17 +102,17 @@ module ApplicationTests end RUBY - add_to_env_config 'production', <<-RUBY + add_to_env_config "production", <<-RUBY config.eager_load = true RUBY - app_file 'app/models/hello.rb', <<-RUBY + app_file "app/models/hello.rb", <<-RUBY raise 'should not be pre-required for rake even eager_load=true' RUBY Dir.chdir(app_path) do - assert system('bin/rails do_nothing RAILS_ENV=production'), - 'should not be pre-required for rake even eager_load=true' + assert system("bin/rails do_nothing RAILS_ENV=production"), + "should not be pre-required for rake even eager_load=true" end end @@ -129,7 +128,7 @@ module ApplicationTests end RUBY - output = Dir.chdir(app_path){ `bin/rails routes` } + output = Dir.chdir(app_path) { `bin/rails routes` } assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end @@ -141,13 +140,13 @@ module ApplicationTests end RUBY - output = Dir.chdir(app_path){ `bin/rails routes CONTROLLER=cart` } + output = Dir.chdir(app_path) { `bin/rails routes CONTROLLER=cart` } assert_equal ["Passing `CONTROLLER` to `bin/rails routes` is deprecated and will be removed in Rails 5.1.", "Please use `bin/rails routes -c controller_name` instead.", "Prefix Verb URI Pattern Controller#Action", " cart GET /cart(.:format) cart#show\n"].join("\n"), output - output = Dir.chdir(app_path){ `bin/rails routes -c cart` } + output = Dir.chdir(app_path) { `bin/rails routes -c cart` } assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end @@ -168,10 +167,10 @@ module ApplicationTests " PUT /admin/post(.:format) admin/posts#update", " DELETE /admin/post(.:format) admin/posts#destroy\n"].join("\n") - output = Dir.chdir(app_path){ `bin/rails routes -c Admin::PostController` } + output = Dir.chdir(app_path) { `bin/rails routes -c Admin::PostController` } assert_equal expected_output, output - output = Dir.chdir(app_path){ `bin/rails routes -c PostController` } + output = Dir.chdir(app_path) { `bin/rails routes -c PostController` } assert_equal expected_output, output end @@ -184,13 +183,13 @@ module ApplicationTests end RUBY - output = Dir.chdir(app_path){ `bin/rails routes -g show` } + output = Dir.chdir(app_path) { `bin/rails routes -g show` } assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output - output = Dir.chdir(app_path){ `bin/rails routes -g POST` } + output = Dir.chdir(app_path) { `bin/rails routes -g POST` } assert_equal "Prefix Verb URI Pattern Controller#Action\n POST /cart(.:format) cart#create\n", output - output = Dir.chdir(app_path){ `bin/rails routes -g basketballs` } + output = Dir.chdir(app_path) { `bin/rails routes -g basketballs` } assert_equal " Prefix Verb URI Pattern Controller#Action\n" \ "basketballs GET /basketballs(.:format) basketball#index\n", output end @@ -203,13 +202,13 @@ module ApplicationTests end RUBY - output = Dir.chdir(app_path){ `bin/rails routes -c cart` } + output = Dir.chdir(app_path) { `bin/rails routes -c cart` } assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output - output = Dir.chdir(app_path){ `bin/rails routes -c Cart` } + output = Dir.chdir(app_path) { `bin/rails routes -c Cart` } assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output - output = Dir.chdir(app_path){ `bin/rails routes -c CartController` } + output = Dir.chdir(app_path) { `bin/rails routes -c CartController` } assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end @@ -219,7 +218,7 @@ module ApplicationTests end RUBY - assert_equal <<-MESSAGE.strip_heredoc, Dir.chdir(app_path){ `bin/rails routes` } + assert_equal <<-MESSAGE.strip_heredoc, Dir.chdir(app_path) { `bin/rails routes` } You don't have any routes defined! Please add some routes in config/routes.rb. @@ -235,7 +234,7 @@ module ApplicationTests end RUBY - output = Dir.chdir(app_path){ `bin/rake --rakefile Rakefile routes` } + output = Dir.chdir(app_path) { `bin/rake --rakefile Rakefile routes` } assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end @@ -248,7 +247,7 @@ module ApplicationTests end RUBY - output = Dir.chdir(app_path){ `bin/rails log_something RAILS_ENV=production && cat log/production.log` } + output = Dir.chdir(app_path) { `bin/rails log_something RAILS_ENV=production && cat log/production.log` } assert_match "Sample log message", output end @@ -347,7 +346,7 @@ module ApplicationTests # ensure we have a schema_migrations table to dump `bin/rails db:migrate db:structure:dump SCHEMA=db/my_structure.sql` end - assert File.exist?(File.join(app_path, 'db', 'my_structure.sql')) + assert File.exist?(File.join(app_path, "db", "my_structure.sql")) end def test_rake_dump_structure_should_be_called_twice_when_migrate_redo @@ -368,24 +367,24 @@ module ApplicationTests bin/rails generate model product name:string; bin/rails db:migrate db:schema:cache:dump` end - assert File.exist?(File.join(app_path, 'db', 'schema_cache.dump')) + assert File.exist?(File.join(app_path, "db", "schema_cache.dump")) end def test_rake_clear_schema_cache Dir.chdir(app_path) do `bin/rails db:schema:cache:dump db:schema:cache:clear` end - assert !File.exist?(File.join(app_path, 'db', 'schema_cache.dump')) + assert !File.exist?(File.join(app_path, "db", "schema_cache.dump")) end def test_copy_templates Dir.chdir(app_path) do `bin/rails app:templates:copy` %w(controller mailer scaffold).each do |dir| - assert File.exist?(File.join(app_path, 'lib', 'templates', 'erb', dir)) + assert File.exist?(File.join(app_path, "lib", "templates", "erb", dir)) end %w(controller helper scaffold_controller assets).each do |dir| - assert File.exist?(File.join(app_path, 'lib', 'templates', 'rails', dir)) + assert File.exist?(File.join(app_path, "lib", "templates", "rails", dir)) end end end diff --git a/railties/test/application/rendering_test.rb b/railties/test/application/rendering_test.rb index b01febd768..ccafc5b6f1 100644 --- a/railties/test/application/rendering_test.rb +++ b/railties/test/application/rendering_test.rb @@ -1,5 +1,5 @@ -require 'isolation/abstract_unit' -require 'rack/test' +require "isolation/abstract_unit" +require "rack/test" module ApplicationTests class RoutingTest < ActiveSupport::TestCase @@ -8,7 +8,6 @@ module ApplicationTests def setup build_app - boot_rails end def teardown @@ -16,13 +15,13 @@ module ApplicationTests end test "Unknown format falls back to HTML template" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'pages/:id', to: 'pages#show' end RUBY - app_file 'app/controllers/pages_controller.rb', <<-RUBY + app_file "app/controllers/pages_controller.rb", <<-RUBY class PagesController < ApplicationController layout false @@ -31,14 +30,14 @@ module ApplicationTests end RUBY - app_file 'app/views/pages/show.html.erb', <<-RUBY + app_file "app/views/pages/show.html.erb", <<-RUBY <%= params[:id] %> RUBY - get '/pages/foo' + get "/pages/foo" assert_equal 200, last_response.status - get '/pages/foo.bar' + get "/pages/foo.bar" assert_equal 200, last_response.status end end diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 93847c7aa9..c515e2b270 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -1,5 +1,5 @@ -require 'isolation/abstract_unit' -require 'rack/test' +require "isolation/abstract_unit" +require "rack/test" module ApplicationTests class RoutingTest < ActiveSupport::TestCase @@ -8,7 +8,6 @@ module ApplicationTests def setup build_app - boot_rails end def teardown @@ -61,24 +60,24 @@ module ApplicationTests test "root takes precedence over internal welcome controller" do app("development") - assert_welcome get('/') + assert_welcome get("/") controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do root to: "foo#index" end RUBY - get '/' - assert_equal 'foo', last_response.body + get "/" + assert_equal "foo", last_response.body end test "rails/welcome in production" do @@ -108,8 +107,8 @@ module ApplicationTests test "simple controller" do simple_controller - get '/foo' - assert_equal 'foo', last_response.body + get "/foo" + assert_equal "foo", last_response.body end test "simple controller with helper" do @@ -121,7 +120,7 @@ module ApplicationTests end RUBY - app_file 'app/helpers/bar_helper.rb', <<-RUBY + app_file "app/helpers/bar_helper.rb", <<-RUBY module BarHelper def foo_or_bar? "bar" @@ -129,18 +128,18 @@ module ApplicationTests end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end RUBY - get '/foo' - assert_equal 'bar', last_response.body + get "/foo" + assert_equal "bar", last_response.body end test "mount rack app" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog" # The line below is required because mount sometimes @@ -149,35 +148,35 @@ module ApplicationTests end RUBY - get '/blog/archives' - assert_equal '/archives', last_response.body + get "/blog/archives" + assert_equal "/archives", last_response.body end test "mount named rack app" do controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: my_blog_path + render plain: my_blog_path end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog", as: "my_blog" get '/foo' => 'foo#index' end RUBY - get '/foo' - assert_equal '/blog', last_response.body + get "/foo" + assert_equal "/blog", last_response.body end test "multiple controllers" do controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -185,59 +184,59 @@ module ApplicationTests controller :bar, <<-RUBY class BarController < ActionController::Base def index - render text: "bar" + render plain: "bar" end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end RUBY - get '/foo' - assert_equal 'foo', last_response.body + get "/foo" + assert_equal "foo", last_response.body - get '/bar' - assert_equal 'bar', last_response.body + get "/bar" + assert_equal "bar", last_response.body end test "nested controller" do - controller 'foo', <<-RUBY + controller "foo", <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY - controller 'admin/foo', <<-RUBY + controller "admin/foo", <<-RUBY module Admin class FooController < ApplicationController def index - render text: "admin::foo" + render plain: "admin::foo" end end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'admin/foo', to: 'admin/foo#index' get 'foo', to: 'foo#index' end RUBY - get '/foo' - assert_equal 'foo', last_response.body + get "/foo" + assert_equal "foo", last_response.body - get '/admin/foo' - assert_equal 'admin::foo', last_response.body + get "/admin/foo" + assert_equal "admin::foo", last_response.body end test "routes appending blocks" do - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller/:action' end @@ -249,36 +248,36 @@ module ApplicationTests end R - app 'development' + app "development" - get '/win' - assert_equal 'WIN', last_response.body + get "/win" + assert_equal "WIN", last_response.body - app_file 'config/routes.rb', <<-R + app_file "config/routes.rb", <<-R Rails.application.routes.draw do get 'lol' => 'hello#index' end R - get '/win' - assert_equal 'WIN', last_response.body + get "/win" + assert_equal "WIN", last_response.body end - {"development" => "baz", "production" => "bar"}.each do |mode, expected| + { "development" => "baz", "production" => "bar" }.each do |mode, expected| test "reloads routes when configuration is changed in #{mode}" do controller :foo, <<-RUBY class FooController < ApplicationController def bar - render text: "bar" + render plain: "bar" end def baz - render text: "baz" + render plain: "baz" end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', to: 'foo#bar' end @@ -286,10 +285,10 @@ module ApplicationTests app(mode) - get '/foo' - assert_equal 'bar', last_response.body + get "/foo" + assert_equal "bar", last_response.body - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', to: 'foo#baz' end @@ -297,12 +296,12 @@ module ApplicationTests sleep 0.1 - get '/foo' + get "/foo" assert_equal expected, last_response.body end end - test 'routes are loaded just after initialization' do + test "routes are loaded just after initialization" do require "#{app_path}/config/application" # Create the rack app just inside after initialize callback @@ -310,17 +309,17 @@ module ApplicationTests ::InitializeRackApp = lambda { |env| [200, {}, ["InitializeRackApp"]] } end - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', to: ::InitializeRackApp end RUBY - get '/foo' + get "/foo" assert_equal "InitializeRackApp", last_response.body end - test 'reload_routes! is part of Rails.application API' do + test "reload_routes! is part of Rails.application API" do app("development") assert_nothing_raised do Rails.application.reload_routes! @@ -328,36 +327,36 @@ module ApplicationTests end def test_root_path - app('development') + app("development") controller :foo, <<-RUBY class FooController < ApplicationController def index - render :text => "foo" + render plain: "foo" end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', :to => 'foo#index' root :to => 'foo#index' end RUBY - remove_file 'public/index.html' + remove_file "public/index.html" - get '/' - assert_equal 'foo', last_response.body + get "/" + assert_equal "foo", last_response.body end - test 'routes are added and removed when reloading' do - app('development') + test "routes are added and removed when reloading" do + app("development") controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -365,28 +364,28 @@ module ApplicationTests controller :bar, <<-RUBY class BarController < ApplicationController def index - render text: "bar" + render plain: "bar" end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', to: 'foo#index' end RUBY - get '/foo' - assert_equal 'foo', last_response.body - assert_equal '/foo', Rails.application.routes.url_helpers.foo_path + get "/foo" + assert_equal "foo", last_response.body + assert_equal "/foo", Rails.application.routes.url_helpers.foo_path - get '/bar' + get "/bar" assert_equal 404, last_response.status assert_raises NoMethodError do - assert_equal '/bar', Rails.application.routes.url_helpers.bar_path + assert_equal "/bar", Rails.application.routes.url_helpers.bar_path end - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', to: 'foo#index' get 'bar', to: 'bar#index' @@ -395,15 +394,15 @@ module ApplicationTests Rails.application.reload_routes! - get '/foo' - assert_equal 'foo', last_response.body - assert_equal '/foo', Rails.application.routes.url_helpers.foo_path + get "/foo" + assert_equal "foo", last_response.body + assert_equal "/foo", Rails.application.routes.url_helpers.foo_path - get '/bar' - assert_equal 'bar', last_response.body - assert_equal '/bar', Rails.application.routes.url_helpers.bar_path + get "/bar" + assert_equal "bar", last_response.body + assert_equal "/bar", Rails.application.routes.url_helpers.bar_path - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get 'foo', to: 'foo#index' end @@ -411,24 +410,24 @@ module ApplicationTests Rails.application.reload_routes! - get '/foo' - assert_equal 'foo', last_response.body - assert_equal '/foo', Rails.application.routes.url_helpers.foo_path + get "/foo" + assert_equal "foo", last_response.body + assert_equal "/foo", Rails.application.routes.url_helpers.foo_path - get '/bar' + get "/bar" assert_equal 404, last_response.status assert_raises NoMethodError do - assert_equal '/bar', Rails.application.routes.url_helpers.bar_path + assert_equal "/bar", Rails.application.routes.url_helpers.bar_path end end - test 'named routes are cleared when reloading' do - app('development') + test "named routes are cleared when reloading" do + app("development") controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY @@ -436,22 +435,22 @@ module ApplicationTests controller :bar, <<-RUBY class BarController < ApplicationController def index - render text: "bar" + render plain: "bar" end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':locale/foo', to: 'foo#index', as: 'foo' end RUBY - get '/en/foo' - assert_equal 'foo', last_response.body - assert_equal '/en/foo', Rails.application.routes.url_helpers.foo_path(:locale => 'en') + get "/en/foo" + assert_equal "foo", last_response.body + assert_equal "/en/foo", Rails.application.routes.url_helpers.foo_path(locale: "en") - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':locale/bar', to: 'bar#index', as: 'foo' end @@ -459,39 +458,39 @@ module ApplicationTests Rails.application.reload_routes! - get '/en/foo' + get "/en/foo" assert_equal 404, last_response.status - get '/en/bar' - assert_equal 'bar', last_response.body - assert_equal '/en/bar', Rails.application.routes.url_helpers.foo_path(:locale => 'en') + get "/en/bar" + assert_equal "bar", last_response.body + assert_equal "/en/bar", Rails.application.routes.url_helpers.foo_path(locale: "en") end - test 'resource routing with irregular inflection' do - app_file 'config/initializers/inflection.rb', <<-RUBY + test "resource routing with irregular inflection" do + app_file "config/initializers/inflection.rb", <<-RUBY ActiveSupport::Inflector.inflections do |inflect| inflect.irregular 'yazi', 'yazilar' end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do resources :yazilar end RUBY - controller 'yazilar', <<-RUBY + controller "yazilar", <<-RUBY class YazilarController < ApplicationController def index - render text: 'yazilar#index' + render plain: 'yazilar#index' end end RUBY - get '/yazilars' + get "/yazilars" assert_equal 404, last_response.status - get '/yazilar' + get "/yazilar" assert_equal 200, last_response.status end end diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb index 9f15ce5e85..8769703f66 100644 --- a/railties/test/application/runner_test.rb +++ b/railties/test/application/runner_test.rb @@ -1,5 +1,5 @@ -require 'isolation/abstract_unit' -require 'env_helpers' +require "isolation/abstract_unit" +require "env_helpers" module ApplicationTests class RunnerTest < ActiveSupport::TestCase @@ -8,7 +8,6 @@ module ApplicationTests def setup build_app - boot_rails # Lets create a model so we have something to play with app_file "app/models/user.rb", <<-MODEL @@ -44,6 +43,15 @@ module ApplicationTests assert_match "42", Dir.chdir(app_path) { `bin/rails runner "bin/count_users.rb"` } end + def test_no_minitest_loaded_in_production_mode + app_file "bin/print_features.rb", <<-SCRIPT + p $LOADED_FEATURES.grep(/minitest/) + SCRIPT + assert_match "[]", Dir.chdir(app_path) { + `RAILS_ENV=production bin/rails runner "bin/print_features.rb"` + } + end + def test_should_set_dollar_0_to_file app_file "bin/dollar0.rb", <<-SCRIPT puts $0 @@ -75,13 +83,15 @@ module ApplicationTests end def test_runner_detects_syntax_errors - Dir.chdir(app_path) { `bin/rails runner "puts 'hello world" 2>&1` } - refute $?.success? + output = Dir.chdir(app_path) { `bin/rails runner "puts 'hello world" 2>&1` } + assert_not $?.success? + assert_match "unterminated string meets end of file", output end def test_runner_detects_bad_script_name - Dir.chdir(app_path) { `bin/rails runner "iuiqwiourowe" 2>&1` } - refute $?.success? + output = Dir.chdir(app_path) { `bin/rails runner "iuiqwiourowe" 2>&1` } + assert_not $?.success? + assert_match "undefined local variable or method `iuiqwiourowe' for", output end def test_environment_with_rails_env diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 08759ab5a4..b442891769 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -1,6 +1,6 @@ -require 'isolation/abstract_unit' -require 'active_support/core_ext/string/strip' -require 'env_helpers' +require "isolation/abstract_unit" +require "active_support/core_ext/string/strip" +require "env_helpers" module ApplicationTests class TestRunnerTest < ActiveSupport::TestCase @@ -16,31 +16,31 @@ module ApplicationTests end def test_run_single_file - create_test_file :models, 'foo' - create_test_file :models, 'bar' + create_test_file :models, "foo" + create_test_file :models, "bar" assert_match "1 runs, 1 assertions, 0 failures", run_test_command("test/models/foo_test.rb") end def test_run_multiple_files - create_test_file :models, 'foo' - create_test_file :models, 'bar' + create_test_file :models, "foo" + create_test_file :models, "bar" assert_match "2 runs, 2 assertions, 0 failures", run_test_command("test/models/foo_test.rb test/models/bar_test.rb") end def test_run_file_with_syntax_error - app_file 'test/models/error_test.rb', <<-RUBY + app_file "test/models/error_test.rb", <<-RUBY require 'test_helper' def; end RUBY - error = capture(:stderr) { run_test_command('test/models/error_test.rb') } + error = capture(:stderr) { run_test_command("test/models/error_test.rb") } assert_match "syntax error", error end def test_run_models - create_test_file :models, 'foo' - create_test_file :models, 'bar' - create_test_file :controllers, 'foobar_controller' + create_test_file :models, "foo" + create_test_file :models, "bar" + create_test_file :controllers, "foobar_controller" run_test_command("test/models").tap do |output| assert_match "FooTest", output assert_match "BarTest", output @@ -49,9 +49,9 @@ module ApplicationTests end def test_run_helpers - create_test_file :helpers, 'foo_helper' - create_test_file :helpers, 'bar_helper' - create_test_file :controllers, 'foobar_controller' + create_test_file :helpers, "foo_helper" + create_test_file :helpers, "bar_helper" + create_test_file :controllers, "foobar_controller" run_test_command("test/helpers").tap do |output| assert_match "FooHelperTest", output assert_match "BarHelperTest", output @@ -61,10 +61,10 @@ module ApplicationTests def test_run_units skip "we no longer have the concept of unit tests. Just different directories..." - create_test_file :models, 'foo' - create_test_file :helpers, 'bar_helper' - create_test_file :unit, 'baz_unit' - create_test_file :controllers, 'foobar_controller' + create_test_file :models, "foo" + create_test_file :helpers, "bar_helper" + create_test_file :unit, "baz_unit" + create_test_file :controllers, "foobar_controller" run_test_units_command.tap do |output| assert_match "FooTest", output assert_match "BarHelperTest", output @@ -74,9 +74,9 @@ module ApplicationTests end def test_run_controllers - create_test_file :controllers, 'foo_controller' - create_test_file :controllers, 'bar_controller' - create_test_file :models, 'foo' + create_test_file :controllers, "foo_controller" + create_test_file :controllers, "bar_controller" + create_test_file :models, "foo" run_test_command("test/controllers").tap do |output| assert_match "FooControllerTest", output assert_match "BarControllerTest", output @@ -85,9 +85,9 @@ module ApplicationTests end def test_run_mailers - create_test_file :mailers, 'foo_mailer' - create_test_file :mailers, 'bar_mailer' - create_test_file :models, 'foo' + create_test_file :mailers, "foo_mailer" + create_test_file :mailers, "bar_mailer" + create_test_file :models, "foo" run_test_command("test/mailers").tap do |output| assert_match "FooMailerTest", output assert_match "BarMailerTest", output @@ -96,9 +96,9 @@ module ApplicationTests end def test_run_jobs - create_test_file :jobs, 'foo_job' - create_test_file :jobs, 'bar_job' - create_test_file :models, 'foo' + create_test_file :jobs, "foo_job" + create_test_file :jobs, "bar_job" + create_test_file :models, "foo" run_test_command("test/jobs").tap do |output| assert_match "FooJobTest", output assert_match "BarJobTest", output @@ -108,10 +108,10 @@ module ApplicationTests def test_run_functionals skip "we no longer have the concept of functional tests. Just different directories..." - create_test_file :mailers, 'foo_mailer' - create_test_file :controllers, 'bar_controller' - create_test_file :functional, 'baz_functional' - create_test_file :models, 'foo' + create_test_file :mailers, "foo_mailer" + create_test_file :controllers, "bar_controller" + create_test_file :functional, "baz_functional" + create_test_file :models, "foo" run_test_functionals_command.tap do |output| assert_match "FooMailerTest", output assert_match "BarControllerTest", output @@ -121,8 +121,8 @@ module ApplicationTests end def test_run_integration - create_test_file :integration, 'foo_integration' - create_test_file :models, 'foo' + create_test_file :integration, "foo_integration" + create_test_file :models, "foo" run_test_command("test/integration").tap do |output| assert_match "FooIntegration", output assert_match "1 runs, 1 assertions, 0 failures", output @@ -132,14 +132,14 @@ module ApplicationTests def test_run_all_suites suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration, :jobs] suites.each { |suite| create_test_file suite, "foo_#{suite}" } - run_test_command('') .tap do |output| + run_test_command("") .tap do |output| suites.each { |suite| assert_match "Foo#{suite.to_s.camelize}Test", output } assert_match "8 runs, 8 assertions, 0 failures", output end end def test_run_named_test - app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY + app_file "test/unit/chu_2_koi_test.rb", <<-RUBY require 'test_helper' class Chu2KoiTest < ActiveSupport::TestCase @@ -153,14 +153,14 @@ module ApplicationTests end RUBY - run_test_command('-n test_rikka test/unit/chu_2_koi_test.rb').tap do |output| + run_test_command("-n test_rikka test/unit/chu_2_koi_test.rb").tap do |output| assert_match "Rikka", output assert_no_match "Sanae", output end end def test_run_matched_test - app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY + app_file "test/unit/chu_2_koi_test.rb", <<-RUBY require 'test_helper' class Chu2KoiTest < ActiveSupport::TestCase @@ -174,7 +174,7 @@ module ApplicationTests end RUBY - run_test_command('-n /rikka/ test/unit/chu_2_koi_test.rb').tap do |output| + run_test_command("-n /rikka/ test/unit/chu_2_koi_test.rb").tap do |output| assert_match "Rikka", output assert_no_match "Sanae", output end @@ -195,14 +195,14 @@ module ApplicationTests def test_run_with_model skip "These feel a bit odd. Not sure we should keep supporting them." create_model_with_fixture - create_fixture_test 'models', 'user' + create_fixture_test "models", "user" assert_match "3 users", run_task(["test models/user"]) assert_match "3 users", run_task(["test app/models/user.rb"]) end def test_run_different_environment_using_env_var skip "no longer possible. Running tests in a different environment should be explicit" - app_file 'test/unit/env_test.rb', <<-RUBY + app_file "test/unit/env_test.rb", <<-RUBY require 'test_helper' class EnvTest < ActiveSupport::TestCase @@ -212,14 +212,14 @@ module ApplicationTests end RUBY - ENV['RAILS_ENV'] = 'development' - assert_match "development", run_test_command('test/unit/env_test.rb') + ENV["RAILS_ENV"] = "development" + assert_match "development", run_test_command("test/unit/env_test.rb") end def test_run_in_test_environment_by_default create_env_test - assert_match "Current Environment: test", run_test_command('test/unit/env_test.rb') + assert_match "Current Environment: test", run_test_command("test/unit/env_test.rb") end def test_run_different_environment @@ -231,27 +231,27 @@ module ApplicationTests def test_generated_scaffold_works_with_rails_test create_scaffold - assert_match "0 failures, 0 errors, 0 skips", run_test_command('') + assert_match "0 failures, 0 errors, 0 skips", run_test_command("") end def test_generated_controller_works_with_rails_test create_controller - assert_match "0 failures, 0 errors, 0 skips", run_test_command('') + assert_match "0 failures, 0 errors, 0 skips", run_test_command("") end def test_run_multiple_folders - create_test_file :models, 'account' - create_test_file :controllers, 'accounts_controller' + create_test_file :models, "account" + create_test_file :controllers, "accounts_controller" - run_test_command('test/models test/controllers').tap do |output| - assert_match 'AccountTest', output - assert_match 'AccountsControllerTest', output - assert_match '2 runs, 2 assertions, 0 failures, 0 errors, 0 skips', output + run_test_command("test/models test/controllers").tap do |output| + assert_match "AccountTest", output + assert_match "AccountsControllerTest", output + assert_match "2 runs, 2 assertions, 0 failures, 0 errors, 0 skips", output end end def test_run_with_ruby_command - app_file 'test/models/post_test.rb', <<-RUBY + app_file "test/models/post_test.rb", <<-RUBY require 'test_helper' class PostTest < ActiveSupport::TestCase @@ -264,15 +264,15 @@ module ApplicationTests Dir.chdir(app_path) do `ruby -Itest test/models/post_test.rb`.tap do |output| - assert_match 'PostTest', output - assert_no_match 'is already defined in', output + assert_match "PostTest", output + assert_no_match "is already defined in", output end end end def test_mix_files_and_line_filters - create_test_file :models, 'account' - app_file 'test/models/post_test.rb', <<-RUBY + create_test_file :models, "account" + app_file "test/models/post_test.rb", <<-RUBY require 'test_helper' class PostTest < ActiveSupport::TestCase @@ -287,15 +287,15 @@ module ApplicationTests end RUBY - run_test_command('test/models/account_test.rb test/models/post_test.rb:4').tap do |output| - assert_match 'AccountTest', output - assert_match 'PostTest', output - assert_match '2 runs, 2 assertions', output + run_test_command("test/models/account_test.rb test/models/post_test.rb:4").tap do |output| + assert_match "AccountTest", output + assert_match "PostTest", output + assert_match "2 runs, 2 assertions", output end end def test_more_than_one_line_filter - app_file 'test/models/post_test.rb', <<-RUBY + app_file "test/models/post_test.rb", <<-RUBY require 'test_helper' class PostTest < ActiveSupport::TestCase @@ -315,15 +315,15 @@ module ApplicationTests end RUBY - run_test_command('test/models/post_test.rb:4:9').tap do |output| - assert_match 'PostTest:FirstFilter', output - assert_match 'PostTest:SecondFilter', output - assert_match '2 runs, 2 assertions', output + run_test_command("test/models/post_test.rb:4:9").tap do |output| + assert_match "PostTest:FirstFilter", output + assert_match "PostTest:SecondFilter", output + assert_match "2 runs, 2 assertions", output end end def test_more_than_one_line_filter_with_multiple_files - app_file 'test/models/account_test.rb', <<-RUBY + app_file "test/models/account_test.rb", <<-RUBY require 'test_helper' class AccountTest < ActiveSupport::TestCase @@ -343,7 +343,7 @@ module ApplicationTests end RUBY - app_file 'test/models/post_test.rb', <<-RUBY + app_file "test/models/post_test.rb", <<-RUBY require 'test_helper' class PostTest < ActiveSupport::TestCase @@ -363,27 +363,27 @@ module ApplicationTests end RUBY - run_test_command('test/models/account_test.rb:4:9 test/models/post_test.rb:4:9').tap do |output| - assert_match 'AccountTest:FirstFilter', output - assert_match 'AccountTest:SecondFilter', output - assert_match 'PostTest:FirstFilter', output - assert_match 'PostTest:SecondFilter', output - assert_match '4 runs, 4 assertions', output + run_test_command("test/models/account_test.rb:4:9 test/models/post_test.rb:4:9").tap do |output| + assert_match "AccountTest:FirstFilter", output + assert_match "AccountTest:SecondFilter", output + assert_match "PostTest:FirstFilter", output + assert_match "PostTest:SecondFilter", output + assert_match "4 runs, 4 assertions", output end end def test_multiple_line_filters - create_test_file :models, 'account' - create_test_file :models, 'post' + create_test_file :models, "account" + create_test_file :models, "post" - run_test_command('test/models/account_test.rb:4 test/models/post_test.rb:4').tap do |output| - assert_match 'AccountTest', output - assert_match 'PostTest', output + run_test_command("test/models/account_test.rb:4 test/models/post_test.rb:4").tap do |output| + assert_match "AccountTest", output + assert_match "PostTest", output end end def test_line_filters_trigger_only_one_runnable - app_file 'test/models/post_test.rb', <<-RUBY + app_file "test/models/post_test.rb", <<-RUBY require 'test_helper' class PostTest < ActiveSupport::TestCase @@ -400,14 +400,14 @@ module ApplicationTests RUBY # Pass seed guaranteeing failure. - run_test_command('test/models/post_test.rb:4 --seed 30410').tap do |output| - assert_no_match 'ran second runnable', output - assert_match '1 runs, 1 assertions', output + run_test_command("test/models/post_test.rb:4 --seed 30410").tap do |output| + assert_no_match "ran second runnable", output + assert_match "1 runs, 1 assertions", output end end def test_line_filter_with_minitest_string_filter - app_file 'test/models/post_test.rb', <<-RUBY + app_file "test/models/post_test.rb", <<-RUBY require 'test_helper' class PostTest < ActiveSupport::TestCase @@ -423,128 +423,128 @@ module ApplicationTests end RUBY - run_test_command('test/models/post_test.rb:4 -n test_by_name').tap do |output| - assert_match 'by line', output - assert_match 'by name', output - assert_match '2 runs, 2 assertions', output + run_test_command("test/models/post_test.rb:4 -n test_by_name").tap do |output| + assert_match "by line", output + assert_match "by name", output + assert_match "2 runs, 2 assertions", output end end def test_shows_filtered_backtrace_by_default create_backtrace_test - assert_match 'Rails::BacktraceCleaner', run_test_command('test/unit/backtrace_test.rb') + assert_match "Rails::BacktraceCleaner", run_test_command("test/unit/backtrace_test.rb") end def test_backtrace_option create_backtrace_test - assert_match 'Minitest::BacktraceFilter', run_test_command('test/unit/backtrace_test.rb -b') - assert_match 'Minitest::BacktraceFilter', - run_test_command('test/unit/backtrace_test.rb --backtrace') + assert_match "Minitest::BacktraceFilter", run_test_command("test/unit/backtrace_test.rb -b") + assert_match "Minitest::BacktraceFilter", + run_test_command("test/unit/backtrace_test.rb --backtrace") end def test_show_full_backtrace_using_backtrace_environment_variable create_backtrace_test - switch_env 'BACKTRACE', 'true' do - assert_match 'Minitest::BacktraceFilter', run_test_command('test/unit/backtrace_test.rb') + switch_env "BACKTRACE", "true" do + assert_match "Minitest::BacktraceFilter", run_test_command("test/unit/backtrace_test.rb") end end def test_run_app_without_rails_loaded # Simulate a real Rails app boot. - app_file 'config/boot.rb', <<-RUBY + app_file "config/boot.rb", <<-RUBY ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' # Set up gems listed in the Gemfile. RUBY - assert_match '0 runs, 0 assertions', run_test_command('') + assert_match "0 runs, 0 assertions", run_test_command("") end def test_output_inline_by_default - create_test_file :models, 'post', pass: false + create_test_file :models, "post", pass: false - output = run_test_command('test/models/post_test.rb') + output = run_test_command("test/models/post_test.rb") expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/models/post_test.rb:6\]:\nwups!\n\nbin/rails test test/models/post_test.rb:4\n\n\n\n} assert_match expect, output end def test_only_inline_failure_output - create_test_file :models, 'post', pass: false + create_test_file :models, "post", pass: false - output = run_test_command('test/models/post_test.rb') + output = run_test_command("test/models/post_test.rb") assert_match %r{Finished in.*\n\n1 runs, 1 assertions}, output end def test_fail_fast - create_test_file :models, 'post', pass: false + create_test_file :models, "post", pass: false assert_match(/Interrupt/, - capture(:stderr) { run_test_command('test/models/post_test.rb --fail-fast') }) + capture(:stderr) { run_test_command("test/models/post_test.rb --fail-fast") }) end def test_raise_error_when_specified_file_does_not_exist - error = capture(:stderr) { run_test_command('test/not_exists.rb') } + error = capture(:stderr) { run_test_command("test/not_exists.rb") } assert_match(%r{cannot load such file.+test/not_exists\.rb}, error) end def test_pass_TEST_env_on_rake_test - create_test_file :models, 'account' - create_test_file :models, 'post', pass: false + create_test_file :models, "account" + create_test_file :models, "post", pass: false # This specifically verifies TEST for backwards compatibility with rake test # as bin/rails test already supports running tests from a single file more cleanly. output = Dir.chdir(app_path) { `bin/rake test TEST=test/models/post_test.rb` } assert_match "PostTest", output, "passing TEST= should run selected test" assert_no_match "AccountTest", output, "passing TEST= should only run selected test" - assert_match '1 runs, 1 assertions', output + assert_match "1 runs, 1 assertions", output end def test_pass_rake_options - create_test_file :models, 'account' + create_test_file :models, "account" output = Dir.chdir(app_path) { `bin/rake --rakefile Rakefile --trace=stdout test` } - assert_match '1 runs, 1 assertions', output - assert_match 'Execute test', output + assert_match "1 runs, 1 assertions", output + assert_match "Execute test", output end def test_rails_db_create_all_restores_db_connection - create_test_file :models, 'account' + create_test_file :models, "account" output = Dir.chdir(app_path) { `bin/rails db:create:all db:migrate && echo ".tables" | rails dbconsole` } assert_match "ar_internal_metadata", output, "tables should be dumped" end def test_rails_db_create_all_restores_db_connection_after_drop - create_test_file :models, 'account' + create_test_file :models, "account" Dir.chdir(app_path) { `bin/rails db:create:all` } # create all to avoid warnings output = Dir.chdir(app_path) { `bin/rails db:drop:all db:create:all db:migrate && echo ".tables" | rails dbconsole` } assert_match "ar_internal_metadata", output, "tables should be dumped" end def test_rake_passes_TESTOPTS_to_minitest - create_test_file :models, 'account' + create_test_file :models, "account" output = Dir.chdir(app_path) { `bin/rake test TESTOPTS=-v` } assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test" end def test_rake_passes_multiple_TESTOPTS_to_minitest - create_test_file :models, 'account' + create_test_file :models, "account" output = Dir.chdir(app_path) { `bin/rake test TESTOPTS='-v --seed=1234'` } assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test" assert_match "seed=1234", output, "passing TEST= should run selected test" end private - def run_test_command(arguments = 'test/unit/test_test.rb') + def run_test_command(arguments = "test/unit/test_test.rb") Dir.chdir(app_path) { `bin/rails t #{arguments}` } end def create_model_with_fixture - script 'generate model user name:string' + script "generate model user name:string" - app_file 'test/fixtures/users.yml', <<-YAML.strip_heredoc + app_file "test/fixtures/users.yml", <<-YAML.strip_heredoc vampire: id: 1 name: Koyomi Araragi @@ -559,7 +559,7 @@ module ApplicationTests run_migration end - def create_fixture_test(path = :unit, name = 'test') + def create_fixture_test(path = :unit, name = "test") app_file "test/#{path}/#{name}_test.rb", <<-RUBY require 'test_helper' @@ -572,7 +572,7 @@ module ApplicationTests end def create_backtrace_test - app_file 'test/unit/backtrace_test.rb', <<-RUBY + app_file "test/unit/backtrace_test.rb", <<-RUBY require 'test_helper' class BacktraceTest < ActiveSupport::TestCase @@ -584,10 +584,10 @@ module ApplicationTests end def create_schema - app_file 'db/schema.rb', '' + app_file "db/schema.rb", "" end - def create_test_file(path = :unit, name = 'test', pass: true) + def create_test_file(path = :unit, name = "test", pass: true) app_file "test/#{path}/#{name}_test.rb", <<-RUBY require 'test_helper' @@ -601,7 +601,7 @@ module ApplicationTests end def create_env_test - app_file 'test/unit/env_test.rb', <<-RUBY + app_file "test/unit/env_test.rb", <<-RUBY require 'test_helper' class EnvTest < ActiveSupport::TestCase @@ -613,13 +613,13 @@ module ApplicationTests end def create_scaffold - script 'generate scaffold user name:string' - Dir.chdir(app_path) { File.exist?('app/models/user.rb') } + script "generate scaffold user name:string" + Dir.chdir(app_path) { File.exist?("app/models/user.rb") } run_migration end def create_controller - script 'generate controller admin/dashboard index' + script "generate controller admin/dashboard index" end def run_migration diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index 85b003fce9..32d2a6857c 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class TestTest < ActiveSupport::TestCase @@ -6,15 +6,14 @@ module ApplicationTests def setup build_app - boot_rails end def teardown teardown_app end - test "truth" do - app_file 'test/unit/foo_test.rb', <<-RUBY + test "simple successful test" do + app_file "test/unit/foo_test.rb", <<-RUBY require 'test_helper' class FooTest < ActiveSupport::TestCase @@ -24,20 +23,52 @@ module ApplicationTests end RUBY - assert_successful_test_run 'unit/foo_test.rb' + assert_successful_test_run "unit/foo_test.rb" + end + + test "after_run" do + app_file "test/unit/foo_test.rb", <<-RUBY + require 'test_helper' + + Minitest.after_run { puts "WORLD" } + Minitest.after_run { puts "HELLO" } + + class FooTest < ActiveSupport::TestCase + def test_truth + assert true + end + end + RUBY + + result = assert_successful_test_run "unit/foo_test.rb" + assert_equal ["HELLO", "WORLD"], result.scan(/HELLO|WORLD/) # only once and in correct order + end + + test "simple failed test" do + app_file "test/unit/foo_test.rb", <<-RUBY + require 'test_helper' + + class FooTest < ActiveSupport::TestCase + def test_truth + assert false + end + end + RUBY + + assert_unsuccessful_run "unit/foo_test.rb", "Failed assertion" end test "integration test" do - controller 'posts', <<-RUBY + controller "posts", <<-RUBY class PostsController < ActionController::Base end RUBY - app_file 'app/views/posts/index.html.erb', <<-HTML + app_file "app/views/posts/index.html.erb", <<-HTML Posts#index HTML - app_file 'test/integration/posts_test.rb', <<-RUBY + app_file "test/integration/posts_test.rb", <<-RUBY require 'test_helper' class PostsTest < ActionDispatch::IntegrationTest @@ -49,11 +80,11 @@ module ApplicationTests end RUBY - assert_successful_test_run 'integration/posts_test.rb' + assert_successful_test_run "integration/posts_test.rb" end test "enable full backtraces on test failures" do - app_file 'test/unit/failing_test.rb', <<-RUBY + app_file "test/unit/failing_test.rb", <<-RUBY require 'test_helper' class FailingTest < ActiveSupport::TestCase @@ -63,16 +94,16 @@ module ApplicationTests end RUBY - output = run_test_file('unit/failing_test.rb', env: { "BACKTRACE" => "1" }) + output = run_test_file("unit/failing_test.rb", env: { "BACKTRACE" => "1" }) assert_match %r{test/unit/failing_test\.rb}, output assert_match %r{test/unit/failing_test\.rb:4}, output end test "ruby schema migrations" do - output = script('generate model user name:string') + output = script("generate model user name:string") version = output.match(/(\d+)_create_users\.rb/)[1] - app_file 'test/models/user_test.rb', <<-RUBY + app_file "test/models/user_test.rb", <<-RUBY require 'test_helper' class UserTest < ActiveSupport::TestCase @@ -81,11 +112,11 @@ module ApplicationTests end end RUBY - app_file 'db/schema.rb', '' + app_file "db/schema.rb", "" assert_unsuccessful_run "models/user_test.rb", "Migrations are pending" - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: #{version}) do create_table :users do |t| t.string :name @@ -93,7 +124,7 @@ module ApplicationTests end RUBY - app_file 'config/initializers/disable_maintain_test_schema.rb', <<-RUBY + app_file "config/initializers/disable_maintain_test_schema.rb", <<-RUBY Rails.application.config.active_record.maintain_test_schema = false RUBY @@ -101,15 +132,15 @@ module ApplicationTests File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb" - result = assert_successful_test_run('models/user_test.rb') - assert !result.include?("create_table(:users)") + result = assert_successful_test_run("models/user_test.rb") + assert_not_includes result, "create_table(:users)" end test "sql structure migrations" do - output = script('generate model user name:string') + output = script("generate model user name:string") version = output.match(/(\d+)_create_users\.rb/)[1] - app_file 'test/models/user_test.rb', <<-RUBY + app_file "test/models/user_test.rb", <<-RUBY require 'test_helper' class UserTest < ActiveSupport::TestCase @@ -119,21 +150,21 @@ module ApplicationTests end RUBY - app_file 'db/structure.sql', '' - app_file 'config/initializers/enable_sql_schema_format.rb', <<-RUBY + app_file "db/structure.sql", "" + app_file "config/initializers/enable_sql_schema_format.rb", <<-RUBY Rails.application.config.active_record.schema_format = :sql RUBY assert_unsuccessful_run "models/user_test.rb", "Migrations are pending" - app_file 'db/structure.sql', <<-SQL + app_file "db/structure.sql", <<-SQL CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)); INSERT INTO schema_migrations (version) VALUES ('#{version}'); SQL - app_file 'config/initializers/disable_maintain_test_schema.rb', <<-RUBY + app_file "config/initializers/disable_maintain_test_schema.rb", <<-RUBY Rails.application.config.active_record.maintain_test_schema = false RUBY @@ -141,14 +172,14 @@ module ApplicationTests File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb" - assert_successful_test_run('models/user_test.rb') + assert_successful_test_run("models/user_test.rb") end test "sql structure migrations when adding column to existing table" do - output_1 = script('generate model user name:string') + output_1 = script("generate model user name:string") version_1 = output_1.match(/(\d+)_create_users\.rb/)[1] - app_file 'test/models/user_test.rb', <<-RUBY + app_file "test/models/user_test.rb", <<-RUBY require 'test_helper' class UserTest < ActiveSupport::TestCase test "user" do @@ -157,23 +188,23 @@ module ApplicationTests end RUBY - app_file 'config/initializers/enable_sql_schema_format.rb', <<-RUBY + app_file "config/initializers/enable_sql_schema_format.rb", <<-RUBY Rails.application.config.active_record.schema_format = :sql RUBY - app_file 'db/structure.sql', <<-SQL + app_file "db/structure.sql", <<-SQL CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)); INSERT INTO schema_migrations (version) VALUES ('#{version_1}'); SQL - assert_successful_test_run('models/user_test.rb') + assert_successful_test_run("models/user_test.rb") - output_2 = script('generate migration add_email_to_users') + output_2 = script("generate migration add_email_to_users") version_2 = output_2.match(/(\d+)_add_email_to_users\.rb/)[1] - app_file 'test/models/user_test.rb', <<-RUBY + app_file "test/models/user_test.rb", <<-RUBY require 'test_helper' class UserTest < ActiveSupport::TestCase @@ -183,7 +214,7 @@ module ApplicationTests end RUBY - app_file 'db/structure.sql', <<-SQL + app_file "db/structure.sql", <<-SQL CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "email" varchar(255)); @@ -191,17 +222,17 @@ module ApplicationTests INSERT INTO schema_migrations (version) VALUES ('#{version_2}'); SQL - assert_successful_test_run('models/user_test.rb') + assert_successful_test_run("models/user_test.rb") end # TODO: would be nice if we could detect the schema change automatically. # For now, the user has to synchronize the schema manually. # This test-case serves as a reminder for this use-case. test "manually synchronize test schema after rollback" do - output = script('generate model user name:string') + output = script("generate model user name:string") version = output.match(/(\d+)_create_users\.rb/)[1] - app_file 'test/models/user_test.rb', <<-RUBY + app_file "test/models/user_test.rb", <<-RUBY require 'test_helper' class UserTest < ActiveSupport::TestCase @@ -210,7 +241,7 @@ module ApplicationTests end end RUBY - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: #{version}) do create_table :users do |t| t.string :name @@ -221,7 +252,7 @@ module ApplicationTests assert_successful_test_run "models/user_test.rb" # Simulate `db:rollback` + edit of the migration file + `db:migrate` - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: #{version}) do create_table :users do |t| t.string :name @@ -241,10 +272,10 @@ Expected: ["id", "name"] end test "hooks for plugins" do - output = script('generate model user name:string') + output = script("generate model user name:string") version = output.match(/(\d+)_create_users\.rb/)[1] - app_file 'lib/tasks/hooks.rake', <<-RUBY + app_file "lib/tasks/hooks.rake", <<-RUBY task :before_hook do has_user_table = ActiveRecord::Base.connection.table_exists?('users') puts "before: " + has_user_table.to_s @@ -259,7 +290,7 @@ Expected: ["id", "name"] Rake::Task[:after_hook].invoke end RUBY - app_file 'test/models/user_test.rb', <<-RUBY + app_file "test/models/user_test.rb", <<-RUBY require 'test_helper' class UserTest < ActiveSupport::TestCase test "user" do @@ -269,7 +300,7 @@ Expected: ["id", "name"] RUBY # Simulate `db:migrate` - app_file 'db/schema.rb', <<-RUBY + app_file "db/schema.rb", <<-RUBY ActiveRecord::Schema.define(version: #{version}) do create_table :users do |t| t.string :name @@ -290,7 +321,7 @@ Expected: ["id", "name"] def assert_unsuccessful_run(name, message) result = run_test_file(name) assert_not_equal 0, $?.to_i - assert result.include?(message) + assert_includes result, message result end diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb index 894e18cb39..37f129475c 100644 --- a/railties/test/application/url_generation_test.rb +++ b/railties/test/application/url_generation_test.rb @@ -1,4 +1,4 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class UrlGenerationTest < ActiveSupport::TestCase @@ -9,7 +9,6 @@ module ApplicationTests end test "it works" do - boot_rails require "rails" require "action_controller/railtie" require "action_view/railtie" @@ -28,7 +27,7 @@ module ApplicationTests class ::OmgController < ::ApplicationController def index - render text: omg_path + render plain: omg_path end end @@ -36,7 +35,7 @@ module ApplicationTests get "/" => "omg#index", as: :omg end - require 'rack/test' + require "rack/test" extend Rack::Test::Methods get "/" @@ -44,12 +43,11 @@ module ApplicationTests end def test_routes_know_the_relative_root - boot_rails require "rails" require "action_controller/railtie" require "action_view/railtie" - relative_url = '/hello' + relative_url = "/hello" ENV["RAILS_RELATIVE_URL_ROOT"] = relative_url app = Class.new(Rails::Application) assert_equal relative_url, app.routes.relative_url_root diff --git a/railties/test/backtrace_cleaner_test.rb b/railties/test/backtrace_cleaner_test.rb index 2dd74f8fd1..17201d6f77 100644 --- a/railties/test/backtrace_cleaner_test.rb +++ b/railties/test/backtrace_cleaner_test.rb @@ -1,24 +1,32 @@ -require 'abstract_unit' -require 'rails/backtrace_cleaner' +require "abstract_unit" +require "rails/backtrace_cleaner" -class BacktraceCleanerVendorGemTest < ActiveSupport::TestCase +class BacktraceCleanerTest < ActiveSupport::TestCase def setup @cleaner = Rails::BacktraceCleaner.new end test "should format installed gems correctly" do - @backtrace = [ "#{Gem.path[0]}/gems/nosuchgem-1.2.3/lib/foo.rb" ] - @result = @cleaner.clean(@backtrace, :all) - assert_equal "nosuchgem (1.2.3) lib/foo.rb", @result[0] + backtrace = [ "#{Gem.path[0]}/gems/nosuchgem-1.2.3/lib/foo.rb" ] + result = @cleaner.clean(backtrace, :all) + assert_equal "nosuchgem (1.2.3) lib/foo.rb", result[0] end test "should format installed gems not in Gem.default_dir correctly" do - @target_dir = Gem.path.detect { |p| p != Gem.default_dir } + target_dir = Gem.path.detect { |p| p != Gem.default_dir } # skip this test if default_dir is the only directory on Gem.path if @target_dir - @backtrace = [ "#{@target_dir}/gems/nosuchgem-1.2.3/lib/foo.rb" ] - @result = @cleaner.clean(@backtrace, :all) - assert_equal "nosuchgem (1.2.3) lib/foo.rb", @result[0] + backtrace = [ "#{target_dir}/gems/nosuchgem-1.2.3/lib/foo.rb" ] + result = @cleaner.clean(backtrace, :all) + assert_equal "nosuchgem (1.2.3) lib/foo.rb", result[0] end end + + test "should consider traces from irb lines as User code" do + backtrace = [ "from (irb):1", + "from /Path/to/rails/railties/lib/rails/commands/console.rb:77:in `start'", + "from bin/rails:4:in `<main>'" ] + result = @cleaner.clean(backtrace, :all) + assert_equal "from (irb):1", result[0] + end end diff --git a/railties/test/code_statistics_calculator_test.rb b/railties/test/code_statistics_calculator_test.rb index cecc3908b3..2dba3c6e96 100644 --- a/railties/test/code_statistics_calculator_test.rb +++ b/railties/test/code_statistics_calculator_test.rb @@ -1,12 +1,12 @@ -require 'abstract_unit' -require 'rails/code_statistics_calculator' +require "abstract_unit" +require "rails/code_statistics_calculator" class CodeStatisticsCalculatorTest < ActiveSupport::TestCase def setup @code_statistics_calculator = CodeStatisticsCalculator.new end - test 'calculate statistics using #add_by_file_path' do + test "calculate statistics using #add_by_file_path" do code = <<-RUBY def foo puts 'foo' @@ -14,7 +14,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase end RUBY - temp_file 'stats.rb', code do |path| + temp_file "stats.rb", code do |path| @code_statistics_calculator.add_by_file_path path assert_equal 4, @code_statistics_calculator.lines @@ -24,7 +24,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase end end - test 'count number of methods in MiniTest file' do + test "count number of methods in MiniTest file" do code = <<-RUBY class FooTest < ActionController::TestCase test 'expectation' do @@ -37,13 +37,13 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase end RUBY - temp_file 'foo_test.rb', code do |path| + temp_file "foo_test.rb", code do |path| @code_statistics_calculator.add_by_file_path path assert_equal 2, @code_statistics_calculator.methods end end - test 'add statistics to another using #add' do + test "add statistics to another using #add" do code_statistics_calculator_1 = CodeStatisticsCalculator.new(1, 2, 3, 4) @code_statistics_calculator.add(code_statistics_calculator_1) @@ -61,7 +61,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 9, @code_statistics_calculator.methods end - test 'accumulate statistics using #add_by_io' do + test "accumulate statistics using #add_by_io" do code_statistics_calculator_1 = CodeStatisticsCalculator.new(1, 2, 3, 4) @code_statistics_calculator.add(code_statistics_calculator_1) @@ -82,7 +82,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 6, @code_statistics_calculator.methods end - test 'calculate number of Ruby methods' do + test "calculate number of Ruby methods" do code = <<-'CODE' def foo puts 'foo' @@ -101,7 +101,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 3, @code_statistics_calculator.methods end - test 'calculate Ruby LOCs' do + test "calculate Ruby LOCs" do code = <<-'CODE' def foo puts 'foo' @@ -119,7 +119,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 5, @code_statistics_calculator.code_lines end - test 'calculate number of Ruby classes' do + test "calculate number of Ruby classes" do code = <<-'CODE' class Foo < Bar def foo @@ -138,7 +138,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 2, @code_statistics_calculator.classes end - test 'skip Ruby comments' do + test "skip Ruby comments" do code = <<-'CODE' =begin class Foo @@ -160,7 +160,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 0, @code_statistics_calculator.methods end - test 'calculate number of JS methods' do + test "calculate number of JS methods" do code = <<-'CODE' function foo(x, y, z) { doX(); @@ -179,7 +179,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 3, @code_statistics_calculator.methods end - test 'calculate JS LOCs' do + test "calculate JS LOCs" do code = <<-'CODE' function foo() alert('foo'); @@ -196,7 +196,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 4, @code_statistics_calculator.code_lines end - test 'skip JS comments' do + test "skip JS comments" do code = <<-'CODE' /* * var f = function () { @@ -216,7 +216,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 0, @code_statistics_calculator.methods end - test 'calculate number of CoffeeScript methods' do + test "calculate number of CoffeeScript methods" do code = <<-'CODE' square = (x) -> x * x @@ -235,7 +235,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 4, @code_statistics_calculator.methods end - test 'calculate CoffeeScript LOCs' do + test "calculate CoffeeScript LOCs" do code = <<-'CODE' # Assignment: number = 42 @@ -256,7 +256,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 3, @code_statistics_calculator.code_lines end - test 'calculate number of CoffeeScript classes' do + test "calculate number of CoffeeScript classes" do code = <<-'CODE' class Animal constructor: (@name) -> @@ -277,7 +277,7 @@ class CodeStatisticsCalculatorTest < ActiveSupport::TestCase assert_equal 2, @code_statistics_calculator.classes end - test 'skip CoffeeScript comments' do + test "skip CoffeeScript comments" do code = <<-'CODE' ### class Animal @@ -299,7 +299,7 @@ class Animal assert_equal 0, @code_statistics_calculator.methods end - test 'count rake tasks' do + test "count rake tasks" do code = <<-'CODE' task :test_task do puts 'foo' @@ -317,7 +317,7 @@ class Animal private def temp_file(name, content) - dir = File.expand_path '../fixtures/tmp', __FILE__ + dir = File.expand_path "../fixtures/tmp", __FILE__ path = "#{dir}/#{name}" FileUtils.mkdir_p dir diff --git a/railties/test/code_statistics_test.rb b/railties/test/code_statistics_test.rb index 4d80901217..965b6eeb79 100644 --- a/railties/test/code_statistics_test.rb +++ b/railties/test/code_statistics_test.rb @@ -1,10 +1,10 @@ -require 'abstract_unit' -require 'rails/code_statistics' +require "abstract_unit" +require "rails/code_statistics" class CodeStatisticsTest < ActiveSupport::TestCase def setup - @tmp_path = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'tmp')) - @dir_js = File.join(@tmp_path, 'lib.js') + @tmp_path = File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "tmp")) + @dir_js = File.join(@tmp_path, "lib.js") FileUtils.mkdir_p(@dir_js) end @@ -12,22 +12,21 @@ class CodeStatisticsTest < ActiveSupport::TestCase FileUtils.rm_rf(@tmp_path) end - test 'ignores directories that happen to have source files extensions' do + test "ignores directories that happen to have source files extensions" do assert_nothing_raised do - @code_statistics = CodeStatistics.new(['tmp dir', @tmp_path]) + @code_statistics = CodeStatistics.new(["tmp dir", @tmp_path]) end end - test 'ignores hidden files' do - File.write File.join(@tmp_path, '.example.rb'), <<-CODE + test "ignores hidden files" do + File.write File.join(@tmp_path, ".example.rb"), <<-CODE def foo puts 'foo' end CODE assert_nothing_raised do - CodeStatistics.new(['hidden file', @tmp_path]) + CodeStatistics.new(["hidden file", @tmp_path]) end end - end diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index de0cf0ba9e..4fc082e4ca 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -1,6 +1,7 @@ -require 'abstract_unit' -require 'env_helpers' -require 'rails/commands/console' +require "abstract_unit" +require "env_helpers" +require "rails/command" +require "rails/commands/console/console_command" class Rails::ConsoleTest < ActiveSupport::TestCase include EnvHelpers @@ -40,7 +41,6 @@ class Rails::ConsoleTest < ActiveSupport::TestCase def test_start_with_sandbox start ["--sandbox"] - assert app.console.started? assert app.sandbox assert_match(/Loading \w+ environment in sandbox \(Rails/, output) @@ -64,52 +64,60 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_default_environment_with_rails_env - with_rails_env 'special-production' do + with_rails_env "special-production" do start assert_match(/\sspecial-production\s/, output) end end def test_default_environment_with_rack_env - with_rack_env 'production' do + with_rack_env "production" do start assert_match(/\sproduction\s/, output) end end def test_e_option - start ['-e', 'special-production'] + start ["-e", "special-production"] assert_match(/\sspecial-production\s/, output) end def test_environment_option - start ['--environment=special-production'] + start ["--environment=special-production"] assert_match(/\sspecial-production\s/, output) end def test_rails_env_is_production_when_first_argument_is_p - start ['p'] + start ["p"] assert_match(/\sproduction\s/, output) end def test_rails_env_is_test_when_first_argument_is_t - start ['t'] + start ["t"] assert_match(/\stest\s/, output) end def test_rails_env_is_development_when_argument_is_d - start ['d'] + start ["d"] assert_match(/\sdevelopment\s/, output) end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - stubbed_console = Class.new(Rails::Console) do - def available_environments - ['dev'] + Rails::Command::ConsoleCommand.class_eval do + alias_method :old_environments, :available_environments + + define_method :available_environments do + ["dev"] end end - options = stubbed_console.parse_arguments(['dev']) - assert_match('dev', options[:environment]) + + assert_match("dev", parse_arguments(["dev"])[:environment]) + ensure + Rails::Command::ConsoleCommand.class_eval do + undef_method :available_environments + alias_method :available_environments, :old_environments + undef_method :old_environments + end end attr_reader :output @@ -117,38 +125,53 @@ class Rails::ConsoleTest < ActiveSupport::TestCase private - def start(argv = []) - rails_console = Rails::Console.new(app, parse_arguments(argv)) - @output = capture(:stdout) { rails_console.start } - end + def start(argv = []) + rails_console = Rails::Console.new(app, parse_arguments(argv)) + @output = capture(:stdout) { rails_console.start } + end - def app - @app ||= build_app(FakeConsole) - end + def app + @app ||= build_app(FakeConsole) + end - def build_app(console) - mocked_console = Class.new do - attr_reader :sandbox, :console + def build_app(console) + mocked_console = Class.new do + attr_reader :sandbox, :console - def initialize(console) - @console = console - end + def initialize(console) + @console = console + end + + def config + self + end - def config - self + def sandbox=(arg) + @sandbox = arg + end + + def load_console + end end + mocked_console.new(console) + end - def sandbox=(arg) - @sandbox = arg + def parse_arguments(args) + Rails::Command::ConsoleCommand.class_eval do + alias_method :old_perform, :perform + define_method(:perform) do + extract_environment_option_from_argument + + options + end end - def load_console + Rails::Command.invoke(:console, args) + ensure + Rails::Command::ConsoleCommand.class_eval do + undef_method :perform + alias_method :perform, :old_perform + undef_method :old_perform end end - mocked_console.new(console) - end - - def parse_arguments(args) - Rails::Console.parse_arguments(args) - end end diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index a5aa6c14a2..2ddb269eae 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -1,17 +1,16 @@ -require 'abstract_unit' -require 'minitest/mock' -require 'rails/commands/dbconsole' +require "abstract_unit" +require "minitest/mock" +require "rails/command" +require "rails/commands/dbconsole/dbconsole_command" class Rails::DBConsoleTest < ActiveSupport::TestCase - - def setup - Rails::DBConsole.const_set('APP_PATH', 'rails/all') + Rails::DBConsole.const_set("APP_PATH", "rails/all") end def teardown - Rails::DBConsole.send(:remove_const, 'APP_PATH') - %w[PGUSER PGHOST PGPORT PGPASSWORD DATABASE_URL].each{|key| ENV.delete(key)} + Rails::DBConsole.send(:remove_const, "APP_PATH") + %w[PGUSER PGHOST PGPORT PGPASSWORD DATABASE_URL].each { |key| ENV.delete(key) } end def test_config_with_db_config_only @@ -41,7 +40,7 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end def test_config_with_database_url_only - ENV['DATABASE_URL'] = 'postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000' + ENV["DATABASE_URL"] = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000" expected = { "adapter" => "postgresql", "host" => "localhost", @@ -60,7 +59,7 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase def test_config_choose_database_url_if_exists host = "database-url-host.com" - ENV['DATABASE_URL'] = "postgresql://foo:bar@#{host}:9000/foo_test?pool=5&timeout=3000" + ENV["DATABASE_URL"] = "postgresql://foo:bar@#{host}:9000/foo_test?pool=5&timeout=3000" sample_config = { "test" => { "adapter" => "postgresql", @@ -81,144 +80,138 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase def test_env assert_equal "test", Rails::DBConsole.new.environment - ENV['RAILS_ENV'] = nil - ENV['RACK_ENV'] = nil + ENV["RAILS_ENV"] = nil + ENV["RACK_ENV"] = nil Rails.stub(:respond_to?, false) do assert_equal "development", Rails::DBConsole.new.environment - ENV['RACK_ENV'] = "rack_env" + ENV["RACK_ENV"] = "rack_env" assert_equal "rack_env", Rails::DBConsole.new.environment - ENV['RAILS_ENV'] = "rails_env" + ENV["RAILS_ENV"] = "rails_env" assert_equal "rails_env", Rails::DBConsole.new.environment end ensure - ENV['RAILS_ENV'] = "test" - ENV['RACK_ENV'] = nil + ENV["RAILS_ENV"] = "test" + ENV["RACK_ENV"] = nil end def test_rails_env_is_development_when_argument_is_dev - Rails::DBConsole.stub(:available_environments, ['development', 'test']) do - options = Rails::DBConsole.send(:parse_arguments, ['dev']) - assert_match('development', options[:environment]) + stub_available_environments([ "development", "test" ]) do + assert_match("development", parse_arguments([ "dev" ])[:environment]) end end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - Rails::DBConsole.stub(:available_environments, ['dev']) do - options = Rails::DBConsole.send(:parse_arguments, ['dev']) - assert_match('dev', options[:environment]) + stub_available_environments([ "dev" ]) do + assert_match("dev", parse_arguments([ "dev" ])[:environment]) end end def test_mysql - start(adapter: 'mysql2', database: 'db') + start(adapter: "mysql2", database: "db") assert !aborted - assert_equal [%w[mysql mysql5], 'db'], dbconsole.find_cmd_and_exec_args + assert_equal [%w[mysql mysql5], "db"], dbconsole.find_cmd_and_exec_args end def test_mysql_full - start(adapter: 'mysql2', database: 'db', host: 'locahost', port: 1234, socket: 'socket', username: 'user', password: 'qwerty', encoding: 'UTF-8') + start(adapter: "mysql2", database: "db", host: "locahost", port: 1234, socket: "socket", username: "user", password: "qwerty", encoding: "UTF-8") assert !aborted - assert_equal [%w[mysql mysql5], '--host=locahost', '--port=1234', '--socket=socket', '--user=user', '--default-character-set=UTF-8', '-p', 'db'], dbconsole.find_cmd_and_exec_args + assert_equal [%w[mysql mysql5], "--host=locahost", "--port=1234", "--socket=socket", "--user=user", "--default-character-set=UTF-8", "-p", "db"], dbconsole.find_cmd_and_exec_args end def test_mysql_include_password - start({adapter: 'mysql2', database: 'db', username: 'user', password: 'qwerty'}, ['-p']) + start({ adapter: "mysql2", database: "db", username: "user", password: "qwerty" }, ["-p"]) assert !aborted - assert_equal [%w[mysql mysql5], '--user=user', '--password=qwerty', 'db'], dbconsole.find_cmd_and_exec_args + assert_equal [%w[mysql mysql5], "--user=user", "--password=qwerty", "db"], dbconsole.find_cmd_and_exec_args end def test_postgresql - start(adapter: 'postgresql', database: 'db') + start(adapter: "postgresql", database: "db") assert !aborted - assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args + assert_equal ["psql", "db"], dbconsole.find_cmd_and_exec_args end def test_postgresql_full - start(adapter: 'postgresql', database: 'db', username: 'user', password: 'q1w2e3', host: 'host', port: 5432) + start(adapter: "postgresql", database: "db", username: "user", password: "q1w2e3", host: "host", port: 5432) assert !aborted - assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args - assert_equal 'user', ENV['PGUSER'] - assert_equal 'host', ENV['PGHOST'] - assert_equal '5432', ENV['PGPORT'] - assert_not_equal 'q1w2e3', ENV['PGPASSWORD'] + assert_equal ["psql", "db"], dbconsole.find_cmd_and_exec_args + assert_equal "user", ENV["PGUSER"] + assert_equal "host", ENV["PGHOST"] + assert_equal "5432", ENV["PGPORT"] + assert_not_equal "q1w2e3", ENV["PGPASSWORD"] end def test_postgresql_include_password - start({adapter: 'postgresql', database: 'db', username: 'user', password: 'q1w2e3'}, ['-p']) + start({ adapter: "postgresql", database: "db", username: "user", password: "q1w2e3" }, ["-p"]) assert !aborted - assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args - assert_equal 'user', ENV['PGUSER'] - assert_equal 'q1w2e3', ENV['PGPASSWORD'] + assert_equal ["psql", "db"], dbconsole.find_cmd_and_exec_args + assert_equal "user", ENV["PGUSER"] + assert_equal "q1w2e3", ENV["PGPASSWORD"] end def test_sqlite3 - start(adapter: 'sqlite3', database: 'db.sqlite3') + start(adapter: "sqlite3", database: "db.sqlite3") assert !aborted - assert_equal ['sqlite3', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args + assert_equal ["sqlite3", Rails.root.join("db.sqlite3").to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_mode - start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--mode', 'html']) + start({ adapter: "sqlite3", database: "db.sqlite3" }, ["--mode", "html"]) assert !aborted - assert_equal ['sqlite3', '-html', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args + assert_equal ["sqlite3", "-html", Rails.root.join("db.sqlite3").to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_header - start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--header']) - assert_equal ['sqlite3', '-header', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args + start({ adapter: "sqlite3", database: "db.sqlite3" }, ["--header"]) + assert_equal ["sqlite3", "-header", Rails.root.join("db.sqlite3").to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_db_absolute_path - start(adapter: 'sqlite3', database: '/tmp/db.sqlite3') + start(adapter: "sqlite3", database: "/tmp/db.sqlite3") assert !aborted - assert_equal ['sqlite3', '/tmp/db.sqlite3'], dbconsole.find_cmd_and_exec_args + assert_equal ["sqlite3", "/tmp/db.sqlite3"], dbconsole.find_cmd_and_exec_args end def test_sqlite3_db_without_defined_rails_root Rails.stub(:respond_to?, false) do - start(adapter: 'sqlite3', database: 'config/db.sqlite3') + start(adapter: "sqlite3", database: "config/db.sqlite3") assert !aborted - assert_equal ['sqlite3', Rails.root.join('../config/db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args + assert_equal ["sqlite3", Rails.root.join("../config/db.sqlite3").to_s], dbconsole.find_cmd_and_exec_args end end def test_oracle - start(adapter: 'oracle', database: 'db', username: 'user', password: 'secret') + start(adapter: "oracle", database: "db", username: "user", password: "secret") assert !aborted - assert_equal ['sqlplus', 'user@db'], dbconsole.find_cmd_and_exec_args + assert_equal ["sqlplus", "user@db"], dbconsole.find_cmd_and_exec_args end def test_oracle_include_password - start({adapter: 'oracle', database: 'db', username: 'user', password: 'secret'}, ['-p']) + start({ adapter: "oracle", database: "db", username: "user", password: "secret" }, ["-p"]) assert !aborted - assert_equal ['sqlplus', 'user/secret@db'], dbconsole.find_cmd_and_exec_args + assert_equal ["sqlplus", "user/secret@db"], dbconsole.find_cmd_and_exec_args end def test_unknown_command_line_client - start(adapter: 'unknown', database: 'db') + start(adapter: "unknown", database: "db") assert aborted assert_match(/Unknown command-line client for db/, output) end def test_print_help_short stdout = capture(:stdout) do - start({}, ['-h']) + Rails::Command.invoke(:dbconsole, ["-h"]) end - assert aborted - assert_equal '', output - assert_match(/Usage:.*dbconsole/, stdout) + assert_match(/bin\/rails dbconsole \[environment\]/, stdout) end def test_print_help_long stdout = capture(:stdout) do - start({}, ['--help']) + Rails::Command.invoke(:dbconsole, ["--help"]) end - assert aborted - assert_equal '', output - assert_match(/Usage:.*dbconsole/, stdout) + assert_match(/bin\/rails dbconsole \[environment\]/, stdout) end attr_reader :aborted, :output @@ -226,39 +219,76 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase private - def app_db_config(results) - Rails.application.config.stub(:database_configuration, results || {}) do - yield + def app_db_config(results) + Rails.application.config.stub(:database_configuration, results || {}) do + yield + end end - end - def dbconsole - @dbconsole ||= Class.new(Rails::DBConsole) do - attr_reader :find_cmd_and_exec_args + def make_dbconsole + Class.new(Rails::DBConsole) do + attr_reader :find_cmd_and_exec_args - def find_cmd_and_exec(*args) - @find_cmd_and_exec_args = args + def find_cmd_and_exec(*args) + @find_cmd_and_exec_args = args + end end - end.new(nil) - end + end - def start(config = {}, argv = []) - dbconsole.stub(:config, config.stringify_keys) do - dbconsole.stub(:arguments, argv) do - capture_abort { dbconsole.start } + attr_reader :dbconsole + + def start(config = {}, argv = []) + @dbconsole = make_dbconsole.new(parse_arguments(argv)) + @dbconsole.stub(:config, config.stringify_keys) do + capture_abort { @dbconsole.start } end end - end - def capture_abort - @aborted = false - @output = capture(:stderr) do - begin - yield - rescue SystemExit - @aborted = true + def capture_abort + @aborted = false + @output = capture(:stderr) do + begin + yield + rescue SystemExit + @aborted = true + end end end - end + def stub_available_environments(environments) + Rails::Command::DbconsoleCommand.class_eval do + alias_method :old_environments, :available_environments + + define_method :available_environments do + environments + end + end + + yield + ensure + Rails::Command::DbconsoleCommand.class_eval do + undef_method :available_environments + alias_method :available_environments, :old_environments + undef_method :old_environments + end + end + + def parse_arguments(args) + Rails::Command::DbconsoleCommand.class_eval do + alias_method :old_perform, :perform + define_method(:perform) do + extract_environment_option_from_argument + + options + end + end + + Rails::Command.invoke(:dbconsole, args) + ensure + Rails::Command::DbconsoleCommand.class_eval do + undef_method :perform + alias_method :perform, :old_perform + undef_method :old_perform + end + end end diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index 38a1605d1f..391886bf33 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -1,6 +1,7 @@ -require 'abstract_unit' -require 'env_helpers' -require 'rails/commands/server' +require "abstract_unit" +require "env_helpers" +require "rails/command" +require "rails/commands/server/server_command" class Rails::ServerTest < ActiveSupport::TestCase include EnvHelpers @@ -8,14 +9,14 @@ class Rails::ServerTest < ActiveSupport::TestCase def test_environment_with_server_option args = ["thin", "-e", "production"] options = Rails::Server::Options.new.parse!(args) - assert_equal 'production', options[:environment] - assert_equal 'thin', options[:server] + assert_equal "production", options[:environment] + assert_equal "thin", options[:server] end def test_environment_without_server_option args = ["-e", "production"] options = Rails::Server::Options.new.parse!(args) - assert_equal 'production', options[:environment] + assert_equal "production", options[:environment] assert_nil options[:server] end @@ -23,23 +24,23 @@ class Rails::ServerTest < ActiveSupport::TestCase args = ["thin"] options = Rails::Server::Options.new.parse!(args) assert_nil options[:environment] - assert_equal 'thin', options[:server] + assert_equal "thin", options[:server] end def test_environment_with_rails_env with_rack_env nil do - with_rails_env 'production' do + with_rails_env "production" do server = Rails::Server.new - assert_equal 'production', server.options[:environment] + assert_equal "production", server.options[:environment] end end end def test_environment_with_rack_env with_rails_env nil do - with_rack_env 'production' do + with_rack_env "production" do server = Rails::Server.new - assert_equal 'production', server.options[:environment] + assert_equal "production", server.options[:environment] end end end @@ -51,6 +52,13 @@ class Rails::ServerTest < ActiveSupport::TestCase end end + def test_environment_with_host + switch_env "HOST", "1.2.3.4" do + server = Rails::Server.new + assert_equal "1.2.3.4", server.options[:Host] + end + end + def test_caching_without_option args = [] options = Rails::Server::Options.new.parse!(args) @@ -83,25 +91,25 @@ class Rails::ServerTest < ActiveSupport::TestCase options = Rails::Server::Options.new.parse!(args) assert_equal false, options[:log_stdout] - with_rack_env 'development' do + with_rack_env "development" do args = [] options = Rails::Server::Options.new.parse!(args) assert_equal true, options[:log_stdout] end - with_rack_env 'production' do + with_rack_env "production" do args = [] options = Rails::Server::Options.new.parse!(args) assert_equal false, options[:log_stdout] end - with_rails_env 'development' do + with_rails_env "development" do args = [] options = Rails::Server::Options.new.parse!(args) assert_equal true, options[:log_stdout] end - with_rails_env 'production' do + with_rails_env "production" do args = [] options = Rails::Server::Options.new.parse!(args) assert_equal false, options[:log_stdout] diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb index d5072614cf..559ce72693 100644 --- a/railties/test/configuration/middleware_stack_proxy_test.rb +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -1,8 +1,8 @@ -require 'active_support' -require 'active_support/testing/autorun' -require 'rails/configuration' -require 'active_support/test_case' -require 'minitest/mock' +require "active_support" +require "active_support/testing/autorun" +require "rails/configuration" +require "active_support/test_case" +require "minitest/mock" module Rails module Configuration @@ -50,12 +50,12 @@ module Rails private - def assert_playback(msg_name, args) - mock = Minitest::Mock.new - mock.expect :send, nil, [msg_name, args] - @stack.merge_into(mock) - mock.verify - end + def assert_playback(msg_name, args) + mock = Minitest::Mock.new + mock.expect :send, nil, [msg_name, args] + @stack.merge_into(mock) + mock.verify + end end end end diff --git a/railties/test/engine/commands_tasks_test.rb b/railties/test/engine/commands_tasks_test.rb new file mode 100644 index 0000000000..817175b9ef --- /dev/null +++ b/railties/test/engine/commands_tasks_test.rb @@ -0,0 +1,24 @@ +require "abstract_unit" + +class Rails::Engine::CommandsTasksTest < ActiveSupport::TestCase + def setup + @destination_root = Dir.mktmpdir("bukkits") + Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --mountable` } + end + + def teardown + FileUtils.rm_rf(@destination_root) + end + + def test_help_command_work_inside_engine + output = capture(:stderr) do + Dir.chdir(plugin_path) { `bin/rails --help` } + end + assert_no_match "NameError", output + end + + private + def plugin_path + "#{@destination_root}/bukkits" + end +end diff --git a/railties/test/engine_test.rb b/railties/test/engine_test.rb index f46fb748f5..248afa2d2c 100644 --- a/railties/test/engine_test.rb +++ b/railties/test/engine_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class EngineTest < ActiveSupport::TestCase test "reports routes as available only if they're actually present" do diff --git a/railties/test/env_helpers.rb b/railties/test/env_helpers.rb index 330fe150ca..1f64d5fda3 100644 --- a/railties/test/env_helpers.rb +++ b/railties/test/env_helpers.rb @@ -1,30 +1,30 @@ -require 'rails' +require "rails" module EnvHelpers private - def with_rails_env(env) - Rails.instance_variable_set :@_env, nil - switch_env 'RAILS_ENV', env do - switch_env 'RACK_ENV', nil do - yield + def with_rails_env(env) + Rails.instance_variable_set :@_env, nil + switch_env "RAILS_ENV", env do + switch_env "RACK_ENV", nil do + yield + end end end - end - def with_rack_env(env) - Rails.instance_variable_set :@_env, nil - switch_env 'RACK_ENV', env do - switch_env 'RAILS_ENV', nil do - yield + def with_rack_env(env) + Rails.instance_variable_set :@_env, nil + switch_env "RACK_ENV", env do + switch_env "RAILS_ENV", nil do + yield + end end end - end - def switch_env(key, value) - old, ENV[key] = ENV[key], value - yield - ensure - ENV[key] = old - end + def switch_env(key, value) + old, ENV[key] = ENV[key], value + yield + ensure + ENV[key] = old + end end diff --git a/railties/test/fixtures/about_yml_plugins/bad_about_yml/init.rb b/railties/test/fixtures/about_yml_plugins/bad_about_yml/init.rb index d4262f8971..636bc1a8ab 100644 --- a/railties/test/fixtures/about_yml_plugins/bad_about_yml/init.rb +++ b/railties/test/fixtures/about_yml_plugins/bad_about_yml/init.rb @@ -1 +1 @@ -# intentionally empty
\ No newline at end of file +# intentionally empty diff --git a/railties/test/fixtures/about_yml_plugins/plugin_without_about_yml/init.rb b/railties/test/fixtures/about_yml_plugins/plugin_without_about_yml/init.rb index d4262f8971..636bc1a8ab 100644 --- a/railties/test/fixtures/about_yml_plugins/plugin_without_about_yml/init.rb +++ b/railties/test/fixtures/about_yml_plugins/plugin_without_about_yml/init.rb @@ -1 +1 @@ -# intentionally empty
\ No newline at end of file +# intentionally empty diff --git a/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb b/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb index a7d079a1bc..1139350b94 100644 --- a/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb +++ b/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators/active_record' +require "rails/generators/active_record" module ActiveRecord module Generators diff --git a/railties/test/fixtures/lib/generators/model_generator.rb b/railties/test/fixtures/lib/generators/model_generator.rb index 9098a8a354..0905fa9631 100644 --- a/railties/test/fixtures/lib/generators/model_generator.rb +++ b/railties/test/fixtures/lib/generators/model_generator.rb @@ -1 +1 @@ -raise "I should never be loaded"
\ No newline at end of file +raise "I should never be loaded" diff --git a/railties/test/fixtures/lib/generators/usage_template/usage_template_generator.rb b/railties/test/fixtures/lib/generators/usage_template/usage_template_generator.rb index 078b0f9412..21b0ff6c28 100644 --- a/railties/test/fixtures/lib/generators/usage_template/usage_template_generator.rb +++ b/railties/test/fixtures/lib/generators/usage_template/usage_template_generator.rb @@ -1,4 +1,4 @@ -require 'rails/generators' +require "rails/generators" class UsageTemplateGenerator < Rails::Generators::Base source_root File.expand_path("templates", File.dirname(__FILE__)) diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 3b2b3c37d0..0a26897a4d 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -1,6 +1,6 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/app/app_generator' -require 'env_helpers' +require "generators/generators_test_helper" +require "rails/generators/rails/app/app_generator" +require "env_helpers" class ActionsTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -19,98 +19,98 @@ class ActionsTest < Rails::Generators::TestCase end def test_invoke_other_generator_with_shortcut - action :invoke, 'model', ['my_model'] - assert_file 'app/models/my_model.rb', /MyModel/ + action :invoke, "model", ["my_model"] + assert_file "app/models/my_model.rb", /MyModel/ end def test_invoke_other_generator_with_full_namespace - action :invoke, 'rails:model', ['my_model'] - assert_file 'app/models/my_model.rb', /MyModel/ + action :invoke, "rails:model", ["my_model"] + assert_file "app/models/my_model.rb", /MyModel/ end def test_create_file_should_write_data_to_file_path - action :create_file, 'lib/test_file.rb', 'heres test data' - assert_file 'lib/test_file.rb', 'heres test data' + action :create_file, "lib/test_file.rb", "heres test data" + assert_file "lib/test_file.rb", "heres test data" end def test_create_file_should_write_block_contents_to_file_path - action(:create_file, 'lib/test_file.rb'){ 'heres block data' } - assert_file 'lib/test_file.rb', 'heres block data' + action(:create_file, "lib/test_file.rb") { "heres block data" } + assert_file "lib/test_file.rb", "heres block data" end def test_add_source_adds_source_to_gemfile run_generator - action :add_source, 'http://gems.github.com' - assert_file 'Gemfile', /source 'http:\/\/gems\.github\.com'/ + action :add_source, "http://gems.github.com" + assert_file "Gemfile", /source 'http:\/\/gems\.github\.com'/ end def test_add_source_with_block_adds_source_to_gemfile_with_gem run_generator - action :add_source, 'http://gems.github.com' do - gem 'rspec-rails' + action :add_source, "http://gems.github.com" do + gem "rspec-rails" end - assert_file 'Gemfile', /source 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ + assert_file "Gemfile", /source 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ end def test_add_source_with_block_adds_source_to_gemfile_after_gem run_generator - action :gem, 'will-paginate' - action :add_source, 'http://gems.github.com' do - gem 'rspec-rails' + action :gem, "will-paginate" + action :add_source, "http://gems.github.com" do + gem "rspec-rails" end - assert_file 'Gemfile', /gem 'will-paginate'\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ + assert_file "Gemfile", /gem 'will-paginate'\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ end def test_gem_should_put_gem_dependency_in_gemfile run_generator - action :gem, 'will-paginate' - assert_file 'Gemfile', /gem 'will\-paginate'/ + action :gem, "will-paginate" + assert_file "Gemfile", /gem 'will\-paginate'/ end def test_gem_with_version_should_include_version_in_gemfile run_generator - action :gem, 'rspec', '>=2.0.0.a5' + action :gem, "rspec", ">=2.0.0.a5" - assert_file 'Gemfile', /gem 'rspec', '>=2.0.0.a5'/ + assert_file "Gemfile", /gem 'rspec', '>=2.0.0.a5'/ end def test_gem_should_insert_on_separate_lines run_generator - File.open('Gemfile', 'a') {|f| f.write('# Some content...') } + File.open("Gemfile", "a") { |f| f.write("# Some content...") } - action :gem, 'rspec' - action :gem, 'rspec-rails' + action :gem, "rspec" + action :gem, "rspec-rails" - assert_file 'Gemfile', /^gem 'rspec'$/ - assert_file 'Gemfile', /^gem 'rspec-rails'$/ + assert_file "Gemfile", /^gem 'rspec'$/ + assert_file "Gemfile", /^gem 'rspec-rails'$/ end def test_gem_should_include_options run_generator - action :gem, 'rspec', github: 'dchelimsky/rspec', tag: '1.2.9.rc1' + action :gem, "rspec", github: "dchelimsky/rspec", tag: "1.2.9.rc1" - assert_file 'Gemfile', /gem 'rspec', github: 'dchelimsky\/rspec', tag: '1\.2\.9\.rc1'/ + assert_file "Gemfile", /gem 'rspec', github: 'dchelimsky\/rspec', tag: '1\.2\.9\.rc1'/ end def test_gem_with_non_string_options run_generator - action :gem, 'rspec', require: false - action :gem, 'rspec-rails', group: [:development, :test] + action :gem, "rspec", require: false + action :gem, "rspec-rails", group: [:development, :test] - assert_file 'Gemfile', /^gem 'rspec', require: false$/ - assert_file 'Gemfile', /^gem 'rspec-rails', group: \[:development, :test\]$/ + assert_file "Gemfile", /^gem 'rspec', require: false$/ + assert_file "Gemfile", /^gem 'rspec-rails', group: \[:development, :test\]$/ end def test_gem_falls_back_to_inspect_if_string_contains_single_quote run_generator - action :gem, 'rspec', ">=2.0'0" + action :gem, "rspec", ">=2.0'0" - assert_file 'Gemfile', /^gem 'rspec', ">=2\.0'0"$/ + assert_file "Gemfile", /^gem 'rspec', ">=2\.0'0"$/ end def test_gem_works_even_if_frozen_string_is_passed_as_argument @@ -118,34 +118,34 @@ class ActionsTest < Rails::Generators::TestCase action :gem, "frozen_gem".freeze, "1.0.0".freeze - assert_file 'Gemfile', /^gem 'frozen_gem', '1.0.0'$/ + assert_file "Gemfile", /^gem 'frozen_gem', '1.0.0'$/ end def test_gem_group_should_wrap_gems_in_a_group run_generator action :gem_group, :development, :test do - gem 'rspec-rails' + gem "rspec-rails" end action :gem_group, :test do - gem 'fakeweb' + gem "fakeweb" end - assert_file 'Gemfile', /\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend/ + assert_file "Gemfile", /\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend/ end def test_environment_should_include_data_in_environment_initializer_block run_generator autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]' action :environment, autoload_paths - assert_file 'config/application.rb', / class Application < Rails::Application\n #{Regexp.escape(autoload_paths)}/ + assert_file "config/application.rb", / class Application < Rails::Application\n #{Regexp.escape(autoload_paths)}/ end def test_environment_should_include_data_in_environment_initializer_block_with_env_option run_generator autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]' - action :environment, autoload_paths, env: 'development' + action :environment, autoload_paths, env: "development" assert_file "config/environments/development.rb", /Rails\.application\.configure do\n #{Regexp.escape(autoload_paths)}/ end @@ -153,80 +153,80 @@ class ActionsTest < Rails::Generators::TestCase run_generator action :environment do - _ = '# This wont be added'# assignment to silence parse-time warning "unused literal ignored" - '# This will be added' + _ = "# This wont be added"# assignment to silence parse-time warning "unused literal ignored" + "# This will be added" end - assert_file 'config/application.rb' do |content| + assert_file "config/application.rb" do |content| assert_match(/# This will be added/, content) assert_no_match(/# This wont be added/, content) end end def test_git_with_symbol_should_run_command_using_git_scm - assert_called_with(generator, :run, ['git init']) do + assert_called_with(generator, :run, ["git init"]) do action :git, :init end end def test_git_with_hash_should_run_each_command_using_git_scm assert_called_with(generator, :run, [ ["git rm README"], ["git add ."] ]) do - action :git, rm: 'README', add: '.' + action :git, rm: "README", add: "." end end def test_vendor_should_write_data_to_file_in_vendor - action :vendor, 'vendor_file.rb', '# vendor data' - assert_file 'vendor/vendor_file.rb', '# vendor data' + action :vendor, "vendor_file.rb", "# vendor data" + assert_file "vendor/vendor_file.rb", "# vendor data" end def test_lib_should_write_data_to_file_in_lib - action :lib, 'my_library.rb', 'class MyLibrary' - assert_file 'lib/my_library.rb', 'class MyLibrary' + action :lib, "my_library.rb", "class MyLibrary" + assert_file "lib/my_library.rb", "class MyLibrary" end def test_rakefile_should_write_date_to_file_in_lib_tasks - action :rakefile, 'myapp.rake', 'task run: [:environment]' - assert_file 'lib/tasks/myapp.rake', 'task run: [:environment]' + action :rakefile, "myapp.rake", "task run: [:environment]" + assert_file "lib/tasks/myapp.rake", "task run: [:environment]" end def test_initializer_should_write_date_to_file_in_config_initializers - action :initializer, 'constants.rb', 'MY_CONSTANT = 42' - assert_file 'config/initializers/constants.rb', 'MY_CONSTANT = 42' + action :initializer, "constants.rb", "MY_CONSTANT = 42" + assert_file "config/initializers/constants.rb", "MY_CONSTANT = 42" end def test_generate_should_run_script_generate_with_argument_and_options - assert_called_with(generator, :run_ruby_script, ['bin/rails generate model MyModel', verbose: false]) do - action :generate, 'model', 'MyModel' + assert_called_with(generator, :run_ruby_script, ["bin/rails generate model MyModel", verbose: false]) do + action :generate, "model", "MyModel" end end def test_rails_should_run_rake_command_with_default_env assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do - action :rake, 'log:clear' + action :rake, "log:clear" end end end def test_rails_with_env_option_should_run_rake_command_in_env - assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do - action :rake, 'log:clear', env: 'production' + assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=production", verbose: false]) do + action :rake, "log:clear", env: "production" end end test "rails command with RAILS_ENV variable should run rake command in env" do - assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do + assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=production", verbose: false]) do with_rails_env "production" do - action :rake, 'log:clear' + action :rake, "log:clear" end end end test "env option should win over RAILS_ENV variable when running rake" do - assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do + assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=production", verbose: false]) do with_rails_env "staging" do - action :rake, 'log:clear', env: 'production' + action :rake, "log:clear", env: "production" end end end @@ -234,7 +234,7 @@ class ActionsTest < Rails::Generators::TestCase test "rails command with sudo option should run rake command with sudo" do assert_called_with(generator, :run, ["sudo rake log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do - action :rake, 'log:clear', sudo: true + action :rake, "log:clear", sudo: true end end end @@ -242,29 +242,29 @@ class ActionsTest < Rails::Generators::TestCase test "rails command should run rails_command with default env" do assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do - action :rails_command, 'log:clear' + action :rails_command, "log:clear" end end end test "rails command with env option should run rails_command with same env" do - assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do - action :rails_command, 'log:clear', env: 'production' + assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=production", verbose: false]) do + action :rails_command, "log:clear", env: "production" end end test "rails command with RAILS_ENV variable should run rails_command in env" do - assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do + assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=production", verbose: false]) do with_rails_env "production" do - action :rails_command, 'log:clear' + action :rails_command, "log:clear" end end end def test_env_option_should_win_over_rails_env_variable_when_running_rails - assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do + assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=production", verbose: false]) do with_rails_env "staging" do - action :rails_command, 'log:clear', env: 'production' + action :rails_command, "log:clear", env: "production" end end end @@ -272,13 +272,13 @@ class ActionsTest < Rails::Generators::TestCase test "rails command with sudo option should run rails_command with sudo" do assert_called_with(generator, :run, ["sudo rails log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do - action :rails_command, 'log:clear', sudo: true + action :rails_command, "log:clear", sudo: true end end end def test_capify_should_run_the_capify_command - assert_called_with(generator, :run, ['capify .', verbose: false]) do + assert_called_with(generator, :run, ["capify .", verbose: false]) do action :capify! end end @@ -287,12 +287,12 @@ class ActionsTest < Rails::Generators::TestCase run_generator route_command = "route '/login', controller: 'sessions', action: 'new'" action :route, route_command - assert_file 'config/routes.rb', /#{Regexp.escape(route_command)}/ + assert_file "config/routes.rb", /#{Regexp.escape(route_command)}/ end def test_route_should_be_idempotent run_generator - route_path = File.expand_path('config/routes.rb', destination_root) + route_path = File.expand_path("config/routes.rb", destination_root) # runs first time, not asserting action :route, "root 'welcome#index'" @@ -312,8 +312,8 @@ class ActionsTest < Rails::Generators::TestCase content = File.read(route_path) # Remove all of the comments and blank lines from the routes file - content.gsub!(/^ \#.*\n/, '') - content.gsub!(/^\n/, '') + content.gsub!(/^ \#.*\n/, "") + content.gsub!(/^\n/, "") File.open(route_path, "wb") { |file| file.write(content) } @@ -372,7 +372,6 @@ F protected def action(*args, &block) - capture(:stdout){ generator.send(*args, &block) } + capture(:stdout) { generator.send(*args, &block) } end - end diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb index 92779452e1..bbb814ef4e 100644 --- a/railties/test/generators/api_app_generator_test.rb +++ b/railties/test/generators/api_app_generator_test.rb @@ -1,11 +1,11 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/app/app_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/app/app_generator" class ApiAppGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper tests Rails::Generators::AppGenerator - arguments [destination_root, '--api'] + arguments [destination_root, "--api"] def setup Rails.application = TestApp::Application @@ -73,51 +73,50 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase private - def default_files - files = %W( - .gitignore - Gemfile - Rakefile - config.ru - app/controllers - app/mailers - app/models - app/views/layouts/mailer.html.erb - app/views/layouts/mailer.text.erb - config/environments - config/initializers - config/locales - db - lib - lib/tasks - log - test/fixtures - test/controllers - test/integration - test/models - tmp - vendor - ) - files.concat %w(bin/bundle bin/rails bin/rake) - files - end + def default_files + files = %W( + .gitignore + Gemfile + Rakefile + config.ru + app/controllers + app/mailers + app/models + app/views/layouts/mailer.html.erb + app/views/layouts/mailer.text.erb + config/environments + config/initializers + config/locales + db + lib + lib/tasks + log + test/fixtures + test/controllers + test/integration + test/models + tmp + vendor + ) + files.concat %w(bin/bundle bin/rails bin/rake) + files + end - def skipped_files - %w(app/assets - app/helpers - app/views/layouts/application.html.erb - config/initializers/assets.rb - config/initializers/cookies_serializer.rb - config/initializers/session_store.rb - lib/assets - vendor/assets - test/helpers - tmp/cache/assets - public/404.html - public/422.html - public/500.html - public/apple-touch-icon-precomposed.png - public/apple-touch-icon.png - public/favicon.ico) - end + def skipped_files + %w(app/assets + app/helpers + app/views/layouts/application.html.erb + config/initializers/assets.rb + config/initializers/cookies_serializer.rb + lib/assets + vendor/assets + test/helpers + tmp/cache/assets + public/404.html + public/422.html + public/500.html + public/apple-touch-icon-precomposed.png + public/apple-touch-icon.png + public/favicon.ico) + end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 058308aa13..9299b9ebea 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -1,6 +1,6 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/app/app_generator' -require 'generators/shared_generator_tests' +require "generators/generators_test_helper" +require "rails/generators/rails/app/app_generator" +require "generators/shared_generator_tests" DEFAULT_APP_FILES = %w( .gitignore @@ -77,7 +77,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_invalid_application_name_raises_an_error - content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] } + content = capture(:stderr) { run_generator [File.join(destination_root, "43-things")] } assert_equal "Invalid application name 43-things. Please give a name which does not start with numbers.\n", content end @@ -88,12 +88,12 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_application_new_exits_with_non_zero_code_on_invalid_application_name - quietly { system 'rails new test --no-rc' } + quietly { system "rails new test --no-rc" } assert_equal false, $?.success? end def test_application_new_exits_with_message_and_non_zero_code_when_generating_inside_existing_rails_directory - app_root = File.join(destination_root, 'myfirstapp') + app_root = File.join(destination_root, "myfirstapp") run_generator [app_root] output = nil Dir.chdir(app_root) do @@ -104,7 +104,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_application_new_show_help_message_inside_existing_rails_directory - app_root = File.join(destination_root, 'myfirstapp') + app_root = File.join(destination_root, "myfirstapp") run_generator [app_root] output = Dir.chdir(app_root) do `rails new --help` @@ -131,20 +131,18 @@ class AppGeneratorTest < Rails::Generators::TestCase generator.send(:app_const) quietly { generator.send(:update_config_files) } assert_file "myapp_moved/config/environment.rb", /Rails\.application\.initialize!/ - assert_file "myapp_moved/config/initializers/session_store.rb", /_myapp_session/ end end end def test_rails_update_generates_correct_session_key - app_root = File.join(destination_root, 'myapp') + app_root = File.join(destination_root, "myapp") run_generator [app_root] stub_rails_application(app_root) do generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell generator.send(:app_const) quietly { generator.send(:update_config_files) } - assert_file "myapp/config/initializers/session_store.rb", /_myapp_session/ end end @@ -157,11 +155,11 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_new_application_not_include_api_initializers run_generator - assert_no_file 'config/initializers/cors.rb' + assert_no_file "config/initializers/cors.rb" end def test_rails_update_keep_the_cookie_serializer_if_it_is_already_configured - app_root = File.join(destination_root, 'myapp') + app_root = File.join(destination_root, "myapp") run_generator [app_root] stub_rails_application(app_root) do @@ -173,7 +171,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_rails_update_set_the_cookie_serializer_to_marshal_if_it_is_not_already_configured - app_root = File.join(destination_root, 'myapp') + app_root = File.join(destination_root, "myapp") run_generator [app_root] FileUtils.rm("#{app_root}/config/initializers/cookies_serializer.rb") @@ -188,7 +186,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_rails_update_dont_set_file_watcher - app_root = File.join(destination_root, 'myapp') + app_root = File.join(destination_root, "myapp") run_generator [app_root] stub_rails_application(app_root) do @@ -202,7 +200,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_rails_update_does_not_create_new_framework_defaults_by_default - app_root = File.join(destination_root, 'myapp') + app_root = File.join(destination_root, "myapp") run_generator [app_root] FileUtils.rm("#{app_root}/config/initializers/new_framework_defaults.rb") @@ -221,7 +219,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_rails_update_does_not_create_rack_cors - app_root = File.join(destination_root, 'myapp') + app_root = File.join(destination_root, "myapp") run_generator [app_root] stub_rails_application(app_root) do @@ -233,7 +231,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_rails_update_does_not_remove_rack_cors_if_already_present - app_root = File.join(destination_root, 'myapp') + app_root = File.join(destination_root, "myapp") run_generator [app_root] FileUtils.touch("#{app_root}/config/initializers/cors.rb") @@ -254,7 +252,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_gemfile_has_no_whitespace_errors run_generator absolute = File.expand_path("Gemfile", destination_root) - File.open(absolute, 'r') do |f| + File.open(absolute, "r") do |f| f.each_line do |line| assert_no_match %r{/^[ \t]+$/}, line end @@ -358,6 +356,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_generator_if_skip_active_record_is_given run_generator [destination_root, "--skip-active-record"] + assert_no_directory "db/" assert_no_file "config/database.yml" assert_no_file "app/models/application_record.rb" assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/ @@ -382,13 +381,15 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "config/environments/production.rb" do |content| assert_no_match(/config\.action_mailer/, content) end + assert_no_directory "app/mailers" + assert_no_directory "test/mailers" end def test_generator_has_assets_gems run_generator - assert_gem 'sass-rails' - assert_gem 'uglifier' + assert_gem "sass-rails" + assert_gem "uglifier" end def test_generator_if_skip_sprockets_is_given @@ -411,6 +412,9 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_match(/config\.assets\.js_compressor = :uglifier/, content) assert_no_match(/config\.assets\.css_compressor = :sass/, content) end + assert_file "config/initializers/new_framework_defaults.rb" do |content| + assert_no_match(/unknown_asset_fallback/, content) + end end def test_generator_if_skip_action_cable_is_given @@ -448,7 +452,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_other_javascript_libraries - run_generator [destination_root, '-j', 'prototype'] + run_generator [destination_root, "-j", "prototype"] assert_file "app/assets/javascripts/application.js" do |contents| assert_match %r{^//= require prototype}, contents assert_match %r{^//= require prototype_ujs}, contents @@ -470,12 +474,17 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |content| assert_no_match(/coffee-rails/, content) assert_no_match(/jquery-rails/, content) + assert_no_match(/uglifier/, content) + end + + assert_file "config/environments/production.rb" do |content| + assert_no_match(/config\.assets\.js_compressor = :uglifier/, content) end end def test_inclusion_of_jbuilder run_generator - assert_gem 'jbuilder' + assert_gem "jbuilder" end def test_inclusion_of_a_debugger @@ -485,13 +494,13 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_match(/byebug/, content) end else - assert_gem 'byebug' + assert_gem "byebug" end end def test_inclusion_of_listen_related_configuration_by_default run_generator - if RbConfig::CONFIG['host_os'] =~ /darwin|linux/ + if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ assert_listen_related_configuration else assert_no_listen_related_configuration @@ -499,14 +508,14 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_non_inclusion_of_listen_related_configuration_if_skip_listen - run_generator [destination_root, '--skip-listen'] + run_generator [destination_root, "--skip-listen"] assert_no_listen_related_configuration end def test_evented_file_update_checker_config run_generator - assert_file 'config/environments/development.rb' do |content| - if RbConfig::CONFIG['host_os'] =~ /darwin|linux/ + assert_file "config/environments/development.rb" do |content| + if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) else assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) @@ -536,8 +545,8 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_file_is_added_for_backwards_compatibility - action :file, 'lib/test_file.rb', 'heres test data' - assert_file 'lib/test_file.rb', 'heres test data' + action :file, "lib/test_file.rb", "heres test data" + assert_file "lib/test_file.rb", "heres test data" end def test_tests_are_removed_from_frameworks_if_skip_test_is_given @@ -552,13 +561,6 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "config/application.rb", /\s+require\s+["']active_job\/railtie["']/ end - def test_new_hash_style - run_generator - assert_file "config/initializers/session_store.rb" do |file| - assert_match(/config.session_store :cookie_store, key: '_.+_session'/, file) - end - end - def test_pretend_option output = run_generator [File.join(destination_root, "myapp"), "--pretend"] assert_no_match(/run bundle install/, output) @@ -568,15 +570,14 @@ class AppGeneratorTest < Rails::Generators::TestCase path = File.join(destination_root, "foo bar") # This also applies to MySQL apps but not with SQLite - run_generator [path, "-d", 'postgresql'] + run_generator [path, "-d", "postgresql"] assert_file "foo bar/config/database.yml", /database: foo_bar_development/ - assert_file "foo bar/config/initializers/session_store.rb", /key: '_foo_bar/ end def test_web_console run_generator - assert_gem 'web-console' + assert_gem "web-console" end def test_web_console_with_dev_option @@ -584,7 +585,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |content| assert_match(/gem 'web-console',\s+github: 'rails\/web-console'/, content) - assert_no_match(/\Agem 'web-console'\z/, content) + assert_no_match(/\Agem 'web-console', '>= 3.3.0'\z/, content) end end @@ -593,13 +594,28 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |content| assert_match(/gem 'web-console',\s+github: 'rails\/web-console'/, content) - assert_no_match(/\Agem 'web-console'\z/, content) + assert_no_match(/\Agem 'web-console', '>= 3.3.0'\z/, content) end end + def test_generation_runs_bundle_install + assert_generates_with_bundler + end + + def test_dev_option + assert_generates_with_bundler dev: true + rails_path = File.expand_path("../../..", Rails.root) + assert_file "Gemfile", /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/ + end + + def test_edge_option + assert_generates_with_bundler edge: true + assert_file "Gemfile", %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} + end + def test_spring run_generator - assert_gem 'spring' + assert_gem "spring" end def test_spring_binstubs @@ -608,9 +624,9 @@ class AppGeneratorTest < Rails::Generators::TestCase @binstub_called ||= 0 case command - when 'install' + when "install" # Called when running bundle, we just want to stub it so nothing to do here. - when 'exec spring binstub --all' + when "exec spring binstub --all" @binstub_called += 1 assert_equal 1, @binstub_called, "exec spring binstub --all expected to be called once, but was called #{@install_called} times." end @@ -635,7 +651,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_skip_spring run_generator [destination_root, "--skip-spring"] - assert_no_file 'config/spring.rb' + assert_no_file "config/spring.rb" assert_file "Gemfile" do |content| assert_no_match(/spring/, content) end @@ -666,15 +682,15 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_gitignore_when_sqlite3 run_generator - assert_file '.gitignore' do |content| + assert_file ".gitignore" do |content| assert_match(/sqlite3/, content) end end def test_gitignore_when_no_active_record - run_generator [destination_root, '--skip-active-record'] + run_generator [destination_root, "--skip-active-record"] - assert_file '.gitignore' do |content| + assert_file ".gitignore" do |content| assert_no_match(/sqlite/i, content) end end @@ -682,7 +698,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_gitignore_when_non_sqlite3_db run_generator([destination_root, "-d", "mysql"]) - assert_file '.gitignore' do |content| + assert_file ".gitignore" do |content| assert_no_match(/sqlite/i, content) end end @@ -725,17 +741,17 @@ class AppGeneratorTest < Rails::Generators::TestCase end def test_after_bundle_callback - path = 'http://example.org/rails_template' + path = "http://example.org/rails_template" template = %{ after_bundle { run 'echo ran after_bundle' } } template.instance_eval "def read; self; end" # Make the string respond to read check_open = -> *args do - assert_equal [ path, 'Accept' => 'application/x-thor-template' ], args + assert_equal [ path, "Accept" => "application/x-thor-template" ], args template end - sequence = ['install', 'exec spring binstub --all', 'echo ran after_bundle'] - @sequence_step ||= 0 + sequence = ["install", "exec spring binstub --all", "echo ran after_bundle"] + @sequence_step ||= 0 ensure_bundler_first = -> command do assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}" @sequence_step += 1 @@ -754,41 +770,61 @@ class AppGeneratorTest < Rails::Generators::TestCase protected - def stub_rails_application(root) - Rails.application.config.root = root - Rails.application.class.stub(:name, "Myapp") do - yield + def stub_rails_application(root) + Rails.application.config.root = root + Rails.application.class.stub(:name, "Myapp") do + yield + end end - end - def action(*args, &block) - capture(:stdout) { generator.send(*args, &block) } - end + def action(*args, &block) + capture(:stdout) { generator.send(*args, &block) } + end - def assert_gem(gem, constraint = nil) - if constraint - assert_file "Gemfile", /^\s*gem\s+["']#{gem}["'], #{constraint}$*/ - else - assert_file "Gemfile", /^\s*gem\s+["']#{gem}["']$*/ + def assert_gem(gem, constraint = nil) + if constraint + assert_file "Gemfile", /^\s*gem\s+["']#{gem}["'], #{constraint}$*/ + else + assert_file "Gemfile", /^\s*gem\s+["']#{gem}["']$*/ + end end - end - def assert_listen_related_configuration - assert_gem 'listen' - assert_gem 'spring-watcher-listen' + def assert_listen_related_configuration + assert_gem "listen" + assert_gem "spring-watcher-listen" - assert_file 'config/environments/development.rb' do |content| - assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + assert_file "config/environments/development.rb" do |content| + assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + end end - end - def assert_no_listen_related_configuration - assert_file 'Gemfile' do |content| - assert_no_match(/listen/, content) + def assert_no_listen_related_configuration + assert_file "Gemfile" do |content| + assert_no_match(/listen/, content) + end + + assert_file "config/environments/development.rb" do |content| + assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + end end - assert_file 'config/environments/development.rb' do |content| - assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + def assert_generates_with_bundler(options = {}) + generator([destination_root], options) + + command_check = -> command do + @install_called ||= 0 + + case command + when "install" + @install_called += 1 + assert_equal 1, @install_called, "install expected to be called once, but was called #{@install_called} times" + when "exec spring binstub --all" + # Called when running tests with spring, let through unscathed. + end + end + + generator.stub :bundle_command, command_check do + quietly { generator.invoke_all } + end end - end end diff --git a/railties/test/generators/argv_scrubber_test.rb b/railties/test/generators/argv_scrubber_test.rb index 31e07bc8da..7f4295a20f 100644 --- a/railties/test/generators/argv_scrubber_test.rb +++ b/railties/test/generators/argv_scrubber_test.rb @@ -1,7 +1,7 @@ -require 'active_support/test_case' -require 'active_support/testing/autorun' -require 'rails/generators/rails/app/app_generator' -require 'tempfile' +require "active_support/test_case" +require "active_support/testing/autorun" +require "rails/generators/rails/app/app_generator" +require "tempfile" module Rails module Generators @@ -11,7 +11,7 @@ module Rails # *must* act this way, I just want to prevent regressions. def test_version - ['-v', '--version'].each do |str| + ["-v", "--version"].each do |str| scrubber = ARGVScrubber.new [str] output = nil exit_code = nil @@ -26,37 +26,37 @@ module Rails end def test_default_help - argv = ['zomg', 'how', 'are', 'you'] + argv = ["zomg", "how", "are", "you"] scrubber = ARGVScrubber.new argv args = scrubber.prepare! - assert_equal ['--help'] + argv.drop(1), args + assert_equal ["--help"] + argv.drop(1), args end def test_prepare_returns_args - scrubber = ARGVScrubber.new ['hi mom'] + scrubber = ARGVScrubber.new ["hi mom"] args = scrubber.prepare! - assert_equal '--help', args.first + assert_equal "--help", args.first end def test_no_mutations - scrubber = ARGVScrubber.new ['hi mom'].freeze + scrubber = ARGVScrubber.new ["hi mom"].freeze args = scrubber.prepare! - assert_equal '--help', args.first + assert_equal "--help", args.first end def test_new_command_no_rc scrubber = Class.new(ARGVScrubber) { def self.default_rc_file - File.join(Dir.tmpdir, 'whatever') + File.join(Dir.tmpdir, "whatever") end - }.new ['new'] + }.new ["new"] args = scrubber.prepare! assert_equal [], args end def test_new_homedir_rc - file = Tempfile.new 'myrcfile' - file.puts '--hello-world' + file = Tempfile.new "myrcfile" + file.puts "--hello-world" file.flush message = nil @@ -65,10 +65,10 @@ module Rails file.path end define_method(:puts) { |msg| message = msg } - }.new ['new'] + }.new ["new"] args = scrubber.prepare! - assert_equal ['--hello-world'], args - assert_match 'hello-world', message + assert_equal ["--hello-world"], args + assert_match "hello-world", message assert_match file.path, message ensure file.close @@ -76,33 +76,33 @@ module Rails end def test_rc_whitespace_separated - file = Tempfile.new 'myrcfile' - file.puts '--hello --world' + file = Tempfile.new "myrcfile" + file.puts "--hello --world" file.flush message = nil scrubber = Class.new(ARGVScrubber) { define_method(:puts) { |msg| message = msg } - }.new ['new', "--rc=#{file.path}"] + }.new ["new", "--rc=#{file.path}"] args = scrubber.prepare! - assert_equal ['--hello', '--world'], args + assert_equal ["--hello", "--world"], args ensure file.close file.unlink end def test_new_rc_option - file = Tempfile.new 'myrcfile' - file.puts '--hello-world' + file = Tempfile.new "myrcfile" + file.puts "--hello-world" file.flush message = nil scrubber = Class.new(ARGVScrubber) { define_method(:puts) { |msg| message = msg } - }.new ['new', "--rc=#{file.path}"] + }.new ["new", "--rc=#{file.path}"] args = scrubber.prepare! - assert_equal ['--hello-world'], args - assert_match 'hello-world', message + assert_equal ["--hello-world"], args + assert_match "hello-world", message assert_match file.path, message ensure file.close @@ -110,14 +110,14 @@ module Rails end def test_new_rc_option_and_custom_options - file = Tempfile.new 'myrcfile' - file.puts '--hello' - file.puts '--world' + file = Tempfile.new "myrcfile" + file.puts "--hello" + file.puts "--world" file.flush scrubber = Class.new(ARGVScrubber) { define_method(:puts) { |msg| } - }.new ['new', 'tenderapp', '--love', "--rc=#{file.path}"] + }.new ["new", "tenderapp", "--love", "--rc=#{file.path}"] args = scrubber.prepare! assert_equal ["tenderapp", "--hello", "--world", "--love"], args @@ -127,7 +127,7 @@ module Rails end def test_no_rc - scrubber = ARGVScrubber.new ['new', '--no-rc'] + scrubber = ARGVScrubber.new ["new", "--no-rc"] args = scrubber.prepare! assert_equal [], args end diff --git a/railties/test/generators/assets_generator_test.rb b/railties/test/generators/assets_generator_test.rb index a2b94f2e50..1c02c67e42 100644 --- a/railties/test/generators/assets_generator_test.rb +++ b/railties/test/generators/assets_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/assets/assets_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/assets/assets_generator" class AssetsGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/channel_generator_test.rb b/railties/test/generators/channel_generator_test.rb index e3edde681f..a1d54200ba 100644 --- a/railties/test/generators/channel_generator_test.rb +++ b/railties/test/generators/channel_generator_test.rb @@ -1,12 +1,12 @@ -require 'generators/generators_test_helper' -require 'rails/generators/channel/channel_generator' +require "generators/generators_test_helper" +require "rails/generators/channel/channel_generator" class ChannelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper tests Rails::Generators::ChannelGenerator def test_application_cable_skeleton_is_created - run_generator ['books'] + run_generator ["books"] assert_file "app/channels/application_cable/channel.rb" do |cable| assert_match(/module ApplicationCable\n class Channel < ActionCable::Channel::Base\n/, cable) @@ -18,7 +18,7 @@ class ChannelGeneratorTest < Rails::Generators::TestCase end def test_channel_is_created - run_generator ['chat'] + run_generator ["chat"] assert_file "app/channels/chat_channel.rb" do |channel| assert_match(/class ChatChannel < ApplicationCable::Channel/, channel) @@ -30,7 +30,7 @@ class ChannelGeneratorTest < Rails::Generators::TestCase end def test_channel_with_multiple_actions_is_created - run_generator ['chat', 'speak', 'mute'] + run_generator ["chat", "speak", "mute"] assert_file "app/channels/chat_channel.rb" do |channel| assert_match(/class ChatChannel < ApplicationCable::Channel/, channel) @@ -46,7 +46,7 @@ class ChannelGeneratorTest < Rails::Generators::TestCase end def test_channel_asset_is_not_created_when_skip_assets_is_passed - run_generator ['chat', '--skip-assets'] + run_generator ["chat", "--skip-assets"] assert_file "app/channels/chat_channel.rb" do |channel| assert_match(/class ChatChannel < ApplicationCable::Channel/, channel) @@ -56,16 +56,16 @@ class ChannelGeneratorTest < Rails::Generators::TestCase end def test_cable_js_is_created_if_not_present_already - run_generator ['chat'] + run_generator ["chat"] FileUtils.rm("#{destination_root}/app/assets/javascripts/cable.js") - run_generator ['camp'] + run_generator ["camp"] assert_file "app/assets/javascripts/cable.js" end def test_channel_on_revoke - run_generator ['chat'] - run_generator ['chat'], behavior: :revoke + run_generator ["chat"] + run_generator ["chat"], behavior: :revoke assert_no_file "app/channels/chat_channel.rb" assert_no_file "app/assets/javascripts/channels/chat.js" diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb index 1351151afb..9b986a636a 100644 --- a/railties/test/generators/controller_generator_test.rb +++ b/railties/test/generators/controller_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/controller/controller_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/controller/controller_generator" class ControllerGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -19,7 +19,7 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_check_class_collision Object.send :const_set, :ObjectController, Class.new - content = capture(:stderr){ run_generator ["object"] } + content = capture(:stderr) { run_generator ["object"] } assert_match(/The name 'ObjectController' is either already used in your application or reserved/, content) ensure Object.send :remove_const, :ObjectController diff --git a/railties/test/generators/create_migration_test.rb b/railties/test/generators/create_migration_test.rb index e16a77479a..ddd40e4d02 100644 --- a/railties/test/generators/create_migration_test.rb +++ b/railties/test/generators/create_migration_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/migration/migration_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/migration/migration_generator" class CreateMigrationTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -19,12 +19,12 @@ class CreateMigrationTest < Rails::Generators::TestCase end def create_migration(destination_path = default_destination_path, config = {}, generator_options = {}, &block) - migration_name = File.basename(destination_path, '.rb') + migration_name = File.basename(destination_path, ".rb") generator([migration_name], generator_options) generator.set_migration_assigns!(destination_path) dir, base = File.split(destination_path) - timestamped_destination_path = File.join(dir, ["%migration_number%", base].join('_')) + timestamped_destination_path = File.join(dir, ["%migration_number%", base].join("_")) @migration = Rails::Generators::Actions::CreateMigration.new(generator, timestamped_destination_path, block || "contents", config) end @@ -51,7 +51,7 @@ class CreateMigrationTest < Rails::Generators::TestCase end def test_invoke_pretended - create_migration(default_destination_path, {}, { pretend: true }) + create_migration(default_destination_path, {}, pretend: true) assert_no_file @migration.destination end @@ -92,7 +92,7 @@ class CreateMigrationTest < Rails::Generators::TestCase def test_invoke_forced_pretended_when_exists_not_identical migration_exists! - create_migration(default_destination_path, { force: true }, { pretend: true }) do + create_migration(default_destination_path, { force: true }, pretend: true) do "different content" end @@ -104,7 +104,7 @@ class CreateMigrationTest < Rails::Generators::TestCase def test_invoke_skipped_when_exists_not_identical migration_exists! - create_migration(default_destination_path, {}, { skip: true }) { "different content" } + create_migration(default_destination_path, {}, skip: true) { "different content" } assert_match(/skip db\/migrate\/2_create_articles.rb\n/, invoke!) assert_no_file @migration.destination @@ -120,7 +120,7 @@ class CreateMigrationTest < Rails::Generators::TestCase def test_revoke_pretended migration_exists! - create_migration(default_destination_path, {}, { pretend: true }) + create_migration(default_destination_path, {}, pretend: true) assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) assert_file @existing_migration.destination diff --git a/railties/test/generators/generated_attribute_test.rb b/railties/test/generators/generated_attribute_test.rb index ee7c009305..97847c8624 100644 --- a/railties/test/generators/generated_attribute_test.rb +++ b/railties/test/generators/generated_attribute_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/generated_attribute' +require "generators/generators_test_helper" +require "rails/generators/generated_attribute" class GeneratedAttributeTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -51,7 +51,7 @@ class GeneratedAttributeTest < Rails::Generators::TestCase end def test_default_value_is_decimal - assert_field_default_value :decimal, '9.99' + assert_field_default_value :decimal, "9.99" end def test_default_value_is_datetime @@ -65,7 +65,7 @@ class GeneratedAttributeTest < Rails::Generators::TestCase end def test_default_value_is_string - assert_field_default_value :string, 'MyString' + assert_field_default_value :string, "MyString" end def test_default_value_for_type @@ -74,7 +74,7 @@ class GeneratedAttributeTest < Rails::Generators::TestCase end def test_default_value_is_text - assert_field_default_value :text, 'MyText' + assert_field_default_value :text, "MyText" end def test_default_value_is_boolean @@ -89,14 +89,14 @@ class GeneratedAttributeTest < Rails::Generators::TestCase def test_default_value_is_empty_string %w(foo bar baz).each do |attribute_type| - assert_field_default_value attribute_type, '' + assert_field_default_value attribute_type, "" end end def test_human_name assert_equal( - 'Full name', - create_generated_attribute(:string, 'full_name').human_name + "Full name", + create_generated_attribute(:string, "full_name").human_name ) end @@ -125,21 +125,21 @@ class GeneratedAttributeTest < Rails::Generators::TestCase end def test_blank_type_defaults_to_string_raises_exception - assert_equal :string, create_generated_attribute(nil, 'title').type - assert_equal :string, create_generated_attribute("", 'title').type + assert_equal :string, create_generated_attribute(nil, "title").type + assert_equal :string, create_generated_attribute("", "title").type end def test_handles_index_names_for_references - assert_equal "post", create_generated_attribute('string', 'post').index_name - assert_equal "post_id", create_generated_attribute('references', 'post').index_name - assert_equal "post_id", create_generated_attribute('belongs_to', 'post').index_name - assert_equal ["post_id", "post_type"], create_generated_attribute('references{polymorphic}', 'post').index_name + assert_equal "post", create_generated_attribute("string", "post").index_name + assert_equal "post_id", create_generated_attribute("references", "post").index_name + assert_equal "post_id", create_generated_attribute("belongs_to", "post").index_name + assert_equal ["post_id", "post_type"], create_generated_attribute("references{polymorphic}", "post").index_name end def test_handles_column_names_for_references - assert_equal "post", create_generated_attribute('string', 'post').column_name - assert_equal "post_id", create_generated_attribute('references', 'post').column_name - assert_equal "post_id", create_generated_attribute('belongs_to', 'post').column_name + assert_equal "post", create_generated_attribute("string", "post").column_name + assert_equal "post_id", create_generated_attribute("references", "post").column_name + assert_equal "post_id", create_generated_attribute("belongs_to", "post").column_name end def test_parse_required_attribute_with_index diff --git a/railties/test/generators/generator_generator_test.rb b/railties/test/generators/generator_generator_test.rb index dcfeaaa8e0..5ff8bb0357 100644 --- a/railties/test/generators/generator_generator_test.rb +++ b/railties/test/generators/generator_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/generator/generator_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/generator/generator_generator" class GeneratorGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -12,7 +12,7 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase lib/generators/awesome lib/generators/awesome/USAGE lib/generators/awesome/templates - ).each{ |path| assert_file path } + ).each { |path| assert_file path } assert_file "lib/generators/awesome/awesome_generator.rb", /class AwesomeGenerator < Rails::Generators::NamedBase/ @@ -28,7 +28,7 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase lib/generators/rails/awesome lib/generators/rails/awesome/USAGE lib/generators/rails/awesome/templates - ).each{ |path| assert_file path } + ).each { |path| assert_file path } assert_file "lib/generators/rails/awesome/awesome_generator.rb", /class Rails::AwesomeGenerator < Rails::Generators::NamedBase/ @@ -44,7 +44,7 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase lib/generators/ lib/generators/USAGE lib/generators/templates - ).each{ |path| assert_file path } + ).each { |path| assert_file path } assert_file "lib/generators/awesome_generator.rb", /class AwesomeGenerator < Rails::Generators::NamedBase/ @@ -60,7 +60,7 @@ class GeneratorGeneratorTest < Rails::Generators::TestCase lib/generators/rails lib/generators/rails/USAGE lib/generators/rails/templates - ).each{ |path| assert_file path } + ).each { |path| assert_file path } assert_file "lib/generators/rails/awesome_generator.rb", /class Rails::AwesomeGenerator < Rails::Generators::NamedBase/ diff --git a/railties/test/generators/generator_test.rb b/railties/test/generators/generator_test.rb index 8ef44a8dcb..c4e4747468 100644 --- a/railties/test/generators/generator_test.rb +++ b/railties/test/generators/generator_test.rb @@ -1,6 +1,6 @@ -require 'active_support/test_case' -require 'active_support/testing/autorun' -require 'rails/generators/app_base' +require "active_support/test_case" +require "active_support/testing/autorun" +require "rails/generators/app_base" module Rails module Generators @@ -21,46 +21,46 @@ module Rails def test_construction klass = make_builder_class - assert klass.start(['new', 'blah']) + assert klass.start(["new", "blah"]) end def test_add_gem klass = make_builder_class - generator = klass.start(['new', 'blah']) - generator.gemfile_entry 'tenderlove' - assert_includes generator.gemfile_entries.map(&:name), 'tenderlove' + generator = klass.start(["new", "blah"]) + generator.gemfile_entry "tenderlove" + assert_includes generator.gemfile_entries.map(&:name), "tenderlove" end def test_add_gem_with_version klass = make_builder_class - generator = klass.start(['new', 'blah']) - generator.gemfile_entry 'tenderlove', '2.0.0' + generator = klass.start(["new", "blah"]) + generator.gemfile_entry "tenderlove", "2.0.0" assert generator.gemfile_entries.find { |gfe| - gfe.name == 'tenderlove' && gfe.version == '2.0.0' + gfe.name == "tenderlove" && gfe.version == "2.0.0" } end def test_add_github_gem klass = make_builder_class - generator = klass.start(['new', 'blah']) - generator.gemfile_entry 'tenderlove', github: 'hello world' + generator = klass.start(["new", "blah"]) + generator.gemfile_entry "tenderlove", github: "hello world" assert generator.gemfile_entries.find { |gfe| - gfe.name == 'tenderlove' && gfe.options[:github] == 'hello world' + gfe.name == "tenderlove" && gfe.options[:github] == "hello world" } end def test_add_path_gem klass = make_builder_class - generator = klass.start(['new', 'blah']) - generator.gemfile_entry 'tenderlove', path: 'hello world' + generator = klass.start(["new", "blah"]) + generator.gemfile_entry "tenderlove", path: "hello world" assert generator.gemfile_entries.find { |gfe| - gfe.name == 'tenderlove' && gfe.options[:path] == 'hello world' + gfe.name == "tenderlove" && gfe.options[:path] == "hello world" } end def test_filter klass = make_builder_class - generator = klass.start(['new', 'blah']) + generator = klass.start(["new", "blah"]) gems = generator.gemfile_entries generator.add_gem_entry_filter { |gem| gem.name != gems.first.name @@ -70,7 +70,7 @@ module Rails def test_two_filters klass = make_builder_class - generator = klass.start(['new', 'blah']) + generator = klass.start(["new", "blah"]) gems = generator.gemfile_entries generator.add_gem_entry_filter { |gem| gem.name != gems.first.name @@ -83,17 +83,17 @@ module Rails def test_recommended_rails_versions klass = make_builder_class - generator = klass.start(['new', 'blah']) + generator = klass.start(["new", "blah"]) specifier_for = -> v { generator.send(:rails_version_specifier, Gem::Version.new(v)) } - assert_equal '~> 4.1.13', specifier_for['4.1.13'] - assert_equal ['>= 4.1.6.rc1', '< 4.2'], specifier_for['4.1.6.rc1'] - assert_equal ['~> 4.1.7', '>= 4.1.7.1'], specifier_for['4.1.7.1'] - assert_equal ['~> 4.1.7', '>= 4.1.7.1.2'], specifier_for['4.1.7.1.2'] - assert_equal ['>= 4.1.7.1.rc2', '< 4.2'], specifier_for['4.1.7.1.rc2'] - assert_equal ['>= 4.2.0.beta1', '< 4.3'], specifier_for['4.2.0.beta1'] - assert_equal ['>= 5.0.0.beta1', '< 5.1'], specifier_for['5.0.0.beta1'] + assert_equal "~> 4.1.13", specifier_for["4.1.13"] + assert_equal [">= 4.1.6.rc1", "< 4.2"], specifier_for["4.1.6.rc1"] + assert_equal ["~> 4.1.7", ">= 4.1.7.1"], specifier_for["4.1.7.1"] + assert_equal ["~> 4.1.7", ">= 4.1.7.1.2"], specifier_for["4.1.7.1.2"] + assert_equal [">= 4.1.7.1.rc2", "< 4.2"], specifier_for["4.1.7.1.rc2"] + assert_equal [">= 4.2.0.beta1", "< 4.3"], specifier_for["4.2.0.beta1"] + assert_equal [">= 5.0.0.beta1", "< 5.1"], specifier_for["5.0.0.beta1"] end end end diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index b19a5a7144..2cdddc8713 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -1,15 +1,15 @@ -require 'abstract_unit' -require 'active_support/core_ext/module/remove_method' -require 'active_support/testing/stream' -require 'active_support/testing/method_call_assertions' -require 'rails/generators' -require 'rails/generators/test_case' +require "abstract_unit" +require "active_support/core_ext/module/remove_method" +require "active_support/testing/stream" +require "active_support/testing/method_call_assertions" +require "rails/generators" +require "rails/generators/test_case" module Rails class << self remove_possible_method :root def root - @root ||= Pathname.new(File.expand_path('../../fixtures', __FILE__)) + @root ||= Pathname.new(File.expand_path("../../fixtures", __FILE__)) end end end @@ -20,9 +20,9 @@ Rails.application.config.generators.templates = [File.join(Rails.root, "lib", "t # Rails.application.config.generators to Rails::Generators Rails.application.load_generators -require 'active_record' -require 'action_dispatch' -require 'action_view' +require "active_record" +require "action_dispatch" +require "action_view" module GeneratorsTestHelper include ActiveSupport::Testing::Stream @@ -34,7 +34,7 @@ module GeneratorsTestHelper setup :prepare_destination begin - base.tests Rails::Generators.const_get(base.name.sub(/Test$/, '')) + base.tests Rails::Generators.const_get(base.name.sub(/Test$/, "")) rescue end end @@ -46,5 +46,4 @@ module GeneratorsTestHelper FileUtils.mkdir_p(destination) FileUtils.cp routes, destination end - end diff --git a/railties/test/generators/helper_generator_test.rb b/railties/test/generators/helper_generator_test.rb index add04f21a4..d9e6e0a85a 100644 --- a/railties/test/generators/helper_generator_test.rb +++ b/railties/test/generators/helper_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/helper/helper_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/helper/helper_generator" ObjectHelper = Class.new AnotherObjectHelperTest = Class.new @@ -14,7 +14,7 @@ class HelperGeneratorTest < Rails::Generators::TestCase end def test_check_class_collision - content = capture(:stderr){ run_generator ["object"] } + content = capture(:stderr) { run_generator ["object"] } assert_match(/The name 'ObjectHelper' is either already used in your application or reserved/, content) end diff --git a/railties/test/generators/integration_test_generator_test.rb b/railties/test/generators/integration_test_generator_test.rb index d05ed76d24..8bcc02440a 100644 --- a/railties/test/generators/integration_test_generator_test.rb +++ b/railties/test/generators/integration_test_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/integration_test/integration_test_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/integration_test/integration_test_generator" class IntegrationTestGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/job_generator_test.rb b/railties/test/generators/job_generator_test.rb index dbff0ab704..68d158eb39 100644 --- a/railties/test/generators/job_generator_test.rb +++ b/railties/test/generators/job_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/job/job_generator' +require "generators/generators_test_helper" +require "rails/generators/job/job_generator" class JobGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index 6a4951840d..7d69d7470d 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/mailer/mailer_generator' +require "generators/generators_test_helper" +require "rails/generators/mailer/mailer_generator" class MailerGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -13,7 +13,7 @@ class MailerGeneratorTest < Rails::Generators::TestCase assert_no_match(/layout :mailer_notifier/, mailer) end - assert_file 'app/mailers/application_mailer.rb' do |mailer| + assert_file "app/mailers/application_mailer.rb" do |mailer| assert_match(/class ApplicationMailer < ActionMailer::Base/, mailer) assert_match(/default from: 'from@example.com'/, mailer) assert_match(/layout 'mailer'/, mailer) @@ -30,7 +30,7 @@ class MailerGeneratorTest < Rails::Generators::TestCase def test_check_class_collision Object.send :const_set, :NotifierMailer, Class.new - content = capture(:stderr){ run_generator } + content = capture(:stderr) { run_generator } assert_match(/The name 'NotifierMailer' is either already used in your application or reserved/, content) ensure Object.send :remove_const, :NotifierMailer @@ -59,7 +59,7 @@ class MailerGeneratorTest < Rails::Generators::TestCase def test_check_test_class_collision Object.send :const_set, :NotifierMailerTest, Class.new - content = capture(:stderr){ run_generator } + content = capture(:stderr) { run_generator } assert_match(/The name 'NotifierMailerTest' is either already used in your application or reserved/, content) ensure Object.send :remove_const, :NotifierMailerTest @@ -67,7 +67,7 @@ class MailerGeneratorTest < Rails::Generators::TestCase def test_check_preview_class_collision Object.send :const_set, :NotifierMailerPreview, Class.new - content = capture(:stderr){ run_generator } + content = capture(:stderr) { run_generator } assert_match(/The name 'NotifierMailerPreview' is either already used in your application or reserved/, content) ensure Object.send :remove_const, :NotifierMailerPreview diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index 46154b7db2..6e1d1b70a9 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/migration/migration_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/migration/migration_generator" class MigrationGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -17,7 +17,7 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration] file_name = migration_file_name "db/migrate/#{migration}.rb" - File.basename(file_name).split('_').first + File.basename(file_name).split("_").first end assert_not_equal first_migration_number, second_migration_number @@ -248,7 +248,7 @@ class MigrationGeneratorTest < Rails::Generators::TestCase def test_migration_with_singular_table_name with_singular_table_name do migration = "add_title_body_to_post" - run_generator [migration, 'title:string'] + run_generator [migration, "title:string"] assert_migration "db/migrate/#{migration}.rb" do |content| assert_method :change, content do |change| assert_match(/add_column :post, :title, :string/, change) diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 6b30c40476..701d3ceaf2 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -1,18 +1,18 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/model/model_generator' -require 'active_support/core_ext/string/strip' +require "generators/generators_test_helper" +require "rails/generators/rails/model/model_generator" +require "active_support/core_ext/string/strip" class ModelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(Account name:string age:integer) - def test_application_record_skeleton_is_created - run_generator - assert_file "app/models/application_record.rb" do |record| - assert_match(/class ApplicationRecord < ActiveRecord::Base/, record) - assert_match(/self.abstract_class = true/, record) - end - end + def test_application_record_skeleton_is_created + run_generator + assert_file "app/models/application_record.rb" do |record| + assert_match(/class ApplicationRecord < ActiveRecord::Base/, record) + assert_match(/self.abstract_class = true/, record) + end + end def test_help_shows_invoked_generators_options content = run_generator ["--help"] @@ -275,7 +275,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase def test_migration_error_is_not_shown_on_revoke run_generator - error = capture(:stderr){ run_generator ["Account"], behavior: :revoke } + error = capture(:stderr) { run_generator ["Account"], behavior: :revoke } assert_no_match(/Another migration is already named create_accounts/, error) end @@ -300,7 +300,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_file "test/fixtures/accounts.yml", /name: MyString/, /age: 1/ assert_generated_fixture("test/fixtures/accounts.yml", - {"one"=>{"name"=>"MyString", "age"=>1}, "two"=>{"name"=>"MyString", "age"=>1}}) + "one"=>{ "name"=>"MyString", "age"=>1 }, "two"=>{ "name"=>"MyString", "age"=>1 }) end def test_fixtures_use_the_references_ids @@ -308,7 +308,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_file "test/fixtures/line_items.yml", /product: one\n cart: one/ assert_generated_fixture("test/fixtures/line_items.yml", - {"one"=>{"product"=>"one", "cart"=>"one"}, "two"=>{"product"=>"two", "cart"=>"two"}}) + "one"=>{ "product"=>"one", "cart"=>"one" }, "two"=>{ "product"=>"two", "cart"=>"two" }) end def test_fixtures_use_the_references_ids_and_type @@ -316,15 +316,15 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_file "test/fixtures/line_items.yml", /product: one\n product_type: Product\n cart: one/ assert_generated_fixture("test/fixtures/line_items.yml", - {"one"=>{"product"=>"one", "product_type"=>"Product", "cart"=>"one"}, - "two"=>{"product"=>"two", "product_type"=>"Product", "cart"=>"two"}}) + "one"=>{ "product"=>"one", "product_type"=>"Product", "cart"=>"one" }, + "two"=>{ "product"=>"two", "product_type"=>"Product", "cart"=>"two" }) end def test_fixtures_respect_reserved_yml_keywords run_generator ["LineItem", "no:integer", "Off:boolean", "ON:boolean"] assert_generated_fixture("test/fixtures/line_items.yml", - {"one"=>{"no"=>1, "Off"=>false, "ON"=>false}, "two"=>{"no"=>1, "Off"=>false, "ON"=>false}}) + "one"=>{ "no"=>1, "Off"=>false, "ON"=>false }, "two"=>{ "no"=>1, "Off"=>false, "ON"=>false }) end def test_fixture_is_skipped @@ -343,13 +343,13 @@ class ModelGeneratorTest < Rails::Generators::TestCase ActiveRecord::Base.pluralize_table_names = false run_generator assert_generated_fixture("test/fixtures/account.yml", - {"one"=>{"name"=>"MyString", "age"=>1}, "two"=>{"name"=>"MyString", "age"=>1}}) + "one"=>{ "name"=>"MyString", "age"=>1 }, "two"=>{ "name"=>"MyString", "age"=>1 }) ensure ActiveRecord::Base.pluralize_table_names = original_pluralize_table_name end def test_check_class_collision - content = capture(:stderr){ run_generator ["object"] } + content = capture(:stderr) { run_generator ["object"] } assert_match(/The name 'Object' is either already used in your application or reserved/, content) end diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index 291f5e06c3..0258b3b9d7 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -1,84 +1,84 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/scaffold_controller/scaffold_controller_generator" class NamedBaseTest < Rails::Generators::TestCase include GeneratorsTestHelper tests Rails::Generators::ScaffoldControllerGenerator def test_named_generator_with_underscore - g = generator ['line_item'] - assert_name g, 'line_item', :name + g = generator ["line_item"] + assert_name g, "line_item", :name assert_name g, %w(), :class_path - assert_name g, 'LineItem', :class_name - assert_name g, 'line_item', :file_path - assert_name g, 'line_item', :file_name - assert_name g, 'Line item', :human_name - assert_name g, 'line_item', :singular_name - assert_name g, 'line_items', :plural_name - assert_name g, 'line_item', :i18n_scope - assert_name g, 'line_items', :table_name + assert_name g, "LineItem", :class_name + assert_name g, "line_item", :file_path + assert_name g, "line_item", :file_name + assert_name g, "Line item", :human_name + assert_name g, "line_item", :singular_name + assert_name g, "line_items", :plural_name + assert_name g, "line_item", :i18n_scope + assert_name g, "line_items", :table_name end def test_named_generator_attributes - g = generator ['admin/foo'] - assert_name g, 'admin/foo', :name + g = generator ["admin/foo"] + assert_name g, "admin/foo", :name assert_name g, %w(admin), :class_path - assert_name g, 'Admin::Foo', :class_name - assert_name g, 'admin/foo', :file_path - assert_name g, 'foo', :file_name - assert_name g, 'Foo', :human_name - assert_name g, 'foo', :singular_name - assert_name g, 'foos', :plural_name - assert_name g, 'admin.foo', :i18n_scope - assert_name g, 'admin_foos', :table_name + assert_name g, "Admin::Foo", :class_name + assert_name g, "admin/foo", :file_path + assert_name g, "foo", :file_name + assert_name g, "Foo", :human_name + assert_name g, "foo", :singular_name + assert_name g, "foos", :plural_name + assert_name g, "admin.foo", :i18n_scope + assert_name g, "admin_foos", :table_name end def test_named_generator_attributes_as_ruby - g = generator ['Admin::Foo'] - assert_name g, 'Admin::Foo', :name + g = generator ["Admin::Foo"] + assert_name g, "Admin::Foo", :name assert_name g, %w(admin), :class_path - assert_name g, 'Admin::Foo', :class_name - assert_name g, 'admin/foo', :file_path - assert_name g, 'foo', :file_name - assert_name g, 'foo', :singular_name - assert_name g, 'Foo', :human_name - assert_name g, 'foos', :plural_name - assert_name g, 'admin.foo', :i18n_scope - assert_name g, 'admin_foos', :table_name + assert_name g, "Admin::Foo", :class_name + assert_name g, "admin/foo", :file_path + assert_name g, "foo", :file_name + assert_name g, "foo", :singular_name + assert_name g, "Foo", :human_name + assert_name g, "foos", :plural_name + assert_name g, "admin.foo", :i18n_scope + assert_name g, "admin_foos", :table_name end def test_named_generator_attributes_without_pluralized original_pluralize_table_names = ActiveRecord::Base.pluralize_table_names ActiveRecord::Base.pluralize_table_names = false - g = generator ['admin/foo'] - assert_name g, 'admin_foo', :table_name + g = generator ["admin/foo"] + assert_name g, "admin_foo", :table_name ensure ActiveRecord::Base.pluralize_table_names = original_pluralize_table_names end def test_scaffold_plural_names - g = generator ['admin/foo'] - assert_name g, 'admin/foos', :controller_name + g = generator ["admin/foo"] + assert_name g, "admin/foos", :controller_name assert_name g, %w(admin), :controller_class_path - assert_name g, 'Admin::Foos', :controller_class_name - assert_name g, 'admin/foos', :controller_file_path - assert_name g, 'foos', :controller_file_name - assert_name g, 'admin.foos', :controller_i18n_scope + assert_name g, "Admin::Foos", :controller_class_name + assert_name g, "admin/foos", :controller_file_path + assert_name g, "foos", :controller_file_name + assert_name g, "admin.foos", :controller_i18n_scope end def test_scaffold_plural_names_as_ruby - g = generator ['Admin::Foo'] - assert_name g, 'Admin::Foos', :controller_name + g = generator ["Admin::Foo"] + assert_name g, "Admin::Foos", :controller_name assert_name g, %w(admin), :controller_class_path - assert_name g, 'Admin::Foos', :controller_class_name - assert_name g, 'admin/foos', :controller_file_path - assert_name g, 'foos', :controller_file_name - assert_name g, 'admin.foos', :controller_i18n_scope + assert_name g, "Admin::Foos", :controller_class_name + assert_name g, "admin/foos", :controller_file_path + assert_name g, "foos", :controller_file_name + assert_name g, "admin.foos", :controller_i18n_scope end def test_application_name - g = generator ['Admin::Foo'] + g = generator ["Admin::Foo"] Rails.stub(:application, Object.new) do assert_name g, "object", :application_name end @@ -89,46 +89,46 @@ class NamedBaseTest < Rails::Generators::TestCase end def test_index_helper - g = generator ['Post'] - assert_name g, 'posts', :index_helper + g = generator ["Post"] + assert_name g, "posts", :index_helper end def test_index_helper_to_pluralize_once - g = generator ['Stadium'] - assert_name g, 'stadia', :index_helper + g = generator ["Stadium"] + assert_name g, "stadia", :index_helper end def test_index_helper_with_uncountable - g = generator ['Sheep'] - assert_name g, 'sheep_index', :index_helper + g = generator ["Sheep"] + assert_name g, "sheep_index", :index_helper end def test_hide_namespace - g = generator ['Hidden'] - g.class.stub(:namespace, 'hidden') do - assert !Rails::Generators.hidden_namespaces.include?('hidden') + g = generator ["Hidden"] + g.class.stub(:namespace, "hidden") do + assert_not_includes Rails::Generators.hidden_namespaces, "hidden" g.class.hide! - assert Rails::Generators.hidden_namespaces.include?('hidden') + assert_includes Rails::Generators.hidden_namespaces, "hidden" end end def test_scaffold_plural_names_with_model_name_option - g = generator ['Admin::Foo'], model_name: 'User' - assert_name g, 'user', :singular_name - assert_name g, 'User', :name - assert_name g, 'user', :file_path - assert_name g, 'User', :class_name - assert_name g, 'user', :file_name - assert_name g, 'User', :human_name - assert_name g, 'users', :plural_name - assert_name g, 'user', :i18n_scope - assert_name g, 'users', :table_name - assert_name g, 'Admin::Foos', :controller_name + g = generator ["Admin::Foo"], model_name: "User" + assert_name g, "user", :singular_name + assert_name g, "User", :name + assert_name g, "user", :file_path + assert_name g, "User", :class_name + assert_name g, "user", :file_name + assert_name g, "User", :human_name + assert_name g, "users", :plural_name + assert_name g, "user", :i18n_scope + assert_name g, "users", :table_name + assert_name g, "Admin::Foos", :controller_name assert_name g, %w(admin), :controller_class_path - assert_name g, 'Admin::Foos', :controller_class_name - assert_name g, 'admin/foos', :controller_file_path - assert_name g, 'foos', :controller_file_name - assert_name g, 'admin.foos', :controller_i18n_scope + assert_name g, "Admin::Foos", :controller_class_name + assert_name g, "admin/foos", :controller_file_path + assert_name g, "foos", :controller_file_name + assert_name g, "admin.foos", :controller_i18n_scope end protected diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index 902c340321..1caabbe6b1 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -1,8 +1,8 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/controller/controller_generator' -require 'rails/generators/rails/model/model_generator' -require 'rails/generators/mailer/mailer_generator' -require 'rails/generators/rails/scaffold/scaffold_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/controller/controller_generator" +require "rails/generators/rails/model/model_generator" +require "rails/generators/mailer/mailer_generator" +require "rails/generators/rails/scaffold/scaffold_generator" class NamespacedGeneratorTestCase < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 5dd4cce28a..15079f2735 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -1,6 +1,6 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/plugin/plugin_generator' -require 'generators/shared_generator_tests' +require "generators/generators_test_helper" +require "rails/generators/rails/plugin/plugin_generator" +require "generators/shared_generator_tests" DEFAULT_PLUGIN_FILES = %w( .gitignore @@ -27,19 +27,19 @@ class PluginGeneratorTest < Rails::Generators::TestCase include SharedGeneratorTests def test_invalid_plugin_name_raises_an_error - content = capture(:stderr){ run_generator [File.join(destination_root, "my_plugin-31fr-extension")] } + content = capture(:stderr) { run_generator [File.join(destination_root, "my_plugin-31fr-extension")] } assert_equal "Invalid plugin name my_plugin-31fr-extension. Please give a name which does not contain a namespace starting with numeric characters.\n", content - content = capture(:stderr){ run_generator [File.join(destination_root, "things4.3")] } + content = capture(:stderr) { run_generator [File.join(destination_root, "things4.3")] } assert_equal "Invalid plugin name things4.3. Please give a name which uses only alphabetic, numeric, \"_\" or \"-\" characters.\n", content - content = capture(:stderr){ run_generator [File.join(destination_root, "43things")] } + content = capture(:stderr) { run_generator [File.join(destination_root, "43things")] } assert_equal "Invalid plugin name 43things. Please give a name which does not start with numbers.\n", content - content = capture(:stderr){ run_generator [File.join(destination_root, "plugin")] } + content = capture(:stderr) { run_generator [File.join(destination_root, "plugin")] } assert_equal "Invalid plugin name plugin. Please give a name which does not match one of the reserved rails words: application, destroy, plugin, runner, test\n", content - content = capture(:stderr){ run_generator [File.join(destination_root, "Digest")] } + content = capture(:stderr) { run_generator [File.join(destination_root, "Digest")] } assert_equal "Invalid plugin name Digest, constant Digest is already in use. Please choose another plugin name.\n", content end @@ -68,8 +68,8 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_match(/Rails::TestUnitReporter\.executable = 'bin\/test'/, content) end assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ - assert_file 'bin/test' - assert_no_file 'bin/rails' + assert_file "bin/test" + assert_no_file "bin/rails" end def test_generating_test_files_in_full_mode @@ -80,7 +80,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_inclusion_of_a_debugger - run_generator [destination_root, '--full'] + run_generator [destination_root, "--full"] if defined?(JRUBY_VERSION) || RUBY_ENGINE == "rbx" assert_file "Gemfile" do |content| assert_no_match(/byebug/, content) @@ -101,7 +101,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_generating_adds_dummy_app_rake_tasks_without_unit_test_files - run_generator [destination_root, "-T", "--mountable", '--dummy-path', 'my_dummy_app'] + run_generator [destination_root, "-T", "--mountable", "--dummy-path", "my_dummy_app"] assert_file "Rakefile", /APP_RAKEFILE/ end @@ -193,13 +193,24 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "test/dummy/config/database.yml", /postgres/ end - def test_generation_runs_bundle_install_with_full_and_mountable - result = run_generator [destination_root, "--mountable", "--full", "--dev"] - assert_match(/run bundle install/, result) - assert $?.success?, "Command failed: #{result}" - assert_file "#{destination_root}/Gemfile.lock" do |contents| - assert_match(/bukkits/, contents) - end + def test_generation_runs_bundle_install + assert_generates_without_bundler + end + + def test_dev_option + assert_generates_without_bundler(dev: true) + rails_path = File.expand_path("../../..", Rails.root) + assert_file "Gemfile", /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/ + end + + def test_edge_option + assert_generates_without_bundler(edge: true) + assert_file "Gemfile", %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} + end + + def test_generation_does_not_run_bundle_install_with_full_and_mountable + assert_generates_without_bundler(mountable: true, full: true, dev: true) + assert_no_file "#{destination_root}/Gemfile.lock" end def test_skipping_javascripts_without_mountable_option @@ -225,21 +236,21 @@ class PluginGeneratorTest < Rails::Generators::TestCase def test_ensure_that_tests_work run_generator FileUtils.cd destination_root - quietly { system 'bundle install' } + quietly { system "bundle install" } assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bin/test 2>&1`) end def test_ensure_that_tests_works_in_full_mode run_generator [destination_root, "--full", "--skip_active_record"] FileUtils.cd destination_root - quietly { system 'bundle install' } + quietly { system "bundle install" } assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test 2>&1`) end def test_ensure_that_migration_tasks_work_with_mountable_option run_generator [destination_root, "--mountable"] FileUtils.cd destination_root - quietly { system 'bundle install' } + quietly { system "bundle install" } output = `bin/rails db:migrate 2>&1` assert $?.success?, "Command failed: #{output}" end @@ -322,7 +333,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_match(/ActionDispatch::IntegrationTest\.fixture_path = ActiveSupport::TestCase\.fixture_pat/, content) assert_no_match(/Rails::TestUnitReporter\.executable = 'bin\/test'/, content) end - assert_no_file 'bin/test' + assert_no_file "bin/test" end def test_create_mountable_application_with_mountable_option_and_hypenated_name @@ -439,7 +450,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy/config/application.rb" assert_no_file "test" assert_no_file "test/test_helper.rb" - assert_file '.gitignore' do |contents| + assert_file ".gitignore" do |contents| assert_match(/spec\/dummy/, contents) end end @@ -447,7 +458,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase def test_dummy_appplication_skip_listen_by_default run_generator - assert_file 'test/dummy/config/environments/development.rb' do |contents| + assert_file "test/dummy/config/environments/development.rb" do |contents| assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, contents) end end @@ -462,21 +473,21 @@ class PluginGeneratorTest < Rails::Generators::TestCase def test_unnecessary_files_are_not_generated_in_dummy_application run_generator - assert_no_file 'test/dummy/.gitignore' - assert_no_file 'test/dummy/db/seeds.rb' - assert_no_file 'test/dummy/Gemfile' - assert_no_file 'test/dummy/public/robots.txt' - assert_no_file 'test/dummy/README.md' - assert_no_directory 'test/dummy/lib/tasks' - assert_no_directory 'test/dummy/doc' - assert_no_directory 'test/dummy/test' - assert_no_directory 'test/dummy/vendor' + assert_no_file "test/dummy/.gitignore" + assert_no_file "test/dummy/db/seeds.rb" + assert_no_file "test/dummy/Gemfile" + assert_no_file "test/dummy/public/robots.txt" + assert_no_file "test/dummy/README.md" + assert_no_directory "test/dummy/lib/tasks" + assert_no_directory "test/dummy/doc" + assert_no_directory "test/dummy/test" + assert_no_directory "test/dummy/vendor" end def test_skipping_test_files run_generator [destination_root, "--skip-test"] assert_no_file "test" - assert_file '.gitignore' do |contents| + assert_file ".gitignore" do |contents| assert_no_match(/test\dummy/, contents) end end @@ -485,7 +496,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-gemspec"] assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| - assert_no_match('gemspec', contents) + assert_no_match("gemspec", contents) assert_match(/gem 'rails'/, contents) assert_match_sqlite3(contents) assert_no_match(/# gem "jquery-rails"/, contents) @@ -496,7 +507,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-gemspec", "--full"] assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| - assert_no_match('gemspec', contents) + assert_no_match("gemspec", contents) assert_match(/gem 'rails'/, contents) assert_match_sqlite3(contents) end @@ -505,21 +516,21 @@ class PluginGeneratorTest < Rails::Generators::TestCase def test_creating_plugin_in_app_directory_adds_gemfile_entry # simulate application existence gemfile_path = "#{Rails.root}/Gemfile" - Object.const_set('APP_PATH', Rails.root) + Object.const_set("APP_PATH", Rails.root) FileUtils.touch gemfile_path run_generator assert_file gemfile_path, /gem 'bukkits', path: 'tmp\/bukkits'/ ensure - Object.send(:remove_const, 'APP_PATH') + Object.send(:remove_const, "APP_PATH") FileUtils.rm gemfile_path end def test_skipping_gemfile_entry # simulate application existence gemfile_path = "#{Rails.root}/Gemfile" - Object.const_set('APP_PATH', Rails.root) + Object.const_set("APP_PATH", Rails.root) FileUtils.touch gemfile_path run_generator [destination_root, "--skip-gemfile-entry"] @@ -528,7 +539,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_no_match(/gem 'bukkits', path: 'tmp\/bukkits'/, contents) end ensure - Object.send(:remove_const, 'APP_PATH') + Object.send(:remove_const, "APP_PATH") FileUtils.rm gemfile_path end @@ -569,7 +580,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase name = "TODO: Write your name" email = "TODO: Write your email address" - run_generator [destination_root, '--skip-git'] + run_generator [destination_root, "--skip-git"] assert_file "MIT-LICENSE" do |contents| assert_match name, contents end @@ -580,8 +591,8 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_skipping_useless_folders_generation_for_api_engines - ['--full', '--mountable'].each do |option| - run_generator [destination_root, option, '--api'] + ["--full", "--mountable"].each do |option| + run_generator [destination_root, option, "--api"] assert_no_directory "app/assets" assert_no_directory "app/helpers" @@ -592,7 +603,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_application_controller_parent_for_mountable_api_plugins - run_generator [destination_root, '--mountable', '--api'] + run_generator [destination_root, "--mountable", "--api"] assert_file "app/controllers/bukkits/application_controller.rb" do |content| assert_match "ApplicationController < ActionController::API", content @@ -600,16 +611,15 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_dummy_api_application_for_api_plugins - run_generator [destination_root, '--api'] + run_generator [destination_root, "--api"] assert_file "test/dummy/config/application.rb" do |content| assert_match "config.api_only = true", content end end - def test_api_generators_configuration_for_api_engines - run_generator [destination_root, '--full', '--api'] + run_generator [destination_root, "--full", "--api"] assert_file "lib/bukkits/engine.rb" do |content| assert_match "config.generators.api_only = true", content @@ -617,7 +627,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_scaffold_generator_for_mountable_api_plugins - run_generator [destination_root, '--mountable', '--api'] + run_generator [destination_root, "--mountable", "--api"] capture(:stdout) do `#{destination_root}/bin/rails g scaffold article` @@ -634,7 +644,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_model_with_existent_application_record_in_mountable_engine - run_generator [destination_root, '--mountable'] + run_generator [destination_root, "--mountable"] capture(:stdout) do `#{destination_root}/bin/rails g model article` end @@ -643,7 +653,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_generate_application_record_when_does_not_exist_in_mountable_engine - run_generator [destination_root, '--mountable'] + run_generator [destination_root, "--mountable"] FileUtils.rm "#{destination_root}/app/models/bukkits/application_record.rb" capture(:stdout) do `#{destination_root}/bin/rails g model article` @@ -657,7 +667,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_generate_application_mailer_when_does_not_exist_in_mountable_engine - run_generator [destination_root, '--mountable'] + run_generator [destination_root, "--mountable"] FileUtils.rm "#{destination_root}/app/mailers/bukkits/application_mailer.rb" capture(:stdout) do `#{destination_root}/bin/rails g mailer User` @@ -670,7 +680,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_generate_mailer_layouts_when_does_not_exist_in_mountable_engine - run_generator [destination_root, '--mountable'] + run_generator [destination_root, "--mountable"] capture(:stdout) do `#{destination_root}/bin/rails g mailer User` end @@ -685,7 +695,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_generate_application_job_when_does_not_exist_in_mountable_engine - run_generator [destination_root, '--mountable'] + run_generator [destination_root, "--mountable"] FileUtils.rm "#{destination_root}/app/jobs/bukkits/application_job.rb" capture(:stdout) do `#{destination_root}/bin/rails g job refresh_counters` @@ -697,48 +707,38 @@ class PluginGeneratorTest < Rails::Generators::TestCase end end - def test_after_bundle_callback - path = 'http://example.org/rails_template' - template = %{ after_bundle { run 'echo ran after_bundle' } } - template.instance_eval "def read; self; end" # Make the string respond to read + protected - check_open = -> *args do - assert_equal [ path, 'Accept' => 'application/x-thor-template' ], args - template + def action(*args, &block) + silence(:stdout) { generator.send(*args, &block) } end - sequence = ['install', 'echo ran after_bundle'] - @sequence_step ||= 0 - ensure_bundler_first = -> command do - assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}" - @sequence_step += 1 + def default_files + ::DEFAULT_PLUGIN_FILES end - generator([destination_root], template: path).stub(:open, check_open, template) do - generator.stub(:bundle_command, ensure_bundler_first) do - generator.stub(:run, ensure_bundler_first) do - quietly { generator.invoke_all } - end + def assert_match_sqlite3(contents) + if defined?(JRUBY_VERSION) + assert_match(/group :development do\n gem 'activerecord-jdbcsqlite3-adapter'\nend/, contents) + else + assert_match(/group :development do\n gem 'sqlite3'\nend/, contents) end end - assert_equal 2, @sequence_step - end - -protected - def action(*args, &block) - silence(:stdout){ generator.send(*args, &block) } - end + def assert_generates_without_bundler(options = {}) + generator([destination_root], options) - def default_files - ::DEFAULT_PLUGIN_FILES - end + command_check = -> command do + case command + when "install" + flunk "install expected to not be called" + when "exec spring binstub --all" + # Called when running tests with spring, let through unscathed. + end + end - def assert_match_sqlite3(contents) - if defined?(JRUBY_VERSION) - assert_match(/group :development do\n gem 'activerecord-jdbcsqlite3-adapter'\nend/, contents) - else - assert_match(/group :development do\n gem 'sqlite3'\nend/, contents) + generator.stub :bundle_command, command_check do + quietly { generator.invoke_all } + end end - end end diff --git a/railties/test/generators/plugin_test_helper.rb b/railties/test/generators/plugin_test_helper.rb index 96c1b1d31f..8ac90e3484 100644 --- a/railties/test/generators/plugin_test_helper.rb +++ b/railties/test/generators/plugin_test_helper.rb @@ -1,5 +1,5 @@ -require 'abstract_unit' -require 'tmpdir' +require "abstract_unit" +require "tmpdir" module PluginTestHelper def create_test_file(name, pass: true) @@ -15,7 +15,7 @@ module PluginTestHelper RUBY end - def plugin_file(path, contents, mode: 'w') + def plugin_file(path, contents, mode: "w") FileUtils.mkdir_p File.dirname("#{plugin_path}/#{path}") File.open("#{plugin_path}/#{path}", mode) do |f| f.puts contents diff --git a/railties/test/generators/plugin_test_runner_test.rb b/railties/test/generators/plugin_test_runner_test.rb index ef6359fece..7a10a2afa9 100644 --- a/railties/test/generators/plugin_test_runner_test.rb +++ b/railties/test/generators/plugin_test_runner_test.rb @@ -1,12 +1,12 @@ -require 'generators/plugin_test_helper' +require "generators/plugin_test_helper" class PluginTestRunnerTest < ActiveSupport::TestCase include PluginTestHelper def setup - @destination_root = Dir.mktmpdir('bukkits') + @destination_root = Dir.mktmpdir("bukkits") Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --skip-bundle` } - plugin_file 'test/dummy/db/schema.rb', '' + plugin_file "test/dummy/db/schema.rb", "" end def teardown @@ -14,20 +14,20 @@ class PluginTestRunnerTest < ActiveSupport::TestCase end def test_run_single_file - create_test_file 'foo' - create_test_file 'bar' + create_test_file "foo" + create_test_file "bar" assert_match "1 runs, 1 assertions, 0 failures", run_test_command("test/foo_test.rb") end def test_run_multiple_files - create_test_file 'foo' - create_test_file 'bar' + create_test_file "foo" + create_test_file "bar" assert_match "2 runs, 2 assertions, 0 failures", run_test_command("test/foo_test.rb test/bar_test.rb") end def test_mix_files_and_line_filters - create_test_file 'account' - plugin_file 'test/post_test.rb', <<-RUBY + create_test_file "account" + plugin_file "test/post_test.rb", <<-RUBY require 'test_helper' class PostTest < ActiveSupport::TestCase @@ -42,50 +42,56 @@ class PluginTestRunnerTest < ActiveSupport::TestCase end RUBY - run_test_command('test/account_test.rb test/post_test.rb:4').tap do |output| - assert_match 'AccountTest', output - assert_match 'PostTest', output - assert_match '2 runs, 2 assertions', output + run_test_command("test/account_test.rb test/post_test.rb:4").tap do |output| + assert_match "AccountTest", output + assert_match "PostTest", output + assert_match "2 runs, 2 assertions", output end end def test_multiple_line_filters - create_test_file 'account' - create_test_file 'post' + create_test_file "account" + create_test_file "post" - run_test_command('test/account_test.rb:4 test/post_test.rb:4').tap do |output| - assert_match 'AccountTest', output - assert_match 'PostTest', output + run_test_command("test/account_test.rb:4 test/post_test.rb:4").tap do |output| + assert_match "AccountTest", output + assert_match "PostTest", output end end def test_output_inline_by_default - create_test_file 'post', pass: false + create_test_file "post", pass: false - output = run_test_command('test/post_test.rb') + output = run_test_command("test/post_test.rb") expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/post_test.rb:6\]:\nwups!\n\nbin/test (/private)?#{plugin_path}/test/post_test.rb:4} assert_match expect, output end def test_only_inline_failure_output - create_test_file 'post', pass: false + create_test_file "post", pass: false - output = run_test_command('test/post_test.rb') + output = run_test_command("test/post_test.rb") assert_match %r{Finished in.*\n\n1 runs, 1 assertions}, output end def test_fail_fast - create_test_file 'post', pass: false + create_test_file "post", pass: false assert_match(/Interrupt/, - capture(:stderr) { run_test_command('test/post_test.rb --fail-fast') }) + capture(:stderr) { run_test_command("test/post_test.rb --fail-fast") }) end def test_raise_error_when_specified_file_does_not_exist - error = capture(:stderr) { run_test_command('test/not_exists.rb') } + error = capture(:stderr) { run_test_command("test/not_exists.rb") } assert_match(%r{cannot load such file.+test/not_exists\.rb}, error) end + def test_executed_only_once + create_test_file "foo" + result = run_test_command("test/foo_test.rb") + assert_equal 1, result.scan(/1 runs, 1 assertions, 0 failures/).length + end + private def plugin_path "#{@destination_root}/bukkits" diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 53dcfc4024..e976e58180 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/resource/resource_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/resource/resource_generator" class ResourceGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index 736ff0b41f..bd23faf268 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/scaffold_controller/scaffold_controller_generator" module Unknown module Generators diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index bd69906b9d..6b7e2c91d7 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/scaffold/scaffold_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/scaffold/scaffold_generator" class ScaffoldGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -74,8 +74,8 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase end assert_file "app/views/product_lines/_form.html.erb" do |test| - assert_match 'product_line', test - assert_no_match '@product_line', test + assert_match "product_line", test + assert_no_match "@product_line", test end # Helpers @@ -269,7 +269,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase def test_scaffold_with_namespace_on_revoke run_generator [ "admin/role", "name:string", "description:string" ] - run_generator [ "admin/role" ], :behavior => :revoke + run_generator [ "admin/role" ], behavior: :revoke # Model assert_file "app/models/admin.rb" # ( should not be remove ) @@ -310,7 +310,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase end File.open(route_path, "wb") { |file| file.write(content) } - run_generator ["product_line"], :behavior => :revoke + run_generator ["product_line"], behavior: :revoke assert_file "config/routes.rb", /\.routes\.draw do\s*\|map\|\s*$/ end @@ -322,13 +322,13 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase content = File.read(route_path) # Remove all of the comments and blank lines from the routes file - content.gsub!(/^ \#.*\n/, '') - content.gsub!(/^\n/, '') + content.gsub!(/^ \#.*\n/, "") + content.gsub!(/^\n/, "") File.open(route_path, "wb") { |file| file.write(content) } assert_file "config/routes.rb", /\.routes\.draw do\n resources :product_lines\nend\n\z/ - run_generator ["product_line"], :behavior => :revoke + run_generator ["product_line"], behavior: :revoke assert_file "config/routes.rb", /\.routes\.draw do\nend\n\z/ end diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index e83d54890a..27b2fc8955 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -5,7 +5,7 @@ module SharedGeneratorTests def setup Rails.application = TestApp::Application super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) + Rails::Generators::AppGenerator.instance_variable_set("@desc", nil) Kernel::silence_warnings do Thor::Base.shell.send(:attr_accessor, :always_force) @@ -16,7 +16,7 @@ module SharedGeneratorTests def teardown super - Rails::Generators::AppGenerator.instance_variable_set('@desc', nil) + Rails::Generators::AppGenerator.instance_variable_set("@desc", nil) Rails.application = TestApp::Application.instance end @@ -26,37 +26,13 @@ module SharedGeneratorTests default_files.each { |path| assert_file path } end - def assert_generates_with_bundler(options = {}) - generator([destination_root], options) - - command_check = -> command do - @install_called ||= 0 - - case command - when 'install' - @install_called += 1 - assert_equal 1, @install_called, "install expected to be called once, but was called #{@install_called} times" - when 'exec spring binstub --all' - # Called when running tests with spring, let through unscathed. - end - end - - generator.stub :bundle_command, command_check do - quietly { generator.invoke_all } - end - end - - def test_generation_runs_bundle_install - assert_generates_with_bundler - end - def test_plugin_new_generate_pretend run_generator ["testapp", "--pretend"] - default_files.each{ |path| assert_no_file File.join("testapp",path) } + default_files.each { |path| assert_no_file File.join("testapp",path) } end def test_invalid_database_option_raises_an_error - content = capture(:stderr){ run_generator([destination_root, "-d", "unknown"]) } + content = capture(:stderr) { run_generator([destination_root, "-d", "unknown"]) } assert_match(/Invalid value for \-\-database option/, content) end @@ -68,14 +44,14 @@ module SharedGeneratorTests def test_name_collision_raises_an_error reserved_words = %w[application destroy plugin runner test] reserved_words.each do |reserved| - content = capture(:stderr){ run_generator [File.join(destination_root, reserved)] } + content = capture(:stderr) { run_generator [File.join(destination_root, reserved)] } assert_match(/Invalid \w+ name #{reserved}. Please give a name which does not match one of the reserved rails words: application, destroy, plugin, runner, test\n/, content) end end def test_name_raises_an_error_if_name_already_used_constant %w{ String Hash Class Module Set Symbol }.each do |ruby_class| - content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] } + content = capture(:stderr) { run_generator [File.join(destination_root, ruby_class)] } assert_match(/Invalid \w+ name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another \w+ name.\n/, content) end end @@ -92,7 +68,7 @@ module SharedGeneratorTests def test_template_raises_an_error_with_invalid_path quietly do - content = capture(:stderr){ run_generator([destination_root, "-m", "non/existent/path"]) } + content = capture(:stderr) { run_generator([destination_root, "-m", "non/existent/path"]) } assert_match(/The template \[.*\] could not be loaded/, content) assert_match(/non\/existent\/path/, content) @@ -105,7 +81,7 @@ module SharedGeneratorTests template.instance_eval "def read; self; end" # Make the string respond to read check_open = -> *args do - assert_equal [ path, 'Accept' => 'application/x-thor-template' ], args + assert_equal [ path, "Accept" => "application/x-thor-template" ], args template end @@ -114,21 +90,10 @@ module SharedGeneratorTests end end - def test_dev_option - assert_generates_with_bundler dev: true - rails_path = File.expand_path('../../..', Rails.root) - assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/ - end - - def test_edge_option - assert_generates_with_bundler edge: true - assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} - end - def test_skip_gemfile assert_not_called(generator([destination_root], skip_gemfile: true), :bundle_command) do quietly { generator.invoke_all } - assert_no_file 'Gemfile' + assert_no_file "Gemfile" end end @@ -137,22 +102,22 @@ module SharedGeneratorTests quietly { generator.invoke_all } # skip_bundle is only about running bundle install, ensure the Gemfile is still # generated. - assert_file 'Gemfile' + assert_file "Gemfile" end end def test_skip_git - run_generator [destination_root, '--skip-git', '--full'] - assert_no_file('.gitignore') + run_generator [destination_root, "--skip-git", "--full"] + assert_no_file(".gitignore") end def test_skip_keeps - run_generator [destination_root, '--skip-keeps', '--full'] + run_generator [destination_root, "--skip-keeps", "--full"] - assert_file '.gitignore' do |content| + assert_file ".gitignore" do |content| assert_no_match(/\.keep/, content) end - assert_no_file('app/models/concerns/.keep') + assert_no_file("app/models/concerns/.keep") end end diff --git a/railties/test/generators/task_generator_test.rb b/railties/test/generators/task_generator_test.rb index d5bd44b9db..2285534bb9 100644 --- a/railties/test/generators/task_generator_test.rb +++ b/railties/test/generators/task_generator_test.rb @@ -1,5 +1,5 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/task/task_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/task/task_generator" class TaskGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -15,10 +15,10 @@ class TaskGeneratorTest < Rails::Generators::TestCase end def test_task_on_revoke - task_path = 'lib/tasks/feeds.rake' + task_path = "lib/tasks/feeds.rake" run_generator assert_file task_path - run_generator ['feeds'], behavior: :revoke + run_generator ["feeds"], behavior: :revoke assert_no_file task_path end end diff --git a/railties/test/generators/test_runner_in_engine_test.rb b/railties/test/generators/test_runner_in_engine_test.rb index d37e261fbb..4b5fb3ba3f 100644 --- a/railties/test/generators/test_runner_in_engine_test.rb +++ b/railties/test/generators/test_runner_in_engine_test.rb @@ -1,12 +1,12 @@ -require 'generators/plugin_test_helper' +require "generators/plugin_test_helper" class TestRunnerInEngineTest < ActiveSupport::TestCase include PluginTestHelper def setup - @destination_root = Dir.mktmpdir('bukkits') + @destination_root = Dir.mktmpdir("bukkits") Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --full --skip-bundle` } - plugin_file 'test/dummy/db/schema.rb', '' + plugin_file "test/dummy/db/schema.rb", "" end def teardown @@ -14,9 +14,9 @@ class TestRunnerInEngineTest < ActiveSupport::TestCase end def test_rerun_snippet_is_relative_path - create_test_file 'post', pass: false + create_test_file "post", pass: false - output = run_test_command('test/post_test.rb') + output = run_test_command("test/post_test.rb") expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/post_test.rb:6\]:\nwups!\n\nbin/rails test test/post_test.rb:4} assert_match expect, output end diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index 291415858c..68ba435393 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -1,6 +1,6 @@ -require 'generators/generators_test_helper' -require 'rails/generators/rails/model/model_generator' -require 'rails/generators/test_unit/model/model_generator' +require "generators/generators_test_helper" +require "rails/generators/rails/model/model_generator" +require "rails/generators/test_unit/model/model_generator" class GeneratorsTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -15,7 +15,7 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_simple_invoke - assert File.exist?(File.join(@path, 'generators', 'model_generator.rb')) + assert File.exist?(File.join(@path, "generators", "model_generator.rb")) assert_called_with(TestUnit::Generators::ModelGenerator, :start, [["Account"], {}]) do Rails::Generators.invoke("test_unit:model", ["Account"]) end @@ -23,32 +23,32 @@ class GeneratorsTest < Rails::Generators::TestCase def test_invoke_when_generator_is_not_found name = :unknown - output = capture(:stdout){ Rails::Generators.invoke name } + output = capture(:stdout) { Rails::Generators.invoke name } assert_match "Could not find generator '#{name}'", output assert_match "`rails generate --help`", output end def test_generator_suggestions name = :migrationz - output = capture(:stdout){ Rails::Generators.invoke name } + output = capture(:stdout) { Rails::Generators.invoke name } assert_match "Maybe you meant 'migration'", output end def test_generator_multiple_suggestions name = :tas - output = capture(:stdout){ Rails::Generators.invoke name } + output = capture(:stdout) { Rails::Generators.invoke name } assert_match "Maybe you meant 'task', 'job' or", output end def test_help_when_a_generator_with_required_arguments_is_invoked_without_arguments - output = capture(:stdout){ Rails::Generators.invoke :model, [] } + output = capture(:stdout) { Rails::Generators.invoke :model, [] } assert_match(/Description:/, output) end def test_should_give_higher_preference_to_rails_generators - assert File.exist?(File.join(@path, 'generators', 'model_generator.rb')) + assert File.exist?(File.join(@path, "generators", "model_generator.rb")) assert_called_with(Rails::Generators::ModelGenerator, :start, [["Account"], {}]) do - warnings = capture(:stderr){ Rails::Generators.invoke :model, ["Account"] } + warnings = capture(:stderr) { Rails::Generators.invoke :model, ["Account"] } assert warnings.empty? end end @@ -108,14 +108,14 @@ class GeneratorsTest < Rails::Generators::TestCase def test_invoke_with_nested_namespaces model_generator = Minitest::Mock.new model_generator.expect(:start, nil, [["Account"], {}]) - assert_called_with(Rails::Generators, :find_by_namespace, ['namespace', 'my:awesome'], returns: model_generator) do - Rails::Generators.invoke 'my:awesome:namespace', ["Account"] + assert_called_with(Rails::Generators, :find_by_namespace, ["namespace", "my:awesome"], returns: model_generator) do + Rails::Generators.invoke "my:awesome:namespace", ["Account"] end model_generator.verify end def test_rails_generators_help_with_builtin_information - output = capture(:stdout){ Rails::Generators.help } + output = capture(:stdout) { Rails::Generators.help } assert_match(/Rails:/, output) assert_match(/^ model$/, output) assert_match(/^ scaffold_controller$/, output) @@ -123,19 +123,19 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_rails_generators_help_does_not_include_app_nor_plugin_new - output = capture(:stdout){ Rails::Generators.help } + output = capture(:stdout) { Rails::Generators.help } assert_no_match(/app/, output) assert_no_match(/[^:]plugin/, output) end def test_rails_generators_with_others_information - output = capture(:stdout){ Rails::Generators.help } + output = capture(:stdout) { Rails::Generators.help } assert_match(/Fixjour:/, output) assert_match(/^ fixjour$/, output) end def test_rails_generators_does_not_show_active_record_hooks - output = capture(:stdout){ Rails::Generators.help } + output = capture(:stdout) { Rails::Generators.help } assert_match(/ActiveRecord:/, output) assert_match(/^ active_record:fixjour$/, output) end @@ -214,7 +214,7 @@ class GeneratorsTest < Rails::Generators::TestCase # Create template mkdir_p(File.dirname(template)) - File.open(template, 'w'){ |f| f.write "empty" } + File.open(template, "w") { |f| f.write "empty" } capture(:stdout) do Rails::Generators.invoke :model, ["user"], destination_root: destination_root @@ -229,18 +229,18 @@ class GeneratorsTest < Rails::Generators::TestCase def test_source_paths_for_not_namespaced_generators mspec = Rails::Generators.find_by_namespace :fixjour - assert mspec.source_paths.include?(File.join(Rails.root, "lib", "templates", "fixjour")) + assert_includes mspec.source_paths, File.join(Rails.root, "lib", "templates", "fixjour") end def test_usage_with_embedded_ruby require File.expand_path("fixtures/lib/generators/usage_template/usage_template_generator", File.dirname(__FILE__)) - output = capture(:stdout) { Rails::Generators.invoke :usage_template, ['--help'] } + output = capture(:stdout) { Rails::Generators.invoke :usage_template, ["--help"] } assert_match(/:: 2 ::/, output) end def test_hide_namespace - assert !Rails::Generators.hidden_namespaces.include?("special:namespace") + assert_not_includes Rails::Generators.hidden_namespaces, "special:namespace" Rails::Generators.hide_namespace("special:namespace") - assert Rails::Generators.hidden_namespaces.include?("special:namespace") + assert_includes Rails::Generators.hidden_namespaces, "special:namespace" end end diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb index ed9573453b..4b67c91cc5 100644 --- a/railties/test/initializable_test.rb +++ b/railties/test/initializable_test.rb @@ -1,8 +1,7 @@ -require 'abstract_unit' -require 'rails/initializable' +require "abstract_unit" +require "rails/initializable" module InitializableTests - class Foo include Rails::Initializable attr_accessor :foo, :bar @@ -174,6 +173,11 @@ module InitializableTests end end end + + test "Initializer provides context's class name" do + foo = Foo.new + assert_equal foo.class, foo.initializers.first.context_class + end end class BeforeAfter < ActiveSupport::TestCase @@ -215,8 +219,8 @@ module InitializableTests class WithArgsTest < ActiveSupport::TestCase test "running initializers with args" do $with_arg = nil - WithArgs.new.run_initializers(:default, 'foo') - assert_equal 'foo', $with_arg + WithArgs.new.run_initializers(:default, "foo") + assert_equal "foo", $with_arg end end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index e427614dfa..6880cf306a 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -1,18 +1,18 @@ # Note: # It is important to keep this file as light as possible # the goal for tests that require this is to test booting up -# rails from an empty state, so anything added here could +# Rails from an empty state, so anything added here could # hide potential failures # # It is also good to know what is the bare minimum to get # Rails booted up. -require 'fileutils' +require "fileutils" -require 'bundler/setup' unless defined?(Bundler) -require 'active_support' -require 'active_support/testing/autorun' -require 'active_support/testing/stream' -require 'active_support/test_case' +require "bundler/setup" unless defined?(Bundler) +require "active_support" +require "active_support/testing/autorun" +require "active_support/testing/stream" +require "active_support/test_case" RAILS_FRAMEWORK_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../..") @@ -21,12 +21,12 @@ RAILS_FRAMEWORK_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../..") require "active_support/core_ext/object/blank" require "active_support/testing/isolation" require "active_support/core_ext/kernel/reporting" -require 'tmpdir' +require "tmpdir" module TestHelpers module Paths def app_template_path - File.join Dir.tmpdir, 'app_template' + File.join Dir.tmpdir, "app_template" end def tmp_path(*args) @@ -66,7 +66,7 @@ module TestHelpers def extract_body(response) "".tap do |body| - response[2].each {|chunk| body << chunk } + response[2].each { |chunk| body << chunk } end end @@ -78,8 +78,8 @@ module TestHelpers resp = Array(resp) assert_equal 200, resp[0] - assert_match 'text/html', resp[1]["Content-Type"] - assert_match 'charset=utf-8', resp[1]["Content-Type"] + assert_match "text/html", resp[1]["Content-Type"] + assert_match "charset=utf-8", resp[1]["Content-Type"] assert extract_body(resp).match(/Yay! You.*re on Rails!/) end @@ -103,9 +103,9 @@ module TestHelpers module Generation # Build an application by invoking the generator and going through the whole stack. def build_app(options = {}) - @prev_rails_env = ENV['RAILS_ENV'] - ENV['RAILS_ENV'] = "development" - ENV['SECRET_KEY_BASE'] ||= SecureRandom.hex(16) + @prev_rails_env = ENV["RAILS_ENV"] + ENV["RAILS_ENV"] = "development" + ENV["SECRET_KEY_BASE"] ||= SecureRandom.hex(16) FileUtils.rm_rf(app_path) FileUtils.cp_r(app_template_path, app_path) @@ -117,14 +117,9 @@ module TestHelpers end end - gemfile_path = "#{app_path}/Gemfile" - if options[:gemfile].blank? && File.exist?(gemfile_path) - File.delete gemfile_path - end - routes = File.read("#{app_path}/config/routes.rb") if routes =~ /(\n\s*end\s*)\Z/ - File.open("#{app_path}/config/routes.rb", 'w') do |f| + File.open("#{app_path}/config/routes.rb", "w") do |f| f.puts $` + "\nActiveSupport::Deprecation.silence { match ':controller(/:action(/:id))(.:format)', via: :all }\n" + $1 end end @@ -158,7 +153,7 @@ module TestHelpers end def teardown_app - ENV['RAILS_ENV'] = @prev_rails_env if @prev_rails_env + ENV["RAILS_ENV"] = @prev_rails_env if @prev_rails_env end # Make a very basic app, without creating the whole directory structure. @@ -167,7 +162,7 @@ module TestHelpers require "rails" require "action_controller/railtie" require "action_view/railtie" - require 'action_dispatch/middleware/flash' + require "action_dispatch/middleware/flash" @app = Class.new(Rails::Application) @app.config.eager_load = false @@ -184,7 +179,7 @@ module TestHelpers get "/" => "omg#index" end - require 'rack/test' + require "rack/test" extend ::Rack::Test::Methods end @@ -192,12 +187,12 @@ module TestHelpers controller :foo, <<-RUBY class FooController < ApplicationController def index - render text: "foo" + render plain: "foo" end end RUBY - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' end @@ -214,7 +209,7 @@ module TestHelpers def write(file, string) path = "#{@path}/#{file}" FileUtils.mkdir_p(File.dirname(path)) - File.open(path, "w") {|f| f.puts string } + File.open(path, "w") { |f| f.puts string } end def delete(file) @@ -230,7 +225,7 @@ module TestHelpers app.insert(2, "$:.unshift(\"#{dir}/lib\")") app.insert(3, "require #{name.inspect}") - File.open("#{app_path}/config/application.rb", 'r+') do |f| + File.open("#{app_path}/config/application.rb", "r+") do |f| f.puts app end @@ -248,7 +243,7 @@ module TestHelpers def add_to_top_of_config(str) environment = File.read("#{app_path}/config/application.rb") if environment =~ /(Rails::Application\s*)/ - File.open("#{app_path}/config/application.rb", 'w') do |f| + File.open("#{app_path}/config/application.rb", "w") do |f| f.puts $` + $1 + "\n#{str}\n" + $' end end @@ -257,7 +252,7 @@ module TestHelpers def add_to_config(str) environment = File.read("#{app_path}/config/application.rb") if environment =~ /(\n\s*end\s*end\s*)\Z/ - File.open("#{app_path}/config/application.rb", 'w') do |f| + File.open("#{app_path}/config/application.rb", "w") do |f| f.puts $` + "\n#{str}\n" + $1 end end @@ -266,7 +261,7 @@ module TestHelpers def add_to_env_config(env, str) environment = File.read("#{app_path}/config/environments/#{env}.rb") if environment =~ /(\n\s*end\s*)\Z/ - File.open("#{app_path}/config/environments/#{env}.rb", 'w') do |f| + File.open("#{app_path}/config/environments/#{env}.rb", "w") do |f| f.puts $` + "\n#{str}\n" + $1 end end @@ -282,11 +277,11 @@ module TestHelpers def remove_from_file(file, str) contents = File.read(file) - contents.sub!(/#{str}/, '') + contents.sub!(/#{str}/, "") File.write(file, contents) end - def app_file(path, contents, mode = 'w') + def app_file(path, contents, mode = "w") FileUtils.mkdir_p File.dirname("#{app_path}/#{path}") File.open("#{app_path}/#{path}", mode) do |f| f.puts contents @@ -305,13 +300,10 @@ module TestHelpers to_remove = [:actionmailer, :activerecord] - arr if to_remove.include?(:activerecord) - remove_from_config 'config.active_record.*' + remove_from_config "config.active_record.*" end - $:.reject! {|path| path =~ %r'/(#{to_remove.join('|')})/' } - end - - def boot_rails + $:.reject! { |path| path =~ %r'/(#{to_remove.join('|')})/' } end end end @@ -334,7 +326,7 @@ Module.new do FileUtils.mkdir(app_template_path) `#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-gemfile --skip-listen --no-rc` - File.open("#{app_template_path}/config/boot.rb", 'w') do |f| + File.open("#{app_template_path}/config/boot.rb", "w") do |f| f.puts "require 'rails/all'" end end unless defined?(RAILS_ISOLATED_ENGINE) diff --git a/railties/test/json_params_parsing_test.rb b/railties/test/json_params_parsing_test.rb new file mode 100644 index 0000000000..7fff3bb465 --- /dev/null +++ b/railties/test/json_params_parsing_test.rb @@ -0,0 +1,49 @@ +require "abstract_unit" +require "action_dispatch" +require "active_record" + +class JsonParamsParsingTest < ActionDispatch::IntegrationTest + def test_prevent_null_query + # Make sure we have data to find + klass = Class.new(ActiveRecord::Base) do + def self.name; "Foo"; end + establish_connection adapter: "sqlite3", database: ":memory:" + connection.create_table "foos" do |t| + t.string :title + t.timestamps null: false + end + end + klass.create + assert klass.first + + app = ->(env) { + request = ActionDispatch::Request.new env + params = ActionController::Parameters.new request.parameters + if params[:t] + klass.find_by_title(params[:t]) + else + nil + end + } + + assert_nil app.call(make_env("t" => nil)) + assert_nil app.call(make_env("t" => [nil])) + + [[[nil]], [[[nil]]]].each do |data| + assert_nil app.call(make_env("t" => data)) + end + ensure + klass.connection.drop_table("foos") + end + + private + def make_env(json) + data = JSON.dump json + content_length = data.length + { + "CONTENT_LENGTH" => content_length, + "CONTENT_TYPE" => "application/json", + "rack.input" => StringIO.new(data) + } + end +end diff --git a/railties/test/path_generation_test.rb b/railties/test/path_generation_test.rb index a16adc72a6..579e50ac95 100644 --- a/railties/test/path_generation_test.rb +++ b/railties/test/path_generation_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'active_support/core_ext/object/with_options' -require 'active_support/core_ext/object/json' +require "abstract_unit" +require "active_support/core_ext/object/with_options" +require "active_support/core_ext/object/json" class PathGenerationTest < ActiveSupport::TestCase attr_reader :app @@ -30,7 +30,7 @@ class PathGenerationTest < ActiveSupport::TestCase end def make_request(env) - Request.new super, self.url_helpers, @block + Request.new(super, url_helpers, @block) end end @@ -38,11 +38,11 @@ class PathGenerationTest < ActiveSupport::TestCase host = uri_or_host.host unless path path ||= uri_or_host.path - params = {'PATH_INFO' => path, - 'REQUEST_METHOD' => method, - 'HTTP_HOST' => host } + params = { "PATH_INFO" => path, + "REQUEST_METHOD" => method, + "HTTP_HOST" => host } - params['SCRIPT_NAME'] = script_name if script_name + params["SCRIPT_NAME"] = script_name if script_name status, headers, body = app.call(params) new_body = [] @@ -72,11 +72,11 @@ class PathGenerationTest < ActiveSupport::TestCase url = URI("http://example.org/blogs") - send_request(url, 'GET', nil, '/FOO') - assert_equal '/FOO/blogs', app.instance.controller.blogs_path + send_request(url, "GET", nil, "/FOO") + assert_equal "/FOO/blogs", app.instance.controller.blogs_path - send_request(url, 'GET', nil) - assert_equal '/blogs', app.instance.controller.blogs_path + send_request(url, "GET", nil) + assert_equal "/blogs", app.instance.controller.blogs_path ensure Rails.logger = original_logger end diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index 96b54c7264..7b2551062a 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'rails/paths' -require 'minitest/mock' +require "abstract_unit" +require "rails/paths" +require "minitest/mock" class PathsTest < ActiveSupport::TestCase def setup @@ -103,7 +103,7 @@ class PathsTest < ActiveSupport::TestCase @root.add "app", with: "/app" @root["app"].autoload_once! assert @root["app"].autoload_once? - assert @root.autoload_once.include?(@root["app"].expanded.first) + assert_includes @root.autoload_once, @root["app"].expanded.first end end @@ -114,14 +114,14 @@ class PathsTest < ActiveSupport::TestCase @root["app"].skip_autoload_once! assert !@root["app"].autoload_once? - assert !@root.autoload_once.include?(@root["app"].expanded.first) + assert_not_includes @root.autoload_once, @root["app"].expanded.first end test "it is possible to add a path without assignment and specify it should be loaded only once" do File.stub(:exist?, true) do @root.add "app", with: "/app", autoload_once: true assert @root["app"].autoload_once? - assert @root.autoload_once.include?("/app") + assert_includes @root.autoload_once, "/app" end end @@ -129,8 +129,8 @@ class PathsTest < ActiveSupport::TestCase File.stub(:exist?, true) do @root.add "app", with: ["/app", "/app2"], autoload_once: true assert @root["app"].autoload_once? - assert @root.autoload_once.include?("/app") - assert @root.autoload_once.include?("/app2") + assert_includes @root.autoload_once, "/app" + assert_includes @root.autoload_once, "/app2" end end @@ -139,7 +139,7 @@ class PathsTest < ActiveSupport::TestCase @root["app"] = "/app" @root["app"].autoload_once! @root["app"].autoload_once! - assert_equal 1, @root.autoload_once.select {|p| p == @root["app"].expanded.first }.size + assert_equal 1, @root.autoload_once.select { |p| p == @root["app"].expanded.first }.size end end @@ -157,7 +157,7 @@ class PathsTest < ActiveSupport::TestCase @root["app"] = "/app" @root["app"].eager_load! assert @root["app"].eager_load? - assert @root.eager_load.include?(@root["app"].to_a.first) + assert_includes @root.eager_load, @root["app"].to_a.first end end @@ -168,14 +168,14 @@ class PathsTest < ActiveSupport::TestCase @root["app"].skip_eager_load! assert !@root["app"].eager_load? - assert !@root.eager_load.include?(@root["app"].to_a.first) + assert_not_includes @root.eager_load, @root["app"].to_a.first end test "it is possible to add a path without assignment and mark it as eager" do File.stub(:exist?, true) do @root.add "app", with: "/app", eager_load: true assert @root["app"].eager_load? - assert @root.eager_load.include?("/app") + assert_includes @root.eager_load, "/app" end end @@ -183,8 +183,8 @@ class PathsTest < ActiveSupport::TestCase File.stub(:exist?, true) do @root.add "app", with: ["/app", "/app2"], eager_load: true assert @root["app"].eager_load? - assert @root.eager_load.include?("/app") - assert @root.eager_load.include?("/app2") + assert_includes @root.eager_load, "/app" + assert_includes @root.eager_load, "/app2" end end @@ -193,8 +193,8 @@ class PathsTest < ActiveSupport::TestCase @root.add "app", with: "/app", eager_load: true, autoload_once: true assert @root["app"].eager_load? assert @root["app"].autoload_once? - assert @root.eager_load.include?("/app") - assert @root.autoload_once.include?("/app") + assert_includes @root.eager_load, "/app" + assert_includes @root.autoload_once, "/app" end end @@ -203,7 +203,7 @@ class PathsTest < ActiveSupport::TestCase @root["app"] = "/app" @root["app"].eager_load! @root["app"].eager_load! - assert_equal 1, @root.eager_load.select {|p| p == @root["app"].expanded.first }.size + assert_equal 1, @root.eager_load.select { |p| p == @root["app"].expanded.first }.size end end diff --git a/railties/test/rack_logger_test.rb b/railties/test/rack_logger_test.rb index fcc79b57fb..7dd91a2465 100644 --- a/railties/test/rack_logger_test.rb +++ b/railties/test/rack_logger_test.rb @@ -1,8 +1,8 @@ -require 'abstract_unit' -require 'active_support/testing/autorun' -require 'active_support/test_case' -require 'rails/rack/logger' -require 'logger' +require "abstract_unit" +require "active_support/testing/autorun" +require "active_support/test_case" +require "rails/rack/logger" +require "logger" module Rails module Rack @@ -39,7 +39,7 @@ module Rails def setup @subscriber = Subscriber.new @notifier = ActiveSupport::Notifications.notifier - @subscription = notifier.subscribe 'request.action_dispatch', subscriber + @subscription = notifier.subscribe "request.action_dispatch", subscriber end def teardown @@ -47,11 +47,11 @@ module Rails end def test_notification - logger = TestLogger.new { } + logger = TestLogger.new {} - assert_difference('subscriber.starts.length') do - assert_difference('subscriber.finishes.length') do - logger.call('REQUEST_METHOD' => 'GET').last.close + assert_difference("subscriber.starts.length") do + assert_difference("subscriber.finishes.length") do + logger.call("REQUEST_METHOD" => "GET").last.close end end end @@ -62,10 +62,10 @@ module Rails raise NotImplementedError end - assert_difference('subscriber.starts.length') do - assert_difference('subscriber.finishes.length') do + assert_difference("subscriber.starts.length") do + assert_difference("subscriber.finishes.length") do assert_raises(NotImplementedError) do - logger.call 'REQUEST_METHOD' => 'GET' + logger.call "REQUEST_METHOD" => "GET" end end end diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index 2e10d63599..d795629ccd 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" module ActionController class Base @@ -11,8 +11,8 @@ class InfoControllerTest < ActionController::TestCase def setup Rails.application.routes.draw do - get '/rails/info/properties' => "rails/info#properties" - get '/rails/info/routes' => "rails/info#routes" + get "/rails/info/properties" => "rails/info#properties" + get "/rails/info/routes" => "rails/info#routes" end @routes = Rails.application.routes @@ -30,7 +30,7 @@ class InfoControllerTest < ActionController::TestCase test "info controller renders an error message when request was forbidden" do @request.env["REMOTE_ADDR"] = "example.org" get :properties - assert_select 'p' + assert_select "p" end test "info controller allows requests when all requests are considered local" do @@ -45,7 +45,7 @@ class InfoControllerTest < ActionController::TestCase test "info controller renders a table with properties" do get :properties - assert_select 'table' + assert_select "table" end test "info controller renders with routes" do @@ -54,29 +54,29 @@ class InfoControllerTest < ActionController::TestCase end test "info controller returns exact matches" do - exact_count = -> { JSON(response.body)['exact'].size } + exact_count = -> { JSON(response.body)["exact"].size } - get :routes, params: { path: 'rails/info/route' } - assert exact_count.call == 0, 'should not match incomplete routes' + get :routes, params: { path: "rails/info/route" } + assert exact_count.call == 0, "should not match incomplete routes" - get :routes, params: { path: 'rails/info/routes' } - assert exact_count.call == 1, 'should match complete routes' + get :routes, params: { path: "rails/info/routes" } + assert exact_count.call == 1, "should match complete routes" - get :routes, params: { path: 'rails/info/routes.html' } - assert exact_count.call == 1, 'should match complete routes with optional parts' + get :routes, params: { path: "rails/info/routes.html" } + assert exact_count.call == 1, "should match complete routes with optional parts" end test "info controller returns fuzzy matches" do - fuzzy_count = -> { JSON(response.body)['fuzzy'].size } + fuzzy_count = -> { JSON(response.body)["fuzzy"].size } - get :routes, params: { path: 'rails/info' } - assert fuzzy_count.call == 2, 'should match incomplete routes' + get :routes, params: { path: "rails/info" } + assert fuzzy_count.call == 2, "should match incomplete routes" - get :routes, params: { path: 'rails/info/routes' } - assert fuzzy_count.call == 1, 'should match complete routes' + get :routes, params: { path: "rails/info/routes" } + assert fuzzy_count.call == 1, "should match complete routes" - get :routes, params: { path: 'rails/info/routes.html' } - assert fuzzy_count.call == 0, 'should match optional parts of route literally' + get :routes, params: { path: "rails/info/routes.html" } + assert fuzzy_count.call == 0, "should match optional parts of route literally" end test "internal routes do not have a default params[:internal] value" do diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index 92e4af25b5..59e79de41a 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" unless defined?(Rails) && defined?(Rails::Info) module Rails @@ -11,46 +11,46 @@ require "active_support/core_ext/kernel/reporting" class InfoTest < ActiveSupport::TestCase def setup Rails.send :remove_const, :Info - silence_warnings { load 'rails/info.rb' } + silence_warnings { load "rails/info.rb" } end def test_property_with_block_swallows_exceptions_and_ignores_property assert_nothing_raised do Rails::Info.module_eval do - property('Bogus') {raise} + property("Bogus") { raise } end end - assert !property_defined?('Bogus') + assert !property_defined?("Bogus") end def test_property_with_string Rails::Info.module_eval do - property 'Hello', 'World' + property "Hello", "World" end - assert_property 'Hello', 'World' + assert_property "Hello", "World" end def test_property_with_block Rails::Info.module_eval do - property('Goodbye') {'World'} + property("Goodbye") { "World" } end - assert_property 'Goodbye', 'World' + assert_property "Goodbye", "World" end def test_rails_version - assert_property 'Rails version', - File.read(File.realpath('../../../RAILS_VERSION', __FILE__)).chomp + assert_property "Rails version", + File.read(File.realpath("../../../RAILS_VERSION", __FILE__)).chomp end def test_html_includes_middleware Rails::Info.module_eval do - property 'Middleware', ['Rack::Lock', 'Rack::Static'] + property "Middleware", ["Rack::Lock", "Rack::Static"] end html = Rails::Info.to_html - assert html.include?('<tr><td class="name">Middleware</td>') - properties.value_for('Middleware').each do |value| - assert html.include?("<li>#{CGI.escapeHTML(value)}</li>") + assert_includes html, '<tr><td class="name">Middleware</td>' + properties.value_for("Middleware").each do |value| + assert_includes html, "<li>#{CGI.escapeHTML(value)}</li>" end end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index fb8a7656d0..397037a394 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -4,7 +4,6 @@ require "rack/test" module RailtiesTest class EngineTest < ActiveSupport::TestCase - include ActiveSupport::Testing::Isolation include Rack::Test::Methods @@ -28,7 +27,6 @@ module RailtiesTest end def boot_rails - super require "#{app_path}/config/environment" end @@ -37,8 +35,6 @@ module RailtiesTest add_to_env_config "development", "config.assets.digest = false" boot_rails - require 'rack/test' - extend Rack::Test::Methods get "/assets/engine.js" assert_match "alert()", last_response.body @@ -102,7 +98,7 @@ module RailtiesTest assert_no_match(/2_create_users/, output.join("\n")) - bukkits_migration_order = output.index(output.detect{|o| /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/ =~ o }) + bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/ =~ o }) assert_not_nil bukkits_migration_order, "Expected migration to be skipped" migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length @@ -112,7 +108,7 @@ module RailtiesTest end end - test 'respects the order of railties when installing migrations' do + test "respects the order of railties when installing migrations" do @blog = engine "blog" do |plugin| plugin.write "lib/blog.rb", <<-RUBY module Blog @@ -213,11 +209,11 @@ module RailtiesTest test "no rake task without migrations" do boot_rails - require 'rake' - require 'rdoc/task' - require 'rake/testtask' + require "rake" + require "rdoc/task" + require "rake/testtask" Rails.application.load_tasks - assert !Rake::Task.task_defined?('bukkits:install:migrations') + assert !Rake::Task.task_defined?("bukkits:install:migrations") end test "puts its lib directory on load path" do @@ -322,8 +318,6 @@ module RailtiesTest RUBY boot_rails - require 'rack/test' - extend Rack::Test::Methods get "/sprokkit" assert_equal "I am a Sprokkit", last_response.body @@ -333,7 +327,7 @@ module RailtiesTest controller "foo", <<-RUBY class FooController < ActionController::Base def index - render :text => "foo" + render plain: "foo" end end RUBY @@ -347,7 +341,7 @@ module RailtiesTest @plugin.write "app/controllers/bar_controller.rb", <<-RUBY class BarController < ActionController::Base def index - render :text => "bar" + render plain: "bar" end end RUBY @@ -360,14 +354,12 @@ module RailtiesTest RUBY boot_rails - require 'rack/test' - extend Rack::Test::Methods - get '/foo' - assert_equal 'foo', last_response.body + get "/foo" + assert_equal "foo", last_response.body - get '/bar' - assert_equal 'bar', last_response.body + get "/bar" + assert_equal "bar", last_response.body end test "rake tasks lib tasks are loaded" do @@ -379,9 +371,9 @@ module RailtiesTest RUBY boot_rails - require 'rake' - require 'rdoc/task' - require 'rake/testtask' + require "rake" + require "rdoc/task" + require "rake/testtask" Rails.application.load_tasks Rake::Task[:foo].invoke assert $executed @@ -392,18 +384,18 @@ module RailtiesTest config.i18n.load_path << "#{app_path}/app/locales/en.yml" RUBY - app_file 'app/locales/en.yml', <<-YAML + app_file "app/locales/en.yml", <<-YAML en: bar: "1" YAML - app_file 'config/locales/en.yml', <<-YAML + app_file "config/locales/en.yml", <<-YAML en: foo: "2" bar: "2" YAML - @plugin.write 'config/locales/en.yml', <<-YAML + @plugin.write "config/locales/en.yml", <<-YAML en: foo: "3" YAML @@ -444,14 +436,12 @@ YAML @plugin.write "app/controllers/admin/foo/bar_controller.rb", <<-RUBY class Admin::Foo::BarController < ApplicationController def index - render text: "Rendered from namespace" + render plain: "Rendered from namespace" end end RUBY boot_rails - require 'rack/test' - extend Rack::Test::Methods get "/admin/foo/bar" assert_equal 200, last_response.status @@ -546,7 +536,7 @@ YAML controller "foo", <<-RUBY class FooController < ActionController::Base def index - render text: params[:username] + render plain: params[:username] end end RUBY @@ -637,11 +627,11 @@ YAML env = Rack::MockRequest.env_for("/") Bukkits::Engine.call(env) - assert_equal Bukkits::Engine.routes, env['action_dispatch.routes'] + assert_equal Bukkits::Engine.routes, env["action_dispatch.routes"] env = Rack::MockRequest.env_for("/") Rails.application.call(env) - assert_equal Rails.application.routes, env['action_dispatch.routes'] + assert_equal Rails.application.routes, env["action_dispatch.routes"] end test "isolated engine should include only its own routes and helpers" do @@ -710,7 +700,7 @@ YAML end def show - render text: foo_path + render plain: foo_path end def from_app @@ -722,7 +712,7 @@ YAML end def polymorphic_path_without_namespace - render text: polymorphic_path(Post.new) + render plain: polymorphic_path(Post.new) end end RUBY @@ -845,7 +835,7 @@ YAML @plugin.write "app/controllers/bukkits/awesome/foo_controller.rb", <<-RUBY class Bukkits::Awesome::FooController < ActionController::Base def index - render :text => "ok" + render plain: "ok" end end RUBY @@ -1028,7 +1018,7 @@ YAML # check expanding paths engine_dir = @plugin.path.chomp("/").split("/").last - engine_path = File.join(@plugin.path, '..', engine_dir) + engine_path = File.join(@plugin.path, "..", engine_dir) assert_equal Bukkits::Engine.instance, Rails::Engine.find(engine_path) end @@ -1230,13 +1220,12 @@ YAML fullpath: \#{request.fullpath} path: \#{request.path} TEXT - render text: text + render plain: text end end end RUBY - app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do mount Bukkits::Engine => "/" @@ -1268,7 +1257,7 @@ YAML app_file "app/controllers/bar_controller.rb", <<-RUBY class BarController < ApplicationController def index - render text: bukkits.bukkit_path + render plain: bukkits.bukkit_path end end RUBY @@ -1286,22 +1275,21 @@ YAML end RUBY - @plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY class Bukkits::BukkitController < ActionController::Base def index - render text: main_app.bar_path + render plain: main_app.bar_path end end RUBY boot_rails - get("/bukkits/bukkit", {}, {'SCRIPT_NAME' => '/foo'}) - assert_equal '/foo/bar', last_response.body + get("/bukkits/bukkit", {}, "SCRIPT_NAME" => "/foo") + assert_equal "/foo/bar", last_response.body - get("/bar", {}, {'SCRIPT_NAME' => '/foo'}) - assert_equal '/foo/bukkits/bukkit', last_response.body + get("/bar", {}, "SCRIPT_NAME" => "/foo") + assert_equal "/foo/bukkits/bukkit", last_response.body end test "paths are properly generated when application is mounted at sub-path and relative_url_root is set" do @@ -1318,7 +1306,7 @@ YAML app_file "app/controllers/bar_controller.rb", <<-RUBY class BarController < ApplicationController def index - render text: bukkits.bukkit_path + render plain: bukkits.bukkit_path end end RUBY @@ -1339,18 +1327,18 @@ YAML @plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY class Bukkits::BukkitController < ActionController::Base def index - render text: main_app.bar_path + render plain: main_app.bar_path end end RUBY boot_rails - get("/bukkits/bukkit", {}, {'SCRIPT_NAME' => '/foo'}) - assert_equal '/foo/bar', last_response.body + get("/bukkits/bukkit", {}, "SCRIPT_NAME" => "/foo") + assert_equal "/foo/bar", last_response.body - get("/bar", {}, {'SCRIPT_NAME' => '/foo'}) - assert_equal '/foo/bukkits/bukkit', last_response.body + get("/bar", {}, "SCRIPT_NAME" => "/foo") + assert_equal "/foo/bukkits/bukkit", last_response.body end private diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb index b85e16c040..732898d0c0 100644 --- a/railties/test/railties/generators_test.rb +++ b/railties/test/railties/generators_test.rb @@ -1,7 +1,7 @@ RAILS_ISOLATED_ENGINE = true require "isolation/abstract_unit" -require 'generators/generators_test_helper' +require "generators/generators_test_helper" require "rails/generators/test_case" module RailtiesTests @@ -9,7 +9,7 @@ module RailtiesTests include ActiveSupport::Testing::Isolation def destination_root - tmp_path 'foo_bar' + tmp_path "foo_bar" end def tmp_path(*args) @@ -18,7 +18,7 @@ module RailtiesTests end def engine_path - tmp_path('foo_bar') + tmp_path("foo_bar") end def bundled_rails(cmd) @@ -39,7 +39,7 @@ module RailtiesTests Dir.chdir(engine_path) do File.open("Gemfile", "w") do |f| - f.write <<-GEMFILE.gsub(/^ {12}/, '') + f.write <<-GEMFILE.gsub(/^ {12}/, "") source "https://rubygems.org" gem 'rails', path: '#{RAILS_FRAMEWORK_ROOT}' diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index fb2071c7c3..5838d0d7e7 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -1,10 +1,10 @@ -require 'isolation/abstract_unit' +require "isolation/abstract_unit" module ApplicationTests class ApplicationRoutingTest < ActiveSupport::TestCase - require 'rack/test' - include Rack::Test::Methods - include ActiveSupport::Testing::Isolation + require "rack/test" + include Rack::Test::Methods + include ActiveSupport::Testing::Isolation def setup build_app @@ -15,7 +15,7 @@ module ApplicationTests @plugin = engine "blog" @metrics_plugin = engine "metrics" - app_file 'config/routes.rb', <<-RUBY + app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do mount Weblog::Engine, :at => '/', :as => 'weblog' resources :posts @@ -34,7 +34,6 @@ module ApplicationTests end RUBY - @simple_plugin.write "lib/weblog.rb", <<-RUBY module Weblog class Engine < ::Rails::Engine @@ -51,7 +50,7 @@ module ApplicationTests @simple_plugin.write "app/controllers/weblogs_controller.rb", <<-RUBY class WeblogsController < ActionController::Base def index - render text: request.url + render plain: request.url end end RUBY @@ -75,7 +74,7 @@ module ApplicationTests module Metrics class GeneratingController < ActionController::Base def generate_blog_route - render text: blog.post_path(1) + render plain: blog.post_path(1) end def generate_blog_route_in_view @@ -123,14 +122,14 @@ module ApplicationTests module Blog class PostsController < ActionController::Base def index - render text: blog.post_path(1) + render plain: blog.post_path(1) end def generate_application_route path = main_app.url_for(controller: "/main", action: "index", only_path: true) - render text: path + render plain: path end def application_route_in_view @@ -138,7 +137,7 @@ module ApplicationTests end def engine_polymorphic_path - render text: polymorphic_path(Post.new) + render plain: polymorphic_path(Post.new) end def engine_asset_path @@ -151,7 +150,7 @@ module ApplicationTests app_file "app/controllers/application_generating_controller.rb", <<-RUBY class ApplicationGeneratingController < ActionController::Base def engine_route - render text: blog.posts_path + render plain: blog.posts_path end def engine_route_in_view @@ -159,7 +158,7 @@ module ApplicationTests end def weblog_engine_route - render text: weblog.weblogs_path + render plain: weblog.weblogs_path end def weblog_engine_route_in_view @@ -167,20 +166,18 @@ module ApplicationTests end def url_for_engine_route - render text: blog.url_for(controller: "blog/posts", action: "index", user: "john", only_path: true) + render plain: blog.url_for(controller: "blog/posts", action: "index", user: "john", only_path: true) end def polymorphic_route - render text: polymorphic_url([blog, Blog::Post.new]) + render plain: polymorphic_url([blog, Blog::Post.new]) end def application_polymorphic_path - render text: polymorphic_path(Blog::Post.new) + render plain: polymorphic_path(Blog::Post.new) end end RUBY - - boot_rails end def teardown @@ -200,7 +197,7 @@ module ApplicationTests assert_equal "/john/blog/posts/1", last_response.body # test generating engine's route from engine with default_url_options - get "/john/blog/posts", {}, 'SCRIPT_NAME' => "/foo" + get "/john/blog/posts", {}, "SCRIPT_NAME" => "/foo" assert_equal "/foo/john/blog/posts/1", last_response.body # test generating engine's route from application @@ -214,10 +211,10 @@ module ApplicationTests assert_equal "/john/blog/posts", last_response.body # test generating engine's route from application with default_url_options - get "/engine_route", {}, 'SCRIPT_NAME' => "/foo" + get "/engine_route", {}, "SCRIPT_NAME" => "/foo" assert_equal "/foo/anonymous/blog/posts", last_response.body - get "/url_for_engine_route", {}, 'SCRIPT_NAME' => "/foo" + get "/url_for_engine_route", {}, "SCRIPT_NAME" => "/foo" assert_equal "/foo/john/blog/posts", last_response.body # test generating application's route from engine @@ -229,21 +226,20 @@ module ApplicationTests # test generating engine's route from other engine get "/metrics/generate_blog_route" - assert_equal '/anonymous/blog/posts/1', last_response.body + assert_equal "/anonymous/blog/posts/1", last_response.body get "/metrics/generate_blog_route_in_view" - assert_equal '/anonymous/blog/posts/1', last_response.body + assert_equal "/anonymous/blog/posts/1", last_response.body # test generating engine's route from other engine with default_url_options - get "/metrics/generate_blog_route", {}, 'SCRIPT_NAME' => '/foo' - assert_equal '/foo/anonymous/blog/posts/1', last_response.body - - get "/metrics/generate_blog_route_in_view", {}, 'SCRIPT_NAME' => '/foo' - assert_equal '/foo/anonymous/blog/posts/1', last_response.body + get "/metrics/generate_blog_route", {}, "SCRIPT_NAME" => "/foo" + assert_equal "/foo/anonymous/blog/posts/1", last_response.body + get "/metrics/generate_blog_route_in_view", {}, "SCRIPT_NAME" => "/foo" + assert_equal "/foo/anonymous/blog/posts/1", last_response.body # test generating application's route from engine with default_url_options - get "/someone/blog/generate_application_route", {}, 'SCRIPT_NAME' => '/foo' + get "/someone/blog/generate_application_route", {}, "SCRIPT_NAME" => "/foo" assert_equal "/foo/", last_response.body # test polymorphic routes diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 5042d628cf..30cd525266 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -6,7 +6,6 @@ module RailtiesTest def setup build_app - boot_rails FileUtils.rm_rf("#{app_path}/config/environments") require "rails/all" end @@ -80,6 +79,13 @@ module RailtiesTest assert_equal app_path, $before_configuration end + test "before_configuration callbacks run as soon as the application constant inherits from Rails::Application" do + $before_configuration = false + class Foo < Rails::Railtie ; config.before_configuration { $before_configuration = true } ; end + class Application < Rails::Application ; end + assert $before_configuration + end + test "railtie can add after_initialize callbacks" do $after_initialize = false class Foo < Rails::Railtie ; config.after_initialize { $after_initialize = true } ; end @@ -100,9 +106,9 @@ module RailtiesTest require "#{app_path}/config/environment" assert !$ran_block - require 'rake' - require 'rake/testtask' - require 'rdoc/task' + require "rake" + require "rake/testtask" + require "rdoc/task" Rails.application.load_tasks assert $ran_block @@ -124,12 +130,12 @@ module RailtiesTest require "#{app_path}/config/environment" assert_equal [], $ran_block - require 'rake' - require 'rake/testtask' - require 'rdoc/task' + require "rake" + require "rake/testtask" + require "rdoc/task" Rails.application.load_tasks - assert $ran_block.include?("my_tie") + assert_includes $ran_block, "my_tie" end test "generators block is executed when MyApp.load_generators is called" do @@ -197,8 +203,8 @@ module RailtiesTest test "we can change our environment if we want to" do begin original_env = Rails.env - Rails.env = 'foo' - assert_equal('foo', Rails.env) + Rails.env = "foo" + assert_equal("foo", Rails.env) ensure Rails.env = original_env assert_equal(original_env, Rails.env) diff --git a/railties/test/test_unit/reporter_test.rb b/railties/test/test_unit/reporter_test.rb index 0d64b48550..e22c939981 100644 --- a/railties/test/test_unit/reporter_test.rb +++ b/railties/test/test_unit/reporter_test.rb @@ -1,6 +1,6 @@ -require 'abstract_unit' -require 'rails/test_unit/reporter' -require 'minitest/mock' +require "abstract_unit" +require "rails/test_unit/reporter" +require "minitest/mock" class TestUnitReporterTest < ActiveSupport::TestCase class ExampleTest < Minitest::Test @@ -33,7 +33,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase @reporter.record(passing_test) @reporter.record(skipped_test) @reporter.report - assert_no_match 'Failed tests:', @output.string + assert_no_match "Failed tests:", @output.string assert_rerun_snippet_count 0 end @@ -87,7 +87,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase @reporter.record(failed_test) @reporter.report - assert_no_match 'Failed tests:', @output.string + assert_no_match "Failed tests:", @output.string end test "fail fast interrupts run on failure" do @@ -100,7 +100,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase rescue Interrupt interrupt_raised = true ensure - assert interrupt_raised, 'Expected Interrupt to be raised.' + assert interrupt_raised, "Expected Interrupt to be raised." end end @@ -114,7 +114,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase rescue Interrupt interrupt_raised = true ensure - assert interrupt_raised, 'Expected Interrupt to be raised.' + assert interrupt_raised, "Expected Interrupt to be raised." end end @@ -122,7 +122,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase fail_fast = Rails::TestUnitReporter.new @output, fail_fast: true fail_fast.record(skipped_test) - assert_no_match 'Failed tests:', @output.string + assert_no_match "Failed tests:", @output.string end test "outputs colored passing results" do @@ -156,38 +156,38 @@ class TestUnitReporterTest < ActiveSupport::TestCase end private - def assert_rerun_snippet_count(snippet_count) - assert_equal snippet_count, @output.string.scan(%r{^bin/rails test }).size - end + def assert_rerun_snippet_count(snippet_count) + assert_equal snippet_count, @output.string.scan(%r{^bin/rails test }).size + end - def failed_test - ft = ExampleTest.new(:woot) - ft.failures << begin - raise Minitest::Assertion, "boo" - rescue Minitest::Assertion => e - e - end - ft - end + def failed_test + ft = ExampleTest.new(:woot) + ft.failures << begin + raise Minitest::Assertion, "boo" + rescue Minitest::Assertion => e + e + end + ft + end - def errored_test - et = ExampleTest.new(:woot) - et.failures << Minitest::UnexpectedError.new(ArgumentError.new("wups")) - et - end + def errored_test + et = ExampleTest.new(:woot) + et.failures << Minitest::UnexpectedError.new(ArgumentError.new("wups")) + et + end - def passing_test - ExampleTest.new(:woot) - end + def passing_test + ExampleTest.new(:woot) + end - def skipped_test - st = ExampleTest.new(:woot) - st.failures << begin - raise Minitest::Skip, "skipchurches, misstemples" - rescue Minitest::Assertion => e - e - end - st.time = 10 - st - end + def skipped_test + st = ExampleTest.new(:woot) + st.failures << begin + raise Minitest::Skip, "skipchurches, misstemples" + rescue Minitest::Assertion => e + e + end + st.time = 10 + st + end end diff --git a/railties/test/version_test.rb b/railties/test/version_test.rb index f270d8f0c9..86a482e091 100644 --- a/railties/test/version_test.rb +++ b/railties/test/version_test.rb @@ -1,4 +1,4 @@ -require 'abstract_unit' +require "abstract_unit" class VersionTest < ActiveSupport::TestCase def test_rails_version_returns_a_string diff --git a/tasks/release.rb b/tasks/release.rb index 4a1ed04478..d1717cec52 100644 --- a/tasks/release.rb +++ b/tasks/release.rb @@ -1,12 +1,12 @@ FRAMEWORKS = %w( activesupport activemodel activerecord actionview actionpack activejob actionmailer actioncable railties ) -root = File.expand_path('../../', __FILE__) +root = File.expand_path("../../", __FILE__) version = File.read("#{root}/RAILS_VERSION").strip tag = "v#{version}" directory "pkg" -(FRAMEWORKS + ['rails']).each do |framework| +(FRAMEWORKS + ["rails"]).each do |framework| namespace framework do gem = "pkg/#{framework}-#{version}.gem" gemspec = "#{framework}.gemspec" @@ -27,7 +27,7 @@ directory "pkg" file = Dir[glob].first ruby = File.read(file) - major, minor, tiny, pre = version.split('.', 4) + major, minor, tiny, pre = version.split(".", 4) pre = pre ? pre.inspect : "nil" ruby.gsub!(/^(\s*)MAJOR(\s*)= .*?$/, "\\1MAJOR = #{major}") @@ -42,8 +42,29 @@ directory "pkg" ruby.gsub!(/^(\s*)PRE(\s*)= .*?$/, "\\1PRE = #{pre}") raise "Could not insert PRE in #{file}" unless $1 - File.open(file, 'w') { |f| f.write ruby } + File.open(file, "w") { |f| f.write ruby } + end + + task gem => %w(update_versions pkg) do + cmd = "" + cmd << "cd #{framework} && " unless framework == "rails" + cmd << "bundle exec rake package && " unless framework == "rails" + cmd << "gem build #{gemspec} && mv #{framework}-#{version}.gem #{root}/pkg/" + sh cmd + end + + task build: [:clean, gem] + task install: :build do + sh "gem install --pre #{gem}" + end + + task push: :build do + sh "gem push #{gem}" + # When running the release task we usually run build first to check that the gem works properly. + # NPM will refuse to publish or rebuild the gem if the version is changed when the Rails gem + # versions are changed. This then causes the gem push to fail. Because of this we need to update + # the version and publish at the same time. if File.exist?("#{framework}/package.json") Dir.chdir("#{framework}") do # This "npm-ifies" the current version @@ -63,65 +84,48 @@ directory "pkg" # => "5.0.0.rc1" # irb(main):004:0> version.gsub(/\./).with_index { |s, i| i >= 2 ? '-' : s } # => "5.0.0-rc1" - version = version.gsub(/\./).with_index { |s, i| i >= 2 ? '-' : s } + version = version.gsub(/\./).with_index { |s, i| i >= 2 ? "-" : s } # Check if npm is installed, and raise an error if not - if sh 'which npm' + if sh "which npm" sh "npm version #{version} --no-git-tag-version" + sh "npm publish" else - raise 'You must have npm installed to release Rails.' + raise "You must have npm installed to release Rails." end end end end - - task gem => %w(update_versions pkg) do - cmd = "" - cmd << "cd #{framework} && " unless framework == "rails" - cmd << "bundle exec rake package && " unless framework == "rails" - cmd << "gem build #{gemspec} && mv #{framework}-#{version}.gem #{root}/pkg/" - sh cmd - end - - task :build => [:clean, gem] - task :install => :build do - sh "gem install --pre #{gem}" - end - - task :push => :build do - sh "gem push #{gem}" - sh "npm publish" if File.exist?("#{framework}/package.json") - end end end namespace :changelog do task :header do - (FRAMEWORKS + ['guides']).each do |fw| - require 'date' - fname = File.join fw, 'CHANGELOG.md' + (FRAMEWORKS + ["guides"]).each do |fw| + require "date" + fname = File.join fw, "CHANGELOG.md" header = "## Rails #{version} (#{Date.today.strftime('%B %d, %Y')}) ##\n\n* No changes.\n\n\n" contents = header + File.read(fname) - File.open(fname, 'wb') { |f| f.write contents } + File.open(fname, "wb") { |f| f.write contents } end end task :release_date do - (FRAMEWORKS + ['guides']).each do |fw| - require 'date' + (FRAMEWORKS + ["guides"]).each do |fw| + require "date" replace = "## Rails #{version} (#{Date.today.strftime('%B %d, %Y')}) ##\n" - fname = File.join fw, 'CHANGELOG.md' + fname = File.join fw, "CHANGELOG.md" contents = File.read(fname).sub(/^(## Rails .*)\n/, replace) - File.open(fname, 'wb') { |f| f.write contents } + File.open(fname, "wb") { |f| f.write contents } end end task :release_summary do - (FRAMEWORKS + ['guides']).each do |fw| + (FRAMEWORKS + ["guides"]).each do |fw| puts "## #{fw}" - fname = File.join fw, 'CHANGELOG.md' + fname = File.join fw, "CHANGELOG.md" contents = File.readlines fname contents.shift changes = [] @@ -133,28 +137,28 @@ namespace :changelog do end namespace :all do - task :build => FRAMEWORKS.map { |f| "#{f}:build" } + ['rails:build'] - task :update_versions => FRAMEWORKS.map { |f| "#{f}:update_versions" } + ['rails:update_versions'] - task :install => FRAMEWORKS.map { |f| "#{f}:install" } + ['rails:install'] - task :push => FRAMEWORKS.map { |f| "#{f}:push" } + ['rails:push'] + task build: FRAMEWORKS.map { |f| "#{f}:build" } + ["rails:build"] + task update_versions: FRAMEWORKS.map { |f| "#{f}:update_versions" } + ["rails:update_versions"] + task install: FRAMEWORKS.map { |f| "#{f}:install" } + ["rails:install"] + task push: FRAMEWORKS.map { |f| "#{f}:push" } + ["rails:push"] task :ensure_clean_state do unless `git status -s | grep -v 'RAILS_VERSION\\|CHANGELOG\\|Gemfile.lock'`.strip.empty? abort "[ABORTING] `git status` reports a dirty tree. Make sure all changes are committed" end - unless ENV['SKIP_TAG'] || `git tag | grep '^#{tag}$'`.strip.empty? + unless ENV["SKIP_TAG"] || `git tag | grep '^#{tag}$'`.strip.empty? abort "[ABORTING] `git tag` shows that #{tag} already exists. Has this version already\n"\ " been released? Git tagging can be skipped by setting SKIP_TAG=1" end end task :bundle do - sh 'bundle check' + sh "bundle check" end task :commit do - File.open('pkg/commit_message.txt', 'w') do |f| + File.open("pkg/commit_message.txt", "w") do |f| f.puts "# Preparing for #{version} release\n" f.puts f.puts "# UNCOMMENT THE LINE ABOVE TO APPROVE THIS COMMIT" @@ -169,7 +173,7 @@ namespace :all do sh "git push --tags" end - task :prep_release => %w(ensure_clean_state build) + task prep_release: %w(ensure_clean_state build) - task :release => %w(ensure_clean_state build bundle commit tag push) + task release: %w(ensure_clean_state build bundle commit tag push) end diff --git a/tools/console b/tools/console index 98a848ff6b..58c76fb1b6 100755 --- a/tools/console +++ b/tools/console @@ -1,9 +1,9 @@ #!/usr/bin/env ruby -require 'bundler' +require "bundler" Bundler.setup -require 'rails/all' -require 'active_support/all' -require 'irb' -require 'irb/completion' +require "rails/all" +require "active_support/all" +require "irb" +require "irb/completion" IRB.start diff --git a/tools/profile b/tools/profile index 191e73b3dd..f7d91e51cf 100755 --- a/tools/profile +++ b/tools/profile @@ -4,8 +4,8 @@ # # Example: # tools/profile activesupport/lib/active_support.rb [ruby-prof mode] [ruby-prof printer] -ENV['NO_RELOAD'] ||= '1' -ENV['RAILS_ENV'] ||= 'development' +ENV["NO_RELOAD"] ||= "1" +ENV["RAILS_ENV"] ||= "development" module CodeTools class Profiler @@ -15,7 +15,7 @@ module CodeTools def initialize(path, mode=nil) assert_ruby_file_exists(path) @path, @mode = path, mode - require 'benchmark' + require "benchmark" end def profile_requires @@ -23,7 +23,7 @@ module CodeTools before_rss = `ps -o rss= -p #{Process.pid}`.to_i if mode - require 'ruby-prof' + require "ruby-prof" RubyProf.measure_mode = RubyProf.const_get(mode.upcase) RubyProf.start else @@ -43,13 +43,13 @@ module CodeTools elsif RubyProf.const_defined?(:CallStackPrinter) filename = "#{File.basename(path, '.rb')}.#{mode}.html" puts "RubyProf outputting to #{filename}" - File.open(filename, 'w') do |out| + File.open(filename, "w") do |out| RubyProf::CallStackPrinter.new(results).print(out) end else filename = "#{File.basename(path, '.rb')}.#{mode}.callgrind" puts "RubyProf outputting to #{filename}" - File.open(filename, 'w') do |out| + File.open(filename, "w") do |out| RubyProf::CallTreePrinter.new(results).print(out) end end @@ -57,7 +57,7 @@ module CodeTools RequireProfiler.stats.each do |file, depth, sec| if sec - puts "%8.1f ms %s%s" % [sec * 1000, ' ' * depth, file] + puts "%8.1f ms %s%s" % [sec * 1000, " " * depth, file] else puts "#{' ' * (13 + depth)}#{file}" end @@ -67,51 +67,51 @@ module CodeTools private - def assert_ruby_file_exists(path) - fail Error.new("No such file") unless File.exist?(path) - fail Error.new("#{path} is a directory") if File.directory?(path) - ruby_extension = File.extname(path) == '.rb' - ruby_executable = File.open(path, 'rb') {|f| f.readline } =~ [/\A#!.*ruby/] - fail Error.new("Not a ruby file") unless ruby_extension or ruby_executable - end + def assert_ruby_file_exists(path) + fail Error.new("No such file") unless File.exist?(path) + fail Error.new("#{path} is a directory") if File.directory?(path) + ruby_extension = File.extname(path) == ".rb" + ruby_executable = File.open(path, "rb") { |f| f.readline } =~ [/\A#!.*ruby/] + fail Error.new("Not a ruby file") unless ruby_extension || ruby_executable + end - module RequireProfiler - private - def require(file, *args) RequireProfiler.profile(file) { super } end - def load(file, *args) RequireProfiler.profile(file) { super } end + module RequireProfiler + private + def require(file, *args) RequireProfiler.profile(file) { super } end + def load(file, *args) RequireProfiler.profile(file) { super } end - @depth, @stats = 0, [] - class << self - attr_accessor :depth - attr_accessor :stats + @depth, @stats = 0, [] + class << self + attr_accessor :depth + attr_accessor :stats - def profile(file) - stats << [file, depth] - self.depth += 1 - result = nil - elapsed = Benchmark.realtime { result = yield } - self.depth -= 1 - stats.pop if stats.last.first == file - stats << [file, depth, elapsed] if result - result - end + def profile(file) + stats << [file, depth] + self.depth += 1 + result = nil + elapsed = Benchmark.realtime { result = yield } + self.depth -= 1 + stats.pop if stats.last.first == file + stats << [file, depth, elapsed] if result + result + end + end end - end end end # ruby-prof printer name causes the third arg to be sent :classify # which is probably overkill if you already know the name of the ruby-prof # printer you want to use, e.g. Graph begin - require 'active_support/inflector' - require 'active_support/core_ext/string/inflections' + require "active_support/inflector" + require "active_support/core_ext/string/inflections" rescue LoadError STDERR.puts $!.message class String # File activesupport/lib/active_support/inflector/methods.rb, line 150 def classify # strip out any leading schema name - camelize(self.sub(/.*\./, '')) + camelize(sub(/.*\./, "")) end # File activesupport/lib/active_support/inflector/methods.rb, line 68 def camelize(uppercase_first_letter = true) @@ -121,7 +121,7 @@ rescue LoadError else string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase } end - string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::') + string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub("/", "::") end end end diff --git a/tools/test.rb b/tools/test.rb index 62e0faa3db..7819c13ee2 100644 --- a/tools/test.rb +++ b/tools/test.rb @@ -1,6 +1,6 @@ $: << File.expand_path("test", COMPONENT_ROOT) -require 'bundler' +require "bundler" Bundler.setup require "rails/test_unit/minitest_plugin" |