auto_demeter 0.0.2 → 0.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/README.md +32 -2
- data/auto_demeter.gemspec +13 -2
- data/lib/auto_demeter.rb +5 -14
- data/lib/auto_demeter/methods.rb +13 -9
- data/lib/auto_demeter/version.rb +1 -1
- data/test/auto_demeter_test.rb +78 -0
- metadata +105 -46
data/README.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# AutoDemeter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
AutoDemeter is an automated delegator to associations. The name comes from the rule of demeter is a mechanism to try to
|
|
4
|
+
prevent the bad things that happen when that rule is violated.
|
|
5
|
+
|
|
6
|
+
It's a little like the new &. (praying dot), but also works with older versions
|
|
7
|
+
of Ruby.
|
|
8
|
+
|
|
9
|
+
It was created after spending hours refactoring lots of ancient code that reached through models and associations with little
|
|
10
|
+
regard for the fact that there could be a nil somewhere which would make the whole thing blow up and the fact that I hated
|
|
11
|
+
the alternative of checking nil manually at every point whilst on the route to refactoring properly.
|
|
12
|
+
|
|
13
|
+
|
|
4
14
|
|
|
5
15
|
## Installation
|
|
6
16
|
|
|
@@ -18,7 +28,21 @@ Or install it yourself as:
|
|
|
18
28
|
|
|
19
29
|
## Usage
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
You can replace things like:
|
|
32
|
+
|
|
33
|
+
@object.user.manager.name
|
|
34
|
+
|
|
35
|
+
with
|
|
36
|
+
|
|
37
|
+
@object.user_manager_name
|
|
38
|
+
|
|
39
|
+
and rather than blowing up when user or manager return nil, the method itself will return nil.
|
|
40
|
+
|
|
41
|
+
It also let's you do things like:
|
|
42
|
+
|
|
43
|
+
@object.users.map(&:manager_name)
|
|
44
|
+
|
|
45
|
+
without having to define manager_name on the association.
|
|
22
46
|
|
|
23
47
|
## Contributing
|
|
24
48
|
|
|
@@ -27,3 +51,9 @@ TODO: Write usage instructions here
|
|
|
27
51
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
28
52
|
4. Push to the branch (`git push origin my-new-feature`)
|
|
29
53
|
5. Create new Pull Request
|
|
54
|
+
|
|
55
|
+
## Todo
|
|
56
|
+
|
|
57
|
+
1. Tests
|
|
58
|
+
2. More tests around the is and is_not mechanism
|
|
59
|
+
3. Potentially deprecate the is and is_not mechanism which should really be handled in a different gem.
|
data/auto_demeter.gemspec
CHANGED
|
@@ -18,6 +18,17 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
spec.add_development_dependency
|
|
22
|
-
|
|
21
|
+
spec.add_development_dependency 'sqlite3'
|
|
22
|
+
|
|
23
|
+
if RUBY_VERSION >= '1.9'
|
|
24
|
+
spec.add_development_dependency 'bundler'
|
|
25
|
+
spec.add_development_dependency 'rake'
|
|
26
|
+
spec.add_development_dependency 'active_record'
|
|
27
|
+
spec.add_development_dependency 'simplecov'
|
|
28
|
+
else
|
|
29
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
|
30
|
+
spec.add_development_dependency 'rake', '~>0.9.2'
|
|
31
|
+
spec.add_development_dependency 'activerecord'
|
|
32
|
+
spec.add_development_dependency 'rcov'
|
|
33
|
+
end
|
|
23
34
|
end
|
data/lib/auto_demeter.rb
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
require
|
|
2
|
-
require 'auto_demeter
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
class ActiveRecord::Associations::BelongsToAssociation
|
|
9
|
-
include AutoDemeter
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
class ActiveRecord::Associations::HasOneAssociation
|
|
13
|
-
include AutoDemeter
|
|
14
|
-
end
|
|
1
|
+
require (File.join(File.dirname(__FILE__), 'auto_demeter', 'version'))
|
|
2
|
+
require (File.join(File.dirname(__FILE__), 'auto_demeter', 'methods'))
|
|
3
|
+
ActiveRecord::Base.send :include, AutoDemeter
|
|
4
|
+
ActiveRecord::Associations::BelongsToAssociation.send :include, AutoDemeter
|
|
5
|
+
ActiveRecord::Associations::HasOneAssociation.send :include, AutoDemeter
|
data/lib/auto_demeter/methods.rb
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
module AutoDemeter
|
|
2
|
+
private
|
|
3
|
+
def base_names
|
|
4
|
+
@base_names||=self.class.reflect_on_all_associations.find_all { |x| [:has_one, :belongs_to].include?(x.send(:macro)) }.map { |x| x.send(:name).to_s }
|
|
5
|
+
end
|
|
6
|
+
|
|
2
7
|
def children_names
|
|
3
|
-
base_names=self.class.reflect_on_all_associations.find_all { |x| [:has_one, :belongs_to].include?(x.instance_variable_get("@macro")) }.map { |x| x.instance_variable_get("@name").to_s }
|
|
4
8
|
class_name=base_names.map { |x| x.gsub(/^#{self.class.name.underscore}_/, '') }
|
|
5
9
|
class_name=class_name | base_names.map { |x| x.gsub(/^#{self.base_name.underscore}_/, '') } if self.respond_to?(:base_name) && self.class.name!=self.base_name
|
|
6
|
-
base_names | class_name
|
|
10
|
+
@children_names||=base_names | class_name
|
|
7
11
|
end
|
|
8
12
|
|
|
9
13
|
def reflected_children_regex
|
|
@@ -11,19 +15,19 @@ module AutoDemeter
|
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def respond_through_association?(method_id)
|
|
14
|
-
|
|
15
|
-
if (match_data=method_id.to_s.match(reflected_children_regex)) && match_data[1].present?
|
|
18
|
+
if children_names && (match_data=method_id.to_s.match(reflected_children_regex)) && match_data[1].present?
|
|
16
19
|
association_name=self.methods.include?(match_data[1]) ? match_data[1] : "#{self.class.name.underscore}_#{match_data[1]}"
|
|
17
|
-
|
|
18
|
-
true
|
|
19
|
-
else
|
|
20
|
-
match_data[2][0..2] == 'is_' ? true : false
|
|
21
|
-
end
|
|
20
|
+
send(association_name) ? true : match_data[2][0..2] == 'is_'
|
|
22
21
|
else
|
|
23
22
|
false
|
|
24
23
|
end
|
|
25
24
|
end
|
|
26
25
|
|
|
26
|
+
public
|
|
27
|
+
def respond_to?(method_id)
|
|
28
|
+
super || (method_id != :base_name && respond_through_association?(method_id))
|
|
29
|
+
end
|
|
30
|
+
|
|
27
31
|
def method_missing(method_id, *args, &block)
|
|
28
32
|
begin
|
|
29
33
|
super
|
data/lib/auto_demeter/version.rb
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
if RUBY_VERSION >= '1.9'
|
|
3
|
+
require 'minitest/autorun'
|
|
4
|
+
require 'active_record'
|
|
5
|
+
else
|
|
6
|
+
require 'test/unit'
|
|
7
|
+
require 'activerecord'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
|
11
|
+
require File.dirname(__FILE__) + '/../lib/auto_demeter'
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
|
14
|
+
|
|
15
|
+
def setup_db
|
|
16
|
+
ActiveRecord::Base.logger
|
|
17
|
+
ActiveRecord::Schema.define(:version => 1) do
|
|
18
|
+
create_table :users do |t|
|
|
19
|
+
t.references :manager
|
|
20
|
+
t.string :name
|
|
21
|
+
end
|
|
22
|
+
create_table :addresses do |t|
|
|
23
|
+
t.references :user
|
|
24
|
+
t.string :postcode
|
|
25
|
+
end
|
|
26
|
+
create_table :managers do |t|
|
|
27
|
+
t.string :name
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class Manager < ActiveRecord::Base
|
|
33
|
+
has_many :users
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class User < ActiveRecord::Base
|
|
37
|
+
belongs_to :manager
|
|
38
|
+
has_one :address
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class Address < ActiveRecord::Base
|
|
42
|
+
belongs_to :user
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def teardown_db
|
|
46
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
|
47
|
+
ActiveRecord::Base.connection.drop_table(table)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class AutoDemeterTest < (
|
|
52
|
+
begin
|
|
53
|
+
MiniTest::Test rescue Test::Unit::TestCase
|
|
54
|
+
end)
|
|
55
|
+
|
|
56
|
+
def setup
|
|
57
|
+
setup_db
|
|
58
|
+
@paul=Manager.create(:name => 'paul')
|
|
59
|
+
User.create(:name => 'ophelia')
|
|
60
|
+
User.create(:name => 'nigel')
|
|
61
|
+
@michael=User.create(:name => 'michael', :manager => @paul)
|
|
62
|
+
@luke=User.create(:name => 'luke', :manager => @paul)
|
|
63
|
+
@michael_address=Address.create(:postcode => 'n111n', :user => @michael)
|
|
64
|
+
@luke_address=Address.create(:postcode => 'bt401uu', :user => @luke)
|
|
65
|
+
Address.create(:postcode => 'gu261aa')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_happy_path
|
|
69
|
+
assert @luke.respond_to?(:address_postcode)
|
|
70
|
+
assert @luke_address.respond_to?(:user_manager_name)
|
|
71
|
+
assert_equal @luke.address_postcode, @luke_address.postcode
|
|
72
|
+
assert_equal [@michael_address.postcode, @luke_address.postcode], @paul.users.map(&:address_postcode)
|
|
73
|
+
assert_equal @luke.name, @luke_address.user_name
|
|
74
|
+
assert_equal @paul.name, @luke_address.user_manager_name
|
|
75
|
+
assert_equal @paul.name, @luke_address.user_manager.name
|
|
76
|
+
assert_equal @paul.name, @luke_address.user.manager_name
|
|
77
|
+
end
|
|
78
|
+
end
|
metadata
CHANGED
|
@@ -1,56 +1,105 @@
|
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: auto_demeter
|
|
3
|
-
version: !ruby/object:Gem::Version
|
|
4
|
-
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 25
|
|
5
5
|
prerelease:
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 0
|
|
9
|
+
- 3
|
|
10
|
+
version: 0.0.3
|
|
6
11
|
platform: ruby
|
|
7
|
-
authors:
|
|
12
|
+
authors:
|
|
8
13
|
- Paul McKibbin
|
|
9
14
|
autorequire:
|
|
10
15
|
bindir: bin
|
|
11
16
|
cert_chain: []
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
|
|
18
|
+
date: 2016-03-19 00:00:00 Z
|
|
19
|
+
dependencies:
|
|
20
|
+
- !ruby/object:Gem::Dependency
|
|
21
|
+
name: sqlite3
|
|
22
|
+
prerelease: false
|
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
24
|
+
none: false
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
hash: 3
|
|
29
|
+
segments:
|
|
30
|
+
- 0
|
|
31
|
+
version: "0"
|
|
32
|
+
type: :development
|
|
33
|
+
version_requirements: *id001
|
|
34
|
+
- !ruby/object:Gem::Dependency
|
|
15
35
|
name: bundler
|
|
16
|
-
|
|
36
|
+
prerelease: false
|
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
17
38
|
none: false
|
|
18
|
-
requirements:
|
|
39
|
+
requirements:
|
|
19
40
|
- - ~>
|
|
20
|
-
- !ruby/object:Gem::Version
|
|
21
|
-
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
hash: 9
|
|
43
|
+
segments:
|
|
44
|
+
- 1
|
|
45
|
+
- 3
|
|
46
|
+
version: "1.3"
|
|
22
47
|
type: :development
|
|
48
|
+
version_requirements: *id002
|
|
49
|
+
- !ruby/object:Gem::Dependency
|
|
50
|
+
name: rake
|
|
23
51
|
prerelease: false
|
|
24
|
-
|
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
25
53
|
none: false
|
|
26
|
-
requirements:
|
|
54
|
+
requirements:
|
|
27
55
|
- - ~>
|
|
28
|
-
- !ruby/object:Gem::Version
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
hash: 63
|
|
58
|
+
segments:
|
|
59
|
+
- 0
|
|
60
|
+
- 9
|
|
61
|
+
- 2
|
|
62
|
+
version: 0.9.2
|
|
63
|
+
type: :development
|
|
64
|
+
version_requirements: *id003
|
|
65
|
+
- !ruby/object:Gem::Dependency
|
|
66
|
+
name: activerecord
|
|
67
|
+
prerelease: false
|
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
33
69
|
none: false
|
|
34
|
-
requirements:
|
|
35
|
-
- -
|
|
36
|
-
- !ruby/object:Gem::Version
|
|
37
|
-
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
hash: 3
|
|
74
|
+
segments:
|
|
75
|
+
- 0
|
|
76
|
+
version: "0"
|
|
38
77
|
type: :development
|
|
78
|
+
version_requirements: *id004
|
|
79
|
+
- !ruby/object:Gem::Dependency
|
|
80
|
+
name: rcov
|
|
39
81
|
prerelease: false
|
|
40
|
-
|
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
|
41
83
|
none: false
|
|
42
|
-
requirements:
|
|
43
|
-
- -
|
|
44
|
-
- !ruby/object:Gem::Version
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
84
|
+
requirements:
|
|
85
|
+
- - ">="
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
hash: 3
|
|
88
|
+
segments:
|
|
89
|
+
- 0
|
|
90
|
+
version: "0"
|
|
91
|
+
type: :development
|
|
92
|
+
version_requirements: *id005
|
|
93
|
+
description: Create automated methods for all children or parents to allow a request to be handled more easily than defining a long chain
|
|
94
|
+
email:
|
|
49
95
|
- pmckibbin@gmail.com
|
|
50
96
|
executables: []
|
|
97
|
+
|
|
51
98
|
extensions: []
|
|
99
|
+
|
|
52
100
|
extra_rdoc_files: []
|
|
53
|
-
|
|
101
|
+
|
|
102
|
+
files:
|
|
54
103
|
- .gitignore
|
|
55
104
|
- Gemfile
|
|
56
105
|
- LICENSE.txt
|
|
@@ -60,29 +109,39 @@ files:
|
|
|
60
109
|
- lib/auto_demeter.rb
|
|
61
110
|
- lib/auto_demeter/methods.rb
|
|
62
111
|
- lib/auto_demeter/version.rb
|
|
63
|
-
|
|
64
|
-
|
|
112
|
+
- test/auto_demeter_test.rb
|
|
113
|
+
homepage: ""
|
|
114
|
+
licenses:
|
|
65
115
|
- MIT
|
|
66
116
|
post_install_message:
|
|
67
117
|
rdoc_options: []
|
|
68
|
-
|
|
118
|
+
|
|
119
|
+
require_paths:
|
|
69
120
|
- lib
|
|
70
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
71
122
|
none: false
|
|
72
|
-
requirements:
|
|
73
|
-
- -
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
|
|
76
|
-
|
|
123
|
+
requirements:
|
|
124
|
+
- - ">="
|
|
125
|
+
- !ruby/object:Gem::Version
|
|
126
|
+
hash: 3
|
|
127
|
+
segments:
|
|
128
|
+
- 0
|
|
129
|
+
version: "0"
|
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
131
|
none: false
|
|
78
|
-
requirements:
|
|
79
|
-
- -
|
|
80
|
-
- !ruby/object:Gem::Version
|
|
81
|
-
|
|
132
|
+
requirements:
|
|
133
|
+
- - ">="
|
|
134
|
+
- !ruby/object:Gem::Version
|
|
135
|
+
hash: 3
|
|
136
|
+
segments:
|
|
137
|
+
- 0
|
|
138
|
+
version: "0"
|
|
82
139
|
requirements: []
|
|
140
|
+
|
|
83
141
|
rubyforge_project:
|
|
84
|
-
rubygems_version: 1.8.
|
|
142
|
+
rubygems_version: 1.8.15
|
|
85
143
|
signing_key:
|
|
86
144
|
specification_version: 3
|
|
87
145
|
summary: Automated demeter methods
|
|
88
|
-
test_files:
|
|
146
|
+
test_files:
|
|
147
|
+
- test/auto_demeter_test.rb
|