serf 0.14.0 → 0.15.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/.gitignore CHANGED
@@ -1,10 +1,18 @@
1
- # Gemfile.lock because this is a library, not a deployable application.
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
2
6
  Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
3
9
  coverage
4
- rdoc
5
- doc
6
- .yardoc
7
- .bundle
8
- vendor
10
+ doc/
11
+ lib/bundler/man
9
12
  pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
10
17
  tmp
18
+ vendor
@@ -2,6 +2,8 @@ language: ruby
2
2
  rvm:
3
3
  - "1.9.2"
4
4
  - "1.9.3"
5
- - jruby-19mode # JRuby in 1.9 mode
6
- - rbx-19mode
5
+ - "jruby-19mode"
6
+ - "rbx-19mode"
7
+ - "ruby-head"
8
+ - "jruby-head"
7
9
  script: bundle exec rake spec
data/README.md CHANGED
@@ -31,13 +31,20 @@ the Domain Layer's Model (Entities, Value Objects and Entity Gateways).
31
31
 
32
32
  1. Include the "Serf::Interactor" module in your class.
33
33
  2. Implement the 'call(parcel)' method.
34
- 3. Return the tuple: (kind, message)
34
+ 3. Return the tuple: (kind, message, headers)
35
35
  a. The kind is the string representation of the message type,
36
36
  This field is RECOMMENDED.
37
37
  b. The message field provides detailed return data about the
38
- interactor's processing.
38
+ interactor's processing. The main meat of the Domain Object.
39
39
  Hashie::Mash is suggested for the message, nil is acceptable.
40
- c. By default, returning nil for both kind and message will still
40
+ c. The headers are OPTIONAL. The headers are there primarily to return
41
+ out of band data about the processing of the request. For example,
42
+ the Interactor can return debug tags about connections to external
43
+ databases.
44
+ The *ONE* semantic relevant piece of information is that the
45
+ Interactor may specify the version the domain object, as represented
46
+ by the message of type 'kind', in the 'version' header field.
47
+ d. By default, returning nil for both kind and message will still
41
48
  result in a response parcel signifying that some Interactor received
42
49
  the inbound parcel. But that is just a almost worthless piece of
43
50
  information for the observer.
@@ -106,6 +113,7 @@ For example,
106
113
  Serf *RESERVES* the following set of header names:
107
114
 
108
115
  * kind
116
+ * version
109
117
  * message
110
118
  * uuid
111
119
  * parent_uuid
@@ -134,6 +142,13 @@ may be used to route messages over messaging channels to Interactors.
134
142
  The convention is 'mymodule/requests/my_business_request' for Requests,
135
143
  and 'mymodule/events/my_business_event' for Events.
136
144
 
145
+ *version* field MAY be used to identify the semantic version of the
146
+ message of the given 'kind'. The triplet of (kind, version, message)
147
+ constitutes the prime parts of domain object as represented by the
148
+ parcel. All other header fields are incidental data that pertain to
149
+ the processing. This field is optional, and is returned in the
150
+ headers portion of the interactor's return results.
151
+
137
152
  *UUIDs* are used to track request and events, providing a sequential
138
153
  order of execution of commands. Already Implemented by Serf middleware.
139
154
 
@@ -320,7 +335,9 @@ Serf Builder Example
320
335
  raise 'Error' if parcel.message.raise_an_error
321
336
 
322
337
  # And return a message as result. Nil is valid response.
323
- return 'my_lib/events/success_event', { success: true }
338
+ return 'my_lib/events/success_event',
339
+ { success: true },
340
+ { version: "1.2.3" }
324
341
 
325
342
  # Optionally just return the kind
326
343
  # return 'my_lib/events/success_event'
@@ -28,19 +28,38 @@ module Serf
28
28
  ##
29
29
  # Set a default chain of the following:
30
30
  #
31
+ # use_default_middleware
32
+ # use_default_serfer_stage
33
+ #
34
+ def use_defaults
35
+ use_default_middleware
36
+ use_default_serfer_stage
37
+ end
38
+
39
+ ##
40
+ # Add the following middleware to the chain:
41
+ #
42
+ # use Serf::Middleware::RequestTimer
31
43
  # use Serf::Middleware::ParcelMasher
