sanford 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -5,5 +5,4 @@ gemspec
5
5
  gem 'rake'
6
6
  gem 'pry'
7
7
 
8
- gem 'bson'
9
- gem 'bson_ext', '~>1.7'
8
+ gem 'bson_ext'
@@ -0,0 +1,28 @@
1
+ require 'ns-options'
2
+ require 'pathname'
3
+ require 'sanford/logger'
4
+ require 'sanford/runner'
5
+ require 'sanford/template_source'
6
+
7
+ module Sanford
8
+
9
+ class Config
10
+ include NsOptions::Proxy
11
+
12
+ option :services_file, Pathname, :default => proc{ ENV['SANFORD_SERVICES_FILE'] }
13
+ option :logger, :default => proc{ Sanford::NullLogger.new }
14
+
15
+ attr_reader :template_source
16
+
17
+ def initialize
18
+ super
19
+ @template_source = NullTemplateSource.new
20
+ end
21
+
22
+ def set_template_source(path, &block)
23
+ @template_source = TemplateSource.new(path).tap{ |s| block.call(s) if block }
24
+ end
25
+
26
+ end
27
+
28
+ end
data/lib/sanford/host.rb CHANGED
@@ -25,7 +25,6 @@ module Sanford
25
25
  option :logger, :default => proc{ Sanford.config.logger }
26
26
  option :verbose_logging, :default => true
27
27
  option :receives_keep_alive, :default => false
28
- option :runner, :default => proc{ Sanford.config.runner }
29
28
  option :error_procs, Array, :default => []
30
29
  option :init_procs, Array, :default => []
31
30
 
@@ -79,10 +78,6 @@ module Sanford
79
78
  self.configuration.receives_keep_alive *args
80
79
  end
81
80
 
82
- def runner(*args)
83
- self.configuration.runner *args
84
- end
85
-
86
81
  def error(&block)
87
82
  self.configuration.error_procs << block
88
83
  end
@@ -111,7 +106,7 @@ module Sanford
111
106
 
112
107
  module ClassMethods
113
108
 
114
- # the class level of a `Host` should just proxy it's methods down to it's
109
+ # the class level of a `Host` should just proxy its methods down to its
115
110
  # instance (it's a `Singleton`)
116
111
 
117
112
  # `name` is defined by all objects, so we can't rely on `method_missing`
@@ -1,4 +1,5 @@
1
1
  require 'sanford/service_handler'
2
+ require 'sanford/sanford_runner'
2
3
 
3
4
  module Sanford
4
5
 
@@ -12,7 +13,7 @@ module Sanford
12
13
  # NOTE: The `name` attribute shouldn't be removed, it is used to identify
13
14
  # a `HostData`, particularly in error handlers
14
15
 
15
- attr_reader :name, :logger, :verbose, :keep_alive, :runner, :error_procs
16
+ attr_reader :name, :logger, :verbose, :keep_alive, :error_procs
16
17
 
17
18
  def initialize(service_host, options = nil)
18
19
  service_host.configuration.init_procs.each(&:call)
@@ -24,7 +25,6 @@ module Sanford
24
25
  @logger = configuration[:logger]
25
26
  @verbose = configuration[:verbose_logging]
26
27
  @keep_alive = configuration[:receives_keep_alive]
27
- @runner = configuration[:runner]
28
28
  @error_procs = configuration[:error_procs]
29
29
 
30
30
  @handlers = service_host.services.inject({}) do |h, (name, handler_class_name)|
@@ -37,7 +37,7 @@ module Sanford
37
37
  end
38
38
 
39
39
  def run(handler_class, request)
40
- self.runner.new(handler_class, request, self.logger).run
40
+ SanfordRunner.new(handler_class, request, self.logger).run
41
41
  end
42
42
 
43
43
  protected
@@ -0,0 +1,38 @@
1
+ require 'set'
2
+ require 'sanford/host'
3
+
4
+ module Sanford
5
+
6
+ class Hosts
7
+
8
+ def initialize(values = [])
9
+ @set = Set.new(values)
10
+ end
11
+
12
+ def method_missing(method, *args, &block)
13
+ @set.send(method, *args, &block)
14
+ end
15
+
16
+ def respond_to?(method)
17
+ super || @set.respond_to?(method)
18
+ end
19
+
20
+ # We want class names to take precedence over a configured name, so that if
21
+ # a user specifies a specific class, they always get it
22
+ def find(name)
23
+ find_by_class_name(name) || find_by_name(name)
24
+ end
25
+
26
+ private
27
+
28
+ def find_by_class_name(class_name)
29
+ @set.detect{|host_class| host_class.to_s == class_name.to_s }
30
+ end
31
+
32
+ def find_by_name(name)
33
+ @set.detect{|host_class| host_class.name == name.to_s }
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -16,7 +16,7 @@ module Sanford
16
16
 
