hydra_attribute 0.3.2 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGELOG.md +1 -1
  2. data/README.md +7 -0
  3. data/features/entity/create.feature +128 -0
  4. data/features/entity/destroy.feature +111 -0
  5. data/features/entity/new.feature +121 -0
  6. data/features/entity/update.feature +147 -0
  7. data/features/{attributes → hydra_attribute}/create.feature +7 -7
  8. data/features/{attributes → hydra_attribute}/destroy.feature +2 -4
  9. data/features/{attributes → hydra_attribute}/update.feature +10 -10
  10. data/features/hydra_set/destroy.feature +31 -0
  11. data/features/migrations/create_and_drop.feature +165 -0
  12. data/features/migrations/migrate_and_rollback.feature +211 -0
  13. data/features/relation/query_methods/group.feature +42 -0
  14. data/features/relation/query_methods/order.feature +67 -0
  15. data/features/relation/query_methods/reorder.feature +29 -0
  16. data/features/relation/query_methods/reverse_order.feature +29 -0
  17. data/features/relation/query_methods/select.feature +50 -0
  18. data/features/relation/query_methods/where.feature +70 -0
  19. data/features/step_definitions/connections.rb +65 -0
  20. data/features/step_definitions/model_steps.rb +79 -6
  21. data/features/step_definitions/query_methods.rb +3 -3
  22. data/features/step_definitions/record_steps.rb +3 -4
  23. data/features/support/env.rb +17 -3
  24. data/features/support/world.rb +15 -10
  25. data/gemfiles/3.1.gemfile.lock +15 -15
  26. data/gemfiles/3.2.gemfile.lock +15 -15
  27. data/lib/hydra_attribute/active_record/association.rb +74 -38
  28. data/lib/hydra_attribute/active_record/association_preloader.rb +49 -49
  29. data/lib/hydra_attribute/active_record/attribute_methods.rb +37 -85
  30. data/lib/hydra_attribute/active_record/migration.rb +2 -2
  31. data/lib/hydra_attribute/active_record/reflection.rb +1 -1
  32. data/lib/hydra_attribute/active_record/relation/query_methods.rb +8 -7
  33. data/lib/hydra_attribute/active_record/relation.rb +1 -0
  34. data/lib/hydra_attribute/active_record.rb +20 -12
  35. data/lib/hydra_attribute/association_builder.rb +1 -2
  36. data/lib/hydra_attribute/builder.rb +7 -8
  37. data/lib/hydra_attribute/entity_callbacks.rb +12 -32
  38. data/lib/hydra_attribute/hydra_attribute.rb +25 -16
  39. data/lib/hydra_attribute/hydra_attribute_methods.rb +85 -0
  40. data/lib/hydra_attribute/hydra_methods.rb +123 -0
  41. data/lib/hydra_attribute/hydra_set.rb +36 -0
  42. data/lib/hydra_attribute/hydra_set_methods.rb +39 -0
  43. data/lib/hydra_attribute/hydra_value_methods.rb +14 -0
  44. data/lib/hydra_attribute/memoize.rb +37 -0
  45. data/lib/hydra_attribute/migrator.rb +100 -51
  46. data/lib/hydra_attribute/railtie.rb +1 -3
  47. data/lib/hydra_attribute/version.rb +1 -1
  48. data/lib/hydra_attribute.rb +7 -1
  49. data/spec/hydra_attribute_methods_spec.rb +458 -0
  50. data/spec/hydra_attribute_spec.rb +19 -0
  51. data/spec/hydra_methods_spec.rb +457 -0
  52. data/spec/hydra_set_methods_spec.rb +203 -0
  53. data/spec/hydra_set_spec.rb +19 -0
  54. data/spec/memoize_spec.rb +95 -0
  55. data/spec/spec_helper.rb +42 -2
  56. metadata +71 -43
  57. data/features/create.feature +0 -47
  58. data/features/define.feature +0 -38
  59. data/features/destroy.feature +0 -102
  60. data/features/query_methods/group.feature +0 -42
  61. data/features/query_methods/order.feature +0 -99
  62. data/features/query_methods/select.feature +0 -50
  63. data/features/query_methods/where.feature +0 -70
  64. data/features/support/schema.rb +0 -79
  65. data/features/update.feature +0 -114
