attributes 3.7.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -11,17 +11,45 @@ URIS
11
11
  SYNOPSIS
12
12
  attributes.rb provides a set of attr_* like method with several user
13
13
  friendly additions. attributes.rb is similar to the traits.rb package but
14
- sacrifices a few features for simplicity of implementation: attributes.rb is
15
- only 42 lines of code.
14
+ sacrifices a few features for simplicity of implementation.
16
15
 
17
- the implimentation of attributes.rb borrows many of the best ideas from the
16
+ the implementation of attributes.rb borrows many of the best ideas from the
18
17
  metakoans.rb ruby quiz
19
18
 
20
19
  http://www.rubyquiz.com/quiz67.html
21
20
 
22
- in particular the solutions of Christian Neukirchen and Florian Gross.
21
+ in particular the solutions of Christian Neukirchen and Florian Gross along
22
+ with concepts from the original traits lib
23
+
24
+ key features provided by attributes are
25
+
26
+ - ability to specify default values for attrs and definition time. values
27
+ can be literal objects or blocks, which are evaluated in the context of
28
+ self to initialize the variable
29
+
30
+ - classes remember which attributes they've defined and this information is
31
+ available to client code
32
+
33
+ - a whole suite of methods is defined by calls to #attributes including
34
+ getter, setter, query (var?) and banger (var! - which forces
35
+ re-initialization from the default value)
36
+
37
+ - ability to define multiple attributes at once using key => value pairs
38
+
39
+ - fast lookup of whether or not a class has defined a certain attribute
40
+
41
+ - attributes can be defined on objects on a per singleton basis as well
42
+
43
+ - getters acts as setters if an argument is given to them
44
+
45
+ all this in < 100 lines of code
23
46
 
24
47
  HISTORY
48
+ 4.0.0
49
+ - removed dependancy on, and bundle of, pervasives
50
+ - faster. as fast as normal method definition.
51
+ - faster lookup for MyClass.attributes.include?('foobar')
52
+
25
53
  3.7.0
26
54
  small patch to use 'instance_variable_defined?' instead of defined?
27
55
  keyword
@@ -42,8 +70,7 @@ SAMPLES
42
70
  ~ > cat samples/a.rb
43
71
 
44
72
  #
45
- # basic usage is like attr, but note that attribute defines three methods,
46
- # getter, setter, and query
73
+ # basic usage is like attr, but note that attribute defines a suite of methods
47
74
  #
48
75
  require 'attributes'
49
76
 
@@ -53,16 +80,16 @@ SAMPLES
53
80
 
54
81
  c = C.new
55
82
 
56
- c.a = 42 # setter
57
- p c.a # getter
58
- p 'forty-two' if c.a? # query
83
+ c.a = 42
84
+ p c.a #=> 42
85
+ p 'forty-two' if c.a? #=> 'forty-two'
59
86
 
60
87
  #
61
- # also not that attribute(s) works as well for objects as classes
88
+ # attributes works on object too
62
89
  #
63
90
  o = Object.new
64
91
  o.attribute 'answer' => 42
65
- p o.answer
92
+ p o.answer #=> 42
66
93
 
67
94
  ~ > ruby samples/a.rb
68
95
 
@@ -78,7 +105,9 @@ SAMPLES
78
105
  #
79
106
  # default values may be given either directly or as a block which will be
80
107
  # evaluated in the context of self. in both cases (value or block) the
81
- # default is set only once and only if needed - it's a lazy evaluation.
108
+ # default is set only once and only if needed - it's a lazy evaluation. the
109
+ # 'banger' method can be used to re-initialize a variable at any point whether
110
+ # or not it's already been initialized.
82
111
  #
83
112
  require 'attributes'
84
113
 
@@ -88,14 +117,20 @@ SAMPLES
88
117
  end
89
118
 
90
119
  c = C.new
120
+ p c.a #=> 42
121
+ p c.b #=> 42.0
91
122
 
92
- p c.a
93
- p c.b
123
+ c.a = 43
124
+ p c.a #=> 43
125
+ c.a!
126
+ p c.a #=> 42
94
127
 
95
128
  ~ > ruby samples/b.rb
96
129
 
97
130
  42
98
131
  42.0
132
+ 43
133
+ 42
99
134
 
100
135
 
101
136
  <========< samples/c.rb >========>
@@ -113,7 +148,7 @@ SAMPLES
113
148
 
114
149
  c = C.new
115
150
  c.x = c.y + c.z
116
- p c.x
151
+ p c.x #=> 42
117
152
 
118
153
  ~ > ruby samples/c.rb
119
154
 
@@ -191,5 +226,5 @@ SAMPLES
191
226
 