17
17
  module InstanceMethods
18
18
 
19
- attr_reader :handler_class, :request, :logger
19
+ attr_reader :handler_class, :request, :logger, :handler
20
20
 
21
21
  def initialize(handler_class, request, logger = nil)
22
22
  @handler_class, @request = handler_class, request
@@ -33,8 +33,7 @@ module Sanford
33
33
  end
34
34
 
35
35
  def run
36
- response_args = catch_halt{ self.run!(@handler) }
37
- Sanford::Protocol::Response.new(response_args.status, response_args.data)
36
+ build_response catch_halt{ self.run! }
38
37
  end
39
38
 
40
39
  def run!
@@ -56,6 +55,12 @@ module Sanford
56
55
  catch(:halt){ ResponseArgs.new(*block.call) }
57
56
  end
58
57
 
58
+ protected
59
+
60
+ def build_response(args)
61
+ Sanford::Protocol::Response.new(args.status, args.data) if args
62
+ end
63
+
59
64
  end
60
65
 
61
66
  module ClassMethods
@@ -69,14 +74,4 @@ module Sanford
69
74
 
70
75
  end
71
76
 
72
- class DefaultRunner
73
- include Sanford::Runner
74
-
75
- def run!(handler)
76
- handler.init
77
- handler.run
78
- end
79
-
80
- end
81
-
82
77
  end
@@ -0,0 +1,27 @@
1
+ require 'sanford/runner'
2
+
3
+ module Sanford
4
+
5
+ class SanfordRunner
6
+ include Sanford::Runner
7
+
8
+ # call the handler init and the handler run - if the init halts, run won't
9
+ # be called.
10
+
11
+ def run!
12
+ run_callbacks self.handler_class.before_callbacks
13
+ self.handler.init
14
+ response_args = self.handler.run
15
+ run_callbacks self.handler_class.after_callbacks
16
+ response_args
17
+ end
18
+
19
+ private
20
+
21
+ def run_callbacks(callbacks)
22
+ callbacks.each{|proc| self.handler.instance_eval(&proc) }
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -89,7 +89,7 @@ module Sanford
89
89
  # packetizes our stream. This improves both latency and throughput.
90
90
  # TCP_CORK disables Nagle's algorithm, which is ideal for sporadic
91
91
  # traffic (like Telnet) but is less optimal for HTTP. Sanford is similar
92
- # to HTTP, it doesn't receive sporadic packets, it has all it's data
92
+ # to HTTP, it doesn't receive sporadic packets, it has all its data
93
93
  # come in at once.
94
94
  # For more information: http://baus.net/on-tcp_cork
95
95
 
@@ -54,6 +54,15 @@ module Sanford
54
54
 
55
55
  # Helpers
56
56
 
57
+ def render(path, options = nil)
58
+ options ||= {}
59
+ get_engine(path, options['source'] || Sanford.config.template_source).render(
60
+ path,
61
+ self,
62
+ options['locals'] || {}
63
+ )
64
+ end
65
+
57
66
  def run_handler(handler_class, params = nil)
58
67
  handler_class.run(params || {}, self.logger)
59
68
  end
@@ -69,23 +78,40 @@ module Sanford
69
78
  end
70
79
  end
71
80
 
81
+ private
82
+
83
+ def get_engine(path, source)
84
+ source.engines[File.extname(get_template(path, source))[1..-1] || '']
85
+ end
86
+
87
+ def get_template(path, source)
88
+ Dir.glob("#{Pathname.new(source.path).join(path.to_s)}.*").first.to_s
89
+ end
90
+
72
91
  end
73
92
 
74
93
  module ClassMethods
75
94
 
76
95
  def run(params = nil, logger = nil)
77
- Sanford.config.runner.run(self, params || {}, logger)
96
+ SanfordRunner.run(self, params || {}, logger)
78
97
  end
79
98
 
99
+ def before_callbacks; @before_callbacks ||= []; end
100
+ def after_callbacks; @after_callbacks ||= []; end
80
101
  def before_init_callbacks; @before_init_callbacks ||= []; end
