cultome_player 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +24 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +325 -0
- data/Rakefile +8 -0
- data/bin/cultome_player +39 -0
- data/config/environment.yml +28 -0
- data/cultome_player.gemspec +35 -0
- data/db/001_create_schema.rb +58 -0
- data/lib/cultome_player.rb +107 -0
- data/lib/cultome_player/command.rb +11 -0
- data/lib/cultome_player/command/language.rb +61 -0
- data/lib/cultome_player/command/processor.rb +165 -0
- data/lib/cultome_player/command/reader.rb +86 -0
- data/lib/cultome_player/environment.rb +130 -0
- data/lib/cultome_player/events.rb +29 -0
- data/lib/cultome_player/media.rb +47 -0
- data/lib/cultome_player/objects.rb +15 -0
- data/lib/cultome_player/objects/album.rb +21 -0
- data/lib/cultome_player/objects/artist.rb +18 -0
- data/lib/cultome_player/objects/command.rb +37 -0
- data/lib/cultome_player/objects/drive.rb +26 -0
- data/lib/cultome_player/objects/genre.rb +16 -0
- data/lib/cultome_player/objects/parameter.rb +37 -0
- data/lib/cultome_player/objects/response.rb +42 -0
- data/lib/cultome_player/objects/song.rb +38 -0
- data/lib/cultome_player/player.rb +13 -0
- data/lib/cultome_player/player/adapter.rb +14 -0
- data/lib/cultome_player/player/adapter/mpg123.rb +143 -0
- data/lib/cultome_player/player/interactive.rb +56 -0
- data/lib/cultome_player/player/interface.rb +13 -0
- data/lib/cultome_player/player/interface/basic.rb +96 -0
- data/lib/cultome_player/player/interface/builtin_help.rb +368 -0
- data/lib/cultome_player/player/interface/extended.rb +199 -0
- data/lib/cultome_player/player/interface/helper.rb +300 -0
- data/lib/cultome_player/player/playlist.rb +280 -0
- data/lib/cultome_player/plugins.rb +23 -0
- data/lib/cultome_player/plugins/help.rb +58 -0
- data/lib/cultome_player/state_checker.rb +74 -0
- data/lib/cultome_player/utils.rb +95 -0
- data/lib/cultome_player/version.rb +3 -0
- data/spec/config.yml +0 -0
- data/spec/cultome_player/command/processor_spec.rb +168 -0
- data/spec/cultome_player/command/reader_spec.rb +45 -0
- data/spec/cultome_player/cultome_player_spec.rb +17 -0
- data/spec/cultome_player/environment_spec.rb +65 -0
- data/spec/cultome_player/events_spec.rb +22 -0
- data/spec/cultome_player/media_spec.rb +41 -0
- data/spec/cultome_player/player/adapter/mpg123_spec.rb +82 -0
- data/spec/cultome_player/player/interface/basic_spec.rb +168 -0
- data/spec/cultome_player/player/interface/extended/connect_spec.rb +117 -0
- data/spec/cultome_player/player/interface/extended/search_spec.rb +90 -0
- data/spec/cultome_player/player/interface/extended/show_spec.rb +36 -0
- data/spec/cultome_player/player/interface/extended/shuffle_spec.rb +26 -0
- data/spec/cultome_player/player/interface/extended_spec.rb +136 -0
- data/spec/cultome_player/player/interface/helper_spec.rb +63 -0
- data/spec/cultome_player/player/interface_spec.rb +17 -0
- data/spec/cultome_player/player/playlist_spec.rb +301 -0
- data/spec/cultome_player/plugins/help_spec.rb +21 -0
- data/spec/cultome_player/plugins_spec.rb +19 -0
- data/spec/cultome_player/utils_spec.rb +15 -0
- data/spec/spec_helper.rb +108 -0
- data/spec/test/uno/dos/dos.mp3 +0 -0
- data/spec/test/uno/dos/tres/tres.mp3 +0 -0
- data/spec/test/uno/uno.mp3 +0 -0
- data/tasks/console.rake +19 -0
- data/tasks/db.rake +19 -0
- data/tasks/run.rake +7 -0
- metadata +322 -0
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'cultome_player/utils'
|
2
|
+
|
3
|
+
module CultomePlayer::Player::Playlist
|
4
|
+
|
5
|
+
# Lazy getter for playlists.
|
6
|
+
#
|
7
|
+
# @return [Playlists] The playlists handled by the system.
|
8
|
+
def playlists
|
9
|
+
@playlists ||= Playlists.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# (see Playlists#registered?)
|
13
|
+
def playlist?(name)
|
14
|
+
playlists.registered?(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
class Playlists
|
18
|
+
include Enumerable
|
19
|
+
include CultomePlayer::Utils
|
20
|
+
|
21
|
+
# Initialize a playlist with optional information to fill.
|
22
|
+
#
|
23
|
+
# @param data [#each] A collection of items to add to playlist
|
24
|
+
def initialize(data=nil)
|
25
|
+
@data = {}
|
26
|
+
data.each{|arr| register(*arr) } unless data.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
# Register a playlist.
|
30
|
+
#
|
31
|
+
# @param name [Symbol] The name of the new playlist.
|
32
|
+
# @param value [List<Object>] Optional data to initialize the playlist.
|
33
|
+
def register(name, value=nil)
|
34
|
+
raise 'invalid registry:playlist already registered' unless @data[name].nil?
|
35
|
+
@data[name] = value.nil? ? {list: [], idx: -1, repeat: true, shuffled: false} : value
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check if a playlist is registered.
|
39
|
+
#
|
40
|
+
# @param name [Symbol] The name of the new playlist.
|
41
|
+
# @return [Boolean] True if previously registered, False otherwise.
|
42
|
+
def registered?(name)
|
43
|
+
@data.has_key?(name)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Creates an interator for all the songs in all the playlists
|
47
|
+
#
|
48
|
+
# @return [Iterator] Iterator over all the songs.
|
49
|
+
def each_song
|
50
|
+
idx = 0
|
51
|
+
@data.values.each{|info| info[:list].each{|song| yield song, idx += 1 } }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates an interator for the playlists
|
55
|
+
#
|
56
|
+
# @return [Iterator] Iterator over the playlists.
|
57
|
+
def each
|
58
|
+
@data.values.each{|info| yield info[:list] }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Check if there is playlists registered.
|
62
|
+
#
|
63
|
+
# @return [Boolean] True if there is any playlist registered. False otherwise.
|
64
|
+
def empty?
|
65
|
+
return @data.values.first[:list].empty? if @data.size == 1
|
66
|
+
@data.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a new playlist object that contains the playlists named in parameters.
|
70
|
+
#
|
71
|
+
# @return [Playlists] Playlists with selected playlists inside.
|
72
|
+
def [](*names)
|
73
|
+
validate names
|
74
|
+
selected = @data.select{|name,info| names.include?(name) }
|
75
|
+
return Playlists.new(selected)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Replace the content of the playlist with the content of parameter.
|
79
|
+
#
|
80
|
+
# @param value [List<Object>] The new contents of the playlist.
|
81
|
+
def <=(value)
|
82
|
+
@data.keys.each{|name| replace(name, value) }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Append the content of the playlist with the content of parameter.
|
86
|
+
#
|
87
|
+
# @param value [List<Object>] The appended of the playlist.
|
88
|
+
def <<(value)
|
89
|
+
if value.respond_to?(:each)
|
90
|
+
@data.values.each{|info| value.each{|v| info[:list] << v } }
|
91
|
+
else
|
92
|
+
@data.values.each{|info| info[:list] << value }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Removes the last element in the playlists.
|
97
|
+
#
|
98
|
+
# @return [List<Object>, Object] The las elements in the playlists.
|
99
|
+
def pop
|
100
|
+
last_ones = collect{|list| list.pop }
|
101
|
+
return last_ones.first if last_ones.size == 1
|
102
|
+
return last_ones
|
103
|
+
end
|
104
|
+
|
105
|
+
# Shuffle the playlists and reset the indexes.
|
106
|
+
def shuffle
|
107
|
+
@data.values.each do |info|
|
108
|
+
info[:list].shuffle!
|
109
|
+
info[:shuffled] = true
|
110
|
+
info[:idx] = -1
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Order the playlists and reset the indexes.
|
115
|
+
def order
|
116
|
+
@data.values.each do |info|
|
117
|
+
info[:list].sort!
|
118
|
+
info[:idx] = -1
|
119
|
+
info[:shuffled] = false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns the next song in playlist, which means the new current song.
|
124
|
+
#
|
125
|
+
# @return [List<Object>,Object] The next element(s) in playlist(s).
|
126
|
+
def next
|
127
|
+
each_next do |info, nxt_idx|
|
128
|
+
info[:idx] = nxt_idx
|
129
|
+
info[:list].at nxt_idx
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns the previous song in playlist.
|
134
|
+
#
|
135
|
+
# @return [List<Object>,Object] The previous element(s) in playlist(s).
|
136
|
+
def rewind_by(idx)
|
137
|
+
each_next do |info, nxt_idx|
|
138
|
+
info[:idx] -= idx
|
139
|
+
info[:list].at info[:idx]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Remove the next element in playlist.
|
144
|
+
#
|
145
|
+
# @return [List<Object>,Object] The next element(s) in playlist(s).
|
146
|
+
def remove_next
|
147
|
+
each_next do |info, nxt_idx|
|
148
|
+
info[:list].delete_at nxt_idx
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Return the play index in the playlists.
|
153
|
+
#
|
154
|
+
# @return [List<Integer>, Integer] Indexes of the playlists.
|
155
|
+
def play_index
|
156
|
+
return first_or_map :idx
|
157
|
+
end
|
158
|
+
|
159
|
+
# Return the repeat status in the playlists.
|
160
|
+
#
|
161
|
+
# @return [List<Boolean>, Boolean] Indexes of the playlists.
|
162
|
+
def repeat?
|
163
|
+
return first_or_map :repeat
|
164
|
+
end
|
165
|
+
|
166
|
+
# Change the repeat status in the playlists.
|
167
|
+
def repeat(value)
|
168
|
+
@data.values.each{|info| info[:repeat] = is_true_value?(value) }
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns the current element in playlists.
|
172
|
+
#
|
173
|
+
# @return [List<Object>, Object] The current element(s) in playlist(s).
|
174
|
+
def current
|
175
|
+
currents = @data.values
|
176
|
+
.select{|info| info[:idx] >= 0}
|
177
|
+
.map do |info|
|
178
|
+
info[:list].at info[:idx]
|
179
|
+
end
|
180
|
+
|
181
|
+
return nil if currents.empty?
|
182
|
+
raise 'no current:no current song in one of the playlists' if @data.size != currents.size
|
183
|
+
return currents.first if currents.size == 1
|
184
|
+
return currents
|
185
|
+
end
|
186
|
+
|
187
|
+
# The number of registered playlists.
|
188
|
+
#
|
189
|
+
# @return [Integer] The size of registered playlist.
|
190
|
+
def size
|
191
|
+
@data.size
|
192
|
+
end
|
193
|
+
|
194
|
+
# Return a list with all the songs in all the playlists.
|
195
|
+
#
|
196
|
+
# @return [List<Object>] A list with all the songs in all the playlists.
|
197
|
+
def to_a
|
198
|
+
@data.values.reduce([]){|acc,info| acc + info[:list]}
|
199
|
+
end
|
200
|
+
|
201
|
+
alias :songs :to_a
|
202
|
+
|
203
|
+
# Returns the elements in the playlist.
|
204
|
+
#
|
205
|
+
# @param idx [Integer] The positional index of the element required.
|
206
|
+
# @return [List<Object>, Object] The positional elements in the playlists.
|
207
|
+
def at(idx)
|
208
|
+
return @data.values.first[:list].at(idx) if @data.size == 1
|
209
|
+
return @data.values.collect{|info| info[:list].at(idx) }
|
210
|
+
end
|
211
|
+
|
212
|
+
# Returns a string representation of the playlists.
|
213
|
+
#
|
214
|
+
# @return [String] A representation of the playlists.
|
215
|
+
def as_list
|
216
|
+
list = ""
|
217
|
+
each_song{|s,i| list << "#{i}. #{s.to_s}\n" }
|
218
|
+
return list
|
219
|
+
end
|
220
|
+
|
221
|
+
# Check if there is another element in playlists.
|
222
|
+
#
|
223
|
+
# @return [List<Boolean>, Boolean] True if the the playlist has more elements, False otherwise.
|
224
|
+
def next?
|
225
|
+
nexts = each_next_with_index{|info, nxt_idx| nxt_idx }
|
226
|
+
has_nexts = nexts.map{|nxt_idx| !nxt_idx.nil? }
|
227
|
+
return has_nexts.first if has_nexts.size == 1
|
228
|
+
return has_nexts
|
229
|
+
end
|
230
|
+
|
231
|
+
# Check the status of shuffling in playlists.
|
232
|
+
#
|
233
|
+
# @return [List<Boolean>, Boolean] True if playlist is shuffling. False otherwise.
|
234
|
+
def shuffling?
|
235
|
+
return first_or_map :shuffled
|
236
|
+
end
|
237
|
+
|
238
|
+
private
|
239
|
+
|
240
|
+
def first_or_map(attr)
|
241
|
+
return @data.values.first[attr] if @data.size == 1
|
242
|
+
return @data.values.map{|info| info[attr] }
|
243
|
+
end
|
244
|
+
|
245
|
+
# Returns the non-empty playlists yielded by the block
|
246
|
+
def each_next_with_index
|
247
|
+
@data.values
|
248
|
+
.select{|info| !info[:list].empty? }
|
249
|
+
.map do |info|
|
250
|
+
nxt_idx = next_idx(info[:idx], info[:list].size, info[:repeat])
|
251
|
+
nxt_idx.nil? ? nil : yield(info, nxt_idx)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Returns an array with songs, if multiple playlists and only one if single playlist is available
|
256
|
+
def each_next(&block)
|
257
|
+
nexts = each_next_with_index(&block).compact
|
258
|
+
raise "playlist empty:no songs in playlists" if nexts.empty?
|
259
|
+
raise "playlist empty:no songs in one of the playlists" if nexts.size != @data.size
|
260
|
+
return nexts.first if nexts.size == 1
|
261
|
+
return nexts
|
262
|
+
end
|
263
|
+
|
264
|
+
def next_idx(actual_idx, size, repeat)
|
265
|
+
next_idx = actual_idx + 1
|
266
|
+
next_idx = next_idx % size if repeat
|
267
|
+
return nil if next_idx >= size
|
268
|
+
return next_idx
|
269
|
+
end
|
270
|
+
|
271
|
+
def replace(name, value)
|
272
|
+
@data[name][:list].replace value
|
273
|
+
@data[name][:idx] = -1
|
274
|
+
end
|
275
|
+
|
276
|
+
def validate(names)
|
277
|
+
raise 'unknown playlist:playlist is not registered' if names.any?{|n| !@data.keys.include?(n) }
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'cultome_player/plugins/help'
|
2
|
+
|
3
|
+
module CultomePlayer
|
4
|
+
module Plugins
|
5
|
+
include Help
|
6
|
+
|
7
|
+
# Check if a plugin implements the given command.
|
8
|
+
#
|
9
|
+
# @param cmd_name [String] The command name.
|
10
|
+
# @return [Boolean] True is the given command is implemented by a plugin.
|
11
|
+
def plugins_respond_to?(cmd_name)
|
12
|
+
return respond_to?("command_#{cmd_name}".to_sym)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get a command format for a command implemented by a plugin
|
16
|
+
#
|
17
|
+
# @param cmd_name [String] The command name.
|
18
|
+
# @return [Regex] The regex to validate a command format that is implemented by a plugin.
|
19
|
+
def plugin_command_sintaxis(cmd_name)
|
20
|
+
return send("sintaxis_#{cmd_name}".to_sym)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module CultomePlayer
|
2
|
+
module Plugins
|
3
|
+
module Help
|
4
|
+
|
5
|
+
# Command implementation for action "help".
|
6
|
+
# Shows usage information for the actions of the player if called with an action as parameter and shows a player usage information if called without parameters.
|
7
|
+
#
|
8
|
+
# @contract Plugin
|
9
|
+
# @param cmd [Command] Command information parsed from user input
|
10
|
+
# @return [Response] Contains a message to be displayed with the help required.
|
11
|
+
def command_help(cmd)
|
12
|
+
if cmd.params.empty?
|
13
|
+
success(message: usage_cultome_player)
|
14
|
+
else
|
15
|
+
help = send("usage_#{cmd.params.first.value}")
|
16
|
+
if help.nil?
|
17
|
+
failure("No help is available for '#{cmd.first.value}'.")
|
18
|
+
else
|
19
|
+
success(message: help)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def sintaxis_help
|
25
|
+
return /^literal (literal)$/
|
26
|
+
end
|
27
|
+
|
28
|
+
# Description of the action help.
|
29
|
+
#
|
30
|
+
# @contract Help Plugin.
|
31
|
+
# @return [String] The description of the action.
|
32
|
+
def description_help
|
33
|
+
"Provides information for player features."
|
34
|
+
end
|
35
|
+
|
36
|
+
# Usage information of the action help.
|
37
|
+
#
|
38
|
+
# @contract Help Plugin.
|
39
|
+
# @return [String] The usage information of the action.
|
40
|
+
def usage_help
|
41
|
+
return <<-USAGE
|
42
|
+
usage: help [command]
|
43
|
+
|
44
|
+
Provides usage information for player commands. If called without parameters, shows the player usage.
|
45
|
+
|
46
|
+
Examples:
|
47
|
+
|
48
|
+
To see all the commands availables in the player:
|
49
|
+
help
|
50
|
+
|
51
|
+
To see the usage for play command:
|
52
|
+
help play
|
53
|
+
|
54
|
+
USAGE
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module CultomePlayer
|
2
|
+
module StateChecker
|
3
|
+
|
4
|
+
# Check the status of pause.
|
5
|
+
#
|
6
|
+
# @return [Boolean] True if paused, False otherwise
|
7
|
+
def paused?
|
8
|
+
@paused ||= false
|
9
|
+
end
|
10
|
+
|
11
|
+
# Check the status of stop.
|
12
|
+
#
|
13
|
+
# @return [Boolean] True if stopped, False otherwise
|
14
|
+
def stopped?
|
15
|
+
@stopped ||= true
|
16
|
+
end
|
17
|
+
|
18
|
+
# Check the status of play.
|
19
|
+
#
|
20
|
+
# @return [Boolean] True if playing, False otherwise
|
21
|
+
def playing?
|
22
|
+
@playing ||= false
|
23
|
+
end
|
24
|
+
|
25
|
+
# Check the status of shuffle.
|
26
|
+
#
|
27
|
+
# @return [Boolean] True if shuffling, False otherwise
|
28
|
+
def shuffling?
|
29
|
+
playlists[:current].shuffling?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the current song.
|
33
|
+
#
|
34
|
+
# @return [Song] The current song or nil if any.
|
35
|
+
def current_song
|
36
|
+
@current_song
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the current artist.
|
40
|
+
#
|
41
|
+
# @return [Artist] The current artist or nil if any.
|
42
|
+
def current_artist
|
43
|
+
current_song.artist
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the current album.
|
47
|
+
#
|
48
|
+
# @return [Album] The current album or nil if any.
|
49
|
+
def current_album
|
50
|
+
current_song.album
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the current playlist.
|
54
|
+
#
|
55
|
+
# @return [Playlist] The current playlist or nil if any.
|
56
|
+
def current_playlist
|
57
|
+
playlists[:current]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the current playback position.
|
61
|
+
#
|
62
|
+
# @return [Integer] The current playback position in seconds.
|
63
|
+
def playback_position
|
64
|
+
@playback_time_position ||= 0
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the current playback length.
|
68
|
+
#
|
69
|
+
# @return [Integer] The current playback length in seconds.
|
70
|
+
def playback_length
|
71
|
+
@playback_time_length ||= 0
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module CultomePlayer
|
4
|
+
module Utils
|
5
|
+
|
6
|
+
# Check if a string value can be a positive boolean value.
|
7
|
+
#
|
8
|
+
# @param value [String] String to check if can be a positive boolean value.
|
9
|
+
# @return [Boolean] True if value is a positive boolean value. False otherwise.
|
10
|
+
def is_true_value?(value)
|
11
|
+
/true|yes|on|y|n|s|si|cierto/ === value
|
12
|
+
end
|
13
|
+
|
14
|
+
# Print a string into stdout (not STDOUT) and finish with a newline character.
|
15
|
+
#
|
16
|
+
# @param msg [String] The value to be printed.
|
17
|
+
# @return [String] The value printed.
|
18
|
+
def display(msg)
|
19
|
+
stdout.puts msg
|
20
|
+
return msg
|
21
|
+
end
|
22
|
+
|
23
|
+
# Print a string into stdout (not STDOUT) but before insert a carriage return and dont append a newline character at the end.
|
24
|
+
#
|
25
|
+
# @param msg [String] The value to be printed.
|
26
|
+
# @return [String] The value printed.
|
27
|
+
def display_over(msg)
|
28
|
+
stdout.print "\r#{msg}"
|
29
|
+
return msg
|
30
|
+
end
|
31
|
+
|
32
|
+
# Define the 15 colors allowed in my console scheme
|
33
|
+
(1..15).each do |idx|
|
34
|
+
define_method :"c#{idx}" do |str|
|
35
|
+
str
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Arrange an array of string into single string arranged by columns separed by an inner border.
|
40
|
+
#
|
41
|
+
# @param cols [List<String>] The strings to be arranged.
|
42
|
+
# @param widths [List<Integer>] The width of the columns.
|
43
|
+
# @param border [Integer] The width of the inner borders.
|
44
|
+
# @return [String] The string representation of columns.
|
45
|
+
def arrange_in_columns(cols, widths, border)
|
46
|
+
row = ""
|
47
|
+
idxs = cols.collect{|c| 0 }
|
48
|
+
|
49
|
+
while cols.zip(idxs).any?{|col| col[0].length > col[1] }
|
50
|
+
cols.each.with_index do |col, idx|
|
51
|
+
slice_width = widths[idx]
|
52
|
+
|
53
|
+
slice = col.slice(idxs[idx], slice_width) || "" # sacamos el pedazo de la columna
|
54
|
+
row << slice.ljust(slice_width) # concatenamos a la fila
|
55
|
+
idxs[idx] += slice_width # recorremos el indice
|
56
|
+
row << " " * border # agregamos el border de la derecha
|
57
|
+
end
|
58
|
+
|
59
|
+
row = row.strip << "\n" # quitamos el ultimo border
|
60
|
+
end
|
61
|
+
|
62
|
+
return row.strip # quitamos el ultimo salto de linea
|
63
|
+
end
|
64
|
+
|
65
|
+
# Capture and dispose the standard output sended inside the block provided.
|
66
|
+
#
|
67
|
+
# @return [String] The swallowed data.
|
68
|
+
def swallow_stdout
|
69
|
+
s = StringIO.new
|
70
|
+
oldstd = $stdout
|
71
|
+
$stdout = s
|
72
|
+
yield
|
73
|
+
return s.string
|
74
|
+
ensure
|
75
|
+
$stdout = oldstd
|
76
|
+
end
|
77
|
+
|
78
|
+
# Provides a wrapper for database connection.
|
79
|
+
#
|
80
|
+
# @param db_block [Block] The block to be executed inside a database connection.
|
81
|
+
def with_connection(&db_logic)
|
82
|
+
begin
|
83
|
+
ActiveRecord::Base.connection_pool
|
84
|
+
rescue Exception => e
|
85
|
+
ActiveRecord::Base.establish_connection(
|
86
|
+
adapter: db_adapter,
|
87
|
+
database: db_file
|
88
|
+
)
|
89
|
+
ActiveRecord::Base.logger = Logger.new(File.open(db_log_file, 'a'))
|
90
|
+
end
|
91
|
+
|
92
|
+
ActiveRecord::Base.connection_pool.with_connection(&db_logic)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|