32
44
  # use Serf::Middleware::UuidTagger
33
- # use Serf::Middleware::ParcelFreezer
34
45
  # use Serf::Middleware::ErrorHandler
35
- # use Serf::Middleware::PolicyChecker, @policy_chain
36
- # use Serf::Serfer
37
46
  #
38
- def use_defaults
47
+ def use_default_middleware
39
48
  use Serf::Middleware::RequestTimer
40
49
  use Serf::Middleware::ParcelMasher
41
50
  use Serf::Middleware::UuidTagger
42
- use Serf::Middleware::ParcelFreezer
43
51
  use Serf::Middleware::ErrorHandler
52
+ end
53
+
54
+ ##
55
+ # Add the following middleware to the chain:
56
+ #
57
+ # use Serf::Middleware::ParcelFreezer
58
+ # use Serf::Middleware::PolicyChecker, @policy_chain
59
+ # use Serf::Serfer
60
+ #
61
+ def use_default_serfer_stage
62
+ use Serf::Middleware::ParcelFreezer
44
63
  use Serf::Middleware::PolicyChecker, policy_chain: @policy_chain
45
64
  use Serf::Serfer
46
65
  end
@@ -0,0 +1,17 @@
1
+ module Serf
2
+ module Errors
3
+
4
+ ##
5
+ # An error occurred while loading serfs.
6
+ #
7
+ class LoadFailure < RuntimeError
8
+ attr_accessor :cause
9
+
10
+ def initialize(message=nil, cause=nil)
11
+ @cause = cause
12
+ super(message)
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -2,6 +2,7 @@ require 'hashie'
2
2
  require 'optser'
3
3
 
4
4
  require 'serf/builder'
5
+ require 'serf/errors/load_failure'
5
6
  require 'serf/loader/registry'
6
7
 
7
8
  module Serf
@@ -63,9 +64,13 @@ module Loader
63
64
  globs.each do |glob_pattern|
64
65
  globs = Dir.glob File.join(base_path, glob_pattern)
65
66
  globs.each do |filename|
66
- File.open filename do |file|
67
- contents = file.read
68
- instance_eval(contents)
67
+ begin
68
+ File.open filename do |file|
69
+ contents = file.read
70
+ instance_eval(contents)
71
+ end
72
+ rescue => e
73
+ raise Serf::Errors::LoadFailure.new "File: #{filename}", e
69
74
  end
70
75
  end
71
76
  end
@@ -73,7 +78,11 @@ module Loader
73
78
  # Construct all the "serfs"
74
79
  map = Hashie::Mash.new
75
80
  serfs.each do |serf|
76
- map[serf] = @registry[serf]
81
+ begin
82
+ map[serf] = @registry[serf]
83
+ rescue => e
84
+ raise Serf::Errors::LoadFailure.new "Kind: #{serf}", e
85
+ end
77
86
  raise "Missing Serf: #{serf}" if map[serf].nil?
78
87
  end
79
88
 
@@ -1,6 +1,8 @@
1
1
  require 'hashie'
2
2
  require 'optser'
3
3
 
4
+ require 'serf/errors/load_failure'
5
+
4
6
  module Serf
5
7
  module Loader
6
8
 
@@ -47,6 +49,7 @@ module Loader
47
49
  class Registry
48
50
  attr_reader :blocks
49
51
  attr_reader :values
52
+ attr_reader :env
50
53
 
51
54
  def initialize(*args)
52
55
  opts = Optser.extract_options! args
@@ -62,7 +65,7 @@ module Loader
62
65
  # @params &block the proc that generates the component instance.
63
66
  #
64
67
  def add(name, &block)
65
- @blocks[name.to_sym] = block
68
+ blocks[name.to_sym] = block
66
69
  end
67
70
 
68
71
  ##
@@ -73,11 +76,18 @@ module Loader
73
76
  #
74
77
  def [](name)
75
78
  name = name.to_sym
