hydra_attribute 0.2.0 → 0.3.0.beta1

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.
Files changed (63) hide show
  1. data/README.md +74 -68
  2. data/cucumber.yml +1 -0
  3. data/features/attributes/create.feature +22 -0
  4. data/features/attributes/destroy.feature +18 -0
  5. data/features/attributes/update.feature +19 -0
  6. data/features/create.feature +47 -0
  7. data/features/define.feature +33 -0
  8. data/features/query_methods/group.feature +13 -14
  9. data/features/query_methods/order.feature +63 -52
  10. data/features/query_methods/select.feature +36 -37
  11. data/features/query_methods/where.feature +36 -38
  12. data/features/step_definitions/model_steps.rb +23 -19
  13. data/features/step_definitions/query_methods.rb +6 -2
  14. data/features/step_definitions/record_steps.rb +28 -10
  15. data/features/support/env.rb +12 -6
  16. data/features/support/schema.rb +62 -35
  17. data/features/support/world.rb +14 -5
  18. data/features/update.feature +114 -0
  19. data/gemfiles/3.1.gemfile.lock +10 -10
  20. data/gemfiles/3.2.gemfile.lock +10 -10
  21. data/lib/hydra_attribute/active_record/association.rb +77 -0
  22. data/lib/hydra_attribute/active_record/association_preloader.rb +82 -0
  23. data/lib/hydra_attribute/active_record/attribute_methods.rb +145 -37
  24. data/lib/hydra_attribute/active_record/migration.rb +21 -0
  25. data/lib/hydra_attribute/active_record/reflection.rb +16 -0
  26. data/lib/hydra_attribute/active_record/relation/query_methods.rb +73 -71
  27. data/lib/hydra_attribute/active_record/relation.rb +1 -24
  28. data/lib/hydra_attribute/active_record.rb +16 -2
  29. data/lib/hydra_attribute/association_builder.rb +44 -20
  30. data/lib/hydra_attribute/builder.rb +15 -13
  31. data/lib/hydra_attribute/configuration.rb +9 -30
  32. data/lib/hydra_attribute/entity_callbacks.rb +46 -0
  33. data/lib/hydra_attribute/hydra_attribute.rb +27 -0
  34. data/lib/hydra_attribute/migrator.rb +106 -0
  35. data/lib/hydra_attribute/railtie.rb +2 -0
  36. data/lib/hydra_attribute/version.rb +2 -2
  37. data/lib/hydra_attribute.rb +8 -6
  38. data/lib/rails/generators/hydra_attribute/install/templates/hydra_attribute.txt +4 -0
  39. data/spec/spec_helper.rb +1 -2
  40. metadata +42 -60
  41. data/features/attribute_methods.feature +0 -146
  42. data/features/define_attributes.feature +0 -56
  43. data/features/load_associations.feature +0 -40
  44. data/features/step_definitions/class_steps.rb +0 -32
  45. data/features/typecast_attributes.feature +0 -24
  46. data/lib/generators/hydra_attribute/install/templates/hydra_attribute.txt +0 -11
  47. data/lib/hydra_attribute/active_record/attribute_methods/before_type_cast.rb +0 -16
  48. data/lib/hydra_attribute/active_record/attribute_methods/read.rb +0 -13
  49. data/lib/hydra_attribute/attribute_builder.rb +0 -57
  50. data/lib/hydra_attribute/attribute_proxy.rb +0 -16
  51. data/lib/hydra_attribute/migration.rb +0 -27
  52. data/spec/hydra_attribute/active_record/relation/query_methods_spec.rb +0 -334
  53. data/spec/hydra_attribute/active_record/relation_spec.rb +0 -67
  54. data/spec/hydra_attribute/active_record/scoping_spec.rb +0 -23
  55. data/spec/hydra_attribute/active_record_spec.rb +0 -18
  56. data/spec/hydra_attribute/association_builder_spec.rb +0 -95
  57. data/spec/hydra_attribute/attribute_builder_spec.rb +0 -70
  58. data/spec/hydra_attribute/attribute_helpers_spec.rb +0 -70
  59. data/spec/hydra_attribute/builder_spec.rb +0 -39
  60. data/spec/hydra_attribute/configuration_spec.rb +0 -65
  61. data/spec/hydra_attribute_spec.rb +0 -20
  62. /data/lib/{generators → rails/generators}/hydra_attribute/install/USAGE +0 -0
  63. /data/lib/{generators → rails/generators}/hydra_attribute/install/install_generator.rb +0 -0
