expose_association 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in expose_association.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Expose Association
2
+
3
+
4
+ ## Usage:
5
+
6
+ Suppose you have this two classes:
7
+
8
+ <pre>
9
+ class Address &lt; ActiveRecord::Base
10
+ belongs_to :contact
11
+ end
12
+
13
+ class Contact &lt; ActiveRecord::Base
14
+
15
+ has_one :primary_address, :class_name => 'Address'
16
+ expose_association :primary_address, prefix: true, class: Address do
17
+ expose :address_line_1, :address_line_2, :city
18
+ expose :phone_number, prefix: false
19
+ expose :country, prefix: 'primary'
20
+ end
21
+
22
+ end
23
+
24
+ </pre>
25
+
26
+ You'll be able to use this class like this:
27
+
28
+ <pre>
29
+ contact = Contact.new
30
+ contact.primary_address_address_line_1 = "122 Fake St."
31
+ contact.primary_address_address_line_2 = "Apt. 45"
32
+ contact.primary_address_city = "Beverly Hill"
33
+ contact.phone_number = "123-123-1234"
34
+ contact.primary_country = "Argentina"
35
+ contact.save
36
+ </pre>
37
+
38
+ Specs?
39
+
40
+ <pre>
41
+ contact.primary_address.should be_a_kind_of(Address)
42
+ ...
43
+
44
+ # Check te real ones on the spec folder
45
+
46
+ </pre>
47
+
48
+ MIT License.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/expose_association/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Lucas Florio"]
6
+ gem.email = ["lucasefe@gmail.com"]
7
+ gem.description = %q{Easy exposition of has_one associations at the object
8
+ level, to avoid nesting.}
9
+ gem.summary = %q{...}
10
+ gem.homepage = ""
11
+
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.name = "expose_association"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = ExposeAssociation::VERSION
18
+ gem.add_dependency 'activerecord'
19
+ gem.add_development_dependency 'rspec'
20
+ gem.add_development_dependency 'sqlite3'
21
+ gem.add_development_dependency 'shoulda'
22
+ end
@@ -0,0 +1,88 @@
1
+ module ExposeAssociation
2
+ module Base
3
+ def expose_association association_name, options = {}, &block
4
+ exposer = AssociationExposer.new(self, association_name, options)
5
+ setup_class_for_exposition(exposer)
6
+ if block_given?
7
+ exposer.instance_eval(&block)
8
+ end
9
+ end
10
+
11
+ def setup_class_for_exposition(exposer)
12
+ # allowing mass assignment of the has_one association
13
+ self.attr_accessible exposer.association_attributes
14
+ self.accepts_nested_attributes_for exposer.association_name
15
+ self.send :alias_method, "old_#{exposer.association_name}", exposer.association_name
16
+ self.send :alias_method, "old_#{exposer.association_name}=", "#{exposer.association_name}="
17
+ self.class_eval <<-CODE
18
+ def #{exposer.association_name}
19
+ #{exposer.association_setup_method}
20
+ end
21
+
22
+ def #{exposer.association_setup_method}
23
+ self.old_#{exposer.association_name} ||= #{exposer.association_class}.new
24
+ end
25
+ CODE
26
+ end
27
+ end
28
+
29
+ class AssociationExposer
30
+
31
+ attr_reader :association_name, :association_class
32
+
33
+ def initialize klass, association_name, options = {}
34
+ @klass = klass
35
+ options[:class] ||= association_name.to_s.camelize.constantize
36
+ @association_class = options[:class]
37
+ @association_name = association_name
38
+ @options = options
39
+ end
40
+
41
+ def expose *attributes
42
+ options = attributes.last.is_a?(Hash) ? attributes.pop : {}
43
+ attributes.each do |attribute|
44
+ expose_attribute attribute, options
45
+ end
46
+ end
47
+
48
+ def expose_attribute name, options = {}
49
+ @klass.delegate name, "#{name}=",
50
+ to: association_setup_method,
51
+ prefix: prefix_for(options[:prefix])
52
+
53
+ @klass.attr_accessible attr_name_for(name, options[:prefix])
54
+ end
55
+
56
+ def attr_name_for(name, prefix)
57
+ case prefix
58
+ when FalseClass then name.to_s
59
+ when String, Symbol then
60
+ "#{prefix.to_s}_#{name}"
61
+ else
62
+ "#{association_name}_#{name}"
63
+ end
64
+ end
65
+
66
+ def prefix_for(prefix_option)
67
+ case prefix_option
68
+ when TrueClass, NilClass then association_name.to_s
69
+ when FalseClass then false
70
+ when String, Symbol then prefix_option.to_s
71
+ else # nil
72
+ raise "Wrong value for prefix: #{prefix_option}"
73
+ end
74
+ end
75
+
76
+ def association_attributes
77
+ "#{association_name}_attributes"
78
+ end
79
+
80
+ def association_setup_method
81
+ "#{setup_method_prefix}_#{@association_name}"
82
+ end
83
+
84
+ def setup_method_prefix
85
+ @options.fetch(:setup_method_prefix, "setup")
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,9 @@
1
+ module ExposeAssociation
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'expose_association.ar_hook' do
4
+ ActiveSupport.on_load :active_record do
5
+ extend ::ExposeAssociation::Base
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module ExposeAssociation
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ require "expose_association/version"
2
+ require 'expose_association/base'
3
+ require 'expose_association/railtie' if defined? Rails
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ class Address < ActiveRecord::Base; end
4
+ class Contact < ActiveRecord::Base
5
+ extend ExposeAssociation::Base
6
+ has_one :main_location, :class_name => 'Address'
7
+ end
8
+
9
+ describe 'SomeModel with ExposeAssociation' do
10
+
11
+ it "should include the basic functionality" do
12
+ Contact.should respond_to(:expose_association)
13
+ end
14
+
15
+ context "exposing another object" do
16
+
17
+ before :all do
18
+ Contact.expose_association :main_location, class: Address do
19
+ expose :city
20
+ expose :address_line_1, prefix: false
21
+ end
22
+ end
23
+
24
+ let(:contact) { Contact.new }
25
+
26
+ it "should setup the association with the provided class" do
27
+ contact.main_location.should be_a_kind_of(Address)
28
+ end
29
+
30
+ it "should add the builder" do
31
+ contact.should respond_to(:setup_main_location)
32
+ end
33
+
34
+ it "should support mass assignment of the other object" do
35
+ contact.should allow_mass_assignment_of(:main_location_attributes)
36
+ end
37
+
38
+ it "should expose a given attribute (with prefix)" do
39
+ contact.should respond_to("main_location_city")
40
+ contact.should respond_to("main_location_city=")
41
+ contact.main_location_city = "Madrid"
42
+ contact.main_location.city.should == "Madrid"
43
+ end
44
+
45
+ it "should allow mass assignment of the exposed attributes" do
46
+ contact = Contact.new main_location_city: "Barcelona"
47
+ contact.main_location.city.should == "Barcelona"
48
+ end
49
+
50
+ context "with no prefix" do
51
+ it "should expose the attribute directly on the main object" do
52
+ contact.should respond_to(:address_line_1)
53
+ contact.address_line_1 = "Freire 1008"
54
+ contact.main_location.address_line_1.should == "Freire 1008"
55
+ end
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+
62
+ describe ExposeAssociation::AssociationExposer do
63
+ it "should know the setup method" do
64
+ exposer = ExposeAssociation::AssociationExposer.new(Contact, :main_location, class: Address)
65
+ exposer.association_setup_method.should == "setup_main_location"
66
+ end
67
+
68
+ it "should infer the class name of the association if none is provided" do
69
+ exposer = ExposeAssociation::AssociationExposer.new(Contact, :address)
70
+ exposer.association_class.should == Address
71
+ exposer = ExposeAssociation::AssociationExposer.new(Contact, :main_location, class: Address)
72
+ exposer.association_class.should == Address
73
+ end
74
+
75
+ it "should calculate properly the attr_name for a given prefix" do
76
+ exposer = ExposeAssociation::AssociationExposer.new(Contact, :address)
77
+ exposer.attr_name_for(:city, nil).should == 'address_city'
78
+ exposer.attr_name_for(:city, true).should == 'address_city'
79
+ exposer.attr_name_for(:city, false).should == 'city'
80
+ exposer.attr_name_for(:city, "culo").should == 'culo_city'
81
+ exposer.attr_name_for(:city, :culito).should == 'culito_city'
82
+ end
83
+
84
+ it "should calculate properly the prefix " do
85
+ exposer = ExposeAssociation::AssociationExposer.new(Contact, :address)
86
+ exposer.prefix_for("culito").should == 'culito'
87
+ exposer.prefix_for(true).should == 'address'
88
+ exposer.prefix_for(nil).should == 'address'
89
+ exposer.prefix_for(false).should == false
90
+ exposer.prefix_for(:culito).should == 'culito'
91
+ end
92
+ end
@@ -0,0 +1,18 @@
1
+ require 'active_record'
2
+ require 'expose_association'
3
+ require 'shoulda'
4
+
5
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
6
+
7
+ ActiveRecord::Schema.define(:version => 1) do
8
+ create_table :contacts do |t|
9
+ t.string :first_name, :last_name
10
+ end
11
+
12
+ create_table :addresses do |t|
13
+ t.string :contactable_type
14
+ t.integer :contactable_id
15
+ t.string :address_line_1, :address_line_2
16
+ t.string :city
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: expose_association
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Lucas Florio
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &70160113896320 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70160113896320
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70160113895020 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70160113895020
36
+ - !ruby/object:Gem::Dependency
37
+ name: sqlite3
38
+ requirement: &70160113893880 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70160113893880
47
+ - !ruby/object:Gem::Dependency
48
+ name: shoulda
49
+ requirement: &70160113892360 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70160113892360
58
+ description: ! "Easy exposition of has_one associations at the object\n level, to
59
+ avoid nesting."
60
+ email:
61
+ - lucasefe@gmail.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - .rspec
68
+ - Gemfile
69
+ - README.md
70
+ - Rakefile
71
+ - expose_association.gemspec
72
+ - lib/expose_association.rb
73
+ - lib/expose_association/base.rb
74
+ - lib/expose_association/railtie.rb
75
+ - lib/expose_association/version.rb
76
+ - spec/expose_association/base_spec.rb
77
+ - spec/spec_helper.rb
78
+ homepage: ''
79
+ licenses: []
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 1.8.10
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: ! '...'
102
+ test_files:
103
+ - spec/expose_association/base_spec.rb
104
+ - spec/spec_helper.rb
105
+ has_rdoc: