treequel 1.1.1 → 1.2.0pre320

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +49 -1
  3. data/README.md +65 -0
  4. data/Rakefile +24 -19
  5. data/bin/treequel +20 -3
  6. data/lib/treequel.rb +3 -3
  7. data/lib/treequel/branch.rb +21 -7
  8. data/lib/treequel/branchset.rb +10 -0
  9. data/lib/treequel/model.rb +12 -2
  10. data/lib/treequel/schema.rb +1 -1
  11. data/rake/documentation.rb +9 -2
  12. data/rake/hg.rb +16 -3
  13. data/rake/manual.rb +1 -1
  14. data/rake/packaging.rb +1 -1
  15. data/rake/publishing.rb +158 -95
  16. data/rake/testing.rb +52 -88
  17. data/spec/lib/constants.rb +1 -0
  18. data/spec/lib/control_behavior.rb +7 -5
  19. data/spec/lib/helpers.rb +40 -17
  20. data/spec/lib/matchers.rb +2 -0
  21. data/spec/treequel/branch_spec.rb +44 -21
  22. data/spec/treequel/branchcollection_spec.rb +4 -3
  23. data/spec/treequel/branchset_spec.rb +42 -31
  24. data/spec/treequel/control_spec.rb +2 -1
  25. data/spec/treequel/controls/contentsync_spec.rb +2 -1
  26. data/spec/treequel/controls/pagedresults_spec.rb +4 -7
  27. data/spec/treequel/controls/sortedresults_spec.rb +4 -7
  28. data/spec/treequel/directory_spec.rb +11 -12
  29. data/spec/treequel/filter_spec.rb +7 -14
  30. data/spec/treequel/mixins_spec.rb +4 -9
  31. data/spec/treequel/model/objectclass_spec.rb +2 -1
  32. data/spec/treequel/model_spec.rb +16 -35
  33. data/spec/treequel/monkeypatches_spec.rb +12 -1
  34. data/spec/treequel/schema/attributetype_spec.rb +2 -1
  35. data/spec/treequel/schema/ldapsyntax_spec.rb +2 -1
  36. data/spec/treequel/schema/matchingrule_spec.rb +2 -1
  37. data/spec/treequel/schema/matchingruleuse_spec.rb +2 -1
  38. data/spec/treequel/schema/objectclass_spec.rb +2 -1
  39. data/spec/treequel/schema/table_spec.rb +2 -1
  40. data/spec/treequel/schema_spec.rb +2 -1
  41. data/spec/treequel_spec.rb +10 -2
  42. metadata +16 -17
  43. metadata.gz.sig +0 -0
  44. data/README +0 -66
data.tar.gz.sig CHANGED
Binary file
data/ChangeLog CHANGED
@@ -1,4 +1,52 @@
1
- 304[tip] 92c28b14730a 2010-09-20 13:51 -0700 ged
1
+ 320[tip] ccdee2d78e68 2010-11-24 18:21 -0800 ged
2
+ Updated build system.
3
+
4
+ 319 47697f2ebc27 2010-11-24 18:18 -0800 ged
5
+ Added hash-key conversion so Branches can be constructed with Symbol-key hashargs.
6
+
7
+ 318 44f8be0662c4 2010-11-18 15:43 -0800 ged
8
+ Adding 'Treequel::Branchset#from' mutator for changing the base DN.
9
+
10
+ 317:316,315 72dd41272f6f 2010-11-11 12:46 -0600 ged
11
+ Merging with 316:33a7dcde80a1
12
+
13
+ 316:313 9f9460125077 2010-11-11 10:59 -0600 ged
14
+ Spec fixes for RSpec 2.0
15
+
16
+ 315 33a7dcde80a1 2010-11-09 13:00 -0800 ged
17
+ Readding subrepo
18
+
19
+ 314 fc9ae9f5b034 2010-11-09 12:53 -0800 ged
20
+ Fixing subrepo corruption caused by rollback
21
+
22
+ 313:312,311 c1b750e4e9fc 2010-11-09 12:09 -0800 ged
23
+ Merged with 310:cc7c63ff15a0
24
+
25
+ 312:310 380662d385e0 2010-11-09 12:08 -0800 ged
26
+ stub! -> stub; added more debugging to try to track down the model test failure
27
+
28
+ 311:309 cc7c63ff15a0 2010-11-03 07:50 -0700 ged
29
+ Converting the README to Markdown
30
+
31
+ 310 7f20ab74d6b1 2010-11-08 12:53 -0800 ged
32
+ Fixed treequel shell's cp to support relative and absolute DNs
33
+
34
+ 309 26c3853695ea 2010-10-22 17:47 -0700 ged
35
+ Converted to RSpec 2.0
36
+
37
+ 308 98b6847de872 2010-10-22 14:58 -0700 ged
38
+ Updating build system; add requirement for Ruby 1.8.7
39
+
40
+ 307 7f70394868e2 2010-09-21 08:49 -0700 ged
41
+ Added tag 1.1.1 for changeset e52c71f4e4ca
42
+
43
+ 306[1.1.1] e52c71f4e4ca 2010-09-21 08:49 -0700 ged
44
+ Added signature for changeset c6d26ab6a7a4
45
+
46
+ 305 c6d26ab6a7a4 2010-09-21 08:48 -0700 ged
47
+ Critical bugfix.
48
+
49
+ 304 92c28b14730a 2010-09-20 13:51 -0700 ged
2
50
  Added tag 1.1.0 for changeset b415e0fce774
