fortitude 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +26 -2
  3. data/CHANGES.md +29 -0
  4. data/lib/fortitude.rb +6 -92
  5. data/lib/fortitude/doctypes.rb +6 -4
  6. data/lib/fortitude/doctypes/base.rb +6 -2
  7. data/lib/fortitude/doctypes/html4.rb +2 -1
  8. data/lib/fortitude/doctypes/html4_frameset.rb +2 -0
  9. data/lib/fortitude/doctypes/html4_strict.rb +1 -0
  10. data/lib/fortitude/doctypes/html4_tags_frameset.rb +3 -2
  11. data/lib/fortitude/doctypes/html4_tags_strict.rb +3 -2
  12. data/lib/fortitude/doctypes/html4_tags_transitional.rb +3 -2
  13. data/lib/fortitude/doctypes/html4_transitional.rb +1 -0
  14. data/lib/fortitude/doctypes/html5.rb +3 -2
  15. data/lib/fortitude/doctypes/unknown_doctype.rb +1 -0
  16. data/lib/fortitude/doctypes/xhtml10.rb +2 -1
  17. data/lib/fortitude/doctypes/xhtml10_frameset.rb +1 -0
  18. data/lib/fortitude/doctypes/xhtml10_strict.rb +1 -0
  19. data/lib/fortitude/doctypes/xhtml10_transitional.rb +1 -0
  20. data/lib/fortitude/doctypes/xhtml11.rb +2 -1
  21. data/lib/fortitude/{fortitude_ruby_ext.rb → extensions/fortitude_ruby_ext.rb} +16 -11
  22. data/lib/fortitude/extensions/native_extensions.rb +33 -0
  23. data/lib/fortitude/{assign_locals_from_template.rb.smpl → method_templates/assign_locals_from_template.rb.smpl} +0 -0
  24. data/lib/fortitude/{need_assignment_template.rb.smpl → method_templates/need_assignment_template.rb.smpl} +0 -0
  25. data/lib/fortitude/{need_method_template.rb.smpl → method_templates/need_method_template.rb.smpl} +0 -0
  26. data/lib/fortitude/method_templates/simple_template.rb +50 -0
  27. data/lib/fortitude/{tag_method_template.rb.smpl → method_templates/tag_method_template.rb.smpl} +0 -0
  28. data/lib/fortitude/{text_method_template.rb.smpl → method_templates/text_method_template.rb.smpl} +0 -0
  29. data/lib/fortitude/rails.rb +26 -0
  30. data/lib/fortitude/rails/railtie.rb +256 -0
  31. data/lib/fortitude/rails/widget_methods.rb +0 -4
  32. data/lib/fortitude/rendering_context.rb +2 -2
  33. data/lib/fortitude/support/assigns_proxy.rb +77 -0
  34. data/lib/fortitude/support/class_inheritable_attributes.rb +98 -0
  35. data/lib/fortitude/support/instance_variable_set.rb +76 -0
  36. data/lib/fortitude/support/staticized_method.rb +87 -0
  37. data/lib/fortitude/tags/partial_tag_placeholder.rb +19 -0
  38. data/lib/fortitude/tags/tag.rb +189 -0
  39. data/lib/fortitude/tags/tag_return_value.rb +13 -0
  40. data/lib/fortitude/tags/tag_store.rb +53 -0
  41. data/lib/fortitude/tags/tag_support.rb +51 -0
  42. data/lib/fortitude/tags/tags_module.rb +16 -0
  43. data/lib/fortitude/tilt.rb +17 -0
  44. data/lib/fortitude/tilt/fortitude_template.rb +13 -13
  45. data/lib/fortitude/version.rb +1 -1
  46. data/lib/fortitude/widget.rb +36 -886
  47. data/lib/fortitude/widget/around_content.rb +53 -0
  48. data/lib/fortitude/widget/capturing.rb +37 -0
  49. data/lib/fortitude/widget/content.rb +51 -0
  50. data/lib/fortitude/widget/doctypes.rb +53 -0
  51. data/lib/fortitude/widget/helpers.rb +62 -0
  52. data/lib/fortitude/widget/integration.rb +76 -0
  53. data/lib/fortitude/widget/localization.rb +63 -0
  54. data/lib/fortitude/widget/modules_and_subclasses.rb +58 -0
  55. data/lib/fortitude/widget/needs.rb +164 -0
  56. data/lib/fortitude/widget/non_rails_widget_methods.rb +13 -0
  57. data/lib/fortitude/widget/rendering.rb +93 -0
  58. data/lib/fortitude/widget/start_and_end_comments.rb +69 -0
  59. data/lib/fortitude/widget/staticization.rb +50 -0
  60. data/lib/fortitude/widget/tag_like_methods.rb +102 -0
  61. data/lib/fortitude/widget/tags.rb +55 -0
  62. data/lib/fortitude/widget/temporary_overrides.rb +28 -0
  63. data/lib/fortitude/widget/widget_class_inheritable_attributes.rb +35 -0
  64. data/lib/fortitude/widgets.rb +12 -0
  65. data/lib/fortitude_jruby_native_ext.jar +0 -0
  66. data/spec/helpers/system_helpers.rb +3 -3
  67. data/spec/system/attribute_rules_system_spec.rb +9 -9
  68. data/spec/system/doctypes_system_spec.rb +15 -0
  69. data/spec/system/escaping_system_spec.rb +2 -2
  70. data/spec/system/formatting_system_spec.rb +2 -2
  71. data/spec/system/id_uniqueness_system_spec.rb +5 -5
  72. data/spec/system/method_precedence_system_spec.rb +1 -1
  73. data/spec/system/needs_system_spec.rb +13 -0
  74. data/spec/system/setting_inheritance_system_spec.rb +20 -20
  75. data/spec/system/tag_rendering_system_spec.rb +27 -20
  76. data/spec/system/tag_rules_system_spec.rb +1 -1
  77. data/spec/system/tag_updating_system_spec.rb +3 -3
  78. data/spec/system/tilt_system_spec.rb +4 -0
  79. data/spec/system/void_tags_system_spec.rb +44 -5
  80. metadata +42 -21
  81. data/lib/fortitude/assigns_proxy.rb +0 -75
  82. data/lib/fortitude/class_inheritable_attributes.rb +0 -96
  83. data/lib/fortitude/instance_variable_set.rb +0 -74
  84. data/lib/fortitude/non_rails_widget_methods.rb +0 -15
  85. data/lib/fortitude/partial_tag_placeholder.rb +0 -17
  86. data/lib/fortitude/railtie.rb +0 -254
  87. data/lib/fortitude/simple_template.rb +0 -45
  88. data/lib/fortitude/staticized_method.rb +0 -85
  89. data/lib/fortitude/tag.rb +0 -162
  90. data/lib/fortitude/tag_return_value.rb +0 -11
  91. data/lib/fortitude/tag_store.rb +0 -48
  92. data/lib/fortitude/tag_support.rb +0 -48
  93. data/lib/fortitude/tags_module.rb +0 -14