@@ -0,0 +1,70 @@
1
+ Feature: hydra attribute where conditions
2
+ When filter by hydra attribute and this value is not nil
3
+ Then records with this attribute should be selected
4
+
5
+ When filter by hydra attribute and this value is nil
6
+ Then records with nil and blank value should be selected
7
+
8
+ Background: create hydra attributes
9
+ Given create hydra attributes for "Product" with role "admin" as "hashes":
10
+ | name | backend_type | white_list |
11
+ | code | string | [bool:t] |
12
+ | summary | string | [bool:t] |
13
+ | title | string | [bool:t] |
14
+ | price | float | [bool:t] |
15
+ | active | boolean | [bool:t] |
16
+ | state | integer | [bool:t] |
17
+
18
+ Scenario: filter by one hydra attribute
19
+ Given create "Product" model with attributes as "hashes":
20
+ | code | price |
21
+ | 1 | 2.75 |
22
+ | 2 | 2.75 |
23
+ | 3 | 2.76 |
24
+ | 4 | |
25
+ When filter "Product" by:
26
+ | field | value |
27
+ | price | 2.75 |
28
+ Then total records should be "2"
29
+ And records should have the following attributes:
30
+ | field | value |
31
+ | code | 1 |
32
+ | code | 2 |
33
+
34
+ Scenario: filter by one hydra attribute with nil value
35
+ Given create "Product" model with attributes as "hashes":
36
+ | code | price |
37
+ | 1 | |
38
+ | 2 | 0 |
39
+ | 3 | |
40
+ When filter "Product" by:
41
+ | field | value |
42
+ | price | [nil:] |
43
+ Then total records should be "2"
44
+ And records should have the following attributes:
45
+ | field | value |
46
+ | code | 1 |
47
+ | code | 3 |
48
+
49
+ Scenario: filter by several fields including both the hydra and general attributes
50
+ Given create "Product" model with attributes as "hashes":
51
+ | name | code | title | price | active | state | summary |
52
+ | toy | 1 | story | 2.40 | 1 | | |
53
+ | toy | 2 | story | 2.45 | 1 | | |
54
+ | toy | 3 | story | 2.45 | 1 | | |
55
+ | toy | 4 | | 2.45 | 0 | | |
56
+ | | 5 | | 2.45 | 1 | | |
57
+ | toy | 6 | | 2.46 | 1 | | |
58
+ When filter "Product" by:
59
+ | field | value |
60
+ | name | toy |
61
+ | title | story |
62
+ | summary | [nil:] |
63
+ | price | [float:2.45] |
64
+ | active | [bool:t] |
65
+ | state | [nil:] |
66
+ Then total records should be "2"
67
+ And records should have the following attributes:
68
+ | field | value |
69
+ | code | 2 |
70
+ | code | 3 |
@@ -0,0 +1,65 @@
1
+ Given /^create connection$/ do
2
+ spec = ActiveRecord::Base::ConnectionSpecification.new({database: ':memory:', adapter: 'sqlite3'}, 'sqlite3_connection')
3
+ @connection = ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec).connection
4
+ end
5
+
6
+ Given /^(create|drop|migrate|rollback)(?:\sto|\sfrom)? hydra entity "([^"]+)"$/ do |method, table|
7
+ HydraAttribute::Migrator.send(method, @connection, table)
8
+ end
9
+
10
+ Given /^create table "([^"]+)"$/ do |table|
11
+ @connection.create_table(table)
12
+ end
13
+
14
+ Then /^should have the following (\d+) tables?:$/ do |count, table|
15
+ @connection.should have(count.to_i).tables
16
+
17
+ table.rows.flatten.each do |name|
18
+ @connection.tables.should include(name)
19
+ end
20
+ end
21
+
22
+ Then /^should not have any tables$/ do
23
+ @connection.should have(0).tables
24
+ end
25
+
26
+ Then /^table "([^"]+)" should have the following (columns|indexes):$/ do |table_name, method, table|
27
+ connection_params = @connection.send(method, table_name).sort_by(&:name)
28
+ checked_params = table.hashes.map { |hash| type_cast_hash(hash) }.sort_by { |param| param['name'] }
29
+
30
+ unless connection_params.length == checked_params.length
31
+ raise %(Table "#{table_name}" has "#{connection_params.length}" #{method} but in our test "#{checked_params.length}". Diff: is "#{connection_params.map(&:name)}" but should be "#{checked_params.map { |h| h['name'] }}")
32
+ end
33
+
34
+ connection_params.zip(checked_params).each do |(real_params, params)|
35
+ params.keys.each do |name|
36
+ params[name].should == real_params.send(name)
37
+ end
38
+ end
39
+ end
40
+
41
+ Then /^table "([^"]+)" should have (\d+) records?$/ do |table_name, count|
42
+ result = ActiveRecord::Base.connection.select_one("SELECT COUNT(*) AS count FROM #{table_name}")
43
+ result['count'].should == count.to_i
44
+ end
45
+
46
+ Then /^table "([^"]+)" should have (\d+) records?:$/ do |table_name, count, table|
47
+ step %(table "#{table_name}" should have #{count} records)
48
+
49
+ table.hashes.each do |hash|
50
+ table = Arel::Table.new(table_name, ActiveRecord::Base)
51
+ select = Arel.sql('COUNT(*)').as('count')
52
+ where = hash.map { |name, value| table[name].eq(type_cast_value(value)) }.inject(:and)
53
+
54
+ result = ActiveRecord::Base.connection.select_one(table.project(select).where(where))
55
+ unless result['count']
56
+ raise %(Query "#{table.project(select).where(where).to_sql}" return nil)
57
+ end
58
+
59
+ unless result['count'] == 1
60
+ raise %(Query "#{table.project(select).where(where).to_sql}" return "#{result['count']}")
61
+ end
62
+ result['count'].should be(1)
63
+ end
64
+ end
65
+
@@ -6,6 +6,34 @@ Given /^create "([^"]+)" model$/ do |klass|
6
6
  klass.constantize.create!
