Class: Ruote::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/ruote/context.rb

Overview

A sort of internal registry, via a shared instance of this class, the worker and the engine can access subservices like reader, treechecker, wfid_generator and so on.

Direct Known Subclasses

TestContext

Constant Summary collapse

SERVICE_PREFIX =
/^s\_/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(storage) ⇒ Context

Returns a new instance of Context


42
43
44
45
46
47
48
49
50
51
# File 'lib/ruote/context.rb', line 42

def initialize(storage)

  @storage = storage
  @storage.context = self

  @dashboard = nil

  @services = {}
  initialize_services
end

Instance Attribute Details

#dashboardObject Also known as: engine

Returns the value of attribute dashboard


40
41
42
# File 'lib/ruote/context.rb', line 40

def dashboard
  @dashboard
end

#storageObject (readonly)

Returns the value of attribute storage


39
40
41
# File 'lib/ruote/context.rb', line 39

def storage
  @storage
end

Instance Method Details

#[](key) ⇒ Object

Used for things like

if @context['ruby_eval_allowed']
  # ...
end

93
94
95
96
97
98
99
100
# File 'lib/ruote/context.rb', line 93

def [](key)

  if SERVICE_PREFIX.match(key)
    @services[key]
  else
    conf[key]
  end
end

#[]=(key, value) ⇒ Object

Mostly used by engine#configure

Raises:

  • (ArgumentError)

104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ruote/context.rb', line 104

def []=(key, value)

  raise(
    ArgumentError.new('use context#add_service to register services')
  ) if SERVICE_PREFIX.match(key)

  @storage.put(conf.merge(key => value))
    # TODO blindly trust the put ? retry in case of failure ?

  value
end

#add_service(key, *args) ⇒ Object

Called by Ruote::Dashboard#add_service

Raises:

  • (ArgumentError)

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ruote/context.rb', line 125

def add_service(key, *args)

  raise ArgumentError.new(
    '#add_service: at least two arguments please'
  ) if args.empty?

  key = key.to_s
  path, klass, opts = args

  key = "s_#{key}" unless SERVICE_PREFIX.match(key)

  aa = [ self, opts ].compact

  service = if klass

    require(path)

    @services[key] = Ruote.constantize(klass).new(*aa)

  elsif path.is_a?(Class)

    @services[key] = path.new(*aa)

  else

    @services[key] = path
  end

  (class << self; self; end).class_eval(
    %{ def #{key[2..-1]}; @services['#{key}']; end })
      #
      # This 'two-liner' will add an instance method to Context for this
      # service.
      #
      # If the service key is 's_dishwasher', then the service will be
      # available via Context#dishwasher.
      #
      # I.e. dishwasher = engine.context.dishwasher

  service
end

#contextObject

A trick : in order to avoid

@context = o.respond_to?(:context) ? o.context : o
# or
#@context = o.is_a?(Ruote::Context) ? o : o.context

simply letting a context say its context is itself.


61
62
63
64
# File 'lib/ruote/context.rb', line 61

def context

  self
end

#engine_idObject

Returns the engine_id (as set in the configuration under the key “engine_id”), or, by default, “engine”.


82
83
84
85
# File 'lib/ruote/context.rb', line 82

def engine_id

  conf['engine_id'] || 'engine'
end

#has_service?(service_name) ⇒ Boolean

Returns true if this context has a given service registered.

Returns:

  • (Boolean)

216
217
218
219
220
221
222
# File 'lib/ruote/context.rb', line 216

def has_service?(service_name)

  service_name = service_name.to_s
  service_name = "s_#{service_name}" if ! SERVICE_PREFIX.match(service_name)

  @services.has_key?(service_name)
end

#keysObject

Configuration keys and service keys.


118
119
120
121
# File 'lib/ruote/context.rb', line 118

def keys

  (@services.keys + conf.keys).uniq.sort
end

#notify(msg) ⇒ Object

This method is called by the worker each time it sucessfully processed a msg. This method calls in turn the #on_msg method for each of the services (that respond to that method).

Makes sure that observers that respond to #wait_for are called last.


189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/ruote/context.rb', line 189

def notify(msg)

  waiters, observers = @services.select { |n, s|
    s.respond_to?(:on_msg)
  }.sort_by { |n, s|
    n
  }.partition { |n, s|
    s.respond_to?(:wait_for)
  }

  (observers + waiters).each { |n, s| s.on_msg(msg) }
end

#pre_notify(msg) ⇒ Object

This is kind of evil. Notifies services responding to #on_pre_msg with the msg before it gets processed.

Might be useful in some cases. Use with great care.


172
173
174
175
176
177
178
179
180
181
# File 'lib/ruote/context.rb', line 172

def pre_notify(msg)

  @services.select { |n, s|
    s.respond_to?(:on_pre_msg)
  }.sort_by { |n, s|
    n
  }.each { |n, s|
    s.on_pre_msg(msg)
  }
end

#servicesObject

List of services in this context, sorted by their name in alphabetical order.


227
228
229
230
# File 'lib/ruote/context.rb', line 227

def services

  @services.keys.sort.collect { |k| @services[k] }
end

#shutdownObject

Takes care of shutting down every service registered in this context.


204
205
206
207
208
209
# File 'lib/ruote/context.rb', line 204

def shutdown

  ([ @storage ] + @services.values).each do |s|
    s.shutdown if s.respond_to?(:shutdown)
  end
end

#workerObject

Let's make sure Context always responds to #storage, #dashboard (#engine) and #worker.


74
75
76
77
# File 'lib/ruote/context.rb', line 74

def worker

  @services['s_worker']
end