treequel 1.4.4 → 1.5.0pre445
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.tar.gz.sig +0 -0
- data/ChangeLog +117 -83
- data/Rakefile +9 -8
- data/lib/treequel.rb +3 -3
- data/lib/treequel/branch.rb +2 -1
- data/lib/treequel/branchset.rb +13 -4
- data/lib/treequel/mixins.rb +2 -2
- data/lib/treequel/model.rb +20 -0
- data/lib/treequel/model/objectclass.rb +43 -9
- data/spec/lib/constants.rb +62 -1
- data/spec/lib/helpers.rb +3 -1
- data/spec/treequel/branch_spec.rb +4 -7
- data/spec/treequel/branchset_spec.rb +47 -78
- data/spec/treequel/mixins_spec.rb +16 -0
- data/spec/treequel/model/objectclass_spec.rb +137 -23
- data/spec/treequel/model_spec.rb +20 -34
- metadata +45 -35
- metadata.gz.sig +3 -3
data/lib/treequel/model.rb
CHANGED
@@ -70,6 +70,7 @@ class Treequel::Model < Treequel::Branch
|
|
70
70
|
|
71
71
|
@objectclass_registry = SET_HASH.dup
|
72
72
|
@base_registry = SET_HASH.dup
|
73
|
+
@directory = nil
|
73
74
|
|
74
75
|
class << self
|
75
76
|
attr_reader :objectclass_registry
|
@@ -77,6 +78,25 @@ class Treequel::Model < Treequel::Branch
|
|
77
78
|
end
|
78
79
|
|
79
80
|
|
81
|
+
### Return the Treequel::Directory the Model will use for searches, creating it if it
|
82
|
+
### hasn't been created already. The default Directory will be created by calling
|
83
|
+
### Treequel.directory_from_config.
|
84
|
+
### @return [Treequel::Directory] the default directory
|
85
|
+
def self::directory
|
86
|
+
self.directory = Treequel.directory_from_config unless @directory
|
87
|
+
return @directory
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
### Set the Treequel::Directory that should be used for searches. The receiving class will also
|
92
|
+
### be set as the #results_class of the +newdirectory+.
|
93
|
+
### @param [Treequel::Directory] newdirectory
|
94
|
+
def self::directory=( newdirectory )
|
95
|
+
@directory = newdirectory
|
96
|
+
@directory.results_class = self if @directory
|
97
|
+
end
|
98
|
+
|
99
|
+
|
80
100
|
### Inheritance callback -- add a class-specific objectclass registry to inheriting classes.
|
81
101
|
### @param [Class] subclass the inheriting class
|
82
102
|
def self::inherited( subclass )
|
@@ -10,6 +10,7 @@ require 'treequel/constants'
|
|
10
10
|
# Mixin that provides Treequel::Model characteristics to a mixin module.
|
11
11
|
module Treequel::Model::ObjectClass
|
12
12
|
include Treequel::HashUtilities
|
13
|
+
extend Treequel::Delegation
|
13
14
|
|
14
15
|
|
15
16
|
### Extension callback -- add data structures to the extending +mod+.
|
@@ -30,6 +31,17 @@ module Treequel::Model::ObjectClass
|
|
30
31
|
end
|
31
32
|
|
32
33
|
|
34
|
+
#################################################################
|
35
|
+
### I N S T A N C E M E T H O D S
|
36
|
+
#################################################################
|
37
|
+
|
38
|
+
# Delegate Branchset methods through #search to allow ObjectClass.filter as a shortcut for
|
39
|
+
# ObjectClass.search.filter
|
40
|
+
def_method_delegators :search,
|
41
|
+
:collection, :map, :to_hash, :each, :first,
|
42
|
+
:filter, :scope, :select, :limit, :timeout, :as, :from
|
43
|
+
|
44
|
+
|
33
45
|
### Declare which Treequel::Model subclasses the mixin will register itself with. If this is
|
34
46
|
### used, it should be declared *before* declaring the mixin's bases and/or objectClasses.
|
35
47
|
def model_class( mclass=nil )
|
@@ -75,11 +87,30 @@ module Treequel::Model::ObjectClass
|
|
75
87
|
end
|
76
88
|
|
77
89
|
|
78
|
-
###
|
79
|
-
###
|
80
|
-
###
|
81
|
-
###
|
82
|
-
|
90
|
+
### @overload create( dn, entryhash={} )
|
91
|
+
### Create a new instance of the mixin's model_class in the model_class's default
|
92
|
+
### directory with the given +dn+ and the objectclasses specified by the mixin. If the
|
93
|
+
### optional +entryhash+ is given, it will be used as the initial attributes of the
|
94
|
+
### new entry.
|
95
|
+
### @param [#to_s] dn the DN of the new model object
|
96
|
+
### @param [Hash] entryhash attributes to set on the new entry
|
97
|
+
### @overload create( directory, dn, entryhash={} )
|
98
|
+
### Create a new instance of the mixin's model_class in the specified +directory+
|
99
|
+
### with the given +dn+ and the objectclasses specified by the mixin. If the
|
100
|
+
### optional +entryhash+ is given, it will be used as the initial attributes of the
|
101
|
+
### new entry.
|
102
|
+
### @param [Treequel::Directory] directory the directory to create the entry in (optional)
|
103
|
+
### @param [#to_s] dn the DN of the new model object
|
104
|
+
### @param [Hash] entryhash attributes to set on the new entry
|
105
|
+
def create( directory, dn=nil, entryhash={} )
|
106
|
+
|
107
|
+
# Shift the arguments if the first one isn't a directory
|
108
|
+
unless directory.is_a?( Treequel::Directory )
|
109
|
+
entryhash = dn || {}
|
110
|
+
dn = directory
|
111
|
+
directory = self.model_class.directory
|
112
|
+
end
|
113
|
+
|
83
114
|
entryhash = stringify_keys( entryhash )
|
84
115
|
|
85
116
|
# Add the objectclasses from the mixin
|
@@ -103,17 +134,20 @@ module Treequel::Model::ObjectClass
|
|
103
134
|
### base) that can be used to search the given +directory+ for entries to which
|
104
135
|
### the receiver applies.
|
105
136
|
###
|
106
|
-
### @param [Treequel::Directory] directory the directory to search
|
137
|
+
### @param [Treequel::Directory] directory the directory to search; if not given, this defaults
|
138
|
+
### to the directory associated with the module's
|
139
|
+
### model_class.
|
107
140
|
### @return [Treequel::Branchset, Treequel::BranchCollection] the encapsulated search
|
108
|
-
def search( directory )
|
141
|
+
def search( directory=nil )
|
142
|
+
directory ||= self.model_class.directory
|
109
143
|
bases = self.model_bases
|
110
144
|
objectclasses = self.model_objectclasses
|
111
145
|
|
112
146
|
raise Treequel::ModelError, "%p has no search criteria defined" % [ self ] if
|
113
147
|
bases.empty? && objectclasses.empty?
|
114
148
|
|
115
|
-
Treequel.log.debug "Creating search for %
|
116
|
-
[ self
|
149
|
+
Treequel.log.debug "Creating search for %p using model class %p" %
|
150
|
+
[ self, self.model_class ]
|
117
151
|
|
118
152
|
# Start by making a Branchset or BranchCollection for the mixin's bases. If
|
119
153
|
# the mixin doesn't have any bases, just use the base DN of the directory
|
data/spec/lib/constants.rb
CHANGED
@@ -87,7 +87,7 @@ module Treequel::TestConstants # :nodoc:all
|
|
87
87
|
TEST_PEOPLE_DN = "#{TEST_PEOPLE_RDN},#{TEST_BASE_DN}"
|
88
88
|
|
89
89
|
TEST_PERSON_DN_ATTR = 'uid'
|
90
|
-
TEST_PERSON_DN_VALUE = '
|
90
|
+
TEST_PERSON_DN_VALUE = 'slappy'
|
91
91
|
TEST_PERSON_RDN = "#{TEST_PERSON_DN_ATTR}=#{TEST_PERSON_DN_VALUE}"
|
92
92
|
TEST_PERSON_DN = "#{TEST_PERSON_RDN},#{TEST_PEOPLE_DN}"
|
93
93
|
|
@@ -124,6 +124,67 @@ module Treequel::TestConstants # :nodoc:all
|
|
124
124
|
]
|
125
125
|
TEST_HOST_MULTIVALUE_DN = "#{TEST_HOST_MULTIVALUE_RDN},#{TEST_HOSTS_DN}"
|
126
126
|
|
127
|
+
# Test entry hashes
|
128
|
+
TEST_HOSTS_ENTRY = {
|
129
|
+
'dn' => [TEST_HOSTS_DN],
|
130
|
+
TEST_HOSTS_DN_ATTR => [TEST_HOSTS_DN_VALUE],
|
131
|
+
'objectClass' => ['top', 'organizationalUnit'],
|
132
|
+
'description' => ['Hosts under acme.com'],
|
133
|
+
}
|
134
|
+
|
135
|
+
TEST_PEOPLE_ENTRY = {
|
136
|
+
'dn' => [TEST_PEOPLE_DN],
|
137
|
+
TEST_PEOPLE_DN_ATTR => [TEST_PEOPLE_DN_VALUE],
|
138
|
+
'objectClass' => ['top', 'organizationalUnit'],
|
139
|
+
'description' => ['Acme.com employees'],
|
140
|
+
}
|
141
|
+
|
142
|
+
TEST_PERSON_ENTRY = {
|
143
|
+
'dn' => [TEST_PERSON_DN],
|
144
|
+
TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE],
|
145
|
+
'cn' => ['Slappy the Frog'],
|
146
|
+
'givenName' => ['Slappy'],
|
147
|
+
'sn' => ['Frog'],
|
148
|
+
'l' => ['a forest in England'],
|
149
|
+
'title' => ['Forest Fire Prevention Advocate'],
|
150
|
+
'displayName' => ['Slappy the Frog'],
|
151
|
+
'logonTime' => ['1293167318'],
|
152
|
+
'uidNumber' => ['1121'],
|
153
|
+
'gidNumber' => ['200'],
|
154
|
+
'homeDirectory' => ['/u/j/jrandom'],
|
155
|
+
'description' => [
|
156
|
+
'Smokey the Bear is much more intense in person.',
|
157
|
+
'Alright.'
|
158
|
+
],
|
159
|
+
'objectClass' => %w[
|
160
|
+
top
|
161
|
+
person
|
162
|
+
organizationalPerson
|
163
|
+
inetOrgPerson
|
164
|
+
posixAccount
|
165
|
+
shadowAccount
|
166
|
+
apple-user
|
167
|
+
],
|
168
|
+
}
|
169
|
+
|
170
|
+
TEST_OPERATIONAL_PEOPLE_ENTRY = {
|
171
|
+
TEST_PEOPLE_DN_ATTR => [TEST_PEOPLE_DN_VALUE],
|
172
|
+
'structuralObjectClass' => ['organizationalUnit'],
|
173
|
+
'entryUUID' => ['5035e674-bae3-102b-992e-e9e937d524d6'],
|
174
|
+
'creatorsName' => ['cn=admin,dc=laika,dc=com'],
|
175
|
+
'createTimestamp' => ['20070629232213Z'],
|
176
|
+
'entryCSN' => ['20070629232213.000000Z#000000#000#000000'],
|
177
|
+
'modifiersName' => ['cn=admin,dc=laika,dc=com'],
|
178
|
+
'modifyTimestamp' => ['20070629232213Z'],
|
179
|
+
'entryDN' => [TEST_PEOPLE_DN],
|
180
|
+
'subschemaSubentry' => ['cn=Subschema'],
|
181
|
+
'hasSubordinates' => ['TRUE'],
|
182
|
+
'dn' => [TEST_PEOPLE_DN],
|
183
|
+
'objectClass' => ['top', 'organizationalUnit'],
|
184
|
+
'description' => ['Acme.com employees'],
|
185
|
+
}
|
186
|
+
|
187
|
+
|
127
188
|
constants.each do |cname|
|
128
189
|
const_get(cname).freeze
|
129
190
|
end
|
data/spec/lib/helpers.rb
CHANGED
@@ -127,7 +127,7 @@ module Treequel::SpecHelpers
|
|
127
127
|
### LDAP connection. Also pre-loads the schema object and fixtures some other
|
128
128
|
### external data.
|
129
129
|
def get_fixtured_directory( conn )
|
130
|
-
LDAP::SSLConn.stub( :new ).and_return(
|
130
|
+
LDAP::SSLConn.stub( :new ).and_return( conn )
|
131
131
|
conn.stub( :search_ext2 ).
|
132
132
|
with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
|
133
133
|
and_return( TEST_DSE )
|
@@ -163,6 +163,8 @@ end
|
|
163
163
|
|
164
164
|
### Mock with Rspec
|
165
165
|
Rspec.configure do |c|
|
166
|
+
include Treequel::TestConstants
|
167
|
+
|
166
168
|
c.mock_with :rspec
|
167
169
|
|
168
170
|
c.extend( Treequel::TestConstants )
|
@@ -28,9 +28,6 @@ include Treequel::Constants
|
|
28
28
|
#####################################################################
|
29
29
|
|
30
30
|
describe Treequel::Branch do
|
31
|
-
include Treequel::SpecHelpers,
|
32
|
-
Treequel::Matchers
|
33
|
-
|
34
31
|
|
35
32
|
before( :all ) do
|
36
33
|
setup_logging( :fatal )
|
@@ -241,13 +238,13 @@ describe Treequel::Branch do
|
|
241
238
|
|
242
239
|
it "clears any cached values if its include_operational_attrs attribute is changed" do
|
243
240
|
@directory.should_receive( :get_entry ).with( @branch ).exactly( :once ).
|
244
|
-
and_return(
|
241
|
+
and_return( TEST_PEOPLE_ENTRY.dup )
|
245
242
|
@directory.should_receive( :get_extended_entry ).with( @branch ).exactly( :once ).
|
246
|
-
and_return(
|
243
|
+
and_return( TEST_OPERATIONAL_PEOPLE_ENTRY.dup )
|
247
244
|
|
248
|
-
@branch.entry.should ==
|
245
|
+
@branch.entry.should == TEST_PEOPLE_ENTRY.dup.tap {|entry| entry.delete('dn') }
|
249
246
|
@branch.include_operational_attrs = true
|
250
|
-
@branch.entry.should ==
|
247
|
+
@branch.entry.should == TEST_OPERATIONAL_PEOPLE_ENTRY.dup.tap {|entry| entry.delete('dn') }
|
251
248
|
end
|
252
249
|
|
253
250
|
it "returns a human-readable representation of itself for #inspect" do
|
@@ -34,6 +34,7 @@ describe Treequel::Branchset do
|
|
34
34
|
:server_controls => [],
|
35
35
|
}
|
36
36
|
|
37
|
+
|
37
38
|
before( :all ) do
|
38
39
|
setup_logging( :fatal )
|
39
40
|
end
|
@@ -56,12 +57,10 @@ describe Treequel::Branchset do
|
|
56
57
|
end
|
57
58
|
|
58
59
|
it "is Enumerable" do
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
and_yield( resultbranch )
|
64
|
-
resultbranch.should_receive( :dn ).and_return( :its_dn )
|
60
|
+
@conn.should_receive( :search_ext2 ).
|
61
|
+
with( TEST_BASE_DN, LDAP::LDAP_SCOPE_SUBTREE, "(objectClass=*)",
|
62
|
+
[], false, [], [], 0, 0, 0, "", nil ).
|
63
|
+
and_return([ TEST_HOSTS_ENTRY.dup ])
|
65
64
|
|
66
65
|
@branchset.all? {|b| b.dn }
|
67
66
|
end
|
@@ -70,20 +69,18 @@ describe Treequel::Branchset do
|
|
70
69
|
# #empty?
|
71
70
|
#
|
72
71
|
it "is empty if it doesn't match at least one entry" do
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
and_return(
|
77
|
-
|
72
|
+
@conn.should_receive( :search_ext2 ).
|
73
|
+
with( TEST_BASE_DN, LDAP::LDAP_SCOPE_SUBTREE, "(objectClass=*)",
|
74
|
+
[], false, [], [], 0, 0, 1, "", nil ).
|
75
|
+
and_return([ ])
|
78
76
|
@branchset.should be_empty()
|
79
77
|
end
|
80
78
|
|
81
79
|
it "isn't empty if it matches at least one entry" do
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
and_return(
|
86
|
-
|
80
|
+
@conn.should_receive( :search_ext2 ).
|
81
|
+
with( TEST_BASE_DN, LDAP::LDAP_SCOPE_SUBTREE, "(objectClass=*)",
|
82
|
+
[], false, [], [], 0, 0, 1, "", nil ).
|
83
|
+
and_return([ TEST_HOSTS_ENTRY.dup ])
|
87
84
|
@branchset.should_not be_empty()
|
88
85
|
end
|
89
86
|
|
@@ -91,16 +88,12 @@ describe Treequel::Branchset do
|
|
91
88
|
# #map
|
92
89
|
#
|
93
90
|
it "can be mapped into an Array of attribute values" do
|
94
|
-
|
95
|
-
|
91
|
+
@conn.should_receive( :search_ext2 ).
|
92
|
+
with( TEST_BASE_DN, LDAP::LDAP_SCOPE_SUBTREE, "(objectClass=*)",
|
93
|
+
[], false, [], [], 0, 0, 0, "", nil ).
|
94
|
+
and_return([ TEST_HOSTS_ENTRY.dup, TEST_PEOPLE_ENTRY.dup ])
|
96
95
|
|
97
|
-
@
|
98
|
-
with( Treequel::Branchset::DEFAULT_SCOPE, @branchset.filter, @params ).
|
99
|
-
and_yield( resultbranch ).and_yield( resultbranch2 )
|
100
|
-
resultbranch.should_receive( :[] ).with( :cn ).and_return([ :first_cn ])
|
101
|
-
resultbranch2.should_receive( :[] ).with( :cn ).and_return([ :second_cn ])
|
102
|
-
|
103
|
-
@branchset.map( :cn ).should == [[:first_cn], [:second_cn]]
|
96
|
+
@branchset.map( :ou ).should == [ ['Hosts'], ['People'] ]
|
104
97
|
end
|
105
98
|
|
106
99
|
|
@@ -108,47 +101,30 @@ describe Treequel::Branchset do
|
|
108
101
|
# #to_hash
|
109
102
|
#
|
110
103
|
it "can be mapped into a Hash of entries keyed by one of its attributes" do
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
resultbranch2.should_receive( :entry ).and_return( :entry2 )
|
124
|
-
|
125
|
-
@branchset.to_hash( :email ).should == {
|
126
|
-
:first_email => :entry1,
|
127
|
-
:second_email => :entry2,
|
104
|
+
@conn.should_receive( :search_ext2 ).
|
105
|
+
with( "dc=acme,dc=com", 2, "(objectClass=*)", [], false, [], [], 0, 0, 0, "", nil ).
|
106
|
+
and_return([ TEST_HOSTS_ENTRY.dup, TEST_PEOPLE_ENTRY.dup ])
|
107
|
+
|
108
|
+
hosthash = TEST_HOSTS_ENTRY.dup
|
109
|
+
hosthash.delete( 'dn' )
|
110
|
+
peoplehash = TEST_PEOPLE_ENTRY.dup
|
111
|
+
peoplehash.delete( 'dn' )
|
112
|
+
|
113
|
+
@branchset.to_hash( :ou ).should == {
|
114
|
+
'Hosts' => hosthash,
|
115
|
+
'People' => peoplehash,
|
128
116
|
}
|
129
117
|
end
|
130
118
|
|
131
119
|
|
132
120
|
it "can be mapped into a Hash of tuples using two attributes" do
|
133
|
-
|
134
|
-
|
121
|
+
@conn.should_receive( :search_ext2 ).
|
122
|
+
with( "dc=acme,dc=com", 2, "(objectClass=*)", [], false, [], [], 0, 0, 0, "", nil ).
|
123
|
+
and_return([ TEST_HOSTS_ENTRY.dup, TEST_PEOPLE_ENTRY.dup ])
|
135
124
|
|
136
|
-
@
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
resultbranch.should_receive( :[] ).with( :email ).
|
141
|
-
and_return([ :first_email ])
|
142
|
-
resultbranch.should_receive( :[] ).with( :cn ).
|
143
|
-
and_return([ :first_cn ])
|
144
|
-
resultbranch2.should_receive( :[] ).with( :email ).
|
145
|
-
and_return([ :second_email, :second_second_email ])
|
146
|
-
resultbranch2.should_receive( :[] ).with( :cn ).
|
147
|
-
and_return([ :second_cn, :second_second_cn ])
|
148
|
-
|
149
|
-
@branchset.to_hash( :email, :cn ).should == {
|
150
|
-
:first_email => :first_cn,
|
151
|
-
:second_email => :second_cn,
|
125
|
+
@branchset.to_hash( :ou, :description ).should == {
|
126
|
+
'Hosts' => TEST_HOSTS_ENTRY['description'].first,
|
127
|
+
'People' => TEST_PEOPLE_ENTRY['description'].first,
|
152
128
|
}
|
153
129
|
end
|
154
130
|
|
@@ -156,8 +132,7 @@ describe Treequel::Branchset do
|
|
156
132
|
# #+
|
157
133
|
#
|
158
134
|
it "can be combined with another instance into a BranchCollection by adding them together" do
|
159
|
-
other_branch =
|
160
|
-
other_branch.stub( :directory ).and_return( @directory )
|
135
|
+
other_branch = @directory.ou( :people )
|
161
136
|
other_branchset = Treequel::Branchset.new( other_branch )
|
162
137
|
|
163
138
|
result = @branchset + other_branchset
|
@@ -167,18 +142,15 @@ describe Treequel::Branchset do
|
|
167
142
|
end
|
168
143
|
|
169
144
|
it "returns the results of the search with the additional Branch if one is added to it" do
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
resultbranch2 = mock( "Result Branch 2" )
|
145
|
+
@conn.should_receive( :search_ext2 ).
|
146
|
+
with( "dc=acme,dc=com", 2, "(objectClass=*)", [], false, [], [], 0, 0, 0, "", nil ).
|
147
|
+
and_return([ TEST_HOSTS_ENTRY.dup, TEST_PEOPLE_ENTRY.dup ])
|
174
148
|
|
175
|
-
@
|
176
|
-
with( Treequel::Branchset::DEFAULT_SCOPE, @branchset.filter, @params ).
|
177
|
-
and_yield( resultbranch ).and_yield( resultbranch2 )
|
149
|
+
other_branch = @directory.ou( :netgroups )
|
178
150
|
|
179
151
|
result = @branchset + other_branch
|
180
152
|
result.should have( 3 ).members
|
181
|
-
result.should include( other_branch
|
153
|
+
result.should include( other_branch )
|
182
154
|
end
|
183
155
|
|
184
156
|
#
|
@@ -186,18 +158,15 @@ describe Treequel::Branchset do
|
|
186
158
|
#
|
187
159
|
it "returns the results of the search without the specified object if an object is " +
|
188
160
|
"subtracted from it" do
|
189
|
-
|
190
|
-
resultbranch2 = stub( "Result Branch 2", :dn => TEST_PERSON2_DN )
|
191
|
-
|
192
|
-
otherbranch = stub( "Subtracted Branch", :dn => TEST_PERSON2_DN )
|
161
|
+
otherbranch = @directory.ou( :people )
|
193
162
|
|
194
|
-
@
|
195
|
-
with(
|
196
|
-
|
163
|
+
@conn.should_receive( :search_ext2 ).
|
164
|
+
with( "dc=acme,dc=com", 2, "(objectClass=*)", [], false, [], [], 0, 0, 0, "", nil ).
|
165
|
+
and_return([ TEST_HOSTS_ENTRY.dup, TEST_PEOPLE_ENTRY.dup ])
|
197
166
|
|
198
167
|
result = @branchset - otherbranch
|
199
168
|
result.should have( 1 ).members
|
200
|
-
result.should_not include(
|
169
|
+
result.should_not include( otherbranch )
|
201
170
|
end
|
202
171
|
|
203
172
|
end
|
@@ -245,6 +245,14 @@ describe Treequel, "mixin" do
|
|
245
245
|
@obj.delegated_method( :arg1, :arg2 )
|
246
246
|
end
|
247
247
|
|
248
|
+
it "allows delegation to the delegate object's method with a block" do
|
249
|
+
@subobj.should_receive( :delegated_method ).with( :arg1 ).
|
250
|
+
and_yield( :the_block_argument )
|
251
|
+
blockarg = nil
|
252
|
+
@obj.delegated_method( :arg1 ) {|arg| blockarg = arg }
|
253
|
+
blockarg.should == :the_block_argument
|
254
|
+
end
|
255
|
+
|
248
256
|
it "reports errors from its caller's perspective", :ruby_1_8_only => true do
|
249
257
|
begin
|
250
258
|
@obj.erroring_delegated_method
|
@@ -291,6 +299,14 @@ describe Treequel, "mixin" do
|
|
291
299
|
@obj.delegated_method( :arg1, :arg2 )
|
292
300
|
end
|
293
301
|
|
302
|
+
it "allows delegation to the delegate's method with a block" do
|
303
|
+
@subobj.should_receive( :delegated_method ).with( :arg1 ).
|
304
|
+
and_yield( :the_block_argument )
|
305
|
+
blockarg = nil
|
306
|
+
@obj.delegated_method( :arg1 ) {|arg| blockarg = arg }
|
307
|
+
blockarg.should == :the_block_argument
|
308
|
+
end
|
309
|
+
|
294
310
|
it "reports errors from its caller's perspective", :ruby_1_8_only => true do
|
295
311
|
begin
|
296
312
|
@obj.erroring_delegated_method
|