81
102
  def after_init_callbacks; @after_init_callbacks ||= []; end
82
103
  def before_run_callbacks; @before_run_callbacks ||= []; end
83
104
  def after_run_callbacks; @after_run_callbacks ||= []; end
84
105
 
106
+ def before(&block); self.before_callbacks << block; end
107
+ def after(&block); self.after_callbacks << block; end
85
108
  def before_init(&block); self.before_init_callbacks << block; end
86
109
  def after_init(&block); self.after_init_callbacks << block; end
87
110
  def before_run(&block); self.before_run_callbacks << block; end
88
111
  def after_run(&block); self.after_run_callbacks << block; end
112
+
113
+ def prepend_before(&block); self.before_callbacks.unshift(block); end
114
+ def prepend_after(&block); self.after_callbacks.unshift(block); end
89
115
  def prepend_before_init(&block); self.before_init_callbacks.unshift(block); end
90
116
  def prepend_after_init(&block); self.after_init_callbacks.unshift(block); end
91
117
  def prepend_before_run(&block); self.before_run_callbacks.unshift(block); end
@@ -0,0 +1,32 @@
1
+ require 'pathname'
2
+
3
+ module Sanford
4
+
5
+ class TemplateEngine
6
+
7
+ attr_reader :source_path, :opts
8
+
9
+ def initialize(opts = nil)
10
+ @opts = opts || {}
11
+ @source_path = Pathname.new(@opts['source_path'].to_s)
12
+ end
13
+
14
+ def render(path, service_handler, locals)
15
+ raise NotImplementedError
16
+ end
17
+
18
+ end
19
+
20
+ class NullTemplateEngine < TemplateEngine
21
+
22
+ def render(path, service_handler, locals)
23
+ template_file = self.source_path.join(path).to_s
24
+ unless File.exists?(template_file)
25
+ raise ArgumentError, "template file `#{template_file}` does not exist"
26
+ end
27
+ File.read(template_file)
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,30 @@
1
+ require 'sanford/template_engine'
2
+
3
+ module Sanford
4
+
5
+ class TemplateSource
6
+
7
+ attr_reader :path, :engines
8
+
9
+ def initialize(path)
10
+ @path = path.to_s
11
+ @default_opts = { 'source_path' => @path }
12
+ @engines = Hash.new{ |h,k| Sanford::NullTemplateEngine.new(@default_opts) }
13
+ end
14
+
15
+ def engine(input_ext, engine_class, registered_opts = nil)
16
+ engine_opts = @default_opts.merge(registered_opts || {})
17
+ @engines[input_ext.to_s] = engine_class.new(engine_opts)
18
+ end
19
+
20
+ end
21
+
22
+ class NullTemplateSource < TemplateSource
23
+
24
+ def initialize
25
+ super('')
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -9,20 +9,18 @@ module Sanford
9
9
  class TestRunner
10
10
  include Sanford::Runner
11
11
 
12
- attr_reader :handler, :response
12
+ attr_reader :response
13
13
 
14
- def initialize(handler_class, *args)
14
+ def initialize(handler_class, request_or_params, *args)
15
15
  if !handler_class.include?(Sanford::ServiceHandler)
16
16
  raise InvalidServiceHandlerError, "#{handler_class.inspect} is not a"\
17
17
  " Sanford::ServiceHandler"
18
18
  end
19
- super
19
+
20
+ super handler_class, build_request(request_or_params), *args
20
21
  end
21
22
 
22
23
  def init!
23
- if !@request.kind_of?(Sanford::Protocol::Request)
24
- @request = test_request(@request)
25
- end
26
24
  @response = build_response catch(:halt){ @handler.init; nil }
27
25
  end
28
26
 
@@ -31,21 +29,25 @@ module Sanford
31
29
  # want to `run` at all.
32
30
 
33
31
  def run
34
- @response ||= build_response(catch_halt{ @handler.run }).tap do |response|
32
+ @response ||= super.tap do |response|
35
33
  # attempt to serialize (and then throw away) the response data
36
34
  # this will error on the developer if BSON can't serialize their response
37
35
  Sanford::Protocol::BsonBody.new.encode(response.to_hash)
38
36
  end
39
37
  end
40
38
 
41
- protected
39
+ def run!
40
+ self.handler.run
41
+ end
42
42
 
