has_associative_facades 1.0.3

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,4 @@
1
+ .* # Ignore all dotfiles...
2
+ !.gitignore # except for .gitignore
3
+ pkg/*
4
+ .rake_tasks~
data/History.txt ADDED
@@ -0,0 +1,8 @@
1
+ == 1.0.3 2010-04-26
2
+
3
+ * Got rid of situation where no method error or other exceptions are eaten instead of raised again.
4
+
5
+
6
+ == 1.0.0 2009-06-25
7
+
8
+ * Initial release
data/README.rdoc ADDED
@@ -0,0 +1,110 @@
1
+ = has_associative_facades
2
+
3
+ http://github.com/midas/has_associative_facades/tree/master
4
+
5
+
6
+ == DESCRIPTION:
7
+
8
+ A Rails gem that creates getters and setters for associated object's attributes to aid in not breaking Demeter's Law.
9
+
10
+ == WHY
11
+
12
+ From http://en.wikipedia.org/wiki/Law_of_Demeter, the "Law of Demeter for Functions/Methods” (LoD-F) states:
13
+
14
+ An object A can request a service (call a method) of an object instance B, but object A cannot “reach through” object
15
+ B to access yet another object, C, to request its services. Doing so would mean that object A implicitly requires greater
16
+ knowledge of object B’s internal structure. Instead, B’s class should be modified if necessary so that object A can simply
17
+ make the request directly of object B, and then let object B propagate the request to any relevant subcomponents. Or A should
18
+ have a direct reference to object C and make the call directly. If the law is followed, only object B knows its own internal
19
+ structure.
20
+
21
+ In particular, an object should avoid invoking methods of a member object returned by another method. For many modern object
22
+ oriented languages that use a dot as field identifier, the law can be stated simply as "use only one dot". That is, the code
23
+ "a.b.Method()" breaks the law where "a.Method()" does not.
24
+
25
+ As a simple example, when one wants to walk a dog, it would be folly to command the dog’s legs to walk directly; instead one
26
+ commands the dog and lets it take care of its legs itself
27
+
28
+ The advantage of following the Law of Demeter is that the resulting software tends to be more maintainable and adaptable. Since
29
+ objects are less dependent on the internal structure of other objects, object containers can be changed without reworking their
30
+ callers.
31
+
32
+ A disadvantage of the Law of Demeter is that it sometimes requires writing a large number of small “wrapper” methods (sometimes
33
+ referred to as Demeter Transmogrifiers) to propagate method calls to the components. Furthermore, a class’s interface can become
34
+ bulky as it hosts methods for contained classes resulting in a class without a cohesive interface.
35
+
36
+ This is where has_associative_facades steps in. Instead of writing this large number of wrapper methods, you can just call the
37
+ methods and they will be defined on an as needed basis, remaining in memory until the object is destroyed. So now you can avoid
38
+ coupling your objects together without the extra work. Only the interface to your object need remain the same. You can change
39
+ the internal implementation of methods to your heart;s content without breaking your project.
40
+
41
+
42
+ == FEATURES:
43
+
44
+ * Automatically creates facade getter methods for has one and belongs to associations.
45
+
46
+
47
+ == TO IMPLEMENT:
48
+
49
+ * Automatically creates facade setter methods for has one and belongs to associations.
50
+ * Possibly provide a static way to define through macro type singleton methods (like attr_accessor, attr_reader, etc).
51
+
52
+
53
+ == USAGE:
54
+
55
+ For:
56
+
57
+ class Account < ActiveRecord::Base
58
+ # has name attribute
59
+ end
60
+
61
+ class User
62
+ has_associative_facades
63
+
64
+ belongs_to :account
65
+ end
66
+
67
+ You can now:
68
+
69
+ user = User.first # or User.new, User.find, etc
70
+ user.account_name # is the same as user.account.name
71
+
72
+
73
+ == REQUIREMENTS:
74
+
75
+ * ActiveRecord
76
+
77
+
78
+ == INSTALL:
79
+
80
+ sudo gem install midas-has_associative_facades
81
+
82
+ In your Rails environment file:
83
+
84
+ config.gem 'has_associative_facades'
85
+
86
+
87
+ == LICENSE:
88
+
89
+ (The MIT License)
90
+
91
+ Copyright (c) 2009 C. Jason Harrelson (midas)
92
+
93
+ Permission is hereby granted, free of charge, to any person obtaining
94
+ a copy of this software and associated documentation files (the
95
+ 'Software'), to deal in the Software without restriction, including
96
+ without limitation the rights to use, copy, modify, merge, publish,
97
+ distribute, sublicense, and/or sell copies of the Software, and to
98
+ permit persons to whom the Software is furnished to do so, subject to
99
+ the following conditions:
100
+
101
+ The above copyright notice and this permission notice shall be
102
+ included in all copies or substantial portions of the Software.
103
+
104
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
105
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
106
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
107
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
108
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
109
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
110
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,67 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "has_associative_facades"
8
+ gem.summary = %Q{An active record gem that creates getters and setters for associated object's attributes to aid in not breaking Demeter's Law.}
9
+ gem.description = %Q{A Rails gem that creates getters and setters for associated object's attributes to aid in not breaking Demeter's Law.}
10
+ gem.email = "jason@lookforwardenterprises.com"
11
+ gem.homepage = "http://github.com/midas/guilded"
12
+ gem.authors = ["C. Jason Harrelson (midas)"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_dependency "activerecord", ">= 2.0.0"
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ begin
38
+ require 'rcov/rcovtask'
39
+ Rcov::RcovTask.new do |test|
40
+ test.libs << 'test'
41
+ test.pattern = 'test/**/*_test.rb'
42
+ test.verbose = true
43
+ end
44
+ rescue LoadError
45
+ task :rcov do
46
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
47
+ end
48
+ end
49
+
50
+ task :test => :check_dependencies
51
+
52
+ task :default => :test
53
+
54
+ require 'rake/rdoctask'
55
+ Rake::RDocTask.new do |rdoc|
56
+ if File.exist?('VERSION')
57
+ version = File.read('VERSION')
58
+ else
59
+ version = ""
60
+ end
61
+
62
+ rdoc.rdoc_dir = 'rdoc'
63
+ rdoc.title = "tester #{version}"
64
+ rdoc.rdoc_files.include('README*')
65
+ rdoc.rdoc_files.include('lib/**/*.rb')
66
+ end
67
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.3
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{has_associative_facades}
8
+ s.version = "1.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["C. Jason Harrelson (midas)"]
12
+ s.date = %q{2010-04-26}
13
+ s.description = %q{A Rails gem that creates getters and setters for associated object's attributes to aid in not breaking Demeter's Law.}
14
+ s.email = %q{jason@lookforwardenterprises.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "History.txt",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "has_associative_facades.gemspec",
25
+ "lib/has_associative_facades.rb",
26
+ "lib/has_associative_facades/acts_methods.rb",
27
+ "lib/has_associative_facades/instance_methods.rb",
28
+ "script/console",
29
+ "script/destroy",
30
+ "script/generate",
31
+ "spec/has_associative_facades_spec.rb",
32
+ "spec/spec.opts",
33
+ "spec/spec_helper.rb",
34
+ "tasks/rspec.rake"
35
+ ]
36
+ s.homepage = %q{http://github.com/midas/guilded}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.6}
40
+ s.summary = %q{An active record gem that creates getters and setters for associated object's attributes to aid in not breaking Demeter's Law.}
41
+ s.test_files = [
42
+ "spec/has_associative_facades_spec.rb",
43
+ "spec/spec_helper.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
52
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.0.0"])
53
+ else
54
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
55
+ s.add_dependency(%q<activerecord>, [">= 2.0.0"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
59
+ s.add_dependency(%q<activerecord>, [">= 2.0.0"])
60
+ end
61
+ end
62
+
@@ -0,0 +1,15 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'has_associative_facades/acts_methods'
5
+ require 'has_associative_facades/instance_methods'
6
+
7
+ module HasAssociativeFacades
8
+ VERSION = '1.0.3'
9
+
10
+ def self.included( base )
11
+ base.extend ActsMethods
12
+ end
13
+ end
14
+
15
+ ActiveRecord::Base.send( :include, HasAssociativeFacades ) if defined?( ActiveRecord::Base )
@@ -0,0 +1,13 @@
1
+ module HasAssociativeFacades
2
+ module ActsMethods
3
+
4
+ # Use this method to declare the associated facade behavior on your ActiveRecord class.
5
+ #
6
+ def has_associative_facades
7
+ unless included_modules.include? InstanceMethods
8
+ include InstanceMethods
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,78 @@
1
+ module HasAssociativeFacades
2
+ module InstanceMethods
3
+
4
+ # When the method being called is the case of "#{association_name}_#{attribute_or_method}" a getter method
5
+ # will be defined and called returning its value. This works for an ActiveRecord object created through the
6
+ # new operator having all attributes set to nil or an find of some sort having all attributes populated.
7
+ #
8
+ # If the associated object is nil but has an attribute or method with the given name a nil is reurned. Otherwise,
9
+ # the NoMethodError is raised.
10
+ #
11
+ def method_missing( method, *args )
12
+ method_name = method.to_s
13
+ super( method, *args ) # allow super to win if it has the method
14
+ rescue NoMethodError => ex
15
+ association = nil
16
+ association_reflection = nil
17
+ associateds = self.class.inheritable_attributes[:reflections]
18
+ associateds.each do |associated|
19
+ if /#{associated[0]}_/.match( method_name )
20
+ association_reflection = associated
21
+ association = associated[0]
22
+ break
23
+ end
24
+ end
25
+ if association.nil?
26
+ raise NoMethodError.new('has_associative_facades could find no ' +
27
+ 'association to resolve ' +
28
+ "#{self.class.name}##{method}",
29
+ method,
30
+ args)
31
+ end
32
+
33
+ if match = /#{association}_([_a-zA-Z]\w*)/.match( method_name )
34
+ if match.captures.empty? || match.captures.size > 2
35
+ raise NoMethodError.new('has_associative_facades failed to resolve ' +
36
+ "#{self.class.name}##{method} via " +
37
+ "#{self.class.name}##{association}",
38
+ method,
39
+ args)
40
+ end
41
+ attribute = match.captures[0].to_sym
42
+
43
+ assoc_klass = nil
44
+ begin
45
+ assoc_klass = association.to_s.classify.constantize
46
+ rescue
47
+ assoc_klass = association_reflection[1].options[:class_name].constantize
48
+ end
49
+ unless assoc_klass.columns_hash.has_key?( attribute.to_s ) || assoc_klass.public_instance_methods.include?( attribute.to_s )
50
+ if match.captures.empty? || match.captures.size > 2
51
+ raise NoMethodError.new('has_associative_facades could find no ' +
52
+ "#{assoc_klass.name}##{method} " +
53
+ 'method to resolve ' +
54
+ "#{self.class.name}##{method}",
55
+ method,
56
+ args)
57
+ end
58
+ end
59
+
60
+ self.class.class_eval <<-END
61
+ def #{method_name}
62
+ return self.send( :#{association} ).send( :#{attribute} ) unless self.send( :#{association} ).nil?
63
+ nil
64
+ end
65
+ END
66
+
67
+ return self.send( method_name )
68
+ end
69
+
70
+ raise NoMethodError.new('has_associative_facades failed to resolve ' +
71
+ "#{self.class.name}##{method} via " +
72
+ "any association on #{self.class.name}",
73
+ method,
74
+ args)
75
+ end
76
+
77
+ end
78
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/has_associative_facades.rb'}"
9
+ puts "Loading has_associative_facades gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe HasAssociativeFacades do
4
+
5
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'has_associative_facades'
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_associative_facades
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 3
9
+ version: 1.0.3
10
+ platform: ruby
11
+ authors:
12
+ - C. Jason Harrelson (midas)
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-26 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: activerecord
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 2
43
+ - 0
44
+ - 0
45
+ version: 2.0.0
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description: A Rails gem that creates getters and setters for associated object's attributes to aid in not breaking Demeter's Law.
49
+ email: jason@lookforwardenterprises.com
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - README.rdoc
56
+ files:
57
+ - .gitignore
58
+ - History.txt
59
+ - README.rdoc
60
+ - Rakefile
61
+ - VERSION
62
+ - has_associative_facades.gemspec
63
+ - lib/has_associative_facades.rb
64
+ - lib/has_associative_facades/acts_methods.rb
65
+ - lib/has_associative_facades/instance_methods.rb
66
+ - script/console
67
+ - script/destroy
68
+ - script/generate
69
+ - spec/has_associative_facades_spec.rb
70
+ - spec/spec.opts
71
+ - spec/spec_helper.rb
72
+ - tasks/rspec.rake
73
+ has_rdoc: true
74
+ homepage: http://github.com/midas/guilded
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --charset=UTF-8
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.6
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: An active record gem that creates getters and setters for associated object's attributes to aid in not breaking Demeter's Law.
103
+ test_files:
104
+ - spec/has_associative_facades_spec.rb
105
+ - spec/spec_helper.rb