3
51
 
4
52
  303[1.1.0] b415e0fce774 2010-09-20 13:51 -0700 ged
@@ -0,0 +1,65 @@
1
+ # Treequel - an honest LDAP library
2
+
3
+ Treequel is an LDAP toolkit for Ruby. It is intended to allow quick, easy
4
+ access to LDAP directories in a manner consistent with LDAP's hierarchical,
5
+ free-form nature.
6
+
7
+ It's inspired by and modeled after [Sequel](http://sequel.rubyforge.org/), a
8
+ kick-ass database library.
9
+
10
+
11
+ ## Examples
12
+
13
+ Here are a few short examples to whet your appetite:
14
+
15
+ # Connect to the directory at the specified URL
16
+ dir = Treequel.directory( 'ldap://ldap.company.com/dc=company,dc=com' )
17
+
18
+ # Get a list of email addresses of every person in the directory (as
19
+ # long as people are under ou=people)
20
+ dir.ou( :people ).filter( :mail ).map( :mail ).flatten
21
+
22
+ # Get a list of all IP addresses for all hosts in any ou=hosts group
23
+ # in the whole directory:
24
+ dir.filter( :ou => :hosts ).collection.filter( :ipHostNumber ).
25
+ map( :ipHostNumber ).flatten
26
+
27
+ # Get all people in the directory in the form of a hash of names
28
+ # keyed by email addresses
29
+ dir.ou( :people ).filter( :mail ).to_hash( :mail, :cn )
30
+
31
+ More elaborate examples of real-world usage can be found
32
+ [in the examples/ directory][examples] in the distribution.
33
+
34
+
35
+ ## Contributing
36
+
37
+ You can check out the current development source [with Mercurial][hgrepo], or
38
+ if you prefer Git, via the project's [Github mirror][gitmirror].
39
+
40
+ You can submit bug reports, suggestions, and read more about future plans at
41
+ [the project page][projectpage].
42
+
43
+
44
+ ## License
45
+
46
+ See the included LICENSE file for licensing details.
47
+
48
+
49
+ ## Authors
50
+
51
+ * Michael Granger
52
+ * Mahlon E. Smith
53
+
54
+
55
+ ## Contributors
56
+
57
+ A special thanks to Ben Bleything, who was part of the initial brainstorm that
58
+ led to the creation of this library.
59
+
60
+
61
+ [examples]:http://deveiate.org/projects/Treequel/browser/examples
62
+ [hgrepo]:http://repo.deveiate.org/Treequel
63
+ [gitmirror]:https://github.com/ged/treequel
64
+ [projectpage]:http://deveiate.org/projects/Treequel
65
+
data/Rakefile CHANGED
@@ -171,9 +171,9 @@ include RakefileHelpers
171
171
  # Set the build ID if the mercurial executable is available
172
172
  if hg = which( 'hg' )
173
173
  id = `#{hg} id -n`.chomp
