Skip to content

Commit beaa718

Browse files
committed
Refactoring. Move .field implementation into a separate class Dynamoid::Fields::Declare
1 parent 8598fdd commit beaa718

File tree

2 files changed

+87
-43
lines changed

2 files changed

+87
-43
lines changed

lib/dynamoid/fields.rb

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require 'dynamoid/fields/declare'
4+
35
module Dynamoid
46
# All fields on a Dynamoid::Document must be explicitly defined -- if you have fields in the database that are not
57
# specified with field, then they will be ignored.
@@ -132,46 +134,12 @@ module ClassMethods
132134
#
133135
# @since 0.2.0
134136
def field(name, type = :string, options = {})
135-
named = name.to_s
136137
if type == :float
137138
Dynamoid.logger.warn("Field type :float, which you declared for '#{name}', is deprecated in favor of :number.")
138139
type = :number
139140
end
140-
self.attributes = attributes.merge(name => { type: type }.merge(options))
141-
142-
# should be called before `define_attribute_methods` method because it defines a getter itself
143-
warn_about_method_overriding(name, name)
144-
warn_about_method_overriding("#{named}=", name)
145-
warn_about_method_overriding("#{named}?", name)
146-
warn_about_method_overriding("#{named}_before_type_cast?", name)
147-
148-
define_attribute_method(name) # Dirty API
149-
150-
generated_methods.module_eval do
151-
define_method(named) { read_attribute(named) }
152-
define_method("#{named}?") do
153-
value = read_attribute(named)
154-
case value
155-
when true then true
156-
when false, nil then false
157-
else
158-
!value.nil?
159-
end
160-
end
161-
define_method("#{named}=") { |value| write_attribute(named, value) }
162-
define_method("#{named}_before_type_cast") { read_attribute_before_type_cast(named) }
163-
end
164-
165-
if options[:alias]
166-
alias_name = options[:alias].to_s
167141

168-
generated_methods.module_eval do
169-
alias_method alias_name, named
170-
alias_method "#{alias_name}=", "#{named}="
171-
alias_method "#{alias_name}?", "#{named}?"
172-
alias_method "#{alias_name}_before_type_cast", "#{named}_before_type_cast"
173-
end
174-
end
142+
Dynamoid::Fields::Declare.new(self, name, type, options).call
175143
end
176144

177145
# Declare a table range key.
@@ -284,21 +252,14 @@ def timestamps_enabled?
284252
options[:timestamps] || (options[:timestamps].nil? && Dynamoid::Config.timestamps)
285253
end
286254

287-
private
288-
255+
# @private
289256
def generated_methods
290257
@generated_methods ||= begin
291258
Module.new.tap do |mod|
292259
include(mod)
293260
end
294261
end
295262
end
296-
297-
def warn_about_method_overriding(method_name, field_name)
298-
if instance_methods.include?(method_name.to_sym)
299-
Dynamoid.logger.warn("Method #{method_name} generated for the field #{field_name} overrides already existing method")
300-
end
301-
end
302263
end
303264

304265
# You can access the attributes of an object directly on its attributes method, which is by default an empty hash.

lib/dynamoid/fields/declare.rb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# frozen_string_literal: true
2+
3+
module Dynamoid
4+
module Fields
5+
# @private
6+
class Declare
7+
def initialize(source, name, type, options)
8+
@source = source
9+
@name = name.to_sym
10+
@type = type
11+
@options = options
12+
end
13+
14+
def call
15+
# Register new field metadata
16+
@source.attributes = @source.attributes.merge(
17+
@name => { type: @type }.merge(@options)
18+
)
19+
20+
# Should be called before `define_attribute_methods` method because it
21+
# defines an attribute getter itself
22+
warn_about_method_overriding
23+
24+
# Dirty API
25+
@source.define_attribute_method(@name)
26+
27+
# Generate getters and setters as well as other helper methods
28+
generate_instance_methods
29+
30+
# If alias name specified - generate the same instance methods
31+
if @options[:alias]
32+
generate_instance_methods_for_alias
33+
end
34+
end
35+
36+
private
37+
38+
def warn_about_method_overriding
39+
warn_if_method_exists(@name)
40+
warn_if_method_exists("#{@name}=")
41+
warn_if_method_exists("#{@name}?")
42+
warn_if_method_exists("#{@name}_before_type_cast?")
43+
end
44+
45+
def generate_instance_methods
46+
name = @name
47+
48+
@source.generated_methods.module_eval do
49+
define_method(name) { read_attribute(name) }
50+
define_method("#{name}?") do
51+
value = read_attribute(name)
52+
case value
53+
when true then true
54+
when false, nil then false
55+
else
56+
!value.nil?
57+
end
58+
end
59+
define_method("#{name}=") { |value| write_attribute(name, value) }
60+
define_method("#{name}_before_type_cast") { read_attribute_before_type_cast(name) }
61+
end
62+
end
63+
64+
def generate_instance_methods_for_alias
65+
alias_name = @options[:alias].to_sym
66+
name = @name
67+
68+
@source.generated_methods.module_eval do
69+
alias_method alias_name, name
70+
alias_method "#{alias_name}=", "#{name}="
71+
alias_method "#{alias_name}?", "#{name}?"
72+
alias_method "#{alias_name}_before_type_cast", "#{name}_before_type_cast"
73+
end
74+
end
75+
76+
def warn_if_method_exists(method)
77+
if @source.instance_methods.include?(method.to_sym)
78+
Dynamoid.logger.warn("Method #{method} generated for the field #{@name} overrides already existing method")
79+
end
80+
end
81+
end
82+
end
83+
end

0 commit comments

Comments
 (0)