puppet 2.7.8 → 2.7.9

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 (98) hide show
  1. data/CHANGELOG +6 -0
  2. data/README_DEVELOPER.md +63 -0
  3. data/conf/redhat/puppet.spec +4 -1
  4. data/ext/puppetstoredconfigclean.rb +39 -27
  5. data/lib/puppet.rb +1 -1
  6. data/lib/puppet/application/agent.rb +33 -25
  7. data/lib/puppet/application/apply.rb +15 -1
  8. data/lib/puppet/application/module.rb +3 -0
  9. data/lib/puppet/defaults.rb +4 -0
  10. data/lib/puppet/face/module.rb +12 -0
  11. data/lib/puppet/face/module/build.rb +31 -0
  12. data/lib/puppet/face/module/changes.rb +38 -0
  13. data/lib/puppet/face/module/clean.rb +30 -0
  14. data/lib/puppet/face/module/generate.rb +40 -0
  15. data/lib/puppet/face/module/install.rb +83 -0
  16. data/lib/puppet/face/module/search.rb +66 -0
  17. data/lib/puppet/indirector/exec.rb +1 -1
  18. data/lib/puppet/module_tool.rb +97 -0
  19. data/lib/puppet/module_tool/applications.rb +12 -0
  20. data/lib/puppet/module_tool/applications/application.rb +83 -0
  21. data/lib/puppet/module_tool/applications/builder.rb +91 -0
  22. data/lib/puppet/module_tool/applications/checksummer.rb +47 -0
  23. data/lib/puppet/module_tool/applications/cleaner.rb +16 -0
  24. data/lib/puppet/module_tool/applications/generator.rb +141 -0
  25. data/lib/puppet/module_tool/applications/installer.rb +89 -0
  26. data/lib/puppet/module_tool/applications/searcher.rb +40 -0
  27. data/lib/puppet/module_tool/applications/unpacker.rb +70 -0
  28. data/lib/puppet/module_tool/cache.rb +56 -0
  29. data/lib/puppet/module_tool/checksums.rb +52 -0
  30. data/lib/puppet/module_tool/contents_description.rb +82 -0
  31. data/lib/puppet/module_tool/dependency.rb +24 -0
  32. data/lib/puppet/module_tool/metadata.rb +141 -0
  33. data/lib/puppet/module_tool/modulefile.rb +75 -0
  34. data/lib/puppet/module_tool/repository.rb +79 -0
  35. data/lib/puppet/module_tool/skeleton.rb +34 -0
  36. data/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb +11 -0
  37. data/lib/puppet/module_tool/skeleton/templates/generator/README.erb +16 -0
  38. data/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb +41 -0
  39. data/lib/puppet/module_tool/skeleton/templates/generator/metadata.json +12 -0
  40. data/lib/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb +17 -0
  41. data/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb +11 -0
  42. data/lib/puppet/module_tool/utils.rb +5 -0
  43. data/lib/puppet/module_tool/utils/interrogation.rb +25 -0
  44. data/lib/puppet/network/http/api/v1.rb +2 -1
  45. data/lib/puppet/parser/functions/create_resources.rb +19 -4
  46. data/lib/puppet/rails.rb +1 -1
  47. data/lib/puppet/rails/database/schema.rb +1 -1
  48. data/lib/puppet/ssl/host.rb +16 -8
  49. data/lib/puppet/transaction.rb +1 -1
  50. data/lib/puppet/type/file.rb +7 -2
  51. data/lib/puppet/type/file/ctime.rb +1 -1
  52. data/lib/puppet/type/file/mtime.rb +1 -1
  53. data/lib/puppet/type/file/type.rb +1 -1
  54. data/lib/puppet/util/queue/stomp.rb +19 -6
  55. data/lib/puppet/util/zaml.rb +39 -5
  56. data/spec/fixtures/releases/jamtur01-apache/Modulefile +2 -0
  57. data/spec/fixtures/releases/jamtur01-apache/files/httpd +24 -0
  58. data/spec/fixtures/releases/jamtur01-apache/files/test.vhost +18 -0
  59. data/spec/fixtures/releases/jamtur01-apache/lib/puppet/provider/a2mod/debian.rb +21 -0
  60. data/spec/fixtures/releases/jamtur01-apache/lib/puppet/type/a2mod.rb +12 -0
  61. data/spec/fixtures/releases/jamtur01-apache/manifests/dev.pp +5 -0
  62. data/spec/fixtures/releases/jamtur01-apache/manifests/init.pp +34 -0
  63. data/spec/fixtures/releases/jamtur01-apache/manifests/params.pp +17 -0
  64. data/spec/fixtures/releases/jamtur01-apache/manifests/php.pp +5 -0
  65. data/spec/fixtures/releases/jamtur01-apache/manifests/ssl.pp +15 -0
  66. data/spec/fixtures/releases/jamtur01-apache/manifests/vhost.pp +15 -0
  67. data/spec/fixtures/releases/jamtur01-apache/metadata.json +1 -0
  68. data/spec/fixtures/releases/jamtur01-apache/templates/vhost-default.conf.erb +20 -0
  69. data/spec/fixtures/releases/jamtur01-apache/tests/apache.pp +1 -0
  70. data/spec/fixtures/releases/jamtur01-apache/tests/dev.pp +1 -0
  71. data/spec/fixtures/releases/jamtur01-apache/tests/init.pp +1 -0
  72. data/spec/fixtures/releases/jamtur01-apache/tests/php.pp +1 -0
  73. data/spec/fixtures/releases/jamtur01-apache/tests/ssl.pp +1 -0
  74. data/spec/fixtures/releases/jamtur01-apache/tests/vhost.pp +2 -0
  75. data/spec/integration/module_tool_spec.rb +477 -0
  76. data/spec/integration/util/windows/security_spec.rb +1 -1
  77. data/spec/unit/application/agent_spec.rb +26 -0
  78. data/spec/unit/application/apply_spec.rb +12 -1
  79. data/spec/unit/face/module/build_spec.rb +30 -0
  80. data/spec/unit/face/module/changes_spec.rb +30 -0
  81. data/spec/unit/face/module/clean_spec.rb +30 -0
  82. data/spec/unit/face/module/generate_spec.rb +30 -0
  83. data/spec/unit/face/module/install_spec.rb +75 -0
  84. data/spec/unit/face/module/search_spec.rb +40 -0
  85. data/spec/unit/face/module_spec.rb +3 -0
  86. data/spec/unit/file_bucket/dipper_spec.rb +1 -1
  87. data/spec/unit/module_tool/application_spec.rb +29 -0
  88. data/spec/unit/module_tool/metadata_spec.rb +11 -0
  89. data/spec/unit/module_tool/repository_spec.rb +52 -0
  90. data/spec/unit/module_tool_spec.rb +38 -0
  91. data/spec/unit/network/http/api/v1_spec.rb +4 -0
  92. data/spec/unit/parser/functions/create_resources_spec.rb +21 -4
  93. data/spec/unit/rails_spec.rb +89 -158
  94. data/spec/unit/ssl/host_spec.rb +10 -33
  95. data/spec/unit/type/file_spec.rb +30 -0
  96. data/spec/unit/util/queue/stomp_spec.rb +9 -4
  97. data/spec/unit/util/zaml_spec.rb +37 -0
  98. metadata +77 -11
