From 9c1a9e18c4a7434ffd4b16bade2c54136d87e382 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Sun, 2 Jul 2017 21:43:15 -0500 Subject: [PATCH] Extract DSL methods (meta programming help) --- lib/ams/dsl_support.rb | 29 ++++++++++++++++++++++++++ lib/ams/serializer.rb | 47 ++++++++++++------------------------------ 2 files changed, 42 insertions(+), 34 deletions(-) create mode 100644 lib/ams/dsl_support.rb diff --git a/lib/ams/dsl_support.rb b/lib/ams/dsl_support.rb new file mode 100644 index 00000000..b4fbb188 --- /dev/null +++ b/lib/ams/dsl_support.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module AMS + module DSLSupport + # @api private + # Macro to add an instance method to the receiver + def add_instance_method(body, receiver) + cl = caller_locations[0] + silence_warnings { receiver.module_eval body, cl.absolute_path, cl.lineno } + end + + # @api private + # Macro to add a class method to the receiver + def add_class_method(body, receiver) + cl = caller_locations[0] + silence_warnings { receiver.class_eval body, cl.absolute_path, cl.lineno } + end + + # @api private + # Silence warnings, primarily when redefining methods + def silence_warnings + original_verbose = $VERBOSE + $VERBOSE = nil + yield + ensure + $VERBOSE = original_verbose + end + end +end diff --git a/lib/ams/serializer.rb b/lib/ams/serializer.rb index aff0d3aa..88a5d0a4 100644 --- a/lib/ams/serializer.rb +++ b/lib/ams/serializer.rb @@ -2,6 +2,7 @@ require "json" require "ams/inflector" +require "ams/dsl_support" module AMS # Lightweight mapping of a model to a JSON API resource object # with attributes and relationships @@ -31,6 +32,7 @@ module AMS # ums = UserModelSerializer.new(user) # ums.to_json class Serializer < BasicObject + extend DSLSupport # delegate constant lookup to Object def self.const_missing(name) ::Object.const_get(name) @@ -40,30 +42,6 @@ module AMS attr_accessor :_attributes, :_relations, :_id_field, :_type attr_accessor :_fields, :_query_params - # @api private - # Macro to add an instance method to the receiver - def add_instance_method(body, receiver = self) - cl = caller_locations[0] - silence_warnings { receiver.module_eval body, cl.absolute_path, cl.lineno } - end - - # @api private - # Macro to add a class method to the receiver - def add_class_method(body, receiver) - cl = caller_locations[0] - silence_warnings { receiver.class_eval body, cl.absolute_path, cl.lineno } - end - - # @api private - # Silence warnings, primarily when redefining methods - def silence_warnings - original_verbose = $VERBOSE - $VERBOSE = nil - yield - ensure - $VERBOSE = original_verbose - end - # @!visibility private def _infer_type(base) Inflector.pluralize( @@ -101,7 +79,7 @@ module AMS # id_field :user_id def id_field(id_field) self._id_field = id_field - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def id object.#{id_field} end @@ -121,7 +99,8 @@ module AMS fail "ForbiddenKey" if attribute_name == :id _fields << key _attributes[attribute_name] = { key: key } - add_instance_method <<-METHOD + + add_instance_method <<-METHOD, self def #{attribute_name} object.#{attribute_name} end @@ -197,22 +176,22 @@ module AMS ids_method = options.fetch(:ids) do "object.#{relation_name}.pluck(:id)" end - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def related_#{relation_name}_ids #{ids_method} end METHOD - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def related_#{relation_name}_data related_#{relation_name}_ids.map { |id| relationship_data(id, "#{type}") } end METHOD - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def related_#{relation_name}_links related_link_to_many("#{type}") end METHOD - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def #{relation_name} {}.tap do |hash| hash[:data] = related_#{relation_name}_data @@ -269,22 +248,22 @@ module AMS id_method = options.fetch(:id) do "object.#{relation_name}.id" end - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def related_#{relation_name}_id #{id_method} end METHOD - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def related_#{relation_name}_data relationship_data(related_#{relation_name}_id, "#{type}") end METHOD - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def related_#{relation_name}_links related_link_to_one(related_#{relation_name}_id, "#{type}") end METHOD - add_instance_method <<-METHOD + add_instance_method <<-METHOD, self def #{relation_name} {}.tap do |hash| hash[:data] = related_#{relation_name}_data