76
- return @values[name] if @values.has_key? name
79
+ return values[name] if values.has_key? name
77
80
  # No memoized value, so grab the block, call it and memoize it
78
81
  # return the block's return value, or nil.
79
- if block = @blocks.delete(name)
80
- @values[name] = block.call self, @env
82
+ if block = blocks[name]
83
+ begin
84
+ value = block.call self, env
85
+ values[name] = value
86
+ blocks.delete name
87
+ return value
88
+ rescue => e
89
+ raise Serf::Errors::LoadFailure.new("Name: #{name}", e)
90
+ end
81
91
  end
82
92
  end
83
93
 
@@ -26,16 +26,29 @@ module Serf
26
26
  #
27
27
  def call(parcel)
28
28
  # 1. Execute interactor
29
- response_kind, response_message = interactor.call parcel
30
-
31
- # 2. Return a new response parcel with:
29
+ response_kind, response_message, response_headers = interactor.call parcel
30
+
31
+ # 2. Extract a possible version embedded in the response_kind.
32
+ # This is sugar syntax for kind and version.
33
+ if response_kind
34
+ kind_part, version_part = response_kind.split '#', 2
35
+ response_kind = kind_part if version_part
36
+ if version_part
37
+ response_headers ||= {}
38
+ response_headers[:version] = version_part
39
+ end
40
+ end
41
+
42
+ # 3. Return a new response parcel with:
32
43
  # a. uuids set from parent parcel
33
44
  # b. kind set to response kind
34
45
  # c. the message set to response_message
46
+ # d. add extra headers to the parcel
35
47
  return parcel_factory.create(
36
48
  parent: parcel,
37
49
  kind: response_kind,
38
- message: response_message)
50
+ message: response_message,
51
+ headers: response_headers)
39
52
  end
40
53
 
41
54
  end
@@ -1,3 +1,5 @@
1
+ require 'socket'
2
+
1
3
  require 'serf/util/protected_call'
2
4
 
3
5
  module Serf
@@ -31,6 +33,7 @@ module Util
31
33
  error: e.class.to_s,
32
34
  message: e.message,
33
35
  process_env: ENV.to_hash,
36
+ hostname: Socket.gethostname,
34
37
  backtrace: e.backtrace.join("\n")
35
38
  }
36
39
  end
@@ -42,6 +42,18 @@ module Util
42
42
  uuid_tool.parse_raw Base64.urlsafe_decode64("#{coded_uuid}==")
43
43
  end
44
44
 
45
+ ##
46
+ # Parses a coded_uuid and returns a time object for the Timestamped UUID.
47
+ #
48
+ # @param coded_uuid the coded uuid from which to get a time.
49
+ #
50
+ # @return ruby time object for which the coded_uuid was timestamped.
51
+ #
52
+ def coded_uuid_time(coded_uuid)
53
+ uuid = parse_coded_uuid coded_uuid
54
+ uuid.timestamp.utc
55
+ end
56
+
45
57
  ##
46
58
  # Create a new set of uuids.
47
59
  #
@@ -1,11 +1,3 @@
1
1
  module Serf
2
-
3
- module Version
4
- MAJOR = 0
5
- MINOR = 14
6
- PATCH = 0
7
- BUILD = nil
8
- STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join '.'
9
- end
10
-
2
+ VERSION = '0.15.0'
11
3
  end
@@ -3,16 +3,29 @@
3
3
  "type": "object",
4
4
  "properties": {
5
5
  "error": {
6
- "type": "string"
6
+ "description": "The error class",
7
+ "type": "string",
8
+ "required": true
7
9
  },
8
10
  "message": {
9
- "type": "string"
11
+ "description": "The description of the error",
12
+ "type": "string",
13
+ "required": true
10
14
  },
11
15
  "process_env": {
12
- "type": "object"
16
+ "description": "The ENV context of the error",
17
+ "type": "object",
18
+ "required": true
19
+ },
20
+ "hostname": {
21
+ "description": "The hostname of the process of the error",
22
+ "type": "string",
23
+ "required": true
13
24
  },
14
25
  "backtrace": {
15
- "type": "string"
26
+ "description": "The backtrace of the error",
27
+ "type": "string",
28
+ "required": true
16
29
  }
17
30
  }
