Skip to content

Commit

Permalink
Fix compatibility with Ruby 1.9.3 and 2.0.0
Browse files Browse the repository at this point in the history
The named arguments syntax used for the Rails 5 `digest` method is only
valid on Ruby 2.1 or higher (or 2.0.0 if default values are supplied),
causing an error parsing the lib/rabl/digestor.rb source on these
older versions.

    SyntaxError: rabl-0.13.0/lib/rabl/digestor.rb:6: syntax error, unexpected ','
          def self.digest(name:, finder:, **options)

The support for different Rails versions has been moved into separate
files that can be loaded only when required.
  • Loading branch information
domcleal committed Jul 15, 2016
1 parent 7b23258 commit 130d422
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -5,7 +5,7 @@ rvm:
- 1.9.3
- 2.0.0
- 2.1
- 2.2
- 2.2.5
- 2.3.1
notifications:
recipients:
Expand Down
3 changes: 2 additions & 1 deletion Gemfile
Expand Up @@ -14,9 +14,10 @@ group :test do
# RABL TEST
gem 'builder'

rails_version = RUBY_VERSION =~ /\A(1|2.[01])/ ? '~> 4.0' : '>= 4.0'
# FIXTURES
gem 'rack-test', :require => 'rack/test'
gem 'activerecord', :require => 'active_record'
gem 'activerecord', rails_version, :require => 'active_record'
gem 'sqlite3'
gem 'sinatra', '>= 1.2.0'
gem 'hashie'
Expand Down
40 changes: 3 additions & 37 deletions lib/rabl/digestor.rb
Expand Up @@ -3,45 +3,11 @@ class Digestor < ActionView::Digestor
# Override the original digest function to ignore partial which
# rabl doesn't use the Rails conventional _ symbol.
if Gem::Version.new(Rails.version) >= Gem::Version.new('5.0.0.beta1')
def self.digest(name:, finder:, **options)

options.assert_valid_keys(:dependencies, :partial)

cache_key = ([ name ].compact + Array.wrap(options[:dependencies])).join('.')

# this is a correctly done double-checked locking idiom
# (Concurrent::Map's lookups have volatile semantics)
finder.digest_cache[cache_key] || @@digest_monitor.synchronize do
finder.digest_cache.fetch(cache_key) do # re-check under lock
begin
# Prevent re-entry or else recursive templates will blow the stack.
# There is no need to worry about other threads seeing the +false+ value,
# as they will then have to wait for this thread to let go of the @@digest_monitor lock.

pre_stored = finder.digest_cache.put_if_absent(cache_key, false).nil? # put_if_absent returns nil on insertion

finder.digest_cache[cache_key] = stored_digest = Digestor.new(name, finder, options).digest
ensure
# something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
finder.digest_cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
end
end
end
end
require 'rabl/digestor/rails5'
elsif Gem::Version.new(Rails.version) >= Gem::Version.new('4.1')
def self.digest(options = {})
cache_key = [options[:name]] + Array.wrap(options[:dependencies])
@@cache[cache_key.join('.')] ||= begin
Digestor.new({ :name => options[:name], :finder => options[:finder] }.merge!(options)).digest
end
end
require 'rabl/digestor/rails41'
else
def self.digest(name, format, finder, options = {})
cache_key = [name, format] + Array.wrap(options[:dependencies])
@@cache[cache_key.join('.')] ||= begin
Digestor.new(name, format, finder, options).digest
end
end
require 'rabl/digestor/rails3'
end

private
Expand Down
10 changes: 10 additions & 0 deletions lib/rabl/digestor/rails3.rb
@@ -0,0 +1,10 @@
module Rabl
class Digestor < ActionView::Digestor
def self.digest(name, format, finder, options = {})
cache_key = [name, format] + Array.wrap(options[:dependencies])
@@cache[cache_key.join('.')] ||= begin
Digestor.new(name, format, finder, options).digest
end
end
end
end
10 changes: 10 additions & 0 deletions lib/rabl/digestor/rails41.rb
@@ -0,0 +1,10 @@
module Rabl
class Digestor < ActionView::Digestor
def self.digest(options = {})
cache_key = [options[:name]] + Array.wrap(options[:dependencies])
@@cache[cache_key.join('.')] ||= begin
Digestor.new({ :name => options[:name], :finder => options[:finder] }.merge!(options)).digest
end
end
end
end
29 changes: 29 additions & 0 deletions lib/rabl/digestor/rails5.rb
@@ -0,0 +1,29 @@
module Rabl
class Digestor < ActionView::Digestor
def self.digest(name:, finder:, **options)

options.assert_valid_keys(:dependencies, :partial)

cache_key = ([ name ].compact + Array.wrap(options[:dependencies])).join('.')

# this is a correctly done double-checked locking idiom
# (Concurrent::Map's lookups have volatile semantics)
finder.digest_cache[cache_key] || @@digest_monitor.synchronize do
finder.digest_cache.fetch(cache_key) do # re-check under lock
begin
# Prevent re-entry or else recursive templates will blow the stack.
# There is no need to worry about other threads seeing the +false+ value,
# as they will then have to wait for this thread to let go of the @@digest_monitor lock.

pre_stored = finder.digest_cache.put_if_absent(cache_key, false).nil? # put_if_absent returns nil on insertion

finder.digest_cache[cache_key] = stored_digest = Digestor.new(name, finder, options).digest
ensure
# something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
finder.digest_cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
end
end
end
end
end
end

0 comments on commit 130d422

Please sign in to comment.