hydra_attribute 0.2.0 → 0.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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