192
227
  ~ > ruby samples/e.rb
193
228
 
194
- #<Config:0x1e834 @port=80, @host="codeforpeople.org">
229
+ #<Config:0x20080 @port=80, @host="codeforpeople.org">
195
230
 
@@ -11,17 +11,45 @@ URIS
11
11
  SYNOPSIS
12
12
  attributes.rb provides a set of attr_* like method with several user
13
13
  friendly additions. attributes.rb is similar to the traits.rb package but
14
- sacrifices a few features for simplicity of implementation: attributes.rb is
15
- only 42 lines of code.
14
+ sacrifices a few features for simplicity of implementation.
16
15
 
17
- the implimentation of attributes.rb borrows many of the best ideas from the
16
+ the implementation of attributes.rb borrows many of the best ideas from the
18
17
  metakoans.rb ruby quiz
19
18
 
20
19
  http://www.rubyquiz.com/quiz67.html
21
20
 
22
- in particular the solutions of Christian Neukirchen and Florian Gross.
21
+ in particular the solutions of Christian Neukirchen and Florian Gross along
22
+ with concepts from the original traits lib
23
+
24
+ key features provided by attributes are
25
+
26
+ - ability to specify default values for attrs and definition time. values
27
+ can be literal objects or blocks, which are evaluated in the context of
28
+ self to initialize the variable
29
+
30
+ - classes remember which attributes they've defined and this information is
31
+ available to client code
32
+
33
+ - a whole suite of methods is defined by calls to #attributes including
34
+ getter, setter, query (var?) and banger (var! - which forces
35
+ re-initialization from the default value)
36
+
37
+ - ability to define multiple attributes at once using key => value pairs
38
+
39
+ - fast lookup of whether or not a class has defined a certain attribute
40
+
41
+ - attributes can be defined on objects on a per singleton basis as well
42
+
43
+ - getters acts as setters if an argument is given to them
44
+
45
+ all this in < 100 lines of code
23
46
 
24
47
  HISTORY
48
+ 4.0.0
49
+ - removed dependancy on, and bundle of, pervasives
50
+ - faster. as fast as normal method definition.
51
+ - faster lookup for MyClass.attributes.include?('foobar')
52
+
25
53
  3.7.0
26
54
  small patch to use 'instance_variable_defined?' instead of defined?
27
55
  keyword
data/a.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'attributes'
2
+
3
+ module M
4
+ p(( attribute 'a' => 42 ))
5
+ p(( attribute('b'){ "forty-two (#{ self })" } ))
6
+ end
7
+ p M.attributes
8
+ p M.attributes.include?('a')
9
+ p M.attributes.include?('b')
10
+ p M.attributes.include?('c')
11
+
12
+ class C
13
+ include M
14
+ end
15
+ p C.new.a
16
+ p C.new.b
17
+ p C.attributes
18
+ p C.attributes.include?('a')
19
+ p C.attributes.include?('b')
20
+ p C.attributes.include?('c')
21
+
22
+ class B < C
23
+ end
24
+ p B.new.a
25
+ p B.new.b
26
+ p B.attributes
27
+ p B.attributes.include?('a')
28
+ p B.attributes.include?('b')
29
+ p B.attributes.include?('c')
@@ -0,0 +1,110 @@
1
+ module Attributes
2
+ Attributes::VERSION = '4.0.0' unless defined? Attributes::VERSION
3
+ def self.version() Attributes::VERSION end
4
+
5
+ class List < ::Array
6
+ def << element
7
+ super
8
+ self
9
+ ensure
10
+ uniq!
11
+ index!
12
+ end
13
+ def index!
14
+ @index ||= Hash.new
15
+ each{|element| @index[element] = true}
16
+ end
17
+ def include? element
18
+ @index ||= Hash.new
19
+ @index[element] ? true : false
20
+ end
21
+ def initializers
22
+ @initializers ||= Hash.new
23
+ end
24
+ end
25
+
26
+ def attributes *a, &b
27
+ unless a.empty?
28
+ returned = Hash.new
29
+
30
+ hashes, names = a.partition{|x| Hash === x}
31
+ names_and_defaults = {}
32
+ hashes.each{|h| names_and_defaults.update h}
33
+ names.flatten.compact.each{|name| names_and_defaults.update name => nil}
34
+
35
+ initializers = __attributes__.initializers
36
+
37
+ names_and_defaults.each do |name, default|
38
+ raise NameError, "bad instance variable name '@#{ name }'" if "@#{ name }" =~ %r/[!?=]$/o
39
+ name = name.to_s
40
+
41
+ initialize = b || lambda { default }
42
+ initializer = lambda do |this|
43
+ Object.instance_method('instance_eval').bind(this).call &initialize
44
+ end
45
+ initializer_id = initializer.object_id
46
+ __attributes__.initializers[name] = initializer
47
+
48
+ module_eval <<-code
49
+ def #{ name }=(value)
50
+ @#{ name } = value
51
+ end
52
+
53
+ def #{ name }(*value)
54
+ return self.#{ name } = value.first unless value.empty?
55
+ #{ name }! unless defined? @#{ name }
56
+ @#{ name }
57
+ end
58
+
59
+ def #{ name }!
60
+ initializer = ObjectSpace._id2ref #{ initializer_id }
61
+ self.#{ name } = initializer.call(self)
62
+ @#{ name }
63
+ end
64
+
65
+ def #{ name }?
66
+ defined? @#{ name } and #{ name }
67
+ end
68
+ code
69
+
70
+ attributes << name
71
+ returned[name] = initializer
72
+ end
73
+
74
+ returned
75
+ else
76
+ begin
77
+ __attribute_list__
78
+ rescue NameError
79
+ singleton_class =
80
+ class << self
81
+ self
82
+ end
83
+ klass = self
84
+ singleton_class.module_eval do
85
+ attribute_list = List.new
86
+ define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) }
87
+ alias_method '__attribute_list__', 'attribute_list'
88
+ end
89
+ __attribute_list__
90
+ end
91
+ end
92
+ end
93
+
94
+ %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
95
+ end
96
+
97
+ class Object
98
+ def attributes *a, &b
99
+ sc =
100
+ class << self
101
+ self
102
+ end
103
+ sc.attributes *a, &b
104
+ end
105
+ %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
106
+ end
107
+
108
+ class Module
109
+ include Attributes
110
+ end
@@ -1,46 +1,77 @@
1
1
  module Attributes