@@ -0,0 +1,50 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/hash'
3
+
4
+ module Fortitude
5
+ module MethodTemplates
6
+ class SimpleTemplate
7
+ class << self
8
+ def template(name)
9
+ @templates ||= { }
10
+ @templates[name] ||= new(File.join(File.dirname(__FILE__), "#{name}.rb.smpl"))
11
+ end
12
+ end
13
+
14
+ def initialize(source_file)
15
+ @lines = File.read(source_file).split(/\r\n|\r|\n/)
16
+ end
17
+
18
+ def result(bindings)
19
+ bindings = bindings.stringify_keys
20
+ bindings_target = Object.new
21
+ bindings.each do |key, value|
22
+ (class << bindings_target; self; end).send(:define_method, key) { value }
23
+ end
24
+
25
+ result_lines = [ ]
26
+ @lines.each do |l|
27
+ if l =~ /^(.*)\#\s*\:if\s*(.*?)\s*$/i
28
+ l, condition = $1, $2
29
+ next unless bindings_target.instance_eval(condition)
30
+ end
31
+
32
+ while l =~ /[^\\]\#\{([^}]+)\}/ || l =~ /^\#\{([^}]+)\}/
33
+ name = $1
34
+ begin
35
+ value = bindings_target.send($1)
36
+ rescue => e
37
+ raise "Failed when processing #{l.inspect}: #{e.inspect}"
38
+ end
39
+ l = l.gsub("\#\{#{$1}\}", value.to_s)
40
+ end
41
+ l = l.gsub(/\\\#\{/, "\#\{")
42
+
43
+ result_lines << l
44
+ end
45
+
46
+ result_lines.join("\n")
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ # See if we can load Rails -- but don't fail if we can't; we'll just use this to decide whether we should
2
+ # load the Railtie or not.
3
+ begin
4
+ gem 'rails'
5
+ rescue Gem::LoadError => le
6
+ # ok
7
+ end
8
+
9
+ begin
10
+ require 'rails'
11
+ rescue LoadError => le
12
+ # ok
13
+ end
14
+
15
+ if defined?(::Rails)
16
+ require 'action_view'
17
+
18
+ require 'fortitude/rails/widget_methods'
19
+ require 'fortitude/rails/renderer'
20
+ require 'fortitude/rails/template_handler'
21
+ require 'fortitude/rails/railtie'
22
+ else
23
+ ::String.class_eval do
24
+ alias_method :original_concat, :concat
25
+ end
26
+ end
@@ -0,0 +1,256 @@
1
+ require 'fortitude/rendering_context'
2
+
3
+ if defined?(ActiveSupport)
4
+ ActiveSupport.on_load(:before_initialize) do
5
+ ActiveSupport.on_load(:action_view) do
6
+ require "fortitude/rails/template_handler"
7
+ end
8
+ end
9
+ end
10
+
11
+ module Fortitude
12
+ class << self
13
+ def refine_rails_helpers(on_or_off = :not_specified)
14
+ @refine_rails_helpers = !! on_or_off unless on_or_off == :not_specified
15
+ !! @refine_rails_helpers
16
+ end
17
+ end
18
+
19
+ refine_rails_helpers true
20
+ end
21
+
22
+ module Fortitude
23
+ module Rails
24
+ class Railtie < ::Rails::Railtie
25
+ config.after_initialize do
26
+ if Fortitude.refine_rails_helpers
27
+ require 'fortitude/rails/helpers'
28
+ Fortitude::Rails::Helpers.apply_refined_helpers_to!(Fortitude::Widget)
29
+ end
30
+
31
+ if ::Rails.env.development?
32
+ ::Fortitude::Widget.class_eval do
33
+ format_output true
34
+ start_and_end_comments true
35
+ debug true
36
+ end
37
+ end
38
+ end
39
+
40
+ initializer :fortitude, :before => :set_autoload_paths do |app|
41
+ # All of this code is involved in setting up autoload_paths to work with Fortitude.
42
+ # Why so hard?
43
+ #
44
+ # We're trying to do something that ActiveSupport::Dependencies -- which is what Rails uses for
45
+ # class autoloading -- doesn't really support. We want app/views to be on the autoload path,
46
+ # because there are now Ruby classes living there. (It usually isn't just because all that's there
47
+ # are template source files, not actual Ruby code.) That isn't an issue, though -- adding it
48
+ # is trivial (just do
49
+ # <tt>ActiveSupport::Dependencies.autoload_paths << File.join(Rails.root, 'app/views')</tt>).
50
+ #
51
+ # The real issue is that we want the class <tt>app/views/foo/bar.rb</tt> to define a class called
52
+ # <tt>Views::Foo::Bar</tt>, not just plain <tt>Foo::Bar</tt>. This is what's different from what
53
+ # ActiveSupport::Dependencies normally supports; it expects the filesystem path underneath the
54
+ # root to be exactly identical to the fully-qualified class name.
55
+ #
56
+ # Why are we doing this crazy thing? Because we want you to be able to have a view called
57
+ # <tt>app/views/user/password.rb</tt>, and _not_ have that conflict with a module you just happen to define
58
+ # elsewhere called <tt>User::Password</tt>. If we don't prefix view classes with anything at all, then the
59
+ # potential for conflicts is enormous.
60
+ #
61
+ # As such, we have this code. We'll walk through it step-by-step; note that at the end we *do*
62
+ # add app/views/ to the autoload path, so all this code is doing is just dealing with the fact that
63
+ # the fully-qualified classname (<tt>Views::Foo::Bar</tt>) has one extra component on the front of it
64
+ # (<tt>Views::</tt>) when compared to the subpath (<tt>foo/bar.rb</tt>) underneath what's on the autoload
65
+ # path (<tt>app/views</tt>).
66
+
67
+ # Go compute our views root.
68
+ views_root = File.expand_path(File.join(::Rails.root, 'app', 'views'))
69
+
70
+ # Now, do all this work inside ::ActiveSupport::Dependencies...
71
+ ::ActiveSupport::Dependencies.module_eval do
72
+ @@_fortitude_views_root = views_root
73
+
74
+ # This is the method that gets called to auto-generate namespacing empty
75
+ # modules (_e.g._, the toplevel <tt>Views::</tt> module) for directories
76
+ # under an autoload path.
77
+ #
78
+ # The original method says:
79
+ #
80
+ # "Does the provided path_suffix correspond to an autoloadable module?
81
+ # Instead of returning a boolean, the autoload base for this module is
82
+ # returned."
83
+ #
84
+ # So, we just need to strip off the leading +views/+ from the +path_suffix+,
85
+ # and see if that maps to a directory underneath <tt>app/views/</tt>; if so,
86
+ # we'll return the path to <tt>.../app/views/</tt>. Otherwise, we just
87
+ # delegate back to the superclass method.
88
+ def autoloadable_module_with_fortitude?(path_suffix)
89
+ if path_suffix =~ %r{^views(/.*)?$}i
90
+ # If we got here, then we were passed a subpath of views/....
91
+ subpath = $1
92
+
93
+ if subpath.blank? || File.directory?(File.join(@@_fortitude_views_root, subpath))
94
+ return @@_fortitude_views_root
95
+ end
96
+ end
97
+
98
+ with_fortitude_views_removed_from_autoload_path do
99
+ autoloadable_module_without_fortitude?(path_suffix)
100
+ end
101
+ end
102
+
103
+ alias_method_chain :autoloadable_module?, :fortitude
104
+
105
+ # When we delegate back to original methods, we want them to act as if
106
+ # <tt>app/views/</tt> is _not_ on the autoload path. In order to be thread-safe
107
+ # about that, we couple this method with our override of the writer side of the
108
+ # <tt>mattr_accessor :autoload_paths</tt>, which simply prefers the thread-local
109
+ # that we set to the actual underlying variable.
110
+ def with_fortitude_views_removed_from_autoload_path
111
+ begin
112
+ Thread.current[:_fortitude_autoload_paths_override] = autoload_paths - [ @@_fortitude_views_root ]
113
+ yield
114
+ ensure
115
+ Thread.current[:_fortitude_autoload_paths_override] = nil
116
+ end
117
+ end
118
+
119
+ # The use of 'class_eval' here may seem funny, and I think it is, but, without it,
120
+ # the +@@autoload_paths+ gets interpreted as a class variable for this *Railtie*,
121
+ # rather than for ::ActiveSupport::Dependencies. (Why is that? Got me...)
122
+ class_eval <<-EOS
123
+ def self.autoload_paths
124
+ Thread.current[:_fortitude_autoload_paths_override] || @@autoload_paths
125
+ end
126
+ EOS
127
+
128
+ # The original method says:
129
+ #
130
+ # "Search for a file in autoload_paths matching the provided suffix."
131
+ #
132
+ # So, we just look to see if the given +path_suffix+ is specifying something like
133
+ # <tt>views/foo/bar</tt>; if so, we glue it together properly, removing the initial
134
+ # <tt>views/</tt> first. (Otherwise, the mechanism would expect
135
+ # <tt>Views::Foo::Bar</tt> to show up in <tt>app/views/views/foo/bar</tt> (yes, a double
136
+ # +views+), since <tt>app/views</tt> is on the autoload path.)
137
+ def search_for_file_with_fortitude(path_suffix)
138
+ # This just makes sure our path always ends in exactly one ".rb", whether it started
139
+ # with one or not.
140
+ new_path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb")
141
+
142
+ if new_path_suffix =~ %r{^views(/.*)$}i
143
+ path = File.join(@@_fortitude_views_root, $1)
144
+ return path if File.file?(path)
145
+ end
146
+
147
+ # Make sure that we remove the views autoload path before letting the rest of
148
+ # the dependency mechanism go searching for files, or else <tt>app/views/foo/bar.rb</tt>
149
+ # *will* be found when looking for just <tt>::Foo::Bar</tt>.
150
+ with_fortitude_views_removed_from_autoload_path { search_for_file_without_fortitude(path_suffix) }
151
+ end
152
+
153
+ alias_method_chain :search_for_file, :fortitude
154
+ end
155
+
156
+ # And, finally, this is where we add our root to the set of autoload paths.
157
+ ::ActiveSupport::Dependencies.autoload_paths << views_root
158
+
159
+ # This is our support for partials. Fortitude doesn't really have a distinction between
160
+ # partials and "full" templates -- everything is just a widget, which is much more elegant --
161
+ # but we still want you to be able to render a widget <tt>Views::Foo::Bar</tt> by saying
162
+ # <tt>render :partial => 'foo/bar'</tt> (from ERb, although you can do it from Fortitude if
163
+ # you want for some reason, too).
164
+ #
165
+ # Normally, ActionView only looks for partials in files starting with an underscore. We
166
+ # do want to allow this, too (in the above case, if you define the widget in the file
167
+ # <tt>app/views/foo/_bar.rb</tt>, it will still work fine); however, we also want to allow
168
+ # you to define it in a file that does _not_ start with an underscore ('cause these are
169
+ # Ruby classes, and that's just plain weird).
170
+ #
171
+ # So, we patch #find_templates: if it's looking for a partial, doesn't find one, and is
172
+ # searching Fortitude templates (the +.rb+ handler), then we try again, turning off the
173
+ # +partial+ flag, and return that instead.
174
+ ::ActionView::PathResolver.class_eval do
175
+ def find_templates_with_fortitude(name, prefix, partial, details)
176
+ templates = find_templates_without_fortitude(name, prefix, partial, details)
177
+ if partial && templates.empty? && details[:handlers] && details[:handlers].include?(:rb)
178
+ templates = find_templates_without_fortitude(name, prefix, false, details.merge(:handlers => [ :rb ]))
179
+ end
180
+ templates
181
+ end
182
+
183
+ alias_method_chain :find_templates, :fortitude
184
+ end
185
+
186
+ require "fortitude/rails/template_handler"
187
+
188
+ # This is our support for render :widget. Although, originally, it looked like creating a new subclass
189
+ # of ActionView::Template was going to be the correct thing to do here, it turns out it isn't: the entire
190
+ # template system is predicated around the idea that you have a template, which is compiled to output
191
+ # Ruby source code, and then that gets evaluated to actually generate output.
192
+ #
193
+ # Because <tt>render :widget => ...</tt> takes an already-instantiated widget as input, this simply isn't
194
+ # possible: you can't reverse-engineer an arbitrary Ruby object into source code, and, without source code,
195
+ # the whole templating paradigm doesn't make sense.
196
+ #
197
+ # So, instead, we simply transform <tt>render :widget => ...</tt> into a <tt>render :text => ...</tt> of the
198
+ # widget's output, and let Rails take it away from there.
199
+ ::ActionController::Base.class_eval do
200
+ def fortitude_rendering_context(options)
201
+ @_fortitude_rendering_context ||= create_fortitude_rendering_context(options)
202
+ end
203
+
204
+ def create_fortitude_rendering_context(options)
205
+ ::Fortitude::RenderingContext.new(options)
206
+ end
207
+
208
+ def render_with_fortitude(*args, &block)
209
+ if (options = args[0]).kind_of?(Hash)
210
+ if (widget = options[:widget])
211
+ rendering_context = fortitude_rendering_context(:delegate_object => self)
212
+ widget.to_html(rendering_context)
213
+
214
+ options = options.dup
215
+ options[:text] = rendering_context.output_buffer_holder.output_buffer.html_safe
216
+ options[:layout] = true unless options.has_key?(:layout)
217
+
218
+ new_args = [ options ] + args[1..-1]
219
+ return render_without_fortitude(*new_args, &block)
220
+ elsif (widget_block = options[:inline]) && (options[:type] == :fortitude)
221
+ options.delete(:inline)
222
+
223
+ rendering_context = fortitude_rendering_context(:delegate_object => self)
224
+ widget_class = Class.new(Fortitude::Widgets::Html5)
225
+ widget_class.use_instance_variables_for_assigns(true)
226
+ widget_class.extra_assigns(:use)
227
+ widget_class.send(:define_method, :content, &widget_block)
228
+
229
+ assigns = { }
230
+ instance_variables.each do |ivar_name|
231
+ value = instance_variable_get(ivar_name)
232
+ assigns[$1.to_sym] = value if ivar_name =~ /^@(.*)$/
233
+ end
234
+ assigns = assigns.merge(options[:locals] || { })
235
+
236
+ widget = widget_class.new(assigns)
237
+ widget.to_html(rendering_context)
238
+
239
+ options = options.dup
240
+ options[:text] = rendering_context.output_buffer_holder.output_buffer.html_safe
241
+ options[:layout] = true unless options.has_key?(:layout)
242
+
243
+ new_args = [ options ] + args[1..-1]
244
+ return render_without_fortitude(*new_args, &block)
245
+ end
246
+ end
247
+
248
+ return render_without_fortitude(*args, &block)
249
+ end
250
+
251
+ alias_method_chain :render, :fortitude
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
@@ -8,10 +8,6 @@ module Fortitude
8
8
  def widget_locale
9
9
  I18n.locale || I18n.default_locale
10
10
  end
11
-
12
- module ClassMethods
13
-
14
- end
15
11
  end
16
12
  end
17
13
  end
@@ -1,4 +1,4 @@
1
- require 'fortitude/instance_variable_set'
1
+ require 'fortitude/support/instance_variable_set'
2
2
 
3
3
  module Fortitude
4
4
  class RenderingContext
@@ -16,7 +16,7 @@ module Fortitude
16
16
  @helpers_object = options[:helpers_object] || options[:delegate_object] || Object.new
17
17
 
18
18
  instance_variables_object = options[:instance_variables_object] || options[:delegate_object] || Object.new
19
- @instance_variable_set = Fortitude::InstanceVariableSet.new(instance_variables_object)
19
+ @instance_variable_set = Fortitude::Support::InstanceVariableSet.new(instance_variables_object)
20
20
 
21
21
  @render_yield_result = true unless options.has_key?(:render_yield_result) && (! options[:render_yield_result])
22
22
 
@@ -0,0 +1,77 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module Fortitude
4
+ module Support
5
+ class AssignsProxy
6
+ def initialize(widget, keys)
7
+ @widget = widget
8
+ @keys = { }
9
+ keys.each { |k| @keys[k] = true }
10
+ end
11
+
12
+ def is_default?(x)
13
+ !! @widget._fortitude_default_assigns[x.to_sym]
14
+ end
15
+
16
+ def keys
17
+ @keys.keys
18
+ end
19
+
20
+ def has_key?(x)
21
+ !! @keys[x.to_sym]
22
+ end
23
+
24
+ def [](x)
25
+ if has_key?(x)
26
+ ivar_name = @widget.class.instance_variable_name_for_need(x)
27
+ @widget.instance_variable_get(ivar_name)
28
+ end
29
+ end
30
+
31
+ def []=(x, y)
32
+ if has_key?(x)
33
+ ivar_name = @widget.class.instance_variable_name_for_need(x)
34
+ @widget.instance_variable_set(ivar_name, y)
35
+ end
36
+ end
37
+
38
+ def to_hash
39
+ out = { }
40
+ keys.each { |k| out[k] = self[k] }
41
+ out
42
+ end
43
+
44
+ def to_h
45
+ to_hash
46
+ end
47
+
48
+ def length
49
+ @keys.length
50
+ end
51
+
52
+ def size
53
+ @keys.size
54
+ end
55
+
56
+ def to_s
57
+ "<Assigns for #{@widget}: #{to_hash}>"
58
+ end
59
+
60
+ def inspect
61
+ "<Assigns for #{@widget}: #{to_hash.inspect}>"
62
+ end
63
+
64
+ def member?(x)
65
+ has_key?(x)
66
+ end
67
+
68
+ def store(key, value)
69
+ self[key] = value
70
+ end
71
+
72
+ delegate :==, :assoc, :each, :each_pair, :each_key, :each_value, :empty?, :eql?, :fetch, :flatten,
73
+ :has_value?, :hash, :include?, :invert, :key, :key?, :merge, :rassoc, :reject, :select,
74
+ :to_a, :value?, :values, :values_at, :to => :to_hash
75
+ end
76
+ end
77
+ end