fantasy 0.1.13 → 0.1.17
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +22 -1
- data/.yardopts +4 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +55 -0
- data/README.md +14 -6
- data/docs/Actor.html +2737 -0
- data/docs/Background.html +961 -0
- data/docs/Camera.html +791 -0
- data/docs/Clock.html +753 -0
- data/docs/Color.html +776 -0
- data/docs/Coordinates.html +730 -0
- data/docs/Cursor.html +752 -0
- data/docs/Disk.html +236 -0
- data/docs/Draggable.html +198 -0
- data/docs/Fantasy.html +121 -0
- data/docs/Game.html +904 -0
- data/docs/Global.html +2791 -0
- data/docs/Gravitier.html +179 -0
- data/docs/HudImage.html +979 -0
- data/docs/HudText.html +1151 -0
- data/docs/Image.html +506 -0
- data/docs/Jumper.html +189 -0
- data/docs/Mouse.html +226 -0
- data/docs/MoveByCursor.html +374 -0
- data/docs/MoveByDirection.html +179 -0
- data/docs/Mover.html +305 -0
- data/docs/Music.html +524 -0
- data/docs/Shape.html +1057 -0
- data/docs/Sound.html +374 -0
- data/docs/Tilemap.html +491 -0
- data/docs/Tween.html +186 -0
- data/docs/UserInputs.html +879 -0
- data/docs/Utils.html +345 -0
- data/docs/_index.html +346 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +497 -0
- data/docs/file.CHANGELOG.html +121 -0
- data/docs/file.README.html +599 -0
- data/docs/file_list.html +61 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +599 -0
- data/docs/js/app.js +314 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +1931 -0
- data/docs/top-level-namespace.html +978 -0
- data/lib/fantasy/actor.rb +455 -123
- data/lib/fantasy/background.rb +109 -13
- data/lib/fantasy/base.rb +113 -1
- data/lib/fantasy/camera.rb +95 -11
- data/lib/fantasy/clock.rb +4 -2
- data/lib/fantasy/color.rb +158 -153
- data/lib/fantasy/coordinates.rb +5 -9
- data/lib/fantasy/cursor.rb +2 -1
- data/lib/fantasy/disk.rb +12 -8
- data/lib/fantasy/draggable.rb +22 -1
- data/lib/fantasy/global.rb +59 -31
- data/lib/fantasy/hud_image.rb +5 -3
- data/lib/fantasy/hud_text.rb +6 -2
- data/lib/fantasy/image.rb +12 -4
- data/lib/fantasy/includes/gravitier.rb +2 -0
- data/lib/fantasy/includes/jumper.rb +3 -2
- data/lib/fantasy/includes/log.rb +12 -0
- data/lib/fantasy/includes/move_by_cursors.rb +24 -15
- data/lib/fantasy/includes/move_by_direction.rb +2 -0
- data/lib/fantasy/includes/mover.rb +3 -0
- data/lib/fantasy/includes/user_inputs.rb +6 -0
- data/lib/fantasy/loop.rb +41 -44
- data/lib/fantasy/mouse.rb +2 -0
- data/lib/fantasy/music.rb +4 -2
- data/lib/fantasy/shape.rb +11 -2
- data/lib/fantasy/sound.rb +3 -1
- data/lib/fantasy/tilemap.rb +19 -13
- data/lib/fantasy/tween.rb +3 -1
- data/lib/fantasy/utils.rb +7 -13
- data/lib/fantasy/version.rb +1 -1
- data/lib/fantasy.rb +2 -0
- metadata +90 -4
- data/fantasy.gemspec +0 -40
- data/fonts/VT323-Regular.ttf +0 -0
data/lib/fantasy/background.rb
CHANGED
@@ -1,9 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Represents on static image that will be rendered on every frame.
|
4
|
+
# Replicable (by default).
|
5
|
+
# The position is relative to `Camera.main`.
|
6
|
+
# ```
|
7
|
+
# on_game do
|
8
|
+
# background = Background.new(image_name: "beach")
|
9
|
+
# # background.replicable = false # if you don't want the image to replicate
|
10
|
+
# background.scale = 6
|
11
|
+
# end
|
12
|
+
# ```
|
1
13
|
class Background
|
2
|
-
attr_accessor :scale, :color, :visible, :position, :layer, :replicable
|
3
14
|
|
15
|
+
# In which layer the image of the Background is rendered.
|
16
|
+
# Smaller numbers are rendered behind higher numbers.
|
17
|
+
#
|
18
|
+
# Default `-100`.
|
19
|
+
#
|
20
|
+
# @example Set layer
|
21
|
+
# background = Background.new("image")
|
22
|
+
# background.layer = -50
|
23
|
+
attr_accessor :layer
|
24
|
+
|
25
|
+
|
26
|
+
# Coordinates object where x and y represent the position of the Background in the World
|
27
|
+
# (no necessarily in the Screen).
|
28
|
+
#
|
29
|
+
# Default `Coordinates.zero`.
|
30
|
+
#
|
31
|
+
# @example Setting position
|
32
|
+
# background = Background.new("image")
|
33
|
+
# background.position = Coordinates.new(10, 20)
|
34
|
+
# background.position.x # => 10
|
35
|
+
#
|
36
|
+
# @example Modify position
|
37
|
+
# background.position.x += 1
|
38
|
+
# background.position.x # => 11
|
39
|
+
attr_accessor :position
|
40
|
+
|
41
|
+
# [Boolean] When `true` the image will replicate itself to cover all the screen. Default `true`.
|
42
|
+
#
|
43
|
+
# Default `true`.
|
44
|
+
#
|
45
|
+
# @example Setting replicable
|
46
|
+
# background = Background.new("image")
|
47
|
+
# background.replicable = false
|
48
|
+
attr_accessor :replicable
|
49
|
+
|
50
|
+
# The value to scale the image of the Background when drawn.
|
51
|
+
# If the value is `2` the image will rendered at double of size.
|
52
|
+
# If the value is `0.5` the image will rendered at half of size.
|
53
|
+
#
|
54
|
+
# @note this value affects the attributes `width` and `height`
|
55
|
+
#
|
56
|
+
# Default `1`.
|
57
|
+
#
|
58
|
+
# @example Set scale
|
59
|
+
# background = Background.new("image")
|
60
|
+
# background.scale = 6
|
61
|
+
attr_accessor :scale
|
62
|
+
|
63
|
+
# When `false` the Background won't be rendered in the next frame.
|
64
|
+
#
|
65
|
+
# Default `true`.
|
66
|
+
#
|
67
|
+
# @example Set visible
|
68
|
+
# background = Background.new("image")
|
69
|
+
# background.visible = false
|
70
|
+
attr_accessor :visible
|
71
|
+
|
72
|
+
# Generates an Background with all the below default values:
|
73
|
+
# - **position**: `Coordinates.zero`.
|
74
|
+
# - **scale**: `1`.
|
75
|
+
# - **draggable_on_debug**: `true`.
|
76
|
+
# - **layer**: `-100`.
|
77
|
+
# - **image**: The Image generated by `image_name`
|
78
|
+
# - **name**: Same as `image_name`
|
79
|
+
# - **visible**: `true`
|
80
|
+
# - **replicable**: `true`
|
81
|
+
#
|
82
|
+
# @param image_name [string] the name of the image file from `./images/*`
|
83
|
+
# @return [Background] the Background
|
84
|
+
# @example Instantiate a new Background
|
85
|
+
# background = Background.new("background")
|
4
86
|
def initialize(image_name:)
|
5
87
|
@image = Image.new(image_name)
|
6
|
-
@name = image_name
|
7
88
|
@position = Coordinates.zero
|
8
89
|
@scale = 1
|
9
90
|
@visible = true
|
@@ -15,18 +96,19 @@ class Background
|
|
15
96
|
Global.backgrounds.push(self)
|
16
97
|
end
|
17
98
|
|
99
|
+
# @return [Fixnum] the Background width in pixels
|
18
100
|
def width
|
19
|
-
@image.width
|
101
|
+
@image.width * @scale
|
20
102
|
end
|
21
103
|
|
104
|
+
# @return [Fixnum] the Background height in pixels
|
22
105
|
def height
|
23
|
-
@image.height
|
106
|
+
@image.height * @scale
|
24
107
|
end
|
25
108
|
|
26
|
-
|
27
|
-
@position - Global.camera.position
|
28
|
-
end
|
109
|
+
# rubocop:disable Style/GuardClause
|
29
110
|
|
111
|
+
# @!visibility private
|
30
112
|
def draw
|
31
113
|
if @visible
|
32
114
|
if @replicable
|
@@ -36,18 +118,31 @@ class Background
|
|
36
118
|
end
|
37
119
|
end
|
38
120
|
end
|
121
|
+
# rubocop:enable Style/GuardClause
|
39
122
|
|
40
|
-
|
41
|
-
|
123
|
+
# Destroy this Background and it will not longer be rendered
|
124
|
+
#
|
125
|
+
# @example Destroy a Background
|
126
|
+
# background = Background.new("background")
|
127
|
+
# background.destroy
|
128
|
+
def destroy
|
129
|
+
Global.backgrounds.delete(self)
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def position_in_camera
|
135
|
+
@position - Camera.main.position
|
42
136
|
end
|
43
137
|
|
44
138
|
# Camera relative Tiles
|
139
|
+
# rubocop:disable Metrics/AbcSize
|
45
140
|
def draw_replicable
|
46
141
|
tiles_delta_x = (position_in_camera.x % width) - width
|
47
142
|
tiles_delta_y = (position_in_camera.y % height) - height
|
48
143
|
|
49
|
-
tiles_needed_horizontal = ((
|
50
|
-
tiles_needed_vertical = ((
|
144
|
+
tiles_needed_horizontal = ((Global.screen_width - (tiles_delta_x + width)) / width.to_f).ceil + 1
|
145
|
+
tiles_needed_vertical = ((Global.screen_height - (tiles_delta_y + height)) / height.to_f).ceil + 1
|
51
146
|
|
52
147
|
tiles_needed_horizontal.times do |index_horizontal|
|
53
148
|
tiles_needed_vertical.times do |index_vertical|
|
@@ -55,8 +150,9 @@ class Background
|
|
55
150
|
end
|
56
151
|
end
|
57
152
|
end
|
153
|
+
# rubocop:enable Metrics/AbcSize
|
58
154
|
|
59
|
-
def
|
60
|
-
|
155
|
+
def draw_normal
|
156
|
+
@image.draw(x: position_in_camera.x, y: position_in_camera.y, scale: @scale)
|
61
157
|
end
|
62
158
|
end
|
data/lib/fantasy/base.rb
CHANGED
@@ -1,60 +1,172 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Here there are all the methods that can be used in the root level
|
4
|
+
|
1
5
|
Global.setup_proc = nil
|
2
6
|
Global.loop_proc = nil
|
3
7
|
|
8
|
+
# Defines the presentation Scene
|
9
|
+
#
|
10
|
+
# ```
|
11
|
+
# on_presentation do
|
12
|
+
# HudText.new(position: Coordinates.new(10, 100), text: "Press space to start")
|
13
|
+
#
|
14
|
+
# on_space_bar do
|
15
|
+
# Global.go_to_game
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# ```
|
4
19
|
def on_presentation(&block)
|
5
20
|
Global.presentation_proc = block
|
6
21
|
end
|
7
22
|
|
23
|
+
# Defines the game Scene
|
24
|
+
#
|
25
|
+
# ```
|
26
|
+
# on_game do
|
27
|
+
# # [...]
|
28
|
+
# if player.dead
|
29
|
+
# Global.go_to_end
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# ```
|
8
33
|
def on_game(&block)
|
9
34
|
Global.game_proc = block
|
10
35
|
end
|
11
36
|
|
37
|
+
# Defines the end Scene
|
38
|
+
#
|
39
|
+
# ```
|
40
|
+
# on_end do
|
41
|
+
# HudText.new(position: Coordinates.new(10, 100), text: "You are dead. Press space to re-tart")
|
42
|
+
#
|
43
|
+
# on_space_bar do
|
44
|
+
# Global.go_to_presentation
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
# ```
|
12
48
|
def on_end(&block)
|
13
49
|
Global.end_proc = block
|
14
50
|
end
|
15
51
|
|
52
|
+
# @!visibility private
|
16
53
|
def on_setup(&block)
|
17
54
|
Global.setup_proc = block
|
18
55
|
end
|
19
56
|
|
57
|
+
# Executes on every frame. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
58
|
+
# ```
|
59
|
+
# on_game do
|
60
|
+
# on_loop do
|
61
|
+
# Global.references.time = Time.at(Global.seconds_in_scene).utc.strftime("%M:%S")
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# ```
|
20
65
|
def on_loop(&block)
|
21
66
|
Global.loop_proc = block
|
22
67
|
end
|
23
68
|
|
69
|
+
# @!visibility private
|
24
70
|
def on_button(&block)
|
25
71
|
Global.button_proc = block
|
26
72
|
end
|
27
73
|
|
74
|
+
# Triggered any time space bar key is pressed. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
75
|
+
# ```
|
76
|
+
# on_game do
|
77
|
+
# on_space_bar do
|
78
|
+
# shoot_gun # for example
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# ```
|
28
82
|
def on_space_bar(&block)
|
29
83
|
Global.space_bar_proc = block
|
30
84
|
end
|
31
85
|
|
86
|
+
# Triggered any time cursor up key is pressed. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
87
|
+
# ```
|
88
|
+
# on_game do
|
89
|
+
# on_cursor_up do
|
90
|
+
# look_ups # for example
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
# ```
|
32
94
|
def on_cursor_up(&block)
|
33
95
|
Global.cursor_up_proc = block
|
34
96
|
end
|
35
97
|
|
98
|
+
# Triggered any time cursor down key is pressed. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
99
|
+
# ```
|
100
|
+
# on_game do
|
101
|
+
# on_cursor_down do
|
102
|
+
# look_down # for example
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
# ```
|
36
106
|
def on_cursor_down(&block)
|
37
107
|
Global.cursor_down_proc = block
|
38
108
|
end
|
39
109
|
|
110
|
+
# Triggered any time cursor left key is pressed. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
111
|
+
# ```
|
112
|
+
# on_game do
|
113
|
+
# on_cursor_left do
|
114
|
+
# look_left # for example
|
115
|
+
# end
|
116
|
+
# end
|
117
|
+
# ```
|
40
118
|
def on_cursor_left(&block)
|
41
119
|
Global.cursor_left_proc = block
|
42
120
|
end
|
43
121
|
|
122
|
+
# Triggered any time cursor right key is pressed. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
123
|
+
# ```
|
124
|
+
# on_game do
|
125
|
+
# on_cursor_right do
|
126
|
+
# look_right # for example
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
# ```
|
44
130
|
def on_cursor_right(&block)
|
45
131
|
Global.cursor_right_proc = block
|
46
132
|
end
|
47
133
|
|
134
|
+
# Triggered any time mouse left button is pressed. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
135
|
+
# ```
|
136
|
+
# on_game do
|
137
|
+
# on_mouse_button_left do
|
138
|
+
# show_menu # for example
|
139
|
+
# end
|
140
|
+
# end
|
141
|
+
# ```
|
48
142
|
def on_mouse_button_left(&block)
|
49
143
|
Global.mouse_button_left_proc = block
|
50
144
|
end
|
51
145
|
|
146
|
+
# Triggered any time mouse right button is pressed. To be used inside one of the scene blocks (`on_presentation`, `on_game`, `on_end`)
|
147
|
+
# ```
|
148
|
+
# on_game do
|
149
|
+
# on_mouse_button_right do
|
150
|
+
# show_menu # for example
|
151
|
+
# end
|
152
|
+
# end
|
153
|
+
# ```
|
52
154
|
def on_mouse_button_right(&block)
|
53
155
|
Global.mouse_button_right_proc = block
|
54
156
|
end
|
55
157
|
|
158
|
+
# Starts the game. This method has to be called when all the desired scene blocks (`on_presentation`, `on_game`, `on_end`) have been declared.
|
159
|
+
# ```
|
160
|
+
# on_game do
|
161
|
+
# # do game stuff
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# start!
|
165
|
+
# ```
|
56
166
|
def start!
|
167
|
+
raise "'SCREEN_WIDTH' and 'SCREEN_HEIGHT' both have to be set at the beginning of the program" unless defined?(SCREEN_WIDTH) && defined?(SCREEN_HEIGHT)
|
168
|
+
|
57
169
|
Global.setup
|
58
|
-
Global.game = Game.new
|
170
|
+
Global.game = Game.new(SCREEN_WIDTH, SCREEN_HEIGHT)
|
59
171
|
Global.game.show
|
60
172
|
end
|
data/lib/fantasy/camera.rb
CHANGED
@@ -1,31 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Represents Coordinates of the camera and it affects the screen position of all Actors and Backgrounds.
|
4
|
+
# There is only one active Camera and it is acceded by `Camera.main`. This Camera is initialized automatically
|
5
|
+
# and it is already accessible. It can also be changed by another `Camera` instance.`
|
6
|
+
#
|
7
|
+
# @example Set the camera position
|
8
|
+
# Camera.main.position = Coordinates.new(0, 100)
|
9
|
+
#
|
10
|
+
# @example Camera follows player vertically
|
11
|
+
# on_game do
|
12
|
+
# player = Actor.new("image")
|
13
|
+
#
|
14
|
+
# on_loop do
|
15
|
+
# Camera.main.position.y = player.position.y - (SCREEN_HEIGHT / 2)
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @example Switching between cameras
|
20
|
+
# camera_1 = Camera.new
|
21
|
+
# camera_2 = Camera.new(position: Coordinates.new(0, 10))
|
22
|
+
# Camera.main = camera_1
|
23
|
+
# Camera.main = camera_2
|
1
24
|
class Camera
|
2
|
-
include MoveByCursor
|
3
25
|
|
4
|
-
|
26
|
+
# Coordinates object where x and y represent the position of the Camera in the World (no necessarily in the Screen).
|
27
|
+
#
|
28
|
+
# Default `Coordinates.zero`.
|
29
|
+
#
|
30
|
+
# @return [Coordinates] the actual position
|
31
|
+
#
|
32
|
+
# @example Setting position
|
33
|
+
# Camera.main.position = Coordinates.new(10, 20)
|
34
|
+
# Camera.main.position.x # => 10
|
35
|
+
#
|
36
|
+
# @example Modify position
|
37
|
+
# Camera.main.position.x += 1
|
38
|
+
# Camera.main.position.x # => 11
|
39
|
+
attr_accessor :position
|
40
|
+
|
41
|
+
# Controls the direction in which the Camera will move in the next frame.
|
42
|
+
#
|
43
|
+
# Default `Coordinates.zero`.
|
44
|
+
#
|
45
|
+
# @return [Coordinates] the actual direction
|
46
|
+
#
|
47
|
+
# @note The the pixels per second is represented by the `@speed` attribute
|
48
|
+
#
|
49
|
+
# @example Set direction
|
50
|
+
# Camera.main.direction = Coordinates.right
|
51
|
+
attr_accessor :direction
|
52
|
+
|
53
|
+
# Controls the pixels per second which the Camera will move in the next frame.
|
54
|
+
#
|
55
|
+
# Default `0`.
|
56
|
+
#
|
57
|
+
# @return [Float] the actual speed
|
58
|
+
#
|
59
|
+
# @note The the direction is represented by the `@direction` attribute
|
60
|
+
#
|
61
|
+
# @example Set speed
|
62
|
+
# Camera.main.speed = 10
|
63
|
+
attr_accessor :speed
|
5
64
|
|
65
|
+
# Generates a Camera with all the default attribute values
|
66
|
+
# @example Generate an Camera
|
67
|
+
# camera = Camera.new
|
68
|
+
# camera.position # => Coordinates.zero
|
69
|
+
# camera.direction # => Coordinates.zero
|
70
|
+
# camera.speed # => 0
|
71
|
+
#
|
72
|
+
# @param position [Coordinates] the initial position of the camera. Default `Coordinates.zero`
|
73
|
+
# @return [Camera] the Camera
|
6
74
|
def initialize(position: Coordinates.zero)
|
7
75
|
@position = position
|
8
76
|
@direction = Coordinates.zero
|
9
77
|
@speed = 0
|
10
|
-
@moving_with_cursors = false
|
11
78
|
@on_after_move_callback = nil
|
12
79
|
end
|
13
80
|
|
14
|
-
|
15
|
-
@moving_with_cursors = true
|
16
|
-
end
|
17
|
-
|
81
|
+
# @!visibility private
|
18
82
|
def move
|
19
|
-
calculate_direction_by_cursors if @moving_with_cursors
|
20
|
-
|
21
83
|
if @direction != Coordinates.zero && !@speed.zero?
|
22
|
-
@position
|
84
|
+
@position += (@direction * @speed * Global.frame_time)
|
23
85
|
end
|
24
86
|
|
25
|
-
@on_after_move_callback
|
87
|
+
@on_after_move_callback&.call
|
26
88
|
end
|
27
89
|
|
90
|
+
# Triggered on every frame after the move has been executed
|
91
|
+
# @example Avoid Camera to move over limits
|
92
|
+
# Camera.main.on_after_move do
|
93
|
+
# if Camera.main.position.x > 100
|
94
|
+
# Camera.main.position.x = 100
|
95
|
+
# end
|
96
|
+
# end
|
28
97
|
def on_after_move(&block)
|
29
98
|
@on_after_move_callback = block
|
30
99
|
end
|
100
|
+
|
101
|
+
class << self
|
102
|
+
# @return [Camera] The active Camera
|
103
|
+
attr_accessor :main
|
104
|
+
|
105
|
+
# @!visibility private
|
106
|
+
def initialize
|
107
|
+
reset
|
108
|
+
end
|
109
|
+
|
110
|
+
# @!visibility private
|
111
|
+
def reset
|
112
|
+
@main = Camera.new
|
113
|
+
end
|
114
|
+
end
|
31
115
|
end
|
data/lib/fantasy/clock.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Clock
|
2
4
|
attr_accessor :persistent
|
3
5
|
attr_reader :thread
|
@@ -29,9 +31,9 @@ class Clock
|
|
29
31
|
times_executed = 0
|
30
32
|
@thread =
|
31
33
|
Thread.new do
|
32
|
-
while
|
34
|
+
while times_executed < times
|
33
35
|
@block.call
|
34
|
-
times_executed += 1
|
36
|
+
times_executed += 1
|
35
37
|
|
36
38
|
seconds_to_sleep = seconds.is_a?(Range) ? rand(seconds) : seconds
|
37
39
|
sleep(seconds_to_sleep)
|