ray 0.1.1 → 0.2.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 (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