pancake 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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