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.
- data/CHANGELOG +58 -0
- data/README +21 -18
- data/Rakefile +176 -36
- data/bin/puppet +34 -48
- data/bin/puppetca +41 -28
- data/bin/puppetd +87 -65
- data/bin/puppetdoc +99 -23
- data/bin/puppetmasterd +72 -91
- data/conf/redhat/client.init +80 -0
- data/conf/redhat/client.sysconfig +11 -0
- data/conf/redhat/fileserver.conf +12 -0
- data/conf/redhat/puppet.spec +130 -0
- data/conf/redhat/server.init +89 -0
- data/conf/redhat/server.sysconfig +9 -0
- data/examples/code/allatonce +2 -2
- data/examples/code/assignments +1 -1
- data/examples/code/classing +2 -2
- data/examples/code/components +2 -2
- data/examples/code/file.bl +5 -5
- data/examples/code/filedefaults +2 -2
- data/examples/code/fileparsing +1 -1
- data/examples/code/filerecursion +1 -1
- data/examples/code/functions +1 -1
- data/examples/code/groups +1 -1
- data/examples/code/importing +1 -1
- data/examples/code/nodes +1 -1
- data/examples/code/one +1 -1
- data/examples/code/relationships +2 -2
- data/examples/code/simpletests +5 -5
- data/examples/code/snippets/argumentdefaults +2 -2
- data/examples/code/snippets/casestatement +16 -8
- data/examples/code/snippets/classheirarchy.pp +4 -4
- data/examples/code/snippets/classincludes.pp +4 -4
- data/examples/code/snippets/classpathtest +2 -2
- data/examples/code/snippets/componentmetaparams.pp +11 -0
- data/examples/code/snippets/dirchmod +5 -5
- data/examples/code/snippets/emptyclass.pp +9 -0
- data/examples/code/snippets/failmissingexecpath.pp +1 -1
- data/examples/code/snippets/falsevalues.pp +1 -1
- data/examples/code/snippets/filecreate +5 -5
- data/examples/code/snippets/implicititeration +5 -5
- data/examples/code/snippets/multipleinstances +4 -4
- data/examples/code/snippets/namevartest +3 -3
- data/examples/code/snippets/scopetest +1 -1
- data/examples/code/snippets/selectorvalues.pp +3 -3
- data/examples/code/snippets/simpledefaults +2 -2
- data/examples/code/snippets/simpleselector +5 -5
- data/examples/code/snippets/singleary.pp +19 -0
- data/examples/root/etc/init.d/sleeper +3 -2
- data/ext/emacs/puppet-mode-init.el +6 -0
- data/ext/emacs/puppet-mode.el +189 -0
- data/ext/ldap/puppet.schema +17 -0
- data/ext/{module:puppet → module_puppet} +30 -31
- data/ext/vim/filetype.vim +9 -0
- data/ext/vim/puppet.vim +87 -0
- data/install.rb +63 -30
- data/lib/puppet.rb +216 -122
- data/lib/puppet/client.rb +51 -416
- data/lib/puppet/client/ca.rb +17 -0
- data/lib/puppet/client/dipper.rb +78 -0
- data/lib/puppet/client/file.rb +20 -0
- data/lib/puppet/client/log.rb +17 -0
- data/lib/puppet/client/master.rb +246 -0
- data/lib/puppet/client/proxy.rb +27 -0
- data/lib/puppet/client/status.rb +7 -0
- data/lib/puppet/config.rb +563 -13
- data/lib/puppet/daemon.rb +50 -22
- data/lib/puppet/element.rb +4 -4
- data/lib/puppet/event-loop.rb +1 -0
- data/lib/puppet/event-loop/better-definers.rb +367 -0
- data/lib/puppet/event-loop/event-loop.rb +355 -0
- data/lib/puppet/event-loop/signal-system.rb +220 -0
- data/lib/puppet/event.rb +9 -11
- data/lib/puppet/filetype.rb +195 -0
- data/lib/puppet/log.rb +35 -12
- data/lib/puppet/metric.rb +2 -2
- data/lib/puppet/networkclient.rb +145 -0
- data/lib/puppet/parameter.rb +335 -0
- data/lib/puppet/parser/ast.rb +42 -1453
- data/lib/puppet/parser/ast/astarray.rb +88 -0
- data/lib/puppet/parser/ast/branch.rb +47 -0
- data/lib/puppet/parser/ast/caseopt.rb +66 -0
- data/lib/puppet/parser/ast/casestatement.rb +78 -0
- data/lib/puppet/parser/ast/classdef.rb +78 -0
- data/lib/puppet/parser/ast/compdef.rb +111 -0
- data/lib/puppet/parser/ast/component.rb +105 -0
- data/lib/puppet/parser/ast/hostclass.rb +82 -0
- data/lib/puppet/parser/ast/leaf.rb +86 -0
- data/lib/puppet/parser/ast/node.rb +103 -0
- data/lib/puppet/parser/ast/nodedef.rb +68 -0
- data/lib/puppet/parser/ast/objectdef.rb +336 -0
- data/lib/puppet/parser/ast/objectparam.rb +30 -0
- data/lib/puppet/parser/ast/objectref.rb +76 -0
- data/lib/puppet/parser/ast/selector.rb +60 -0
- data/lib/puppet/parser/ast/typedefaults.rb +45 -0
- data/lib/puppet/parser/ast/vardef.rb +44 -0
- data/lib/puppet/parser/interpreter.rb +31 -14
- data/lib/puppet/parser/lexer.rb +2 -4
- data/lib/puppet/parser/parser.rb +332 -242
- data/lib/puppet/parser/scope.rb +55 -38
- data/lib/puppet/server.rb +43 -44
- data/lib/puppet/server/authstore.rb +3 -6
- data/lib/puppet/server/ca.rb +5 -2
- data/lib/puppet/server/filebucket.rb +2 -4
- data/lib/puppet/server/fileserver.rb +28 -12
- data/lib/puppet/server/logger.rb +15 -4
- data/lib/puppet/server/master.rb +62 -7
- data/lib/puppet/sslcertificates.rb +41 -607
- data/lib/puppet/sslcertificates/ca.rb +291 -0
- data/lib/puppet/sslcertificates/certificate.rb +283 -0
- data/lib/puppet/statechange.rb +6 -1
- data/lib/puppet/storage.rb +67 -56
- data/lib/puppet/transaction.rb +25 -9
- data/lib/puppet/transportable.rb +102 -22
- data/lib/puppet/type.rb +1096 -315
- data/lib/puppet/type/component.rb +30 -21
- data/lib/puppet/type/cron.rb +409 -448
- data/lib/puppet/type/exec.rb +234 -174
- data/lib/puppet/type/group.rb +65 -82
- data/lib/puppet/type/nameservice.rb +247 -3
- data/lib/puppet/type/nameservice/netinfo.rb +29 -40
- data/lib/puppet/type/nameservice/objectadd.rb +52 -66
- data/lib/puppet/type/nameservice/posix.rb +6 -194
- data/lib/puppet/type/package.rb +447 -295
- data/lib/puppet/type/package/apt.rb +51 -50
- data/lib/puppet/type/package/bsd.rb +82 -0
- data/lib/puppet/type/package/dpkg.rb +85 -88
- data/lib/puppet/type/package/rpm.rb +67 -63
- data/lib/puppet/type/package/sun.rb +119 -98
- data/lib/puppet/type/package/yum.rb +41 -37
- data/lib/puppet/type/parsedtype.rb +295 -0
- data/lib/puppet/type/parsedtype/host.rb +143 -0
- data/lib/puppet/type/parsedtype/port.rb +232 -0
- data/lib/puppet/type/parsedtype/sshkey.rb +129 -0
- data/lib/puppet/type/pfile.rb +484 -460
- data/lib/puppet/type/pfile/checksum.rb +237 -181
- data/lib/puppet/type/pfile/content.rb +67 -0
- data/lib/puppet/type/pfile/ensure.rb +212 -0
- data/lib/puppet/type/pfile/group.rb +106 -105
- data/lib/puppet/type/pfile/mode.rb +98 -101
- data/lib/puppet/type/pfile/source.rb +228 -209
- data/lib/puppet/type/pfile/type.rb +18 -21
- data/lib/puppet/type/pfile/uid.rb +127 -130
- data/lib/puppet/type/pfilebucket.rb +68 -63
- data/lib/puppet/type/schedule.rb +341 -0
- data/lib/puppet/type/service.rb +351 -255
- data/lib/puppet/type/service/base.rb +9 -14
- data/lib/puppet/type/service/debian.rb +32 -38
- data/lib/puppet/type/service/init.rb +130 -130
- data/lib/puppet/type/service/smf.rb +48 -20
- data/lib/puppet/type/state.rb +229 -16
- data/lib/puppet/type/symlink.rb +51 -63
- data/lib/puppet/type/tidy.rb +105 -102
- data/lib/puppet/type/user.rb +118 -180
- data/lib/puppet/util.rb +100 -6
- data/test/certmgr/certmgr.rb +0 -1
- data/test/client/client.rb +4 -4
- data/test/executables/puppetbin.rb +7 -14
- data/test/executables/puppetca.rb +18 -24
- data/test/executables/puppetd.rb +7 -16
- data/test/executables/puppetmasterd.rb +7 -9
- data/test/executables/puppetmodule.rb +11 -16
- data/test/language/ast.rb +11 -7
- data/test/language/interpreter.rb +1 -1
- data/test/language/scope.rb +2 -0
- data/test/language/snippets.rb +30 -5
- data/test/language/transportable.rb +77 -0
- data/test/other/config.rb +316 -0
- data/test/other/events.rb +22 -21
- data/test/other/log.rb +14 -14
- data/test/other/metrics.rb +4 -8
- data/test/other/overrides.rb +5 -5
- data/test/other/relationships.rb +4 -2
- data/test/other/storage.rb +64 -3
- data/test/other/transactions.rb +20 -20
- data/test/parser/parser.rb +7 -4
- data/test/puppet/conffiles.rb +12 -12
- data/test/puppet/defaults.rb +13 -11
- data/test/puppet/utiltest.rb +14 -11
- data/test/puppettest.rb +156 -48
- data/test/server/bucket.rb +2 -2
- data/test/server/fileserver.rb +6 -6
- data/test/server/logger.rb +19 -11
- data/test/server/master.rb +33 -4
- data/test/server/server.rb +2 -7
- data/test/types/basic.rb +5 -7
- data/test/types/component.rb +22 -18
- data/test/types/cron.rb +111 -44
- data/test/types/exec.rb +116 -59
- data/test/types/file.rb +262 -137
- data/test/types/filebucket.rb +13 -15
- data/test/types/fileignoresource.rb +12 -16
- data/test/types/filesources.rb +73 -48
- data/test/types/filetype.rb +13 -15
- data/test/types/group.rb +15 -13
- data/test/types/host.rb +146 -0
- data/test/types/package.rb +74 -63
- data/test/types/port.rb +139 -0
- data/test/types/query.rb +8 -8
- data/test/types/schedule.rb +335 -0
- data/test/types/service.rb +137 -21
- data/test/types/sshkey.rb +140 -0
- data/test/types/symlink.rb +3 -5
- data/test/types/tidy.rb +5 -14
- data/test/types/type.rb +67 -11
- data/test/types/user.rb +25 -23
- metadata +186 -122
- data/lib/puppet/type/pfile/create.rb +0 -108
- data/lib/puppet/type/pprocess.rb +0 -97
- data/lib/puppet/type/typegen.rb +0 -149
- data/lib/puppet/type/typegen/filerecord.rb +0 -243
- data/lib/puppet/type/typegen/filetype.rb +0 -316
- data/test/other/state.rb +0 -106
data/lib/puppet/daemon.rb
CHANGED
@@ -2,9 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'puppet'
|
4
4
|
|
5
|
-
module Puppet
|
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
|
236
|
+
# $Id: daemon.rb 856 2006-01-30 16:18:24Z luke $
|
data/lib/puppet/element.rb
CHANGED
@@ -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
|
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
|
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
|
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
|