18
31
  }
@@ -1,9 +1,11 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/serf/version', __FILE__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'serf/version'
3
5
 
4
6
  Gem::Specification.new do |gem|
5
7
  gem.name = 'serf'
6
- gem.version = Serf::Version::STRING
8
+ gem.version = Serf::VERSION
7
9
  gem.authors = ['Benjamin Yu']
8
10
  gem.email = 'benjaminlyu@gmail.com'
9
11
  gem.description = 'Interactors with policy protection'
@@ -0,0 +1,3 @@
1
+ registry.add 'spec/data/bad_construction' do |r, env|
2
+ raise 'Intentional Construction Error'
3
+ end
@@ -0,0 +1 @@
1
+ raise 'Intentional Error'
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'serf/errors/load_failure'
3
4
  require 'serf/loader/loader'
4
5
 
5
6
  describe Serf::Loader::Loader do
@@ -14,7 +15,8 @@ describe Serf::Loader::Loader do
14
15
  subject {
15
16
  Serf::Loader::Loader.new.serfup(
16
17
  globs: [
17
- 'example/**/*.serf'
18
+ 'example/components/**/*.serf',
19
+ 'example/serfs/**/*.serf'
18
20
  ],
19
21
  serfs: [
20
22
  'subsystem/requests/create_widget'
@@ -70,4 +72,44 @@ describe Serf::Loader::Loader do
70
72
  end
71
73
  end
72
74
 
75
+ context '#serfup with construction error' do
76
+ let(:serfup_config) {
77
+ Hashie::Mash.new(
78
+ globs: [
79
+ 'spec/data/construction_error.serf'
80
+ ],
81
+ serfs: [
82
+ 'spec/data/bad_construction'
83
+ ])
84
+ }
85
+
86
+ it 'raises an error' do
87
+ expect {
88
+ Serf::Loader::Loader.new.serfup serfup_config
89
+ }.to raise_error { |error|
90
+ expect(error).to be_a(Serf::Errors::LoadFailure)
91
+ expect(error.message).to match(/Kind: .+$/)
92
+ }
93
+ end
94
+ end
95
+
96
+ context '#serfup Serf Map bad serf file' do
97
+ let(:serfup_config) {
98
+ Hashie::Mash.new(
99
+ globs: [
100
+ 'spec/data/raises_error.serf'
101
+ ],
102
+ serfs: [])
103
+ }
104
+
105
+ it 'raises an error' do
106
+ expect {
107
+ Serf::Loader::Loader.new.serfup serfup_config
108
+ }.to raise_error { |error|
109
+ expect(error).to be_a(Serf::Errors::LoadFailure)
110
+ expect(error.message).to match(/^File: .+$/)
111
+ }
112
+ end
113
+ end
114
+
73
115
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
+ require 'serf/errors/load_failure'
3
4
  require 'serf/loader/registry'
4
5
 
5
6
  describe Serf::Loader::Registry do
@@ -59,4 +60,18 @@ describe Serf::Loader::Registry do
59
60
  end
60
61
  end
61
62
 
63
+ context '#[] with error' do
64
+ it 'raises LoadFailure on error' do
65
+ subject.add 'component_name' do
66
+ raise 'Intentional Error'
67
+ end
68
+ expect {
69
+ subject['component_name']
70
+ }.to raise_error { |error|
71
+ expect(error).to be_a(Serf::Errors::LoadFailure)
72
+ expect(error.message).to match(/^Name: .+$/)
73
+ }
74
+ end
75
+ end
76
+
62
77
  end
@@ -14,7 +14,8 @@ describe Serf::Loader do
14
14
  subject {
15
15
  Serf::Loader.serfup(
16
16
  globs: [
17
- 'example/**/*.serf'
17
+ 'example/components/**/*.serf',
18
+ 'example/serfs/**/*.serf'
18
19
  ],
19
20
  serfs: [
20
21
  'subsystem/requests/create_widget'
@@ -11,12 +11,21 @@ describe Serf::Serfer do
11
11
  let(:request_parcel) {
12
12
  FactoryGirl.create :random_parcel
13
13
  }
14
+ let(:versioned_response_kind_version) {
15
+ SecureRandom.hex
16
+ }
17
+ let(:versioned_response_kind) {
18
+ "#{response_kind}\##{versioned_response_kind_version}"
19
+ }
14
20
  let(:response_kind) {
15
21
  SecureRandom.hex
16
22
  }
17
23
  let(:response_message) {
18
24
  FactoryGirl.create :random_hash
19
25
  }
26
+ let(:response_headers) {
27
+ FactoryGirl.create :random_hash
28
+ }
20
29
  let(:disconnected_response_parcel) {
21
30
  FactoryGirl.create :random_parcel
22
31
  }
@@ -49,14 +58,55 @@ describe Serf::Serfer do
49
58
  expect(parcel.message).to eq(response_message)
50
59
  end
51
60
 
52
- it 'uses parcel factory w/ kind, parent and message' do
61
+ it 'uses parcel factory w/ parent (w/ nil kind+message+headers)' do
62
+ mock_parcel_factory = double 'parcel_factory'
63
+ mock_parcel_factory.
64
+ should_receive(:create).
65
+ with({
66
+ parent: request_parcel,
67
+ kind: nil,
68
+ message: nil,
69
+ headers: nil
70
+ }).
71
+ and_return(disconnected_response_parcel)
72
+
73
+ serfer = described_class.new(
74
+ lambda { |obj| },
75
+ parcel_factory: mock_parcel_factory)
76
+ parcel = serfer.call request_parcel
77
+
78
+ expect(parcel).to eq(disconnected_response_parcel)
79
+ end
80
+
81
+ it 'uses parcel factory w/ kind, parent (w/ nil message+headers)' do
82
+ mock_parcel_factory = double 'parcel_factory'
83
+ mock_parcel_factory.
84
+ should_receive(:create).
85
+ with({
86
+ parent: request_parcel,
87
+ kind: response_kind,
88
+ message: nil,
89
+ headers: nil
90
+ }).
91
+ and_return(disconnected_response_parcel)
92
+
93
+ serfer = described_class.new(
94
+ lambda { |obj| return response_kind },
95
+ parcel_factory: mock_parcel_factory)
96
+ parcel = serfer.call request_parcel
97
+
98
+ expect(parcel).to eq(disconnected_response_parcel)
99
+ end
100
+
101
+ it 'uses parcel factory w/ kind, parent and message (w/ nil headers)' do
53
102
  mock_parcel_factory = double 'parcel_factory'
54
103
  mock_parcel_factory.
55
104
  should_receive(:create).
56
105
  with({
57
106
  parent: request_parcel,
58
107
  kind: response_kind,
59
- message: response_message
108
+ message: response_message,
109
+ headers: nil
60
110
  }).
61
111
  and_return(disconnected_response_parcel)
62
112
 
@@ -68,6 +118,52 @@ describe Serf::Serfer do
68
118
  expect(parcel).to eq(disconnected_response_parcel)
69
119
  end
70
120
 
121
+ it 'uses parcel factory w/ kind, parent, message and headers' do
122
+ mock_parcel_factory = double 'parcel_factory'
123
+ mock_parcel_factory.
124
+ should_receive(:create).
125
+ with({
126
+ parent: request_parcel,
127
+ kind: response_kind,
128
+ message: response_message,
129
+ headers: response_headers
130
+ }).
131
+ and_return(disconnected_response_parcel)
132
+
133
+ serfer = described_class.new(
134
+ lambda { |obj|
135
+ return response_kind, response_message, response_headers
136
+ },
137
+ parcel_factory: mock_parcel_factory)
138
+ parcel = serfer.call request_parcel
139
+
140
+ expect(parcel).to eq(disconnected_response_parcel)
141
+ end
142
+
143
+ it 'moves version info from a versioned kind to the headers' do
144
+ mock_parcel_factory = double 'parcel_factory'
145
+ mock_parcel_factory.
146
+ should_receive(:create).
147
+ with({
148
+ parent: request_parcel,
149
+ kind: response_kind,
150
+ message: response_message,
151
+ headers: {
152
+ version: versioned_response_kind_version
153
+ }
154
+ }).
155
+ and_return(disconnected_response_parcel)
156
+
157
+ serfer = described_class.new(
158
+ lambda { |obj|
159
+ return versioned_response_kind, response_message
160
+ },
161
+ parcel_factory: mock_parcel_factory)
162
+ parcel = serfer.call request_parcel
163
+
164
+ expect(parcel).to eq(disconnected_response_parcel)
165
+ end
166
+
71
167
  end
72
168
 
73
169
  end
@@ -12,7 +12,12 @@ describe Serf::Util::ErrorHandling do
12
12
  expect(result).to be_nil
13
13
  JsonSchemaTester.new.validate_for!(
14
14
  'serf/events/caught_error',
15
- error)
15
+ Hashie::Mash.new(error))
16
+ expect(error[:error]).to be_kind_of(String)
17
+ expect(error[:message]).to be_kind_of(String)
18
+ expect(error[:process_env]).to be_kind_of(Hash)
19
+ expect(error[:hostname]).to be_kind_of(String)
20
+ expect(error[:backtrace]).to be_kind_of(String)
16
21
  end
17
22
 
18
23
  end
@@ -21,6 +21,26 @@ describe Serf::Util::Uuidable do
21
21
 
22
22
  end
23
23
 
24
+ describe '#coded_uuid_time' do
25
+ let(:coded_uuid) {
26
+ 'RIEHuF5-EeKLPQQMzuOZ7g'
27
+ }
28
+ let(:time_seconds) {
29
+ 1358190718
30
+ }
31
+ let(:time_usec) {
32
+ 273324
33
+ }
34
+
35
+ it 'returns a valid time object' do
36
+ time = subject.coded_uuid_time coded_uuid
37
+ # Check that we have a good timestamp in seconds and nanoseconds
38
+ expect(time.to_i).to eq(time_seconds)
39
+ expect(time.tv_usec).to eq(time_usec)
40
+ end
41
+
42
+ end
43
+
24
44
  describe '#create_uuids' do
25
45
 
26
46
  it 'works with no parent' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-03 00:00:00.000000000 Z
12
+ date: 2013-02-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hashie
@@ -96,6 +96,7 @@ files:
96
96
  - example/serfs/create_widget.serf
97
97
  - lib/serf.rb
98
98
  - lib/serf/builder.rb
99
+ - lib/serf/errors/load_failure.rb
99
100
  - lib/serf/errors/policy_failure.rb
100
101
  - lib/serf/loader.rb
101
102
  - lib/serf/loader/loader.rb
@@ -115,6 +116,8 @@ files:
115
116
  - lib/serf/version.rb
116
117
  - schemas/serf/events/caught_error.json
117
118
  - serf.gemspec
119
+ - spec/data/construction_error.serf
120
+ - spec/data/raises_error.serf
118
121
  - spec/serf/builder_spec.rb
119
122
  - spec/serf/errors/policy_failure_spec.rb
120
123
  - spec/serf/loader/loader_spec.rb
@@ -155,7 +158,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
155
158
  version: '0'
156
159
  segments:
157
160
  - 0
158
- hash: -3964117889067138578
161
+ hash: 526665702158101187
159
162
  required_rubygems_version: !ruby/object:Gem::Requirement
160
163
  none: false
161
164
  requirements:
@@ -164,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
167
  version: '0'
165
168
  segments:
166
169
  - 0
167
- hash: -3964117889067138578
170
+ hash: 526665702158101187
168
171
  requirements: []
169
172
  rubyforge_project:
170
173
  rubygems_version: 1.8.23
@@ -172,6 +175,8 @@ signing_key:
172
175
  specification_version: 3
173
176
  summary: Interactors with policy protection
174
177
  test_files:
178
+ - spec/data/construction_error.serf
179
+ - spec/data/raises_error.serf
175
180
  - spec/serf/builder_spec.rb
176
181
  - spec/serf/errors/policy_failure_spec.rb
177
182
  - spec/serf/loader/loader_spec.rb