2
- VERSION = '3.7.0'
3
- def self.version() VERSION end
2
+ Attributes::VERSION = '4.0.0' unless defined? Attributes::VERSION
3
+ def self.version() Attributes::VERSION end
4
+
5
+ class List < ::Array
6
+ def << element
7
+ super
8
+ self
9
+ ensure
10
+ uniq!
11
+ index!
12
+ end
13
+ def index!
14
+ @index ||= Hash.new
15
+ each{|element| @index[element] = true}
16
+ end
17
+ def include? element
18
+ @index ||= Hash.new
19
+ @index[element] ? true : false
20
+ end
21
+ def initializers
22
+ @initializers ||= Hash.new
23
+ end
24
+ end
4
25
 
5
26
  def attributes *a, &b
6
27
  unless a.empty?
7
- hashes, names = a.partition{|x| Hash === x}
28
+ returned = Hash.new
8
29
 
30
+ hashes, names = a.partition{|x| Hash === x}
9
31
  names_and_defaults = {}
10
32
  hashes.each{|h| names_and_defaults.update h}
11
33
  names.flatten.compact.each{|name| names_and_defaults.update name => nil}
12
34
 
13
- names_and_defaults.each do |name, default|
14
- init = b || lambda { default }
15
- ivar, getter, setter, query, banger =
16
- "@#{ name }", "#{ name }", "#{ name }=", "#{ name }?", "#{ name }!"
35
+ initializers = __attributes__.initializers
17
36
 
18
- raise NameError, "bad instance variable name '#{ ivar }'" if ivar =~ %r/[!?=]$/o
37
+ names_and_defaults.each do |name, default|
38
+ raise NameError, "bad instance variable name '@#{ name }'" if "@#{ name }" =~ %r/[!?=]$/o
39
+ name = name.to_s
19
40
 
20
- define_method(setter) do |value|
21
- __pervasive__('instance_variable_set', ivar, value)
41
+ initialize = b || lambda { default }
42
+ initializer = lambda do |this|
43
+ Object.instance_method('instance_eval').bind(this).call &initialize
22
44
  end
45
+ initializer_id = initializer.object_id
46
+ __attributes__.initializers[name] = initializer
23
47
 
24
- define_method(getter) do |*value|
25
- unless value.empty?
26
- __pervasive__('send', setter, value.shift)
27
- else
28
- defined = __pervasive__('instance_variable_defined?', "#{ ivar }")
29
- __pervasive__('send', setter, __pervasive__('instance_eval', &init)) unless defined
30
- __pervasive__('instance_variable_get', ivar)
48
+ module_eval <<-code
49
+ def #{ name }=(value)
50
+ @#{ name } = value
31
51
  end
32
- end
33
52
 
