rains 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +3 -0
- data/.rubocop.yml +29 -0
- data/.rubocop_todo.yml +7 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +16 -0
- data/LICENSE +21 -0
- data/README.md +15 -0
- data/Rakefile +5 -0
- data/lib/rains.rb +18 -0
- data/lib/rains/assertion.rb +4 -0
- data/lib/rains/dsl/assertions.rb +13 -0
- data/lib/rains/dsl/dependencies.rb +13 -0
- data/lib/rains/dsl/translation.rb +21 -0
- data/lib/rains/form.rb +19 -0
- data/lib/rains/helpers.rb +10 -0
- data/lib/rains/serializer.rb +13 -0
- data/lib/rains/service.rb +60 -0
- data/lib/rains/version.rb +3 -0
- data/rains.gemspec +25 -0
- data/rakelib/mutant.rake +16 -0
- data/rakelib/rubocop.rake +17 -0
- data/spec/rains/dsl/assertions_spec.rb +28 -0
- data/spec/rains/dsl/dependencies_spec.rb +35 -0
- data/spec/rains/dsl/translation_spec.rb +52 -0
- data/spec/rains/form_spec.rb +65 -0
- data/spec/rains/helpers_spec.rb +17 -0
- data/spec/rains/serializer_spec.rb +26 -0
- data/spec/rains/service_spec.rb +123 -0
- data/spec/rains_spec.rb +5 -0
- data/spec/shared/en.yml +16 -0
- data/spec/shared/i18n.rb +15 -0
- data/spec/spec_helper.rb +6 -0
- metadata +148 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c22fc4439ba7d1e73ca9690fac1a06324e2be900
|
4
|
+
data.tar.gz: 11854bceb0869db31511f2d4b5cac34613b4b8da
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 527b2cbd870e10c1b383f0297b78d93820e42706926a267b3fa3026f46b78ad0114bc7999ec51966f877da3c702482c7323ad91bffb5d6062fc94d208fd57b94
|
7
|
+
data.tar.gz: 9b7ace8d34e8a7117b813456490643463cd12c467d4f3b3803152e2c760e04d97086b1b67835c0224824cb56c28bf9b1d0c7a2b1c434c803c8c70063f860cbfa
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
# Who needs documentation?
|
4
|
+
Style/Documentation:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
# RSpec styles
|
8
|
+
Style/BlockDelimiters:
|
9
|
+
EnforcedStyle: semantic
|
10
|
+
FunctionalMethods:
|
11
|
+
- let
|
12
|
+
- let!
|
13
|
+
- subject
|
14
|
+
- before
|
15
|
+
- after
|
16
|
+
|
17
|
+
# Don't introduce semantic fail/raise distinction
|
18
|
+
Style/SignalException:
|
19
|
+
EnforcedStyle: only_raise
|
20
|
+
|
21
|
+
# Mutant fails when change /\// to %r{\/}
|
22
|
+
Style/RegexpLiteral:
|
23
|
+
Exclude:
|
24
|
+
- 'lib/rains/dsl/translation.rb'
|
25
|
+
|
26
|
+
# Fix for LoadError on travis
|
27
|
+
Lint/HandleExceptions:
|
28
|
+
Exclude:
|
29
|
+
- 'rakelib/rubocop.rake'
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2015-09-10 03:49:07 +0300 using RuboCop version 0.34.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem 'rubocop', '~> 0.34'
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem 'codeclimate-test-reporter', require: nil
|
9
|
+
end
|
10
|
+
|
11
|
+
group :tools do
|
12
|
+
platform :mri do
|
13
|
+
gem 'mutant', '>= 0.8.0', github: 'mbj/mutant', branch: 'master'
|
14
|
+
gem 'mutant-rspec'
|
15
|
+
end
|
16
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Yuri Artemev
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
### rains
|
2
|
+
|
3
|
+
---
|
4
|
+
|
5
|
+
...
|
6
|
+
|
7
|
+
---
|
8
|
+
|
9
|
+
### Contributing
|
10
|
+
|
11
|
+
1. Fork it
|
12
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
13
|
+
3. Commit your changes (`git commit -am 'add some feature'`)
|
14
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
15
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/rains.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'virtus'
|
3
|
+
require 'inflecto'
|
4
|
+
require 'assertion'
|
5
|
+
|
6
|
+
require 'rains/dsl/assertions'
|
7
|
+
require 'rains/dsl/dependencies'
|
8
|
+
require 'rains/dsl/translation'
|
9
|
+
|
10
|
+
require 'rains/assertion'
|
11
|
+
require 'rains/form'
|
12
|
+
require 'rains/helpers'
|
13
|
+
require 'rains/serializer'
|
14
|
+
require 'rains/service'
|
15
|
+
require 'rains/version'
|
16
|
+
|
17
|
+
module Rains
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Rains
|
2
|
+
module DSL
|
3
|
+
module Translation
|
4
|
+
def translate
|
5
|
+
I18n.translate(translation_key)
|
6
|
+
end
|
7
|
+
|
8
|
+
def translation_key
|
9
|
+
"#{translation_root}.#{translation_class}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def translation_class
|
13
|
+
Inflecto.underscore(self.class).gsub(/\//, '.')
|
14
|
+
end
|
15
|
+
|
16
|
+
def translation_root
|
17
|
+
:rains
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/rains/form.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rains
|
2
|
+
class Form
|
3
|
+
extend DSL::Assertions
|
4
|
+
include Virtus.model(strict: true)
|
5
|
+
|
6
|
+
def as_form
|
7
|
+
attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate
|
11
|
+
cached = as_form
|
12
|
+
truthy = ::Assertion::State.new(true)
|
13
|
+
|
14
|
+
__assertions__.inject(truthy) do |acc, assertion|
|
15
|
+
acc + assertion[cached]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Rains
|
2
|
+
class Service
|
3
|
+
include Virtus.model(strict: true)
|
4
|
+
extend DSL::Dependencies
|
5
|
+
|
6
|
+
class Error < StandardError
|
7
|
+
include DSL::Translation
|
8
|
+
|
9
|
+
def translation_root
|
10
|
+
:service
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Result
|
15
|
+
attr_reader :value, :error
|
16
|
+
|
17
|
+
def success?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def error?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
class Success < Result
|
26
|
+
def initialize(value)
|
27
|
+
@value = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def success?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Fail < Result
|
36
|
+
def initialize(error)
|
37
|
+
@error = error
|
38
|
+
end
|
39
|
+
|
40
|
+
def error?
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def action
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
|
50
|
+
def call!
|
51
|
+
action
|
52
|
+
end
|
53
|
+
|
54
|
+
def call
|
55
|
+
Result::Success.new(action)
|
56
|
+
rescue StandardError => error
|
57
|
+
Result::Fail.new(error)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/rains.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'rains/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'rains'
|
7
|
+
gem.version = Rains::VERSION
|
8
|
+
gem.authors = ['Yuri Artemev']
|
9
|
+
gem.email = ['i@artemeff.com']
|
10
|
+
gem.summary = 'Gem for doing OOP the right way'
|
11
|
+
gem.description = 'Contains some useful techniques and best-practices'
|
12
|
+
gem.homepage = 'https://github.com/artemeff/rains'
|
13
|
+
gem.license = 'MIT'
|
14
|
+
gem.require_paths = ['lib']
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split("\n")
|
17
|
+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
18
|
+
|
19
|
+
gem.add_runtime_dependency 'virtus', '~> 1.0'
|
20
|
+
gem.add_runtime_dependency 'assertion', '~> 0.2'
|
21
|
+
gem.add_runtime_dependency 'inflecto', '~> 0.0'
|
22
|
+
|
23
|
+
gem.add_development_dependency 'rake', '~> 10.3'
|
24
|
+
gem.add_development_dependency 'rspec', '~> 3.3'
|
25
|
+
end
|
data/rakelib/mutant.rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
desc 'Run mutant against a specific subject'
|
2
|
+
task :mutant do
|
3
|
+
subject = ARGV.last
|
4
|
+
if subject == 'mutant'
|
5
|
+
abort "usage: rake mutant SUBJECT\nexample: rake mutant ROM::Header"
|
6
|
+
else
|
7
|
+
opts = {
|
8
|
+
'include' => 'lib',
|
9
|
+
'require' => 'rains',
|
10
|
+
'use' => 'rspec',
|
11
|
+
'ignore-subject' => "#{subject}#respond_to_missing?"
|
12
|
+
}.to_a.map { |k, v| "--#{k} #{v}" }.join(' ')
|
13
|
+
|
14
|
+
exec("bundle exec mutant #{opts} #{subject}")
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
|
4
|
+
Rake::Task[:default].enhance [:rubocop]
|
5
|
+
|
6
|
+
RuboCop::RakeTask.new do |task|
|
7
|
+
task.options << '--display-cop-names'
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace :rubocop do
|
11
|
+
desc 'Generate a configuration file acting as a TODO list.'
|
12
|
+
task :auto_gen_config do
|
13
|
+
exec 'bundle exec rubocop --auto-gen-config'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
describe Rains::DSL::Assertions do
|
2
|
+
it 'extend defines new method' do
|
3
|
+
simple = Class.new
|
4
|
+
|
5
|
+
expect(simple.instance_methods).not_to include(:assertions)
|
6
|
+
expect(simple).to receive(:define_method) { :__assertions__ }
|
7
|
+
|
8
|
+
simple.class_eval { extend Rains::DSL::Assertions }
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'has empty assertions by default' do
|
12
|
+
simple = Class.new do
|
13
|
+
extend Rains::DSL::Assertions
|
14
|
+
end
|
15
|
+
|
16
|
+
expect(simple.new.__assertions__).to eq([])
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'defines list of assertions when use dsl' do
|
20
|
+
simple = Class.new do
|
21
|
+
extend Rains::DSL::Assertions
|
22
|
+
|
23
|
+
assertions :one, :two
|
24
|
+
end
|
25
|
+
|
26
|
+
expect(simple.new.__assertions__).to eq([:one, :two])
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
describe Rains::DSL::Dependencies do
|
2
|
+
before do
|
3
|
+
module Test
|
4
|
+
class SampleService < Rains::Service
|
5
|
+
def action
|
6
|
+
true
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Sample
|
11
|
+
extend Rains::DSL::Dependencies
|
12
|
+
|
13
|
+
depends_on :sample, SampleService
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
subject { Test::Sample.new }
|
19
|
+
|
20
|
+
after { Object.send(:remove_const, :Test) }
|
21
|
+
|
22
|
+
it 'defines method for dependency' do
|
23
|
+
expect(subject.sample).to eq(Test::SampleService)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'throw error when try to use not Rains::Service for dependency' do
|
27
|
+
expect {
|
28
|
+
Class.new do
|
29
|
+
extend Rains::DSL::Dependencies
|
30
|
+
|
31
|
+
depends_on :sample, Hash
|
32
|
+
end
|
33
|
+
}.to raise_error(TypeError, 'The Hash is not a Rains::Service')
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
describe Rains::DSL::Translation do
|
2
|
+
include_context 'preloaded translations'
|
3
|
+
|
4
|
+
before do
|
5
|
+
module Test
|
6
|
+
module Nested
|
7
|
+
class NamedEntity
|
8
|
+
include Rains::DSL::Translation
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
subject { Test::Nested::NamedEntity.new }
|
15
|
+
|
16
|
+
after { Object.send(:remove_const, :Test) }
|
17
|
+
|
18
|
+
it 'defines new methods' do
|
19
|
+
empty = Class.new
|
20
|
+
methods = empty.instance_methods
|
21
|
+
|
22
|
+
expect(methods).not_to include(:translate)
|
23
|
+
expect(methods).not_to include(:translation_key)
|
24
|
+
expect(methods).not_to include(:translation_class)
|
25
|
+
expect(methods).not_to include(:translation_root)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'defined new methods' do
|
29
|
+
methods = subject.methods
|
30
|
+
|
31
|
+
expect(methods).to include(:translate)
|
32
|
+
expect(methods).to include(:translation_key)
|
33
|
+
expect(methods).to include(:translation_class)
|
34
|
+
expect(methods).to include(:translation_root)
|
35
|
+
end
|
36
|
+
|
37
|
+
it '#translation_root' do
|
38
|
+
expect(subject.translation_root).to eq(:rains)
|
39
|
+
end
|
40
|
+
|
41
|
+
it '#translation_class' do
|
42
|
+
expect(subject.translation_class).to eq('test.nested.named_entity')
|
43
|
+
end
|
44
|
+
|
45
|
+
it '#translation_key' do
|
46
|
+
expect(subject.translation_key).to eq('rains.test.nested.named_entity')
|
47
|
+
end
|
48
|
+
|
49
|
+
it '#translate' do
|
50
|
+
expect(subject.translate).to eq('test named entity')
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
describe Rains::Form do
|
2
|
+
include_context 'preloaded translations'
|
3
|
+
|
4
|
+
before do
|
5
|
+
module User
|
6
|
+
class IsAdult < Rains::Assertion
|
7
|
+
attribute :age
|
8
|
+
|
9
|
+
def check
|
10
|
+
return true if age.nil?
|
11
|
+
|
12
|
+
age >= 18
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class IsNameValid < Rains::Assertion
|
17
|
+
attribute :name
|
18
|
+
|
19
|
+
def check
|
20
|
+
(3..20).include?(name.size)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Form < Rains::Form
|
25
|
+
attribute :name, String
|
26
|
+
attribute :age, Integer, required: false
|
27
|
+
|
28
|
+
assertions IsAdult, IsNameValid
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
after { Object.send(:remove_const, :User) }
|
34
|
+
|
35
|
+
context '#validate' do
|
36
|
+
it 'returns truthy state' do
|
37
|
+
form = User::Form.new(name: 'john', age: 18)
|
38
|
+
result = form.validate
|
39
|
+
|
40
|
+
expect(result.valid?).to eq(true)
|
41
|
+
expect(result.messages).to eq([])
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns one falsy with custom translation' do
|
45
|
+
form = User::Form.new(name: 'jane', age: 16)
|
46
|
+
result = form.validate
|
47
|
+
|
48
|
+
expect(result.valid?).to eq(false)
|
49
|
+
expect(result.messages).to eq(['User is a child (age 16)'])
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'skips age validating' do
|
53
|
+
form = User::Form.new(name: 'jane')
|
54
|
+
result = form.validate
|
55
|
+
|
56
|
+
expect(result.valid?).to eq(true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'throws error when required attribute not provided' do
|
60
|
+
expect {
|
61
|
+
User::Form.new
|
62
|
+
}.to raise_error(Virtus::CoercionError)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Rains::Helpers do
|
2
|
+
context '#kind_of_service_class?' do
|
3
|
+
let(:dummy) { Class.new(Rains::Service) }
|
4
|
+
|
5
|
+
it 'false for not Rains::Service' do
|
6
|
+
expect(subject.kind_of_service_class?(Class)).to eq(false)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'false for not primitives' do
|
10
|
+
expect(subject.kind_of_service_class?(double)).to eq(false)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'true for Rains::Service' do
|
14
|
+
expect(subject.kind_of_service_class?(dummy)).to eq(true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
describe Rains::Serializer do
|
2
|
+
before do
|
3
|
+
module User
|
4
|
+
class Serializer < Rains::Serializer
|
5
|
+
attribute :name, String
|
6
|
+
attribute :age, Integer
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:all) { Object.send(:remove_const, :User) }
|
12
|
+
|
13
|
+
context '#to_json' do
|
14
|
+
it 'returns json string' do
|
15
|
+
serializer = User::Serializer.new(name: 'john', age: 21)
|
16
|
+
|
17
|
+
expect(serializer.to_json).to eq('{"name":"john","age":21}')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'uses as interface to json libs' do
|
21
|
+
serializer = User::Serializer.new(name: 'john', age: 21)
|
22
|
+
|
23
|
+
expect(JSON.dump(serializer)).to eq('{"name":"john","age":21}')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
describe Rains::Service do
|
2
|
+
include_context 'preloaded translations'
|
3
|
+
|
4
|
+
before do
|
5
|
+
module User
|
6
|
+
class Create < Rains::Service
|
7
|
+
attribute :name, String
|
8
|
+
attribute :age, Integer, required: false
|
9
|
+
end
|
10
|
+
|
11
|
+
class EmptyCreate < Create
|
12
|
+
def action
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class SampleDependency < Rains::Service
|
17
|
+
def action
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class EnhancedCreate < Create
|
23
|
+
CreateError = Class.new(Rains::Service::Error)
|
24
|
+
|
25
|
+
def action
|
26
|
+
raise CreateError
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Depends < Rains::Service
|
31
|
+
depends_on :sample, SampleDependency
|
32
|
+
|
33
|
+
def action
|
34
|
+
sample.new.call!
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class BrokenDepends < Rains::Service
|
39
|
+
depends_on :create, EnhancedCreate
|
40
|
+
|
41
|
+
def action
|
42
|
+
create.new(name: 'john').call
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
after { Object.send(:remove_const, :User) }
|
49
|
+
|
50
|
+
context '#call' do
|
51
|
+
it 'raises NotImplementedError for default action' do
|
52
|
+
expect {
|
53
|
+
User::Create.new(name: 'john').call
|
54
|
+
}.to raise_error(NotImplementedError)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns Service::Result' do
|
58
|
+
result = User::EmptyCreate.new(name: 'john').call
|
59
|
+
|
60
|
+
expect(result).to be_a(Rains::Service::Result)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns Service::Result::Success for success actions' do
|
64
|
+
result = User::EmptyCreate.new(name: 'john').call
|
65
|
+
|
66
|
+
expect(result).to be_a(Rains::Service::Result::Success)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns Service::Result::Fail for failed actions' do
|
70
|
+
result = User::EnhancedCreate.new(name: 'john').call
|
71
|
+
|
72
|
+
expect(result).to be_a(Rains::Service::Result::Fail)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'uses service dependency' do
|
76
|
+
result = User::Depends.new.call
|
77
|
+
|
78
|
+
expect(result.value).to eq(true)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'throws error when dependency fails' do
|
82
|
+
result = User::BrokenDepends.new.call!
|
83
|
+
|
84
|
+
expect(result.error).to be_a(User::EnhancedCreate::CreateError)
|
85
|
+
end
|
86
|
+
|
87
|
+
context '#value' do
|
88
|
+
it 'returns nothing for empty action' do
|
89
|
+
result = User::EmptyCreate.new(name: 'john').call
|
90
|
+
|
91
|
+
expect(result.value).to eq(nil)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context '#error' do
|
96
|
+
it 'returns error when raises error in action' do
|
97
|
+
result = User::EnhancedCreate.new(name: 'john').call
|
98
|
+
|
99
|
+
expect(result.error).to be_a(User::EnhancedCreate::CreateError)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'contains translation for raised error' do
|
103
|
+
result = User::EnhancedCreate.new(name: 'john').call
|
104
|
+
|
105
|
+
expect(result.error.translate).to eq('something went wrong')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context '#call!' do
|
111
|
+
it 'raises NotImplementedError for default action' do
|
112
|
+
expect {
|
113
|
+
User::Create.new(name: 'john').call!
|
114
|
+
}.to raise_error(NotImplementedError)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'raises error for any custom errors' do
|
118
|
+
expect {
|
119
|
+
User::EnhancedCreate.new(name: 'john').call!
|
120
|
+
}.to raise_error(User::EnhancedCreate::CreateError)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/spec/rains_spec.rb
ADDED
data/spec/shared/en.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
assertion:
|
4
|
+
user/is_adult:
|
5
|
+
truthy: "User is an adult (age %{age})"
|
6
|
+
falsey: "User is a child (age %{age})"
|
7
|
+
|
8
|
+
service:
|
9
|
+
user:
|
10
|
+
enhanced_create:
|
11
|
+
create_error: something went wrong
|
12
|
+
|
13
|
+
rains:
|
14
|
+
test:
|
15
|
+
nested:
|
16
|
+
named_entity: 'test named entity'
|
data/spec/shared/i18n.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
shared_context 'preloaded translations' do
|
2
|
+
around do |example|
|
3
|
+
load_path = Dir[File.expand_path '../*.yml', __FILE__]
|
4
|
+
|
5
|
+
old_path, I18n.load_path = I18n.load_path, load_path
|
6
|
+
old_locale, I18n.locale = I18n.locale, :en
|
7
|
+
I18n.backend.load_translations
|
8
|
+
|
9
|
+
example.run
|
10
|
+
|
11
|
+
I18n.locale = old_locale
|
12
|
+
I18n.load_path = old_path
|
13
|
+
I18n.backend.reload!
|
14
|
+
end
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rains
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yuri Artemev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: virtus
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: assertion
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: inflecto
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.3'
|
83
|
+
description: Contains some useful techniques and best-practices
|
84
|
+
email:
|
85
|
+
- i@artemeff.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".rubocop.yml"
|
93
|
+
- ".rubocop_todo.yml"
|
94
|
+
- ".travis.yml"
|
95
|
+
- CHANGELOG.md
|
96
|
+
- Gemfile
|
97
|
+
- LICENSE
|
98
|
+
- README.md
|
99
|
+
- Rakefile
|
100
|
+
- lib/rains.rb
|
101
|
+
- lib/rains/assertion.rb
|
102
|
+
- lib/rains/dsl/assertions.rb
|
103
|
+
- lib/rains/dsl/dependencies.rb
|
104
|
+
- lib/rains/dsl/translation.rb
|
105
|
+
- lib/rains/form.rb
|
106
|
+
- lib/rains/helpers.rb
|
107
|
+
- lib/rains/serializer.rb
|
108
|
+
- lib/rains/service.rb
|
109
|
+
- lib/rains/version.rb
|
110
|
+
- rains.gemspec
|
111
|
+
- rakelib/mutant.rake
|
112
|
+
- rakelib/rubocop.rake
|
113
|
+
- spec/rains/dsl/assertions_spec.rb
|
114
|
+
- spec/rains/dsl/dependencies_spec.rb
|
115
|
+
- spec/rains/dsl/translation_spec.rb
|
116
|
+
- spec/rains/form_spec.rb
|
117
|
+
- spec/rains/helpers_spec.rb
|
118
|
+
- spec/rains/serializer_spec.rb
|
119
|
+
- spec/rains/service_spec.rb
|
120
|
+
- spec/rains_spec.rb
|
121
|
+
- spec/shared/en.yml
|
122
|
+
- spec/shared/i18n.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
homepage: https://github.com/artemeff/rains
|
125
|
+
licenses:
|
126
|
+
- MIT
|
127
|
+
metadata: {}
|
128
|
+
post_install_message:
|
129
|
+
rdoc_options: []
|
130
|
+
require_paths:
|
131
|
+
- lib
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
requirements: []
|
143
|
+
rubyforge_project:
|
144
|
+
rubygems_version: 2.4.8
|
145
|
+
signing_key:
|
146
|
+
specification_version: 4
|
147
|
+
summary: Gem for doing OOP the right way
|
148
|
+
test_files: []
|