174
- PKG_BUILD = "pre%03d" % [(id.chomp[ /^[[:xdigit:]]+/ ] || '1')]
174
+ PKG_BUILD = (id.chomp[ /^[[:xdigit:]]+/ ] || '1')
175
175
  else
176
- PKG_BUILD = 'pre000'
176
+ PKG_BUILD = '0'
177
177
  end
178
178
  SNAPSHOT_PKG_NAME = "#{PKG_FILE_NAME}.#{PKG_BUILD}"
179
179
  SNAPSHOT_GEM_NAME = "#{SNAPSHOT_PKG_NAME}.gem"
@@ -190,7 +190,6 @@ RDOC_OPTIONS = [
190
190
  ]
191
191
  YARD_OPTIONS = [
192
192
  '--use-cache',
193
- '--no-private',
194
193
  '--protected',
195
194
  '-r', README_FILE,
196
195
  '--exclude', 'extconf\\.rb',
@@ -210,27 +209,29 @@ PROJECT_DOCDIR = "#{PROJECT_PUBDIR}/#{PKG_NAME}"
210
209
  PROJECT_SCPPUBURL = "#{PROJECT_HOST}:#{PROJECT_PUBDIR}"
211
210
  PROJECT_SCPDOCURL = "#{PROJECT_HOST}:#{PROJECT_DOCDIR}"
212
211
 
212
+ GEM_PUBHOST = 'rubygems.org'
213
+
213
214
  # Gem dependencies: gemname => version
214
215
  DEPENDENCIES = {
215
- 'ruby-ldap' => '>= 0.9.9',
216
+ 'ruby-ldap' => '~> 0.9.9',
216
217
  }
217
218
 
218
219
  # Developer Gem dependencies: gemname => version
219
220
  DEVELOPMENT_DEPENDENCIES = {
220
- 'rake' => '>= 0.8.7',
221
- 'rcodetools' => '>= 0.7.0.0',
222
- 'rcov' => '>= 0.8.1.2.0',
223
- 'rdoc' => '>= 2.4.3',
224
- 'RedCloth' => '>= 4.0.3',
225
- 'rspec' => '>= 1.2.6',
226
- 'ruby-termios' => '>= 0.9.6',
227
- 'text-format' => '>= 1.0.0',
228
- 'tmail' => '>= 1.2.3.1',
229
- 'diff-lcs' => '>= 1.1.2',
230
- 'columnize' => '>= 0.3.1',
231
- 'diff-lcs' => '>= 1.1.2',
232
- 'ruby-termios' => '>= 0.9.6',
233
- 'ruby-terminfo' => '>= 0.1.1',
221
+ 'rake' => '~> 0.8.7',
222
+ 'rcodetools' => '~> 0.7.0.0',
223
+ 'rcov' => '~> 0.8.1.2.0',
224
+ 'yard' => '~> 0.6.1',
225
+ 'RedCloth' => '~> 4.2.3',
226
+ 'rspec' => '~> 2.0.1',
227
+ 'ruby-termios' => '~> 0.9.6',
228
+ 'text-format' => '~> 1.0.0',
229
+ 'tmail' => '~> 1.2.3.1',
230
+ 'columnize' => '~> 0.3.1',
231
+ 'diff-lcs' => '~> 1.1.2',
232
+ 'ruby-termios' => '~> 0.9.6',
233
+ 'rspec' => '~> 2.0.1',
234
+ 'ruby-terminfo' => '~> 0.1.1',
234
235
  }
235
236
 
236
237
  # Non-gem requirements: packagename => version
@@ -258,9 +259,10 @@ GEMSPEC = Gem::Specification.new do |gem|
258
259
  " - diff-lcs",
259
260
  ].join( "\n" )
260
261
 
261
- gem.authors = "Michael Granger, Mahlon E. Smith"
262
+ gem.authors = ["Michael Granger", "Mahlon E. Smith"]
262
263
  gem.email = ["mahlon@martini.nu", "ged@FaerieMUD.org"]
263
264
  gem.homepage = 'http://deveiate.org/projects/Treequel'
265
+ gem.licenses = ["BSD"]
264
266
 
265
267
  gem.has_rdoc = true
266
268
  gem.rdoc_options = RDOC_OPTIONS