34
- define_method(banger) do
35
- __pervasive__('send', setter, __pervasive__('instance_eval', &init))
36
- __pervasive__('instance_variable_get', ivar)
37
- end
53
+ def #{ name }(*value)
54
+ return self.#{ name } = value.first unless value.empty?
55
+ #{ name }! unless defined? @#{ name }
56
+ @#{ name }
57
+ end
58
+
59
+ def #{ name }!
60
+ initializer = ObjectSpace._id2ref #{ initializer_id }
61
+ self.#{ name } = initializer.call(self)
62
+ @#{ name }
63
+ end
38
64
 
39
- alias_method query, getter
65
+ def #{ name }?
66
+ defined? @#{ name } and #{ name }
67
+ end
68
+ code
40
69
 
41
- (attributes << name.to_s).uniq!
42
- attributes
70
+ attributes << name
71
+ returned[name] = initializer
43
72
  end
73
+
74
+ returned
44
75
  else
45
76
  begin
46
77
  __attribute_list__
@@ -51,7 +82,7 @@ module Attributes
51
82
  end
52
83
  klass = self
53
84
  singleton_class.module_eval do
54
- attribute_list = []
85
+ attribute_list = List.new
55
86
  define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) }
56
87
  alias_method '__attribute_list__', 'attribute_list'
57
88
  end
@@ -77,47 +108,3 @@ end
77
108
  class Module
78
109
  include Attributes
79
110
  end
80
-
81
- BEGIN {
82
- unless defined? Pervasives
83
- begin
84
- require 'pervasives'
85
- rescue LoadError
86
- module Pervasives
87
- VERSION = "1.0.0"
88
- def self.version() VERSION end
89
- class ::Class
90
- def __pervasive__ m, *a, &b
91
- (( Class.instance_method(m) rescue
92
- Module.instance_method(m) rescue
93
- Object.instance_method(m) )).bind(self).call(*a, &b)
94
- end
95
- end
96
- class ::Module
97
- def __pervasive__ m, *a, &b
98
- (( Module.instance_method(m) rescue
99
- Object.instance_method(m) )).bind(self).call(*a, &b)
100
- end
101
- end
102
- class ::Object
103
- def __pervasive__ m, *a, &b
104
- (( Object.instance_method(m) )).bind(self).call(*a, &b)
105
- end
106
- end
107
-
108
- class Proxy
109
- instance_methods.each{|m| undef_method m unless m[%r/__/]}
110
- def initialize obj
111
- @obj = obj
112
- end
113
- def method_missing m, *a, &b
114
- @obj.__pervasive__ m, *a, &b
115
- end
116
- def __obj__
117
- @obj
118
- end
119
- end
120
- end
121
- end
122
- end
123
- }
@@ -1,6 +1,5 @@
1
1
  #
2
- # basic usage is like attr, but note that attribute defines three methods,
3
- # getter, setter, and query
2
+ # basic usage is like attr, but note that attribute defines a suite of methods
4
3
  #
5
4
  require 'attributes'
6
5
 
@@ -10,13 +9,13 @@
10
9
 
11
10
  c = C.new
12
11
 
13
- c.a = 42 # setter
14
- p c.a # getter
15
- p 'forty-two' if c.a? # query
12
+ c.a = 42
13
+ p c.a #=> 42
14
+ p 'forty-two' if c.a? #=> 'forty-two'
16
15
 
17
16
  #
18
- # also not that attribute(s) works as well for objects as classes
17
+ # attributes works on object too
19
18
  #
20
19
  o = Object.new
21
20
  o.attribute 'answer' => 42
22
- p o.answer
21
+ p o.answer #=> 42
@@ -1,7 +1,9 @@
1
1
  #
2
2
  # default values may be given either directly or as a block which will be
3
3
  # evaluated in the context of self. in both cases (value or block) the
4
- # default is set only once and only if needed - it's a lazy evaluation.
4
+ # default is set only once and only if needed - it's a lazy evaluation. the
5
+ # 'banger' method can be used to re-initialize a variable at any point whether
6
+ # or not it's already been initialized.
5
7
  #
6
8
  require 'attributes'
7
9
 
@@ -11,6 +13,10 @@
11
13
  end
12
14
 
13
15
  c = C.new
16
+ p c.a #=> 42
17
+ p c.b #=> 42.0
14
18
 
15
- p c.a
16
- p c.b
19
+ c.a = 43
20
+ p c.a #=> 43
21
+ c.a!
22
+ p c.a #=> 42
@@ -9,4 +9,4 @@
9
9
 
10
10
  c = C.new
11
11
  c.x = c.y + c.z
12
- p c.x
12
+ p c.x #=> 42
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: attributes
5
5
  version: !ruby/object:Gem::Version
