state-handler 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/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +28 -0
- data/README +0 -0
- data/examples/response.rb +25 -0
- data/lib/state-handler.rb +7 -0
- data/lib/state-handler/mixing.rb +92 -0
- data/lib/state-handler/version.rb +3 -0
- data/spec/lib/state-handler/mixing_spec.rb +100 -0
- data/spec/spec_helper.rb +20 -0
- data/state-handler.gemspec +22 -0
- metadata +90 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color -fd
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
state-handler (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.3)
|
10
|
+
rake (0.9.2.2)
|
11
|
+
rspec (2.10.0)
|
12
|
+
rspec-core (~> 2.10.0)
|
13
|
+
rspec-expectations (~> 2.10.0)
|
14
|
+
rspec-mocks (~> 2.10.0)
|
15
|
+
rspec-core (2.10.0)
|
16
|
+
rspec-expectations (2.10.0)
|
17
|
+
diff-lcs (~> 1.1.3)
|
18
|
+
rspec-mocks (2.10.1)
|
19
|
+
timecop (0.3.5)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
rake
|
26
|
+
rspec
|
27
|
+
state-handler!
|
28
|
+
timecop
|
data/README
ADDED
File without changes
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '../lib/'))
|
3
|
+
|
4
|
+
require 'ostruct'
|
5
|
+
require 'state-handler'
|
6
|
+
|
7
|
+
class ResponseHandler
|
8
|
+
include StateHandler::Mixing
|
9
|
+
|
10
|
+
code 200 => :success
|
11
|
+
code 404 => :not_found
|
12
|
+
code 401 => :unauthorized
|
13
|
+
|
14
|
+
match /5\d\d/ => :error
|
15
|
+
end
|
16
|
+
|
17
|
+
response = OpenStruct.new(:code => 500)
|
18
|
+
ResponseHandler.new(response) do |r|
|
19
|
+
r.at :not_found, :unauthorized do
|
20
|
+
puts 'Another response handled'
|
21
|
+
end
|
22
|
+
|
23
|
+
r.success { puts 'Request executed' }
|
24
|
+
r.error { puts 'Request failed' }
|
25
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module StateHandler
|
2
|
+
module Mixing
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.class_attribute :mapping, :patterns
|
6
|
+
base.mapping, base.patterns = {}, {}
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :response
|
10
|
+
|
11
|
+
def initialize(response, &block)
|
12
|
+
raise ArgumentError unless response.respond_to?(:code)
|
13
|
+
@response, @blocks = response, {}
|
14
|
+
exec(&block) if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
def exec(&block)
|
18
|
+
# map blocks
|
19
|
+
yield(self)
|
20
|
+
|
21
|
+
if state
|
22
|
+
@blocks[state].call
|
23
|
+
else
|
24
|
+
self.class.patterns.each do |s, regex|
|
25
|
+
@blocks[s].call if @response.code.to_s =~ regex
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def at(*args, &block)
|
31
|
+
args.each { |s| @blocks[s.to_sym] = block }
|
32
|
+
end
|
33
|
+
|
34
|
+
def state
|
35
|
+
self.class.mapping.keys.each.find { |state| find_mapped(state) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_mapped(state)
|
39
|
+
if self.class.mapping[state].kind_of?(Array)
|
40
|
+
self.class.mapping[state].include?(@response.code.to_i)
|
41
|
+
else
|
42
|
+
self.class.mapping[state] == @response.code.to_i
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(name, &block)
|
47
|
+
state = name.to_s.gsub(/\?/, '').to_sym
|
48
|
+
|
49
|
+
if name.to_s.end_with?('?')
|
50
|
+
raise StateHandler::UnexpectedState, "Got: #{state.inspect}" unless self.class.mapping[state]
|
51
|
+
find_mapped(state)
|
52
|
+
elsif block_given?
|
53
|
+
@blocks[state] = block
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module ClassMethods
|
58
|
+
def class_attribute(*attrs)
|
59
|
+
attrs.each do |name|
|
60
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
61
|
+
def self.#{name}() nil end
|
62
|
+
def self.#{name}?() !!#{name} end
|
63
|
+
|
64
|
+
def self.#{name}=(val)
|
65
|
+
singleton_class.class_eval do
|
66
|
+
define_method(:#{name}) { val }
|
67
|
+
end
|
68
|
+
val
|
69
|
+
end
|
70
|
+
RUBY
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def map(&block)
|
75
|
+
class_eval(&block)
|
76
|
+
end
|
77
|
+
|
78
|
+
def match(regexp)
|
79
|
+
self.patterns[regexp.values.first] = regexp.keys.first
|
80
|
+
end
|
81
|
+
|
82
|
+
def code(*codes, &block)
|
83
|
+
if codes.first.kind_of?(Hash)
|
84
|
+
self.mapping[codes.first.values.first] = codes.first.keys.first
|
85
|
+
elsif block_given?
|
86
|
+
self.mapping[yield] = codes
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe StateHandler::Mixing do
|
4
|
+
before do
|
5
|
+
class DummyResponse
|
6
|
+
include StateHandler::Mixing
|
7
|
+
|
8
|
+
map do
|
9
|
+
code 200 => :enabled
|
10
|
+
code 400 => :false
|
11
|
+
|
12
|
+
match /5\d\d/ => :error
|
13
|
+
|
14
|
+
code 401, 402 do
|
15
|
+
:bad_params
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class DuplicateDeclarationResponse
|
20
|
+
include StateHandler::Mixing
|
21
|
+
|
22
|
+
map do
|
23
|
+
code 200 => :fuck_up
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
subject {
|
28
|
+
DuplicateDeclarationResponse.new(response_struct)
|
29
|
+
DummyResponse.new(response_struct)
|
30
|
+
}
|
31
|
+
|
32
|
+
describe "#exec" do
|
33
|
+
let(:response_struct) { OpenStruct.new(:code => 401) }
|
34
|
+
class ExecException < Exception
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should call block from 'at' notation with multiply states" do
|
38
|
+
expect {
|
39
|
+
subject.exec do |r|
|
40
|
+
r.at :bad_params, :success, :fake do
|
41
|
+
raise ExecException
|
42
|
+
end
|
43
|
+
r.test { raise ArgumentError }
|
44
|
+
end
|
45
|
+
}.should raise_error(ExecException)
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#match" do
|
49
|
+
let(:response_struct) { OpenStruct.new(:code => 500) }
|
50
|
+
it "should call matched block" do
|
51
|
+
expect {
|
52
|
+
subject.exec do |r|
|
53
|
+
r.bad_params do
|
54
|
+
raise ExecException
|
55
|
+
end
|
56
|
+
|
57
|
+
r.error do
|
58
|
+
raise ArgumentError
|
59
|
+
end
|
60
|
+
end
|
61
|
+
}.should raise_error(ArgumentError)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
let(:response_struct) { OpenStruct.new(:code => 401) }
|
66
|
+
it "should call block" do
|
67
|
+
expect {
|
68
|
+
subject.exec do |r|
|
69
|
+
r.bad_params do
|
70
|
+
raise ExecException
|
71
|
+
end
|
72
|
+
|
73
|
+
r.success do
|
74
|
+
raise ArgumentError
|
75
|
+
end
|
76
|
+
end
|
77
|
+
}.should raise_error(ExecException)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#codes" do
|
82
|
+
let(:response_struct) { OpenStruct.new(:code => 401) }
|
83
|
+
|
84
|
+
its(:bad_params?) { should be_true }
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#code" do
|
88
|
+
let(:response_struct) { OpenStruct.new(:code => 200) }
|
89
|
+
|
90
|
+
its(:enabled?) { should be_true }
|
91
|
+
its(:false?) { should be_false }
|
92
|
+
its(:state) { should == :enabled }
|
93
|
+
|
94
|
+
it "should raise UnexpectedState error" do
|
95
|
+
expect { subject.disabled? }.should raise_error(StateHandler::UnexpectedState)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
$:.unshift File.expand_path('../../lib/', __FILE__)
|
4
|
+
|
5
|
+
ROOT = File.expand_path('../..', __FILE__)
|
6
|
+
|
7
|
+
require 'state-handler'
|
8
|
+
|
9
|
+
Bundler.require(:default, :test, :development)
|
10
|
+
|
11
|
+
Dir['spec/support/**/*.rb'].each{|f| require File.join(ROOT, f) }
|
12
|
+
Dir['spec/shared_examples/**/*.rb'].each{|f| require File.join(ROOT,f)}
|
13
|
+
Dir['spec/shared_context/**/*.rb'].each{|f| require File.join(ROOT,f)}
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.filter_run :focus => true
|
17
|
+
config.run_all_when_everything_filtered = true
|
18
|
+
end
|
19
|
+
|
20
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/state-handler/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.author = "Maxim Filipovich"
|
6
|
+
gem.email = "fatumka@gmail.com"
|
7
|
+
gem.description = %q{State handler per object params}
|
8
|
+
gem.summary = %q{State handler per object params}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "state-handler"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = StateHandler::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency('rake')
|
19
|
+
gem.add_development_dependency('rspec')
|
20
|
+
gem.add_development_dependency('timecop')
|
21
|
+
end
|
22
|
+
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: state-handler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Maxim Filipovich
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-14 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &70106966478060 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70106966478060
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70106966477640 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70106966477640
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: timecop
|
38
|
+
requirement: &70106966477220 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70106966477220
|
47
|
+
description: State handler per object params
|
48
|
+
email: fatumka@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .rspec
|
54
|
+
- Gemfile
|
55
|
+
- Gemfile.lock
|
56
|
+
- README
|
57
|
+
- examples/response.rb
|
58
|
+
- lib/state-handler.rb
|
59
|
+
- lib/state-handler/mixing.rb
|
60
|
+
- lib/state-handler/version.rb
|
61
|
+
- spec/lib/state-handler/mixing_spec.rb
|
62
|
+
- spec/spec_helper.rb
|
63
|
+
- state-handler.gemspec
|
64
|
+
homepage: ''
|
65
|
+
licenses: []
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.8.10
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: State handler per object params
|
88
|
+
test_files:
|
89
|
+
- spec/lib/state-handler/mixing_spec.rb
|
90
|
+
- spec/spec_helper.rb
|