state_machine-audit_trail 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -2
- data/README.rdoc +15 -5
- data/lib/state_machine/audit_trail/backend/active_record.rb +12 -1
- data/lib/state_machine/audit_trail/backend.rb +5 -2
- data/lib/state_machine/audit_trail/transition_auditing.rb +6 -5
- data/lib/state_machine/audit_trail.rb +1 -1
- data/spec/helpers/active_record.rb +38 -8
- data/spec/state_machine/active_record_spec.rb +29 -14
- data/state_machine-audit_trail.gemspec +1 -1
- metadata +93 -107
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -2,18 +2,25 @@
|
|
2
2
|
|
3
3
|
This plugin for the state machine gem (see https://github.com/pluginaweek/state_machine) adds support for keeping an audit trail for any state machine. Having an audit trail gives you a complete history of the state changes in your model. This history allows you to investigate incidents or perform analytics, like: "How long does it take on average to go from state a to state b?", or "What percentage of cases goes from state a to b via state c?"
|
4
4
|
|
5
|
-
|
5
|
+
== ORM support
|
6
|
+
|
7
|
+
Note: while the state_machine gem integrates with multiple ORMs, this plugin is currently limited to the following ORM backends:
|
8
|
+
|
9
|
+
* ActiveRecord
|
10
|
+
* Mongoid
|
11
|
+
|
12
|
+
It should be easy to add new backends by looking at the implementation of the current backends. Pull requests are welcome!
|
6
13
|
|
7
14
|
== Usage
|
8
15
|
|
9
16
|
First, make the gem available by adding it to your <tt>Gemfile</tt>, and run <tt>bundle install</tt>:
|
10
17
|
|
11
18
|
gem 'state_machine-audit_trail'
|
12
|
-
|
13
|
-
Create a model/table that holds the audit trail. The table needs to have a foreign key to the original object,
|
19
|
+
|
20
|
+
Create a model/table that holds the audit trail. The table needs to have a foreign key to the original object, an "event" field, a "from" state field, a "to" state field, and a "created_at" timestamp that stores the timestamp of the transition. This gem comes with a Rails 3 generator to create a model and a migration like that.
|
14
21
|
|
15
22
|
rails generate state_machine:audit_trail <model> <state_attribute>
|
16
|
-
|
23
|
+
|
17
24
|
For a model called "Model", and a state attribute "state", this will generate the ModelStateTransition model and an accompanying migration.
|
18
25
|
|
19
26
|
Next, tell your state machine you want to store an audit trail:
|
@@ -32,6 +39,9 @@ If your audit trail model does not use the default naming scheme, provide it usi
|
|
32
39
|
|
33
40
|
That's it! The plugin will register an <tt>after_transition</tt> callback that is used to log all transitions. It will also log the initial state if there is one.
|
34
41
|
|
42
|
+
If you would like to store additional messages in the audit trail, you can do so with the following:
|
43
|
+
store_audit_trail :context_to_log => :state_message # Will grab the results of the state_message method on the model and store it in a field called state_message on the audit trail model
|
44
|
+
|
35
45
|
== About
|
36
46
|
|
37
|
-
This plugin is written by Jesse Storimer and Willem van Bergen for Shopify. It is released under the MIT license (see LICENSE)
|
47
|
+
This plugin is written by Jesse Storimer and Willem van Bergen for Shopify. Mongoid support was contributed by Siddharth (https://github.com/svs). It is released under the MIT license (see LICENSE).
|
@@ -1,9 +1,20 @@
|
|
1
1
|
class StateMachine::AuditTrail::Backend::ActiveRecord < StateMachine::AuditTrail::Backend
|
2
|
+
attr_accessor :context_to_log
|
2
3
|
|
4
|
+
def initialize(transition_class, context_to_log)
|
5
|
+
self.context_to_log = context_to_log
|
6
|
+
super transition_class
|
7
|
+
end
|
3
8
|
def log(object, event, from, to, timestamp = Time.now)
|
4
9
|
# Let ActiveRecord manage the timestamp for us so it does the
|
5
10
|
# right thing with regards to timezones.
|
6
|
-
|
11
|
+
params = {foreign_key_field(object) => object.id, :event => event, :from => from, :to => to}
|
12
|
+
|
13
|
+
if context_to_log.is_a?(Array.class)
|
14
|
+
elsif !context_to_log.nil?
|
15
|
+
params[context_to_log] = object.send(context_to_log)
|
16
|
+
end
|
17
|
+
transition_class.create(params)
|
7
18
|
end
|
8
19
|
|
9
20
|
def foreign_key_field(object)
|
@@ -13,10 +13,13 @@ class StateMachine::AuditTrail::Backend < Struct.new(:transition_class)
|
|
13
13
|
#
|
14
14
|
# in order to adda new ORM here, copy audit_trail/mongoid.rb to whatever you want to call the new file and implement the #log function there
|
15
15
|
# then, return from here the appropriate object based on which ORM the transition_class is using
|
16
|
-
def self.create_for_transition_class(transition_class)
|
16
|
+
def self.create_for_transition_class(transition_class, context_to_log = nil)
|
17
17
|
if Object.const_defined?('ActiveRecord') && transition_class.ancestors.include?(::ActiveRecord::Base)
|
18
|
-
return StateMachine::AuditTrail::Backend::ActiveRecord.new(transition_class)
|
18
|
+
return StateMachine::AuditTrail::Backend::ActiveRecord.new(transition_class, context_to_log)
|
19
19
|
elsif Object.const_defined?('Mongoid') && transition_class.ancestors.include?(::Mongoid::Document)
|
20
|
+
# Mongoid implementation doesn't yet support additional context fields
|
21
|
+
raise NotImplemented, "Mongoid does not support additional context fields" if context_to_log.present?
|
22
|
+
|
20
23
|
return StateMachine::AuditTrail::Backend::Mongoid.new(transition_class)
|
21
24
|
else
|
22
25
|
raise NotImplemented, "Only support for ActiveRecord and Mongoid is included at this time"
|
@@ -7,24 +7,25 @@ module StateMachine::AuditTrail::TransitionAuditing
|
|
7
7
|
|
8
8
|
# Public tells the state machine to hook in the appropriate before / after behaviour
|
9
9
|
#
|
10
|
-
# options: a Hash of options. keys that are used are :to => CustomTransitionClass
|
10
|
+
# options: a Hash of options. keys that are used are :to => CustomTransitionClass,
|
11
|
+
# :context_to_log => method(s) to call on object and store in transitions
|
11
12
|
def store_audit_trail(options = {})
|
12
13
|
state_machine = self
|
13
14
|
state_machine.transition_class_name = (options[:to] || default_transition_class_name).to_s
|
14
15
|
state_machine.after_transition do |object, transition|
|
15
|
-
state_machine.audit_trail.log(object, transition.event, transition.from, transition.to)
|
16
|
+
state_machine.audit_trail(options[:context_to_log]).log(object, transition.event, transition.from, transition.to)
|
16
17
|
end
|
17
18
|
|
18
19
|
state_machine.owner_class.after_create do |object|
|
19
20
|
if !object.send(state_machine.attribute).nil?
|
20
|
-
state_machine.audit_trail.log(object, nil, nil, object.send(state_machine.attribute))
|
21
|
+
state_machine.audit_trail(options[:context_to_log]).log(object, nil, nil, object.send(state_machine.attribute))
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
26
|
# Public returns an instance of the class which does the actual audit trail logging
|
26
|
-
def audit_trail
|
27
|
-
@transition_auditor ||= StateMachine::AuditTrail::Backend.create_for_transition_class(transition_class)
|
27
|
+
def audit_trail(context_to_log = nil)
|
28
|
+
@transition_auditor ||= StateMachine::AuditTrail::Backend.create_for_transition_class(transition_class, context_to_log)
|
28
29
|
end
|
29
30
|
|
30
31
|
private
|
@@ -10,6 +10,12 @@ ActiveRecord::Base.connection.create_table(:active_record_test_models) do |t|
|
|
10
10
|
t.timestamps
|
11
11
|
end
|
12
12
|
|
13
|
+
ActiveRecord::Base.connection.create_table(:active_record_test_model_with_contexts) do |t|
|
14
|
+
t.string :state
|
15
|
+
t.string :type
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
13
19
|
ActiveRecord::Base.connection.create_table(:active_record_test_model_with_multiple_state_machines) do |t|
|
14
20
|
t.string :first
|
15
21
|
t.string :second
|
@@ -21,6 +27,10 @@ class ActiveRecordTestModelStateTransition < ActiveRecord::Base
|
|
21
27
|
belongs_to :test_model
|
22
28
|
end
|
23
29
|
|
30
|
+
class ActiveRecordTestModelWithContextStateTransition < ActiveRecord::Base
|
31
|
+
belongs_to :test_model
|
32
|
+
end
|
33
|
+
|
24
34
|
class ActiveRecordTestModelWithMultipleStateMachinesFirstTransition < ActiveRecord::Base
|
25
35
|
belongs_to :test_model
|
26
36
|
end
|
@@ -32,16 +42,34 @@ end
|
|
32
42
|
class ActiveRecordTestModel < ActiveRecord::Base
|
33
43
|
|
34
44
|
state_machine :state, :initial => :waiting do # log initial state?
|
35
|
-
store_audit_trail
|
45
|
+
store_audit_trail
|
46
|
+
|
47
|
+
event :start do
|
48
|
+
transition [:waiting, :stopped] => :started
|
49
|
+
end
|
50
|
+
|
51
|
+
event :stop do
|
52
|
+
transition :started => :stopped
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ActiveRecordTestModelWithContext < ActiveRecord::Base
|
58
|
+
state_machine :state, :initial => :waiting do # log initial state?
|
59
|
+
store_audit_trail :context_to_log => :context
|
36
60
|
|
37
61
|
event :start do
|
38
62
|
transition [:waiting, :stopped] => :started
|
39
63
|
end
|
40
|
-
|
64
|
+
|
41
65
|
event :stop do
|
42
66
|
transition :started => :stopped
|
43
67
|
end
|
44
68
|
end
|
69
|
+
|
70
|
+
def context
|
71
|
+
"Some context"
|
72
|
+
end
|
45
73
|
end
|
46
74
|
|
47
75
|
class ActiveRecordTestModelDescendant < ActiveRecordTestModel
|
@@ -50,15 +78,15 @@ end
|
|
50
78
|
class ActiveRecordTestModelWithMultipleStateMachines < ActiveRecord::Base
|
51
79
|
|
52
80
|
state_machine :first, :initial => :beginning do
|
53
|
-
store_audit_trail
|
81
|
+
store_audit_trail
|
54
82
|
|
55
83
|
event :begin_first do
|
56
84
|
transition :beginning => :end
|
57
85
|
end
|
58
86
|
end
|
59
|
-
|
87
|
+
|
60
88
|
state_machine :second do
|
61
|
-
store_audit_trail
|
89
|
+
store_audit_trail
|
62
90
|
|
63
91
|
event :begin_second do
|
64
92
|
transition nil => :beginning_second
|
@@ -68,16 +96,18 @@ end
|
|
68
96
|
|
69
97
|
def create_transition_table(owner_class, state)
|
70
98
|
class_name = "#{owner_class.name}#{state.to_s.camelize}Transition"
|
71
|
-
|
72
99
|
ActiveRecord::Base.connection.create_table(class_name.tableize) do |t|
|
100
|
+
add_context = owner_class.instance_methods.include? :context
|
73
101
|
t.integer owner_class.name.foreign_key
|
74
102
|
t.string :event
|
75
103
|
t.string :from
|
76
104
|
t.string :to
|
105
|
+
t.string :context if add_context
|
77
106
|
t.datetime :created_at
|
78
107
|
end
|
79
108
|
end
|
80
109
|
|
81
|
-
create_transition_table(ActiveRecordTestModel, :state)
|
82
|
-
create_transition_table(
|
110
|
+
create_transition_table(ActiveRecordTestModel, :state)
|
111
|
+
create_transition_table(ActiveRecordTestModelWithContext, :state)
|
112
|
+
create_transition_table(ActiveRecordTestModelWithMultipleStateMachines, :first)
|
83
113
|
create_transition_table(ActiveRecordTestModelWithMultipleStateMachines, :second)
|
@@ -2,15 +2,15 @@ require 'spec_helper'
|
|
2
2
|
require 'helpers/active_record'
|
3
3
|
|
4
4
|
describe StateMachine::AuditTrail::Backend::ActiveRecord do
|
5
|
-
|
5
|
+
|
6
6
|
it "should create an ActiveRecord backend" do
|
7
7
|
backend = StateMachine::AuditTrail::Backend.create_for_transition_class(ActiveRecordTestModelStateTransition)
|
8
8
|
backend.should be_instance_of(StateMachine::AuditTrail::Backend::ActiveRecord)
|
9
|
-
end
|
10
|
-
|
9
|
+
end
|
10
|
+
|
11
11
|
context 'on an object with a single state machine' do
|
12
12
|
let!(:state_machine) { ActiveRecordTestModel.create! }
|
13
|
-
|
13
|
+
|
14
14
|
it "should log an event with all fields set correctly" do
|
15
15
|
state_machine.start!
|
16
16
|
last_transition = ActiveRecordTestModelStateTransition.where(:active_record_test_model_id => state_machine.id).last
|
@@ -18,21 +18,36 @@ describe StateMachine::AuditTrail::Backend::ActiveRecord do
|
|
18
18
|
last_transition.event.to_s.should == 'start'
|
19
19
|
last_transition.from.should == 'waiting'
|
20
20
|
last_transition.to.should == 'started'
|
21
|
+
#last_transition.context.should_not be_nil
|
21
22
|
last_transition.created_at.should be_within(10.seconds).of(Time.now.utc)
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
it "should log multiple events" do
|
25
26
|
lambda { state_machine.start && state_machine.stop && state_machine.start }.should change(ActiveRecordTestModelStateTransition, :count).by(3)
|
26
27
|
end
|
27
|
-
|
28
|
-
it "should do nothing when the transition is not
|
28
|
+
|
29
|
+
it "should do nothing when the transition is not executed successfully" do
|
29
30
|
lambda { state_machine.stop }.should_not change(ActiveRecordTestModelStateTransition, :count)
|
30
31
|
end
|
31
32
|
end
|
32
|
-
|
33
|
+
|
34
|
+
context 'on an object with a single state machine that wants to log a single context' do
|
35
|
+
before do
|
36
|
+
backend = StateMachine::AuditTrail::Backend.create_for_transition_class(ActiveRecordTestModelWithContextStateTransition, :context)
|
37
|
+
end
|
38
|
+
|
39
|
+
let!(:state_machine) { ActiveRecordTestModelWithContext.create! }
|
40
|
+
|
41
|
+
it "should log an event with all fields set correctly" do
|
42
|
+
state_machine.start!
|
43
|
+
last_transition = ActiveRecordTestModelWithContextStateTransition.where(:active_record_test_model_with_context_id => state_machine.id).last
|
44
|
+
last_transition.context.should == state_machine.context
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
33
48
|
context 'on an object with multiple state machines' do
|
34
49
|
let!(:state_machine) { ActiveRecordTestModelWithMultipleStateMachines.create! }
|
35
|
-
|
50
|
+
|
36
51
|
it "should log a state transition for the affected state machine" do
|
37
52
|
lambda { state_machine.begin_first! }.should change(ActiveRecordTestModelWithMultipleStateMachinesFirstTransition, :count).by(1)
|
38
53
|
end
|
@@ -41,15 +56,15 @@ describe StateMachine::AuditTrail::Backend::ActiveRecord do
|
|
41
56
|
lambda { state_machine.begin_first! }.should_not change(ActiveRecordTestModelWithMultipleStateMachinesSecondTransition, :count)
|
42
57
|
end
|
43
58
|
end
|
44
|
-
|
59
|
+
|
45
60
|
context 'on an object with a state machine having an initial state' do
|
46
61
|
let(:state_machine_class) { ActiveRecordTestModelWithMultipleStateMachines }
|
47
62
|
let(:state_transition_class) { ActiveRecordTestModelWithMultipleStateMachinesFirstTransition }
|
48
|
-
|
63
|
+
|
49
64
|
it "should log a state transition for the inital state" do
|
50
65
|
lambda { state_machine_class.create! }.should change(state_transition_class, :count).by(1)
|
51
66
|
end
|
52
|
-
|
67
|
+
|
53
68
|
it "should only set the :to state for the initial transition" do
|
54
69
|
state_machine_class.create!
|
55
70
|
initial_transition = state_transition_class.last
|
@@ -59,11 +74,11 @@ describe StateMachine::AuditTrail::Backend::ActiveRecord do
|
|
59
74
|
initial_transition.created_at.should be_within(10.seconds).of(Time.now.utc)
|
60
75
|
end
|
61
76
|
end
|
62
|
-
|
77
|
+
|
63
78
|
context 'on an object with a state machine not having an initial state' do
|
64
79
|
let(:state_machine_class) { ActiveRecordTestModelWithMultipleStateMachines }
|
65
80
|
let(:state_transition_class) { ActiveRecordTestModelWithMultipleStateMachinesSecondTransition }
|
66
|
-
|
81
|
+
|
67
82
|
it "should not log a transition when the object is created" do
|
68
83
|
lambda { state_machine_class.create! }.should_not change(state_transition_class, :count)
|
69
84
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = "state_machine-audit_trail"
|
4
|
-
s.version = "0.1.
|
4
|
+
s.version = "0.1.1"
|
5
5
|
s.platform = Gem::Platform::RUBY
|
6
6
|
s.authors = ["Willem van Bergen", "Jesse Storimer"]
|
7
7
|
s.email = ["willem@shopify.com", "jesse@shopify.com"]
|
metadata
CHANGED
@@ -1,118 +1,103 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_machine-audit_trail
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
version: 0.1.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Willem van Bergen
|
13
9
|
- Jesse Storimer
|
14
10
|
autorequire:
|
15
11
|
bindir: bin
|
16
12
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
13
|
+
date: 2012-07-28 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
22
16
|
name: state_machine
|
23
|
-
|
24
|
-
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
- 0
|
30
|
-
version: "0"
|
17
|
+
requirement: &70159599977080 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
31
23
|
type: :runtime
|
32
|
-
version_requirements: *id001
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: rake
|
35
24
|
prerelease: false
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
25
|
+
version_requirements: *70159599977080
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake
|
28
|
+
requirement: &70159599976060 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
43
34
|
type: :development
|
44
|
-
version_requirements: *id002
|
45
|
-
- !ruby/object:Gem::Dependency
|
46
|
-
name: rspec
|
47
35
|
prerelease: false
|
48
|
-
|
49
|
-
|
36
|
+
version_requirements: *70159599976060
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
requirement: &70159599992820 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
50
42
|
- - ~>
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
|
53
|
-
- 2
|
54
|
-
version: "2"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '2'
|
55
45
|
type: :development
|
56
|
-
version_requirements: *id003
|
57
|
-
- !ruby/object:Gem::Dependency
|
58
|
-
name: activerecord
|
59
46
|
prerelease: false
|
60
|
-
|
61
|
-
|
47
|
+
version_requirements: *70159599992820
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: activerecord
|
50
|
+
requirement: &70159599991160 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
62
53
|
- - ~>
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
|
65
|
-
- 3
|
66
|
-
version: "3"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3'
|
67
56
|
type: :development
|
68
|
-
version_requirements: *id004
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: sqlite3
|
71
57
|
prerelease: false
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
58
|
+
version_requirements: *70159599991160
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: sqlite3
|
61
|
+
requirement: &70159599989960 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
79
67
|
type: :development
|
80
|
-
version_requirements: *id005
|
81
|
-
- !ruby/object:Gem::Dependency
|
82
|
-
name: mongoid
|
83
68
|
prerelease: false
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
69
|
+
version_requirements: *70159599989960
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: mongoid
|
72
|
+
requirement: &70159599988580 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
91
78
|
type: :development
|
92
|
-
version_requirements: *id006
|
93
|
-
- !ruby/object:Gem::Dependency
|
94
|
-
name: bson_ext
|
95
79
|
prerelease: false
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
80
|
+
version_requirements: *70159599988580
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: bson_ext
|
83
|
+
requirement: &70159600002560 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
103
89
|
type: :development
|
104
|
-
|
105
|
-
|
106
|
-
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *70159600002560
|
92
|
+
description: Log transitions on a state machine to support auditing and business process
|
93
|
+
analytics.
|
94
|
+
email:
|
107
95
|
- willem@shopify.com
|
108
96
|
- jesse@shopify.com
|
109
97
|
executables: []
|
110
|
-
|
111
98
|
extensions: []
|
112
|
-
|
113
99
|
extra_rdoc_files: []
|
114
|
-
|
115
|
-
files:
|
100
|
+
files:
|
116
101
|
- .gitignore
|
117
102
|
- .travis.yml
|
118
103
|
- Gemfile
|
@@ -135,37 +120,38 @@ files:
|
|
135
120
|
- spec/state_machine/mongoid_spec.rb
|
136
121
|
- state_machine-audit_trail.gemspec
|
137
122
|
- tasks/github_gem.rb
|
138
|
-
has_rdoc: true
|
139
123
|
homepage: https://github.com/wvanbergen/state_machine-audit_trail
|
140
124
|
licenses: []
|
141
|
-
|
142
125
|
post_install_message:
|
143
126
|
rdoc_options: []
|
144
|
-
|
145
|
-
require_paths:
|
127
|
+
require_paths:
|
146
128
|
- lib
|
147
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
segments:
|
152
136
|
- 0
|
153
|
-
|
154
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
137
|
+
hash: 3519932254629100155
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
segments:
|
159
145
|
- 0
|
160
|
-
|
146
|
+
hash: 3519932254629100155
|
161
147
|
requirements: []
|
162
|
-
|
163
148
|
rubyforge_project: state_machine
|
164
|
-
rubygems_version: 1.
|
149
|
+
rubygems_version: 1.8.16
|
165
150
|
signing_key:
|
166
151
|
specification_version: 3
|
167
|
-
summary: Log transitions on a state machine to support auditing and business process
|
168
|
-
|
152
|
+
summary: Log transitions on a state machine to support auditing and business process
|
153
|
+
analytics.
|
154
|
+
test_files:
|
169
155
|
- spec/state_machine/active_record_spec.rb
|
170
156
|
- spec/state_machine/audit_trail_spec.rb
|
171
157
|
- spec/state_machine/mongoid_spec.rb
|