pancake 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. data/bin/pancake +96 -0
  2. data/lib/pancake.rb +5 -7
  3. data/lib/pancake/configuration.rb +2 -23
  4. data/lib/pancake/core_ext/object.rb +1 -1
  5. data/lib/pancake/defaults/configuration.rb +21 -1
  6. data/lib/pancake/generators.rb +0 -3
  7. data/lib/pancake/hooks/inheritable_inner_classes.rb +15 -2
  8. data/lib/pancake/master.rb +34 -1
  9. data/lib/pancake/mixins/render.rb +1 -2
  10. data/lib/pancake/mixins/stack_helper.rb +1 -1
  11. data/lib/pancake/router.rb +18 -63
  12. data/lib/pancake/stack/configuration.rb +3 -5
  13. data/lib/pancake/stack/router.rb +10 -33
  14. data/lib/pancake/stack/stack.rb +70 -50
  15. data/{spec/helpers → lib/pancake/test}/helpers.rb +3 -3
  16. data/lib/pancake/test/matchers.rb +20 -0
  17. data/lib/pancake/vendor/hashie/.document +5 -0
  18. data/lib/pancake/vendor/hashie/.gitignore +7 -0
  19. data/lib/pancake/vendor/hashie/Gemfile +11 -0
  20. data/lib/pancake/vendor/hashie/Gemfile.lock +25 -0
  21. data/lib/pancake/{generators/templates/short/%stack_name%/LICENSE.tt → vendor/hashie/LICENSE} +1 -1
  22. data/lib/pancake/vendor/hashie/README.rdoc +101 -0
  23. data/lib/pancake/{generators/templates/micro/%stack_name%/Rakefile.tt → vendor/hashie/Rakefile} +3 -13
  24. data/lib/pancake/vendor/hashie/VERSION +1 -0
  25. data/lib/pancake/vendor/hashie/hashie.gemspec +33 -0
  26. data/lib/pancake/vendor/hashie/lib/hashie.rb +5 -0
  27. data/lib/pancake/vendor/hashie/lib/hashie/clash.rb +86 -0
  28. data/lib/pancake/vendor/hashie/lib/hashie/dash.rb +108 -0
  29. data/lib/pancake/vendor/hashie/lib/hashie/hash.rb +22 -0
  30. data/lib/pancake/vendor/hashie/lib/hashie/hash_extensions.rb +49 -0
  31. data/lib/pancake/vendor/hashie/lib/hashie/mash.rb +148 -0
  32. data/lib/pancake/vendor/hashie/spec/hashie/clash_spec.rb +42 -0
  33. data/lib/pancake/vendor/hashie/spec/hashie/dash_spec.rb +103 -0
  34. data/lib/pancake/vendor/hashie/spec/hashie/hash_spec.rb +22 -0
  35. data/lib/pancake/vendor/hashie/spec/hashie/mash_spec.rb +135 -0
  36. data/lib/pancake/vendor/hashie/spec/spec.opts +2 -0
  37. data/lib/pancake/{generators/templates/short/%stack_name%/spec/spec_helper.rb.tt → vendor/hashie/spec/spec_helper.rb} +7 -7
  38. data/spec/pancake/configuration_spec.rb +1 -1
  39. data/spec/pancake/constants_spec.rb +1 -1
  40. data/spec/pancake/defaults/configuration_spec.rb +1 -1
  41. data/spec/pancake/hooks/on_inherit_spec.rb +13 -13
  42. data/spec/pancake/inheritance_spec.rb +22 -22
  43. data/spec/pancake/middleware_spec.rb +6 -5
  44. data/spec/pancake/middlewares/logger_spec.rb +1 -1
  45. data/spec/pancake/middlewares/static_spec.rb +1 -1
  46. data/spec/pancake/mime_types_spec.rb +1 -1
  47. data/spec/pancake/mixins/publish_spec.rb +24 -24
  48. data/spec/pancake/mixins/render/template_spec.rb +1 -1
  49. data/spec/pancake/mixins/render/view_context_spec.rb +1 -1
  50. data/spec/pancake/mixins/render_spec.rb +1 -1
  51. data/spec/pancake/mixins/request_helper_spec.rb +1 -1
  52. data/spec/pancake/mixins/stack_helper_spec.rb +3 -3
  53. data/spec/pancake/pancake_spec.rb +1 -1
  54. data/spec/pancake/paths_spec.rb +30 -30
  55. data/spec/pancake/stack/router_spec.rb +24 -62
  56. data/spec/pancake/stack/stack_configuration_spec.rb +1 -1
  57. data/spec/pancake/stack/stack_spec.rb +47 -4
  58. data/spec/spec_helper.rb +3 -3
  59. metadata +56 -128
  60. data/bin/pancake-gen +0 -30
  61. data/lib/pancake/bootloaders.rb +0 -187
  62. data/lib/pancake/generators/base.rb +0 -12
  63. data/lib/pancake/generators/micro_generator.rb +0 -17
  64. data/lib/pancake/generators/short_generator.rb +0 -18
  65. data/lib/pancake/generators/templates/common/dotgitignore +0 -22
  66. data/lib/pancake/generators/templates/common/dothtaccess +0 -17
  67. data/lib/pancake/generators/templates/micro/%stack_name%/%stack_name%.rb.tt +0 -8
  68. data/lib/pancake/generators/templates/micro/%stack_name%/config.ru.tt +0 -12
  69. data/lib/pancake/generators/templates/micro/%stack_name%/pancake_init.rb.tt +0 -1
  70. data/lib/pancake/generators/templates/micro/%stack_name%/public/.empty_directory +0 -0
  71. data/lib/pancake/generators/templates/micro/%stack_name%/tmp/.empty_directory +0 -0
  72. data/lib/pancake/generators/templates/micro/%stack_name%/views/root.html.haml +0 -1
  73. data/lib/pancake/generators/templates/short/%stack_name%/README.tt +0 -7
  74. data/lib/pancake/generators/templates/short/%stack_name%/Rakefile.tt +0 -56
  75. data/lib/pancake/generators/templates/short/%stack_name%/VERSION.tt +0 -1
  76. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%.rb.tt +0 -12
  77. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/%stack_name%.rb.tt +0 -6
  78. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config.ru.tt +0 -10
  79. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/config.rb.tt +0 -23
  80. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/environments/development.rb.tt +0 -15
  81. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/environments/production.rb.tt +0 -16
  82. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/environments/staging.rb.tt +0 -17
  83. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/models/.empty_directory +0 -0
  84. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/mounts/.empty_directory +0 -0
  85. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/public/.empty_directory +0 -0
  86. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/tasks/%stack_name%.rake.tt +0 -4
  87. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/tmp/.empty_directory +0 -0
  88. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/views/root.html.haml +0 -2
  89. data/lib/pancake/generators/templates/short/%stack_name%/pancake_init.rb.tt +0 -1
  90. data/lib/pancake/generators/templates/short/%stack_name%/spec/%stack_name%_spec.rb.tt +0 -11
  91. data/lib/pancake/stack/app.rb +0 -10
  92. data/lib/pancake/stack/bootloader.rb +0 -114
  93. data/lib/pancake/stack/middleware.rb +0 -0
  94. data/lib/pancake/stacks/short.rb +0 -3
  95. data/lib/pancake/stacks/short/bootloaders.rb +0 -5
  96. data/lib/pancake/stacks/short/controller.rb +0 -184
  97. data/lib/pancake/stacks/short/default/views/base.html.haml +0 -5
  98. data/lib/pancake/stacks/short/default/views/error.html.haml +0 -12
  99. data/lib/pancake/stacks/short/stack.rb +0 -207
  100. data/spec/helpers/matchers.rb +0 -25
  101. data/spec/pancake/bootloaders_spec.rb +0 -119
  102. data/spec/pancake/stack/app_spec.rb +0 -28
  103. data/spec/pancake/stack/bootloader_spec.rb +0 -41
  104. data/spec/pancake/stack/middleware_spec.rb +0 -0
  105. data/spec/pancake/stacks/short/controller_spec.rb +0 -442
  106. data/spec/pancake/stacks/short/middlewares_spec.rb +0 -22
  107. data/spec/pancake/stacks/short/router_spec.rb +0 -150
  108. data/spec/pancake/stacks/short/stack_spec.rb +0 -117
