duck_record 0.0.16 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,23 +7,23 @@ module DuckRecord
7
7
  include ActiveModel::ForbiddenAttributesProtection
8
8
 
9
9
  # Alias for ActiveModel::AttributeAssignment#assign_attributes. See ActiveModel::AttributeAssignment.
10
- def attributes=(attributes, force_write_readonly: false)
11
- assign_attributes(attributes, force_write_readonly: force_write_readonly)
10
+ def attributes=(attributes)
11
+ assign_attributes(attributes)
12
12
  end
13
13
 
14
- def assign_attributes(new_attributes, force_write_readonly: false)
14
+ def assign_attributes(new_attributes)
15
15
  unless new_attributes.respond_to?(:stringify_keys)
16
16
  raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
17
17
  end
18
18
  return if new_attributes.nil? || new_attributes.empty?
19
19
 
20
20
  attributes = new_attributes.stringify_keys
21
- _assign_attributes(sanitize_for_mass_assignment(attributes), force_write_readonly: force_write_readonly)
21
+ _assign_attributes(sanitize_for_mass_assignment(attributes))
22
22
  end
23
23
 
24
24
  private
25
25
 
26
- def _assign_attributes(attributes, force_write_readonly: false)
26
+ def _assign_attributes(attributes)
27
27
  multi_parameter_attributes = {}
28
28
  nested_parameter_attributes = {}
29
29
 
@@ -36,21 +36,21 @@ module DuckRecord
36
36
  end
37
37
 
38
38
  attributes.each do |k, v|
39
- _assign_attribute(k, v, force_write_readonly: force_write_readonly)
39
+ _assign_attribute(k, v)
40
40
  end
41
41
 
42
42
  unless nested_parameter_attributes.empty?
43
- assign_nested_parameter_attributes(nested_parameter_attributes, force_write_readonly: force_write_readonly)
43
+ assign_nested_parameter_attributes(nested_parameter_attributes)
44
44
  end
45
45
 
46
46
  unless multi_parameter_attributes.empty?
47
- assign_multiparameter_attributes(multi_parameter_attributes, force_write_readonly: force_write_readonly)
47
+ assign_multiparameter_attributes(multi_parameter_attributes)
48
48
  end
49
49
  end
50
50
 
51
51
  # Assign any deferred nested attributes after the base attributes have been set.
52
- def assign_nested_parameter_attributes(pairs, force_write_readonly: false)
53
- pairs.each { |k, v| _assign_attribute(k, v, force_write_readonly: force_write_readonly) }
52
+ def assign_nested_parameter_attributes(pairs)
53
+ pairs.each { |k, v| _assign_attribute(k, v) }
54
54
  end
55
55
 
56
56
  # Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
@@ -59,14 +59,13 @@ module DuckRecord
59
59
  # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
60
60
  # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Integer and
61
61
  # f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+.
62
- def assign_multiparameter_attributes(pairs, force_write_readonly: false)
62
+ def assign_multiparameter_attributes(pairs)
63
63
  execute_callstack_for_multiparameter_attributes(
64
- extract_callstack_for_multiparameter_attributes(pairs),
65
- force_write_readonly: force_write_readonly
64
+ extract_callstack_for_multiparameter_attributes(pairs)
66
65
  )
67
66
  end
68
67
 
69
- def execute_callstack_for_multiparameter_attributes(callstack, force_write_readonly: false)
68
+ def execute_callstack_for_multiparameter_attributes(callstack)
70
69
  errors = []
71
70
  callstack.each do |name, values_with_empty_parameters|
72
71
  begin
@@ -75,7 +74,7 @@ module DuckRecord
75
74
  else
76
75
  values = values_with_empty_parameters
77
76
  end
78
- send("#{name}=", values, force_write_readonly: force_write_readonly)
77
+ send("#{name}=", values)
79
78
  rescue => ex
80
79
  errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
81
80
  end
@@ -108,9 +107,9 @@ module DuckRecord
108
107
  multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
109
108
  end
110
109
 
111
- def _assign_attribute(k, v, force_write_readonly: false)
110
+ def _assign_attribute(k, v)
112
111
  if respond_to?("#{k}=")
113
- public_send("#{k}=", v, force_write_readonly: force_write_readonly)
112
+ public_send("#{k}=", v)
114
113
  else
