cultome_player 2.0.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.
- 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
|