ad-framework 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +12 -0
  3. data/README.markdown +36 -0
  4. data/Rakefile +19 -0
  5. data/ad-framework.gemspec +25 -0
  6. data/doc/open_ldap_server.markdown +17 -0
  7. data/extras/adtest.schema +304 -0
  8. data/extras/slapd.conf +10 -0
  9. data/lib/ad-framework.rb +53 -0
  10. data/lib/ad-framework/attribute.rb +35 -0
  11. data/lib/ad-framework/attribute_type.rb +133 -0
  12. data/lib/ad-framework/auxiliary_class.rb +24 -0
  13. data/lib/ad-framework/config.rb +72 -0
  14. data/lib/ad-framework/config/attribute_definition.rb +18 -0
  15. data/lib/ad-framework/config/mapping.rb +26 -0
  16. data/lib/ad-framework/exceptions.rb +17 -0
  17. data/lib/ad-framework/fields.rb +44 -0
  18. data/lib/ad-framework/patterns/callbacks.rb +47 -0
  19. data/lib/ad-framework/patterns/has_schema.rb +127 -0
  20. data/lib/ad-framework/patterns/persistence.rb +67 -0
  21. data/lib/ad-framework/patterns/searchable.rb +117 -0
  22. data/lib/ad-framework/patterns/validations.rb +50 -0
  23. data/lib/ad-framework/schema.rb +118 -0
  24. data/lib/ad-framework/structural_class.rb +61 -0
  25. data/lib/ad-framework/utilities/entry_builder.rb +77 -0
  26. data/lib/ad-framework/utilities/transaction.rb +32 -0
  27. data/lib/ad-framework/utilities/validator.rb +26 -0
  28. data/lib/ad-framework/version.rb +5 -0
  29. data/test/helper.rb +71 -0
  30. data/test/integration/defined_array_test.rb +49 -0
  31. data/test/integration/defined_integer_test.rb +48 -0
  32. data/test/integration/defined_string_test.rb +48 -0
  33. data/test/integration/defined_top_test.rb +101 -0
  34. data/test/integration/defined_user_test.rb +140 -0
  35. data/test/irb.rb +2 -0
  36. data/test/support/factory.rb +67 -0
  37. data/test/support/ldap.yml +6 -0
  38. data/test/support/schema/attribute_types.rb +67 -0
  39. data/test/support/schema/attributes.rb +10 -0
  40. data/test/support/schema/auxiliary_classes.rb +12 -0
  41. data/test/support/schema/structural_classes.rb +46 -0
  42. data/test/support/seed.rb +28 -0
  43. data/test/support/state.rb +29 -0
  44. data/test/unit/ad-framework/attribute_test.rb +84 -0
  45. data/test/unit/ad-framework/attribute_type/class_methods_test.rb +146 -0
  46. data/test/unit/ad-framework/attribute_type_test.rb +114 -0
  47. data/test/unit/ad-framework/auxiliary_class_test.rb +39 -0
  48. data/test/unit/ad-framework/config/attribute_definition_test.rb +26 -0
  49. data/test/unit/ad-framework/config/mapping_test.rb +41 -0
  50. data/test/unit/ad-framework/config_test.rb +121 -0
  51. data/test/unit/ad-framework/fields_test.rb +44 -0
  52. data/test/unit/ad-framework/patterns/callbacks_test.rb +90 -0
  53. data/test/unit/ad-framework/patterns/has_schema/class_methods_test.rb +214 -0
  54. data/test/unit/ad-framework/patterns/has_schema_test.rb +96 -0
  55. data/test/unit/ad-framework/patterns/persistence_test.rb +126 -0
  56. data/test/unit/ad-framework/patterns/searchable_test.rb +201 -0
  57. data/test/unit/ad-framework/patterns/validations_test.rb +113 -0
  58. data/test/unit/ad-framework/schema_test.rb +268 -0
  59. data/test/unit/ad-framework/structural_class_test.rb +64 -0
  60. data/test/unit/ad-framework/utilities/entry_builder_test.rb +107 -0
  61. data/test/unit/ad-framework/utilities/transaction_test.rb +50 -0
  62. data/test/unit/ad-framework/utilities/validator_test.rb +46 -0
  63. data/test/unit/ad-framework_test.rb +116 -0
  64. metadata +225 -0