115
114
  raise UnknownAttributeError.new(self, k)
116
115
  end
@@ -15,9 +15,9 @@ module DuckRecord
15
15
  DuckRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
16
16
 
17
17
  generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
18
- def __temp__#{safe_name}=(value, force_write_readonly: false)
18
+ def __temp__#{safe_name}=(value)
19
19
  name = ::DuckRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
20
- write_attribute(name, value, force_write_readonly: force_write_readonly)
20
+ write_attribute(name, value)
21
21
  end
22
22
  alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
23
23
  undef_method :__temp__#{safe_name}=
@@ -28,32 +28,35 @@ module DuckRecord
28
28
  # Updates the attribute identified by <tt>attr_name</tt> with the
29
29
  # specified +value+. Empty strings for Integer and Float columns are
30
30
  # turned into +nil+.
31
- def write_attribute(attr_name, value, force_write_readonly: false)
32
- name = if self.class.attribute_alias?(attr_name)
33
- self.class.attribute_alias(attr_name).to_s
34
- else
35
- attr_name.to_s
36
- end
31
+ def write_attribute(attr_name, value)
32
+ name =
33
+ if self.class.attribute_alias?(attr_name)
34
+ self.class.attribute_alias(attr_name).to_s
35
+ else
36
+ attr_name.to_s
37
+ end
37
38
 
38
- write_attribute_with_type_cast(name, value, true, force_write_readonly: force_write_readonly)
39
+ if self.class.readonly_attributes.include?(name) && attr_readonly_enabled?
40
+ return
41
+ end
42
+
43
+ write_attribute_with_type_cast(name, value, true)
39
44
  end
40
45
 
41
- def raw_write_attribute(attr_name, value, force_write_readonly: false) # :nodoc:
42
- write_attribute_with_type_cast(attr_name, value, false, force_write_readonly: force_write_readonly)
46
+ def raw_write_attribute(attr_name, value) # :nodoc:
47
+ write_attribute_with_type_cast(attr_name, value, false)
43
48
  end
44
49
 
45
50
  private
46
51
 
47
52
  # Handle *= for method_missing.
48
- def attribute=(attribute_name, value, force_write_readonly: false)
49
- write_attribute(attribute_name, value, force_write_readonly: force_write_readonly)
53
+ def attribute=(attribute_name, value)
54
+ write_attribute(attribute_name, value)
50
55
  end
51
56
 
52
- def write_attribute_with_type_cast(attr_name, value, should_type_cast, force_write_readonly: false)
57
+ def write_attribute_with_type_cast(attr_name, value, should_type_cast)
53
58
  attr_name = attr_name.to_s
54
59
 
55
- return if !force_write_readonly && self.class.readonly_attributes.include?(attr_name)
56
-
57
60
  if should_type_cast
58
61
  @attributes.write_from_user(attr_name, value)
59
62
  else
@@ -294,26 +294,6 @@ module DuckRecord #:nodoc:
294
294
  include NestedAttributes
295
295
  include Reflection
296
296
  include Serialization
297
-
298
- def to_h(include_empty: true)
299
- hash = serializable_hash
300
-
301
- self.class.reflections.keys.each do |k|
302
- records = send(k)
303
- sub_hash =
304
- if records.respond_to?(:to_ary)
305
- records.to_ary.map { |a| a.to_h }
306
- else
307
- records.to_h
308
- end
309
-
310
- if include_empty || sub_hash.any?
311
- hash[k] = sub_hash
312
- end
313
- end
314
-
315
- hash
316
- end
317
297
  end
318
298
 
319
299
  ActiveSupport.run_load_hooks(:duck_record, Base)
@@ -63,16 +63,20 @@ module DuckRecord
63
63
  self.class.define_attribute_methods
64
64
  @attributes = self.class._default_attributes.deep_dup
65
65
 
66
+ disable_attr_readonly!
67
+
66
68
  init_internals
67
69
  initialize_internals_callback
68
70
 
69
71
  if attributes
70
- assign_attributes(attributes, force_write_readonly: true)
72
+ assign_attributes(attributes)
71
73
  clear_changes_information
72
74
  end
73
75
 
74
76
  yield self if block_given?