7
7
  end
8
8
 
9
+ Given /^build "([^"]+)" model$/ do |klass|
10
+ @model = klass.constantize.new
11
+ end
12
+
13
+ Given /^build "([^"]+)" model:$/ do |klass, table|
14
+ @model = klass.constantize.new(type_cast_hash(table.rows_hash))
15
+ end
16
+
17
+ When /^set "([^"]+)" to "([^"]+)"$/ do |attribute, value|
18
+ @model.send("#{attribute}=", type_cast_value(value))
19
+ end
20
+
21
+ When /^(save|destroy) model$/ do |method|
22
+ @model.send(method)
23
+ end
24
+
25
+ When /^find "([^"]+)" model by attribute "([^"]+)" and value "([^"]+)"$/ do |class_name, attribute, value|
26
+ @model = class_name.constantize.send("find_by_#{attribute}", type_cast_value(value))
27
+ end
28
+
29
+ When /^find (first|last) "([^"]+)" model$/ do |method, class_name|
30
+ @model = class_name.constantize.send(method)
31
+ end
32
+
33
+ When /^reload model$/ do
34
+ @model.reload
35
+ end
36
+
9
37
  Given /^create "([^"]+)" model with attributes as "([^"]+):"$/ do |klass, format, table|
10
38
  Array.wrap(table.send(format)).each do |hash|
11
39
  klass.constantize.create!(type_cast_hash(hash))
@@ -18,6 +46,26 @@ Given /^create hydra attributes for "([^"]+)" with role "([^"]+)" as "([^"]+)":$
18
46
  end
19
47
  end
20
48
 
