class Observr::Script

A script object wraps a script file, and is used by a controller.

@example

path   = Pathname.new('specs.observr')
script = Observr::Script.new(path)

Constants

DEFAULT_EVENT_TYPE

@private

Rule

Convenience type. Provides clearer and simpler access to rule properties.

@example

rule = script.watch('lib/.*\.rb') { 'ohaie' }
rule.pattern      #=> 'lib/.*\.rb'
rule.action.call  #=> 'ohaie'

Attributes

ec[R]

EvalContext instance

@example

script.ec.watch('pattern') { }
script.ec.reload

@return [EvalContext]

rules[R]

Defined rules

@return [Rule]

all rules defined with `#watch` calls

Public Class Methods

new(path = nil) click to toggle source

Create a Script object for script at ‘path`

@param [Pathname] path

the path to the script
# File lib/observr/script.rb, line 77
def initialize(path = nil)
  @path = path
  @rules = []
  @default_action = Proc.new {}
  @ec = EvalContext.new(self)
end

Public Instance Methods

action_for(path, event_type = DEFAULT_EVENT_TYPE) click to toggle source

Find an action corresponding to a path and event type. The returned action is actually a wrapper around the rule’s action, with the match_data prepopulated.

@example

script.watch( 'test/test_.*\.rb' ) {|md| "ruby #{md[0]}" }
script.action_for('test/test_observr.rb').call #=> "ruby test/test_observr.rb"

@param [Pathname, String] path

find action that corresponds to this path.

@param [Symbol] event_type

find action only if rule's event is of this type.

@return [Proc]

action, preparsed and ready to be called
# File lib/observr/script.rb, line 200
def action_for(path, event_type = DEFAULT_EVENT_TYPE)
  path = rel_path(path).to_s
  rule = rules_for(path).detect {|rule| rule.event_type.nil? || rule.event_type == event_type }
  if rule
    data = path.match(rule.pattern)
    lambda { rule.action.call(data) }
  else
    lambda {}
  end
end
default_action(&action) click to toggle source

Convenience method. Define a default action to be triggered when a rule has none specified. When called without a block, acts as a getter and returns stored default_action

@example

# in script file

default_action { system('rake --silent yard') }

watch( 'lib/.*\.rb'  )
watch( 'README.md'   )
watch( 'TODO.txt'    )
watch( 'LICENSE'     )

# is equivalent to:

watch( 'lib/.*\.rb'  ) { system('rake --silent yard') }
watch( 'README.md'   ) { system('rake --silent yard') }
watch( 'TODO.txt'    ) { system('rake --silent yard') }
watch( 'LICENSE'     ) { system('rake --silent yard') }

@return [Proc]

default action
# File lib/observr/script.rb, line 157
def default_action(&action)
  @default_action = action if action
  @default_action
end
parse!() click to toggle source

Eval content of script file.

@todo improve ENOENT error handling

# File lib/observr/script.rb, line 171
def parse!
  return unless @path
  reset
  @ec.instance_eval(@path.read, @path.to_s)
rescue Errno::ENOENT
  sleep(0.3) #enough?
  retry
ensure
  Observr.debug('loaded script file %s' % @path.to_s.inspect)
end
path() click to toggle source

Path to the script file corresponding to this object

@return [Pathname]

absolute path to script file
# File lib/observr/script.rb, line 226
def path
  @path && Pathname(@path.respond_to?(:to_path) ? @path.to_path : @path.to_s).expand_path
end
patterns() click to toggle source

Collection of all patterns defined in script.

@return [Array<String,Regexp>]

all defined patterns
# File lib/observr/script.rb, line 216
def patterns
  #@rules.every.pattern
  @rules.map {|r| r.pattern }
end
reset() click to toggle source

Reset script state

# File lib/observr/script.rb, line 163
def reset
  @rules = []
  @default_action = Proc.new {}
end
watch(pattern, event_type = DEFAULT_EVENT_TYPE, &action) click to toggle source

Main script API method. Builds a new rule, binding a pattern to an action.

Whenever a file is saved that matches a rule’s ‘pattern`, its corresponding `action` is triggered.

Patterns can be either a Regexp or a string. Because they always represent paths however, it’s simpler to use strings. But remember to use single quotes (not double quotes), otherwise escape sequences will be parsed (for example ‘“foo/bar.rb” #=> “foo/bar.rb”`, notice “.” becomes “.”), and won’t be interpreted as the regexp you expect.

Also note that patterns will be matched against relative paths (relative to current working directory).

Actions, the blocks passed to ‘watch`, receive a `MatchData` object as argument. It will be populated with the whole matched string ( `md` ) as well as individual backreferences ( `md` ). See `MatchData#[]` documentation for more details.

@example

# in script file
watch( 'test/test_.*\.rb' )  {|md| system("ruby #{md[0]}") }
watch( 'lib/(.*)\.rb' )      {|md| system("ruby test/test_#{md[1]}.rb") }

With these two rules, observr will run any test file whenever it is itself changed (first rule), and will also run a corresponding test file whenever a lib file is changed (second rule).

@param [#match] pattern

pattern to match targetted paths

@param [Symbol] event_type

rule will only match events of this type. Accepted types are
`:accessed`, `:modified`, `:changed`, `:delete` and `nil` (any), where
the first three correspond to atime, mtime and ctime respectively.
Defaults to `:modified`.

@yield

action to trigger

@return [Rule]

# File lib/observr/script.rb, line 127
def watch(pattern, event_type = DEFAULT_EVENT_TYPE, &action)
  @rules << Rule.new(pattern, event_type, action || @default_action)
  @rules.last
end

Private Instance Methods

rel_path(path) click to toggle source

Make a path relative to current working directory.

@param [Pathname, String] path

absolute or relative path

@return [Pathname]

relative path, from current working directory.
# File lib/observr/script.rb, line 253
def rel_path(path)
  Pathname(path).expand_path.relative_path_from(Pathname(Dir.pwd))
end
rules_for(path) click to toggle source

Rules corresponding to a given path, in reversed order of precedence (latest one is most inportant).

@param [Pathname, String] path

path to look up rule for

@return [Array<Rule>]

rules corresponding to `path`
# File lib/observr/script.rb, line 241
def rules_for(path)
  @rules.reverse.select {|rule| path.match(rule.pattern) }
end