sanford 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/README.md +41 -56
- data/Rakefile +0 -1
- data/bench/client.rb +8 -3
- data/bench/{services.rb → config.sanford} +11 -6
- data/bench/{runner.rb → report.rb} +2 -2
- data/bench/report.txt +32 -32
- data/lib/sanford/cli.rb +42 -28
- data/lib/sanford/config_file.rb +79 -0
- data/lib/sanford/{worker.rb → connection_handler.rb} +28 -20
- data/lib/sanford/error_handler.rb +7 -7
- data/lib/sanford/pid_file.rb +42 -0
- data/lib/sanford/process.rb +136 -0
- data/lib/sanford/process_signal.rb +20 -0
- data/lib/sanford/route.rb +48 -0
- data/lib/sanford/router.rb +36 -0
- data/lib/sanford/runner.rb +30 -58
- data/lib/sanford/sanford_runner.rb +19 -9
- data/lib/sanford/server.rb +211 -42
- data/lib/sanford/server_data.rb +47 -0
- data/lib/sanford/service_handler.rb +8 -46
- data/lib/sanford/template_source.rb +19 -2
- data/lib/sanford/test_runner.rb +27 -28
- data/lib/sanford/version.rb +1 -1
- data/lib/sanford.rb +1 -23
- data/sanford.gemspec +4 -5
- data/test/helper.rb +3 -20
- data/test/support/app_server.rb +142 -0
- data/test/support/config.sanford +7 -0
- data/test/support/config_invalid_run.sanford +3 -0
- data/test/support/config_no_run.sanford +0 -0
- data/test/support/fake_server_connection.rb +58 -0
- data/test/support/pid_file_spy.rb +19 -0
- data/test/support/template.erb +1 -0
- data/test/system/server_tests.rb +378 -0
- data/test/system/service_handler_tests.rb +224 -0
- data/test/unit/cli_tests.rb +187 -0
- data/test/unit/config_file_tests.rb +59 -0
- data/test/unit/connection_handler_tests.rb +254 -0
- data/test/unit/error_handler_tests.rb +30 -35
- data/test/unit/pid_file_tests.rb +70 -0
- data/test/unit/process_signal_tests.rb +61 -0
- data/test/unit/process_tests.rb +428 -0
- data/test/unit/route_tests.rb +92 -0
- data/test/unit/router_tests.rb +65 -0
- data/test/unit/runner_tests.rb +61 -15
- data/test/unit/sanford_runner_tests.rb +162 -28
- data/test/unit/sanford_tests.rb +0 -8
- data/test/unit/server_data_tests.rb +87 -0
- data/test/unit/server_tests.rb +502 -21
- data/test/unit/service_handler_tests.rb +114 -219
- data/test/unit/template_engine_tests.rb +1 -1
- data/test/unit/template_source_tests.rb +56 -16
- data/test/unit/test_runner_tests.rb +206 -0
- metadata +67 -67
- data/bench/tasks.rb +0 -41
- data/lib/sanford/config.rb +0 -28
- data/lib/sanford/host.rb +0 -129
- data/lib/sanford/host_data.rb +0 -65
- data/lib/sanford/hosts.rb +0 -38
- data/lib/sanford/manager.rb +0 -275
- data/test/support/fake_connection.rb +0 -36
- data/test/support/helpers.rb +0 -17
- data/test/support/service_handlers.rb +0 -154
- data/test/support/services.rb +0 -123
- data/test/support/simple_client.rb +0 -62
- data/test/system/request_handling_tests.rb +0 -306
- data/test/unit/config_tests.rb +0 -56
- data/test/unit/host_data_tests.rb +0 -71
- data/test/unit/host_tests.rb +0 -141
- data/test/unit/hosts_tests.rb +0 -50
- data/test/unit/manager_tests.rb +0 -195
- data/test/unit/worker_tests.rb +0 -24
@@ -0,0 +1,47 @@
|
|
1
|
+
module Sanford
|
2
|
+
|
3
|
+
class ServerData
|
4
|
+
|
5
|
+
# The server uses this to "compile" its configuration for speed. NsOptions
|
6
|
+
# is relatively slow everytime an option is read. To avoid this, we read the
|
7
|
+
# options one time here and memoize their values. This way, we don't pay the
|
8
|
+
# NsOptions overhead when reading them while handling a request.
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
attr_reader :ip, :port
|
12
|
+
attr_reader :pid_file
|
13
|
+
attr_reader :logger, :verbose_logging
|
14
|
+
attr_reader :receives_keep_alive
|
15
|
+
attr_reader :error_procs
|
16
|
+
attr_reader :routes
|
17
|
+
attr_reader :template_source
|
18
|
+
|
19
|
+
def initialize(args = nil)
|
20
|
+
args ||= {}
|
21
|
+
@name = args[:name]
|
22
|
+
@ip = args[:ip]
|
23
|
+
@port = args[:port]
|
24
|
+
@pid_file = args[:pid_file]
|
25
|
+
@logger = args[:logger]
|
26
|
+
@verbose_logging = !!args[:verbose_logging]
|
27
|
+
@receives_keep_alive = !!args[:receives_keep_alive]
|
28
|
+
@error_procs = args[:error_procs] || []
|
29
|
+
@routes = build_routes(args[:routes] || [])
|
30
|
+
@template_source = args[:template_source]
|
31
|
+
end
|
32
|
+
|
33
|
+
def route_for(name)
|
34
|
+
@routes[name] || raise(NotFoundError, "no service named '#{name}'")
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_routes(routes)
|
40
|
+
routes.inject({}){ |h, route| h.merge(route.name => route) }
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
NotFoundError = Class.new(RuntimeError)
|
46
|
+
|
47
|
+
end
|
@@ -1,22 +1,7 @@
|
|
1
|
-
require 'sanford/sanford_runner'
|
2
|
-
require 'sanford/template_source'
|
3
|
-
|
4
1
|
module Sanford
|
5
2
|
|
6
3
|
module ServiceHandler
|
7
4
|
|
8
|
-
DISALLOWED_TEMPLATE_EXTS = Sanford::TemplateSource::DISALLOWED_ENGINE_EXTS
|
9
|
-
|
10
|
-
def self.constantize(class_name)
|
11
|
-
names = class_name.to_s.split('::').reject{|name| name.empty? }
|
12
|
-
klass = names.inject(Object) do |constant, name|
|
13
|
-
constant.const_get(name)
|
14
|
-
end
|
15
|
-
klass == Object ? false : klass
|
16
|
-
rescue NameError
|
17
|
-
false
|
18
|
-
end
|
19
|
-
|
20
5
|
def self.included(klass)
|
21
6
|
klass.class_eval do
|
22
7
|
extend ClassMethods
|
@@ -31,18 +16,18 @@ module Sanford
|
|
31
16
|
end
|
32
17
|
|
33
18
|
def init
|
34
|
-
|
19
|
+
run_callback 'before_init'
|
35
20
|
self.init!
|
36
|
-
|
21
|
+
run_callback 'after_init'
|
37
22
|
end
|
38
23
|
|
39
24
|
def init!
|
40
25
|
end
|
41
26
|
|
42
27
|
def run
|
43
|
-
|
28
|
+
run_callback 'before_run'
|
44
29
|
data = self.run!
|
45
|
-
|
30
|
+
run_callback 'after_run'
|
46
31
|
[ 200, data ]
|
47
32
|
end
|
48
33
|
|
@@ -55,26 +40,19 @@ module Sanford
|
|
55
40
|
"#<#{self.class}:#{reference} @request=#{self.request.inspect}>"
|
56
41
|
end
|
57
42
|
|
58
|
-
|
43
|
+
private
|
59
44
|
|
60
45
|
# Helpers
|
61
46
|
|
62
47
|
def render(path, options = nil)
|
63
48
|
options ||= {}
|
64
|
-
|
65
|
-
|
66
|
-
self,
|
67
|
-
options['locals'] || {}
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
|
-
def run_handler(handler_class, params = nil)
|
72
|
-
handler_class.run(params || {}, self.logger)
|
49
|
+
source = options['source'] || @sanford_runner.template_source
|
50
|
+
source.render(path, self, options['locals'] || {})
|
73
51
|
end
|
74
52
|
|
75
53
|
def halt(*args); @sanford_runner.halt(*args); end
|
76
54
|
def request; @sanford_runner.request; end
|
77
|
-
def params;
|
55
|
+
def params; @sanford_runner.params; end
|
78
56
|
def logger; @sanford_runner.logger; end
|
79
57
|
|
80
58
|
def run_callback(callback)
|
@@ -83,26 +61,10 @@ module Sanford
|
|
83
61
|
end
|
84
62
|
end
|
85
63
|
|
86
|
-
private
|
87
|
-
|
88
|
-
def get_engine(path, source)
|
89
|
-
source.engines[File.extname(get_template(path, source))[1..-1] || '']
|
90
|
-
end
|
91
|
-
|
92
|
-
def get_template(path, source)
|
93
|
-
files = Dir.glob("#{Pathname.new(source.path).join(path.to_s)}.*")
|
94
|
-
files = files.reject{ |p| DISALLOWED_TEMPLATE_EXTS.include?(File.extname(p)) }
|
95
|
-
files.first.to_s
|
96
|
-
end
|
97
|
-
|
98
64
|
end
|
99
65
|
|
100
66
|
module ClassMethods
|
101
67
|
|
102
|
-
def run(params = nil, logger = nil)
|
103
|
-
SanfordRunner.run(self, params || {}, logger)
|
104
|
-
end
|
105
|
-
|
106
68
|
def before_callbacks; @before_callbacks ||= []; end
|
107
69
|
def after_callbacks; @after_callbacks ||= []; end
|
108
70
|
def before_init_callbacks; @before_init_callbacks ||= []; end
|
@@ -4,7 +4,7 @@ module Sanford
|
|
4
4
|
|
5
5
|
class TemplateSource
|
6
6
|
|
7
|
-
DISALLOWED_ENGINE_EXTS = [ '
|
7
|
+
DISALLOWED_ENGINE_EXTS = [ 'rb' ]
|
8
8
|
|
9
9
|
DisallowedEngineExtError = Class.new(ArgumentError)
|
10
10
|
|
@@ -17,7 +17,7 @@ module Sanford
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def engine(input_ext, engine_class, registered_opts = nil)
|
20
|
-
if DISALLOWED_ENGINE_EXTS.include?(
|
20
|
+
if DISALLOWED_ENGINE_EXTS.include?(input_ext)
|
21
21
|
raise DisallowedEngineExtError, "`#{input_ext}` is disallowed as an"\
|
22
22
|
" engine extension."
|
23
23
|
end
|
@@ -25,6 +25,23 @@ module Sanford
|
|
25
25
|
@engines[input_ext.to_s] = engine_class.new(engine_opts)
|
26
26
|
end
|
27
27
|
|
28
|
+
def render(template_path, service_handler, locals)
|
29
|
+
engine = @engines[get_template_ext(template_path)]
|
30
|
+
engine.render(template_path, service_handler, locals)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def get_template_ext(template_path)
|
36
|
+
files = Dir.glob("#{File.join(@path, template_path.to_s)}.*")
|
37
|
+
files = files.reject{ |p| !@engines.keys.include?(parse_ext(p)) }
|
38
|
+
parse_ext(files.first.to_s || '')
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_ext(template_path)
|
42
|
+
File.extname(template_path)[1..-1]
|
43
|
+
end
|
44
|
+
|
28
45
|
end
|
29
46
|
|
30
47
|
class NullTemplateSource < TemplateSource
|
data/lib/sanford/test_runner.rb
CHANGED
@@ -1,53 +1,52 @@
|
|
1
1
|
require 'sanford-protocol'
|
2
|
+
require 'sanford/logger'
|
2
3
|
require 'sanford/runner'
|
3
4
|
require 'sanford/service_handler'
|
5
|
+
require 'sanford/template_source'
|
4
6
|
|
5
7
|
module Sanford
|
6
8
|
|
7
|
-
InvalidServiceHandlerError = Class.new(
|
9
|
+
InvalidServiceHandlerError = Class.new(StandardError)
|
8
10
|
|
9
|
-
class TestRunner
|
10
|
-
include Sanford::Runner
|
11
|
+
class TestRunner < Sanford::Runner
|
11
12
|
|
12
13
|
attr_reader :response
|
13
14
|
|
14
|
-
def initialize(handler_class,
|
15
|
+
def initialize(handler_class, args = nil)
|
15
16
|
if !handler_class.include?(Sanford::ServiceHandler)
|
16
17
|
raise InvalidServiceHandlerError, "#{handler_class.inspect} is not a"\
|
17
18
|
" Sanford::ServiceHandler"
|
18
19
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
args = (args || {}).dup
|
21
|
+
@request = args.delete(:request)
|
22
|
+
@params = args.delete(:params) || {}
|
23
|
+
@logger = args.delete(:logger) || Sanford::NullLogger.new
|
24
|
+
@template_source = args.delete(:template_source) ||
|
25
|
+
Sanford::NullTemplateSource.new
|
26
|
+
|
27
|
+
super(handler_class)
|
28
|
+
args.each{ |key, value| @handler.send("#{key}=", value) }
|
29
|
+
|
30
|
+
return_value = catch(:halt){ @handler.init; nil }
|
31
|
+
@response = build_and_serialize_response{ return_value } if return_value
|
25
32
|
end
|
26
33
|
|
27
|
-
# we
|
28
|
-
#
|
29
|
-
#
|
34
|
+
# If `init` generated a response, we don't want to `run` at all. This makes
|
35
|
+
# the `TestRunner` behave similar to the `SanfordRunner`, i.e. `halt` in
|
36
|
+
# `init` stops processing where `halt` is called.
|
30
37
|
|
31
38
|
def run
|
32
|
-
@response ||=
|
33
|
-
# attempt to serialize (and then throw away) the response data
|
34
|
-
# this will error on the developer if BSON can't serialize their response
|
35
|
-
Sanford::Protocol::BsonBody.new.encode(response.to_hash)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def run!
|
40
|
-
self.handler.run
|
39
|
+
@response ||= build_and_serialize_response{ self.handler.run }
|
41
40
|
end
|
42
41
|
|
43
42
|
private
|
44
43
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
def build_and_serialize_response(&block)
|
45
|
+
build_response(&block).tap do |response|
|
46
|
+
# attempt to serialize (and then throw away) the response data
|
47
|
+
# this will error on the developer if BSON can't serialize their response
|
48
|
+
Sanford::Protocol::BsonBody.new.encode(response.to_hash) if response
|
49
|
+
end
|
51
50
|
end
|
52
51
|
|
53
52
|
end
|
data/lib/sanford/version.rb
CHANGED
data/lib/sanford.rb
CHANGED
@@ -1,29 +1,7 @@
|
|
1
1
|
require 'sanford/version'
|
2
|
-
require 'sanford/
|
3
|
-
require 'sanford/hosts'
|
4
|
-
require 'sanford/host'
|
2
|
+
require 'sanford/server'
|
5
3
|
require 'sanford/service_handler'
|
6
4
|
|
7
|
-
ENV['SANFORD_SERVICES_FILE'] ||= 'config/services'
|
8
|
-
|
9
5
|
module Sanford
|
10
6
|
|
11
|
-
def self.config; @config ||= Config.new; end
|
12
|
-
def self.configure(&block)
|
13
|
-
block.call(self.config)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.init
|
17
|
-
@hosts ||= Sanford::Hosts.new
|
18
|
-
require self.config.services_file
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.register(host)
|
22
|
-
@hosts.add(host)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.hosts
|
26
|
-
@hosts
|
27
|
-
end
|
28
|
-
|
29
7
|
end
|
data/sanford.gemspec
CHANGED
@@ -18,10 +18,9 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
-
gem.add_dependency("dat-tcp",
|
22
|
-
gem.add_dependency("ns-options",
|
23
|
-
gem.add_dependency("sanford-protocol",
|
21
|
+
gem.add_dependency("dat-tcp", ["~> 0.5"])
|
22
|
+
gem.add_dependency("ns-options", ["~> 1.1"])
|
23
|
+
gem.add_dependency("sanford-protocol", ["~> 0.9"])
|
24
24
|
|
25
|
-
gem.add_development_dependency("assert",
|
26
|
-
gem.add_development_dependency("assert-mocha", ["~> 1.1"])
|
25
|
+
gem.add_development_dependency("assert", ["~> 2.11"])
|
27
26
|
end
|
data/test/helper.rb
CHANGED
@@ -5,27 +5,10 @@
|
|
5
5
|
$LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
|
6
6
|
|
7
7
|
require 'pry' # require pry for debugging (`binding.pry`)
|
8
|
-
require 'assert-mocha' if defined?(Assert)
|
9
8
|
|
10
9
|
ENV['SANFORD_PROTOCOL_DEBUG'] = 'yes'
|
11
10
|
|
12
|
-
require '
|
13
|
-
|
11
|
+
require 'pathname'
|
12
|
+
ROOT_PATH = Pathname.new(File.expand_path('../..', __FILE__))
|
14
13
|
|
15
|
-
|
16
|
-
def render(path, service_handler, locals)
|
17
|
-
[path.to_s, service_handler.class.to_s, locals]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
Sanford.configure do |config|
|
21
|
-
config.services_file = File.join(ROOT, 'test/support/services')
|
22
|
-
config.set_template_source File.join(ROOT, 'test/support') do |s|
|
23
|
-
s.engine 'test', MyTestEngine
|
24
|
-
end
|
25
|
-
end
|
26
|
-
Sanford.init
|
27
|
-
|
28
|
-
require 'test/support/fake_connection'
|
29
|
-
require 'test/support/service_handlers'
|
30
|
-
require 'test/support/simple_client'
|
31
|
-
require 'test/support/helpers'
|
14
|
+
require 'test/support/factory'
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'sanford'
|
3
|
+
require 'sanford-protocol'
|
4
|
+
|
5
|
+
if !defined?(ROOT_PATH)
|
6
|
+
ROOT_PATH = Pathname.new(File.expand_path('../../..', __FILE__))
|
7
|
+
end
|
8
|
+
|
9
|
+
class AppERBEngine < Sanford::TemplateEngine
|
10
|
+
RenderScope = Struct.new(:view)
|
11
|
+
|
12
|
+
def render(path, service_handler, locals)
|
13
|
+
require 'erb'
|
14
|
+
full_path = ROOT_PATH.join("test/support/#{path}.erb")
|
15
|
+
binding = RenderScope.new(service_handler).send(:binding)
|
16
|
+
ERB.new(File.read(full_path)).result(binding)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class AppServer
|
21
|
+
include Sanford::Server
|
22
|
+
|
23
|
+
name 'app'
|
24
|
+
ip 'localhost'
|
25
|
+
port 12000
|
26
|
+
|
27
|
+
receives_keep_alive true
|
28
|
+
|
29
|
+
logger Logger.new(ROOT_PATH.join('log/app_server.log').to_s)
|
30
|
+
verbose_logging true
|
31
|
+
|
32
|
+
router do
|
33
|
+
service_handler_ns 'AppHandlers'
|
34
|
+
|
35
|
+
service 'echo', 'Echo'
|
36
|
+
service 'raise', 'Raise'
|
37
|
+
service 'bad_response', 'BadResponse'
|
38
|
+
service 'template', 'Template'
|
39
|
+
service 'halt', 'Halt'
|
40
|
+
service 'custom_error', 'CustomError'
|
41
|
+
end
|
42
|
+
|
43
|
+
build_template_source ROOT_PATH.join('test/support').to_s do |s|
|
44
|
+
s.engine 'erb', AppERBEngine
|
45
|
+
end
|
46
|
+
|
47
|
+
error do |exception, server_data, request|
|
48
|
+
if request && request.name == 'custom_error'
|
49
|
+
data = "The server on #{server_data.ip}:#{server_data.port} " \
|
50
|
+
"threw a #{exception.class}."
|
51
|
+
Sanford::Protocol::Response.new(200, data)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
module AppHandlers
|
58
|
+
|
59
|
+
class Echo
|
60
|
+
include Sanford::ServiceHandler
|
61
|
+
|
62
|
+
def run!
|
63
|
+
params['message']
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Raise
|
68
|
+
include Sanford::ServiceHandler
|
69
|
+
|
70
|
+
def run!
|
71
|
+
raise "hahaha"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class BadResponse
|
76
|
+
include Sanford::ServiceHandler
|
77
|
+
|
78
|
+
def run!
|
79
|
+
Class.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class Template
|
84
|
+
include Sanford::ServiceHandler
|
85
|
+
|
86
|
+
attr_reader :message
|
87
|
+
|
88
|
+
def init!
|
89
|
+
@message = params['message']
|
90
|
+
end
|
91
|
+
|
92
|
+
def run!
|
93
|
+
render "template"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Halt
|
98
|
+
include Sanford::ServiceHandler
|
99
|
+
|
100
|
+
before do
|
101
|
+
halt(200, :message => "in before") if params['when'] == 'before'
|
102
|
+
end
|
103
|
+
|
104
|
+
before_init do
|
105
|
+
halt(200, :message => "in before init") if params['when'] == 'before_init'
|
106
|
+
end
|
107
|
+
|
108
|
+
def init!
|
109
|
+
halt(200, :message => "in init") if params['when'] == 'init'
|
110
|
+
end
|
111
|
+
|
112
|
+
after_init do
|
113
|
+
halt(200, :message => "in after init") if params['when'] == 'after_init'
|
114
|
+
end
|
115
|
+
|
116
|
+
before_run do
|
117
|
+
halt(200, :message => "in before run") if params['when'] == 'before_run'
|
118
|
+
end
|
119
|
+
|
120
|
+
def run!
|
121
|
+
halt(200, :message => "in run") if params['when'] == 'run'
|
122
|
+
false
|
123
|
+
end
|
124
|
+
|
125
|
+
after_run do
|
126
|
+
halt(200, :message => "in after run") if params['when'] == 'after_run'
|
127
|
+
end
|
128
|
+
|
129
|
+
after do
|
130
|
+
halt(200, :message => "in after") if params['when'] == 'after'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class CustomError
|
135
|
+
include Sanford::ServiceHandler
|
136
|
+
|
137
|
+
def run!
|
138
|
+
raise StandardError
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
File without changes
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'sanford-protocol'
|
2
|
+
|
3
|
+
class FakeServerConnection
|
4
|
+
|
5
|
+
attr_reader :request, :response
|
6
|
+
attr_reader :write_closed
|
7
|
+
attr_accessor :raise_on_write, :write_exception
|
8
|
+
attr_writer :read_data
|
9
|
+
|
10
|
+
def self.with_request(name, params = nil)
|
11
|
+
self.new.tap{ |c| c.add_request(name, params) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(read_data = nil)
|
15
|
+
@read_data = read_data
|
16
|
+
@raise_on_write = false
|
17
|
+
@write_closed = false
|
18
|
+
|
19
|
+
@write_exception = RuntimeError.new('oops')
|
20
|
+
|
21
|
+
@request = nil
|
22
|
+
@response = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_request(name, params = nil)
|
26
|
+
@request = Sanford::Protocol::Request.new(name, params || {})
|
27
|
+
@read_data = @request.to_hash
|
28
|
+
end
|
29
|
+
|
30
|
+
def read_data
|
31
|
+
@read_data || {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_data(data = nil)
|
35
|
+
write_data!(data) if data
|
36
|
+
@write_data
|
37
|
+
end
|
38
|
+
|
39
|
+
def peek_data
|
40
|
+
@read_data ? @read_data[0] : ""
|
41
|
+
end
|
42
|
+
|
43
|
+
def close_write
|
44
|
+
@write_closed = true
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def write_data!(data)
|
50
|
+
if @raise_on_write
|
51
|
+
@raise_on_write = false
|
52
|
+
raise @write_exception
|
53
|
+
end
|
54
|
+
@response = Sanford::Protocol::Response.parse(data) rescue nil
|
55
|
+
@write_data = data
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class PIDFileSpy
|
2
|
+
|
3
|
+
attr_reader :pid, :write_called, :remove_called
|
4
|
+
|
5
|
+
def initialize(pid)
|
6
|
+
@pid = pid
|
7
|
+
@write_called = false
|
8
|
+
@remove_called = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def write
|
12
|
+
@write_called = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove
|
16
|
+
@remove_called = true
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
ERB Template Message: <%= view.message %>
|