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

Instance Method Summary collapse

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, exceptions = Try::DEFAULT_CATCHABLE_EXCEPTIONS, &block) ⇒ Object

A simple try method for the common case.



122
123
124
# File 'lib/stud/try.rb', line 122

def try(enumerable=Stud::Try::FOREVER, exceptions=Try::DEFAULT_CATCHABLE_EXCEPTIONS, &block)
  return TRY.try(enumerable, exceptions, &block)
end