@@ -282,6 +284,9 @@ GEMSPEC = Gem::Specification.new do |gem|
282
284
  gem.signing_key = '/Volumes/Keys/ged-private_gem_key.pem'
283
285
  gem.cert_chain = [File.expand_path('~/.gem/ged-public_gem_cert.pem')]
284
286
 
287
+
288
+ gem.required_ruby_version = '>=1.8.7'
289
+
285
290
  DEPENDENCIES.each do |name, version|
286
291
  version = '>= 0' if version.length.zero?
287
292
  gem.add_runtime_dependency( name, version )
@@ -690,10 +690,27 @@ class Treequel::Shell
690
690
 
691
691
  ### Copy an entry
692
692
  def cp_command( options, rdn, newrdn )
693
- branch = @currbranch.get_child( rdn )
694
- newbranch = @currbranch.get_child( newrdn )
693
+ base_dn = @currbranch.directory.base_dn
694
+
695
+ # If the RDN includes the base, it's a DN
696
+ branch = if rdn =~ /,#{base_dn}$/i
697
+ Treequel::Branch.new( @currbranch.directory, rdn )
698
+ else
699
+ @currbranch.get_child( rdn )
700
+ end
701
+
702
+ # The source should already exist
703
+ raise "#{branch.dn}: no such entry" unless branch.exists?
704
+
705
+ # Same for the other RDN...
706
+ newbranch = if newrdn =~ /,#{base_dn}$/i
707
+ Treequel::Branch.new( @currbranch.directory, newrdn )
708
+ else
709
+ @currbranch.get_child( newrdn )
710
+ end
695
711
 
696
- raise "#{branch.dn}: already exists" if newbranch.exists?
712
+ # But it *shouldn't* exist already
713
+ raise "#{newbranch.dn}: already exists" if newbranch.exists?
697
714
 
698
715
  attributes = branch.entry.merge( :dn => newbranch.dn )
699
716
  newbranch.create( attributes )
@@ -25,7 +25,7 @@ end
25
25
 
26
26
  # A library for interacting with LDAP modelled after Sequel.
27
27
  #
28
- # @version 1.1.1
28
+ # @version 1.2.0
29
29
  #
30
30
  # @example
31
31
  # # Connect to the directory at the specified URL
@@ -53,10 +53,10 @@ end
53
53
  module Treequel
54
54
 
55
55
  # Library version
56
- VERSION = '1.1.1'
56
+ VERSION = '1.2.0'
57
57
 
58
58
  # VCS revision
59
- REVISION = %q$Revision: c6d26ab6a7a4 $
59
+ REVISION = %q$Revision: 44f8be0662c4 $
60
60
 
61
61
  # Common paths for ldap.conf
