hydra_attribute 0.1.0

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 (57) hide show
  1. data/.gitignore +20 -0
  2. data/.rspec +2 -0
  3. data/Appraisals +7 -0
  4. data/CHANGELOG.md +6 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +22 -0
  7. data/README.md +122 -0
  8. data/Rakefile +12 -0
  9. data/features/attribute_methods.feature +151 -0
  10. data/features/define_attributes.feature +61 -0
  11. data/features/load_associations.feature +45 -0
  12. data/features/order_conditions.feature +93 -0
  13. data/features/select_attributes.feature +56 -0
  14. data/features/step_definitions/class_steps.rb +32 -0
  15. data/features/step_definitions/model_steps.rb +31 -0
  16. data/features/step_definitions/record_steps.rb +103 -0
  17. data/features/support/env.rb +24 -0
  18. data/features/support/schema.rb +51 -0
  19. data/features/support/world.rb +31 -0
  20. data/features/typecast_attributes.feature +29 -0
  21. data/features/where_conditions.feature +77 -0
  22. data/gemfiles/3.1.gemfile +7 -0
  23. data/gemfiles/3.1.gemfile.lock +60 -0
  24. data/gemfiles/3.2.gemfile +7 -0
  25. data/gemfiles/3.2.gemfile.lock +60 -0
  26. data/hydra_attribute.gemspec +24 -0
  27. data/lib/generators/hydra_attribute/install/USAGE +8 -0
  28. data/lib/generators/hydra_attribute/install/install_generator.rb +11 -0
  29. data/lib/generators/hydra_attribute/install/templates/hydra_attribute.txt +11 -0
  30. data/lib/hydra_attribute.rb +31 -0
  31. data/lib/hydra_attribute/active_record.rb +7 -0
  32. data/lib/hydra_attribute/active_record/attribute_methods.rb +72 -0
  33. data/lib/hydra_attribute/active_record/attribute_methods/before_type_cast.rb +16 -0
  34. data/lib/hydra_attribute/active_record/attribute_methods/read.rb +13 -0
  35. data/lib/hydra_attribute/active_record/relation.rb +44 -0
  36. data/lib/hydra_attribute/active_record/relation/query_methods.rb +162 -0
  37. data/lib/hydra_attribute/active_record/scoping.rb +15 -0
  38. data/lib/hydra_attribute/association_builder.rb +40 -0
  39. data/lib/hydra_attribute/attribute_builder.rb +57 -0
  40. data/lib/hydra_attribute/attribute_proxy.rb +16 -0
  41. data/lib/hydra_attribute/builder.rb +25 -0
  42. data/lib/hydra_attribute/configuration.rb +47 -0
  43. data/lib/hydra_attribute/migration.rb +27 -0
  44. data/lib/hydra_attribute/railtie.rb +9 -0
  45. data/lib/hydra_attribute/version.rb +3 -0
  46. data/spec/hydra_attribute/active_record/relation/query_methods_spec.rb +286 -0
  47. data/spec/hydra_attribute/active_record/relation_spec.rb +93 -0
  48. data/spec/hydra_attribute/active_record/scoping_spec.rb +19 -0
  49. data/spec/hydra_attribute/active_record_spec.rb +20 -0
  50. data/spec/hydra_attribute/association_builder_spec.rb +95 -0
  51. data/spec/hydra_attribute/attribute_builder_spec.rb +70 -0
  52. data/spec/hydra_attribute/attribute_helpers_spec.rb +70 -0
  53. data/spec/hydra_attribute/builder_spec.rb +39 -0
  54. data/spec/hydra_attribute/configuration_spec.rb +96 -0
  55. data/spec/hydra_attribute_spec.rb +20 -0
  56. data/spec/spec_helper.rb +17 -0
  57. metadata +196 -0
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe HydraAttribute::ActiveRecord::Relation do
4
+ def record_class(loaded_associations = false)
5
+ Class.new do
6
+
7
+ @hydra_attributes = {'code' => :string}
8
+ define_singleton_method :hydra_attribute_types do
9
+ [:string]
10
+ end
11
+
12
+ define_singleton_method :hydra_attribute_names do
13
+ ['code']
14
+ end
15
+
16
+ define_singleton_method :hydra_attributes do
17
+ @hydra_attributes
18
+ end
19
+
20
+ define_method :association do |_|
21
+ Class.new do
22
+ define_singleton_method :loaded? do
23
+ loaded_associations
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def relation_function(records)
31
+ Module.new do
32
+ define_method :loaded? do
33
+ false
34
+ end
35
+
36
+ define_method :select_values do
37
+ []
38
+ end
39
+
40
+ define_method :hydra_select_values do
41
+ []
42
+ end
43
+
44
+ define_method HydraAttribute.config.relation_execute_method do
45
+ records
46
+ end
47
+
48
+ define_method :klass do
49
+ records.first.class
50
+ end
51
+
52
+ define_method :where do |*|
53
+ self
54
+ end
55
+ end
56
+ end
57
+
58
+ let(:records) { [record_class.new] }
59
+ let(:ancestor) { relation_function(records) }
60
+ let(:klass) { Class.new.extend(ancestor).extend(HydraAttribute::ActiveRecord::Relation) }
61
+
62
+ describe "##{HydraAttribute.config.relation_execute_method}" do
63
+ describe 'parent method return one record' do
64
+ it 'should return one record' do
65
+ klass.send(HydraAttribute.config.relation_execute_method).should have(1).record
66
+ end
67
+ end
68
+
69
+ describe 'parent method returns two records' do
70
+ let(:records) { [record_class(loaded_associations).new, record_class(loaded_associations).new] }
71
+
72
+ describe 'association models are already loaded' do
73
+ let(:loaded_associations) { true }
74
+
75
+ it 'should return two record' do
76
+ klass.send(HydraAttribute.config.relation_execute_method).should have(2).records
77
+ end
78
+ end
79
+
80
+ describe 'association models are not yet loaded' do
81
+ let(:loaded_associations) { false }
82
+
83
+ before do
84
+ ::ActiveRecord::Associations::Preloader.should_receive(:new).with(records, :hydra_string_attributes).and_return(mock(run: records))
85
+ end
86
+
87
+ it 'should return two record' do
88
+ klass.send(HydraAttribute.config.relation_execute_method).should have(2).records
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe HydraAttribute::ActiveRecord::Scoping do
4
+ describe '#scoped' do
5
+ let(:ancestor) do
6
+ Module.new do
7
+ def scoped(*) self end
8
+ def where(*) self end
9
+ end
10
+ end
11
+
12
+ let(:klass) { Class.new.extend(ancestor) }
13
+
14
+ it 'should return ActiveRecord::Relation object with extended HydraAttribute::ActiveRecord::Relation module' do
15
+ klass.send :include, HydraAttribute::ActiveRecord::Scoping
16
+ klass.scoped.singleton_class.ancestors.should include(HydraAttribute::ActiveRecord::Relation)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe HydraAttribute::ActiveRecord do
4
+ let(:klass) { Class.new.extend(HydraAttribute::ActiveRecord) }
5
+
6
+ describe '#define_hydra_attributes' do
7
+ let(:builder) { @builder }
8
+ before { klass.define_hydra_attributes { |b| @builder = b } }
9
+
10
+ it 'should yield block with preconfigured current class' do
11
+ builder.should be_an_instance_of(HydraAttribute::Builder)
12
+ builder.klass.should be_equal(klass)
13
+
14
+ end
15
+
16
+ it 'should include HydraAttribute::ActiveRecord::Scoping to class' do
17
+ klass.should include(HydraAttribute::ActiveRecord::Scoping)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe HydraAttribute::AssociationBuilder do
4
+ def remove_association
5
+ [::HydraAttribute, ::Object].each do |klass|
6
+ klass.send(:remove_const, :StringAttribute) if klass.constants.include?(:StringAttribute)
7
+ end
8
+ end
9
+
10
+ after(:each) { remove_association }
11
+
12
+ let(:klass) do
13
+ Class.new do
14
+ @reflection = {}
15
+ define_singleton_method :reflect_on_association do |assoc|
16
+ @reflection[assoc]
17
+ end
18
+ define_singleton_method :has_many do |assoc, options|
19
+ @reflection[assoc] = options
20
+ end
21
+ end
22
+ end
23
+
24
+ let(:type) { :string }
25
+ let(:association) { HydraAttribute::AssociationBuilder.new(klass, type) }
26
+
27
+ describe '#buld' do
28
+ it 'should call #build_associated_model and build_association' do
29
+ association.should_receive(:create_associated_model)
30
+ association.should_receive(:add_association_for_class)
31
+ association.build
32
+ end
33
+ end
34
+
35
+ describe '#create_associated_model' do
36
+ describe 'use namespace for associated models' do
37
+ it 'should create new model' do
38
+ association.send(:create_associated_model)
39
+ HydraAttribute.should be_const_defined(:StringAttribute)
40
+ end
41
+ end
42
+
43
+ describe 'should not use namespace for associated models' do
44
+ before { HydraAttribute.config.use_module_for_associated_models = false }
45
+ after { HydraAttribute.config.use_module_for_associated_models = true }
46
+
47
+ it 'should create new model' do
48
+ association.send(:create_associated_model)
49
+ Object.should be_const_defined(:StringAttribute)
50
+ end
51
+ end
52
+
53
+ describe 'do not try to create twice the same class' do
54
+ it 'should not warn "already initialized constant"' do
55
+ association.send(:create_associated_model)
56
+ HydraAttribute.should_not_receive(:const_set)
57
+ association.send(:create_associated_model)
58
+ end
59
+ end
60
+
61
+ describe 'set correct table name' do
62
+ it 'should be :hydra_string_attributes' do
63
+ association.send(:create_associated_model)
64
+ HydraAttribute::StringAttribute.table_name.should == 'hydra_string_attributes'
65
+ end
66
+ end
67
+
68
+ describe 'set correct belongs_to' do
69
+ it 'should be polymorphic association' do
70
+ association.send(:create_associated_model)
71
+ reflection = HydraAttribute::StringAttribute.reflect_on_association(:entity)
72
+ reflection.macro.should == :belongs_to
73
+ reflection.options[:polymorphic].should be_true
74
+ reflection.options[:touch].should be_true
75
+ reflection.options[:autosave].should be_true
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#add_association_for_class' do
81
+ it 'should add has_many association for class' do
82
+ association.send(:add_association_for_class)
83
+ reflection = klass.reflect_on_association(:hydra_string_attributes)
84
+ reflection[:as].should == :entity
85
+ reflection[:class_name].should == 'HydraAttribute::StringAttribute'
86
+ reflection[:autosave].should be_true
87
+ end
88
+
89
+ it 'should not add twice the same has_many association' do
90
+ association.send(:add_association_for_class)
91
+ klass.should_not_receive(:has_many)
92
+ association.send(:add_association_for_class)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe HydraAttribute::AttributeBuilder do
4
+ let(:klass) { Class.new }
5
+ let(:attribute) { HydraAttribute::AttributeBuilder.new(klass, :name, :string) }
6
+
7
+ describe '#build' do
8
+ it 'should call required methods' do
9
+ attribute.should_receive(:define_attribute_methods)
10
+ attribute.should_receive(:save_attribute)
11
+ attribute.build
12
+ end
13
+ end
14
+
15
+ describe '#define_attribute_methods' do
16
+ let(:matcher_get) do
17
+ mock_matcher = mock
18
+ mock_matcher.stub(:method_name) { |value| value.to_s }
19
+ mock_matcher
20
+ end
21
+
22
+ let(:matcher_set) do
23
+ mock_matcher = mock
24
+ mock_matcher.stub(:method_name) { |value| "#{value}=" }
25
+ mock_matcher
26
+ end
27
+
28
+ let(:matcher_query) do
29
+ mock_matcher = mock
30
+ mock_matcher.stub(:method_name) { |value| "#{value}?" }
31
+ mock_matcher
32
+ end
33
+
34
+ before do
35
+ klass.stub(attribute_method_matchers: [matcher_get, matcher_set, matcher_query])
36
+ attribute.send(:define_attribute_methods)
37
+ end
38
+
39
+ it 'should respond to #name' do
40
+ klass.new.should respond_to(:name)
41
+ end
42
+
43
+ it 'should respond to #name=' do
44
+ klass.new.should respond_to(:name=)
45
+ end
46
+
47
+ it 'should respond to #name?' do
48
+ klass.new.should respond_to(:name?)
49
+ end
50
+
51
+ it 'should define all methods in module' do
52
+ [:name, :name=, :name?].each do |method|
53
+ klass.new.method(method).owner.class.should == Module
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#store_attribute' do
59
+ before do
60
+ attribute.instance_variable_set(:@name, :name)
61
+ attribute.instance_variable_set(:@type, :type)
62
+ klass.instance_variable_set(:@hydra_attributes, {})
63
+ end
64
+
65
+ it 'should save attribute name and type in @hydra_attributes' do
66
+ attribute.send(:save_attribute)
67
+ klass.instance_variable_get(:@hydra_attributes)[:name].should == :type
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+ __END__
3
+ describe HydraAttribute::AttributeHelpers do
4
+ let(:klass) { Class.new { include HydraAttribute::AttributeHelpers } }
5
+
6
+ describe '.inherited' do
7
+ it 'should clone @hydra_attributes to base class' do
8
+ klass.instance_variable_set(:@hydra_attributes, {a: 1, b: 2})
9
+ sub_class = Class.new(klass)
10
+ sub_class.instance_variable_get(:@hydra_attributes).should == {a: 1, b: 2}
11
+ sub_class.instance_variable_get(:@hydra_attributes).should_not equal(klass.instance_variable_get(:@hydra_attributes))
12
+ end
13
+ end
14
+
15
+ describe '.hydra_attributes' do
16
+ it 'should return hash of attributes' do
17
+ klass.hydra_attributes.should == {}
18
+ end
19
+
20
+ it 'should return cloned hash' do
21
+ klass.hydra_attributes.should_not equal(klass.hydra_attributes)
22
+ end
23
+ end
24
+
25
+ describe '.hydra_attribute_names' do
26
+ it 'should return hash keys' do
27
+ klass.instance_variable_set(:@hydra_attributes, {a: 1, b: 2})
28
+ klass.hydra_attribute_names.should == [:a, :b]
29
+ end
30
+ end
31
+
32
+ describe '.hydra_attribute_types' do
33
+ it 'should return hash values' do
34
+ klass.instance_variable_set(:@hydra_attributes, {a: 1, b: 2})
35
+ klass.hydra_attribute_types.should == [1, 2]
36
+ end
37
+ end
38
+
39
+ describe '#hydra_attribute_model' do
40
+ let(:code_model) { mock(name: :code) }
41
+ let(:title_model) { mock(name: :title) }
42
+ let(:collection) { [code_model, title_model] }
43
+
44
+ before do
45
+ HydraAttribute.config.should_receive(:association).with(:string).and_return(:string_association)
46
+ klass.any_instance.should_receive(:string_association).and_return(collection)
47
+ end
48
+
49
+ describe 'type collection has built model' do
50
+ let(:name) { :code }
51
+
52
+ it 'should return model' do
53
+ klass.new.hydra_attribute_model(name, :string).should == code_model
54
+ end
55
+ end
56
+
57
+ describe 'type collection has not built model' do
58
+ let(:name) { :price }
59
+ let(:built) { mock(:built) }
60
+
61
+ before do
62
+ collection.should_receive(:build).with(name: :price).and_return(built)
63
+ end
64
+
65
+ it 'should build model' do
66
+ klass.new.hydra_attribute_model(name, :string).should == built
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe HydraAttribute::Builder do
4
+
5
+ let(:klass) { Class.new }
6
+ let!(:builder) { HydraAttribute::Builder.new(klass) }
7
+
8
+ describe '#initialzie' do
9
+ it 'should include HydraAttribute::ActiveRecord::Scoping to class' do
10
+ klass.should include(HydraAttribute::ActiveRecord::Scoping)
11
+ end
12
+
13
+ it 'should include HydraAttribute::ActiveRecord::AttributeMethods to class' do
14
+ klass.should include(HydraAttribute::ActiveRecord::AttributeMethods)
15
+ end
16
+
17
+ it 'should respond to all supported types' do
18
+ HydraAttribute::SUPPORT_TYPES.each do |type|
19
+ builder.should respond_to(type)
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#string' do
25
+ let(:association_instance) { mock(:association_instance) }
26
+ let(:attribute_instance) { mock(:attribute_instance) }
27
+
28
+ before do
29
+ HydraAttribute::AssociationBuilder.should_receive(:new).with(klass, :string).and_return(association_instance)
30
+ HydraAttribute::AttributeBuilder.should_receive(:new).with(klass, :name, :string).and_return(attribute_instance)
31
+
32
+ [association_instance, attribute_instance].each { |instance| instance.should_receive(:build) }
33
+ end
34
+
35
+ it 'should build association' do
36
+ builder.string :name
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe HydraAttribute::Configuration do
4
+ let(:config) { HydraAttribute::Configuration.new }
5
+
6
+ describe '#table_name' do
7
+ describe 'with table prefix' do
8
+ before { config.table_prefix = 'table_' }
9
+
10
+ it 'should return table name' do
11
+ config.table_name(:string).should == :table_string_attributes
12
+ end
13
+ end
14
+
15
+ describe 'without table prefix' do
16
+ before { config.table_prefix = '' }
17
+
18
+ it 'should return table name' do
19
+ config.table_name(:string).should == :string_attributes
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#association' do
25
+ describe 'with association prefix' do
26
+ before { config.association_prefix = 'assoc_' }
27
+
28
+ it 'should return association name' do
29
+ config.association(:string).should == :assoc_string_attributes
30
+ end
31
+ end
32
+
33
+ describe 'without association prefix' do
34
+ before { config.association_prefix = '' }
35
+
36
+ it 'should return association name' do
37
+ config.association(:string).should == :string_attributes
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#associated_model_name' do
43
+ describe 'use module wrapper' do
44
+ before { config.use_module_for_associated_models = true }
45
+
46
+ it 'should return associated model name' do
47
+ config.associated_model_name(:string).should == 'HydraAttribute::StringAttribute'
48
+ end
49
+ end
50
+
51
+ describe 'don not use module wrapper' do
52
+ before { config.use_module_for_associated_models = false }
53
+
54
+ it 'should return associated model name' do
55
+ config.associated_model_name(:string).should == 'StringAttribute'
56
+ end
57
+ end
58
+ end
59
+
60
+ describe '#associated_const_name' do
61
+ it 'should return constant name for new model' do
62
+ config.associated_const_name(:string).should == :StringAttribute
63
+ end
64
+ end
65
+
66
+ describe '#relation_execute_method' do
67
+ after do
68
+ ::ActiveRecord::VERSION.send(:remove_const, :MINOR)
69
+ ::ActiveRecord::VERSION.const_set(:MINOR, @old_value)
70
+ end
71
+
72
+ describe 'ActiveRecord::VERSION::MINOR is great than 1' do
73
+ before do
74
+ @old_value = ::ActiveRecord::VERSION::MINOR
75
+ ::ActiveRecord::VERSION.send(:remove_const, :MINOR)
76
+ ::ActiveRecord::VERSION.const_set(:MINOR, 2)
77
+ end
78
+
79
+ it 'should return :exec_queries' do
80
+ config.relation_execute_method.should == :exec_queries
81
+ end
82
+ end
83
+
84
+ describe 'ActiveRecord::VERSION::MINOR is less than or equal 1' do
85
+ before do
86
+ @old_value = ::ActiveRecord::VERSION::MINOR
87
+ ::ActiveRecord::VERSION.send(:remove_const, :MINOR)
88
+ ::ActiveRecord::VERSION.const_set(:MINOR, 1)
89
+ end
90
+
91
+ it 'should return :to_a' do
92
+ config.relation_execute_method.should == :to_a
93
+ end
94
+ end
95
+ end
96
+ end