43
- def test_request(params)
44
- Sanford::Protocol::Request.new('name', params || {})
43
+ private
44
+
45
+ def build_request(req)
46
+ !req.kind_of?(Sanford::Protocol::Request) ? test_request(req) : req
45
47
  end
46
48
 
47
- def build_response(response_args)
48
- Sanford::Protocol::Response.new(response_args.status, response_args.data) if response_args
49
+ def test_request(params)
50
+ Sanford::Protocol::Request.new('name', params || {})
49
51
  end
50
52
 
51
53
  end
@@ -1,3 +1,3 @@
1
1
  module Sanford
2
- VERSION = "0.9.0"
2
+ VERSION = "0.10.0"
3
3
  end
data/lib/sanford.rb CHANGED
@@ -1,29 +1,20 @@
1
- require 'ns-options'
2
- require 'pathname'
3
- require 'set'
4
-
5
1
  require 'sanford/version'
2
+ require 'sanford/config'
3
+ require 'sanford/hosts'
6
4
  require 'sanford/host'
7
- require 'sanford/logger'
8
- require 'sanford/runner'
9
- require 'sanford/server'
10
5
  require 'sanford/service_handler'
11
6
 
12
7
  ENV['SANFORD_SERVICES_FILE'] ||= 'config/services'
13
8
 
14
9
  module Sanford
15
10
 
16
- def self.config
17
- Sanford::Config
18
- end
19
-
11
+ def self.config; @config ||= Config.new; end
20
12
  def self.configure(&block)
21
- self.config.define(&block)
22
- self.config
13
+ block.call(self.config)
23
14
  end
24
15
 
25
16
  def self.init
26
- @hosts ||= Hosts.new
17
+ @hosts ||= Sanford::Hosts.new
27
18
  require self.config.services_file
28
19
  end
29
20
 
@@ -35,43 +26,4 @@ module Sanford
35
26
  @hosts
36
27
  end
37
28
 
38
- module Config
39
- include NsOptions::Proxy
40
- option :services_file, Pathname, :default => ENV['SANFORD_SERVICES_FILE']
41
- option :logger, :default => Sanford::NullLogger.new
42
- option :runner, :default => Sanford::DefaultRunner
43
- end
44
-
45
- class Hosts
46
-
47
- def initialize(values = [])
48
- @set = Set.new(values)
49
- end
50
-
51
- def method_missing(method, *args, &block)
52
- @set.send(method, *args, &block)
53
- end
54
-
55
- def respond_to?(method)
56
- super || @set.respond_to?(method)
57
- end
58
-
59
- # We want class names to take precedence over a configured name, so that if
60
- # a user specifies a specific class, they always get it
61
- def find(name)
62
- find_by_class_name(name) || find_by_name(name)
63
- end
64
-
65
- private
66
-
67
- def find_by_class_name(class_name)
68
- @set.detect{|host_class| host_class.to_s == class_name.to_s }
69
- end
70
-
71
- def find_by_name(name)
72
- @set.detect{|host_class| host_class.name == name.to_s }
73
- end
74
-
75
- end
76
-
77
29
  end
data/sanford.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |gem|
20
20
 
21
21
  gem.add_dependency("dat-tcp", ["~> 0.4"])
22
22
  gem.add_dependency("ns-options", ["~> 1.1"])
23
- gem.add_dependency("sanford-protocol", ["~> 0.7"])
23
+ gem.add_dependency("sanford-protocol", ["~> 0.8"])
24
24
 
25
25
  gem.add_development_dependency("assert", ["~> 2.10"])
26
26
  gem.add_development_dependency("assert-mocha", ["~> 1.1"])
data/test/helper.rb CHANGED
@@ -11,8 +11,17 @@ ENV['SANFORD_PROTOCOL_DEBUG'] = 'yes'
11
11
 
12
12
  require 'sanford'
13
13
  ROOT = File.expand_path('../..', __FILE__)
14
+
15
+ MyTestEngine = Class.new(Sanford::TemplateEngine) do
16
+ def render(path, service_handler, locals)
17
+ [path.to_s, service_handler.class.to_s, locals]
18
+ end
19
+ end
14
20
  Sanford.configure do |config|
15
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
16
25
  end
17
26
  Sanford.init
18
27
 
@@ -0,0 +1,6 @@
1
+ require 'assert/factory'
2
+
3
+ module Factory
4
+ extend Assert::Factory
5
+
6
+ end
@@ -24,10 +24,18 @@ module CallbackServiceHandler
24
24
 
25
25
  def self.included(receiver)
