puppet 0.9.2 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (213) hide show
  1. data/CHANGELOG +58 -0
  2. data/README +21 -18
  3. data/Rakefile +176 -36
  4. data/bin/puppet +34 -48
  5. data/bin/puppetca +41 -28
  6. data/bin/puppetd +87 -65
  7. data/bin/puppetdoc +99 -23
  8. data/bin/puppetmasterd +72 -91
  9. data/conf/redhat/client.init +80 -0
  10. data/conf/redhat/client.sysconfig +11 -0
  11. data/conf/redhat/fileserver.conf +12 -0
  12. data/conf/redhat/puppet.spec +130 -0
  13. data/conf/redhat/server.init +89 -0
  14. data/conf/redhat/server.sysconfig +9 -0
  15. data/examples/code/allatonce +2 -2
  16. data/examples/code/assignments +1 -1
  17. data/examples/code/classing +2 -2
  18. data/examples/code/components +2 -2
  19. data/examples/code/file.bl +5 -5
  20. data/examples/code/filedefaults +2 -2
  21. data/examples/code/fileparsing +1 -1
  22. data/examples/code/filerecursion +1 -1
  23. data/examples/code/functions +1 -1
  24. data/examples/code/groups +1 -1
  25. data/examples/code/importing +1 -1
  26. data/examples/code/nodes +1 -1
  27. data/examples/code/one +1 -1
  28. data/examples/code/relationships +2 -2
  29. data/examples/code/simpletests +5 -5
  30. data/examples/code/snippets/argumentdefaults +2 -2
  31. data/examples/code/snippets/casestatement +16 -8
  32. data/examples/code/snippets/classheirarchy.pp +4 -4
  33. data/examples/code/snippets/classincludes.pp +4 -4
  34. data/examples/code/snippets/classpathtest +2 -2
  35. data/examples/code/snippets/componentmetaparams.pp +11 -0
  36. data/examples/code/snippets/dirchmod +5 -5
  37. data/examples/code/snippets/emptyclass.pp +9 -0
  38. data/examples/code/snippets/failmissingexecpath.pp +1 -1
  39. data/examples/code/snippets/falsevalues.pp +1 -1
  40. data/examples/code/snippets/filecreate +5 -5
  41. data/examples/code/snippets/implicititeration +5 -5
  42. data/examples/code/snippets/multipleinstances +4 -4
  43. data/examples/code/snippets/namevartest +3 -3
  44. data/examples/code/snippets/scopetest +1 -1
  45. data/examples/code/snippets/selectorvalues.pp +3 -3
  46. data/examples/code/snippets/simpledefaults +2 -2
  47. data/examples/code/snippets/simpleselector +5 -5
  48. data/examples/code/snippets/singleary.pp +19 -0
  49. data/examples/root/etc/init.d/sleeper +3 -2
  50. data/ext/emacs/puppet-mode-init.el +6 -0
  51. data/ext/emacs/puppet-mode.el +189 -0
  52. data/ext/ldap/puppet.schema +17 -0
  53. data/ext/{module:puppet → module_puppet} +30 -31
  54. data/ext/vim/filetype.vim +9 -0
  55. data/ext/vim/puppet.vim +87 -0
  56. data/install.rb +63 -30
  57. data/lib/puppet.rb +216 -122
  58. data/lib/puppet/client.rb +51 -416
  59. data/lib/puppet/client/ca.rb +17 -0
  60. data/lib/puppet/client/dipper.rb +78 -0
  61. data/lib/puppet/client/file.rb +20 -0
  62. data/lib/puppet/client/log.rb +17 -0
  63. data/lib/puppet/client/master.rb +246 -0
  64. data/lib/puppet/client/proxy.rb +27 -0
  65. data/lib/puppet/client/status.rb +7 -0
  66. data/lib/puppet/config.rb +563 -13
  67. data/lib/puppet/daemon.rb +50 -22
  68. data/lib/puppet/element.rb +4 -4
  69. data/lib/puppet/event-loop.rb +1 -0
  70. data/lib/puppet/event-loop/better-definers.rb +367 -0
  71. data/lib/puppet/event-loop/event-loop.rb +355 -0
  72. data/lib/puppet/event-loop/signal-system.rb +220 -0
  73. data/lib/puppet/event.rb +9 -11
  74. data/lib/puppet/filetype.rb +195 -0
  75. data/lib/puppet/log.rb +35 -12
  76. data/lib/puppet/metric.rb +2 -2
  77. data/lib/puppet/networkclient.rb +145 -0
  78. data/lib/puppet/parameter.rb +335 -0
  79. data/lib/puppet/parser/ast.rb +42 -1453
  80. data/lib/puppet/parser/ast/astarray.rb +88 -0
  81. data/lib/puppet/parser/ast/branch.rb +47 -0
  82. data/lib/puppet/parser/ast/caseopt.rb +66 -0
  83. data/lib/puppet/parser/ast/casestatement.rb +78 -0
  84. data/lib/puppet/parser/ast/classdef.rb +78 -0
  85. data/lib/puppet/parser/ast/compdef.rb +111 -0
  86. data/lib/puppet/parser/ast/component.rb +105 -0
  87. data/lib/puppet/parser/ast/hostclass.rb +82 -0
  88. data/lib/puppet/parser/ast/leaf.rb +86 -0
  89. data/lib/puppet/parser/ast/node.rb +103 -0
  90. data/lib/puppet/parser/ast/nodedef.rb +68 -0
  91. data/lib/puppet/parser/ast/objectdef.rb +336 -0
  92. data/lib/puppet/parser/ast/objectparam.rb +30 -0
  93. data/lib/puppet/parser/ast/objectref.rb +76 -0
  94. data/lib/puppet/parser/ast/selector.rb +60 -0
  95. data/lib/puppet/parser/ast/typedefaults.rb +45 -0
  96. data/lib/puppet/parser/ast/vardef.rb +44 -0
  97. data/lib/puppet/parser/interpreter.rb +31 -14
  98. data/lib/puppet/parser/lexer.rb +2 -4
  99. data/lib/puppet/parser/parser.rb +332 -242
  100. data/lib/puppet/parser/scope.rb +55 -38
  101. data/lib/puppet/server.rb +43 -44
  102. data/lib/puppet/server/authstore.rb +3 -6
  103. data/lib/puppet/server/ca.rb +5 -2
  104. data/lib/puppet/server/filebucket.rb +2 -4
  105. data/lib/puppet/server/fileserver.rb +28 -12
  106. data/lib/puppet/server/logger.rb +15 -4
  107. data/lib/puppet/server/master.rb +62 -7
  108. data/lib/puppet/sslcertificates.rb +41 -607
  109. data/lib/puppet/sslcertificates/ca.rb +291 -0
  110. data/lib/puppet/sslcertificates/certificate.rb +283 -0
  111. data/lib/puppet/statechange.rb +6 -1
  112. data/lib/puppet/storage.rb +67 -56
  113. data/lib/puppet/transaction.rb +25 -9
  114. data/lib/puppet/transportable.rb +102 -22
  115. data/lib/puppet/type.rb +1096 -315
  116. data/lib/puppet/type/component.rb +30 -21
  117. data/lib/puppet/type/cron.rb +409 -448
  118. data/lib/puppet/type/exec.rb +234 -174
  119. data/lib/puppet/type/group.rb +65 -82
  120. data/lib/puppet/type/nameservice.rb +247 -3
  121. data/lib/puppet/type/nameservice/netinfo.rb +29 -40
  122. data/lib/puppet/type/nameservice/objectadd.rb +52 -66
  123. data/lib/puppet/type/nameservice/posix.rb +6 -194
  124. data/lib/puppet/type/package.rb +447 -295
  125. data/lib/puppet/type/package/apt.rb +51 -50
  126. data/lib/puppet/type/package/bsd.rb +82 -0
  127. data/lib/puppet/type/package/dpkg.rb +85 -88
  128. data/lib/puppet/type/package/rpm.rb +67 -63
  129. data/lib/puppet/type/package/sun.rb +119 -98
  130. data/lib/puppet/type/package/yum.rb +41 -37
  131. data/lib/puppet/type/parsedtype.rb +295 -0
  132. data/lib/puppet/type/parsedtype/host.rb +143 -0
  133. data/lib/puppet/type/parsedtype/port.rb +232 -0
  134. data/lib/puppet/type/parsedtype/sshkey.rb +129 -0
  135. data/lib/puppet/type/pfile.rb +484 -460
  136. data/lib/puppet/type/pfile/checksum.rb +237 -181
  137. data/lib/puppet/type/pfile/content.rb +67 -0
  138. data/lib/puppet/type/pfile/ensure.rb +212 -0
  139. data/lib/puppet/type/pfile/group.rb +106 -105
  140. data/lib/puppet/type/pfile/mode.rb +98 -101
  141. data/lib/puppet/type/pfile/source.rb +228 -209
  142. data/lib/puppet/type/pfile/type.rb +18 -21
  143. data/lib/puppet/type/pfile/uid.rb +127 -130
  144. data/lib/puppet/type/pfilebucket.rb +68 -63
  145. data/lib/puppet/type/schedule.rb +341 -0
  146. data/lib/puppet/type/service.rb +351 -255
  147. data/lib/puppet/type/service/base.rb +9 -14
  148. data/lib/puppet/type/service/debian.rb +32 -38
  149. data/lib/puppet/type/service/init.rb +130 -130
  150. data/lib/puppet/type/service/smf.rb +48 -20
  151. data/lib/puppet/type/state.rb +229 -16
  152. data/lib/puppet/type/symlink.rb +51 -63
  153. data/lib/puppet/type/tidy.rb +105 -102
  154. data/lib/puppet/type/user.rb +118 -180
  155. data/lib/puppet/util.rb +100 -6
  156. data/test/certmgr/certmgr.rb +0 -1
  157. data/test/client/client.rb +4 -4
  158. data/test/executables/puppetbin.rb +7 -14
  159. data/test/executables/puppetca.rb +18 -24
  160. data/test/executables/puppetd.rb +7 -16
  161. data/test/executables/puppetmasterd.rb +7 -9
  162. data/test/executables/puppetmodule.rb +11 -16
  163. data/test/language/ast.rb +11 -7
  164. data/test/language/interpreter.rb +1 -1
  165. data/test/language/scope.rb +2 -0
  166. data/test/language/snippets.rb +30 -5
  167. data/test/language/transportable.rb +77 -0
  168. data/test/other/config.rb +316 -0
  169. data/test/other/events.rb +22 -21
  170. data/test/other/log.rb +14 -14
  171. data/test/other/metrics.rb +4 -8
  172. data/test/other/overrides.rb +5 -5
  173. data/test/other/relationships.rb +4 -2
  174. data/test/other/storage.rb +64 -3
  175. data/test/other/transactions.rb +20 -20
  176. data/test/parser/parser.rb +7 -4
  177. data/test/puppet/conffiles.rb +12 -12
  178. data/test/puppet/defaults.rb +13 -11
  179. data/test/puppet/utiltest.rb +14 -11
  180. data/test/puppettest.rb +156 -48
  181. data/test/server/bucket.rb +2 -2
  182. data/test/server/fileserver.rb +6 -6
  183. data/test/server/logger.rb +19 -11
  184. data/test/server/master.rb +33 -4
  185. data/test/server/server.rb +2 -7
  186. data/test/types/basic.rb +5 -7
  187. data/test/types/component.rb +22 -18
  188. data/test/types/cron.rb +111 -44
  189. data/test/types/exec.rb +116 -59
  190. data/test/types/file.rb +262 -137
  191. data/test/types/filebucket.rb +13 -15
  192. data/test/types/fileignoresource.rb +12 -16
  193. data/test/types/filesources.rb +73 -48
  194. data/test/types/filetype.rb +13 -15
  195. data/test/types/group.rb +15 -13
  196. data/test/types/host.rb +146 -0
  197. data/test/types/package.rb +74 -63
  198. data/test/types/port.rb +139 -0
  199. data/test/types/query.rb +8 -8
  200. data/test/types/schedule.rb +335 -0
  201. data/test/types/service.rb +137 -21
  202. data/test/types/sshkey.rb +140 -0
  203. data/test/types/symlink.rb +3 -5
  204. data/test/types/tidy.rb +5 -14
  205. data/test/types/type.rb +67 -11
  206. data/test/types/user.rb +25 -23
  207. metadata +186 -122
  208. data/lib/puppet/type/pfile/create.rb +0 -108
  209. data/lib/puppet/type/pprocess.rb +0 -97
  210. data/lib/puppet/type/typegen.rb +0 -149
  211. data/lib/puppet/type/typegen/filerecord.rb +0 -243
  212. data/lib/puppet/type/typegen/filetype.rb +0 -316
  213. data/test/other/state.rb +0 -106