@@ -1,11 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
- require 'pancake'
4
-
5
- require File.join(Pancake.get_root(__FILE__), "<%= stack_name %>")
6
- Pancake.root = Pancake.get_root(__FILE__)
7
- THIS_STACK = <%= stack_name.camel_case %>
8
- <%= stack_name.camel_case %>.load_rake_tasks!(:master => true)
9
3
 
10
4
  require 'spec/rake/spectask'
11
5
  Spec::Rake::SpecTask.new(:spec) do |spec|
@@ -19,22 +13,18 @@ Spec::Rake::SpecTask.new(:rcov) do |spec|
19
13
  spec.rcov = true
20
14
  end
21
15
 
22
-
23
16
  task :default => :spec
24
17
 
25
18
  require 'rake/rdoctask'
26
19
  Rake::RDocTask.new do |rdoc|
27
- if File.exist?('VERSION.yml')
28
- config = YAML.load(File.read('VERSION.yml'))
29
- version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
20
+ if File.exist?('VERSION')
21
+ version = File.read('VERSION')
30
22
  else
31
23
  version = ""
32
24
  end
33
25
 
34
26
  rdoc.rdoc_dir = 'rdoc'
35
- rdoc.title = "foo #{version}"
27
+ rdoc.title = "hashie #{version}"
36
28
  rdoc.rdoc_files.include('README*')
