hydra_attribute 0.1.0

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