simple_states 1.1.0.rc11 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -3
- data/Gemfile.lock +20 -26
- data/lib/simple_states.rb +34 -54
- data/lib/simple_states/event.rb +52 -83
- data/lib/simple_states/helpers.rb +7 -0
- data/lib/simple_states/states.rb +28 -52
- data/lib/simple_states/version.rb +1 -1
- data/simple_states.gemspec +1 -7
- metadata +7 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 627c1d0bd3ec1db9f71afc51615e7a1c5d8ee194
|
4
|
+
data.tar.gz: ca2532ece2327f549c0c113dcd09155f4df8b578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8295626ea865b2d3e1bfdac8e6ef2e4a5c50100ac3c0168fb68e183a03a3a8d591dfc578713d6ecae618a6ccdd9973f329068fbddde3f1039fd5ab95fd29939
|
7
|
+
data.tar.gz: c6a2062e68a1f7814a3b40634eb7aefcdb3e567bc444dd95b15c8ec2b4adcca3e03526c01829946104572f0ff3fbd29ffd9dc73aa5c38da6fad7c38fa11a8718
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,37 +1,31 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
simple_states (1.1.0.rc9)
|
5
|
-
activesupport
|
6
|
-
|
7
1
|
GEM
|
8
2
|
remote: https://rubygems.org/
|
9
3
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
minitest (~> 5.1)
|
14
|
-
thread_safe (~> 0.3, >= 0.3.4)
|
15
|
-
tzinfo (~> 1.1)
|
16
|
-
i18n (0.7.0)
|
17
|
-
json (1.8.3)
|
18
|
-
metaclass (0.0.1)
|
19
|
-
minitest (5.8.0)
|
20
|
-
mocha (0.14.0)
|
4
|
+
diff-lcs (1.2.5)
|
5
|
+
metaclass (0.0.4)
|
6
|
+
mocha (1.1.0)
|
21
7
|
metaclass (~> 0.0.1)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
8
|
+
rspec (3.3.0)
|
9
|
+
rspec-core (~> 3.3.0)
|
10
|
+
rspec-expectations (~> 3.3.0)
|
11
|
+
rspec-mocks (~> 3.3.0)
|
12
|
+
rspec-core (3.3.2)
|
13
|
+
rspec-support (~> 3.3.0)
|
14
|
+
rspec-expectations (3.3.1)
|
15
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
16
|
+
rspec-support (~> 3.3.0)
|
17
|
+
rspec-mocks (3.3.2)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.3.0)
|
20
|
+
rspec-support (3.3.0)
|
27
21
|
|
28
22
|
PLATFORMS
|
29
23
|
java
|
30
24
|
ruby
|
31
25
|
|
32
26
|
DEPENDENCIES
|
33
|
-
minitest
|
34
27
|
mocha
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
rspec
|
29
|
+
|
30
|
+
BUNDLED WITH
|
31
|
+
1.10.6
|
data/lib/simple_states.rb
CHANGED
@@ -1,66 +1,42 @@
|
|
1
|
-
require '
|
1
|
+
require 'simple_states/states'
|
2
2
|
|
3
3
|
module SimpleStates
|
4
|
-
class
|
5
|
-
|
6
|
-
autoload :Event, 'simple_states/event'
|
7
|
-
autoload :States, 'simple_states/states'
|
4
|
+
class Error < RuntimeError; end
|
8
5
|
|
9
6
|
class << self
|
10
|
-
def included(
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def define_accessors(base, *names)
|
17
|
-
base.singleton_class.send(:attr_accessor, *names)
|
18
|
-
base.public_class_method(*names + names.map { |name| "#{name}=".to_sym })
|
19
|
-
end
|
20
|
-
|
21
|
-
def set_defaults(base)
|
22
|
-
base.after_initialize(:init_state) if base.respond_to?(:after_initialize)
|
23
|
-
base.initial_state = :created
|
24
|
-
base.state_names = []
|
25
|
-
base.state_options = {}
|
26
|
-
base.events = []
|
7
|
+
def included(const)
|
8
|
+
states = const.const_set(:States, States.new)
|
9
|
+
const.send(:prepend, states) if const.respond_to?(:prepend)
|
10
|
+
const.extend(ClassMethods)
|
11
|
+
const.initial_state = :created
|
12
|
+
const.after_initialize(:init_state) if const.respond_to?(:after_initialize)
|
27
13
|
end
|
28
14
|
end
|
29
15
|
|
30
16
|
module ClassMethods
|
31
|
-
|
32
|
-
super.tap { |object| States.init(object) }
|
33
|
-
end
|
17
|
+
attr_accessor :initial_state
|
34
18
|
|
35
|
-
def
|
36
|
-
super.tap { |object|
|
37
|
-
end
|
38
|
-
|
39
|
-
def states(*args)
|
40
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
41
|
-
self.initial_state = options.delete(:initial).to_sym if options.key?(:initial)
|
42
|
-
self.state_options = options
|
43
|
-
add_states(*[self.initial_state].concat(args))
|
19
|
+
def new(*)
|
20
|
+
super.tap { |object| object.init_state }
|
44
21
|
end
|
45
22
|
|
46
|
-
def
|
47
|
-
|
23
|
+
def event(name, opts = {})
|
24
|
+
method = name == :all ? :update_events : :define_event
|
25
|
+
self::States.send(method, name, opts)
|
48
26
|
end
|
49
27
|
|
50
|
-
def
|
51
|
-
|
52
|
-
self.events << [name, options]
|
28
|
+
def state?(state)
|
29
|
+
states.include?(state)
|
53
30
|
end
|
54
31
|
|
55
|
-
def
|
56
|
-
|
32
|
+
def states
|
33
|
+
[initial_state] + self::States.states
|
57
34
|
end
|
58
35
|
end
|
59
36
|
|
60
|
-
attr_reader :past_states
|
61
|
-
|
62
37
|
def init_state
|
63
|
-
self.
|
38
|
+
singleton_class.send(:include, self.class::States) unless self.class.respond_to?(:prepend)
|
39
|
+
self.state = self.class.initial_state if self.state.nil?
|
64
40
|
end
|
65
41
|
|
66
42
|
def state=(state)
|
@@ -68,23 +44,27 @@ module SimpleStates
|
|
68
44
|
end
|
69
45
|
|
70
46
|
def state
|
71
|
-
super
|
47
|
+
state = super
|
48
|
+
state.to_sym if state
|
72
49
|
end
|
73
50
|
|
74
|
-
def
|
75
|
-
self.state
|
76
|
-
self.class.events.map { |*args| Event.new(*args).reset(self) }
|
51
|
+
def state?(state)
|
52
|
+
self.state.to_sym == state.to_sym
|
77
53
|
end
|
78
54
|
|
79
|
-
def
|
80
|
-
|
55
|
+
def reset_state
|
56
|
+
self.state = self.class.initial_state
|
57
|
+
self.class::States.events.map { |_, event| event.reset(self) }
|
81
58
|
end
|
82
59
|
|
83
|
-
def
|
84
|
-
|
60
|
+
def respond_to?(name)
|
61
|
+
state = name.to_s[0..-2].to_sym
|
62
|
+
name.to_s[-1] == '?' && self.class.state?(state) || super
|
85
63
|
end
|
86
64
|
|
87
|
-
def
|
88
|
-
|
65
|
+
def method_missing(name, *args)
|
66
|
+
state = name.to_s[0..-2].to_sym
|
67
|
+
return super unless name.to_s[-1] == '?' && self.class.state?(state)
|
68
|
+
state?(state)
|
89
69
|
end
|
90
70
|
end
|
data/lib/simple_states/event.rb
CHANGED
@@ -1,112 +1,81 @@
|
|
1
|
-
require 'active_support/core_ext/module/delegation'
|
2
|
-
|
3
1
|
module SimpleStates
|
4
|
-
class Event
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
class Event < Struct.new(:name, :opts)
|
3
|
+
MSGS = {
|
4
|
+
invalid_state: 'If multiple target states are defined, then a valid target state must be passed as an attribute ({ state: :state }). %p given, known states: %p.',
|
5
|
+
unknown_state: 'Unknown state %p for %p for event %p. Known states are: %p'
|
6
|
+
}
|
7
|
+
|
8
|
+
def call(obj, data, opts)
|
9
|
+
return false if not ordered?(obj, data) or not applies?(obj, data)
|
10
|
+
|
11
|
+
run_callbacks(:before, obj, data)
|
12
|
+
set_attrs(obj, data)
|
13
|
+
yield
|
14
|
+
obj.save! if opts[:save]
|
15
|
+
|
16
|
+
raise_unknown_state(obj, data) unless known_state?(obj)
|
17
|
+
run_callbacks(:after, obj, data)
|
18
|
+
obj.save! if opts[:save]
|
19
|
+
true
|
10
20
|
end
|
11
21
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
raise_invalid_transition(object) unless can_transition?(object)
|
16
|
-
run_callbacks(object, :before, args)
|
17
|
-
set_state(object, args)
|
18
|
-
|
19
|
-
yield.tap do
|
20
|
-
raise_unknown_target_state(object) unless known_target_state?(object)
|
21
|
-
run_callbacks(object, :after, args)
|
22
|
-
object.save! if save?
|
23
|
-
end
|
22
|
+
def reset(obj)
|
23
|
+
Array(opts[:to]).each { |state| set_attr(obj, :"#{state}_at", nil) }
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
write_attr(object, :"#{target_state}_at", nil)
|
28
|
-
end
|
29
|
-
|
30
|
-
protected
|
31
|
-
|
32
|
-
def save?
|
33
|
-
options[:save]
|
34
|
-
end
|
35
|
-
|
36
|
-
def skip?(object, args)
|
37
|
-
result = false
|
38
|
-
result ||= !send_methods(object, options[:if], args) if options[:if]
|
39
|
-
result ||= send_methods(object, options[:unless], args) if options[:unless]
|
40
|
-
result
|
41
|
-
end
|
42
|
-
|
43
|
-
def can_transition?(object)
|
44
|
-
!options[:from] || object.state && Array(options[:from]).include?(object.state.to_sym)
|
45
|
-
end
|
46
|
-
|
47
|
-
def run_callbacks(object, type, args)
|
48
|
-
object.save! if save?
|
49
|
-
send_methods(object, options[type], args)
|
50
|
-
end
|
51
|
-
|
52
|
-
def set_state(object, args)
|
53
|
-
data = args.last.is_a?(Hash) ? args.last : {}
|
54
|
-
state = data[:state].try(:to_sym) || target_state
|
55
|
-
object.past_states << object.state.to_sym if object.state
|
56
|
-
object.state = state.to_sym
|
57
|
-
write_attrs(object, data)
|
58
|
-
end
|
26
|
+
private
|
59
27
|
|
60
|
-
def
|
61
|
-
|
62
|
-
data.each { |key, value| write_attr(object, key, value) }
|
28
|
+
def run_callbacks(type, obj, data)
|
29
|
+
send_methods(opts[type], obj, data)
|
63
30
|
end
|
64
31
|
|
65
|
-
def
|
66
|
-
|
32
|
+
def set_attrs(obj, data)
|
33
|
+
attrs = { :"#{target_state(data)}_at" => Time.now.utc }.merge(data)
|
34
|
+
attrs.each { |key, value| set_attr(obj, key, value) }
|
35
|
+
obj.state = target_state(data)
|
67
36
|
end
|
68
37
|
|
69
|
-
def
|
70
|
-
|
71
|
-
state = data[:state].try(:to_sym) || target_state
|
72
|
-
return true unless object.class.state_options[:ordered]
|
73
|
-
states = object.class.state_names
|
74
|
-
lft, rgt = states.index(object.state.try(:to_sym)), states.index(state)
|
75
|
-
lft.nil? || rgt.nil? || lft <= rgt
|
38
|
+
def set_attr(obj, key, value)
|
39
|
+
obj.send(:"#{key}=", value) if obj.respond_to?(:"#{key}=")
|
76
40
|
end
|
77
41
|
|
78
|
-
def
|
79
|
-
|
42
|
+
def ordered?(obj, data)
|
43
|
+
states = obj.class.states
|
44
|
+
states.index(obj.state).to_i <= states.index(target_state(data)).to_i
|
80
45
|
end
|
81
46
|
|
82
|
-
def
|
83
|
-
|
47
|
+
def applies?(obj, data)
|
48
|
+
result = opts[:if].nil? || send_methods(opts[:if], obj, data)
|
49
|
+
result and opts[:unless].nil? || !send_methods(opts[:unless], obj, data)
|
84
50
|
end
|
85
51
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
52
|
+
def target_state(data)
|
53
|
+
to = Array(opts[:to])
|
54
|
+
return to.first if to.size == 1
|
55
|
+
state = data[:state].to_sym if data[:state]
|
56
|
+
to.include?(state) ? state : raise_invalid_state(data)
|
90
57
|
end
|
91
58
|
|
92
|
-
def
|
93
|
-
|
59
|
+
def send_methods(names, obj, data)
|
60
|
+
Array(names).inject(false) do |result, name|
|
61
|
+
result | send_method(name, obj, data)
|
62
|
+
end
|
94
63
|
end
|
95
64
|
|
96
|
-
def
|
97
|
-
|
65
|
+
def send_method(name, obj, data)
|
66
|
+
obj.send(name, *[self.name, data].slice(0, obj.method(name).arity.abs))
|
98
67
|
end
|
99
68
|
|
100
|
-
def
|
101
|
-
|
69
|
+
def known_state?(obj)
|
70
|
+
obj.class.states.include?(obj.state)
|
102
71
|
end
|
103
72
|
|
104
|
-
def
|
105
|
-
raise
|
73
|
+
def raise_invalid_state(data)
|
74
|
+
raise Error, MSGS[:invalid_state] % [data[:state], Array(opts[:to])]
|
106
75
|
end
|
107
76
|
|
108
|
-
def
|
109
|
-
raise
|
77
|
+
def raise_unknown_state(obj, data)
|
78
|
+
raise Error, MSGS[:unknown_state] % [obj.state, obj, name, obj.class.states]
|
110
79
|
end
|
111
80
|
end
|
112
81
|
end
|
data/lib/simple_states/states.rb
CHANGED
@@ -1,65 +1,41 @@
|
|
1
|
+
require 'simple_states/event'
|
2
|
+
require 'simple_states/helpers'
|
3
|
+
|
1
4
|
module SimpleStates
|
2
5
|
class States < Module
|
3
|
-
|
4
|
-
def init(object)
|
5
|
-
object.class.state_names = [object.class.initial_state] if object.class.state_names.empty?
|
6
|
-
respond_to?(:prepend) ? prepend_module(object.class) : include_module(object)
|
7
|
-
object.init_state unless object.singleton_class.respond_to?(:after_initialize)
|
8
|
-
end
|
9
|
-
|
10
|
-
def prepend_module(const)
|
11
|
-
const.prepend(module_for(const)) unless const.const_defined?(:StatesProxy)
|
12
|
-
end
|
13
|
-
|
14
|
-
def include_module(object)
|
15
|
-
object.singleton_class.send(:include, module_for(object.class))
|
16
|
-
end
|
17
|
-
|
18
|
-
def module_for(const)
|
19
|
-
args = [:StatesProxy].concat(const.method(:const_defined?).arity != 1 ? [false] : [])
|
20
|
-
const.const_defined?(*args) ? const::StatesProxy : const.const_set(:StatesProxy, create_module(const))
|
21
|
-
end
|
22
|
-
|
23
|
-
def create_module(const)
|
24
|
-
new.tap do |mod|
|
25
|
-
merge_events(const.events).each { |event| define_event(mod, event) }
|
26
|
-
const.state_names.each { |name| define_state(mod, name) }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def define_event(const, (name, options))
|
31
|
-
const.send(:define_method, name) do |*args|
|
32
|
-
event = args.first.is_a?(Event) ? args.shift : Event.new(name, options)
|
33
|
-
event.call(self, *args) { defined?(super) ? super(*args) : true }
|
34
|
-
end
|
6
|
+
include Helpers
|
35
7
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
8
|
+
def events
|
9
|
+
@events ||= {}
|
10
|
+
end
|
40
11
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
12
|
+
def states
|
13
|
+
events.values.map { |event| event.opts[:to] }.flatten.compact
|
14
|
+
end
|
45
15
|
|
46
|
-
|
47
|
-
|
16
|
+
def define_event(name, opts)
|
17
|
+
events[name] = Event.new(name, { to: to_past(name).to_sym }.merge(opts))
|
18
|
+
|
19
|
+
send(:define_method, name) do |data = {}, opts = {}|
|
20
|
+
self.class::States.events[name].call(self, data, opts) do
|
21
|
+
if method(name).respond_to?(:super_method)
|
22
|
+
supa = method(name).super_method
|
23
|
+
supa.call(*[name, data].slice(0, supa.arity.abs)) if supa
|
24
|
+
elsif defined?(super)
|
25
|
+
super(name, data)
|
26
|
+
end
|
48
27
|
end
|
49
28
|
end
|
50
29
|
|
51
|
-
|
52
|
-
|
53
|
-
other = events.slice!(other_ix)
|
54
|
-
events.each_with_index do |event, ix|
|
55
|
-
merge_event(event, other, ix < other_ix)
|
56
|
-
end
|
57
|
-
merge_events(events)
|
30
|
+
send(:define_method, :"#{name}!") do |data = {}|
|
31
|
+
send(name, data, save: true)
|
58
32
|
end
|
33
|
+
end
|
59
34
|
|
60
|
-
|
61
|
-
|
62
|
-
|
35
|
+
def update_events(_, opts)
|
36
|
+
events.values.each do |event|
|
37
|
+
opts.each do |key, value|
|
38
|
+
event.opts[key] = Array(event.opts[key]).concat(Array(value))
|
63
39
|
end
|
64
40
|
end
|
65
41
|
end
|
data/simple_states.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.name = "simple_states"
|
8
8
|
s.version = SimpleStates::VERSION
|
9
9
|
s.authors = ["Sven Fuchs"]
|
10
|
-
s.email = "svenfuchs
|
10
|
+
s.email = "me@svenfuchs.com"
|
11
11
|
s.homepage = "https://github.com/svenfuchs/simple_states"
|
12
12
|
s.licenses = ['MIT']
|
13
13
|
s.summary = "[summary]"
|
@@ -17,10 +17,4 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.platform = Gem::Platform::RUBY
|
18
18
|
s.require_path = 'lib'
|
19
19
|
s.rubyforge_project = '[none]'
|
20
|
-
|
21
|
-
s.add_dependency 'activesupport'
|
22
|
-
|
23
|
-
s.add_development_dependency 'rake', '~> 0.9.2'
|
24
|
-
s.add_development_dependency 'test_declarative'
|
25
|
-
s.add_development_dependency 'mocha'
|
26
20
|
end
|
metadata
CHANGED
@@ -1,73 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_states
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Fuchs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.9.2
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.9.2
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: test_declarative
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: mocha
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
11
|
+
date: 2015-11-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
69
13
|
description: "[description]"
|
70
|
-
email: svenfuchs
|
14
|
+
email: me@svenfuchs.com
|
71
15
|
executables: []
|
72
16
|
extensions: []
|
73
17
|
extra_rdoc_files: []
|
@@ -80,6 +24,7 @@ files:
|
|
80
24
|
- Rakefile
|
81
25
|
- lib/simple_states.rb
|
82
26
|
- lib/simple_states/event.rb
|
27
|
+
- lib/simple_states/helpers.rb
|
83
28
|
- lib/simple_states/states.rb
|
84
29
|
- lib/simple_states/version.rb
|
85
30
|
- simple_states.gemspec
|
@@ -98,9 +43,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
43
|
version: '0'
|
99
44
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
45
|
requirements:
|
101
|
-
- - "
|
46
|
+
- - ">="
|
102
47
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
48
|
+
version: '0'
|
104
49
|
requirements: []
|
105
50
|
rubyforge_project: "[none]"
|
106
51
|
rubygems_version: 2.4.5
|