hydra_attribute 0.4.2 → 0.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +6 -5
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +1 -1
  5. data/README.md +3 -3
  6. data/Rakefile +2 -7
  7. data/gemfiles/activerecord-3.2.gemfile +5 -0
  8. data/hydra_attribute.gemspec +6 -7
  9. data/lib/hydra_attribute.rb +17 -18
  10. data/lib/hydra_attribute/active_record.rb +34 -13
  11. data/lib/hydra_attribute/active_record/association_preloader.rb +47 -28
  12. data/lib/hydra_attribute/active_record/attribute_methods.rb +29 -140
  13. data/lib/hydra_attribute/active_record/mass_assignment_security.rb +39 -0
  14. data/lib/hydra_attribute/active_record/migration.rb +4 -4
  15. data/lib/hydra_attribute/active_record/relation.rb +6 -7
  16. data/lib/hydra_attribute/active_record/relation/query_methods.rb +28 -18
  17. data/lib/hydra_attribute/hydra_attribute.rb +12 -49
  18. data/lib/hydra_attribute/hydra_attribute_set.rb +67 -0
  19. data/lib/hydra_attribute/hydra_entity.rb +110 -0
  20. data/lib/hydra_attribute/hydra_entity_attribute_association.rb +155 -0
  21. data/lib/hydra_attribute/hydra_set.rb +24 -26
  22. data/lib/hydra_attribute/hydra_value.rb +210 -0
  23. data/lib/hydra_attribute/identity_map.rb +18 -0
  24. data/lib/hydra_attribute/middleware/identity_map.rb +15 -0
  25. data/lib/hydra_attribute/migrator.rb +24 -21
  26. data/lib/hydra_attribute/model.rb +47 -0
  27. data/lib/hydra_attribute/model/cacheable.rb +207 -0
  28. data/lib/hydra_attribute/model/dirty.rb +39 -0
  29. data/lib/hydra_attribute/model/has_many_through.rb +168 -0
  30. data/lib/hydra_attribute/model/identity_map.rb +59 -0
  31. data/lib/hydra_attribute/model/mediator.rb +89 -0
  32. data/lib/hydra_attribute/model/notifiable.rb +23 -0
  33. data/lib/hydra_attribute/model/persistence.rb +424 -0
  34. data/lib/hydra_attribute/model/validations.rb +40 -0
  35. data/lib/hydra_attribute/version.rb +1 -1
  36. data/spec/environments/mysql.rb +23 -0
  37. data/spec/environments/postgresql.rb +23 -0
  38. data/spec/environments/sqlite.rb +12 -0
  39. data/spec/fixtures/category.rb +8 -0
  40. data/spec/fixtures/product.rb +8 -0
  41. data/spec/fixtures/product_black_list.rb +13 -0
  42. data/spec/fixtures/product_white_list.rb +13 -0
  43. data/spec/hydra_attribute/active_record/attribute_methods_spec.rb +23 -28
  44. data/spec/hydra_attribute/active_record/mass_assignment_security_spec.rb +41 -0
  45. data/spec/hydra_attribute/active_record_spec.rb +577 -0
  46. data/spec/hydra_attribute/hydra_attribute_set_spec.rb +651 -0
  47. data/spec/hydra_attribute/hydra_attribute_spec.rb +208 -10
  48. data/spec/hydra_attribute/hydra_entity_attribute_association_spec.rb +216 -0
  49. data/spec/hydra_attribute/hydra_entity_spec.rb +71 -0
  50. data/spec/hydra_attribute/hydra_set_spec.rb +51 -10
  51. data/spec/hydra_attribute/hydra_value_spec.rb +286 -0
  52. data/spec/hydra_attribute/identity_map_spec.rb +47 -0
  53. data/spec/hydra_attribute/migrator_spec.rb +411 -0
  54. data/spec/hydra_attribute/model/cacheable_spec.rb +106 -0
  55. data/spec/hydra_attribute/model/has_many_through_spec.rb +132 -0
  56. data/spec/hydra_attribute/model/identity_map_spec.rb +39 -0
  57. data/spec/hydra_attribute/model/mediator_spec.rb +62 -0
  58. data/spec/hydra_attribute/model/persistence_spec.rb +550 -0
  59. data/spec/hydra_attribute/model_spec.rb +39 -0
  60. data/spec/hydra_attribute_spec.rb +36 -0
  61. data/spec/spec_helper.rb +10 -42
  62. metadata +76 -100
  63. data/Appraisals +0 -7
  64. data/cucumber.yml +0 -1
  65. data/features/entity/create.feature +0 -145
  66. data/features/entity/destroy.feature +0 -111
  67. data/features/entity/new.feature +0 -121
  68. data/features/entity/update.feature +0 -147
  69. data/features/hydra_attribute/create.feature +0 -30
  70. data/features/hydra_attribute/destroy.feature +0 -26
  71. data/features/hydra_attribute/update.feature +0 -36
  72. data/features/hydra_set/destroy.feature +0 -31
  73. data/features/migrations/create_and_drop.feature +0 -165
  74. data/features/migrations/migrate_and_rollback.feature +0 -211
  75. data/features/relation/query_methods/group.feature +0 -42
  76. data/features/relation/query_methods/order.feature +0 -67
  77. data/features/relation/query_methods/reorder.feature +0 -29
  78. data/features/relation/query_methods/reverse_order.feature +0 -29
  79. data/features/relation/query_methods/select.feature +0 -50
  80. data/features/relation/query_methods/where.feature +0 -115
  81. data/features/step_definitions/connections.rb +0 -65
  82. data/features/step_definitions/model_steps.rb +0 -136
  83. data/features/step_definitions/query_methods.rb +0 -48
  84. data/features/step_definitions/record_steps.rb +0 -93
  85. data/features/support/env.rb +0 -38
  86. data/features/support/world.rb +0 -61
  87. data/lib/hydra_attribute/active_record/association.rb +0 -113
  88. data/lib/hydra_attribute/active_record/reflection.rb +0 -16
  89. data/lib/hydra_attribute/association_builder.rb +0 -69
  90. data/lib/hydra_attribute/builder.rb +0 -37
  91. data/lib/hydra_attribute/entity_callbacks.rb +0 -26
  92. data/lib/hydra_attribute/hydra_attribute_methods.rb +0 -226
  93. data/lib/hydra_attribute/hydra_methods.rb +0 -528
  94. data/lib/hydra_attribute/hydra_set_methods.rb +0 -95
  95. data/lib/hydra_attribute/hydra_value_methods.rb +0 -21
  96. data/lib/hydra_attribute/memoizable.rb +0 -37
  97. data/spec/hydra_attribute/active_record/relation/query_methods_spec.rb +0 -31
  98. data/spec/hydra_attribute/hydra_attribute_methods_spec.rb +0 -458
  99. data/spec/hydra_attribute/hydra_methods_spec.rb +0 -456
  100. data/spec/hydra_attribute/hydra_set_methods_spec.rb +0 -203
  101. data/spec/hydra_attribute/memoizable_spec.rb +0 -95
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
@@ -18,4 +19,4 @@ tmp
18
19
  .idea