75
77
  _run_initialize_callbacks
78
+
79
+ enable_attr_readonly!
76
80
  end
77
81
 
78
82
  # Initialize an empty model object from +coder+. +coder+ should be
@@ -356,7 +356,7 @@ module DuckRecord
356
356
  if method_defined?(:#{association_name}_attributes=)
357
357
  remove_method(:#{association_name}_attributes=)
358
358
  end
359
- def #{association_name}_attributes=(attributes, force_write_readonly: false)
359
+ def #{association_name}_attributes=(attributes)
360
360
  assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
361
361
  end
362
362
  eoruby
@@ -139,7 +139,7 @@ module DuckRecord
139
139
  end
140
140
 
141
141
  included do
142
- Associations::Builder::Association.extensions << AssociationBuilderExtension
142
+ Associations::Builder::EmbedsAssociation.extensions << AssociationBuilderExtension
143
143
  mattr_accessor :index_nested_attribute_errors, instance_writer: false
144
144
  self.index_nested_attribute_errors = false
145
145
  end
@@ -3,10 +3,23 @@ module DuckRecord
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
+ attr_accessor :_attr_readonly_enabled
6
7
  class_attribute :_attr_readonly, instance_accessor: false
7
8
  self._attr_readonly = []
8
9
  end
9
10
 
11
+ def attr_readonly_enabled?
12
+ _attr_readonly_enabled
13
+ end
14
+
15
+ def enable_attr_readonly!
16
+ self._attr_readonly_enabled = true
17
+ end
18
+
19
+ def disable_attr_readonly!
20
+ self._attr_readonly_enabled = false
21
+ end
22
+
10
23
  module ClassMethods
11
24
  # Attributes listed as readonly will be used to create a new record but update operations will
12
25
  # ignore these fields.
@@ -15,10 +15,10 @@ module DuckRecord
15
15
  def self.create(macro, name, options, ar)
16
16
  klass = \
17
17
  case macro
18
- when :has_many
19
- HasManyReflection
20
- when :has_one
21
- HasOneReflection
18
+ when :embeds_many
19
+ EmbedsManyReflection
20
+ when :embeds_one
21
+ EmbedsOneReflection
22
22
  else
23
23
  raise "Unsupported Macro: #{macro}"
24
24
  end
@@ -182,7 +182,7 @@ module DuckRecord
182
182
 
183
183
  # Holds all the metadata about an association as it was specified in the
184
184
  # Active Record class.
185
- class AssociationReflection < MacroReflection #:nodoc:
185
+ class EmbedsAssociationReflection < MacroReflection #:nodoc:
186
186
  # Returns the target association's class.
187
187
  #
188
188
  # class Author < ActiveRecord::Base
@@ -286,23 +286,23 @@ module DuckRecord
286
286
  end
287
287
  end
288
288
 
289
- class HasManyReflection < AssociationReflection # :nodoc:
290
- def macro; :has_many; end
289
+ class EmbedsManyReflection < EmbedsAssociationReflection # :nodoc:
290
+ def macro; :embeds_many; end
291
291
 
292
292
  def collection?; true; end
293
293
 
294
294
  def association_class
295
- Associations::HasManyAssociation
295
+ Associations::EmbedsManyAssociation
296
296
  end
297
297
  end
298
298
 
299
- class HasOneReflection < AssociationReflection # :nodoc:
300
- def macro; :has_one; end
299
+ class EmbedsOneReflection < EmbedsAssociationReflection # :nodoc:
300
+ def macro; :embeds_one; end
301
301
 
302
302
  def has_one?; true; end
303
303
 
304
304
  def association_class
305
- Associations::HasOneAssociation
305
+ Associations::EmbedsOneAssociation
306
306
  end
307
307
  end
308
308
  end
@@ -8,24 +8,13 @@ module DuckRecord #:nodoc:
8
8
  self.include_root_in_json = false
9
9
  end
10
10
 
11
- def serializable_hash(options = {})
12
- options = (options || {}).reverse_merge except: Array(options[:except]).map(&:to_s)
13
- super options
14
- end
11
+ def serializable_hash(options = nil)
12
+ options = options.try(:dup) || {}
15
13
 
16
- private
14
+ options[:except] = Array(options[:except]).map(&:to_s)
15
+ options[:include] = Array(_reflections.keys).map(&:to_s)
17
16
 
18
- def read_attribute_for_serialization(key)
19
- v = send(key)
20
- if v.respond_to?(:serializable_hash)
21
- v.serializable_hash
22
- elsif v.respond_to?(:to_ary)
23
- v.to_ary
24
- elsif v.respond_to?(:to_hash)
25
- v.to_hash
26
- else
27
- v
28
- end
17
+ super(options)
29
18
  end
30
19
  end
31
20
  end
@@ -1,3 +1,3 @@
1
1
  module DuckRecord
2
- VERSION = "0.0.16"
2
+ VERSION = "0.0.18"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duck_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - jasl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-17 00:00:00.000000000 Z
11
+ date: 2017-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -83,17 +83,13 @@ files:
83
83
  - lib/core_ext/array_without_blank.rb
84
84
  - lib/duck_record.rb
85
85
  - lib/duck_record/associations.rb
86
- - lib/duck_record/associations/association.rb
87
- - lib/duck_record/associations/builder/association.rb
88
- - lib/duck_record/associations/builder/collection_association.rb
89
- - lib/duck_record/associations/builder/has_many.rb
90
- - lib/duck_record/associations/builder/has_one.rb
91
- - lib/duck_record/associations/builder/singular_association.rb
92
- - lib/duck_record/associations/collection_association.rb
93
- - lib/duck_record/associations/collection_proxy.rb
94
- - lib/duck_record/associations/has_many_association.rb
95
- - lib/duck_record/associations/has_one_association.rb
96
- - lib/duck_record/associations/singular_association.rb
86
+ - lib/duck_record/associations/builder/embeds_association.rb
87
+ - lib/duck_record/associations/builder/embeds_many.rb
88
+ - lib/duck_record/associations/builder/embeds_one.rb
89
+ - lib/duck_record/associations/embeds_association.rb
90
+ - lib/duck_record/associations/embeds_many_association.rb
91
+ - lib/duck_record/associations/embeds_many_proxy.rb
92
+ - lib/duck_record/associations/embeds_one_association.rb
97
93
  - lib/duck_record/attribute.rb
98
94
  - lib/duck_record/attribute/user_provided_default.rb
99
95
  - lib/duck_record/attribute_assignment.rb
@@ -164,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
160
  version: '0'
165
161
  requirements: []
166
162
  rubyforge_project:
167
- rubygems_version: 2.6.13
163
+ rubygems_version: 2.6.12
168
164
  signing_key:
169
165
  specification_version: 4
170
166
  summary: Used for creating virtual models like ActiveType or ModelAttribute does
@@ -1,7 +0,0 @@
1
- module DuckRecord::Associations::Builder # :nodoc:
2
- class HasMany < CollectionAssociation #:nodoc:
3
- def self.macro
4
- :has_many
5
- end
6
- end
7
- end
@@ -1,15 +0,0 @@
1
- module DuckRecord::Associations::Builder # :nodoc:
2
- class HasOne < SingularAssociation #:nodoc:
3
- def self.macro
4
- :has_one
5
- end
6
-
7
- def self.define_validations(model, reflection)
8
- super
9
-
10
- if reflection.options[:required]
11
- model.validates_presence_of reflection.name, message: :required
12
- end
13
- end
14
- end
15
- end
@@ -1,11 +0,0 @@
1
- module DuckRecord
2
- # = Active Record Has Many Association
3
- module Associations
4
- # This is the proxy that handles a has many association.
5
- #
6
- # If the association has a <tt>:through</tt> option further specialization
7
- # is provided by its child HasManyThroughAssociation.
8
- class HasManyAssociation < CollectionAssociation #:nodoc:
9
- end
10
- end
11
- end
@@ -1,17 +0,0 @@
1
- module DuckRecord
2
- # = Active Record Has One Association
3
- module Associations
4
- class HasOneAssociation < SingularAssociation #:nodoc:
5
- def replace(record)
6
- self.target =
7
- if record.is_a? klass
8
- record
9
- elsif record.respond_to?(:to_h)
10
- build_record(record.to_h)
11
- end
12
- rescue
13
- raise_on_type_mismatch!(record)
14
- end
15
- end
16
- end
17
- end