Module: Stud
- Extended by:
- Stud
- Included in:
- Stud
- Defined in:
- lib/stud/secret.rb,
lib/stud/try.rb,
lib/stud/pool.rb,
lib/stud/task.rb,
lib/stud/trap.rb,
lib/stud/with.rb,
lib/stud/buffer.rb,
lib/stud/interval.rb,
lib/stud/temporary.rb
Overview
A class for holding a secret. The main goal is to prevent the common mistake of accidentally logging or printing passwords or other secrets.
See <github.com/jordansissel/software-patterns/blob/master/dont-log-secrets/ruby/> for a discussion of why this implementation is useful.
Defined Under Namespace
Modules: Buffer, Temporary, With Classes: Pool, Secret, Task, Try
Constant Summary collapse
- TRY =
class Stud::Try
Try.new
Class Method Summary collapse
-
.interval(time, opts = {}, &block) ⇒ Object
This implementation tries to keep clock more accurately.
-
.simulate_signal(signal) ⇒ Object
Simulate a signal.
-
.sleep_for_interval(time, start) ⇒ Object
def interval.
-
.trap(signal, &block) ⇒ Object
Bind a block to be called when a certain signal is received.
-
.untrap(signal, id) ⇒ Object
Remove a previously set signal trap.
Instance Method Summary collapse
- #interval(time, opts = {}, &block) ⇒ Object
-
#try(enumerable = Stud::Try::FOREVER, &block) ⇒ Object
A simple try method for the common case.
Class Method Details
.interval(time, opts = {}, &block) ⇒ Object
This implementation tries to keep clock more accurately. Prior implementations still permitted skew, where as this one will attempt to correct for skew.
The execution patterns of this method should be that the start time of ‘block.call’ should always be at time T*interval
9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/stud/interval.rb', line 9 def self.interval(time, opts = {}, &block) start = Time.now while true break if Task.interrupted? if opts[:sleep_then_run] start = sleep_for_interval(time, start) block.call else block.call start = sleep_for_interval(time, start) end end # loop forever end |
.simulate_signal(signal) ⇒ Object
Simulate a signal. This lets you force an interrupt without sending a signal to yourself.
44 45 46 47 |
# File 'lib/stud/trap.rb', line 44 def self.simulate_signal(signal) #puts "Simulate: #{signal} w/ #{@traps[signal].count} callbacks" @traps[signal].each(&:call) end |
.sleep_for_interval(time, start) ⇒ Object
def interval
23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/stud/interval.rb', line 23 def self.sleep_for_interval(time, start) duration = Time.now - start # Sleep only if the duration was less than the time interval if duration < time sleep(time - duration) start += time else # Duration exceeded interval time, reset the clock and do not sleep. start = Time.now end end |
.trap(signal, &block) ⇒ Object
Bind a block to be called when a certain signal is received.
Same arguments to Signal::trap.
The behavior of this method is different than Signal::trap because multiple handlers can request notification for the same signal.
For example, this is valid:
Stud.trap("INT") { puts "Hello" }
Stud.trap("INT") { puts "World" }
When SIGINT is received, both callbacks will be invoked, in order.
This helps avoid the situation where a library traps a signal outside of your control.
If something has already used Signal::trap, that callback will be saved and scheduled the same way as any other Stud::trap.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/stud/trap.rb', line 21 def self.trap(signal, &block) @traps ||= Hash.new { |h,k| h[k] = [] } if !@traps.include?(signal) # First trap call for this signal, tell ruby to invoke us. previous_trap = Signal::trap(signal) { simulate_signal(signal) } # If there was a previous trap (via Kernel#trap) set, make sure we remember it. if previous_trap.is_a?(Proc) # MRI's default traps are "DEFAULT" string # JRuby's default traps are Procs with a source_location of "(internal") if RUBY_ENGINE != "jruby" || previous_trap.source_location.first != "(internal)" @traps[signal] << previous_trap end end end @traps[signal] << block return block.object_id end |
.untrap(signal, id) ⇒ Object
Remove a previously set signal trap.
‘signal’ is the name of the signal (“INT”, etc) ‘id’ is the value returned by a previous Stud.trap() call
53 54 55 56 57 58 59 60 61 |
# File 'lib/stud/trap.rb', line 53 def self.untrap(signal, id) @traps[signal].delete_if { |block| block.object_id == id } # Restore the default handler if there are no custom traps anymore. if @traps[signal].empty? @traps.delete(signal) Signal::trap(signal, "DEFAULT") end end |
Instance Method Details
#interval(time, opts = {}, &block) ⇒ Object
35 36 37 |
# File 'lib/stud/interval.rb', line 35 def interval(time, opts = {}, &block) return Stud.interval(time, opts, &block) end |
#try(enumerable = Stud::Try::FOREVER, &block) ⇒ Object
A simple try method for the common case.
118 119 120 |
# File 'lib/stud/try.rb', line 118 def try(enumerable=Stud::Try::FOREVER, &block) return TRY.try(enumerable, &block) end |