49
+ Given /^create hydra sets for "([^"]+)" as "([^"]+)":$/ do |klass, format, table|
50
+ Array.wrap(table.send(format)).each do |hash|
51
+ step %(create hydra set "#{hash['name']}" for "#{klass}")
52
+ end
53
+ end
54
+
55
+ Given /^create hydra set "([^"]+)" for "([^"]+)"$/ do |hydra_set_name, klass|
56
+ klass.constantize.hydra_sets.create!(name: type_cast_value(hydra_set_name))
57
+ end
58
+
59
+ Given /^add "([^"]+)" hydra attributes to hydra set:$/ do |klass, table|
60
+ klass = klass.constantize
61
+
62
+ Array.wrap(table.hashes).each do |hash|
63
+ Array.wrap(type_cast_value(hash['hydra set name'])).each do |set|
64
+ klass.hydra_sets.find_by_name(set).hydra_attributes << klass.hydra_attributes.find_by_name(type_cast_value(hash['hydra attribute name']))
65
+ end
66
+ end
67
+ end
68
+
21
69
  Given /^(load and )?(save|create|update(?: all| attributes)?|destroy(?: all)?|delete(?: all)?)(?: for)? "([^"]+)" models? with attributes as "([^"]+)":$/ do |load, action, klass, format, table|
22
70
  action = action.gsub(' ', '_')
23
71
  klass = klass.constantize
@@ -30,20 +78,45 @@ Given /^(load and )?(save|create|update(?: all| attributes)?|destroy(?: all)?|de
30
78
  end
31
79
  end
32
80
 
33
- Then /^model "([^"]+)" (should(?:\snot)?) respond to "([^"]+)"$/ do |klass, method, attributes|
34
- model = klass.constantize.new
81
+ Then /^model (should(?:\snot)?) respond to "([^"]+)"$/ do |method, attributes|
82
+ method = method.gsub(/\s+/, '_')
83
+ attributes.split.each do |attribute|
84
+ @model.send(method, respond_to(attribute))
85
+ end
86
+ end
87
+
88
+ Then /^model attributes (should(?:\snot)?) include "([^"]+)"$/ do |method, attributes|
35
89
  method = method.gsub(/\s+/, '_')
36
90
  attributes.split.each do |attribute|
37
- model.send(method, respond_to(attribute))
91
+ @model.attributes.keys.send(method, include(attribute))
38
92
  end
39
93
  end
40
94
 
41
- Then /^(last|first) created "([^"]+)" (should|should not) have the following attributes:$/ do |method, klass, match, table|
42
- table.rows_hash.each_with_object(klass.constantize.send(method)) do |(attribute, value), model|
43
- model.send(attribute).send(match) == type_cast_value(value)
95
+ Then /^model attributes (should(?:\snot)?) match "([^"]+)"$/ do |match, attribute|
96
+ @model.attributes.keys.send(match) =~ Array(type_cast_value(attribute))
97
+ end
98
+
99
+ Then /^model "([^"]+)" (should(?:\snot)?) respond to "([^"]+)"$/ do |klass, method, attributes|
100
+ @model = klass.constantize.new
101
+ step %(model #{method} respond to "#{attributes}")
102
+ end
103
+
104
+ Then /^error "([^"]+)" (should(?:\snot)?) be risen when methods? "([^"]+)" (?:is|are) called$/ do |error_class, expect, methods|
105
+ Array.wrap(methods.split).each do |method|
106
+ lambda { @model.send(method) }.send(expect.gsub(/\s+/, '_'), raise_error(error_class.constantize))
44
107
  end
45
108
  end
46
109
 
110
+ Then /^(last|first) created "([^"]+)" (should|should not) have the following attributes:$/ do |position, klass, match, table|
111
+ table.rows_hash.each do |attribute, value|
112
+ step %(#{position} created "#{klass}" #{match} have attribute "#{attribute}" with value "#{value}")
113
+ end
114
+ end
115
+
116
+ Then /^(last|first) created "([^"]+)" (should|should not) have attribute "([^"]+)" with value "([^"]+)"$/ do |position, klass, match, attribute, value|
117
+ klass.constantize.send(position).send(attribute).send(match) == type_cast_value(value)
118
+ end
119
+
47
120
  Then /^class "([^"]+)" (should(?:\snot)?) have "([^"]+)" in white list$/ do |klass, accept, attribute|
48
121
  method = accept.sub(' ', '_')
49
122
  klass.constantize.accessible_attributes.send(method, include(attribute))
@@ -5,7 +5,7 @@ end
5
5
 
6
6
  When /^filter "([^"]+)" records by "([^"]+)"$/ do |klass, attribute|
7
7
  @records = Object.const_get(klass)
8
- step %Q(filter records by "#{attribute}")
8
+ step %(filter records by "#{attribute}")
9
9
  end
10
10
 
11
11
  When /^filter records by "([^"]+)"$/ do |attribute|
@@ -15,7 +15,7 @@ end
15
15
 
