duck_test 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/ducktest +29 -0
- data/lib/duck_test/autoload_config.rb +103 -0
- data/lib/duck_test/base.rb +41 -0
- data/lib/duck_test/commands.rb +208 -0
- data/lib/duck_test/config.rb +675 -0
- data/lib/duck_test/config_helper.rb +99 -0
- data/lib/duck_test/console.rb +18 -0
- data/lib/duck_test/default_config.rb +48 -0
- data/lib/duck_test/frame_work/base.rb +587 -0
- data/lib/duck_test/frame_work/file_manager.rb +511 -0
- data/lib/duck_test/frame_work/filter_set.rb +233 -0
- data/lib/duck_test/frame_work/map.rb +331 -0
- data/lib/duck_test/frame_work/queue.rb +221 -0
- data/lib/duck_test/frame_work/queue_event.rb +29 -0
- data/lib/duck_test/frame_work/rspec/base.rb +17 -0
- data/lib/duck_test/frame_work/rspec/frame_work.rb +30 -0
- data/lib/duck_test/frame_work/test_unit/base.rb +14 -0
- data/lib/duck_test/frame_work/test_unit/frame_work.rb +33 -0
- data/lib/duck_test/frame_work/watch_config.rb +69 -0
- data/lib/duck_test/gem/helper.rb +107 -0
- data/lib/duck_test/logger.rb +127 -0
- data/lib/duck_test/option_parser.rb +30 -0
- data/lib/duck_test/platforms/base.rb +18 -0
- data/lib/duck_test/platforms/dependencies.rb +18 -0
- data/lib/duck_test/platforms/generic/base.rb +15 -0
- data/lib/duck_test/platforms/generic/listener.rb +104 -0
- data/lib/duck_test/platforms/linux/base.rb +15 -0
- data/lib/duck_test/platforms/linux/listener.rb +76 -0
- data/lib/duck_test/platforms/listener.rb +303 -0
- data/lib/duck_test/platforms/mac/base.rb +15 -0
- data/lib/duck_test/platforms/mac/listener.rb +79 -0
- data/lib/duck_test/platforms/mac/listener.rb.orig +147 -0
- data/lib/duck_test/platforms/os_helper.rb +102 -0
- data/lib/duck_test/platforms/watch_event.rb +47 -0
- data/lib/duck_test/platforms/windows/base.rb +15 -0
- data/lib/duck_test/platforms/windows/listener.rb +123 -0
- data/lib/duck_test/railtie.rb +29 -0
- data/lib/duck_test/usage.rb +34 -0
- data/lib/duck_test/usage.yml +112 -0
- data/lib/duck_test/version.rb +3 -0
- data/lib/duck_test.rb +6 -0
- data/lib/notes.txt +215 -0
- data/lib/tasks/duck_tests.rake +35 -0
- data/lib/tasks/gem_tasks.rake +18 -0
- metadata +92 -0
@@ -0,0 +1,221 @@
|
|
1
|
+
module DuckTest
|
2
|
+
module FrameWork
|
3
|
+
|
4
|
+
# Queue is responsible to managing and triggering events after being notified via a listener.
|
5
|
+
class Queue
|
6
|
+
include DuckTest::ConfigHelper
|
7
|
+
include LoggerHelper
|
8
|
+
|
9
|
+
# Boolean flag used to force the queue to empty and run any pending regardless of the current state of autorun.
|
10
|
+
attr_accessor :force_run
|
11
|
+
|
12
|
+
# Holds the time when a queue event was last triggered. This value is a factor when calculating if the queue should be processed.
|
13
|
+
attr_accessor :last_queue_event
|
14
|
+
|
15
|
+
# Latency is the amount of time that should pass between each time the event queue is processed. The default value is: 0.15, however,
|
16
|
+
# you can use any valid float number. Use this value in conjuction with {#speed} to fine tune the overall behavior of the queue.
|
17
|
+
#
|
18
|
+
# set_latency(10) # wait 10 seconds since the last time the queue event was triggered. Regardless of the setting of {#speed}.
|
19
|
+
#
|
20
|
+
attr_accessor :latency
|
21
|
+
|
22
|
+
# A {http://ruby-doc.org/core-1.9.3/Mutex.html Mutex} used when working on data items related specifically to the Queue.
|
23
|
+
attr_accessor :lock
|
24
|
+
|
25
|
+
# A boolean flag used to determine if it is ok to process and run the set of tests currently in the queue.
|
26
|
+
# Depending on settings and the number of tests being run, the queue loop may need to wait for the queue_event_block to complete it's previous run.
|
27
|
+
# This flag helps control that situation.
|
28
|
+
attr_accessor :ok_to_run
|
29
|
+
|
30
|
+
# An Array representing the list of files that have changed and need to be processed.
|
31
|
+
attr_accessor :queue
|
32
|
+
|
33
|
+
# The block to execute when after the queue has been processed and a list of runnable test files is ready to be run.
|
34
|
+
attr_accessor :queue_event_block
|
35
|
+
|
36
|
+
# A {http://ruby-doc.org/core-1.9.3/Mutex.html Mutex} used when working on data items related specifically executing the queue event.
|
37
|
+
attr_accessor :queue_event_lock
|
38
|
+
|
39
|
+
# A float number indicating how fast the queue should run. The thread processing the queue will sleep for the value set by speed.
|
40
|
+
# The default value is 0.15, however, you can use any valid float number. Use this value in conjuction with {#latency} to fine tune the overall behavior of the queue.
|
41
|
+
# The higher the number, the slower the speed since the thread containing the loop that checks the queue uses speed as the time to sleep between each interation of the loop.
|
42
|
+
#
|
43
|
+
# set_speed(5) # sleep 5 seconds between each interation of the loop.
|
44
|
+
#
|
45
|
+
attr_accessor :speed
|
46
|
+
|
47
|
+
# A boolean indicating if the queue should stop processing and have the thread end it's loop.
|
48
|
+
attr_accessor :stop
|
49
|
+
|
50
|
+
# A reference to the thread object responsible for processing the queue.
|
51
|
+
attr_accessor :thread
|
52
|
+
|
53
|
+
# A running total of the total number of files that have been processed by the queue during the lifetime of a Queue session.
|
54
|
+
attr_accessor :total_ran
|
55
|
+
|
56
|
+
alias :force_run? :force_run
|
57
|
+
alias :ok_to_run? :ok_to_run
|
58
|
+
alias :stop? :stop
|
59
|
+
|
60
|
+
##################################################################################
|
61
|
+
def initialize
|
62
|
+
|
63
|
+
super
|
64
|
+
|
65
|
+
self.force_run = false
|
66
|
+
self.last_queue_event = Time.now
|
67
|
+
self.latency = 0.65
|
68
|
+
self.lock = Mutex.new
|
69
|
+
self.queue = []
|
70
|
+
self.queue_event_block = nil
|
71
|
+
self.queue_event_lock = Mutex.new
|
72
|
+
self.speed = 0.65 #25
|
73
|
+
self.stop = false
|
74
|
+
self.total_ran = 0
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
##################################################################################
|
79
|
+
# Sets the block to execute when the queue has runnable test files ready to be run.
|
80
|
+
# The value of this block is actually set by {FileManager}.
|
81
|
+
# @return [NilClass]
|
82
|
+
def queue_event(&block)
|
83
|
+
if block_given?
|
84
|
+
self.queue_event_block = block
|
85
|
+
self.ok_to_run = true
|
86
|
+
end
|
87
|
+
|
88
|
+
return nil
|
89
|
+
end
|
90
|
+
|
91
|
+
##################################################################################
|
92
|
+
# Executes {#queue_event_block} and passes the list of runnable test files to it.
|
93
|
+
# A thread lock is obtained and {#ok_to_run} is set to false prior to executing the block.
|
94
|
+
# {#ok_to_run} is set back to true after the block completes execution.
|
95
|
+
# @param [Array] list A list of full file specs pointing to runnable test files.
|
96
|
+
# @return [NilClass]
|
97
|
+
def run(list = [])
|
98
|
+
|
99
|
+
self.queue_event_lock.synchronize do
|
100
|
+
|
101
|
+
self.ok_to_run = false
|
102
|
+
|
103
|
+
unless self.queue_event_block.blank?
|
104
|
+
self.queue_event_block.call QueueEvent.new(self, list)
|
105
|
+
end
|
106
|
+
|
107
|
+
self.ok_to_run = true
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
|
114
|
+
##################################################################################
|
115
|
+
# Starts the queue thread which is the controlling body of the Queue class.
|
116
|
+
# @return [NilClass]
|
117
|
+
def start
|
118
|
+
|
119
|
+
self.thread = Thread.new do
|
120
|
+
|
121
|
+
begin
|
122
|
+
|
123
|
+
until self.stop do
|
124
|
+
|
125
|
+
sleep(self.speed)
|
126
|
+
|
127
|
+
if self.autorun? || self.force_run?
|
128
|
+
if self.ok_to_run?
|
129
|
+
buffer = []
|
130
|
+
self.lock.synchronize do
|
131
|
+
self.force_run = false
|
132
|
+
if ((Time.now - self.last_queue_event) >= self.latency)
|
133
|
+
length = self.queue.length
|
134
|
+
length.times {|x| buffer.push(self.queue.pop)}
|
135
|
+
self.total_ran += buffer.length
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
if (buffer.length > 0)
|
140
|
+
self.run(buffer)
|
141
|
+
end
|
142
|
+
else
|
143
|
+
ducklog.console "Waiting on runner. Files in queue: (#{self.queue.length}) Total ran during session: (#{self.total_ran})"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
rescue Exception => e
|
150
|
+
ducklog.exception e
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
return nil
|
156
|
+
end
|
157
|
+
|
158
|
+
##################################################################################
|
159
|
+
# Adds a file_spec to the list of runnable test files that need to be run. It prevents duplicates by
|
160
|
+
# checking to see if the file_spec is already in the queue.
|
161
|
+
# @param [String] file_spec The full file specification of the file or directory on which the event occured.
|
162
|
+
# @return [NilClass]
|
163
|
+
def push(file_spec)
|
164
|
+
|
165
|
+
self.lock.synchronize do
|
166
|
+
|
167
|
+
if self.autorun? && !self.queue.include?(file_spec)
|
168
|
+
self.queue.push(file_spec)
|
169
|
+
end
|
170
|
+
|
171
|
+
self.last_queue_event = Time.now
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
return nil
|
176
|
+
end
|
177
|
+
|
178
|
+
##################################################################################
|
179
|
+
# Safely resets the queue to an empty Array.
|
180
|
+
# @return [NilClass]
|
181
|
+
def reset
|
182
|
+
self.lock.synchronize do
|
183
|
+
self.queue = []
|
184
|
+
end
|
185
|
+
return nil
|
186
|
+
end
|
187
|
+
|
188
|
+
##################################################################################
|
189
|
+
# Safely sets the value of {#speed}
|
190
|
+
# @return [NilClass]
|
191
|
+
def set_speed(value)
|
192
|
+
self.lock.synchronize do
|
193
|
+
self.speed = value unless value.blank?
|
194
|
+
end
|
195
|
+
return nil
|
196
|
+
end
|
197
|
+
|
198
|
+
##################################################################################
|
199
|
+
# Safely sets the value of {#latency}
|
200
|
+
# @return [NilClass]
|
201
|
+
def set_latency(value)
|
202
|
+
self.lock.synchronize do
|
203
|
+
self.latency = value unless value.blank?
|
204
|
+
end
|
205
|
+
return nil
|
206
|
+
end
|
207
|
+
|
208
|
+
##################################################################################
|
209
|
+
# Returns the total number of tests in the queue waiting to run.
|
210
|
+
# @return [Number]
|
211
|
+
def tests_pending
|
212
|
+
value = 0
|
213
|
+
self.lock.synchronize do
|
214
|
+
value = self.queue.length
|
215
|
+
end
|
216
|
+
return value
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DuckTest
|
2
|
+
module FrameWork
|
3
|
+
|
4
|
+
# A QueueEvent is triggered when directories / files have changed and contains a list of the files that have changed.
|
5
|
+
class QueueEvent
|
6
|
+
|
7
|
+
# See {#initialize}
|
8
|
+
attr_accessor :source
|
9
|
+
|
10
|
+
# See {#initialize}
|
11
|
+
attr_accessor :files
|
12
|
+
|
13
|
+
##################################################################################
|
14
|
+
# Initialize a new QueueEvent
|
15
|
+
# @param [Object] source A reference to the calling object.
|
16
|
+
# @param [Array] files A list of files that have changed and require action.
|
17
|
+
# @return [QueueEvent]
|
18
|
+
def initialize(source, files)
|
19
|
+
super()
|
20
|
+
|
21
|
+
self.source = source
|
22
|
+
self.files = files.uniq
|
23
|
+
|
24
|
+
return self
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DuckTest
|
2
|
+
module FrameWork
|
3
|
+
module RSpec
|
4
|
+
|
5
|
+
# Testing Framework for RSpec
|
6
|
+
class FrameWork < DuckTest::FrameWork::Base
|
7
|
+
|
8
|
+
##################################################################################
|
9
|
+
# This is a hack to override run_fork in order to set the rspec global variable rspec_start_time.
|
10
|
+
# The report at the end of the run of the specs was reporting incorrect duration since rspec_start_time
|
11
|
+
# is set when the gem loads. This is a good place to start looking if incorrect results start happenning again.
|
12
|
+
def run_fork(non_runnable_files, runnable_files, force_run = false)
|
13
|
+
$rspec_start_time = Time.now
|
14
|
+
super(non_runnable_files, runnable_files, force_run)
|
15
|
+
end
|
16
|
+
|
17
|
+
##################################################################################
|
18
|
+
# Does the work of actually running the tests.
|
19
|
+
def run_tests
|
20
|
+
|
21
|
+
::RSpec::Core::Runner.run([])
|
22
|
+
|
23
|
+
puts ::IRB.CurrentContext.io.prompt
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DuckTest
|
2
|
+
module FrameWork
|
3
|
+
module TestUnit
|
4
|
+
|
5
|
+
##################################################################################
|
6
|
+
# FrameWork for running Test::Unit tests
|
7
|
+
class FrameWork < DuckTest::FrameWork::Base
|
8
|
+
|
9
|
+
##################################################################################
|
10
|
+
# Does the work of actually running the tests.
|
11
|
+
def run_tests
|
12
|
+
|
13
|
+
if defined?(::Test::Unit::Runner)
|
14
|
+
ducklog.console "Running tests using: Test::Unit::Runner"
|
15
|
+
::Test::Unit::Runner.new.run([])
|
16
|
+
|
17
|
+
elsif defined?(::MiniTest::Unit)
|
18
|
+
ducklog.console "Running tests using: MiniTest::Unit"
|
19
|
+
::MiniTest::Unit.new.run([])
|
20
|
+
|
21
|
+
else
|
22
|
+
ducklog.console "Cannot run tests. Unable to determine which test runner to use."
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
puts ::IRB.CurrentContext.io.prompt
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module DuckTest
|
2
|
+
module FrameWork
|
3
|
+
|
4
|
+
|
5
|
+
# A WatchConfig represents a single watch definition including attributes such as pattern, filter sets, mappings, etc.
|
6
|
+
#
|
7
|
+
# DuckTest.config do
|
8
|
+
#
|
9
|
+
# runnable "**/*" # this would represent a WatchConfig object.
|
10
|
+
#
|
11
|
+
# end
|
12
|
+
class WatchConfig
|
13
|
+
include DuckTest::ConfigHelper
|
14
|
+
|
15
|
+
# See {DuckTest::ConfigHelper#autorun}
|
16
|
+
attr_accessor :autorun
|
17
|
+
|
18
|
+
# See {#initialize}
|
19
|
+
attr_accessor :filter_set
|
20
|
+
|
21
|
+
# See {#initialize}
|
22
|
+
attr_accessor :maps
|
23
|
+
|
24
|
+
# See {#initialize}
|
25
|
+
attr_accessor :pattern
|
26
|
+
|
27
|
+
# See {#initialize}
|
28
|
+
attr_accessor :runnable
|
29
|
+
|
30
|
+
alias :autorun? :autorun
|
31
|
+
alias :runnable? :runnable
|
32
|
+
|
33
|
+
##################################################################################
|
34
|
+
# Initialize a new WatchConfig
|
35
|
+
# @param [Hash] options An options Hash containing values used to initialize the object.
|
36
|
+
# @option options [Symbol] :autorun See {DuckTest::ConfigHelper#autorun}
|
37
|
+
# @option options [String] :watch_basedir See {DuckTest::ConfigHelper#watch_basedir}
|
38
|
+
# @option options [DuckTest::FrameWork::FilterSet] :filter_set See {DuckTest::FrameWork::FilterSet}
|
39
|
+
# @option options [Array] :maps See {DuckTest::FrameWork::Map}
|
40
|
+
# @option options [String] :pattern See {DuckTest::Config#watch}
|
41
|
+
# @option options [Boolean] :runnable Boolean indicating if the files watch by this WatchConfig are runnable test files.
|
42
|
+
# @option options [String] :runnable_basedir See {DuckTest::ConfigHelper#runnable_basedir}
|
43
|
+
# @return [WatchConfig]
|
44
|
+
def initialize(options = {})
|
45
|
+
super()
|
46
|
+
|
47
|
+
self.autorun = options[:autorun]
|
48
|
+
self.autorun = false if self.autorun.nil?
|
49
|
+
|
50
|
+
self.watch_basedir = options[:watch_basedir]
|
51
|
+
|
52
|
+
self.filter_set = options[:filter_set] unless options[:filter_set].blank?
|
53
|
+
self.filter_set = FilterSet.new(options) if self.filter_set.blank?
|
54
|
+
|
55
|
+
self.maps = options[:maps] unless options[:maps].blank?
|
56
|
+
self.maps = [] if self.maps.blank?
|
57
|
+
|
58
|
+
self.pattern = options[:pattern]
|
59
|
+
self.runnable = options[:runnable]
|
60
|
+
self.runnable = false if self.runnable.nil?
|
61
|
+
|
62
|
+
self.runnable_basedir = options[:runnable_basedir]
|
63
|
+
|
64
|
+
return self
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# once upon a time, I had a series of tasks and gemspecs to build different versions for different platforms.
|
2
|
+
# I made a decision to adandon all of those different gems and simply notify the developer to edit their Gemfile.
|
3
|
+
# however, i kept this code in case i need to go back down that path...
|
4
|
+
require "yaml"
|
5
|
+
|
6
|
+
module DuckTest
|
7
|
+
# ...
|
8
|
+
module Gem
|
9
|
+
|
10
|
+
##################################################################################
|
11
|
+
# ...
|
12
|
+
class Helper
|
13
|
+
|
14
|
+
##################################################################################
|
15
|
+
# ...
|
16
|
+
def initialize
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
##################################################################################
|
21
|
+
# ...
|
22
|
+
def base_dir
|
23
|
+
@base_dir ||= File.expand_path(".")
|
24
|
+
return @base_dir
|
25
|
+
end
|
26
|
+
|
27
|
+
# ...
|
28
|
+
def base_dir=(value)
|
29
|
+
@base_dir = File.expand_path(value)
|
30
|
+
end
|
31
|
+
|
32
|
+
##################################################################################
|
33
|
+
# ...
|
34
|
+
def output_gem_spec(name, pkg = "")
|
35
|
+
Dir[File.join(self.base_dir, pkg, "#{name}*.gem")].sort_by{|f| File.mtime(f)}.last
|
36
|
+
end
|
37
|
+
|
38
|
+
##################################################################################
|
39
|
+
# ...
|
40
|
+
def build(gem_spec, output_gem_spec)
|
41
|
+
%x(gem build -V '#{gem_spec}.gemspec')
|
42
|
+
output_file_spec = self.output_gem_spec(output_gem_spec)
|
43
|
+
file_name = File.basename(output_file_spec)
|
44
|
+
FileUtils.mkdir_p(File.join(self.base_dir, 'pkg'))
|
45
|
+
FileUtils.mv(output_file_spec, 'pkg')
|
46
|
+
puts "#{file_name} built to pkg/#{file_name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
##################################################################################
|
50
|
+
# ...
|
51
|
+
def install(gem_spec, output_gem_spec)
|
52
|
+
self.build(gem_spec, output_gem_spec)
|
53
|
+
output_file_spec = self.output_gem_spec(output_gem_spec, "pkg")
|
54
|
+
puts "Installing gem: #{output_file_spec}"
|
55
|
+
%x(gem install '#{output_file_spec}')
|
56
|
+
puts " Install complete."
|
57
|
+
end
|
58
|
+
|
59
|
+
##################################################################################
|
60
|
+
# ...
|
61
|
+
def release(gem_spec, output_gem_spec)
|
62
|
+
if File.exist?(File.expand_path("~/.gem/credentials"))
|
63
|
+
self.build(gem_spec, output_gem_spec)
|
64
|
+
output_file_spec = self.output_gem_spec(output_gem_spec, "pkg")
|
65
|
+
puts "Releasing gem: #{output_file_spec}"
|
66
|
+
%x(gem push '#{output_file_spec}')
|
67
|
+
puts " Release complete."
|
68
|
+
else
|
69
|
+
raise "Your rubygems.org credentials aren't set. Run `gem push` to set them."
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
##################################################################################
|
74
|
+
# ...
|
75
|
+
def local(gem_spec, output_gem_spec)
|
76
|
+
config_file_spec = File.expand_path("~/.gem/gemserverlocal")
|
77
|
+
|
78
|
+
if File.exist?(config_file_spec)
|
79
|
+
|
80
|
+
yaml = YAML.load_file(config_file_spec)
|
81
|
+
|
82
|
+
if yaml && yaml["path"]
|
83
|
+
|
84
|
+
path = yaml["path"]
|
85
|
+
|
86
|
+
self.build(gem_spec, output_gem_spec)
|
87
|
+
output_file_spec = self.output_gem_spec(output_gem_spec, 'pkg')
|
88
|
+
|
89
|
+
puts "Locally releasing gem: #{output_file_spec}"
|
90
|
+
FileUtils.mkdir_p(File.join(path, 'gems'))
|
91
|
+
FileUtils.cp(output_file_spec, File.join(path, 'gems'))
|
92
|
+
|
93
|
+
%x(gem generate_index --directory #{path})
|
94
|
+
puts " Local release complete."
|
95
|
+
|
96
|
+
else
|
97
|
+
raise "~/.gem/gemserverlocal file exists, however, path: /path/to/repo is missing. please add a path to the root of a local gem server"
|
98
|
+
end
|
99
|
+
else
|
100
|
+
raise "~/.gem/gemserverlocal file is missing. Please create the file and include path: /path/to/repo to the root of a local gem server"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module DuckTest
|
2
|
+
|
3
|
+
# Conveinence methods providing access to the Logger class.
|
4
|
+
module LoggerHelper
|
5
|
+
# ...
|
6
|
+
def ducklog
|
7
|
+
return Logger.ducklog
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Custom Logger
|
12
|
+
class Logger < ActiveSupport::BufferedLogger
|
13
|
+
|
14
|
+
SYSTEM = 6
|
15
|
+
|
16
|
+
##################################################################################
|
17
|
+
# Instance of DuckTest::Logger
|
18
|
+
def self.ducklog
|
19
|
+
dir = defined?(Rails) ? Rails.root : "."
|
20
|
+
return @@ducklog ||= self.new("#{dir}/log/ducktest.log", INFO)
|
21
|
+
end
|
22
|
+
|
23
|
+
##################################################################################
|
24
|
+
# Converts a Symbol to a valid log level and vise versa.
|
25
|
+
# @return [Object] The return value is based on the argument :key.
|
26
|
+
# - If you pass a Symbol, you get a log level.
|
27
|
+
# - If you pass a log level, you get a Symbol.
|
28
|
+
def self.to_severity(key)
|
29
|
+
values = {debug: DEBUG, info: INFO, warn: WARN, error: ERROR, fatal: FATAL, unknown: UNKNOWN, system: SYSTEM}
|
30
|
+
value = values.map.find {|value| value[key.kind_of?(Symbol) ? 0 : 1].eql?(key)}
|
31
|
+
return value.blank? ? nil : value[key.kind_of?(Symbol) ? 1 : 0]
|
32
|
+
end
|
33
|
+
|
34
|
+
##################################################################################
|
35
|
+
# Sets the logging level for the ducklog.
|
36
|
+
# @param [Symbol, Number] key A value representing the desired logging level. Can be a Symbol such as :debug, :info, etc.
|
37
|
+
# or an ActiveSupport::BufferedLogger Constant DEBUG, INFO, etc.
|
38
|
+
# @return [Number]
|
39
|
+
def self.log_level=(key)
|
40
|
+
key = key.blank? ? "" : key.to_sym
|
41
|
+
value = self.to_severity(key)
|
42
|
+
|
43
|
+
unless value.blank?
|
44
|
+
@@log_level = value
|
45
|
+
value = value.eql?(SYSTEM) ? DEBUG : value
|
46
|
+
self.ducklog.level = value
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
##################################################################################
|
52
|
+
# Gets the current logging level for the ducklog.
|
53
|
+
# @return [Number]
|
54
|
+
def self.log_level
|
55
|
+
@@log_level ||= self.ducklog.level
|
56
|
+
return @@log_level
|
57
|
+
end
|
58
|
+
|
59
|
+
##################################################################################
|
60
|
+
# ...
|
61
|
+
def console(msg = nil, progname = nil, &block)
|
62
|
+
STDOUT.puts msg
|
63
|
+
add(INFO, "#{Config.framework_name.to_s.rjust(15)}: #{msg}", progname, &block)
|
64
|
+
return nil
|
65
|
+
end
|
66
|
+
|
67
|
+
##################################################################################
|
68
|
+
# ...
|
69
|
+
def exception(exception, progname = nil, &block)
|
70
|
+
STDOUT.puts %(ERROR!! ducktest.log for: #{exception})
|
71
|
+
#if self.class.log_level.eql?(DEBUG)
|
72
|
+
exception.backtrace.each {|x| STDOUT.puts x}
|
73
|
+
#end
|
74
|
+
add(ERROR, "#{Config.framework_name.to_s.rjust(15)}: #{exception.to_s}", progname, &block)
|
75
|
+
exception.backtrace.each {|x| add(ERROR, x, progname, &block)}
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
##################################################################################
|
80
|
+
# ...
|
81
|
+
def debug(msg = nil, progname = nil, &block)
|
82
|
+
add(DEBUG, "#{Config.framework_name.to_s.rjust(15)}: #{msg}", progname, &block)
|
83
|
+
return nil
|
84
|
+
end
|
85
|
+
|
86
|
+
##################################################################################
|
87
|
+
# ...
|
88
|
+
def info(msg = nil, progname = nil, &block)
|
89
|
+
add(INFO, "#{Config.framework_name.to_s.rjust(15)}: #{msg}", progname, &block)
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
|
93
|
+
##################################################################################
|
94
|
+
# ...
|
95
|
+
def system(msg = nil, progname = nil, &block)
|
96
|
+
if self.class.log_level.eql?(SYSTEM)
|
97
|
+
add(DEBUG, "#{Config.framework_name.to_s.rjust(15)}: #{msg}", progname, &block)
|
98
|
+
end
|
99
|
+
return nil
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# could be useful for adding colored logging later.
|
106
|
+
# CLEAR = "\e[0m"
|
107
|
+
# BOLD = "\e[1m"
|
108
|
+
#
|
109
|
+
# # Colors
|
110
|
+
# BLACK = "\e[30m"
|
111
|
+
# RED = "\e[31m"
|
112
|
+
# GREEN = "\e[32m"
|
113
|
+
# YELLOW = "\e[33m"
|
114
|
+
# BLUE = "\e[34m"
|
115
|
+
# MAGENTA = "\e[35m"
|
116
|
+
# CYAN = "\e[36m"
|
117
|
+
# WHITE = "\e[37m"
|
118
|
+
#
|
119
|
+
# #############################################################################################
|
120
|
+
# def color(text, color, bold=false)
|
121
|
+
# color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
122
|
+
# bold = bold ? BOLD : ""
|
123
|
+
# return "#{bold}#{color}#{text}#{CLEAR}"
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# puts "Database Name: #{color(database, CYAN, true)}"
|
127
|
+
# puts " User Name: #{color(user_name, CYAN, true)}"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# this is unfinished code that was not implemented
|
2
|
+
# the original idea was to alter OptionParser class to grab and remove
|
3
|
+
# arguments from the CLI prior to the console loading fully as it will
|
4
|
+
# puke with an error if a user passes invalid arguments.
|
5
|
+
# the desire was to somehow grab a CLI arg from a user and set the session
|
6
|
+
# to load while still allowing the user to use the standard rails command
|
7
|
+
|
8
|
+
# like: rails c test
|
9
|
+
|
10
|
+
# i would have like to do something like: rails c test --duck=rspec
|
11
|
+
|
12
|
+
# then, remove the argument from ARGV and let rails c test continue
|
13
|
+
# the test of the idea actually worked, however, i never actually coded a solution, because,
|
14
|
+
# i thought it might make the gem to brittle to use. I may decide to implement it at a later
|
15
|
+
# date after more thought. for now, the current solution was to simply create an executable
|
16
|
+
# that grabs the args and fire up the console.
|
17
|
+
|
18
|
+
# class OptionParser
|
19
|
+
#
|
20
|
+
# alias_method :my_parse!, :parse!
|
21
|
+
#
|
22
|
+
# def parse!(x)
|
23
|
+
#
|
24
|
+
# value = ARGV.find {|item| item =~ /^--duck/ || item =~ /^-duck/}
|
25
|
+
# ARGV.delete_if {|item| item =~ /^--duck/ || item =~ /^-duck/}
|
26
|
+
#
|
27
|
+
# my_parse!(x)
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# end
|