@@ -1,146 +0,0 @@
1
- Feature: helper methods for hydra attributes
2
- When class calls hydra_attributes
3
- Then symbolize hash with hydra attribute names and their types should be returned
4
-
5
- When class calls hydra_attribute_names
6
- Then array with symbolize hydra attribute names should be returned
7
-
8
- When class calls hydra_attribute_types
9
- Then array with symbolize hydra attribute types should be returned
10
-
11
- When model calls hydra_attributes
12
- Then stringify hash with hydra attribute names and their values should be returned
13
-
14
- When model calls attributes
15
- Then stringify hash with both native and hydra attributes should be returned
16
-
17
- When model calls attributes_before_type_cast
18
- Then stringify hash with both native and hydra attributes should be returned with values before type cast
19
-
20
- When model calls read_attribute on hydra attribute
21
- Then hydra attribute value should be returned
22
-
23
- When model calls read_attribute_before_type_cast
24
- Then hydra attribute value before type cast should be returned
25
-
26
- Background: create models and describe hydra attributes
27
- Given create model class "Product"
28
- And create model class "SimpleProduct" as "Product" with hydra attributes:
29
- | type | name |
30
- | string | code |
31
- | float | price |
32
- | text | note |
33
- And create model class "GroupProduct" as "Product" with hydra attributes:
34
- | type | name |
35
- | integer | price |
36
- | string | title |
37
- | boolean | active |
38
- | datetime | launch |
39
-
40
- Scenario Outline: class hydra_attributes
41
- Then class "<class>"::"<method>" "<behavior>" have "<param>" hash
42
-
43
- Scenarios: hydra attributes
44
- | class | method | behavior | param |
45
- | SimpleProduct | hydra_attributes | should | code=string price=float note=text |
46
- | GroupProduct | hydra_attributes | should | price=integer title=string active=boolean launch=datetime |
47
-
48
- Scenario Outline: class hydra_attribute_names
49
- Then class "<class>"::"<method>" "<behavior>" have string "<params>" in array
50
-
51
- Scenarios: hydra attribute names
52
- | class | method | behavior | params |
53
- | SimpleProduct | hydra_attribute_names | should | code price note |
54
- | SimpleProduct | hydra_attribute_names | should_not | title active launch |
55
- | GroupProduct | hydra_attribute_names | should | price title active launch |
56
- | GroupProduct | hydra_attribute_names | should_not | code note |
57
-
58
- Scenario Outline: class hydra_attribute_types
59
- Then class "<class>"::"<method>" "<behavior>" have symbol "<params>" in array
60
-
61
- Scenarios: hydra attribute types
62
- | class | method | behavior | params |
63
- | SimpleProduct | hydra_attribute_types | should | string float text |
64
- | SimpleProduct | hydra_attribute_types | should_not | integer boolean datetime |
65
- | GroupProduct | hydra_attribute_types | should | integer string boolean datetime |
66
- | GroupProduct | hydra_attribute_types | should_not | text float |
67
-
68
- Scenario Outline: model hydra_attributes
69
- Given create models:
70
- | model | attributes |
71
- | SimpleProduct | name=[string:a] info=[string:i] code=[string:c] price=[float:2] note=[string:n] |
72
- | GroupProduct | name=[string:a] info=[string:i] price=[float:2] title=[string:t] active=[boolean:true] launch=[string:2012-06-03] |
73
- When select "first" "<model>" record
74
- Then model "<model>" should have only the following hydra attributes "<attributes>"
75
- And record should have the following hydra attributes "<values>" in attribute hash
76
-
77
- Scenarios: required hydra attributes
78
- | model | attributes | values |
79
- | SimpleProduct | code price note | code=[string:c] price=[float:2] note=[string:n] |
80
- | GroupProduct | price title active launch | price=[float:2] title=[string:t] active=[boolean:true] launch=[string:2012-06-03] |
81
-
82
- Scenario Outline: model attributes
83
- Given create models:
84
- | model | attributes |
85
- | SimpleProduct | name=[string:a] info=[string:i] code=[string:c] price=[float:2] note=[string:n] |
86
- | GroupProduct | name=[string:a] info=[string:i] price=[float:2] title=[string:t] active=[boolean:true] launch=[string:2012-06-03] |
87
- When select "first" "<model>" record
88
- Then model "<model>" should have only the following attributes "<attributes>"
89
- And record should have the following attributes "<values>" in attribute hash
90
-
91
- Scenarios: required attributes
92
- | model | attributes | values |
93
- | SimpleProduct | id type name info created_at updated_at code price note | name=[string:a] info=[string:i] code=[string:c] price=[float:2] note=[string:n] |
94
- | GroupProduct | id type name info created_at updated_at price title active launch | name=[string:a] info=[string:i] price=[float:2] title=[string:t] active=[boolean:true] launch=[string:2012-06-03] |
95
-
96
- Scenario Outline: model attributes_before_type_cast
97
- Given create models:
98
- | model | attributes |
99
- | SimpleProduct | name=[string:a] info=[string:i] code=[string:c] price=[float:2] note=[string:n] |
100
- | GroupProduct | name=[string:a] info=[string:i] price=[float:2] title=[string:t] active=[boolean:true] launch=[string:2012-06-07] |
101
- When select "first" "<model>" record
102
- Then model "<model>" should have only the following attributes before type cast "<attributes>"
103
- And record should have the following attributes before type cast "<before type cast values>" in attribute hash
104
-
105
- Scenarios: required before type cast attributes
106
- | model | attributes | before type cast values |
107
- | SimpleProduct | id type name info created_at updated_at code price note | name=[string:a] info=[string:i] code=[string:c] price=[float:2] note=[string:n] |
108
- | GroupProduct | id type name info created_at updated_at price title active launch | name=[string:a] info=[string:i] price=[float:2] title=[string:t] active=[string:t] launch=[string:2012-06-07 00:00:00.000000] |
109
-
110
- Scenario Outline: model read_attributes
111
- Given create models:
112
- | model | attributes |
113
- | SimpleProduct | name=[string:a] info=[string:i] code=[string:c] price=[nil:] |
114
- | GroupProduct | name=[string:a] info=[string:i] price=[nil:] active=[boolean:true] launch=[string:2012-06-03] |
115
- When select "first" "<model>" record
116
- Then record read attribute "<attribute>" and value should be "<value>"
117
-
118
- Scenarios: read attributes
119
- | model | attribute | value |
120
- | SimpleProduct | name | [string:a] |
121
- | SimpleProduct | info | [string:i] |
122
- | SimpleProduct | code | [string:c] |
123
- | SimpleProduct | price | [nil:] |
124
- | SimpleProduct | note | [nil:] |
125
- | GroupProduct | name | [string:a] |
126
- | GroupProduct | info | [string:i] |
127
- | GroupProduct | price | [nil:] |
128
- | GroupProduct | title | [nil:] |
129
- | GroupProduct | active | [boolean:true] |
130
- | GroupProduct | launch | [datetime:2012-06-03] |
131
-
132
- Scenario Outline: model read_attributes_before_type_cast
133
- Given create models:
134
- | model | attributes |
135
- | SimpleProduct | name=[string:a] price=[float:2] |
136
- | GroupProduct | name=[string:a] active=[boolean:false] launch=[string:2012-06-03] |
137
- When select "first" "<model>" record
138
- Then record read attribute before type cast "<attribute>" and value should be "<value>"
139
-
140
- Scenarios: read attributes
141
- | model | attribute | value |
142
- | SimpleProduct | name | [string:a] |
143
- | SimpleProduct | price | [float:2] |
144
- | GroupProduct | name | [string:a] |
145
- | GroupProduct | active | [string:f] |
146
- | GroupProduct | launch | [string:2012-06-03 00:00:00.000000] |
@@ -1,56 +0,0 @@
1
- Feature: define hydra attributes
2
- Models should respond to hydra attributes
3
-
4
- Model should respond to hydra attributes if they are described in the class.
5
- Model should not respond to hydra attribute if it isn't described in it class.
6
-
7
- Background: create models and describe hydra attributes
8
- Given create model class "Product"
9
- And create model class "SimpleProduct" as "Product" with hydra attributes:
10
- | type | name |
11
- | string | code |
12
- And create model class "GroupProduct" as "Product" with hydra attributes:
13
- | type | name |
14
- | float | price |
15
-
16
- Scenario Outline: models should respond to hydra attributes
17
- Then model "<model>" should "<respond>" to "<attributes>"
18
-
19
- Scenarios: model should respond to own hydra attributes
20
- | model | respond | attributes |
21
- | SimpleProduct | should | code |
22
- | SimpleProduct | should | code= |
23
- | SimpleProduct | should | code? |
24
- | SimpleProduct | should | code_before_type_cast |
25
- | SimpleProduct | should | code_changed? |
26
- | SimpleProduct | should | code_change |
27
- | SimpleProduct | should | code_will_change! |
28
- | SimpleProduct | should | code_was |
29
- | SimpleProduct | should | reset_code! |
30
- | SimpleProduct | should_not | price |
31
- | SimpleProduct | should_not | price= |
32
- | SimpleProduct | should_not | price? |
33
- | SimpleProduct | should_not | price_before_type_cast |
34
- | SimpleProduct | should_not | price_changed? |
35
- | SimpleProduct | should_not | price_change |
36
- | SimpleProduct | should_not | price_will_change! |
37
- | SimpleProduct | should_not | price_was |
38
- | SimpleProduct | should_not | reset_price! |
39
- | GroupProduct | should | price |
40
- | GroupProduct | should | price= |
41
- | GroupProduct | should | price? |
42
- | GroupProduct | should | price_before_type_cast |
43
- | GroupProduct | should | price_changed? |
44
- | GroupProduct | should | price_change |
45
- | GroupProduct | should | price_will_change! |
46
- | GroupProduct | should | price_was |
47
- | GroupProduct | should | reset_price! |
48
- | GroupProduct | should_not | code |
49
- | GroupProduct | should_not | code= |
50
- | GroupProduct | should_not | code? |
51
- | GroupProduct | should_not | code_before_type_cast |
52
- | GroupProduct | should_not | code_changed? |
53
- | GroupProduct | should_not | code_change |
54
- | GroupProduct | should_not | code_will_change! |
55
- | GroupProduct | should_not | code_was |
56
- | GroupProduct | should_not | reset_code! |
@@ -1,40 +0,0 @@
1
- Feature: hydra attribute associations
2
- When loaded collection has more than one record
3
- Then all hydra attribute associations should be loaded
4
-
5
- When loaded collection hasn't records or has only one
6
- Then hydra attribute association should not be loaded automatically
7
-
8
- Background: create models and describe hydra attributes
9
- Given create model class "Product"
10
- And create model class "SimpleProduct" as "Product" with hydra attributes:
11
- | type | name |
12
- | string | code |
13
- | float | price |
14
- And create model class "GroupProduct" as "Product" with hydra attributes:
15
- | type | name |
16
- | float | price |
17
- | string | title |
18
- | boolean | active |
19
-
20
- Scenario: hydra attribute associations should be included for collection with more then one record
21
- Given create models:
22
- | model | attributes |
23
- | SimpleProduct | code=[integer:1] |
24
- | SimpleProduct | code=[integer:2] |
25
- When load all "SimpleProduct" records
26
- Then records "should" have loaded associations:
27
- | association |
28
- | hydra_string_attributes |
29
- | hydra_float_attributes |
30
-
31
- Scenario: hydra attribute associations should not be included for collection with one record
32
- Given create models:
33
- | model | attributes |
34
- | GroupProduct | price=[float:2.75] |
35
- When load all "GroupProduct" records
36
- Then records "should_not" have loaded associations:
37
- | association |
38
- | hydra_float_attributes |
39
- | hydra_string_attributes |
40
- | hydra_boolean_attributes |
@@ -1,32 +0,0 @@
1
- Given /^removed constants if they exist:$/ do |table|
2
- table.hashes.each do |hash|
3
- Object.send(:remove_const, hash[:name]) if Object.const_defined?(hash[:name])
4
- end
5
- end
6
-
7
- Given /^create model class "([^"]+)"$/ do |klass|
8
- Object.const_set(klass, Class.new(ActiveRecord::Base))
9
- end
10
-
11
- Given /^create model class "([^"]+)" as "([^"]+)" with hydra attributes:$/ do |klass, sti_class, table|
12
- Object.const_set klass, Class.new(Object.const_get(sti_class)) {
13
- define_hydra_attributes do
14
- table.hashes.each do |hash|
15
- send(hash[:type], hash[:name].to_sym)
16
- end
17
- end
18
- }
19
- end
20
-
21
- Then /^class "([^"]+)"::"([^"]+)" "(should|should_not)" have (string|symbol) "([^"]+)" in array$/ do |klass, method, behavior, type, params|
22
- klass = Object.const_get(klass)
23
- params = params.split
24
- params.map!(&:to_sym) if type == 'symbol'
25
- klass.send(method).send(behavior) =~ params
26
- end
27
-
28
- Then /^class "([^"]+)"::"([^"]+)" "(should|should_not)" have "([^"]+)" hash$/ do |klass, method, behavior, params|
29
- klass = Object.const_get(klass)
30
- array = params.split.map{ |item| item.split('=').map(&:to_sym) }
31
- klass.send(method).send(behavior) == Hash[array].stringify_keys
32
- end
@@ -1,24 +0,0 @@
1
- Feature: create model
2
- Model should be created with typecast hydra attributes.
3
-
4
- Background: create models and describe hydra attributes
5
- Given create model class "Product"
6
- And create model class "SimpleProduct" as "Product" with hydra attributes:
7
- | type | name |
8
- | string | code |
9
- | float | price |
10
- And create model class "GroupProduct" as "Product" with hydra attributes:
11
- | type | name |
12
- | float | price |
13
- | string | title |
14
- | boolean | active |
15
-
16
- Scenario Outline: create model with hydra attributes
17
- Given create model "<model>" with attributes "<attributes>"
18
- Then it should have typecast attributes "<typecast_attributes>"
19
-
20
- Scenarios:
21
- | model | attributes | typecast_attributes |
22
- | SimpleProduct | code=[integer:1] price=[string:2.75] | code=[string:1] price=[float:2.75] |
23
- | GroupProduct | price=[string:2] title=[integer:1] active=[integer:1] | price=[float:2] title=[string:1] active=[boolean:true] |
24
- | GroupProduct | active=[integer:0] | price=[nil:] title=[nil:] active=[boolean:false] |
@@ -1,11 +0,0 @@
1
- # Change default hydra_attribute configurations
2
- HydraAttribute.setup do |config|
3
- # Add prefix for all attribute tables
4
- # config.table_prefix = 'hydra_'
5
-
6
- # Add prefix for has_many associations
7
- # config.association_prefix = 'hydra_'
8
-
9
- # Wrap all associated models in HydraAttribute module
10
- # config.use_module_for_associated_models = true
11
- end
@@ -1,16 +0,0 @@
1
- module HydraAttribute
2
- module ActiveRecord
3
- module AttributeMethods
4
- module BeforeTypeCast
5
- extend ActiveSupport::Concern
6
- extend AttributeProxy
7
-
8
- use_proxy_to_hydra_attribute :read_attribute_before_type_cast
9
-
10
- def attributes_before_type_cast
11
- super.merge(hydra_attributes_before_type_cast)
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,13 +0,0 @@
1
- module HydraAttribute
2
- module ActiveRecord
3
- module AttributeMethods
4
- module Read
5
- extend ActiveSupport::Concern
6
- extend AttributeProxy
7
-
8
- use_proxy_to_hydra_attribute :read_attribute
9
-
10
- end
11
- end
12
- end
13
- end
@@ -1,57 +0,0 @@
1
- module HydraAttribute
2
- class AttributeBuilder
3
- NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
4
- CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
5
-
6
- attr_reader :klass, :name, :type
7
-
8
- def initialize(klass, name, type)
9
- @klass, @name, @type = klass, name.to_s, type
10
- end
11
-
12
- def build
13
- define_attribute_methods
14
- save_attribute
15
- end
16
-
17
- private
18
-
19
- def define_attribute_methods
20
- m = Module.new
21
- @klass.attribute_method_matchers.each do |matcher|
22
- current = matcher.method_name(name)
23
- target = matcher.method_name(:value)
24
-
25
- if current =~ NAME_COMPILABLE_REGEXP
26
- defn = "def #{current}(*args)"
27
- else
28
- defn = "define_method(:'#{current}') do |*args|"
29
- end
30
-
31
- if target =~ CALL_COMPILABLE_REGEXP
32
- send = "#{target}(*args)"
33
- else
34
- send = "send(:'#{target}', *args)"
35
- end
36
-
37
- body = "hydra_attribute_model('#{name}', :#{type}).#{send}"
38
- if current.end_with?('=')
39
- body = "v = #{body}; @hydra_attribute_names << '#{name}' unless @hydra_attribute_names.include?('#{name}'); v"
40
- else
41
- body.insert(0, "missing_attribute('#{name}', caller) unless @hydra_attribute_names.include?('#{name}'); ")
42
- end
43
-
44
- m.class_eval <<-EOS, __FILE__, __LINE__ + 1
45
- #{defn}
46
- #{body}
47
- end
48
- EOS
49
- end
50
- klass.send :include, m
51
- end
52
-
53
- def save_attribute
54
- klass.instance_variable_get(:@hydra_attributes)[name] = type
55
- end
56
- end
57
- end
@@ -1,16 +0,0 @@
1
- module HydraAttribute
2
- module AttributeProxy
3
- def use_proxy_to_hydra_attribute(symbol)
4
- module_eval <<-EOS, __FILE__, __LINE__ + 1
5
- def #{symbol}(attr_name)
6
- if self.class.hydra_attribute_names.include?(attr_name)
7
- type = self.class.hydra_attributes[attr_name]
8
- hydra_attribute_model(attr_name, type).#{symbol}('value')
9
- else
10
- super
11
- end
12
- end
13
- EOS
14
- end
15
- end
16
- end
@@ -1,27 +0,0 @@
1
- module HydraAttribute
2
- class Migration
3
- def initialize(migration)
4
- @migration = migration
5
- end
6
-
7
- def migrate
8
- SUPPORT_TYPES.each do |type|
9
- table_name = HydraAttribute.config.table_name(type)
10
- @migration.create_table table_name do |t|
11
- t.integer :entity_id
12
- t.string :entity_type
13
- t.string :name
14
- t.send type, :value
15
- end
16
-
17
- @migration.add_index table_name, [:entity_id, :entity_type, :name], unique: true, name: "index_#{table_name}_on_attribute"
18
- end
19
- end
20
-
21
- def rollback
22
- SUPPORT_TYPES.each do |type|
23
- @migration.drop_table HydraAttribute.config.table_name(type)
24
- end
25
- end
26
- end
27
- end