@@ -2,9 +2,19 @@
2
2
 
3
3
  require 'puppet'
4
4
 
5
- module Puppet # :nodoc:
6
- # A module that handles operations common to all daemons.
5
+ module Puppet
6
+ # A module that handles operations common to all daemons. This is included
7
+ # into the Server and Client base classes.
7
8
  module Daemon
9
+ def daemonname
10
+ $0.sub(/.+#{File::SEPARATOR}/,'')
11
+ end
12
+
13
+ # The path to the pid file for this server
14
+ def pidfile
15
+ File.join(Puppet[:rundir], daemonname() + ".pid")
16
+ end
17
+
8
18
  # Put the daemon into the background.
9
19
  def daemonize
10
20
  if pid = fork()
@@ -12,6 +22,8 @@ module Puppet # :nodoc:
12
22
  exit(0)
13
23
  end
14
24
 
25
+ setpidfile()
26
+
15
27
  # Get rid of console logging
16
28
  Puppet::Log.close(:console)
17
29
 
@@ -29,25 +41,6 @@ module Puppet # :nodoc:
29
41
  Puppet.err "Could not start %s: %s" % [$0, detail]
30
42
  exit(12)
31
43
  end
32
-
33
- name = $0.gsub(/.+#{File::SEPARATOR}/,'')
34
- @pidfile = File.join(Puppet[:puppetvar], name + ".pid")
35
- if FileTest.exists?(@pidfile)
36
- Puppet.info "Deleting old pid file"
37
- begin
38
- File.unlink(@pidfile)
39
- rescue Errno::EACCES
40
- Puppet.err "Could not delete old PID file; cannot create new one"
41
- return
42
- end
43
- end
44
-
45
- begin
46
- File.open(@pidfile, "w") { |f| f.puts $$ }
47
- rescue => detail
48
- Puppet.err "Could not create PID file: %s" % detail
49
- end
50
- Puppet.info "pid file is %s" % @pidfile
51
44
  end
52
45
 
53
46
  def fqdn
@@ -82,6 +75,7 @@ module Puppet # :nodoc:
82
75
  return log
83
76
  end
84
77
 
78
+ # Read in an existing certificate.
85
79
  def readcert
86
80
  return unless @secureinit
87
81
  # verify we've got all of the certs set up and such
@@ -117,6 +111,9 @@ module Puppet # :nodoc:
117
111
  return true
118
112
  end
119
113
 
114
+ # Request a certificate from the remote system. This does all of the work
115
+ # of creating the cert request, contacting the remote system, and
116
+ # storing the cert locally.
120
117
  def requestcert
121
118
  retrieved = false
122
119
  # create the directories involved
@@ -161,6 +158,9 @@ module Puppet # :nodoc:
161
158
  begin
162
159
  cert, cacert = @driver.getcert(@csr.to_pem)
163
160
  rescue => detail
161
+ if Puppet[:debug]
162
+ puts detail.backtrace
163
+ end
164
164
  raise Puppet::Error.new("Certificate retrieval failed: %s" %
165
165
  detail)
166
166
  end
@@ -186,6 +186,34 @@ module Puppet # :nodoc:
186
186
  return retrieved
187
187
  end
188
188
 
189
+ # Create the pid file.
190
+ def setpidfile
191
+ @pidfile = self.pidfile
192
+ if FileTest.exists?(@pidfile)
193
+ Puppet.info "Deleting old pid file"
194
+ begin
195
+ File.unlink(@pidfile)
196
+ rescue Errno::EACCES
197
+ Puppet.err "Could not delete old PID file; cannot create new one"
198
+ return
199
+ end
200
+ end
201
+
202
+ unless FileTest.exists?(Puppet[:rundir])
203
+ Puppet.recmkdir(Puppet[:rundir])
204
+ File.chmod(01777, Puppet[:rundir])
205
+ end
206
+
207
+ Puppet.info "Setting pidfile to %s" % @pidfile
208
+ begin
209
+ File.open(@pidfile, "w") { |f| f.puts $$ }
210
+ rescue => detail
211
+ Puppet.err "Could not create PID file: %s" % detail
212
+ exit(74)
213
+ end
214
+ Puppet.info "pid file is %s" % @pidfile
215
+ end
216
+
189
217
  # Shut down our server
190
218
  def shutdown
191
219
  # Remove our pid file
@@ -205,4 +233,4 @@ module Puppet # :nodoc:
205
233
  end
206
234
  end
207
235
 
208
- # $Id: daemon.rb 732 2005-10-28 05:39:59Z luke $
236
+ # $Id: daemon.rb 856 2006-01-30 16:18:24Z luke $
@@ -40,7 +40,7 @@ class Puppet::Element
40
40
  def path
41
41
  unless defined? @path
42
42
  if defined? @parent and @parent
43
- if self.is_a?(Puppet::Type::Component)
43
+ if self.is_a?(Puppet.type(:component))
44
44
  @path = [@parent.path, self.name]
45
45
  else
46
46
  @path = [@parent.path, self.class.name.to_s + "=" + self.name]
@@ -54,10 +54,10 @@ class Puppet::Element
54
54
  else
55
55
  # We assume that if we don't have a parent that we should not
56
56
  # cache the path
57
- if self.is_a?(Puppet::Type::Component)
57
+ if self.is_a?(Puppet.type(:component))
58
58
  @path = [self.name]
59
59
  else
60
- @path = [self.class.name.to_s + "=" + self.name]
60
+ @path = [self.class.name.to_s + "=" + self.name.to_s]
61
61
  end
62
62
  end
63
63
  end
@@ -68,4 +68,4 @@ class Puppet::Element
68
68
 
69
69
  end
70
70
 
71
- # $Id: element.rb 742 2005-11-16 17:12:11Z luke $
71
+ # $Id: element.rb 787 2006-01-08 00:02:23Z luke $
@@ -0,0 +1 @@
1
+ require "puppet/event-loop/event-loop"
@@ -0,0 +1,367 @@
1
+ ## better-definers.rb --- better attribute and method definers
2
+ # Copyright (C) 2005 Daniel Brockman
3
+
4
+ # This program is free software; you can redistribute it
5
+ # and/or modify it under the terms of the GNU General Public
6
+ # License as published by the Free Software Foundation;
7
+ # either version 2 of the License, or (at your option) any
8
+ # later version.
9
+
10
+ # This file is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty
12
+ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ # See the GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public
16
+ # License along with this program; if not, write to the Free
17
+ # Software Foundation, 51 Franklin Street, Fifth Floor,
18
+ # Boston, MA 02110-1301, USA.
19
+
20
+ class Symbol
21
+ def predicate?
22
+ to_s.include? "?" end
23
+ def imperative?
24
+ to_s.include? "!" end
25
+ def writer?
26
+ to_s.include? "=" end
27
+
28
+ def punctuated?
29
+ predicate? or imperative? or writer? end
30
+ def without_punctuation
31
+ to_s.delete("?!=").to_sym end
32
+
33
+ def predicate
34
+ without_punctuation.to_s + "?" end
35
+ def imperative
36
+ without_punctuation.to_s + "!" end
37
+ def writer
38
+ without_punctuation.to_s + "=" end
39
+ end
40
+
41
+ class Hash
42
+ def collect! (&block)
43
+ replace Hash[*collect(&block).flatten]
44
+ end
45
+
46
+ def flatten
47
+ to_a.flatten
48
+ end
49
+ end
50
+
51
+ module Kernel
52
+ def returning (value)
53
+ yield value ; value
54
+ end
55
+ end
56
+
57
+ class Module
58
+ def define_hard_aliases (name_pairs)
59
+ for new_aliases, existing_name in name_pairs do
60
+ new_aliases.kind_of? Array or new_aliases = [new_aliases]
61
+ for new_alias in new_aliases do
62
+ alias_method(new_alias, existing_name)
63
+ end
64
+ end
65
+ end
66
+
67
+ def define_soft_aliases (name_pairs)
68
+ for new_aliases, existing_name in name_pairs do
69
+ new_aliases.kind_of? Array or new_aliases = [new_aliases]
70
+ for new_alias in new_aliases do
71
+ class_eval %{def #{new_alias}(*args, &block)
72
+ #{existing_name}(*args, &block) end}
73
+ end
74
+ end
75
+ end
76
+
77
+ define_soft_aliases \
78
+ :define_hard_alias => :define_hard_aliases,
79
+ :define_soft_alias => :define_soft_aliases
80
+
81
+ # This method lets you define predicates like :foo?,
82
+ # which will be defined to return the value of @foo.
83
+ def define_readers (*names)
84
+ for name in names.map { |x| x.to_sym } do
85
+ if name.punctuated?
86
+ # There's no way to define an efficient reader whose
87
+ # name is different from the instance variable.
88
+ class_eval %{def #{name} ; @#{name.without_punctuation} end}
89
+ else
90
+ # Use `attr_reader' to define an efficient method.
91
+ attr_reader(name)
92
+ end
93
+ end
94
+ end
95
+
96
+ def writer_defined? (name)
97
+ method_defined? name.to_sym.writer
98
+ end
99
+
100
+ # If you pass a predicate symbol :foo? to this method, it'll first
101
+ # define a regular writer method :foo, without a question mark.
102
+ # Then it'll define an imperative writer method :foo! as a shorthand
103
+ # for setting the property to true.
104
+ def define_writers (*names, &body)
105
+ for name in names.map { |x| x.to_sym } do
106
+ if block_given?
107
+ define_method(name.writer, &body)
108
+ else
109
+ attr_writer(name.without_punctuation)
110
+ end
111
+ if name.predicate?
112
+ class_eval %{def #{name.imperative}
113
+ self.#{name.writer} true end}
114
+ end
115
+ end
116
+ end
117
+
118
+ define_soft_aliases \
119
+ :define_reader => :define_readers,
120
+ :define_writer => :define_writers
121
+
122
+ # We don't need a singular alias for `define_accessors',
123
+ # because it always defines at least two methods.
124
+
125
+ def define_accessors (*names)
126
+ define_readers(*names)
127
+ define_writers(*names)
128
+ end
129
+
130
+ def define_opposite_readers (name_pairs)
131
+ name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
132
+ for opposite_name, name in name_pairs do
133
+ define_reader(name) unless method_defined? name
134
+ class_eval %{def #{opposite_name} ; not #{name} end}
135
+ end
136
+ end
137
+
138
+ def define_opposite_writers (name_pairs)
139
+ name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
140
+ for opposite_name, name in name_pairs do
141
+ define_writer(name) unless writer_defined? name
142
+ class_eval %{def #{opposite_name.writer} x
143
+ self.#{name.writer} !x end}
144
+ class_eval %{def #{opposite_name.imperative}
145
+ self.#{name.writer} false end}
146
+ end
147
+ end
148
+
149
+ define_soft_aliases \
150
+ :define_opposite_reader => :define_opposite_readers,
151
+ :define_opposite_writer => :define_opposite_writers
152
+
153
+ def define_opposite_accessors (name_pairs)
154
+ define_opposite_readers name_pairs
155
+ define_opposite_writers name_pairs
156
+ end
157
+
158
+ def define_reader_with_opposite (name_pair, &body)
159
+ name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
160
+ define_method(name, &body)
161
+ define_opposite_reader(opposite_name => name)
162
+ end
163
+
164
+ def define_writer_with_opposite (name_pair, &body)
165
+ name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
166
+ define_writer(name, &body)
167
+ define_opposite_writer(opposite_name => name)
168
+ end
169
+
170
+ public :define_method
171
+
172
+ def define_methods (*names, &body)
173
+ names.each { |name| define_method(name, &body) }
174
+ end
175
+
176
+ def define_private_methods (*names, &body)
177
+ define_methods(*names, &body)
178
+ names.each { |name| private name }
179
+ end
180
+
181
+ def define_protected_methods (*names, &body)
182
+ define_methods(*names, &body)
183
+ names.each { |name| protected name }
184
+ end
185
+
186
+ def define_private_method (name, &body)
187
+ define_method(name, &body)
188
+ private name
189
+ end
190
+
191
+ def define_protected_method (name, &body)
192
+ define_method(name, &body)
193
+ protected name
194
+ end
195
+ end
196
+
197
+ class ImmutableAttributeError < StandardError
198
+ def initialize (attribute=nil, message=nil)
199
+ super message
200
+ @attribute = attribute
201
+ end
202
+
203
+ define_accessors :attribute
204
+
205
+ def to_s
206
+ if @attribute and @message
207
+ "cannot change the value of `#@attribute': #@message"
208
+ elsif @attribute
209
+ "cannot change the value of `#@attribute'"
210
+ elsif @message
211
+ "cannot change the value of attribute: #@message"
212
+ else
213
+ "cannot change the value of attribute"
214
+ end
215
+ end
216
+ end
217
+
218
+ class Module
219
+ # Guard each of the specified attributes by replacing the writer
220
+ # method with a proxy that asks the supplied block before proceeding
221
+ # with the change.
222
+ #
223
+ # If it's okay to change the attribute, the block should return
224
+ # either nil or the symbol :mutable. If it isn't okay, the block
225
+ # should return a string saying why the attribute can't be changed.
226
+ # If you don't want to provide a reason, you can have the block
227
+ # return just the symbol :immutable.
228
+ def guard_writers(*names, &predicate)
229
+ for name in names.map { |x| x.to_sym } do
230
+ define_hard_alias("__unguarded_#{name.writer}" => name.writer)
231
+ define_method(name.writer) do |new_value|
232
+ case result = predicate.call
233
+ when :mutable, nil
234
+ __send__("__unguarded_#{name.writer}", new_value)
235
+ when :immutable
236
+ raise ImmutableAttributeError.new(name)
237
+ else
238
+ raise ImmutableAttributeError.new(name, result)
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ def define_guarded_writers (*names, &block)
245
+ define_writers(*names)
246
+ guard_writers(*names, &block)
247
+ end
248
+
249
+ define_soft_alias :guard_writer => :guard_writers
250
+ define_soft_alias :define_guarded_writer => :define_guarded_writers
251
+ end
252
+
253
+ if __FILE__ == $0
254
+ require "test/unit"
255
+
256
+ class DefineAccessorsTest < Test::Unit::TestCase
257
+ def setup
258
+ @X = Class.new
259
+ @Y = Class.new @X
260
+ @x = @X.new
261
+ @y = @Y.new
262
+ end
263
+
264
+ def test_define_hard_aliases
265
+ @X.define_method(:foo) { 123 }
266
+ @X.define_method(:baz) { 321 }
267
+ @X.define_hard_aliases :bar => :foo, :quux => :baz
268
+ assert_equal @x.foo, 123
269
+ assert_equal @x.bar, 123
270
+ assert_equal @y.foo, 123
271
+ assert_equal @y.bar, 123
272
+ assert_equal @x.baz, 321
273
+ assert_equal @x.quux, 321
274
+ assert_equal @y.baz, 321
275
+ assert_equal @y.quux, 321
276
+ @Y.define_method(:foo) { 456 }
277
+ assert_equal @y.foo, 456
278
+ assert_equal @y.bar, 123
279
+ @Y.define_method(:quux) { 654 }
280
+ assert_equal @y.baz, 321
281
+ assert_equal @y.quux, 654
282
+ end
283
+
284
+ def test_define_soft_aliases
285
+ @X.define_method(:foo) { 123 }
286
+ @X.define_method(:baz) { 321 }
287
+ @X.define_soft_aliases :bar => :foo, :quux => :baz
288
+ assert_equal @x.foo, 123
289
+ assert_equal @x.bar, 123
290
+ assert_equal @y.foo, 123
291
+ assert_equal @y.bar, 123
292
+ assert_equal @x.baz, 321
293
+ assert_equal @x.quux, 321
294
+ assert_equal @y.baz, 321
295
+ assert_equal @y.quux, 321
296
+ @Y.define_method(:foo) { 456 }
297
+ assert_equal @y.foo, @y.bar, 456
298
+ @Y.define_method(:quux) { 654 }
299
+ assert_equal @y.baz, 321
300
+ assert_equal @y.quux, 654
301
+ end
302
+
303
+ def test_define_readers
304
+ @X.define_readers :foo, :bar
305
+ assert !@x.respond_to?(:foo=)
306
+ assert !@x.respond_to?(:bar=)
307
+ @x.instance_eval { @foo = 123 ; @bar = 456 }
308
+ assert_equal @x.foo, 123
309
+ assert_equal @x.bar, 456
310
+ @X.define_readers :baz?, :quux?
311
+ assert !@x.respond_to?(:baz=)
312
+ assert !@x.respond_to?(:quux=)
313
+ @x.instance_eval { @baz = false ; @quux = true }
314
+ assert !@x.baz?
315
+ assert @x.quux?
316
+ end
317
+
318
+ def test_define_writers
319
+ assert !@X.writer_defined?(:foo)
320
+ assert !@X.writer_defined?(:bar)
321
+ @X.define_writers :foo, :bar
322
+ assert @X.writer_defined?(:foo)
323
+ assert @X.writer_defined?(:bar)
324
+ assert @X.writer_defined?(:foo=)
325
+ assert @X.writer_defined?(:bar=)
326
+ assert @X.writer_defined?(:foo?)
327
+ assert @X.writer_defined?(:bar?)
328
+ assert !@x.respond_to?(:foo)
329
+ assert !@x.respond_to?(:bar)
330
+ @x.foo = 123
331
+ @x.bar = 456
332
+ assert_equal @x.instance_eval { @foo }, 123
333
+ assert_equal @x.instance_eval { @bar }, 456
334
+ @X.define_writers :baz?, :quux?
335
+ assert !@x.respond_to?(:baz?)
336
+ assert !@x.respond_to?(:quux?)
337
+ @x.baz = true
338
+ @x.quux = false
339
+ assert_equal @x.instance_eval { @baz }, true
340
+ assert_equal @x.instance_eval { @quux }, false
341
+ end
342
+
343
+ def test_define_accessors
344
+ @X.define_accessors :foo, :bar
345
+ @x.foo = 123 ; @x.bar = 456
346
+ assert_equal @x.foo, 123
347
+ assert_equal @x.bar, 456
348
+ end
349
+
350
+ def test_define_opposite_readers
351
+ @X.define_opposite_readers :foo? => :bar?, :baz? => :quux?
352
+ assert !@x.respond_to?(:foo=)
353
+ assert !@x.respond_to?(:bar=)
354
+ assert !@x.respond_to?(:baz=)
355
+ assert !@x.respond_to?(:quux=)
356
+ @x.instance_eval { @bar = true ; @quux = false }
357
+ assert !@x.foo?
358
+ assert @x.bar?
359
+ assert @x.baz?
360
+ assert !@x.quux?
361
+ end
362
+
363
+ def test_define_opposite_writers
364
+ @X.define_opposite_writers :foo? => :bar?, :baz => :quux
365
+ end
366
+ end
367
+ end