62
62
  COMMON_LDAP_CONF_PATHS = %w[
@@ -17,7 +17,8 @@ class Treequel::Branch
17
17
  include Comparable,
18
18
  Treequel::Loggable,
19
19
  Treequel::Constants,
20
- Treequel::Constants::Patterns
20
+ Treequel::Constants::Patterns,
21
+ Treequel::HashUtilities
21
22
 
22
23
  extend Treequel::Delegation,
23
24
  Treequel::AttributeDeclarations
@@ -52,6 +53,7 @@ class Treequel::Branch
52
53
  ###
53
54
  ### @return [Treequel::Branch] The new branch object.
54
55
  def self::new_from_entry( entry, directory )
56
+ entry = Treequel::HashUtilities.stringify_keys( entry )
55
57
  return self.new( directory, entry['dn'].first, entry )
56
58
  end
57
59
 
@@ -76,7 +78,7 @@ class Treequel::Branch
76
78
 
77
79
  @directory = directory
78
80
  @dn = dn
79
- @entry = entry
81
+ @entry = entry ? stringify_keys( entry ) : nil
80
82
  @values = {}
81
83
 
82
84
  @include_operational_attrs = self.class.include_operational_attrs?
@@ -287,11 +289,13 @@ class Treequel::Branch
287
289
  attrsym = attrname.to_sym
288
290
 
289
291
  unless @values.key?( attrsym )
292
+ self.log.debug " value for %p is NOT cached." % [ attrsym ]
290
293
  value = self.get_converted_object( attrsym )
294
+ self.log.debug " converted value is: %p" % [ value ]
291
295
  value.freeze if value.respond_to?( :freeze )
292
296
  @values[ attrsym ] = value
293
297
  else
294
- self.log.debug " value is cached."
298
+ self.log.debug " value for %p is cached." % [ attrname ]
295
299
  end
296
300
 
297
301
  return @values[ attrsym ]
@@ -474,11 +478,13 @@ class Treequel::Branch
474
478
  ### @param [Array<String, Symbol>] additional_classes
475
479
  ### @return [Array<Treequel::Schema::ObjectClass>]
476
480
  def object_classes( *additional_classes )
481
+ self.log.debug "Fetching object classes for %s" % [ self.dn ]
477
482
  schema = self.directory.schema
478
483
 
479
484
  oc_oids = self[:objectClass] || []
485
+ self.log.debug " objectClass OIDs are: %p" % [ oc_oids ]
480
486
  oc_oids |= additional_classes.collect {|str| str.to_sym }
481
- oc_oids << 'top' if oc_oids.empty?
487
+ oc_oids << :top if oc_oids.empty?
482
488
 
483
489
  oclasses = []
484
490
  oc_oids.each do |oid|
@@ -487,6 +493,7 @@ class Treequel::Branch
487
493
  oclasses << oc
488
494
  end
489
495
 
496
+ self.log.debug " found %d objectClasses: %p" % [ oclasses.length, oclasses ]
490
497
  return oclasses.uniq
491
498
  end
492
499
 
@@ -517,7 +524,8 @@ class Treequel::Branch
517
524
  def must_attribute_types( *additional_object_classes )
518
525
  types = []
519
526
  oclasses = self.object_classes( *additional_object_classes )
520
- self.log.debug "Gathering MUST attribute types for objectClasses: %p" % [ oclasses ]
527
+ self.log.debug "Gathering MUST attribute types for objectClasses: %p" %
528
+ [ oclasses.map(&:name) ]
521
529
 
522
530
  oclasses.each do |oc|
523
531
  self.log.debug " adding %p from %p" % [ oc.must, oc ]
@@ -734,13 +742,19 @@ class Treequel::Branch
734
742
 
735
743
  ### Fetch the entry from the Branch's directory.
736
744
  def lookup_entry
745
+ self.log.debug "Looking up entry for %s" % [ self.dn ]
746
+ entry = nil
747
+
737
748
  if self.include_operational_attrs?
738
749
  self.log.debug " including operational attributes."
739
- return self.directory.get_extended_entry( self )
750
+ entry = self.directory.get_extended_entry( self )
740
751
  else
741
752
  self.log.debug " not including operational attributes."
742
- return self.directory.get_entry( self )
753
+ entry = self.directory.get_entry( self )
743
754
  end
755
+
756
+ self.log.debug " entry is: %p" % [ entry ]
757
+ return entry
744
758
  end
745
759
 
746
760
 
@@ -399,6 +399,16 @@ class Treequel::Branchset
399
399
  end
400
400
 
401
401
 
402
+ ### Return a clone of the receiving Branchset that will perform its search from
403
+ ### +other_dn+ instead of its own.
404
+ ### @param [String, #dn] other_dn the new base DN of the search
405
+ def from( other_dn )
406
+ newset = self.clone
407
+ other_dn = other_dn.dn if other_dn.respond_to?( :dn )
408
+ newset.branch = newset.branch.class.new( self.branch.directory, other_dn )
409
+ return newset
410
+ end
411
+
402
412
  end # class Treequel::Branchset
403
413
 
404
414
 
@@ -162,7 +162,7 @@ class Treequel::Model < Treequel::Branch
162
162
  ### @param [Symbol,String] sym the name of the method to test for
163
163
  ### @return [Boolean]
164
164
  def respond_to?( sym, include_priv=false )
165
- return super if caller(1).first =~ %r{/spec/} &&
165
+ return super if caller(1).first =~ %r{/r?spec/} &&
166
166
  caller(1).first !~ /respond_to/ # RSpec workaround
167
167
  return true if super
168
168
  plainsym, _ = attribute_from_method( sym )
@@ -213,26 +213,34 @@ class Treequel::Model < Treequel::Branch
213
213
 
214
214
  ### Proxy method -- Handle calls to missing methods by searching for an attribute.
215
215
  def method_missing( sym, *args )
216
+ self.log.debug "Dynamic dispatch to %p with args: %p" % [ sym, args ]
216
217
 
217
218
  # First, if the entry hasn't yet been loaded, try loading it to make sure the
218
219
  # object is already extended with any applicable objectClass mixins. If that ends
219
220
  # up defining the method in question, call it.
220
221
  if !@entry && self.entry
222
+ self.log.debug " entry wasn't loaded, looking for methods added by loading it..."
221
223
  meth = begin
222
224
  self.method( sym )
223
- rescue NoMethodError, NameError
225
+ rescue NoMethodError, NameError => err
226
+ self.log.debug " it still didn't define %p: %s: %s" %
227
+ [ sym, err.class.name, err.message ]
224
228
  nil
225
229
  end
226
230
  return meth.call( *args ) if meth
227
231
  end
228
232
 
233
+ self.log.debug " checking to see if it's a traversal call"
229
234
  # Next, super to rdn-traversal if it looks like a reader but has arguments
230
235
  plainsym, methodtype = attribute_from_method( sym )
236
+ self.log.debug " method look like a %p" % [ methodtype ]
231
237
  return super if methodtype == :reader && !args.empty?
238
+ self.log.debug " ...but it doesn't have any arguments. Finding attr type."
232
239
 
233
240
  # Now make a method body for a new method based on what attributeType it is if
234
241
  # it's a valid attribute
235
242
  attrtype = self.find_attribute_type( plainsym ) or return super
243
+ self.log.debug " attrtype is: %p" % [ attrtype ]
236
244
  methodbody = case methodtype
237
245
  when :writer
238
246
  self.make_writer( attrtype )
@@ -310,6 +318,8 @@ class Treequel::Model < Treequel::Branch
310
318
  if entry = super
311
319
  self.log.debug " applying mixins to %p" % [ entry ]
312
320
  self.apply_applicable_mixins( self.dn, entry )
321
+ else
322
+ self.log.debug " failed to fetch the entry."
313
323
  end
314
324
  return entry
315
325
  end
@@ -214,7 +214,7 @@ class Treequel::Schema
214
214
  def inspect
215
215
  ivar_descs = self.instance_variables.sort.collect do |ivar|
216
216
  len = self.instance_variable_get( ivar ).length
217
- "%d %s" % [ len, ivar.gsub(/_/, ' ')[1..-1] ]
217
+ "%d %s" % [ len, ivar.to_s.gsub(/_/, ' ')[1..-1] ]
218
218
  end
219
219
  return %{#<%s:0x%0x %s>} % [
220
220
  self.class.name,
@@ -54,7 +54,7 @@ begin
54
54
  class YARD::RegistryStore; include YardGlobals; end
55
55
  class YARD::Docstring; include YardGlobals; end
56
56
  module YARD::Templates::Helpers::ModuleHelper; include YardGlobals; end
57
- module YARD::Tags::RefTaglist; include YardGlobals; end
57
+ module YARD::Templates::Helpers::HtmlHelper; include YardGlobals; end
58
58
 
59
59
  if vvec(RUBY_VERSION) >= vvec("1.9.1")
60
60
  # Monkeypatched to allow more than two '#' characters at the beginning
@@ -63,8 +63,15 @@ begin
63
63
  require 'yard/parser/ruby/ruby_parser'
64
64
  class YARD::Parser::Ruby::RipperParser < Ripper
65
65
  def on_comment(comment)
66
- $stderr.puts "Adding comment: %p" % [ comment ]
67
66
  visit_ns_token(:comment, comment)
67
+ case comment
68
+ when /\A# @group\s+(.+)\s*\Z/
69
+ @groups.unshift [lineno, $1]
70
+ return
71
+ when /\A# @endgroup\s*\Z/
72
+ @groups.unshift [lineno, nil]
73
+ return
74
+ end
68
75
 
69
76
  comment = comment.gsub(/^\#+\s{0,1}/, '').chomp
70
77
  append_comment = @comments[lineno - 1]