railjet 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +44 -0
- data/.rspec +2 -0
- data/.ruby-gemset +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +96 -0
- data/LICENSE.txt +21 -0
- data/README.md +250 -0
- data/Rakefile +17 -0
- data/VERSION +1 -0
- data/bin/bundler +17 -0
- data/bin/coderay +17 -0
- data/bin/console +14 -0
- data/bin/htmldiff +17 -0
- data/bin/ldiff +17 -0
- data/bin/pry +17 -0
- data/bin/rake +17 -0
- data/bin/rspec +17 -0
- data/bin/setup +8 -0
- data/lib/active_model/merge_errors.rb +22 -0
- data/lib/gettext_i18n/translate_attributes.rb +73 -0
- data/lib/railjet.rb +46 -0
- data/lib/railjet/auth/ability.rb +20 -0
- data/lib/railjet/auth/activity.rb +12 -0
- data/lib/railjet/composed_policy.rb +41 -0
- data/lib/railjet/context.rb +32 -0
- data/lib/railjet/form.rb +10 -0
- data/lib/railjet/policy.rb +26 -0
- data/lib/railjet/railtie.rb +7 -0
- data/lib/railjet/repository.rb +34 -0
- data/lib/railjet/repository/active_record.rb +54 -0
- data/lib/railjet/repository/cupido.rb +34 -0
- data/lib/railjet/repository/registry.rb +71 -0
- data/lib/railjet/use_case.rb +65 -0
- data/lib/railjet/util/form_helper.rb +26 -0
- data/lib/railjet/util/policy_helper.rb +9 -0
- data/lib/railjet/util/use_case_helper.rb +9 -0
- data/lib/railjet/validator.rb +15 -0
- data/lib/railjet/version.rb +3 -0
- data/lib/tasks/gettext_i18n.rake +36 -0
- data/railjet.gemspec +33 -0
- metadata +226 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module Railjet
|
2
|
+
module Policy
|
3
|
+
extend ::ActiveSupport::Concern
|
4
|
+
include Railjet::Validator
|
5
|
+
|
6
|
+
attr_reader :context, :object
|
7
|
+
|
8
|
+
def initialize(context, object)
|
9
|
+
@context, @object = context, object
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate!
|
13
|
+
valid? || (raise Railjet::PolicyError.new(errors) )
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def context(*context_members)
|
18
|
+
delegate *context_members, to: :context
|
19
|
+
end
|
20
|
+
|
21
|
+
def object(name)
|
22
|
+
alias_method name, :object
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "railjet/repository/active_record"
|
2
|
+
require "railjet/repository/cupido"
|
3
|
+
|
4
|
+
module Railjet
|
5
|
+
module Repository
|
6
|
+
extend ::ActiveSupport::Concern
|
7
|
+
|
8
|
+
attr_reader :registry
|
9
|
+
delegate :settings, to: :registry
|
10
|
+
|
11
|
+
attr_reader :record_dao, :cupido_dao
|
12
|
+
|
13
|
+
def initialize(registry, record: nil, cupido: nil)
|
14
|
+
@registry = registry
|
15
|
+
|
16
|
+
@record_dao = record
|
17
|
+
@cupido_dao = cupido
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def record
|
23
|
+
if self.class.const_defined?("ActiveRecordRepository")
|
24
|
+
@record ||= self.class::ActiveRecordRepository.new(registry, record_dao)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def cupido
|
29
|
+
if self.class.const_defined?("CupidoRepository")
|
30
|
+
@cupido ||= self.class::CupidoRepository.new(registry, cupido_dao)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Railjet
|
2
|
+
module Repository
|
3
|
+
module ActiveRecord
|
4
|
+
extend ::ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_reader :registry, :record
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(registry, record = nil)
|
11
|
+
@registry = registry
|
12
|
+
@record = record
|
13
|
+
end
|
14
|
+
|
15
|
+
def all
|
16
|
+
record.all
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_by_ids(ids)
|
20
|
+
record.where(id: ids)
|
21
|
+
end
|
22
|
+
|
23
|
+
def build(args = {}, &block)
|
24
|
+
record.new(args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def duplicate(object, args = {})
|
28
|
+
object.dup.tap do |new_object|
|
29
|
+
new_object.assign_attributes(args) if args.present?
|
30
|
+
yield(new_object) if block_given?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def persist(object)
|
35
|
+
object.save!
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy(object)
|
39
|
+
object.destroy!
|
40
|
+
end
|
41
|
+
|
42
|
+
def transaction(&block)
|
43
|
+
record.transaction(&block)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def query_columns
|
49
|
+
columns = (record.column_names - [:created_at, :updated_at])
|
50
|
+
columns.map { |column_name| "#{record.table_name}.#{column_name}" }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Railjet
|
2
|
+
module Repository
|
3
|
+
module Cupido
|
4
|
+
extend ::ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_reader :registry, :cupido
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(registry, cupido = nil)
|
11
|
+
@registry = registry
|
12
|
+
@cupido = cupido
|
13
|
+
end
|
14
|
+
|
15
|
+
def build(args = {})
|
16
|
+
cupido.new(args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def persist(object)
|
20
|
+
cupido.do.create(object)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def for_person(person)
|
26
|
+
cupido.find.proxy(person.external_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def cupido_class(obj)
|
30
|
+
"Cupido::#{obj.class.name}".constantize
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Railjet
|
2
|
+
module Repository
|
3
|
+
class Registry
|
4
|
+
attr_reader :repositories, :initialized_repositories
|
5
|
+
protected :repositories, :initialized_repositories
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@repositories = {}
|
9
|
+
@initialized_repositories = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def register(name, repository, **kwargs)
|
13
|
+
add_to_registry(name, repository, kwargs)
|
14
|
+
define_accessor(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def new(**kwargs)
|
18
|
+
self.clone.tap do |registry|
|
19
|
+
unless kwargs.blank?
|
20
|
+
clone_module = Module.new.tap { |m| registry.extend(m) }
|
21
|
+
|
22
|
+
kwargs.each do |name, val|
|
23
|
+
clone_module.send(:define_method, name) { val }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def initialize_copy(original)
|
32
|
+
super
|
33
|
+
|
34
|
+
@initialized_repositories = original.initialized_repositories.dup
|
35
|
+
@repositories = original.repositories.dup
|
36
|
+
@registry_module = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_to_registry(name, repository, args = {})
|
40
|
+
initialized_repositories[name] = nil
|
41
|
+
repositories[name] = {
|
42
|
+
repository: repository,
|
43
|
+
args: args
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_from_registry(name)
|
48
|
+
repositories[name]
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize_repo(name)
|
52
|
+
initialized_repositories[name] ||= begin
|
53
|
+
repo = get_from_registry(name)
|
54
|
+
klass = repo[:repository]
|
55
|
+
args = repo[:args]
|
56
|
+
|
57
|
+
klass.new(self, **args)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def define_accessor(name)
|
62
|
+
pluralized_name = name.to_s.pluralize
|
63
|
+
registry_module.send(:define_method, pluralized_name) { initialize_repo(name) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def registry_module
|
67
|
+
@registry_module ||= Module.new.tap { |m| self.class.include(m) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Railjet
|
2
|
+
module UseCase
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ::Railjet::Util::UseCaseHelper
|
5
|
+
include ::Railjet::Util::PolicyHelper
|
6
|
+
|
7
|
+
attr_reader :context
|
8
|
+
|
9
|
+
def initialize(context)
|
10
|
+
@context = context
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_requirements_check(*args)
|
14
|
+
with_ability_check(*args) do
|
15
|
+
with_policy_check(*args) do
|
16
|
+
yield if block_given?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def with_ability_check(*args)
|
22
|
+
if check_ability!(*args)
|
23
|
+
yield if block_given?
|
24
|
+
else
|
25
|
+
raise Railjet::UnauthorizedError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_policy_check(*args)
|
30
|
+
check_policy!(*args)
|
31
|
+
yield if block_given?
|
32
|
+
rescue Railjet::PolicyError => e
|
33
|
+
raise Railjet::PolicyNotMetError.new(e.errors)
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_ability!(*args)
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_policy!(*args)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
module ClassMethods
|
45
|
+
def context(*context_members)
|
46
|
+
delegate *context_members, to: :context
|
47
|
+
end
|
48
|
+
|
49
|
+
def repositories(*repositories)
|
50
|
+
context :repository
|
51
|
+
delegate *repositories, to: :repository
|
52
|
+
end
|
53
|
+
|
54
|
+
def check_ability(ability_name)
|
55
|
+
define_method :check_ability! do |*args|
|
56
|
+
context.current_ability.send(ability_name, *args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def check_policy(&block)
|
61
|
+
define_method :check_policy!, &block
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Railjet
|
2
|
+
module Util
|
3
|
+
module FormHelper
|
4
|
+
def form(klass)
|
5
|
+
klass.new(clean_params).tap(&:validate!)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def object_params
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def clean_params
|
15
|
+
object_params
|
16
|
+
end
|
17
|
+
|
18
|
+
def respond_with_errors(object_with_errors, status: :unprocessable_entity)
|
19
|
+
raise ArgumentError unless object_with_errors.respond_to?(:errors)
|
20
|
+
|
21
|
+
response = object_with_errors.errors.to_hash(true)
|
22
|
+
render json: response, status: status
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Railjet
|
2
|
+
# @private Use either form or policy
|
3
|
+
module Validator
|
4
|
+
extend ::ActiveSupport::Concern
|
5
|
+
include ::ActiveModel::Model
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Virtus.model(nullify_blank: true)
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate!
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
namespace :gettext do
|
2
|
+
def files_to_translate
|
3
|
+
Dir.glob("{app,lib,config,locale,gems,engines}/**/*.{rb,erb,haml,slim,rhtml}")
|
4
|
+
end
|
5
|
+
|
6
|
+
desc "write the form attributes to <locale_path>/form_attributes.rb"
|
7
|
+
task :store_form_attributes, [:file] => :environment do |t, args|
|
8
|
+
FastGettext.silence_errors
|
9
|
+
|
10
|
+
require "gettext_i18n/translate_attributes"
|
11
|
+
|
12
|
+
storage_file = args[:file] || "#{locale_path}/form_attributes.rb"
|
13
|
+
puts "writing form translations to: #{storage_file}"
|
14
|
+
|
15
|
+
GettextI18n::TranslateAttributes.store_form_attributes(file: storage_file)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "write the policy attributes to <locale_path>/policy_attributes.rb"
|
19
|
+
task :store_policy_attributes, [:file] => :environment do |t, args|
|
20
|
+
args.with_defau
|
21
|
+
FastGettext.silence_errors
|
22
|
+
|
23
|
+
require "gettext_i18n/translate_attributes"
|
24
|
+
|
25
|
+
storage_file = args[:file] || "#{locale_path}/policy_attributes.rb"
|
26
|
+
puts "writing form translations to: #{storage_file}"
|
27
|
+
|
28
|
+
GettextI18n::TranslateAttributes.store_policy_attributes(file: storage_file)
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "write validators (policy & form) attributes"
|
32
|
+
task :store_attributes, [:form_file, :policy_file] => :environment do |t, args|
|
33
|
+
Rake::Task["gettext:store_form_attributes", args[:form_file]].invoke
|
34
|
+
Rake::Task["gettext:store_policy_attributes", args[:policy_file]].invoke
|
35
|
+
end
|
36
|
+
end
|
data/railjet.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "railjet/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "railjet"
|
8
|
+
spec.version = Railjet::VERSION
|
9
|
+
spec.authors = ["Krzysztof Zalewski"]
|
10
|
+
spec.email = ["zlw.zalewski@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Better architecture for high-speed railway}
|
13
|
+
spec.description = %q{Design patterns for Ruby on Rails}
|
14
|
+
spec.homepage = "https://github.com/nedap/railjet"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
23
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
spec.add_development_dependency "pry"
|
26
|
+
spec.add_development_dependency "gemfury"
|
27
|
+
spec.add_development_dependency "rake-version", "~> 1.0"
|
28
|
+
|
29
|
+
spec.add_dependency "activesupport", '~> 4.2'
|
30
|
+
spec.add_dependency "activemodel", '~> 4.2'
|
31
|
+
spec.add_dependency "virtus", "~> 1.0.2"
|
32
|
+
spec.add_dependency "validates_timeliness", "~> 3.0.15"
|
33
|
+
end
|