26
26
  receiver.class_eval do
27
+ attr_reader :before_called, :after_called
27
28
  attr_reader :before_init_called, :init_bang_called, :after_init_called
28
29
  attr_reader :before_run_called, :run_bang_called, :after_run_called
29
30
  attr_reader :second_before_init_called, :second_after_run_called
30
31
 
32
+ before do
33
+ @before_called = true
34
+ end
35
+ after do
36
+ @after_called = true
37
+ end
38
+
31
39
  before_init do
32
40
  @before_init_called = true
33
41
  end
@@ -117,6 +125,14 @@ class HaltingBehaviorServiceHandler
117
125
 
118
126
  end
119
127
 
128
+ class RenderHandler
129
+ include Sanford::ServiceHandler
130
+
131
+ def run!
132
+ render 'test_template'
133
+ end
134
+ end
135
+
120
136
  class RunOtherHandler
121
137
  include Sanford::ServiceHandler
122
138
 
@@ -0,0 +1 @@
1
+ This is a json template for use in template engine tests.
File without changes
@@ -251,7 +251,7 @@ class RequestHandlingTests < Assert::Context
251
251
  end
252
252
  end
253
253
 
254
- # Sending the server a protocol version that doesn't match it's version
254
+ # Sending the server a protocol version that doesn't match its version
255
255
  class WrongProtocolVersionTests < ForkedServerTests
256
256
  desc "when sent a request with a wrong protocol version"
257
257
 
@@ -0,0 +1,56 @@
1
+ require 'assert'
2
+ require 'sanford/config'
3
+
4
+ require 'ns-options/assert_macros'
5
+ require 'ns-options/proxy'
6
+ require 'sanford/logger'
7
+ require 'sanford/runner'
8
+ require 'sanford/template_source'
9
+ require 'test/support/factory'
10
+
11
+ class Sanford::Config
12
+
13
+ class UnitTests < Assert::Context
14
+ include NsOptions::AssertMacros
15
+
16
+ desc "Sanford::Config"
17
+ setup do
18
+ @config = Sanford::Config.new
19
+ end
20
+ subject{ @config }
21
+
22
+ should have_options :services_file, :logger
23
+ should have_readers :template_source
24
+ should have_imeths :set_template_source
25
+
26
+ should "be an NsOptions::Proxy" do
27
+ assert_includes NsOptions::Proxy, subject.class
28
+ end
29
+
30
+ should "default its services file" do
31
+ exp = Pathname.new(ENV['SANFORD_SERVICES_FILE'])
32
+ assert_equal exp, subject.services_file
33
+ end
34
+
35
+ should "default its logger to a NullLogger" do
36
+ assert_kind_of Sanford::NullLogger, subject.logger
37
+ end
38
+
39
+ should "have a null template source by default" do
40
+ assert_kind_of Sanford::NullTemplateSource, subject.template_source
41
+ end
42
+
43
+ should "set a new template source" do
44
+ path = '/path/to/app/assets'
45
+ block_called = false
46
+ subject.set_template_source(path) { |s| block_called = true}
47
+
48
+ assert_not_nil subject.template_source
49
+ assert_kind_of Sanford::TemplateSource, subject.template_source
50
+ assert_equal path, subject.template_source.path
51
+ assert_true block_called
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -1,8 +1,6 @@
1
1
  require 'assert'
2
2
  require 'sanford/host_data'
3
3
 
4
- require 'test/support/services'
5
-
6
4
  class Sanford::HostData
7
5
 
8
6
  class UnitTests < Assert::Context
@@ -16,7 +14,7 @@ class Sanford::HostData
16
14
  end
17
15
  subject{ @host_data }
18
16
 
19
- should have_readers :name, :logger, :verbose, :keep_alive, :runner, :error_procs
17
+ should have_readers :name, :logger, :verbose, :keep_alive, :error_procs
20
18
  should have_imeths :handler_class_for, :run
21
19
 
22
20
  should "call the init procs" do
@@ -28,7 +26,6 @@ class Sanford::HostData
28
26
  assert_equal TestHost.configuration.logger.class, subject.logger.class
29
27
  assert_equal TestHost.configuration.verbose_logging, subject.verbose
30
28
  assert_equal TestHost.configuration.receives_keep_alive, subject.keep_alive
31
- assert_equal TestHost.configuration.runner.class, subject.runner.class
32
29
  assert_equal TestHost.configuration.error_procs, subject.error_procs
33
30
  end
34
31