6
- version: 3.7.0
7
- date: 2007-09-15 00:00:00 -06:00
6
+ version: 4.0.0
7
+ date: 2007-10-10 00:00:00 -06:00
8
8
  summary: attributes
9
9
  require_paths:
10
10
  - lib
@@ -29,11 +29,12 @@ post_install_message:
29
29
  authors:
30
30
  - Ara T. Howard
31
31
  files:
32
+ - a.rb
32
33
  - gemspec.rb
33
34
  - gen_readme.rb
34
35
  - install.rb
35
36
  - lib
36
- - lib/attributes-3.7.0.rb
37
+ - lib/attributes-4.0.0.rb
37
38
  - lib/attributes.rb
38
39
  - README
39
40
  - README.tmpl
@@ -1,123 +0,0 @@
1
- module Attributes
2
- VERSION = '3.7.0'
3
- def self.version() VERSION end
4
-
5
- def attributes *a, &b
6
- unless a.empty?
7
- hashes, names = a.partition{|x| Hash === x}
8
-
9
- names_and_defaults = {}
10
- hashes.each{|h| names_and_defaults.update h}
11
- names.flatten.compact.each{|name| names_and_defaults.update name => nil}
12
-
13
- names_and_defaults.each do |name, default|
14
- init = b || lambda { default }
15
- ivar, getter, setter, query, banger =
16
- "@#{ name }", "#{ name }", "#{ name }=", "#{ name }?", "#{ name }!"
17
-
18
- raise NameError, "bad instance variable name '#{ ivar }'" if ivar =~ %r/[!?=]$/o
19
-
20
- define_method(setter) do |value|
21
- __pervasive__('instance_variable_set', ivar, value)
22
- end
23
-
24
- define_method(getter) do |*value|
25
- unless value.empty?
26
- __pervasive__('send', setter, value.shift)
27
- else
28
- defined = __pervasive__('instance_variable_defined?', "#{ ivar }")
29
- __pervasive__('send', setter, __pervasive__('instance_eval', &init)) unless defined
30
- __pervasive__('instance_variable_get', ivar)
31
- end
32
- end
33
-
34
- define_method(banger) do
35
- __pervasive__('send', setter, __pervasive__('instance_eval', &init))
36
- __pervasive__('instance_variable_get', ivar)
37
- end
38
-
39
- alias_method query, getter
40
-
41
- (attributes << name.to_s).uniq!
42
- attributes
43
- end
44
- else
45
- begin
46
- __attribute_list__
47
- rescue NameError
48
- singleton_class =
49
- class << self
50
- self
51
- end
52
- klass = self
53
- singleton_class.module_eval do
54
- attribute_list = []
55
- define_method('attribute_list'){ klass == self ? attribute_list : raise(NameError) }
56
- alias_method '__attribute_list__', 'attribute_list'
57
- end
58
- __attribute_list__
59
- end
60
- end
61
- end
62
-
63
- %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
64
- end
65
-
66
- class Object
67
- def attributes *a, &b
68
- sc =
69
- class << self
70
- self
71
- end
72
- sc.attributes *a, &b
73
- end
74
- %w( __attributes__ __attribute__ attribute ).each{|dst| alias_method dst, 'attributes'}
75
- end
76
-
77
- class Module
78
- include Attributes
79
- end
80
-
81
- BEGIN {
82
- unless defined? Pervasives
83
- begin
84
- require 'pervasives'
85
- rescue LoadError
86
- module Pervasives
87
- VERSION = "1.0.0"
88
- def self.version() VERSION end
89
- class ::Class
90
- def __pervasive__ m, *a, &b
91
- (( Class.instance_method(m) rescue
92
- Module.instance_method(m) rescue
93
- Object.instance_method(m) )).bind(self).call(*a, &b)
94
- end
95
- end
96
- class ::Module
97
- def __pervasive__ m, *a, &b
98
- (( Module.instance_method(m) rescue
99
- Object.instance_method(m) )).bind(self).call(*a, &b)
100
- end
101
- end
102
- class ::Object
103
- def __pervasive__ m, *a, &b
104
- (( Object.instance_method(m) )).bind(self).call(*a, &b)
105
- end
106
- end
107
-
108
- class Proxy
109
- instance_methods.each{|m| undef_method m unless m[%r/__/]}
110
- def initialize obj
111
- @obj = obj
112
- end
113
- def method_missing m, *a, &b
114
- @obj.__pervasive__ m, *a, &b
115
- end
116
- def __obj__
117
- @obj
118
- end
119
- end
120
- end
121
- end
122
- end
123
- }