37
29
  rdoc.rdoc_files.include('lib/**/*.rb')
38
30
  end
39
-
40
-
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'bundler'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{hashie}
7
+ s.version = File.read("VERSION")
8
+
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.authors = ["Michael Bleigh"]
11
+ s.date = %q{2010-03-05}
12
+ s.description = %q{Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).}
13
+ s.email = %q{michael@intridea.com}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = Dir["**/*"]
19
+ s.add_bundler_dependencies
20
+ s.homepage = %q{http://github.com/intridea/hashie}
21
+ s.rdoc_options = ["--charset=UTF-8"]
22
+ s.require_paths = ["lib"]
23
+ s.rubygems_version = %q{1.3.6}
24
+ s.summary = %q{Your friendly neighborhood hash toolkit.}
25
+ s.test_files = [
26
+ "spec/hashie/clash_spec.rb",
27
+ "spec/hashie/dash_spec.rb",
28
+ "spec/hashie/hash_spec.rb",
29
+ "spec/hashie/mash_spec.rb",
30
+ "spec/spec_helper.rb"
31
+ ]
32
+ end
33
+
@@ -0,0 +1,5 @@
1
+ require 'hashie/hash_extensions'
2
+ require 'hashie/hash'
3
+ require 'hashie/mash'
4
+ require 'hashie/dash'
5
+ require 'hashie/clash'
@@ -0,0 +1,86 @@
1
+ require 'hashie/hash'
2
+
3
+ module Hashie
4
+ #
5
+ # A Clash is a "Chainable Lazy Hash". Inspired by libraries such as Arel,
6
+ # a Clash allows you to chain together method arguments to build a
7
+ # hash, something that's especially useful if you're doing something
8
+ # like constructing a complex options hash. Here's a basic example:
9
+ #
10
+ # c = Hashie::Clash.new.conditions(:foo => 'bar').order(:created_at)
11
+ # c # => {:conditions => {:foo => 'bar'}, :order => :created_at}
12
+ #
13
+ # Clash provides another way to create sub-hashes by using bang notation.
14
+ # You can dive into a sub-hash by providing a key with a bang and dive
15
+ # back out again with the _end! method. Example:
16
+ #
17
+ # c = Hashie::Clash.new.conditions!.foo('bar').baz(123)._end!.order(:created_at)
18
+ # c # => {:conditions => {:foo => 'bar', :baz => 123}, :order => :created_at}
19
+ #
20
+ # Because the primary functionality of Clash is to build options objects,
21
+ # all keys are converted to symbols since many libraries expect symbols explicitly
22
+ # for keys.
23
+ #
24
+ class Clash < ::Hash
25
+ class ChainError < ::StandardError; end
26
+ # The parent Clash if this Clash was created via chaining.
27
+ attr_reader :_parent
28
+
29
+ # Initialize a new clash by passing in a Hash to
30
+ # convert and, optionally, the parent to which this
31
+ # Clash is chained.
32
+ def initialize(other_hash = {}, parent = nil)
33
+ @_parent = parent
34
+ other_hash.each_pair do |k, v|
35
+ self[k.to_sym] = v
36
+ end
37
+ end
38
+
39
+ # Jump back up a level if you are using bang method
40
+ # chaining. For example:
41
+ #
42
+ # c = Hashie::Clash.new.foo('bar')
43
+ # c.baz!.foo(123) # => c[:baz]
44
+ # c.baz!._end! # => c
45
+ def _end!
46
+ self._parent
47
+ end
48
+
49
+ def id(*args) #:nodoc:
50
+ method_missing(:id, *args)
51
+ end
52
+
53
+ def merge_store(key, *args) #:nodoc:
54
+ case args.length
55
+ when 1
56
+ val = args.first
57
+ val = self[key].merge(val) if self[key].is_a?(::Hash) && val.is_a?(::Hash)
58
+ else
59
+ val = args
60
+ end
61
+
62
+ self[key.to_sym] = val
63
+ self
64
+ end
65
+
66
+ def method_missing(name, *args) #:nodoc:
67
+ name = name.to_s
68
+ if name.match(/!$/) && args.empty?
69
+ key = name[0...-1].to_sym
70
+
71
+ if self[key].nil?
72
+ self[key] = Clash.new({}, self)
73
+ elsif self[key].is_a?(::Hash) && !self[key].is_a?(Clash)
74
+ self[key] = Clash.new(self[key], self)
75
+ else
76
+ raise ChainError, "Tried to chain into a non-hash key."
77
+ end
78
+
79
+ self[key]
80
+ elsif args.any?
81
+ key = name.to_sym
82
+ self.merge_store(key, *args)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,108 @@
1
+ require 'hashie/hash'
2
+
3
+ module Hashie
4
+ include Hashie::PrettyInspect
5
+ # A Dash is a 'defined' or 'discrete' Hash, that is, a Hash
6
+ # that has a set of defined keys that are accessible (with
7
+ # optional defaults) and only those keys may be set or read.
8
+ #
9
+ # Dashes are useful when you need to create a very simple
10
+ # lightweight data object that needs even fewer options and
11
+ # resources than something like a DataMapper resource.
12
+ #
13
+ # It is preferrable to a Struct because of the in-class
14
+ # API for defining properties as well as per-property defaults.
15
+ class Dash < Hashie::Hash
16
+ include Hashie::PrettyInspect
17
+ alias_method :to_s, :inspect
18
+
19
+ # Defines a property on the Dash. Options are
20
+ # as follows:
21
+ #
22
+ # * <tt>:default</tt> - Specify a default value for this property,
23
+ # to be returned before a value is set on the property in a new
24
+ # Dash.
25
+ #
26
+ def self.property(property_name, options = {})
27
+ property_name = property_name.to_sym
28
+
29
+ (@properties ||= []) << property_name
30
+ (@defaults ||= {})[property_name] = options.delete(:default)
31
+
32
+ class_eval <<-RUBY
33
+ def #{property_name}
34
+ self[:#{property_name}]
35
+ end
36
+
37
+ def #{property_name}=(val)
38
+ self[:#{property_name}] = val
39
+ end
40
+ RUBY
41
+ end
42
+
43
+ # Get a String array of the currently defined
44
+ # properties on this Dash.
45
+ def self.properties
46
+ properties = []
47
+ ancestors.each do |elder|
48
+ if elder.instance_variable_defined?("@properties")
49
+ properties << elder.instance_variable_get("@properties")
50
+ end
51
+ end
52
+
53
+ properties.flatten.map{|p| p.to_s}
54
+ end
55
+
56
+ # Check to see if the specified property has already been
57
+ # defined.
58
+ def self.property?(prop)
59
+ properties.include?(prop.to_s)
60
+ end
61
+
62
+ # The default values that have been set for this Dash
63
+ def self.defaults
64
+ properties = {}
65
+ ancestors.each do |elder|
66
+ if elder.instance_variable_defined?("@defaults")
67
+ properties.merge! elder.instance_variable_get("@defaults")
68
+ end
69
+ end
70
+
71
+ properties
72
+ end
73
+
74
+ # You may initialize a Dash with an attributes hash
75
+ # just like you would many other kinds of data objects.
76
+ def initialize(attributes = {})
77
+ self.class.properties.each do |prop|
78
+ self.send("#{prop}=", self.class.defaults[prop.to_sym])
79
+ end
80
+
81
+ attributes.each_pair do |att, value|
82
+ self.send("#{att}=", value)
83
+ end
84
+ end
85
+
86
+ # Retrieve a value from the Dash (will return the
87
+ # property's default value if it hasn't been set).
88
+ def [](property)
89
+ super(property.to_sym) if property_exists? property
90
+ end
91
+
92
+ # Set a value on the Dash in a Hash-like way. Only works
93
+ # on pre-existing properties.
94
+ def []=(property, value)
95
+ super if property_exists? property
96
+ end
97
+
98
+ private
99
+ # Raises an NoMethodError if the property doesn't exist
100
+ #
101
+ def property_exists?(property)
102
+ unless self.class.property?(property.to_sym)
103
+ raise NoMethodError, "The property '#{property}' is not defined for this Dash."
104
+ end
105
+ true
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,22 @@
1
+ module Hashie
2
+ # A Hashie Hash is simply a Hash that has convenience
3
+ # functions baked in such as stringify_keys that may
4
+ # not be available in all libraries.
5
+ class Hash < Hash
6
+ include Hashie::HashExtensions
7
+
8
+ # Converts a mash back to a hash (with stringified keys)
9
+ def to_hash
10
+ out = {}
11
+ keys.each do |k|
12
+ out[k] = Hashie::Hash === self[k] ? self[k].to_hash : self[k]
13
+ end
14
+ out
15
+ end
16
+
17
+ # The C geneartor for the json gem doesn't like mashies
18
+ def to_json(*args)
19
+ to_hash.to_json(*args)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ module Hashie
2
+ module HashExtensions
3
+ def self.included(base)
4
+ # Don't tread on existing extensions of Hash by
5
+ # adding methods that are likely to exist.
6
+ %w(stringify_keys stringify_keys!).each do |hashie_method|
7
+ base.send :alias_method, hashie_method, "hashie_#{hashie_method}" unless base.instance_methods.include?(hashie_method)
8
+ end
9
+ end
10
+
11
+ # Destructively convert all of the keys of a Hash
12
+ # to their string representations.
13
+ def hashie_stringify_keys!
14
+ self.keys.each do |k|
15
+ unless String === k
16
+ self[k.to_s] = self.delete(k)
17
+ end
18
+ end
19
+ self
20
+ end
21
+
22
+ # Convert all of the keys of a Hash
23
+ # to their string representations.
24
+ def hashie_stringify_keys
25
+ self.dup.stringify_keys!
26
+ end
27
+
28
+ # Convert this hash into a Mash
29
+ def to_mash
30
+ Hashie::Mash.new(self)
31
+ end
32
+ end
33
+
34
+ module PrettyInspect
35
+ def self.included(base)
36
+ base.send :alias_method, :hash_inspect, :inspect
37
+ base.send :alias_method, :inspect, :hashie_inspect
38
+ end
39
+
40
+ def hashie_inspect
41
+ ret = "<##{self.class.to_s}"
42
+ stringify_keys.keys.sort.each do |key|
43
+ ret << " #{key}=#{self[key].inspect}"
44
+ end
45
+ ret << ">"
46
+ ret
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,148 @@
1
+ module Hashie
2
+ # Mash allows you to create pseudo-objects that have method-like
3
+ # accessors for hash keys. This is useful for such implementations
4
+ # as an API-accessing library that wants to fake robust objects
5
+ # without the overhead of actually doing so. Think of it as OpenStruct
6
+ # with some additional goodies.
7
+ #
8
+ # A Mash will look at the methods you pass it and perform operations
9
+ # based on the following rules:
10
+ #
11
+ # * No punctuation: Returns the value of the hash for that key, or nil if none exists.
12
+ # * Assignment (<tt>=</tt>): Sets the attribute of the given method name.
13
+ # * Existence (<tt>?</tt>): Returns true or false depending on whether that key has been set.
14
+ # * Bang (<tt>!</tt>): Forces the existence of this key, used for deep Mashes. Think of it as "touch" for mashes.
15
+ #
16
+ # == Basic Example
17
+ #
18
+ # mash = Mash.new
19
+ # mash.name? # => false
20
+ # mash.name = "Bob"
21
+ # mash.name # => "Bob"
22
+ # mash.name? # => true
23
+ #
24
+ # == Hash Conversion Example
25
+ #
26
+ # hash = {:a => {:b => 23, :d => {:e => "abc"}}, :f => [{:g => 44, :h => 29}, 12]}
27
+ # mash = Mash.new(hash)
28
+ # mash.a.b # => 23
29
+ # mash.a.d.e # => "abc"
30
+ # mash.f.first.g # => 44
31
+ # mash.f.last # => 12
32
+ #
33
+ # == Bang Example
34
+ #
35
+ # mash = Mash.new
36
+ # mash.author # => nil
37
+ # mash.author! # => <Mash>
38
+ #
39
+ # mash = Mash.new
40
+ # mash.author!.name = "Michael Bleigh"
41
+ # mash.author # => <Mash name="Michael Bleigh">
42
+ #
43
+ class Mash < Hashie::Hash
44
+ include Hashie::PrettyInspect
45
+ alias_method :to_s, :inspect
46
+
47
+ # If you pass in an existing hash, it will
48
+ # convert it to a Mash including recursively
49
+ # descending into arrays and hashes, converting
50
+ # them as well.
51
+ def initialize(source_hash = nil, default = nil, &blk)
52
+ deep_update(source_hash) if source_hash
53
+ default ? super(default) : super(&blk)
54
+ end
55
+
56
+ class << self; alias [] new; end
57
+
58
+ def id #:nodoc:
59
+ key?("id") ? self["id"] : super
60
+ end
61
+
62
+ alias_method :regular_reader, :[]
63
+ alias_method :regular_writer, :[]=
64
+
65
+ # Retrieves an attribute set in the Mash. Will convert
66
+ # any key passed in to a string before retrieving.
67
+ def [](key)
68
+ regular_reader(convert_key(key))
69
+ end
70
+
71
+ # Sets an attribute in the Mash. Key will be converted to
72
+ # a string before it is set, and Hashes will be converted
73
+ # into Mashes for nesting purposes.
74
+ def []=(key,value) #:nodoc:
75
+ regular_writer(convert_key(key), convert_value(value))
76
+ end
77
+
78
+ # This is the bang method reader, it will return a new Mash
79
+ # if there isn't a value already assigned to the key requested.
80
+ def initializing_reader(key)
81
+ ck = convert_key(key)
82
+ regular_writer(ck, Hashie::Mash.new) unless key?(ck)
83
+ regular_reader(ck)
84
+ end
85
+
86
+ alias_method :regular_dup, :dup
87
+ # Duplicates the current mash as a new mash.
88
+ def dup
89
+ Mash.new(self, self.default)
90
+ end
91
+
92
+ def key?(key)
93
+ super(convert_key(key))
94
+ end
95
+
96
+ # Performs a deep_update on a duplicate of the
97
+ # current mash.
98
+ def deep_merge(other_hash)
99
+ dup.deep_merge!(other_hash)
100
+ end
101
+
102
+ # Recursively merges this mash with the passed
103
+ # in hash, merging each hash in the hierarchy.
104
+ def deep_update(other_hash)
105
+ other_hash.each_pair do |k,v|
106
+ regular_writer(convert_key(k), convert_value(other_hash[k], true))
107
+ end
108
+ self
109
+ end
110
+ alias_method :deep_merge!, :deep_update
111
+ alias_method :update, :deep_update
112
+ alias_method :merge!, :update
113
+
114
+
115
+ def method_missing(method_name, *args, &blk)
116
+ return self[method_name] if key?(method_name)
117
+ match = method_name.to_s.match(/(.*?)([?=!]?)$/)
118
+ case match[2]
119
+ when "="
120
+ self[match[1]] = args.first
121
+ when "?"
122
+ key?(match[1])
123
+ when "!"
124
+ initializing_reader(match[1])
125
+ else
126
+ default(method_name, *args, &blk)
127
+ end
128
+ end
129
+
130
+ protected
131
+
132
+ def convert_key(key) #:nodoc:
133
+ key.to_s
134
+ end
135
+
136
+ def convert_value(val, duping=false) #:nodoc:
137
+ case val
138
+ when ::Hash
139
+ val = val.dup if duping
140
+ self.class.new(val)
141
+ when Array
142
+ val.collect{ |e| convert_value(e) }
143
+ else
144
+ val
145
+ end
146
+ end
147
+ end
148
+ end