@@ -0,0 +1,34 @@
1
+ module Puppet::Module::Tool
2
+
3
+ # = Skeleton
4
+ #
5
+ # This class provides methods for finding templates for the 'generate' action.
6
+ class Skeleton
7
+
8
+ # TODO Review whether the 'freeze' feature should be fixed or deleted.
9
+ # def freeze!
10
+ # FileUtils.rm_fr custom_path rescue nil
11
+ # FileUtils.cp_r default_path, custom_path
12
+ # end
13
+
14
+ # Return Pathname with 'generate' templates.
15
+ def path
16
+ paths.detect { |path| path.directory? }
17
+ end
18
+
19
+ # Return Pathnames to look for 'generate' templates.
20
+ def paths
21
+ @paths ||= [ custom_path, default_path ]
22
+ end
23
+
24
+ # Return Pathname of custom templates directory.
25
+ def custom_path
26
+ Pathname(Puppet.settings[:module_working_dir]) + 'skeleton'
27
+ end
28
+
29
+ # Return Pathname of default template directory.
30
+ def default_path
31
+ Pathname(__FILE__).dirname + 'skeleton/templates/generator'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ name '<%= metadata.full_module_name %>'
2
+ version '0.0.1'
3
+ source '<%= metadata.source %>'
4
+ author '<%= metadata.author %>'
5
+ license '<%= metadata.license %>'
6
+ summary '<%= metadata.summary %>'
7
+ description '<%= metadata.description %>'
8
+ project_page '<%= metadata.project_page %>'
9
+
10
+ ## Add dependencies, if any:
11
+ # dependency 'username/name', '>= 1.2.0'
@@ -0,0 +1,16 @@
1
+ <%= metadata.name %>
2
+
3
+ This is the <%= metadata.name %> module.
4
+
5
+ License
6
+ -------
7
+
8
+
9
+ Contact
10
+ -------
11
+
12
+
13
+ Support
14
+ -------
15
+
16
+ Please log tickets and issues at our [Projects site](http://projects.example.com)
@@ -0,0 +1,41 @@
1
+ # == Class: <%= metadata.name %>
2
+ #
3
+ # Full description of class <%= metadata.name %> here.
4
+ #
5
+ # === Parameters
6
+ #
7
+ # Document parameters here.
8
+ #
9
+ # [*sample_parameter*]
10
+ # Explanation of what this parameter affects and what it defaults to.
11
+ # e.g. "Specify one or more upstream ntp servers as an array."
12
+ #
13
+ # === Variables
14
+ #
15
+ # Here you should define a list of variables that this module would require.
16
+ #
17
+ # [*sample_variable*]
18
+ # Explanation of how this variable affects the funtion of this class and if it
19
+ # has a default. e.g. "The parameter enc_ntp_servers must be set by the
20
+ # External Node Classifier as a comma separated list of hostnames." (Note,
21
+ # global variables should not be used in preference to class parameters as of
22
+ # Puppet 2.6.)
23
+ #
24
+ # === Examples
25
+ #
26
+ # class { <%= metadata.name %>:
27
+ # servers => [ 'pool.ntp.org', 'ntp.local.company.com' ]
28
+ # }
29
+ #
30
+ # === Authors
31
+ #
32
+ # Author Name <author@domain.com>
33
+ #
34
+ # === Copyright
35
+ #
36
+ # Copyright 2011 Your name here, unless otherwise noted.
37
+ #
38
+ class <%= metadata.name %> {
39
+
40
+
41
+ }
@@ -0,0 +1,12 @@
1
+ /*
2
+ +-----------------------------------------------------------------------+
3
+ | |
4
+ | ==> DO NOT EDIT THIS FILE! <== |
5
+ | |
6
+ | You should edit the `Modulefile` and run `puppet-module build` |
7
+ | to generate the `metadata.json` file for your releases. |
8
+ | |
9
+ +-----------------------------------------------------------------------+
10
+ */
11
+
12
+ {}
@@ -0,0 +1,17 @@
1
+ dir = File.expand_path(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift File.join(dir, 'lib')
3
+
4
+ require 'mocha'
5
+ require 'puppet'
6
+ require 'rspec'
7
+ require 'spec/autorun'
8
+
9
+ Spec::Runner.configure do |config|
10
+ config.mock_with :mocha
11
+ end
12
+
13
+ # We need this because the RAL uses 'should' as a method. This
14
+ # allows us the same behaviour but with a different method name.
15
+ class Object
16
+ alias :must :should
17
+ end
@@ -0,0 +1,11 @@
1
+ # The baseline for module testing used by Puppet Labs is that each manifest
2
+ # should have a corresponding test manifest that declares that class or defined
3
+ # type.
4
+ #
5
+ # Tests are then run by using puppet apply --noop (to check for compilation errors
6
+ # and view a log of events) or by fully applying the test in a virtual environment
7
+ # (to compare the resulting system state to the desired state).
8
+ #
9
+ # Learn more about module testing here: http://docs.puppetlabs.com/guides/tests_smoke.html
10
+ #
11
+ include <%= metadata.name %>
@@ -0,0 +1,5 @@
1
+ module Puppet::Module::Tool
2
+ module Utils
3
+ require 'puppet/module_tool/utils/interrogation'
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ module Puppet::Module::Tool
2
+ module Utils
3
+
4
+ # = Interrogation
5
+ #
6
+ # This module contains methods to emit questions to the console.
7
+ module Interrogation
8
+ def confirms?(question)
9
+ $stderr.print "#{question} [y/N]: "
10
+ $stdin.gets =~ /y/i
11
+ end
12
+
13
+ def prompt(question, quiet = false)
14
+ $stderr.print "#{question}: "
15
+ system 'stty -echo' if quiet
16
+ $stdin.gets.strip
17
+ ensure
18
+ if quiet
19
+ system 'stty echo'
20
+ say "\n---------"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -74,7 +74,8 @@ module Puppet::Network::HTTP::API::V1
74
74
 
75
75
  result = (indirection =~ /s$|_search$/) ? :plural : :singular
76
76
 
77
- indirection.sub!(/s$|_search$|es$/, '')
77
+ indirection.sub!(/s$|_search$/, '')
78
+ indirection.sub!(/statuse$/, 'status')
78
79
 
79
80
  result
80
81
  end
@@ -1,7 +1,7 @@
1
1
  Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC') do |args|
2
2
  Converts a hash into a set of resources and adds them to the catalog.
3
3
 
4
- This function takes two arguments: a resource type, and a hash describing
4
+ This function takes two mandatory arguments: a resource type, and a hash describing
5
5
  a set of resources. The hash should be in the form `{title => {parameters} }`:
6
6
 
7
7
  # A hash of user resources:
@@ -16,11 +16,24 @@ Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC
16
16
 
17
17
  create_resource(user, $myusers)
18
18
 
19
+ A third, optional parameter may be given, also as a hash:
20
+
21
+ $defaults => {
22
+ 'ensure' => present,
23
+ 'provider' => 'ldap',
24
+ }
25
+
26
+ create_resources(user, $myusers, $defaults)
27
+
28
+ The values given on the third argument are added to the parameters of each resource
29
+ present in the set given on the second argument. If a parameter is present on both
30
+ the second and third arguments, the one on the second argument takes precedence.
31
+
19
32
  This function can be used to create defined resources and classes, as well
20
33
  as native resources.
21
34
  ENDHEREDOC
22
- raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2
23
- #raise ArgumentError, 'requires resource type and param hash' if args.size < 2
35
+ raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2 or 3)") if args.length < 2 || args.length > 3
36
+
24
37
  # figure out what kind of resource we are
25
38
  type_of_resource = nil
26
39
  type_name = args[0].downcase
@@ -36,8 +49,10 @@ Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC
36
49
  end
37
50
  end
38
51
  # iterate through the resources to create
52
+ defaults = args[2] || {}
39
53
  args[1].each do |title, params|
40
54
  raise ArgumentError, 'params should not contain title' if(params['title'])
55
+ params = defaults.merge(params)
41
56
  case type_of_resource
42
57
  # JJM The only difference between a type and a define is the call to instantiate_resource
43
58
  # for a defined type.
@@ -54,7 +69,7 @@ Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC
54
69
  klass = find_hostclass(title)
55
70
  raise ArgumentError, "could not find hostclass #{title}" unless klass
56
71
  klass.ensure_in_catalog(self, params)
57
- compiler.catalog.add_class([title])
72
+ compiler.catalog.add_class(title)
58
73
  end
59
74
  end
60
75
  end
@@ -47,7 +47,7 @@ module Puppet::Rails
47
47
  case adapter
48
48
  when "sqlite3"
49
49
  args[:database] = Puppet[:dblocation]
50
- when "mysql", "postgresql"
50
+ when "mysql", "mysql2", "postgresql"
51
51
  args[:host] = Puppet[:dbserver] unless Puppet[:dbserver].to_s.empty?
52
52
  args[:port] = Puppet[:dbport] unless Puppet[:dbport].to_s.empty?
53
53
  args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
@@ -22,7 +22,7 @@ class Puppet::Rails::Schema
22
22
  # Thanks, mysql! MySQL requires a length on indexes in text fields.
23
23
  # So, we provide them for mysql and handle everything else specially.
24
24
  # Oracle doesn't index on CLOB fields, so we skip it
25
- if Puppet[:dbadapter] == "mysql"
25
+ if ['mysql','mysql2'].include? Puppet[:dbadapter]
26
26
  execute "CREATE INDEX typentitle ON resources (restype,title(50));"
27
27
  elsif Puppet[:dbadapter] != "oracle_enhanced"
28
28
  add_index :resources, [:title, :restype]
@@ -199,18 +199,26 @@ class Puppet::SSL::Host
199
199
  return nil unless Certificate.indirection.find("ca") unless ca?
200
200
  return nil unless @certificate = Certificate.indirection.find(name)
201
201
 
202
- unless certificate_matches_key?
203
- raise Puppet::Error, "Retrieved certificate does not match private key; please remove certificate from server and regenerate it with the current key"
204
- end
202
+ validate_certificate_with_key
205
203
  end
206
204
  @certificate
207
205
  end
208
206
 
209
- def certificate_matches_key?
210
- return false unless key
211
- return false unless certificate
212
-
213
- certificate.content.check_private_key(key.content)
207
+ def validate_certificate_with_key
208
+ raise Puppet::Error, "No certificate to validate." unless certificate
209
+ raise Puppet::Error, "No private key with which to validate certificate with fingerprint: #{certificate.fingerprint}" unless key
210
+ unless certificate.content.check_private_key(key.content)
211
+ raise Puppet::Error, <<ERROR_STRING
212
+ The certificate retrieved from the master does not match the agent's private key.
213
+ Certificate fingerprint: #{certificate.fingerprint}
214
+ To fix this, remove the certificate from both the master and the agent and then start a puppet run, which will automatically regenerate a certficate.
215
+ On the master:
216
+ puppet cert clean #{Puppet[:certname]}
217
+ On the agent:
218
+ rm -f #{Puppet[:hostcert]}
219
+ puppet agent -t
220
+ ERROR_STRING
221
+ end
214
222
  end
215
223
 
216
224
  # Generate all necessary parts of our ssl host.
@@ -150,7 +150,7 @@ class Puppet::Transaction
150
150
  begin
151
151
  made = resource.eval_generate.uniq
152
152
  return false if made.empty?
153
- made = Hash[made.map(&:name).zip(made)]
153
+ made = made.inject({}) {|a,v| a.merge(v.name => v) }
154
154
  rescue => detail
155
155
  puts detail.backtrace if Puppet[:trace]
156
156
  resource.err "Failed to generate additional resources using 'eval_generate: #{detail}"
@@ -261,13 +261,18 @@ Puppet::Type.newtype(:file) do
261
261
 
262
262
  # Autorequire the nearest ancestor directory found in the catalog.
263
263
  autorequire(:file) do
264
+ req = []
264
265
  path = Pathname.new(self[:path])
265
266
  if !path.root?
266
267
  # Start at our parent, to avoid autorequiring ourself
267
268
  parents = path.parent.enum_for(:ascend)
268
- found = parents.find { |p| catalog.resource(:file, p.to_s) }
269
- found and found.to_s
269
+ if found = parents.find { |p| catalog.resource(:file, p.to_s) }
270
+ req << found.to_s
271
+ end
270
272
  end
273
+ # if the resource is a link, make sure the target is created first
274
+ req << self[:target] if self[:target]
275
+ req
271
276
  end
272
277
 
273
278
  # Autorequire the owner and group of the file.
@@ -10,7 +10,7 @@ module Puppet
10
10
  current_value
11
11
  end
12
12
 
13
- validate do
13
+ validate do |val|
14
14
  fail "ctime is read-only"
15
15
  end
16
16
  end
@@ -10,7 +10,7 @@ module Puppet
10
10
  current_value
11
11
  end
12
12
 
13
- validate do
13
+ validate do |val|
14
14
  fail "mtime is read-only"
15
15
  end
16
16
  end
@@ -11,7 +11,7 @@ module Puppet
11
11
  current_value
12
12
  end
13
13
 
14
- validate do
14
+ validate do |val|
15
15
  fail "type is read-only"
16
16
  end
17
17
  end
@@ -2,12 +2,14 @@ require 'puppet/util/queue'
2
2
  require 'stomp'
3
3
  require 'uri'
4
4
 
5
- # Implements the Ruby Stomp client as a queue type within the Puppet::Indirector::Queue::Client
6
- # registry, for use with the <tt>:queue</tt> indirection terminus type.
5
+ # Implements the Ruby Stomp client as a queue type within the
6
+ # Puppet::Indirector::Queue::Client registry, for use with the <tt>:queue</tt>
7
+ # indirection terminus type.
7
8
  #
8
- # Looks to <tt>Puppet[:queue_source]</tt> for the sole argument to the underlying Stomp::Client constructor;
9
- # consequently, for this client to work, <tt>Puppet[:queue_source]</tt> must use the Stomp::Client URL-like
10
- # syntax for identifying the Stomp message broker: <em>login:pass@host.port</em>
9
+ # Looks to <tt>Puppet[:queue_source]</tt> for the sole argument to the
10
+ # underlying Stomp::Client constructor; consequently, for this client to work,
11
+ # <tt>Puppet[:queue_source]</tt> must use the Stomp::Client URL-like syntax
12
+ # for identifying the Stomp message broker: <em>login:pass@host.port</em>
11
13
  class Puppet::Util::Queue::Stomp
12
14
  attr_accessor :stomp_client
13
15
 
@@ -26,10 +28,21 @@ class Puppet::Util::Queue::Stomp
26
28
  rescue => detail
27
29
  raise ArgumentError, "Could not create Stomp client instance with queue source #{Puppet[:queue_source]}: got internal Stomp client error #{detail}"
28
30
  end
31
+
32
+ # Identify the supported method for sending messages.
33
+ @method =
34
+ case
35
+ when stomp_client.respond_to?(:publish)
36
+ :publish
37
+ when stomp_client.respond_to?(:send)
38
+ :send
39
+ else
40
+ raise ArgumentError, "STOMP client does not respond to either publish or send"
41
+ end
29
42
  end
30
43
 
31
44
  def publish_message(target, msg)
32
- stomp_client.publish(stompify_target(target), msg, :persistent => true)
45
+ stomp_client.__send__(@method, stompify_target(target), msg, :persistent => true)
33
46
  end
34
47
 
35
48
  def subscribe(target)
@@ -1,4 +1,15 @@
1
+ # encoding: UTF-8
1
2
  #
3
+ # The above encoding line is a magic comment to set the default source encoding
4
+ # of this file for the Ruby interpreter. It must be on the first or second
5
+ # line of the file if an interpreter is in use. In Ruby 1.9 and later, the
6
+ # source encoding determines the encoding of String and Regexp objects created
7
+ # from this source file. This explicit encoding is important becuase otherwise
8
+ # Ruby will pick an encoding based on LANG or LC_CTYPE environment variables.
9
+ # These may be different from site to site so it's important for us to
10
+ # establish a consistent behavior. For more information on M17n please see:
11
+ # http://links.puppetlabs.com/understanding_m17n
12
+
2
13
  # ZAML -- A partial replacement for YAML, writen with speed and code clarity
3
14
  # in mind. ZAML fixes one YAML bug (loading Exceptions) and provides
4
15
  # a replacement for YAML.dump unimaginatively called ZAML.dump,
@@ -218,10 +229,16 @@ end
218
229
  class String
219
230
  ZAML_ESCAPES = %w{\x00 \x01 \x02 \x03 \x04 \x05 \x06 \a \x08 \t \n \v \f \r \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f }
220
231
  def escaped_for_zaml
221
- gsub( /\x5C/, "\\\\\\" ). # Demi-kludge for Maglev/rubinius; the regexp should be /\\/ but parsetree chokes on that.
222
- gsub( /"/, "\\\"" ).
223
- gsub( /([\x00-\x1F])/ ) { |x| ZAML_ESCAPES[ x.unpack("C")[0] ] }.
224
- gsub( /([\x80-\xFF])/ ) { |x| "\\x#{x.unpack("C")[0].to_s(16)}" }
232
+ # JJM (Note the trailing dots to construct a multi-line method chain.) This
233
+ # code is meant to escape all bytes which are not ASCII-8BIT printable
234
+ # characters. Multi-byte unicode characters are handled just fine because
235
+ # each byte of the character results in an escaped string emitted to the
236
+ # YAML stream. When the YAML is de-serialized back into a String the bytes
237
+ # will be reconstructed properly into the unicode character.
238
+ self.to_ascii8bit.gsub( /\x5C/n, "\\\\\\" ). # Demi-kludge for Maglev/rubinius; the regexp should be /\\/ but parsetree chokes on that.
239
+ gsub( /"/n, "\\\"" ).
240
+ gsub( /([\x00-\x1F])/n ) { |x| ZAML_ESCAPES[ x.unpack("C")[0] ] }.
241
+ gsub( /([\x80-\xFF])/n ) { |x| "\\x#{x.unpack("C")[0].to_s(16)}" }
225
242
  end
226
243
  def to_zaml(z)
227
244
  z.first_time_only(self) {
@@ -238,7 +255,10 @@ class String
238
255
  (self =~ /[\s:]$/) or
239
256
  (self =~ /^[>|][-+\d]*\s/i) or
240
257
  (self[-1..-1] =~ /\s/) or
241
- (self =~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/) or
258
+ # This regular expression assumes the string is a byte sequence.
259
+ # It does not concern itself with characters so we convert the string
260
+ # to ASCII-8BIT for Ruby 1.9 to match up encodings.
261
+ (self.to_ascii8bit=~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/n) or
242
262
  (self =~ /[,\[\]\{\}\r\t]|:\s|\s#/) or
243
263
  (self =~ /\A([-:?!#&*'"]|<<|%.+:.)/)
244
264
  )
@@ -251,6 +271,20 @@ class String
251
271
  end
252
272
  }
253
273
  end
274
+
275
+ # Return a guranteed ASCII-8BIT encoding for Ruby 1.9 This is a helper
276
+ # method for other methods that perform regular expressions against byte
277
+ # sequences deliberately rather than dealing with characters.
278
+ # The method may or may not return a new instance.
279
+ def to_ascii8bit
280
+ if self.respond_to?(:encoding) and self.encoding.name != "ASCII-8BIT" then
281
+ str = self.dup
282
+ str.force_encoding("ASCII-8BIT")
283
+ return str
284
+ else
285
+ return self
286
+ end
287
+ end
254
288
  end
255
289
 
256
290
  class Hash