-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prefer methods over instance variables #1166
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,16 +42,16 @@ class << self | |
end | ||
|
||
def self.inherited(base) | ||
base._attributes = self._attributes.try(:dup) || [] | ||
base._attributes_keys = self._attributes_keys.try(:dup) || {} | ||
base._attributes = _attributes.try(:dup) || [] | ||
base._attributes_keys = _attributes_keys.try(:dup) || {} | ||
base._cache_digest = digest_caller_file(caller.first) | ||
super | ||
end | ||
|
||
def self.attributes(*attrs) | ||
attrs = attrs.first if attrs.first.class == Array | ||
@_attributes.concat attrs | ||
@_attributes.uniq! | ||
_attributes.concat(attrs) | ||
_attributes.uniq! | ||
|
||
attrs.each do |attr| | ||
define_method attr do | ||
|
@@ -62,8 +62,8 @@ def self.attributes(*attrs) | |
|
||
def self.attribute(attr, options = {}) | ||
key = options.fetch(:key, attr) | ||
@_attributes_keys[attr] = { key: key } if key != attr | ||
@_attributes << key unless @_attributes.include?(key) | ||
self._attributes_keys[attr] = { key: key } if key != attr | ||
self._attributes << key unless _attributes.include?(key) | ||
|
||
ActiveModelSerializers.silence_warnings do | ||
define_method key do | ||
|
@@ -73,16 +73,16 @@ def self.attribute(attr, options = {}) | |
end | ||
|
||
def self.fragmented(serializer) | ||
@_fragmented = serializer | ||
self._fragmented = serializer | ||
end | ||
|
||
# Enables a serializer to be automatically cached | ||
def self.cache(options = {}) | ||
@_cache = ActionController::Base.cache_store if Rails.configuration.action_controller.perform_caching | ||
@_cache_key = options.delete(:key) | ||
@_cache_only = options.delete(:only) | ||
@_cache_except = options.delete(:except) | ||
@_cache_options = (options.empty?) ? nil : options | ||
self._cache = ActionController::Base.cache_store if Rails.configuration.action_controller.perform_caching | ||
self._cache_key = options.delete(:key) | ||
self._cache_only = options.delete(:only) | ||
self._cache_except = options.delete(:except) | ||
self._cache_options = (options.empty?) ? nil : options | ||
end | ||
|
||
def self.serializer_for(resource, options = {}) | ||
|
@@ -91,7 +91,7 @@ def self.serializer_for(resource, options = {}) | |
elsif resource.respond_to?(:to_ary) | ||
config.array_serializer | ||
else | ||
options.fetch(:serializer, get_serializer_for(resource.class)) | ||
options.fetch(:serializer) { get_serializer_for(resource.class) } | ||
end | ||
end | ||
|
||
|
@@ -104,17 +104,40 @@ def self.root_name | |
name.demodulize.underscore.sub(/_serializer$/, '') if name | ||
end | ||
|
||
def self.serializers_cache | ||
@serializers_cache ||= ThreadSafe::Cache.new | ||
end | ||
|
||
def self.digest_caller_file(caller_line) | ||
serializer_file_path = caller_line[CALLER_FILE] | ||
serializer_file_contents = IO.read(serializer_file_path) | ||
Digest::MD5.hexdigest(serializer_file_contents) | ||
end | ||
|
||
def self.get_serializer_for(klass) | ||
serializers_cache.fetch_or_store(klass) do | ||
serializer_class_name = "#{klass.name}Serializer" | ||
serializer_class = serializer_class_name.safe_constantize | ||
|
||
if serializer_class | ||
serializer_class | ||
elsif klass.superclass | ||
get_serializer_for(klass.superclass) | ||
end | ||
end | ||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not required from PR, just grouped the class methods together |
||
attr_accessor :object, :root, :meta, :meta_key, :scope | ||
|
||
def initialize(object, options = {}) | ||
@object = object | ||
@options = options | ||
@root = options[:root] | ||
@meta = options[:meta] | ||
@meta_key = options[:meta_key] | ||
@scope = options[:scope] | ||
|
||
scope_name = options[:scope_name] | ||
self.object = object | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean by that. see my answer #1166 (comment) |
||
self.instance_options = options | ||
self.root = instance_options[:root] | ||
self.meta = instance_options[:meta] | ||
self.meta_key = instance_options[:meta_key] | ||
self.scope = instance_options[:scope] | ||
|
||
scope_name = instance_options[:scope_name] | ||
if scope_name && !respond_to?(scope_name) | ||
self.class.class_eval do | ||
define_method scope_name, lambda { scope } | ||
|
@@ -123,7 +146,7 @@ def initialize(object, options = {}) | |
end | ||
|
||
def json_key | ||
@root || object.class.model_name.to_s.underscore | ||
root || object.class.model_name.to_s.underscore | ||
end | ||
|
||
def attributes(options = {}) | ||
|
@@ -143,29 +166,10 @@ def attributes(options = {}) | |
end | ||
end | ||
|
||
def self.serializers_cache | ||
@serializers_cache ||= ThreadSafe::Cache.new | ||
end | ||
|
||
def self.digest_caller_file(caller_line) | ||
serializer_file_path = caller_line[CALLER_FILE] | ||
serializer_file_contents = IO.read(serializer_file_path) | ||
Digest::MD5.hexdigest(serializer_file_contents) | ||
end | ||
|
||
attr_reader :options | ||
private # rubocop:disable Lint/UselessAccessModifier | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤷 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is how class method are supposed to be declared private: http://stackoverflow.com/a/4953043/356849 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not a class method :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh I guess I'm a smidge dysfunctional in the morning. ha why the rubocop error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you could get rid of private? looks like there are no methods under the private There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And yet ActiveModelSerializers.silence_warnings do
attr_accessor :instance_options
end which is, I think, why rubocop thinks it's an unnecessary private |
||
|
||
def self.get_serializer_for(klass) | ||
serializers_cache.fetch_or_store(klass) do | ||
serializer_class_name = "#{klass.name}Serializer" | ||
serializer_class = serializer_class_name.safe_constantize | ||
|
||
if serializer_class | ||
serializer_class | ||
elsif klass.superclass | ||
get_serializer_for(klass.superclass) | ||
end | ||
end | ||
ActiveModelSerializers.silence_warnings do | ||
attr_accessor :instance_options | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ class Adapter | |
autoload :JsonApi | ||
autoload :Null | ||
autoload :FlattenJson | ||
autoload :CachedSerializer | ||
|
||
def self.create(resource, options = {}) | ||
override = options.delete(:adapter) | ||
|
@@ -80,11 +81,11 @@ def self.inherited(subclass) | |
ActiveModel::Serializer::Adapter.register(subclass.to_s.demodulize, subclass) | ||
end | ||
|
||
attr_reader :serializer | ||
attr_reader :serializer, :instance_options | ||
|
||
def initialize(serializer, options = {}) | ||
@serializer = serializer | ||
@options = options | ||
@instance_options = options | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's no accessor here, just a reader.. |
||
end | ||
|
||
def serializable_hash(options = nil) | ||
|
@@ -101,43 +102,12 @@ def fragment_cache(*args) | |
raise NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.' | ||
end | ||
|
||
private | ||
|
||
def cache_check(serializer) | ||
@cached_serializer = serializer | ||
@klass = @cached_serializer.class | ||
if is_cached? | ||
@klass._cache.fetch(cache_key, @klass._cache_options) do | ||
yield | ||
end | ||
elsif is_fragment_cached? | ||
FragmentCache.new(self, @cached_serializer, @options).fetch | ||
else | ||
CachedSerializer.new(serializer).cache_check(self) do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extraction of latent class not required for PR. All the other methods are essentially private methods in the service of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice |
||
yield | ||
end | ||
end | ||
|
||
def is_cached? | ||
@klass._cache && !@klass._cache_only && !@klass._cache_except | ||
end | ||
|
||
def is_fragment_cached? | ||
@klass._cache_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except | ||
end | ||
|
||
def cache_key | ||
parts = [] | ||
parts << object_cache_key | ||
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest] | ||
parts.join('/') | ||
end | ||
|
||
def object_cache_key | ||
object_time_safe = @cached_serializer.object.updated_at | ||
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime) | ||
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key | ||
end | ||
|
||
def meta | ||
serializer.meta if serializer.respond_to?(:meta) | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
module ActiveModel | ||
class Serializer | ||
class Adapter | ||
class CachedSerializer | ||
def initialize(serializer) | ||
@cached_serializer = serializer | ||
@klass = @cached_serializer.class | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. retained ivars from adapter for ease of 1to1 review of extraction |
||
|
||
def cache_check(adapter_instance) | ||
if cached? | ||
@klass._cache.fetch(cache_key, @klass._cache_options) do | ||
yield | ||
end | ||
elsif fragment_cached? | ||
FragmentCache.new(adapter_instance, @cached_serializer, adapter_instance.instance_options).fetch | ||
else | ||
yield | ||
end | ||
end | ||
|
||
def cached? | ||
@klass._cache && !@klass._cache_only && !@klass._cache_except | ||
end | ||
|
||
def fragment_cached? | ||
@klass._cache_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except | ||
end | ||
|
||
def cache_key | ||
parts = [] | ||
parts << object_cache_key | ||
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest] | ||
parts.join('/') | ||
end | ||
|
||
def object_cache_key | ||
object_time_safe = @cached_serializer.object.updated_at | ||
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime) | ||
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key | ||
end | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required for PR, just lazy evals the method when the fetch fails