16
16
  When /^group "([^"]+)" by "([^"]+)"$/ do |klass, attributes|
17
17
  @records = Object.const_get(klass)
18
- step %Q(group by "#{attributes}")
18
+ step %(group by "#{attributes}")
19
19
  end
20
20
 
21
21
  When /^group by "([^"]+)"$/ do |attributes|
@@ -24,7 +24,7 @@ end
24
24
 
25
25
  When /^(order|reorder) "([^"]+)" records by "([^"]+)"$/ do |sort_method, klass, attributes|
26
26
  @records = Object.const_get(klass)
27
- step %Q(#{sort_method} records by "#{attributes}")
27
+ step %(#{sort_method} records by "#{attributes}")
28
28
  end
29
29
 
30
30
  When /^(order|reorder) records by "([^"]+)"$/ do |sort_method, attributes|
@@ -58,11 +58,10 @@ Then /^records should have only the following "([^"]+)" names$/ do |attributes|
58
58
  end
59
59
  end
60
60
 
61
- Then /^records should raise "([^"]+)" when call the following "([^"]+)"$/ do |error, methods|
62
- error_class = error.constantize
61
+ Then /^records should raise "([^"]+)" when call the following "([^"]+)"$/ do |error_class, methods|
63
62
  @records.each do |record|
64
63
  methods.split(/\s+/).each do |method|
65
- lambda { record.send(method) }.should raise_error(error_class)
64
+ lambda { record.send(method) }.should raise_error(error_class.constantize)
66
65
  end
67
66
  end
68
67
  end
@@ -73,7 +72,7 @@ end
73
72
 
74
73
  Then /^total "([^"]+)" records should be "([^"]+)"$/ do |klass, count|
75
74
  @records = klass.constantize.scoped
76
- step %Q(total records should be "#{count}")
75
+ step %(total records should be "#{count}")
77
76
  end
78
77
 
79
78
  Then /^records "(should|should_not)" have loaded associations:$/ do |should, table|
@@ -1,19 +1,33 @@
1
1
  require 'active_record'
2
2
  require 'hydra_attribute'
3
3
  require 'database_cleaner'
4
- require 'database_cleaner/cucumber'
5
4
 
6
5
  ActiveSupport.on_load(:active_record) do
7
6
  self.default_timezone = :utc
8
- unless ActiveRecord::VERSION::STRING.start_with?('3.1.')
7
+ unless ActiveRecord::VERSION::STRING.start_with?('3.1.') # @COMPATIBILITY with 3.1.x. active_record 3.1 doesn't have "mass_assignment_sanitizer" method
9
8
  self.mass_assignment_sanitizer = :strict
10
9
  end
11
- extend HydraAttribute::ActiveRecord
10
+
11
+ ActiveRecord::Migration.send(:include, HydraAttribute::ActiveRecord::Migration)
12
12
  end
13
13
 
14
14
  ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
15
15
  DatabaseCleaner.strategy = :truncation
16
16
 
17
+ class Migration < ActiveRecord::Migration
18
+ def up
19
+ create_hydra_entity :products do |t|
20
+ t.string :name
21
+ t.timestamps
22
+ end
23
+ end
24
+
25
+ def down
26
+ end
27
+ end
28
+
29
+ Migration.new.up
30
+
17
31
  Before do
18
32
  redefine_hydra_entity('Product')
19
33
  DatabaseCleaner.start
@@ -3,15 +3,19 @@ module HydraAttribute
3
3
  module World
4
4
  def type_cast_value(schema)
5
5
  return schema unless schema.is_a?(String)
6
- type, value = schema.gsub(/\[|\]/, '').split(':', 2)
6
+ type, value = schema.gsub(/(^\[)|(\]$)/, '').split(':', 2)
7
7
  return schema if schema == type && value.nil?
8
8
 
9
9
  case type
10
- when 'integer' then value.to_i
11
- when 'float' then value.to_f
12
- when 'boolean' then value == 'true' ? true : false
13
- when 'nil' then nil
14
- when 'datetime' then ActiveSupport::TimeZone.new('UTC').parse(value)
10
+ when 'int' then type_cast_value(value).to_i
11
+ when 'float' then type_cast_value(value).to_f
12
+ when 'bool' then ::ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(type_cast_value(value))
13
+ when 'nil' then nil
14
+ when 'date' then ActiveSupport::TimeZone.new('UTC').parse(type_cast_value(value))
15
+ when 'sym' then type_cast_value(value).to_sym
16
+ when 'array' then value.split(',').map { |v| type_cast_value(v) }
17
+ when 'eval' then eval(type_cast_value(value))
18
+ when 'str' then type_cast_value(value).to_s
15
19
  else value
16
20
  end
17
21
  end
@@ -22,7 +26,8 @@ module HydraAttribute
22
26
  end
23
27
 
24
28
  def type_cast_attributes(attributes)
25
- attributes.split(/(?<=\])\s+/).flatten.each_with_object({}) do |attribute, hash|
29
+ # 'a=[b c] c=a c=[v abc]' => ["a=[b c]", "c=a", "c=[v abc]"]
30
+ attributes.gsub(/\s+(\w+=)/, '<###>\1').split('<###>').each_with_object({}) do |attribute, hash|
26
31
  name, value = type_cast_attribute(attribute)
27
32
  hash[name] = value
28
33
  end
@@ -39,15 +44,15 @@ module HydraAttribute
39
44
 
40
45
  Object.send(:remove_const, klass.to_sym) if Object.const_defined?(klass.to_sym)
41
46
 
42
- ::HydraAttribute::SUPPORT_TYPES.each do |type|
47
+ ::HydraAttribute::SUPPORTED_BACKEND_TYPES.each do |type|
43
48
  class_name = "Hydra#{type.capitalize}#{klass}".to_sym
44
49
  ::HydraAttribute.send(:remove_const, class_name) if ::HydraAttribute.const_defined?(class_name)
45
50
  end
46
51
 
47
52
  Object.const_set(klass.to_sym, Class.new(::ActiveRecord::Base))
48
53
  klass.to_s.constantize.send(:accessible_attributes_configs).values.each(&:clear)
49
- klass.to_s.constantize.attr_accessible :name
50
- klass.to_s.constantize.use_hydra_attributes
54
+ klass.to_s.constantize.attr_accessible :name, :hydra_set_id
55
+ klass.to_s.constantize.send(:include, ::HydraAttribute::ActiveRecord)
51
56
  end
52
57
  end
53
58
  end
@@ -1,22 +1,22 @@
1
1
  PATH
2
2
  remote: /Users/kostyantyn/Sites/github/gems/hydra_attribute
3
3
  specs:
4
- hydra_attribute (0.3.2.beta)
4
+ hydra_attribute (0.4.0.beta)
5
5
  activerecord (>= 3.1.0)
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
- activemodel (3.1.6)
11
- activesupport (= 3.1.6)
10
+ activemodel (3.1.7)
11
+ activesupport (= 3.1.7)
12
12
  builder (~> 3.0.0)
13
13
  i18n (~> 0.6)
14
- activerecord (3.1.6)
15
- activemodel (= 3.1.6)
16
- activesupport (= 3.1.6)
14
+ activerecord (3.1.7)
15
+ activemodel (= 3.1.7)
16
+ activesupport (= 3.1.7)
17
17
  arel (~> 2.2.3)
18
18
  tzinfo (~> 0.3.29)
19
- activesupport (3.1.6)
19
+ activesupport (3.1.7)
20
20
  multi_json (>= 1.0, < 1.3)
21
21
  appraisal (0.4.1)
22
22
  bundler
@@ -33,17 +33,17 @@ GEM
33
33
  gherkin (2.11.1)
34
34
  json (>= 1.4.6)
35
35
  i18n (0.6.0)
36
- json (1.7.3)
36
+ json (1.7.4)
37
37
  multi_json (1.2.0)
38
38
  rake (0.9.2.2)
39
- rspec (2.10.0)
40
- rspec-core (~> 2.10.0)
41
- rspec-expectations (~> 2.10.0)
42
- rspec-mocks (~> 2.10.0)
43
- rspec-core (2.10.1)
44
- rspec-expectations (2.10.0)
39
+ rspec (2.11.0)
40
+ rspec-core (~> 2.11.0)
41
+ rspec-expectations (~> 2.11.0)
42
+ rspec-mocks (~> 2.11.0)
43
+ rspec-core (2.11.1)
44
+ rspec-expectations (2.11.2)
45
45
  diff-lcs (~> 1.1.3)
46
- rspec-mocks (2.10.1)
46
+ rspec-mocks (2.11.1)
47
47
  sqlite3 (1.3.6)
48
48
  tzinfo (0.3.33)
49
49
 
@@ -1,21 +1,21 @@
1
1
  PATH
2
2
  remote: /Users/kostyantyn/Sites/github/gems/hydra_attribute
3
3
  specs:
4
- hydra_attribute (0.3.2.beta)
4
+ hydra_attribute (0.4.0.beta)
5
5
  activerecord (>= 3.1.0)
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
- activemodel (3.2.6)
11
- activesupport (= 3.2.6)
10
+ activemodel (3.2.7)
11
+ activesupport (= 3.2.7)
12
12
  builder (~> 3.0.0)
13
- activerecord (3.2.6)
14
- activemodel (= 3.2.6)
15
- activesupport (= 3.2.6)
13
+ activerecord (3.2.7)
14
+ activemodel (= 3.2.7)
15
+ activesupport (= 3.2.7)
16
16
  arel (~> 3.0.2)
17
17
  tzinfo (~> 0.3.29)
18
- activesupport (3.2.6)
18
+ activesupport (3.2.7)
19
19
  i18n (~> 0.6)
20
20
  multi_json (~> 1.0)
21
21
  appraisal (0.4.1)
@@ -33,17 +33,17 @@ GEM
33
33
  gherkin (2.11.1)
34
34
  json (>= 1.4.6)
35
35
  i18n (0.6.0)
36
- json (1.7.3)
36
+ json (1.7.4)
37
37
  multi_json (1.3.6)
38
38
  rake (0.9.2.2)
39
- rspec (2.10.0)
40
- rspec-core (~> 2.10.0)
41
- rspec-expectations (~> 2.10.0)
42
- rspec-mocks (~> 2.10.0)
43
- rspec-core (2.10.1)
44
- rspec-expectations (2.10.0)
39
+ rspec (2.11.0)
40
+ rspec-core (~> 2.11.0)
41
+ rspec-expectations (~> 2.11.0)
42
+ rspec-mocks (~> 2.11.0)
43
+ rspec-core (2.11.1)
44
+ rspec-expectations (2.11.2)
45
45
  diff-lcs (~> 1.1.3)
46
- rspec-mocks (2.10.1)
46
+ rspec-mocks (2.11.1)
47
47
  sqlite3 (1.3.6)
48
48
  tzinfo (0.3.33)
49
49
 
@@ -2,76 +2,112 @@ module HydraAttribute
2
2
  module ActiveRecord
3
3
  class Association < ::ActiveRecord::Associations::HasManyAssociation
4
4
 
5
- def find_model(attributes = {})
5
+ def find_model(hydra_attribute_id)
6
6
  load_target unless loaded?
7
- target.detect do |model|
8
- model.hydra_attribute_id == attributes[:hydra_attribute_id]
7
+
8
+ hydra_set_target.detect do |model|
9
+ model.hydra_attribute_id == hydra_attribute_id
9
10
  end
10
11
  end
11
12
 
12
- def find_model_or_build(attributes = {})
13
- find_model(attributes) || build(attributes)
13
+ def find_model_or_build(options = {})
14
+ find_model(options[:hydra_attribute_id]) || build(options)
14
15
  end
15
16
 
16
17
  def build(attributes = {}, options = {}, &block)
17
- return if locked_for_build? and white_list_for_build.exclude?(attributes[:hydra_attribute_id])
18
+ return if hydra_attribute_ids.exclude?(attributes[:hydra_attribute_id])
19
+ return if target.any? { |model| model.hydra_attribute_id == attributes[:hydra_attribute_id] }
20
+
18
21
  super
19
22
  end
20
23
 
21
24
  def all_models
22
25
  unless @full_loaded
23
- (all_attribute_ids - target.map(&:hydra_attribute_id)).each do |hydra_attribute_id|
26
+ (hydra_attribute_ids - target.map(&:hydra_attribute_id)).each do |hydra_attribute_id|
24
27
  build(hydra_attribute_id: hydra_attribute_id)
25
28
  end
26
29
  @full_loaded = true
27
30
  end
28
- target
31
+ hydra_set_target
29
32
  end
30
33
 
31
- def locked_for_build
32
- @locked_for_build ||= false
34
+ def save
35
+ changed = false
36
+ all_models.each do |model|
37
+ model.entity_id = owner.id
38
+ model.save
39
+ changed = true unless model.previous_changes.blank?
40
+ end
41
+ changed
33
42
  end
34
- alias_method :locked_for_build?, :locked_for_build
35
43
 
36
- def lock_for_build!(white_list_for_build = [])
37
- @locked_for_build = true
38
- @white_list_for_build = Array(white_list_for_build)
44
+ def lock!(white_list = [])
45
+ @white_list = Array(white_list)
39
46
  loaded!
40
47
  end
41
48
 
42
- def white_list_for_build
43
- @white_list_for_build ||= []
49
+ def hydra_attributes
50
+ if @white_list
51
+ @hydra_attributes ||= owner.class.hydra_set_attributes_for_backend_type(owner.hydra_set_id, reflection.backend_type)
52
+ else
53
+ owner.class.hydra_set_attributes_for_backend_type(owner.hydra_set_id, reflection.backend_type)
54
+ end
44
55
  end
45
56
 
46
- def all_attribute_ids
47
- hydra_attribute_ids = owner.class.grouped_hydra_attribute_ids(reflection.backend_type)
48
- hydra_attribute_ids &= white_list_for_build if locked_for_build?
49
- hydra_attribute_ids
57
+ def hydra_attribute_ids
58
+ if @white_list
59
+ @hydra_attribute_ids ||= owner.class.hydra_set_attribute_ids_for_backend_type(owner.hydra_set_id, reflection.backend_type) & @white_list
60
+ else
61
+ owner.class.hydra_set_attribute_ids_for_backend_type(owner.hydra_set_id, reflection.backend_type)
62
+ end
50
63
  end
51
64
 
52
- private
65
+ def hydra_attribute_names
66
+ if @white_list
67
+ hydra_attributes.map(&:name)
68
+ else
69
+ owner.class.hydra_set_attribute_names_for_backend_type(owner.hydra_set_id, reflection.backend_type)
70
+ end
71
+ end
53
72
 
54
- # Optimized method
55
- # Remove unnecessary callbacks
56
- def add_to_target(record)
57
- @target << record
58
- record
73
+ def hydra_set_target
74
+ @hydra_set_target ||= target.select do |model|
75
+ hydra_attribute_ids.include?(model.hydra_attribute_id)
76
+ end
59
77
  end
60
78
 
61
- # Optimized method
62
- # Attributes are written via low level function without additional checks
63
- def build_record(attributes, _)
64
- reflection.klass.new do |record|
65
- unless attributes.has_key?(:value)
66
- attributes[:value] = owner.class.hydra_attribute(attributes[:hydra_attribute_id]).default_value
67
- end
79
+ def clear_cache!
80
+ @hydra_attributes = nil
81
+ @hydra_attribute_ids = nil
82
+ @full_loaded = nil
83
+ @hydra_set_target = nil
84
+ end
85
+
86
+ private
68
87
 
69
- record.send :write_attribute, 'id', attributes[:id]
70
- record.send :write_attribute, 'entity_id', owner.id
71
- record.send :write_attribute, 'hydra_attribute_id', attributes[:hydra_attribute_id]
72
- record.send :write_attribute, 'value', attributes[:value]
88
+ # Optimized method
89
+ # Remove unnecessary callbacks
90
+ def add_to_target(record)
91
+ @target << record
92
+ record
93
+ end
94
+
95
+ # Optimized method
96
+ # Attributes are written via low level function without additional checks
97
+ def build_record(options, _)
98
+ reflection.klass.new do |record|
99
+ unless options.has_key?(:value)
100
+ options[:value] = owner.class.hydra_attribute(options[:hydra_attribute_id]).default_value
101
+ end
102
+
103
+ record.send :write_attribute, 'id', options[:id]
104
+ record.send :write_attribute, 'entity_id', owner.id
105
+ record.send :write_attribute, 'hydra_attribute_id', options[:hydra_attribute_id]
106
+ record.send :write_attribute, 'value', options[:value]
107
+
108
+ hydra_set_target << record unless hydra_set_target.include?(record)
109
+ end
73
110
  end
74
- end
75
111
  end
76
112
  end
77
113
  end