@@ -0,0 +1,35 @@
1
+ require 'ad-framework/exceptions'
2
+
3
+ module AD
4
+ module Framework
5
+
6
+ class Attribute
7
+ attr_accessor :name, :ldap_name, :attribute_type
8
+
9
+ def initialize(name)
10
+ self.name = name
11
+ definition = AD::Framework.defined_attributes.find(self.name)
12
+ if !definition
13
+ raise(AD::Framework::AttributeNotDefined, "There is no attribute defintion for #{name.inspect}.")
14
+ end
15
+ self.ldap_name = definition.ldap_name
16
+ self.attribute_type = AD::Framework.defined_attribute_types.find(definition.type)
17
+ if !self.attribute_type
18
+ raise(*[
19
+ AD::Framework::AttributeTypeNotDefined,
20
+ "There is no attribute type defined for #{definition.type.inspect}"
21
+ ])
22
+ end
23
+ end
24
+
25
+ def define_reader(klass)
26
+ self.attribute_type.define_reader(self, klass)
27
+ end
28
+ def define_writer(klass)
29
+ self.attribute_type.define_writer(self, klass)
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,133 @@
1
+ module AD
2
+ module Framework
3
+
4
+ class AttributeType
5
+ attr_accessor :object, :attr_ldap_name, :value, :ldap_value
6
+
7
+ def initialize(object, attr_ldap_name, value = nil)
8
+ self.object = object
9
+ self.attr_ldap_name = attr_ldap_name
10
+ self.value = value.nil? ? self.value_from_field : value
11
+ end
12
+
13
+ def value_from_field
14
+ (self.object.fields[self.attr_ldap_name] || []).first
15
+ end
16
+
17
+ def value=(new_value)
18
+ @value = new_value
19
+ self.ldap_value = @value
20
+ @value
21
+ end
22
+
23
+ def ldap_value=(new_ldap_value)
24
+ self.object.fields[self.attr_ldap_name] = if new_ldap_value
25
+ [*new_ldap_value].collect(&:to_s)
26
+ else
27
+ []
28
+ end
29
+ @ldap_value = new_ldap_value
30
+ end
31
+
32
+ def reset
33
+ self.value = self.value_from_field
34
+ end
35
+
36
+ def is_set?
37
+ !self.value.nil?
38
+ end
39
+
40
+ def inspect
41
+ attr_display = [ :value, :ldap_value, :attr_ldap_name ].collect do |attr|
42
+ "#{attr}: #{self.instance_variable_get("@#{attr}").inspect}"
43
+ end
44
+ attr_display.push("object: #{object.class} - #{object.dn.inspect}")
45
+ [ "#<#{self.class} ", attr_display.sort.join(", "), ">" ].join
46
+ end
47
+
48
+ class << self
49
+
50
+ def key(new_value = nil)
51
+ if new_value
52
+ @key = new_value
53
+ end
54
+ @key
55
+ end
56
+
57
+ def define_attribute_type(attribute, klass)
58
+ method_name = "#{attribute.name}_attribute_type"
59
+ if !klass.instance_methods.collect(&:to_s).include?(method_name)
60
+ attribute_type_method = self.attribute_type_method(attribute, method_name)
61
+ if attribute_type_method.kind_of?(::Proc)
62
+ klass.class_eval(&attribute_type_method)
63
+ else
64
+ klass.class_eval(attribute_type_method.to_s)
65
+ end
66
+ end
67
+ end
68
+
69
+ def attribute_type_method(attribute, method_name)
70
+ <<-DEFINE_ATTRIBUTE_TYPE
71
+
72
+ def #{method_name}
73
+ unless @#{method_name}
74
+ type = #{attribute.attribute_type}.new(self, "#{attribute.ldap_name}")
75
+ @#{method_name} = type
76
+ end
77
+ @#{method_name}
78
+ end
79
+
80
+ DEFINE_ATTRIBUTE_TYPE
81
+ end
82
+
83
+ def define_reader(attribute, klass)
84
+ self.define_attribute_type(attribute, klass)
85
+ reader_method = self.reader_method(attribute)
86
+ if reader_method.kind_of?(::Proc)
87
+ klass.class_eval(&reader_method)
88
+ else
89
+ klass.class_eval(reader_method.to_s)
90
+ end
91
+ end
92
+
93
+ def reader_method(attribute)
94
+ <<-DEFINE_READER
95
+
96
+ def #{attribute.name}
97
+ self.#{attribute.name}_attribute_type.value
98
+ end
99
+
100
+ DEFINE_READER
101
+ end
102
+
103
+ def define_writer(attribute, klass)
104
+ self.define_attribute_type(attribute, klass)
105
+ writer_method = self.writer_method(attribute)
106
+ if writer_method.kind_of?(::Proc)
107
+ klass.class_eval(&writer_method)
108
+ else
109
+ klass.class_eval(writer_method.to_s)
110
+ end
111
+ end
112
+
113
+ def writer_method(attribute)
114
+ <<-DEFINE_WRITER
115
+
116
+ def #{attribute.name}=(new_value)
117
+ self.#{attribute.name}_attribute_type.value = new_value
118
+ if self.respond_to?("#{attribute.name}")
119
+ self.#{attribute.name}
120
+ else
121
+ new_value
122
+ end
123
+ end
124
+
125
+ DEFINE_WRITER
126
+ end
127
+
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+ end
@@ -0,0 +1,24 @@
1
+ require 'ad-framework/patterns/has_schema'
2
+
3
+ module AD
4
+ module Framework
5
+
6
+ module AuxiliaryClass
7
+ class << self
8
+
9
+ def included(klass)
10
+ klass.class_eval do
11
+ include AD::Framework::Patterns::HasSchema
12
+
13
+ def self.included(klass)
14
+ super
15
+ klass.schema.add_auxiliary_class(self)
16
+ end
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,72 @@
1
+ require 'ad-ldap'
2
+
3
+ require 'ad-framework/config/mapping'
4
+ require 'ad-framework/config/attribute_definition'
5
+
6
+ module AD
7
+ module Framework
8
+
9
+ class Config
10
+ attr_accessor :attributes, :attribute_types, :object_classes, :ldap_prefix
11
+
12
+ def initialize
13
+ self.mappings = AD::Framework::Config::Mapping.new
14
+ self.mappings.add(:dn, "distinguishedname")
15
+
16
+ self.attributes = AD::Framework::Config::Mapping.new
17
+ self.attribute_types = AD::Framework::Config::Mapping.new
18
+ self.object_classes = AD::Framework::Config::Mapping.new
19
+ end
20
+
21
+ def ldap_prefix=(new_value)
22
+ @ldap_prefix = new_value
23
+ self.object_classes.dup.each do |key, value|
24
+ self.object_classes.delete(key)
25
+ self.object_classes.add("#{@ldap_prefix}#{key}", value)
26
+ end
27
+ end
28
+
29
+ def ldap(&block)
30
+ if block
31
+ AD::LDAP.configure(&block)
32
+ end
33
+ AD::LDAP
34
+ end
35
+ alias :adapter :ldap
36
+
37
+ def logger
38
+ self.adapter.logger
39
+ end
40
+ def logger=(new_logger)
41
+ self.adapter.config.logger = new_logger
42
+ end
43
+
44
+ [ :search_size_supported, :mappings, :run_commands, :treebase ].each do |method|
45
+
46
+ define_method(method) do
47
+ self.adapter.config.send(method)
48
+ end
49
+
50
+ writer = "#{method}="
51
+ define_method(writer) do |new_value|
52
+ self.adapter.config.send(writer, new_value)
53
+ end
54
+
55
+ end
56
+
57
+ def add_attribute(attribute)
58
+ definition = AD::Framework::Config::AttributeDefinition.new(attribute)
59
+ self.mappings.add(definition.name, definition.ldap_name)
60
+ self.attributes.add(definition.name, definition)
61
+ end
62
+ def add_attribute_type(attribute_type)
63
+ self.attribute_types.add(attribute_type.key, attribute_type)
64
+ end
65
+ def add_object_class(object_class)
66
+ self.object_classes.add(object_class.ldap_name, object_class)
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,18 @@
1
+ module AD
2
+ module Framework
3
+ class Config
4
+
5
+ class AttributeDefinition
6
+ attr_accessor :name, :ldap_name, :type
7
+
8
+ def initialize(attributes)
9
+ attributes.each do |key, value|
10
+ self.send("#{key}=", value)
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ module AD
2
+ module Framework
3
+ class Config
4
+
5
+ class Mapping < Hash
6
+
7
+ def [](lookup)
8
+ super(lookup.to_sym)
9
+ end
10
+ def find(lookup)
11
+ self[lookup]
12
+ end
13
+
14
+ def []=(lookup, object)
15
+ super(lookup.to_sym, object)
16
+ end
17
+
18
+ def add(lookup, object)
19
+ self[lookup] = object
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ module AD
2
+ module Framework
3
+
4
+ class AttributeNotDefined < StandardError
5
+ end
6
+
7
+ class AttributeTypeNotDefined < StandardError
8
+ end
9
+
10
+ class ObjectClassNotDefined < StandardError
11
+ end
12
+
13
+ class EntryNotFound < StandardError
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ module AD
2
+ module Framework
3
+
4
+ class Fields < Hash
5
+
6
+ def initialize(ldap_entry)
7
+ super()
8
+ @changed_keys = Set.new
9
+ (ldap_entry || {}).each do |ldap_name, value|
10
+ self[ldap_name.to_s] = value
11
+ end
12
+ end
13
+
14
+ def [](lookup)
15
+ super(lookup.to_s)
16
+ end
17
+ def []=(lookup, value)
18
+ if self[lookup] != value
19
+ @changed_keys << lookup.to_s
20
+ end
21
+ super(lookup.to_s, value)
22
+ end
23
+
24
+ def changes
25
+ @changed_keys.inject({}){|h, k| h.merge({ k => self[k] }) }
26
+ end
27
+
28
+ def to_hash
29
+ self.inject({}){|h, (k,v)| h.merge({ k => v }) }
30
+ end
31
+
32
+ def inspect
33
+ max_key_length = (self.keys.collect(&:size).max || 0) + 1
34
+ display = self.collect do |(key, value)|
35
+ key_label = "#{key}:".rjust(max_key_length, ' ')
36
+ [ key_label, value.inspect ].join(" ")
37
+ end
38
+ "\n#{display.join("\n")}"
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,47 @@
1
+ require 'ad-framework/utilities/transaction'
2
+
3
+ module AD
4
+ module Framework
5
+ module Patterns
6
+
7
+ module Callbacks
8
+ class << self
9
+
10
+ def included(klass)
11
+ klass.class_eval do
12
+ include AD::Framework::Patterns::Callbacks::InstanceMethods
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ module InstanceMethods
19
+
20
+ def create
21
+ transaction = AD::Framework::Utilities::Transaction.new(:create, self) do
22
+ super
23
+ end
24
+ transaction.run
25
+ end
26
+
27
+ def update
28
+ transaction = AD::Framework::Utilities::Transaction.new(:update, self) do
29
+ super
30
+ end
31
+ transaction.run
32
+ end
33
+
34
+ def destroy
35
+ transaction = AD::Framework::Utilities::Transaction.new(:destroy, self) do
36
+ super
37
+ end
38
+ transaction.run
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,127 @@
1
+ require 'ad-framework/schema'
2
+
3
+ module AD
4
+ module Framework
5
+ module Patterns
6
+
7
+ module HasSchema
8
+ class << self
9
+
10
+ def included(klass)
11
+ klass.class_eval do
12
+ extend AD::Framework::Patterns::HasSchema::ClassMethods
13
+ include AD::Framework::Patterns::HasSchema::InstanceMethods
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ module InstanceMethods
20
+
21
+ def schema
22
+ @schema ||= self.class.schema.dup
23
+ end
24
+
25
+ def dn
26
+ dn = self.fields[:distinguishedname] || self.fields[:dn]
27
+ dn ||= if self.respond_to?(self.schema.rdn)
28
+ [ "CN=#{self.send(self.schema.rdn)}", self.schema.treebase ].join(", ")
29
+ end
30
+ end
31
+
32
+ def attributes
33
+ self.schema.attributes.inject({}) do |attrs, name|
34
+ attrs.merge({ name.to_sym => self.send(name.to_sym) })
35
+ end
36
+ end
37
+ def attributes=(new_attributes)
38
+ new_attributes.each do |name, value|
39
+ if self.schema.attributes.include?(name)
40
+ self.send("#{name}=", value)
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ module ClassMethods
48
+
49
+ def schema
50
+ @schema ||= AD::Framework::Schema.new(self)
51
+ end
52
+
53
+ def ldap_name(name = nil)
54
+ (self.schema.ldap_name = name) if name
55
+ self.schema.ldap_name
56
+ end
57
+
58
+ def treebase(value = nil)
59
+ (self.schema.treebase = value) if value
60
+ self.schema.treebase
61
+ end
62
+
63
+ def rdn(name = nil)
64
+ (self.schema.rdn = name) if name
65
+ self.schema.rdn
66
+ end
67
+
68
+ # Attributes methods
69
+ def attributes(*attribute_names)
70
+ self.schema.add_attributes(attribute_names)
71
+ end
72
+
73
+ def read_attributes(*attribute_names)
74
+ self.schema.add_read_attributes(attribute_names)
75
+ end
76
+
77
+ def write_attributes(*attribute_names)
78
+ self.schema.add_write_attributes(attribute_names)
79
+ end
80
+
81
+ # Validation methods
82
+ def must_set(*attribute_names)
83
+ self.schema.add_mandatory(attribute_names)
84
+ end
85
+
86
+ # Callbacks methods
87
+ def before_create(*method_names)
88
+ self.schema.add_callback(:before, :create, method_names)
89
+ end
90
+
91
+ def before_update(*method_names)
92
+ self.schema.add_callback(:before, :update, method_names)
93
+ end
94
+
95
+ def before_save(*method_names)
96
+ self.before_create(*method_names)
97
+ self.before_update(*method_names)
98
+ end
99
+
100
+ def before_destroy(*method_names)
101
+ self.schema.add_callback(:before, :destroy, method_names)
102
+ end
103
+
104
+ def after_create(*method_names)
105
+ self.schema.add_callback(:after, :create, method_names)
106
+ end
107
+
108
+ def after_update(*method_names)
109
+ self.schema.add_callback(:after, :update, method_names)
110
+ end
111
+
112
+ def after_save(*method_names)
113
+ self.after_create(*method_names)
114
+ self.after_update(*method_names)
115
+ end
116
+
117
+ def after_destroy(*method_names)
118
+ self.schema.add_callback(:after, :destroy, method_names)
119
+ end
120
+
121
+ end
122
+
123
+ end
124
+
125
+ end
126
+ end
127
+ end