pavlov 0.0.1
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/lib/pavlov.rb +41 -0
- data/lib/pavlov/access_denied.rb +4 -0
- data/lib/pavlov/command.rb +11 -0
- data/lib/pavlov/entity.rb +61 -0
- data/lib/pavlov/helpers.rb +33 -0
- data/lib/pavlov/helpers/safe_evaluator.rb +17 -0
- data/lib/pavlov/interactor.rb +20 -0
- data/lib/pavlov/operation.rb +72 -0
- data/lib/pavlov/query.rb +12 -0
- data/lib/pavlov/utils.rb +7 -0
- data/lib/pavlov/validation_error.rb +4 -0
- data/lib/pavlov/validations.rb +38 -0
- data/lib/pavlov/validations/errors.rb +21 -0
- data/lib/pavlov/validations/not_valid.rb +7 -0
- data/lib/pavlov/version.rb +6 -0
- metadata +214 -0
data/lib/pavlov.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Pavlov
|
2
|
+
# this method is also available as constantize in Rails,
|
3
|
+
# but we want to be able to write classes and/or tests without Rails
|
4
|
+
def self.get_class_by_string classname
|
5
|
+
classname.constantize
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.string_to_classname string
|
9
|
+
string.to_s.camelize
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.command command_name, *args
|
13
|
+
class_name = "Commands::"+string_to_classname(command_name)
|
14
|
+
klass = get_class_by_string(class_name)
|
15
|
+
klass.new(*args).call
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.interactor command_name, *args
|
19
|
+
class_name = "Interactors::"+string_to_classname(command_name)
|
20
|
+
klass = get_class_by_string class_name
|
21
|
+
klass.new(*args).call
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.query command_name, *args
|
25
|
+
class_name = "Queries::"+string_to_classname(command_name)
|
26
|
+
klass = get_class_by_string class_name
|
27
|
+
klass.new(*args).call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require_relative 'pavlov/helpers'
|
32
|
+
require_relative 'pavlov/utils'
|
33
|
+
require_relative 'pavlov/access_denied'
|
34
|
+
require_relative 'pavlov/validation_error'
|
35
|
+
require_relative 'pavlov/validations'
|
36
|
+
require_relative 'pavlov/operation'
|
37
|
+
require_relative 'pavlov/command'
|
38
|
+
require_relative 'pavlov/query'
|
39
|
+
require_relative 'pavlov/interactor'
|
40
|
+
require_relative 'pavlov/entity'
|
41
|
+
require_relative 'pavlov/version'
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative 'helpers/safe_evaluator'
|
2
|
+
|
3
|
+
module Pavlov
|
4
|
+
class Entity
|
5
|
+
def self.attributes *args
|
6
|
+
args.each do |attribute_name|
|
7
|
+
define_attribute_writer attribute_name
|
8
|
+
attr_reader attribute_name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new hash = {}, &block
|
13
|
+
super().send :mutate, hash, &block
|
14
|
+
end
|
15
|
+
|
16
|
+
def update hash = {}, &block
|
17
|
+
self.dup.send :mutate, hash, &block
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def mutate hash, &block
|
22
|
+
copy_hash_values hash
|
23
|
+
safely_evaluate_against(&block) if block_given?
|
24
|
+
validate if respond_to? :validate
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def copy_hash_values hash
|
29
|
+
make_temporary_mutatable do
|
30
|
+
hash.each {|key,value| send("#{key}=",value)}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def safely_evaluate_against &block
|
35
|
+
make_temporary_mutatable do
|
36
|
+
caller_instance = eval "self", block.binding
|
37
|
+
evaluator = Pavlov::Helpers::SafeEvaluator.new(self, caller_instance)
|
38
|
+
evaluator.instance_eval(&block)
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def make_temporary_mutatable &block
|
44
|
+
@mutable = true
|
45
|
+
block.call
|
46
|
+
@mutable = false
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.define_attribute_writer attribute_name
|
50
|
+
define_method "#{attribute_name}=" do |new_value|
|
51
|
+
raise_not_mutable unless @mutable
|
52
|
+
instance_variable_symbol = "@#{attribute_name}".to_sym
|
53
|
+
instance_variable_set instance_variable_symbol, new_value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def raise_not_mutable
|
58
|
+
raise "This entity is immutable, please use 'instance = #{self.class.name}.new do; self.attribute = 'value'; end' or 'instance = instance.update do; self.attribute = 'value'; end'."
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Pavlov
|
2
|
+
module Helpers
|
3
|
+
def interactor name, *args
|
4
|
+
args = add_pavlov_options args
|
5
|
+
Pavlov.interactor name, *args
|
6
|
+
end
|
7
|
+
|
8
|
+
def query name, *args
|
9
|
+
args = add_pavlov_options args
|
10
|
+
Pavlov.query name, *args, pavlov_options
|
11
|
+
end
|
12
|
+
|
13
|
+
def command name, *args
|
14
|
+
args = add_pavlov_options args
|
15
|
+
Pavlov.command name, *args, pavlov_options
|
16
|
+
end
|
17
|
+
|
18
|
+
def pavlov_options
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def add_pavlov_options args
|
24
|
+
# TODO: we should do this at a point where we know how many arguments we need
|
25
|
+
# so we can decide if we need to merge with another options object or
|
26
|
+
# just add it.
|
27
|
+
if pavlov_options != {}
|
28
|
+
args << pavlov_options
|
29
|
+
end
|
30
|
+
args
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pavlov
|
2
|
+
module Helpers
|
3
|
+
class SafeEvaluator < BasicObject
|
4
|
+
def initialize target_instance, caller_instance
|
5
|
+
@target_instance, @caller_instance = target_instance, caller_instance
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing method_name, *args
|
9
|
+
if method_name[-1] == '='
|
10
|
+
@target_instance.public_send method_name, *args
|
11
|
+
else
|
12
|
+
@caller_instance.send method_name, *args
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
module Pavlov
|
5
|
+
module Interactor
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include Pavlov::Operation
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
# make our interactors behave as Resque jobs
|
11
|
+
def perform(*args)
|
12
|
+
new(*args).call
|
13
|
+
end
|
14
|
+
|
15
|
+
def queue
|
16
|
+
@queue ||= :interactor_operations
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Pavlov
|
4
|
+
module Operation
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
include Pavlov::Helpers
|
7
|
+
include Pavlov::Validations
|
8
|
+
include Pavlov::Utils
|
9
|
+
def pavlov_options
|
10
|
+
@options
|
11
|
+
end
|
12
|
+
|
13
|
+
def raise_unauthorized(message='Unauthorized')
|
14
|
+
raise Pavlov::AccessDenied, message
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_authority
|
18
|
+
raise_unauthorized unless respond_to? :authorized? and authorized?
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize *params
|
22
|
+
keys = (respond_to? :arguments) ? arguments : []
|
23
|
+
names = params.first(keys.length)
|
24
|
+
if params.length == keys.length + 1
|
25
|
+
@options = params.last
|
26
|
+
elsif params.length == keys.length
|
27
|
+
@options = {}
|
28
|
+
else
|
29
|
+
raise "wrong number of arguments."
|
30
|
+
end
|
31
|
+
|
32
|
+
(keys.zip names).each do |pair|
|
33
|
+
name = "@" + pair[0].to_s
|
34
|
+
value = pair[1]
|
35
|
+
instance_variable_set(name, value)
|
36
|
+
end
|
37
|
+
|
38
|
+
validate if respond_to? :validate
|
39
|
+
check_authority
|
40
|
+
finish_initialize if respond_to? :finish_initialize
|
41
|
+
end
|
42
|
+
|
43
|
+
def call
|
44
|
+
self.execute
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
# arguments :foo, :bar
|
49
|
+
#
|
50
|
+
# results in
|
51
|
+
#
|
52
|
+
# def initialize(foo, bar)
|
53
|
+
# @foo = foo
|
54
|
+
# @bar = bar
|
55
|
+
# end
|
56
|
+
def arguments *keys
|
57
|
+
define_method :arguments do
|
58
|
+
keys
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# make our interactors behave as Resque jobs
|
63
|
+
def perform(*args)
|
64
|
+
new(*args).call
|
65
|
+
end
|
66
|
+
|
67
|
+
def queue
|
68
|
+
@queue || :interactor_operations
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/pavlov/query.rb
ADDED
data/lib/pavlov/utils.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'validations/errors'
|
2
|
+
require_relative 'validations/not_valid'
|
3
|
+
|
4
|
+
module Pavlov
|
5
|
+
module Validations
|
6
|
+
def errors
|
7
|
+
@errors ||= Pavlov::Validations::Errors.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_hexadecimal_string param_name, param
|
11
|
+
raise Pavlov::ValidationError, "#{param_name.to_s} should be an hexadecimal string." unless param.is_a? String and /\A[\da-fA-F]+\Z/.match param
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_regex param_name, param, regex, message
|
15
|
+
raise Pavlov::ValidationError, "#{param_name.to_s} #{message}" unless regex.match param
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate_integer param_name, param
|
19
|
+
raise Pavlov::ValidationError, "#{param_name.to_s} should be an integer." unless param.is_a? Integer
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate_in_set param_name, param, set
|
23
|
+
raise Pavlov::ValidationError, "#{param_name.to_s} should be on of these values: #{set.inspect}." unless set.include? param
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_string param_name, param
|
27
|
+
raise Pavlov::ValidationError, "#{param_name.to_s} should be a string." unless param.is_a? String
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_integer_string param_name, param
|
31
|
+
raise Pavlov::ValidationError, "#{param_name.to_s} should be an integer string." unless param.is_a? String and /\A\d+\Z/.match param
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate_not_nil param_name, param
|
35
|
+
raise Pavlov::ValidationError, "#{param_name.to_s} should not be nil." if param.nil?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pavlov
|
2
|
+
module Validations
|
3
|
+
module Errors
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@messages = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def each &block
|
11
|
+
@messages.each_key do |attribute|
|
12
|
+
@messages[attribute.to_s].each { |error| block.call attribute, error }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def add attribute, error_message
|
17
|
+
(@messages[attribute.to_s] ||= []) << error_message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pavlov
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mark IJbema
|
9
|
+
- Tom de Vries
|
10
|
+
- Jan Paul Posma
|
11
|
+
- Remon Oldenbeuving
|
12
|
+
- Jan Deelstra
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
date: 2013-01-14 00:00:00.000000000 Z
|
17
|
+
dependencies:
|
18
|
+
- !ruby/object:Gem::Dependency
|
19
|
+
name: activesupport
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
21
|
+
none: false
|
22
|
+
requirements:
|
23
|
+
- - ! '>='
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 3.2.7
|
26
|
+
type: :runtime
|
27
|
+
prerelease: false
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.2.7
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: minitest
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
type: :development
|
43
|
+
prerelease: false
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: minitest-stub-const
|
52
|
+
requirement: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
type: :development
|
59
|
+
prerelease: false
|
60
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: guard
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: guard-bundler
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: guard-minitest
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
type: :development
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
- !ruby/object:Gem::Dependency
|
115
|
+
name: rb-fsevent
|
116
|
+
requirement: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
type: :development
|
123
|
+
prerelease: false
|
124
|
+
version_requirements: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ! '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
name: rake
|
132
|
+
requirement: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ! '>='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
none: false
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
- !ruby/object:Gem::Dependency
|
147
|
+
name: benchmark-ips
|
148
|
+
requirement: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
type: :development
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ! '>='
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
description: Pavlov is a opinionated toolbox to help you architect your Ruby project.
|
163
|
+
email:
|
164
|
+
- jan+pavlov@deelstra.org
|
165
|
+
executables: []
|
166
|
+
extensions: []
|
167
|
+
extra_rdoc_files: []
|
168
|
+
files:
|
169
|
+
- lib/pavlov.rb
|
170
|
+
- lib/pavlov/access_denied.rb
|
171
|
+
- lib/pavlov/command.rb
|
172
|
+
- lib/pavlov/entity.rb
|
173
|
+
- lib/pavlov/helpers.rb
|
174
|
+
- lib/pavlov/helpers/safe_evaluator.rb
|
175
|
+
- lib/pavlov/interactor.rb
|
176
|
+
- lib/pavlov/operation.rb
|
177
|
+
- lib/pavlov/query.rb
|
178
|
+
- lib/pavlov/utils.rb
|
179
|
+
- lib/pavlov/validation_error.rb
|
180
|
+
- lib/pavlov/validations.rb
|
181
|
+
- lib/pavlov/validations/errors.rb
|
182
|
+
- lib/pavlov/validations/not_valid.rb
|
183
|
+
- lib/pavlov/version.rb
|
184
|
+
homepage: https://github.com/Factlink/pavlov/
|
185
|
+
licenses: []
|
186
|
+
post_install_message:
|
187
|
+
rdoc_options: []
|
188
|
+
require_paths:
|
189
|
+
- lib
|
190
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
191
|
+
none: false
|
192
|
+
requirements:
|
193
|
+
- - ! '>='
|
194
|
+
- !ruby/object:Gem::Version
|
195
|
+
version: '0'
|
196
|
+
segments:
|
197
|
+
- 0
|
198
|
+
hash: -4075067472850494356
|
199
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
200
|
+
none: false
|
201
|
+
requirements:
|
202
|
+
- - ! '>='
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: '0'
|
205
|
+
segments:
|
206
|
+
- 0
|
207
|
+
hash: -4075067472850494356
|
208
|
+
requirements: []
|
209
|
+
rubyforge_project:
|
210
|
+
rubygems_version: 1.8.23
|
211
|
+
signing_key:
|
212
|
+
specification_version: 3
|
213
|
+
summary: Infrastructure for defining your Ruby architecture.
|
214
|
+
test_files: []
|