+ Spec for Net::LDAP::Entry
Pretty much rewrote the code. It now also responds to respond_to? correctly. Most of that symbol manipulation is now in just one place.
This commit is contained in:
parent
c01dc9ee89
commit
cfd9dbc922
|
@ -71,14 +71,9 @@ class LDAP
|
||||||
#
|
#
|
||||||
class Entry
|
class Entry
|
||||||
# This constructor is not generally called by user code.
|
# This constructor is not generally called by user code.
|
||||||
#--
|
#
|
||||||
# Originally, myhash took a block so we wouldn't have to
|
|
||||||
# make sure its elements returned empty arrays when necessary.
|
|
||||||
# Got rid of that to enable marshalling of Entry objects,
|
|
||||||
# but that doesn't work anyway, because Entry objects have
|
|
||||||
# singleton methods. So we define a custom dump and load.
|
|
||||||
def initialize dn = nil # :nodoc:
|
def initialize dn = nil # :nodoc:
|
||||||
@myhash = {} # originally: Hash.new {|k,v| k[v] = [] }
|
@myhash = {}
|
||||||
@myhash[:dn] = [dn]
|
@myhash[:dn] = [dn]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -95,20 +90,18 @@ class LDAP
|
||||||
#--
|
#--
|
||||||
# Discovered bug, 26Aug06: I noticed that we're not converting the
|
# Discovered bug, 26Aug06: I noticed that we're not converting the
|
||||||
# incoming value to an array if it isn't already one.
|
# incoming value to an array if it isn't already one.
|
||||||
def []= name, value # :nodoc:
|
def []=(name, value) # :nodoc:
|
||||||
sym = name.to_s.downcase.intern
|
sym = attribute_name(name)
|
||||||
value = [value] unless value.is_a?(Array)
|
value = [value] unless value.is_a?(Array)
|
||||||
@myhash[sym] = value
|
@myhash[sym] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
#--
|
#--
|
||||||
# We have to deal with this one as we do with []=
|
# We have to deal with this one as we do with []= because this one and not
|
||||||
# because this one and not the other one gets called
|
# the other one gets called in formulations like entry["CN"] << cn.
|
||||||
# in formulations like entry["CN"] << cn.
|
|
||||||
#
|
#
|
||||||
def [] name # :nodoc:
|
def [](name) # :nodoc:
|
||||||
name = name.to_s.downcase.intern unless name.is_a?(Symbol)
|
name = attribute_name(name) unless name.is_a?(Symbol)
|
||||||
@myhash[name] || []
|
@myhash[name] || []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -139,8 +132,6 @@ class LDAP
|
||||||
|
|
||||||
alias_method :each_attribute, :each
|
alias_method :each_attribute, :each
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Converts the Entry to a String, representing the
|
# Converts the Entry to a String, representing the
|
||||||
# Entry's attributes in LDIF format.
|
# Entry's attributes in LDIF format.
|
||||||
#--
|
#--
|
||||||
|
@ -166,24 +157,15 @@ class LDAP
|
||||||
|
|
||||||
#--
|
#--
|
||||||
# TODO, doesn't support broken lines.
|
# TODO, doesn't support broken lines.
|
||||||
# It generates a SINGLE Entry object from an incoming LDIF stream
|
# It generates a SINGLE Entry object from an incoming LDIF stream which is
|
||||||
# which is of course useless for big LDIF streams that encode
|
# of course useless for big LDIF streams that encode many objects.
|
||||||
# many objects.
|
|
||||||
# DO NOT DOCUMENT THIS METHOD UNTIL THESE RESTRICTIONS ARE LIFTED.
|
|
||||||
# As it is, it's useful for unmarshalling objects that we create,
|
|
||||||
# but not for reading arbitrary LDIF files.
|
|
||||||
# Eventually, we should have a class method that parses large LDIF
|
|
||||||
# streams into individual LDIF blocks (delimited by blank lines)
|
|
||||||
# and passes them here.
|
|
||||||
#
|
#
|
||||||
# There is one oddity, noticed by Matthias Tarasiewicz: as originally
|
# DO NOT DOCUMENT THIS METHOD UNTIL THESE RESTRICTIONS ARE LIFTED.
|
||||||
# written, this code would return an Entry object in which the DN
|
#
|
||||||
# attribute consisted of a two-element array, and the first element was
|
# As it is, it's useful for unmarshalling objects that we create, but not
|
||||||
# nil. That's because Entry#initialize doesn't like to create an object
|
# for reading arbitrary LDIF files. Eventually, we should have a class
|
||||||
# without a DN attribute so it adds one: nil. The workaround here is
|
# method that parses large LDIF streams into individual LDIF blocks
|
||||||
# to wipe out the nil DN after creating the Entry object, and trust the
|
# (delimited by blank lines) and passes them here.
|
||||||
# LDIF string to fill it in. If it doesn't we return a nil at the end.
|
|
||||||
# (30Sep06, FCianfrocca)
|
|
||||||
#
|
#
|
||||||
class << self
|
class << self
|
||||||
def from_single_ldif_string ldif
|
def from_single_ldif_string ldif
|
||||||
|
@ -202,35 +184,42 @@ class LDAP
|
||||||
entry.dn ? entry : nil
|
entry.dn ? entry : nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#--
|
||||||
|
# Part of the support for getter and setter style access to attributes.
|
||||||
|
#
|
||||||
|
def respond_to?(sym)
|
||||||
|
name = attribute_name(sym)
|
||||||
|
return true if valid_attribute?(name)
|
||||||
|
return super
|
||||||
|
end
|
||||||
|
|
||||||
#--
|
#--
|
||||||
# Convenience method to convert unknown method names
|
# Supports getter and setter style access for all the attributes that this
|
||||||
# to attribute references. Of course the method name
|
# entry holds.
|
||||||
# comes to us as a symbol, so let's save a little time
|
|
||||||
# and not bother with the to_s.downcase two-step.
|
|
||||||
# Of course that means that a method name like mAIL
|
|
||||||
# won't work, but we shouldn't be encouraging that
|
|
||||||
# kind of bad behavior in the first place.
|
|
||||||
# Maybe we should thow something if the caller sends
|
|
||||||
# arguments or a block...
|
|
||||||
#
|
#
|
||||||
def method_missing *args, &block # :nodoc:
|
def method_missing sym, *args, &block # :nodoc:
|
||||||
s = args[0].to_s.downcase.intern
|
name = attribute_name(sym)
|
||||||
if attribute_names.include?(s)
|
|
||||||
self[s]
|
if valid_attribute? name
|
||||||
elsif s.to_s[-1] == 61 and s.to_s.length > 1
|
if setter?(sym) && args.size == 1
|
||||||
value = args[1] or raise RuntimeError.new( "unable to set value" )
|
value = args.first
|
||||||
value = [value] unless value.is_a?(Array)
|
value = [value] unless value.instance_of?(Array)
|
||||||
name = s.to_s[0..-2].intern
|
self[name]= value
|
||||||
self[name] = value
|
|
||||||
else
|
return value
|
||||||
raise NoMethodError.new( "undefined method '#{s}'" )
|
elsif args.empty?
|
||||||
|
return self[name]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def write
|
def write
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
#--
|
#--
|
||||||
# Internal convenience method. It seems like the standard
|
# Internal convenience method. It seems like the standard
|
||||||
|
@ -249,8 +238,27 @@ class LDAP
|
||||||
end
|
end
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
private :is_attribute_value_binary?
|
|
||||||
|
# Returns the symbol that can be used to access the attribute that
|
||||||
|
# sym_or_str designates.
|
||||||
|
#
|
||||||
|
def attribute_name(sym_or_str)
|
||||||
|
str = sym_or_str.to_s.downcase
|
||||||
|
|
||||||
|
# Does str match 'something='? Still only returns :something
|
||||||
|
return str[0...-1].to_sym if str.size>1 && str[-1] == ?=
|
||||||
|
return str.to_sym
|
||||||
|
end
|
||||||
|
|
||||||
|
# Given a valid attribute symbol, returns true.
|
||||||
|
#
|
||||||
|
def valid_attribute?(attr_name)
|
||||||
|
attribute_names.include?(attr_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setter?(sym)
|
||||||
|
sym.to_s[-1] == ?=
|
||||||
|
end
|
||||||
end # class Entry
|
end # class Entry
|
||||||
|
|
||||||
|
|
||||||
|
|
51
spec/unit/ldap/entry_spec.rb
Normal file
51
spec/unit/ldap/entry_spec.rb
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Net::LDAP::Entry do
|
||||||
|
attr_reader :entry
|
||||||
|
before(:each) do
|
||||||
|
@entry = Net::LDAP::Entry.from_single_ldif_string(
|
||||||
|
%Q{dn: something
|
||||||
|
foo: foo
|
||||||
|
barAttribute: bar
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "entry access" do
|
||||||
|
it "should always respond to #dn" do
|
||||||
|
entry.should respond_to(:dn)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "<- #foo" do
|
||||||
|
it "should respond_to?" do
|
||||||
|
entry.should respond_to(:foo)
|
||||||
|
end
|
||||||
|
it "should return 'foo'" do
|
||||||
|
entry.foo.should == ['foo']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "<- #Foo" do
|
||||||
|
it "should respond_to?" do
|
||||||
|
entry.should respond_to(:Foo)
|
||||||
|
end
|
||||||
|
it "should return 'foo'" do
|
||||||
|
entry.foo.should == ['foo']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "<- #foo=" do
|
||||||
|
it "should respond_to?" do
|
||||||
|
entry.should respond_to(:foo=)
|
||||||
|
end
|
||||||
|
it "should set 'foo'" do
|
||||||
|
entry.foo= 'bar'
|
||||||
|
entry.foo.should == ['bar']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context "<- #fOo=" do
|
||||||
|
it "should return 'foo'" do
|
||||||
|
entry.fOo= 'bar'
|
||||||
|
entry.fOo.should == ['bar']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue