ray 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. data/README.md +9 -6
  2. data/Rakefile +1 -5
  3. data/ext/audio.c +25 -19
  4. data/ext/audio_source.c +67 -39
  5. data/ext/color.c +19 -19
  6. data/ext/drawable.c +190 -31
  7. data/ext/extconf.rb +16 -14
  8. data/ext/gl.c +310 -30
  9. data/ext/gl_buffer.c +223 -2
  10. data/ext/gl_index_buffer.c +11 -0
  11. data/ext/gl_int_array.c +24 -22
  12. data/ext/gl_vertex.c +84 -49
  13. data/ext/image.c +115 -51
  14. data/ext/image_target.c +58 -10
  15. data/ext/input.c +73 -6
  16. data/ext/mo.c +583 -0
  17. data/ext/mo.h +189 -0
  18. data/ext/music.c +9 -8
  19. data/ext/pixel_bus.c +349 -0
  20. data/ext/polygon.c +68 -45
  21. data/ext/ray.c +1 -0
  22. data/ext/ray.h +19 -1
  23. data/ext/rect.c +9 -47
  24. data/ext/say.h +1 -2
  25. data/ext/say_all.h +6 -0
  26. data/ext/say_audio.h +3 -0
  27. data/ext/say_audio_context.c +1 -4
  28. data/ext/say_basic_type.c +24 -0
  29. data/ext/say_basic_type.h +4 -0
  30. data/ext/say_buffer.c +217 -88
  31. data/ext/say_buffer.h +20 -5
  32. data/ext/say_buffer_renderer.c +10 -7
  33. data/ext/say_buffer_renderer.h +1 -1
  34. data/ext/say_buffer_slice.c +70 -76
  35. data/ext/say_context.c +109 -22
  36. data/ext/say_context.h +14 -0
  37. data/ext/say_drawable.c +113 -25
  38. data/ext/say_drawable.h +23 -2
  39. data/ext/say_error.c +7 -2
  40. data/ext/say_font.c +30 -27
  41. data/ext/say_font.h +3 -6
  42. data/ext/say_get_proc.c +35 -0
  43. data/ext/say_image.c +102 -27
  44. data/ext/say_image.h +11 -4
  45. data/ext/say_image_target.c +88 -34
  46. data/ext/say_image_target.h +3 -2
  47. data/ext/say_index_buffer.c +31 -19
  48. data/ext/say_index_buffer.h +4 -2
  49. data/ext/say_index_buffer_slice.c +78 -70
  50. data/ext/say_music.c +4 -2
  51. data/ext/say_osx.h +3 -2
  52. data/ext/say_osx_context.h +37 -4
  53. data/ext/say_osx_window.h +32 -37
  54. data/ext/say_pixel_bus.c +163 -0
  55. data/ext/say_pixel_bus.h +44 -0
  56. data/ext/say_polygon.c +2 -2
  57. data/ext/say_shader.c +66 -62
  58. data/ext/say_shader.h +2 -0
  59. data/ext/say_sprite.c +1 -2
  60. data/ext/say_target.c +14 -23
  61. data/ext/say_target.h +3 -1
  62. data/ext/say_text.c +45 -7
  63. data/ext/say_text.h +12 -3
  64. data/ext/say_thread.c +13 -6
  65. data/ext/say_thread.h +1 -1
  66. data/ext/say_thread_variable.c +5 -5
  67. data/ext/say_vertex_type.c +79 -41
  68. data/ext/say_vertex_type.h +6 -2
  69. data/ext/say_view.c +10 -31
  70. data/ext/say_view.h +1 -5
  71. data/ext/say_win.h +2 -2
  72. data/ext/say_win_context.h +49 -11
  73. data/ext/say_win_window.h +30 -27
  74. data/ext/say_window.c +3 -3
  75. data/ext/say_x11.h +3 -1
  76. data/ext/say_x11_context.h +64 -10
  77. data/ext/say_x11_window.h +22 -17
  78. data/ext/shader.c +9 -0
  79. data/ext/sprite.c +7 -1
  80. data/ext/target.c +80 -28
  81. data/ext/text.c +43 -1
  82. data/ext/view.c +53 -1
  83. data/ext/window.c +4 -0
  84. data/lib/ray/animation_list.rb +17 -2
  85. data/lib/ray/audio_source.rb +11 -0
  86. data/lib/ray/color.rb +14 -0
  87. data/lib/ray/drawable.rb +23 -0
  88. data/lib/ray/dsl/event.rb +1 -9
  89. data/lib/ray/dsl/event_runner.rb +3 -4
  90. data/lib/ray/dsl/matcher.rb +20 -1
  91. data/lib/ray/effect.rb +116 -0
  92. data/lib/ray/effect/black_and_white.rb +38 -0
  93. data/lib/ray/effect/color_inversion.rb +16 -0
  94. data/lib/ray/effect/generator.rb +145 -0
  95. data/lib/ray/effect/grayscale.rb +32 -0
  96. data/lib/ray/game.rb +25 -5
  97. data/lib/ray/gl/vertex.rb +105 -26
  98. data/lib/ray/helper.rb +5 -0
  99. data/lib/ray/image.rb +54 -13
  100. data/lib/ray/image_target.rb +7 -0
  101. data/lib/ray/matrix.rb +26 -0
  102. data/lib/ray/music.rb +4 -0
  103. data/lib/ray/pixel_bus.rb +22 -0
  104. data/lib/ray/polygon.rb +17 -0
  105. data/lib/ray/pp.rb +28 -0
  106. data/lib/ray/ray.rb +7 -1
  107. data/lib/ray/rect.rb +7 -13
  108. data/lib/ray/scene.rb +24 -5
  109. data/lib/ray/scene_list.rb +9 -0
  110. data/lib/ray/shader.rb +11 -2
  111. data/lib/ray/sound.rb +4 -0
  112. data/lib/ray/sprite.rb +23 -62
  113. data/lib/ray/target.rb +25 -0
  114. data/lib/ray/text.rb +10 -0
  115. data/lib/ray/turtle.rb +9 -3
  116. data/lib/ray/vector.rb +18 -0
  117. data/lib/ray/vertex.rb +6 -0
  118. data/lib/ray/view.rb +22 -0
  119. data/samples/animation/sprite_motion.rb +0 -60
  120. data/samples/audio/{spacial.rb → spatial.rb} +1 -1
  121. data/samples/buffer/buffer.rb +1 -0
  122. data/samples/buffer/index_buffer.rb +2 -0
  123. data/samples/cptn_ruby/cptn_ruby.rb +6 -7
  124. data/samples/effects/effect.rb +39 -0
  125. data/samples/effects/grayscale.rb +27 -0
  126. data/samples/opengl/image.rb +7 -5
  127. data/samples/opengl/instancing.rb +159 -0
  128. data/samples/opengl/instancing.rbc +3231 -0
  129. data/samples/opengl/obj_loader.rb +9 -8
  130. data/samples/opengl/shader.rb +1 -3
  131. data/samples/shaders/geometry.rb +108 -38
  132. data/samples/shaders/geometry.rbc +2074 -0
  133. data/samples/shaders/shape.rb +2 -2
  134. data/samples/starfighter/starfighter.rb +5 -5
  135. data/samples/window/get_pixel.rb +1 -1
  136. data/test/animation_list_test.rb +18 -4
  137. data/test/drawable_test.rb +70 -1
  138. data/test/effect_generator_test.rb +63 -0
  139. data/test/effect_test.rb +61 -0
  140. data/test/game_test.rb +18 -0
  141. data/test/gl_buffer_test.rb +43 -1
  142. data/test/gl_index_buffer_test.rb +5 -0
  143. data/test/gl_vertex_test.rb +28 -1
  144. data/test/image_test.rb +5 -5
  145. data/test/input_test.rb +49 -0
  146. data/test/pixel_bus_test.rb +28 -0
  147. data/test/rect_test.rb +4 -0
  148. data/{samples/_media → test/res}/Beep.wav +0 -0
  149. data/samples/_media/CptnRuby Gem.png b/data/test/res/CptnRuby → Gem.png +0 -0
  150. data/samples/_media/CptnRuby Map.txt b/data/test/res/CptnRuby → Map.txt +0 -0
  151. data/samples/_media/CptnRuby Tileset.png b/data/test/res/CptnRuby → Tileset.png +0 -0
  152. data/{samples/_media → test/res}/CptnRuby.png +0 -0
  153. data/{samples/_media → test/res}/Space.png +0 -0
  154. data/{samples/_media → test/res}/Star.png +0 -0
  155. data/{samples/_media → test/res}/Starfighter.png +0 -0
  156. data/test/res/cube.obj +28 -0
  157. data/test/res/light3d.c +2 -2
  158. data/test/res/stone.png +0 -0
  159. data/test/scene_test.rb +3 -0
  160. data/test/sprite_test.rb +10 -0
  161. data/test/text_test.rb +31 -2
  162. data/test/view_test.rb +13 -1
  163. metadata +38 -17
  164. data/ext/say_array.c +0 -124
  165. data/ext/say_array.h +0 -34
  166. data/ext/say_table.c +0 -86
  167. data/ext/say_table.h +0 -24
@@ -143,6 +143,11 @@ module Ray
143
143
  Ray::Text.new(content, opts)
144
144
  end
145
145
 
146
+ # (see Ray::Effect::Generator#initialize)
147
+ def effect_generator(version = 110, &block)
148
+ Ray::Effect::Generator.new(version, &block)
149
+ end
150
+
146
151
  # @param [Symbol, Key, Integer] val A symbol to find the key (its name),
147
152
  # a Key object, or one of the KEY_* constant.
148
153
  # @return [true, false] True if the user is holding key.
@@ -1,19 +1,20 @@
1
1
  module Ray
2
2
  class Image
3
3
  include Enumerable
4
-
5
- def inspect
6
- "#<#{self.class} size=#{size}>"
7
- end
8
-
9
- alias :w :width
10
- alias :h :height
4
+ include Ray::PP
11
5
 
12
6
  extend Ray::ResourceSet
13
7
  add_set(/^(.*)$/) { |filename| new(filename) }
14
8
 
9
+ # @group Iterating over an image
10
+
11
+ # Iterates over all the pixels of an image
12
+ #
13
+ # Iteration is done over each pixel from a line from left to right,
14
+ # and each line from top to bottom.
15
+ #
15
16
  # @yield [pixel]
16
- # @yieldparam [Ray::Color] pixel Color of a point
17
+ # @yieldparam [Ray::Color] pixel Color of the pixel
17
18
  def each
18
19
  return Enumerator.new(self, :each) unless block_given?
19
20
 
@@ -26,8 +27,12 @@ module Ray
26
27
  self
27
28
  end
28
29
 
29
- # Same as each, but also yields the position of each point.
30
+ # Yields all the pixels and their positions
31
+ #
30
32
  # @yield [pixel, x, y]
33
+ # @yieldparam [Ray::Color] pixel Color of the pixel
34
+ # @yieldparam [Integer] x X position of the pixel
35
+ # @yieldparam [Integer] y Y position of the pixel
31
36
  def each_with_pos
32
37
  return Enumerator.new(self, :each_with_pos) unless block_given?
33
38
 
@@ -40,7 +45,12 @@ module Ray
40
45
  self
41
46
  end
42
47
 
43
- # @yield [pixel] Block returning the new color of this pixel.
48
+ # Modifies each pixel of the image in-place
49
+ #
50
+ # @yield [pixel]
51
+ # @yieldparam (see #each)
52
+ #
53
+ # @yieldreturn [Ray::Color] New color of the pixel
44
54
  def map!
45
55
  return Enumerator.new(self, :map!) unless block_given?
46
56
 
@@ -53,7 +63,13 @@ module Ray
53
63
  self
54
64
  end
55
65
 
56
- # @yield [pixel, x, y] Block returning the new color of this pixel
66
+ # Modifies each pixel of the image in-place, passing their position to the
67
+ # block
68
+ #
69
+ # @yield [pixel, x, y]
70
+ # @yieldparam (see #each_with_pos)
71
+ #
72
+ # @yieldreturn (see #mapV)
57
73
  def map_with_pos!
58
74
  return Enumerator.new(self, :map_with_pos!) unless block_given?
59
75
 
@@ -66,14 +82,39 @@ module Ray
66
82
  self
67
83
  end
68
84
 
69
- # @return [Ray::Image] New image created according to a block.
85
+ # Creates a new image using a block
86
+ #
87
+ # @yield [pixel]
88
+ # @yieldparam (see #map!)
89
+ # @yieldreturn (see #map!)
90
+ #
91
+ # @return [Ray::Image] New image created according to a block
70
92
  def map(&block)
71
93
  dup.map!(&block)
72
94
  end
73
95
 
74
- # @return [Ray::Image] New image created according to a block.
96
+ # Creates a new image using a block, passing the position of each point
97
+ # to it
98
+ #
99
+ # @yield [pixel, x, y]
100
+ # @yieldparam (see #map_with_pos!)
101
+ #
102
+ # @return (see #map)
75
103
  def map_with_pos(&block)
76
104
  dup.map_with_pos!(&block)
77
105
  end
106
+
107
+ # @endgroup
108
+
109
+ def inspect
110
+ "#<#{self.class} size=#{size}>"
111
+ end
112
+
113
+ def pretty_print(q)
114
+ pretty_print_attributes q, ["size", "smooth?"]
115
+ end
116
+
117
+ alias w width
118
+ alias h height
78
119
  end
79
120
  end
@@ -1,5 +1,8 @@
1
1
  module Ray
2
2
  class ImageTarget < Target
3
+ # @yield [target] Yields itself if a block is given
4
+ # @yieldparam [Ray::ImageTarget] target The new target
5
+ #
3
6
  # @param [Ray::Image, nil] image The image to use
4
7
  def initialize(image = nil)
5
8
  self.image = image if image
@@ -8,5 +11,9 @@ module Ray
8
11
  yield self
9
12
  end
10
13
  end
14
+
15
+ def pretty_print(q)
16
+ super q, ["image"]
17
+ end
11
18
  end
12
19
  end
@@ -86,5 +86,31 @@ module Ray
86
86
  def to_s
87
87
  "#<#{self.class} #{content.join(', ')}>"
88
88
  end
89
+
90
+ def pretty_print(q)
91
+ content = self.content.map { |n| ("%g" % n).to_f }
92
+
93
+ columns = Array.new(4) do |x|
94
+ Array.new(4) { |y| ("%g" % self[x, y]).to_f }
95
+ end
96
+
97
+ column_length = columns.map { |c| c.map { |n| n.to_s.length }.max }
98
+
99
+ q.group(2, '{', '}') do
100
+ q.breakable ''
101
+ content.each_slice(4).with_index do |(x, y, z, w), i|
102
+ q.text '('
103
+ q.pp x
104
+ q.text ', ' + ' ' * (column_length[0] - x.to_s.length)
105
+ q.pp y
106
+ q.text ', ' + ' ' * (column_length[1] - y.to_s.length)
107
+ q.pp z
108
+ q.text ', ' + ' ' * (column_length[2] - z.to_s.length)
109
+ q.pp w
110
+ q.text ')'
111
+ q.breakable '' unless i == 3
112
+ end
113
+ end
114
+ end
89
115
  end
90
116
  end
@@ -4,6 +4,10 @@ module Ray
4
4
  open(filename) if filename
5
5
  end
6
6
 
7
+ def pretty_print(q)
8
+ super q, ["time", "duration", "looping?"]
9
+ end
10
+
7
11
  alias time= seek
8
12
 
9
13
  alias position pos
@@ -0,0 +1,22 @@
1
+ module Ray
2
+ class PixelBus
3
+ # @group Copying data
4
+
5
+ # Duplicates an image through this bus
6
+ #
7
+ # @param [Ray::Image] image Image to be copied
8
+ # @param [Integer] offset Offset to write the pixels to
9
+ #
10
+ # @return [Ray::Image] Copied image
11
+ def copy(image, offset = 0)
12
+ copy = Ray::Image.new image.size
13
+
14
+ pull image, :offset => offset
15
+ push copy, :offset => offset
16
+
17
+ copy
18
+ end
19
+
20
+ # @endgroup
21
+ end
22
+ end
@@ -4,6 +4,8 @@ module Ray
4
4
 
5
5
  # One of the points contained in a polygon.
6
6
  class Point
7
+ include Ray::PP
8
+
7
9
  def initialize(polygon, id)
8
10
  @polygon, @id = polygon, id
9
11
  end
@@ -43,6 +45,10 @@ module Ray
43
45
  outline=#{outline}>"
44
46
  end
45
47
 
48
+ def pretty_print(q)
49
+ pretty_print_attributes q, ["pos", "color", "outline"]
50
+ end
51
+
46
52
  attr_reader :polygon, :id
47
53
  end
48
54
 
@@ -68,10 +74,21 @@ outline=#{outline}>"
68
74
  0.upto(size - 1) { |n| yield self[n] }
69
75
  end
70
76
 
77
+ alias points to_a
78
+
71
79
  # @return [Ray::Polygon::Point] idth point of the polygon (id should be less
72
80
  # than size)
73
81
  def [](id)
74
82
  Point.new(self, id)
75
83
  end
84
+
85
+ def pretty_print(q, other_attr = [])
86
+ attr = [
87
+ "filled?", "outlined?", "outline_width",
88
+ "points"
89
+ ]
90
+
91
+ super q, attr + other_attr
92
+ end
76
93
  end
77
94
  end
@@ -0,0 +1,28 @@
1
+ module Ray
2
+ # Module containing helpers to implement pretty print
3
+ module PP
4
+ # @param [PrettyPrint] q Object used for pretty printing
5
+ # @param [Array<String>] attributes Methods to call and to print the result
6
+ # of
7
+ def pretty_print_attributes(q, attributes)
8
+ id = "%x" % (__id__ * 2)
9
+ id.sub!(/\Af(?=[[:xdigit:]]{2}+\z)/, '') if id.sub!(/\A\.\./, '')
10
+
11
+ klass = self.class.pretty_inspect.chomp
12
+
13
+ q.group(2, "\#<#{klass}:0x#{id}", '>') do
14
+ q.seplist(attributes, lambda { q.text ',' }) do |key|
15
+ q.breakable
16
+
17
+ q.text key.to_s
18
+ q.text '='
19
+
20
+ q.group(2) do
21
+ q.breakable ''
22
+ q.pp send(key)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -4,7 +4,7 @@ require 'iconv'
4
4
  # Change PATH so as to find DLLs on windows.
5
5
  if RUBY_PLATFORM =~ /mingw/
6
6
  ext_dir = File.expand_path("../../ext", File.dirname(__FILE__))
7
- ENV["PATH"] = ENV["PATH"] + File::PATH_SEPARATOR + ext_dir
7
+ ENV["PATH"] = ext_dir + File::PATH_SEPARATOR + ENV["PATH"]
8
8
  end
9
9
 
10
10
  require 'ray_ext'
@@ -17,6 +17,8 @@ module Ray
17
17
  InternalEncoding = BigEndian ? "UTF-32BE" : "UTF-32LE"
18
18
  end
19
19
 
20
+ require 'ray/pp'
21
+
20
22
  require 'ray/resource_set'
21
23
 
22
24
  require 'ray/vector'
@@ -28,6 +30,7 @@ require 'ray/vertex'
28
30
  require 'ray/gl/vertex'
29
31
  require 'ray/gl/int_array'
30
32
  require 'ray/buffer_renderer'
33
+ require 'ray/pixel_bus'
31
34
  require 'ray/shader'
32
35
 
33
36
  require 'ray/image'
@@ -47,6 +50,7 @@ require 'ray/text'
47
50
  require 'ray/turtle'
48
51
 
49
52
  require 'ray/audio'
53
+ require 'ray/audio_source'
50
54
  require 'ray/sound_buffer'
51
55
  require 'ray/sound'
52
56
  require 'ray/music'
@@ -61,6 +65,8 @@ require 'ray/helper'
61
65
  require 'ray/animation'
62
66
  require 'ray/animation_list'
63
67
 
68
+ require 'ray/effect'
69
+
64
70
  require 'ray/scene_list'
65
71
  require 'ray/scene'
66
72
 
@@ -21,16 +21,17 @@ module Ray
21
21
 
22
22
  # @return [true, false] True if the receiver is outside the rect.
23
23
  def outside?(rect)
24
- rect = rect.to_rect
25
- !rect.contain?(top_left) &&
26
- !rect.contain?(bottom_left) &&
27
- !rect.contain?(top_right) &&
28
- !rect.contain?(bottom_right)
24
+ !collide?(rect)
29
25
  end
30
26
 
31
27
  # @return [true, false] True if the receiver collides with the rect.
32
28
  def collide?(rect)
33
- !outside?(rect)
29
+ rect = rect.to_rect
30
+
31
+ rect.x < x + width &&
32
+ x < rect.x + rect.width &&
33
+ rect.y < y + height &&
34
+ y < rect.y + rect.height
34
35
  end
35
36
 
36
37
  # @return [true, false] True if the receiver contians this point
@@ -107,10 +108,3 @@ class Array
107
108
  Ray::Rect.new(*self)
108
109
  end
109
110
  end
110
-
111
- class Hash
112
- # @return [Ray::Rect] Converts a hash into a rect.
113
- def to_rect
114
- Ray::Rect.new(self)
115
- end
116
- end
@@ -111,7 +111,7 @@ module Ray
111
111
 
112
112
  def register_events
113
113
  if @scene_register_block
114
- instance_exec(@scene_arguments, &@scene_register_block)
114
+ instance_exec(*@scene_arguments, &@scene_register_block)
115
115
  else
116
116
  register
117
117
  end
@@ -155,10 +155,12 @@ module Ray
155
155
  def run_tick(check_events = true)
156
156
  collect_events if check_events
157
157
 
158
+ @scene_animations.update
158
159
  @scene_always_block.call if @scene_always_block
160
+
159
161
  listener_runner.run
160
162
 
161
- @scene_animations.update
163
+ @scene_animations.remove_unused
162
164
 
163
165
  @scene_window.clear Ray::Color.none
164
166
  render @scene_window
@@ -202,6 +204,16 @@ module Ray
202
204
  game.pop_scene
203
205
  end
204
206
 
207
+ # (see Ray::Game#pop_scene_while)
208
+ def pop_scene_while(&block)
209
+ game.pop_scene_while(&block)
210
+ end
211
+
212
+ # (see Ray::Game#pop_scene_until)
213
+ def pop_scene_until(&block)
214
+ game.pop_scene_until(&block)
215
+ end
216
+
205
217
  # Registers a block to be excuted as often as possible.
206
218
  def always(&block)
207
219
  @scene_always_block = block
@@ -237,11 +249,18 @@ module Ray
237
249
  end
238
250
  end
239
251
 
240
- def inspect
241
- "#<#{self.class} game=#{self.game.inspect}>"
252
+ alias :pop_scene :exit!
253
+
254
+ # Sets the name of the scene
255
+ # @param [String] val New name of the scene
256
+ def name=(val)
257
+ @scene_name = val
242
258
  end
243
259
 
244
- alias :pop_scene :exit!
260
+ # @see name=
261
+ def name
262
+ @scene_name
263
+ end
245
264
 
246
265
  def game
247
266
  @scene_game
@@ -3,6 +3,7 @@ module Ray
3
3
  # It needs a game object to find a scene from its name.
4
4
  class SceneList
5
5
  include Enumerable
6
+ include Ray::PP
6
7
 
7
8
  # @param [Ray::Game] game The game which will be used to find scenes.
8
9
  def initialize(game)
@@ -67,8 +68,16 @@ module Ray
67
68
  @scenes.each(&block)
68
69
  end
69
70
 
71
+ # @return [Array<Ray::Scene>]
72
+ attr_reader :scenes
73
+ alias to_a scenes
74
+
70
75
  def inspect
71
76
  "#{self.class}#{@scenes.inspect}"
72
77
  end
78
+
79
+ def pretty_print(q)
80
+ pretty_print_attributes q, ["scenes"]
81
+ end
73
82
  end
74
83
  end
@@ -42,8 +42,11 @@ module Ray
42
42
  self
43
43
  end
44
44
 
45
- # @param [String, Symbol] attr Name of the parameter to set
46
- # @param
45
+ # @param [String, Symbol] attr Name of the parameter to set. Can be a
46
+ # variable name or a way to identify an element from a struct or an array
47
+ # (e.g. array[3] or some_struct.field).
48
+ #
49
+ # @param [Object] value Value to set it to.
47
50
  def []=(attr, value)
48
51
  attr = attr.to_sym
49
52
  @locations[attr] ||= locate(attr)
@@ -78,5 +81,11 @@ module Ray
78
81
  set_numeric loc, value
79
82
  end
80
83
  end
84
+
85
+ # @param [Hash] attr Hash containing the parameter names as keys and the
86
+ # values to set them to.
87
+ def merge(hash)
88
+ hash.each { |key, val| self[key] = val }
89
+ end
81
90
  end
82
91
  end