19
20
  .rvmrc
20
21
  bin/
21
- gemfiles
22
+ gemfiles/*.lock
data/.travis.yml CHANGED
@@ -1,9 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
-
5
- before_install: bundle && rake appraisal:gemfiles
6
-
4
+ - 2.0.0
7
5
  gemfile:
8
- - gemfiles/3.1.gemfile
9
- - gemfiles/3.2.gemfile
6
+ - gemfiles/activerecord-3.2.gemfile
7
+ env:
8
+ - DB=sqlite
9
+ - DB=mysql
10
+ - DB=postgresql
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ **0.5.0 (...)**
2
+ * Cache all hydra attributes per request
3
+ * Add support of `decimal` backend type
4
+ * Add `id` to `hydra_attribute_sets` table
5
+ * Use new index name pattern `*_idx` instead of `*_index`
6
+
1
7
  **0.4.2 (January 20, 2013)**
2
8
  * Fixed bug in `count` method which added unnecessary columns to query [#2](https://github.com/kostyantyn/hydra_attribute/issues/2)
3
9
 
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # hydra_attribute [![Gem Version](https://fury-badge.herokuapp.com/rb/hydra_attribute.png)](http://badge.fury.io/rb/hydra_attribute) [![Build Status](https://secure.travis-ci.org/kostyantyn/hydra_attribute.png)](http://travis-ci.org/kostyantyn/hydra_attribute)
1
+ # hydra_attribute [![Gem Version](https://fury-badge.herokuapp.com/rb/hydra_attribute.png)](http://badge.fury.io/rb/hydra_attribute) [![Build Status](https://travis-ci.org/kostyantyn/hydra_attribute.png?branch=value_model_optimization)](https://travis-ci.org/kostyantyn/hydra_attribute)
2
2
 
3
3
  [Wiki](https://github.com/kostyantyn/hydra_attribute/wiki) | [RDoc](http://rdoc.info/github/kostyantyn/hydra_attribute)
4
4
 
@@ -12,7 +12,7 @@ Until the first major version is released:
12
12
 
13
13
  ## Requirements
14
14
  * ruby >= 1.9.2
15
- * active_record ~> 3.1
15
+ * active_record ~> 3.2
16
16
 
17
17
  ## Installation
18
18
 
@@ -82,7 +82,7 @@ Creating method accepts the following options:
82
82
  * **name**. The **required** parameter. Any string is allowed.
83
83
  * **backend_type**. The **required** parameter. One of the following strings is allowed: `string`, `text`, `integer`, `float`, `boolean` and `datetime`.
84
84
  * **default_value**. The **optional** parameter. Any value is allowed. `nil` is default.
85
- * **white_list**. The **optional** parameter. Should be `true` or `flase`. `false` is default. If `white_list: true` is passed, this attribute will be added to white list and will be allowed for mass-assignment. This parameter is in black list for creation by default so if you want to pass it, you have to pass the role `as: :admin` too.
85
+ * **white_list**. The **optional** parameter. Should be `true` or `false`. `false` is default. If `white_list: true` is passed, this attribute will be added to white list and will be allowed for mass-assignment. This parameter is in black list for creation by default so if you want to pass it, you have to pass the role `as: :admin` too.
86
86
 
87
87
  ```ruby
88
88
  Product.hydra_attributes.create({name: 'title', backend_type: 'string', white_list: true}, as: :admin)
data/Rakefile CHANGED
@@ -1,12 +1,7 @@
1
1
  #!/usr/bin/env rake
2
2
  require 'bundler/gem_tasks'
3
- require 'appraisal'
4
3
  require 'rspec/core/rake_task'
5
- require 'cucumber/rake/task'
6
4
 
7
- RSpec::Core::RakeTask.new('spec')
8
- Cucumber::Rake::Task.new(:features) do |t|
9
- t.cucumber_opts = '--format pretty'
10
- end
5
+ RSpec::Core::RakeTask.new(:spec)
11
6
 
12
- task default: [:features, :spec]
7
+ task default: [:spec]
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord', '~> 3.2.0'
4
+
5
+ gemspec path: '../'
@@ -8,18 +8,17 @@ Gem::Specification.new do |gem|
8
8
  gem.description = 'hydra_attribute is an implementation of EAV pattern for ActiveRecord models.'
9
9
  gem.homepage = 'https://github.com/kostyantyn/hydra_attribute'
10
10
  gem.files = `git ls-files`.split("\n")
11
- gem.test_files = `git ls-files -- Appraisals {spec,features,gemfiles}/*`.split("\n")
12
- gem.name = "hydra_attribute"
11
+ gem.test_files = `git ls-files -- {spec,features,gemfiles}/*`.split("\n")
12
+ gem.name = 'hydra_attribute'
13
13
  gem.require_paths = %w(lib)
14
14
  gem.required_ruby_version = Gem::Requirement.new('>= 1.9.2')
15
15
  gem.version = HydraAttribute::VERSION
16
16
 
17
- gem.add_dependency('activerecord', '~> 3.1')
17
+ gem.add_dependency('activerecord', '~> 3.2')
18
18
 
19
- gem.add_development_dependency('rspec')
20
- gem.add_development_dependency('cucumber')
19
+ gem.add_development_dependency('rspec', '~> 2.13')
21
20
  gem.add_development_dependency('sqlite3')
22
- gem.add_development_dependency('database_cleaner')
23
- gem.add_development_dependency('appraisal')
21
+ gem.add_development_dependency('mysql2')
22
+ gem.add_development_dependency('pg')
24
23
  gem.add_development_dependency('rake')
25
24
  end
@@ -1,5 +1,7 @@
1
+ require 'active_record'
2
+
1
3
  module HydraAttribute
2
- SUPPORTED_BACKEND_TYPES = %w(string text integer float boolean datetime).freeze
4
+ SUPPORTED_BACKEND_TYPES = %w[string text integer float decimal boolean datetime].freeze
3
5
 
4
6
  class << self
5
7
  def config
@@ -9,32 +11,29 @@ module HydraAttribute
9
11
  def setup
10
12
  yield config
11
13
  end
14
+
15
+ def identity_map
16
+ Thread.current[:hydra_attribute] ||= IdentityMap.new
17
+ end
18
+
19
+ def cache(key, value = nil, &block)
20
+ identity_map.cache(key, value, &block)
21
+ end
12
22
  end
13
23
 
14
24
  end
15
25
 
16
26
  require 'hydra_attribute/version'
17
27
  require 'hydra_attribute/configuration'
18
- require 'hydra_attribute/association_builder'
19
- require 'hydra_attribute/builder'
20
28
  require 'hydra_attribute/migrator'
21
- require 'hydra_attribute/memoizable'
29
+ require 'hydra_attribute/identity_map'
30
+ require 'hydra_attribute/model'
22
31
  require 'hydra_attribute/hydra_attribute'
23
32
  require 'hydra_attribute/hydra_set'
24
- require 'hydra_attribute/entity_callbacks'
25
- require 'hydra_attribute/hydra_set_methods'
26
- require 'hydra_attribute/hydra_value_methods'
27
- require 'hydra_attribute/hydra_attribute_methods'
28
- require 'hydra_attribute/hydra_methods'
33
+ require 'hydra_attribute/hydra_attribute_set'
34
+ require 'hydra_attribute/hydra_value'
35
+ require 'hydra_attribute/hydra_entity'
36
+ require 'hydra_attribute/hydra_entity_attribute_association'
29
37
  require 'hydra_attribute/active_record'
30
- require 'hydra_attribute/active_record/scoping'
31
- require 'hydra_attribute/active_record/reflection'
32
- require 'hydra_attribute/active_record/association'
33
- require 'hydra_attribute/active_record/association_preloader'
34
- require 'hydra_attribute/active_record/migration'
35
- require 'hydra_attribute/active_record/relation'
36
- require 'hydra_attribute/active_record/relation/calculations'
37
- require 'hydra_attribute/active_record/relation/query_methods'
38
- require 'hydra_attribute/active_record/attribute_methods'
39
38
 
40
39
  require 'hydra_attribute/railtie' if defined?(Rails)
@@ -1,29 +1,50 @@
1
+ require 'hydra_attribute/active_record/attribute_methods'
2
+ require 'hydra_attribute/active_record/migration'
3
+ require 'hydra_attribute/active_record/relation'
4
+ require 'hydra_attribute/active_record/scoping'
5
+ require 'hydra_attribute/active_record/mass_assignment_security'
6
+
1
7
  module HydraAttribute
2
8
  module ActiveRecord
3
- def self.append_features(base)
4
- unless base.ancestors.include?(::ActiveRecord::Base)
5
- raise %(Cannot include HydraAttribute::ActiveRecord module because "#{base}" is not inherited from ActiveRecord::Base)
6
- end
9
+ extend ActiveSupport::Concern
7
10
 
8
- unless base.base_class.equal?(base)
9
- raise %(HydraAttribute::ActiveRecord module should be included to base class "#{base.base_class}" instead of "#{base}")
11
+ included do
12
+ unless ancestors.include?(::ActiveRecord::Base)
13
+ raise %(Cannot include HydraAttribute::ActiveRecord module because "#{self}" is not inherited from ActiveRecord::Base)
10
14
  end
11
15
 
12
- super
13
-
14
- base.extend(ClassMethods)
15
- Builder.build(base)
16
+ unless base_class.equal?(self)
17
+ raise %(HydraAttribute::ActiveRecord module should be included to the base class "#{base_class}" instead of "#{self}")
18
+ end
16
19
  end
17
20
 
21
+ include ::HydraAttribute::HydraEntity
22
+ include ::HydraAttribute::ActiveRecord::Scoping
23
+ include ::HydraAttribute::ActiveRecord::AttributeMethods
24
+ include ::HydraAttribute::ActiveRecord::MassAssignmentSecurity
25
+
18
26
  module ClassMethods
19
- def create_reflection(macro, name, options, active_record)
20
- if name.to_s.start_with?('hydra_')
21
- reflections[name] = Reflection.new(macro, name, options, active_record)
27
+ def inspect
28
+ if hydra_attributes.any?
29
+ inspection = hydra_attributes.map do |hydra_attribute|
30
+ "#{hydra_attribute.name}: #{hydra_attribute.backend_type}"
31
+ end
32
+ super.sub(/\)$/, ", #{inspection.join(', ')})")
22
33
  else
23
34
  super
24
35
  end
25
36
  end
26
37
  end
27
38
 
39
+ def inspect
40
+ if hydra_attributes.any?
41
+ inspection = hydra_attributes.keys.map do |name|
42
+ "#{name}: #{attribute_for_inspect(name)}"
43
+ end
44
+ super.sub(/>$/, ", #{inspection.join(', ')}>")
45
+ else
46
+ super
47
+ end
48
+ end
28
49
  end
29
50
  end
@@ -6,7 +6,6 @@ module HydraAttribute
6
6
  def initialize(relation, records = [])
7
7
  @relation = relation
8
8
  @records = records
9
- prepared_records # lock attributes
10
9
  end
11
10
 
12
11
  def self.run(relation, records)
@@ -16,41 +15,69 @@ module HydraAttribute
16
15
  def run
17
16
  return if records.blank?
18
17
 
19
- prepared_records.keys.each_slice(in_clause_length || prepared_records.keys.length) do |entity_ids|
20
- grouped_attribute_ids.each do |backend_type, hydra_attribute_ids|
21
- next if hydra_attribute_ids.blank?
18
+ prepared_records.keys.each_slice(in_clause_length || records.length) do |entity_ids|
19
+ grouped_hydra_attribute_ids.each do |backend_type, hydra_attribute_ids|
20
+ next if hydra_attribute_ids.blank? # entity doesn't have any hydra attributes for the current backend type
22
21
 
22
+ # set values from database
23
+ database_entity_and_hydra_attribute_ids = {}
23
24
  hydra_attribute_ids.each_slice(in_clause_length || hydra_attribute_ids.length) do |attribute_ids|
24
- value_class(backend_type).select(%w(id entity_id hydra_attribute_id value)).where(entity_id: entity_ids, hydra_attribute_id: attribute_ids).each do |model|
25
- assoc = association_builder.association_name(backend_type)
26
- prepared_records[model.entity_id].association(assoc).target.push(model)
25
+ ::ActiveRecord::Base.connection.select_all("SELECT id, entity_id, hydra_attribute_id, value FROM hydra_#{backend_type}_#{klass.table_name} WHERE entity_id IN (#{entity_ids.join(', ')}) AND hydra_attribute_id IN (#{attribute_ids.join(', ')})").each do |attributes|
26
+ # PostgreSQL driver doesn't convert values, it returns them as strings
27
+ id = attributes['id'].to_i
28
+ entity_id = attributes['entity_id'].to_i
29
+ hydra_attribute_id = attributes['hydra_attribute_id'].to_i
30
+
31
+ assign_hydra_value_options(id: id, entity_id: entity_id, hydra_attribute_id: hydra_attribute_id, value: attributes['value'])
32
+ (database_entity_and_hydra_attribute_ids[entity_id] ||= []) << hydra_attribute_id
33
+ end
34
+ end
35
+
36
+ # set nil if attribute's value is not saved into the database
37
+ # these values are not persisted
38
+ entity_ids.each do |entity_id|
39
+ missing_hydra_attribute_ids = hydra_attribute_ids - Array(database_entity_and_hydra_attribute_ids[entity_id])
40
+ missing_hydra_attribute_ids.each do |missing_hydra_attribute_id|
41
+ assign_hydra_value_options(entity_id: entity_id, hydra_attribute_id: missing_hydra_attribute_id, value: nil)
27
42
  end
28
43
  end
29
44
  end
30
45
  end
31
46
  end
32
47
 
48
+ def assign_hydra_value_options(options = {})
49
+ entity = prepared_records[options[:entity_id]]
50
+ assoc = entity.hydra_attribute_association
51
+
52
+ if entity.hydra_set_id
53
+ assoc.hydra_value_options = options.symbolize_keys if entity.hydra_set.has_hydra_attribute_id?(options[:hydra_attribute_id])
54
+ else
55
+ assoc.hydra_value_options = options.symbolize_keys
56
+ end
57
+ end
58
+
33
59
  private
34
60
  def prepared_records
35
- limit = attribute_limit?
36
61
  @prepared_records ||= records.each_with_object({}) do |record, hash|
37
- grouped_attribute_ids.each do |backend_type, hydra_attribute_ids|
38
- association = record.association(association_builder.association_name(backend_type))
39
- limit ? association.lock!(hydra_attribute_ids) : association.loaded!
40
- end
62
+ record.hydra_attribute_association.lock_values
41
63
  hash[record.id] = record
42
64
  end
43
65
  end
44
66
 
45
- def grouped_attribute_ids
46
- @grouped_attribute_ids ||= if attribute_limit?
47
- map = klass.hydra_attribute_backend_types.each_with_object({}) { |backend_type, hash| hash[backend_type] = [] }
48
- relation.hydra_select_values.each_with_object(map) do |name, grouped_ids|
49
- hydra_attribute = klass.hydra_attribute(name)
50
- grouped_ids[hydra_attribute.backend_type] << hydra_attribute.id
67
+ def grouped_hydra_attribute_ids
68
+ @grouped_hydra_attribute_ids ||= begin
69
+ hydra_attributes = ::HydraAttribute::HydraAttribute.all_by_entity_type(klass.model_name)
70
+ if attribute_limit?
71
+ map = hydra_attributes.map(&:backend_type).each_with_object({}) { |backend_type, hash| hash[backend_type] = [] }
72
+ relation.hydra_select_values.each_with_object(map) do |name, grouped_ids|
73
+ hydra_attribute = hydra_attributes.find { |attr| attr.name == name }
74
+ grouped_ids[hydra_attribute.backend_type] << hydra_attribute.id
75
+ end
76
+ else
77
+ hydra_attributes.each_with_object({}) do |hydra_attribute, hash|
78
+ (hash[hydra_attribute.backend_type] ||= []) << hydra_attribute.id
79
+ end
51
80
  end
52
- else
53
- klass.hydra_attribute_ids_by_backend_type
54
81
  end
55
82
  end
56
83
 
@@ -58,14 +85,6 @@ module HydraAttribute
58
85
  relation.select_values.any? or relation.hydra_select_values.any?
59
86
  end
60
87
 
61
- def value_class(backend_type)
62
- instance_variable_get(:"@#{backend_type}_class") || instance_variable_set(:"@#{backend_type}_class", association_builder.class_name(klass, backend_type).constantize)
63
- end
64
-
65
- def association_builder
66
- AssociationBuilder
67
- end
68
-
69
88
  def connection
70
89
  relation.connection
71
90
  end
@@ -3,156 +3,45 @@ module HydraAttribute
3
3
  module AttributeMethods
4
4
  extend ActiveSupport::Concern
5
5
 
6
- include HydraMethods
7
-
8
- NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
9
- CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
10
-
11
- included do
12
- @hydra_attribute_methods_mutex = Mutex.new
6
+ # Returns type casted attributes
7
+ #
8
+ # @return [Hash]
9
+ def attributes
10
+ super.merge(hydra_attributes)
13
11
  end
14
12
 
15
- module ClassMethods
16
- def hydra_attribute_methods_generated?
17
- base_class.instance_variable_get(:@hydra_attribute_methods_generated) || base_class.instance_variable_set(:@hydra_attribute_methods_generated, false)
18
- end
19
-
20
- def generated_hydra_attribute_methods
21
- return base_class.instance_variable_get(:@generated_hydra_attribute_methods) if base_class.instance_variable_defined?(:@generated_hydra_attribute_methods)
22
-
23
- mod = Module.new
24
- base_class.send(:include, mod)
25
- base_class.instance_variable_set(:@generated_hydra_attribute_methods, mod)
26
- end
27
-
28
- def define_hydra_attribute_methods
29
- base_class.instance_variable_get(:@hydra_attribute_methods_mutex).synchronize do
30
- return if hydra_attribute_methods_generated?
31
- hydra_attributes.each { |hydra_attribute| define_hydra_attribute_method(hydra_attribute) }
32
- base_class.instance_variable_set(:@hydra_attribute_methods_generated, true)
33
- end
34
- end
35
-
36
- def define_hydra_attribute_method(hydra_attribute)
37
- attribute_method_matchers.each do |matcher|
38
- current = matcher.method_name(hydra_attribute.name)
39
- target = matcher.method_name(:value)
40
-
41
- if current =~ NAME_COMPILABLE_REGEXP
42
- defn = "def #{current}(*args)"
43
- else
44
- defn = "define_method(:'#{current}') do |*args|"
45
- end
46
-
47
- if target =~ CALL_COMPILABLE_REGEXP
48
- send = "#{target}(*args)"
49
- else
50
- send = "send(:'#{target}', *args)"
51
- end
52
-
53
- generated_hydra_attribute_methods.module_eval <<-EOS, __FILE__, __LINE__ + 1
54
- #{defn}
55
- if hydra_set_id? and self.class.hydra_set_attribute_ids(hydra_set_id).exclude?(#{hydra_attribute.id})
56
- raise MissingAttributeInHydraSetError, %(Hydra attribute "#{hydra_attribute.name}" does not exist in hydra set "\#{self.class.hydra_set(hydra_set_id).name}")
57
- end
58
-
59
- if value_model = hydra_value_model(#{hydra_attribute.id})
60
- value_model.#{send}
61
- else
62
- missing_attribute('#{hydra_attribute.name}', caller)
63
- end
64
- end
65
- EOS
66
- end
67
- end
68
-
69
- def reset_hydra_attribute_methods!
70
- generated_hydra_attribute_methods.module_eval do
71
- instance_methods.each { |m| undef_method(m) }
72
- end
73
- base_class.instance_variable_set(:@hydra_attribute_methods_generated, false)
74
-
75
- clear_hydra_method_cache!
76
- end
77
-
78
- def undefine_attribute_methods
79
- reset_hydra_attribute_methods!
80
- super
81
- end
82
-
83
- def inspect
84
- attr_list = columns.map { |c| "#{c.name}: #{c.type}" }
85
- attr_list += hydra_attributes.map { |a| "#{a.name}: #{a.backend_type}" }
86
- "#{name}(#{attr_list.join(', ')})"
87
- end
13
+ # Returns attributes before type casting
14
+ #
15
+ # @return [Hash]
16
+ def attributes_before_type_cast
17
+ super.merge(hydra_attributes_before_type_cast)
88
18
  end
89
19
 
90
- def respond_to?(name, include_private = false)
91
- self.class.define_hydra_attribute_methods unless self.class.hydra_attribute_methods_generated?
92
-
93
- # @COMPATIBILITY with 3.1.x active_model doesn't have "attribute_method_matcher" method
94
- if ::ActiveRecord::VERSION::STRING.start_with?('3.1.')
95
- matchers = attribute_method_matchers.partition { |m| m.prefix.empty? && m.suffix.empty? }.reverse.flatten(1)
96
- matcher = matchers.detect { |method| method.match(name) }
97
- attr_name = matcher.match(name).attr_name
98
- else
99
- attr_name = self.class.send(:attribute_method_matcher, name).attr_name
100
- end
101
-
102
- if self.class.hydra_attribute_names.include?(attr_name)
103
- self.class.hydra_set_attribute_names(hydra_set_id).include?(attr_name)
20
+ # Read type cast attribute value by its name
21
+ #
22
+ # @param [String,Symbol] name
23
+ # @return [Hash]
24
+ def read_attribute(name)
25
+ name = name.to_s
26
+ if hydra_attributes.has_key?(name)
27
+ hydra_attributes[name]
104
28
  else
105
29
  super
106
30
  end
107
31
  end
108
32
 
109
- def attributes
110
- hydra_value_models.each_with_object(super) do |model, attributes|
111
- attributes[model.hydra_attribute_name] = model.read_attribute('value')
112
- end
113
- end
114
-
115
- def attributes_before_type_cast
116
- hydra_value_models.each_with_object(super) do |model, attributes|
117
- attributes[model.hydra_attribute_name] = model.read_attribute_before_type_cast('value')
118
- end
119
- end
120
-
121
- %w(read_attribute read_attribute_before_type_cast).each do |method|
122
- class_eval <<-EOS, __FILE__, __LINE__ + 1
123
- def #{method}(attr_name)
124
- identifier = attr_name.to_s
125
- if self.class.hydra_set_attribute_names(hydra_set_id).include?(identifier)
126
- if value_model = hydra_value_model(identifier)
127
- value_model.#{method}('value')
128
- else
129
- missing_attribute(identifier, caller)
130
- end
131
- else
132
- super
133
- end
134
- end
135
- EOS
136
- end
137
-
138
- def inspect
139
- attrs = hydra_value_models.map { |model| "#{model.hydra_attribute_name}: #{model.attribute_for_inspect('value')}" }
140
- super.gsub(/>$/, ", #{attrs.join(', ')}>")
33
+ # Assigns attributes to the model
34
+ #
35
+ # @param [Hash] new_attributes
36
+ # @param [Hash] options
37
+ # @return [NilClass]
38
+ def assign_attributes(new_attributes, options = {})
39
+ if new_attributes[:hydra_set_id]
40
+ # set :hydra_set_id attribute as a last attribute to avoid HydraAttribute::HydraSet::MissingAttributeInHydraSetError error
41
+ new_attributes[:hydra_set_id] = new_attributes.delete(:hydra_set_id)
42
+ end
43
+ super
141
44
  end
142
-
143
- private
144
- def method_missing(method, *args, &block)
145
- if self.class.hydra_attribute_methods_generated?
146
- super
147
- else
148
- self.class.define_hydra_attribute_methods
149
- if respond_to_without_attributes?(method)
150
- send(method, *args, &block)
151
- else
152
- super
153
- end
154
- end
155
- end
156
45
  end
157
46
  end
158
47
  end