expose_association 0.0.1

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.
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: