actify 0.1.0 → 1.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +65 -0
- data/lib/actify/generators/actify/install_generator.rb +48 -0
- data/lib/actify/railtie.rb +16 -0
- data/lib/actify/templates/action_log.rb.tt +6 -0
- data/lib/actify/templates/create_action_logs.rb.tt +22 -0
- data/lib/actify/version.rb +1 -1
- data/lib/actify.rb +151 -3
- data/lib/action.rb +154 -0
- metadata +11 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: db8b33dd7b2f9adbf5075e1a468a078e9790ae58e8d3b1794a683e0942645d6a
|
|
4
|
+
data.tar.gz: b12f8c7f50427d65d13274928d39993fa45f5b92e12fafa881c7b3cdf2badbc3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 33cd3b5d55aa2b1c1d18c417edaf97eb9fc2a51c27c2eaf4d1e363fe36b588da51c2b9de60f5f138f2d301378f25e83c2cea1abfb2785ef0dbf3ad03149d16b4
|
|
7
|
+
data.tar.gz: 2a928012168cbef71539306ec233acc3c6d36f527be665f7ac19b14c541919203c82981e223427f644eae02ba9e418c570e091203dfbb9c5c5ba49f1266a6c53
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
actify (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
ast (2.4.3)
|
|
10
|
+
diff-lcs (1.6.2)
|
|
11
|
+
json (2.12.2)
|
|
12
|
+
language_server-protocol (3.17.0.5)
|
|
13
|
+
lint_roller (1.1.0)
|
|
14
|
+
parallel (1.27.0)
|
|
15
|
+
parser (3.3.8.0)
|
|
16
|
+
ast (~> 2.4.1)
|
|
17
|
+
racc
|
|
18
|
+
prism (1.4.0)
|
|
19
|
+
racc (1.8.1)
|
|
20
|
+
rainbow (3.1.1)
|
|
21
|
+
rake (13.3.0)
|
|
22
|
+
regexp_parser (2.10.0)
|
|
23
|
+
rspec (3.13.1)
|
|
24
|
+
rspec-core (~> 3.13.0)
|
|
25
|
+
rspec-expectations (~> 3.13.0)
|
|
26
|
+
rspec-mocks (~> 3.13.0)
|
|
27
|
+
rspec-core (3.13.5)
|
|
28
|
+
rspec-support (~> 3.13.0)
|
|
29
|
+
rspec-expectations (3.13.5)
|
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
31
|
+
rspec-support (~> 3.13.0)
|
|
32
|
+
rspec-mocks (3.13.5)
|
|
33
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
34
|
+
rspec-support (~> 3.13.0)
|
|
35
|
+
rspec-support (3.13.4)
|
|
36
|
+
rubocop (1.77.0)
|
|
37
|
+
json (~> 2.3)
|
|
38
|
+
language_server-protocol (~> 3.17.0.2)
|
|
39
|
+
lint_roller (~> 1.1.0)
|
|
40
|
+
parallel (~> 1.10)
|
|
41
|
+
parser (>= 3.3.0.2)
|
|
42
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
43
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
44
|
+
rubocop-ast (>= 1.45.1, < 2.0)
|
|
45
|
+
ruby-progressbar (~> 1.7)
|
|
46
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
47
|
+
rubocop-ast (1.45.1)
|
|
48
|
+
parser (>= 3.3.7.2)
|
|
49
|
+
prism (~> 1.4)
|
|
50
|
+
ruby-progressbar (1.13.0)
|
|
51
|
+
unicode-display_width (3.1.4)
|
|
52
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
|
53
|
+
unicode-emoji (4.0.4)
|
|
54
|
+
|
|
55
|
+
PLATFORMS
|
|
56
|
+
arm64-darwin-23
|
|
57
|
+
|
|
58
|
+
DEPENDENCIES
|
|
59
|
+
actify!
|
|
60
|
+
rake (~> 13.0)
|
|
61
|
+
rspec (~> 3.0)
|
|
62
|
+
rubocop (~> 1.21)
|
|
63
|
+
|
|
64
|
+
BUNDLED WITH
|
|
65
|
+
2.3.27
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/migration"
|
|
3
|
+
|
|
4
|
+
module Actify
|
|
5
|
+
module Generators
|
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
|
7
|
+
include Rails::Generators::Migration
|
|
8
|
+
|
|
9
|
+
source_root File.expand_path("../../../templates", __FILE__)
|
|
10
|
+
desc "Creates a migration for action_logs table"
|
|
11
|
+
|
|
12
|
+
def copy_migration
|
|
13
|
+
migration_template(
|
|
14
|
+
"create_action_logs.rb.tt",
|
|
15
|
+
"db/migrate/create_action_logs.rb",
|
|
16
|
+
migration_version: migration_version
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def copy_model
|
|
21
|
+
template "action_log.rb.tt", "app/models/action_log.rb"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def run_migration
|
|
25
|
+
say_status("migrating", "Running `rails db:migrate`", :green)
|
|
26
|
+
rake("db:migrate")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.next_migration_number(dirname)
|
|
30
|
+
if @prev_migration_nr
|
|
31
|
+
@prev_migration_nr += 1
|
|
32
|
+
else
|
|
33
|
+
timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
34
|
+
@prev_migration_nr = timestamp.to_i
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@prev_migration_nr.to_s
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
# Detect version from Rails project
|
|
43
|
+
def migration_version
|
|
44
|
+
"[#{ActiveRecord::Migration.current_version.to_s[0..2]}]"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/railtie"
|
|
4
|
+
require "rails/generators"
|
|
5
|
+
|
|
6
|
+
module Actify
|
|
7
|
+
# Railtie to integrate Actify with Rails
|
|
8
|
+
class Railtie < Rails::Railtie
|
|
9
|
+
# Load custom Rails commands
|
|
10
|
+
railtie_name :actify
|
|
11
|
+
|
|
12
|
+
generators do
|
|
13
|
+
require File.expand_path("../generators/actify/install_generator", __FILE__)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class CreateActionLogs < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
+
def change
|
|
3
|
+
create_table :action_logs do |t|
|
|
4
|
+
t.integer :status, null: false
|
|
5
|
+
t.integer :actor_id
|
|
6
|
+
t.string :action_code
|
|
7
|
+
t.string :actionable_type
|
|
8
|
+
t.integer :actionable_id
|
|
9
|
+
t.string :action_label
|
|
10
|
+
t.text :action_data
|
|
11
|
+
t.text :context
|
|
12
|
+
t.text :object_before
|
|
13
|
+
t.text :object_after
|
|
14
|
+
t.text :error
|
|
15
|
+
|
|
16
|
+
t.timestamps
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
add_index :action_logs, [ :actionable_type, :actionable_id ]
|
|
20
|
+
add_index :action_logs, :actor_id
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/actify/version.rb
CHANGED
data/lib/actify.rb
CHANGED
|
@@ -1,11 +1,159 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "actify/railtie" if defined?(Rails)
|
|
3
4
|
require_relative "actify/version"
|
|
5
|
+
require_relative "action"
|
|
4
6
|
|
|
7
|
+
# This module allows models to define and execute custom actions with various hooks,
|
|
8
|
+
# authorization checks, and lifecycle callbacks.
|
|
5
9
|
module Actify
|
|
6
|
-
|
|
10
|
+
def self.included(base)
|
|
11
|
+
return if base.const_defined?(:Actions)
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
13
|
+
base.const_set :Actions, (Module.new do
|
|
14
|
+
def self.all
|
|
15
|
+
@actions
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.[](code)
|
|
19
|
+
(@actions || {})[code]
|
|
20
|
+
end
|
|
21
|
+
end)
|
|
22
|
+
|
|
23
|
+
class << base
|
|
24
|
+
def use_policy_in_actionable(accept = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
25
|
+
@use_policy = accept
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def action(name, options = {}, &block)
|
|
29
|
+
options["use_policy"] = @use_policy if (options.keys & [:use_policy, "use_policy"]).empty?
|
|
30
|
+
action_def = Def.new(name, options)
|
|
31
|
+
|
|
32
|
+
existing_action = const_get(:Actions).class_eval do
|
|
33
|
+
(@actions || {})[name]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if existing_action
|
|
37
|
+
action_def.action = existing_action
|
|
38
|
+
action_def.with_options(options)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
action_def.instance_eval(&block) if block_given?
|
|
42
|
+
|
|
43
|
+
const_get(:Actions).class_eval do
|
|
44
|
+
@actions ||= {}
|
|
45
|
+
@actions[name] = action_def.action
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
base.action :create, label: "Create" do
|
|
51
|
+
show? { false }
|
|
52
|
+
commit do |object, ctx|
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
base.action :update, label: "Update" do
|
|
57
|
+
show? { false }
|
|
58
|
+
commit do |object, ctx|
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Context class to hold action context data
|
|
64
|
+
# It is a Hash-like object that provides access to common attributes like actor, data
|
|
65
|
+
class Context < Hash
|
|
66
|
+
%i[actor data].each do |attr_name|
|
|
67
|
+
define_method attr_name do
|
|
68
|
+
self[attr_name]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
define_method "#{attr_name}=".to_sym do |value|
|
|
72
|
+
self[attr_name] = value
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def initialize(options = {}) # rubocop:disable Lint/MissingSuper
|
|
77
|
+
# TODO: check option validity
|
|
78
|
+
options.each do |key, value|
|
|
79
|
+
self[key] = value
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class Def # rubocop:disable Style/Documentation
|
|
85
|
+
attr_accessor :action
|
|
86
|
+
|
|
87
|
+
def initialize(name, options = {})
|
|
88
|
+
@action = Action.new
|
|
89
|
+
@action.code = name
|
|
90
|
+
|
|
91
|
+
with_options options
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def with_options(options)
|
|
95
|
+
options.each do |key, value|
|
|
96
|
+
send(key.to_s, value)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def label(label)
|
|
101
|
+
@action.label = label
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def order(order)
|
|
105
|
+
@action.order = order
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def type(type)
|
|
109
|
+
@action.type = type
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def use_policy(use_policy)
|
|
113
|
+
@action.use_policy = use_policy
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def execute_before_action(action_code, options = {})
|
|
117
|
+
@action.before_actions << {
|
|
118
|
+
action_code: action_code,
|
|
119
|
+
options: options
|
|
120
|
+
}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def execute_after_action(action_code, options = {})
|
|
124
|
+
@action.after_actions << {
|
|
125
|
+
action_code: action_code,
|
|
126
|
+
options: options
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def show?(&block)
|
|
131
|
+
@action.hdl_show = block
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def authorized?(&block)
|
|
135
|
+
@action.hdl_authorized = block
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def commitable?(&block)
|
|
139
|
+
@action.hdl_commitable = block
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def commit(&block)
|
|
143
|
+
@action.hdl_commit = block
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def finalize(&block)
|
|
147
|
+
@action.hdl_finalize = block
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
class Error < StandardError
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
class ActorMissingError < Error
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
class InvalidDataError < Error
|
|
10
158
|
end
|
|
11
159
|
end
|
data/lib/action.rb
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Action # rubocop:disable Metrics/ClassLength,Style/Documentation
|
|
4
|
+
attr_accessor :code, :label, :order, :use_policy, :after_actions, :before_actions, :hdl_show, :hdl_authorized,
|
|
5
|
+
:hdl_commitable, :hdl_commit, :hdl_finalize
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@order = 0
|
|
9
|
+
@after_actions = []
|
|
10
|
+
@before_actions = []
|
|
11
|
+
@error = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def commit!(object, context)
|
|
15
|
+
execute(object, context)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def show?(object, context)
|
|
19
|
+
if use_policy
|
|
20
|
+
if hdl_show
|
|
21
|
+
instance_exec(object, context, &hdl_show)
|
|
22
|
+
else
|
|
23
|
+
authorized?(object, context) && commitable?(object, context)
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
!hdl_show || instance_exec(object, context, &hdl_show)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def authorized?(object, context) # rubocop:disable Metrics/MethodLength
|
|
31
|
+
# if use_policy
|
|
32
|
+
# if hdl_authorized
|
|
33
|
+
# instance_exec(object, context, &hdl_authorized)
|
|
34
|
+
# else
|
|
35
|
+
# context_for_policy = context.merge({ user: context[:actor] })
|
|
36
|
+
# policy = Pundit.policy!(context_for_policy, object)
|
|
37
|
+
# policy.send("#{code}?")
|
|
38
|
+
# end
|
|
39
|
+
# else
|
|
40
|
+
# !hdl_authorized || instance_exec(object, context, &hdl_authorized)
|
|
41
|
+
# end
|
|
42
|
+
!hdl_authorized || instance_exec(object, context, &hdl_authorized)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def commitable?(object, context)
|
|
46
|
+
!hdl_commitable || instance_exec(object, context, &hdl_commitable)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def after_action?(action_code)
|
|
50
|
+
!!after_actions.detect { |after_action| after_action[:action_code] == action_code }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def before_action?(action_code)
|
|
54
|
+
!!before_actions.detect { |before_action| before_action[:action_code] == action_code }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def commit(object, context)
|
|
60
|
+
instance_exec object, context, &hdl_commit
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def verify_context(context)
|
|
64
|
+
return if context.actor
|
|
65
|
+
|
|
66
|
+
raise Actify::ActorMissingError, "Actor is required to commit action"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def execute(object, context) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
70
|
+
verify_context(context)
|
|
71
|
+
|
|
72
|
+
log = initialize_action_log(object, context)
|
|
73
|
+
|
|
74
|
+
if !(commitable = authorized?(object, context))
|
|
75
|
+
log.status = ActionLog.statuses[:aborted]
|
|
76
|
+
log.error = { message: "Unauthorized" }
|
|
77
|
+
elsif !(commmitable = commitable && commitable?(object, context))
|
|
78
|
+
log.status = ActionLog.statuses[:aborted]
|
|
79
|
+
log.error = { message: "Wrong context" }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
if commmitable
|
|
83
|
+
begin
|
|
84
|
+
execute_before_actions object, context
|
|
85
|
+
|
|
86
|
+
commit object, context
|
|
87
|
+
|
|
88
|
+
execute_after_actions object, context
|
|
89
|
+
|
|
90
|
+
log.status = ActionLog.statuses[:finished]
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
log.status = ActionLog.statuses[:aborted]
|
|
93
|
+
log.error = { message: e.message }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
finalize_action_log log, object, context
|
|
98
|
+
|
|
99
|
+
log
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def finalize_action_log(log, object, context) # rubocop:disable Metrics/AbcSize
|
|
103
|
+
object_before = {}
|
|
104
|
+
object_after = {}
|
|
105
|
+
|
|
106
|
+
object.previous_changes.each do |k, v|
|
|
107
|
+
object_before[k] = v[0]
|
|
108
|
+
object_after[k] = v[1]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
log.object_before = object_before.as_json.to_s
|
|
112
|
+
log.object_after = object_after.as_json.to_s
|
|
113
|
+
|
|
114
|
+
instance_exec(log, object, context, &hdl_finalize) if hdl_finalize
|
|
115
|
+
|
|
116
|
+
log.save!
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def execute_before_actions(object, context)
|
|
120
|
+
to_run_actions = object.class::Actions.all.select do |_code, action|
|
|
121
|
+
action.before_action? code
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
to_run_actions.each_value do |action|
|
|
125
|
+
# if action.executable?(context, object, params)
|
|
126
|
+
action.commit! object, context
|
|
127
|
+
# end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def execute_after_actions(object, context)
|
|
132
|
+
to_run_actions = object.class::Actions.all.select do |_code, action|
|
|
133
|
+
action.after_action? code
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
to_run_actions.each_value do |action|
|
|
137
|
+
# if action.executable?(context, object, params)
|
|
138
|
+
action.commit! object, context
|
|
139
|
+
# end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def initialize_action_log(object, context) # rubocop:disable Metrics/MethodLength
|
|
144
|
+
ActionLog.create!(
|
|
145
|
+
status: ActionLog.statuses[:created],
|
|
146
|
+
actor_id: context.actor.id,
|
|
147
|
+
actionable: object,
|
|
148
|
+
action_code: code,
|
|
149
|
+
action_label: label,
|
|
150
|
+
action_data: context.data.to_s,
|
|
151
|
+
context: context.to_s
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: actify
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- nguyenta99
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-07-
|
|
11
|
+
date: 2025-07-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email:
|
|
@@ -22,16 +22,23 @@ files:
|
|
|
22
22
|
- CHANGELOG.md
|
|
23
23
|
- CODE_OF_CONDUCT.md
|
|
24
24
|
- Gemfile
|
|
25
|
+
- Gemfile.lock
|
|
25
26
|
- LICENSE.txt
|
|
26
27
|
- README.md
|
|
27
28
|
- Rakefile
|
|
28
29
|
- lib/actify.rb
|
|
30
|
+
- lib/actify/generators/actify/install_generator.rb
|
|
31
|
+
- lib/actify/railtie.rb
|
|
32
|
+
- lib/actify/templates/action_log.rb.tt
|
|
33
|
+
- lib/actify/templates/create_action_logs.rb.tt
|
|
29
34
|
- lib/actify/version.rb
|
|
35
|
+
- lib/action.rb
|
|
30
36
|
- sig/actify.rbs
|
|
31
|
-
homepage: https://
|
|
37
|
+
homepage: https://github.com/nguyenta99/actify
|
|
32
38
|
licenses:
|
|
33
39
|
- MIT
|
|
34
|
-
metadata:
|
|
40
|
+
metadata:
|
|
41
|
+
source_code_uri: https://github.com/nguyenta99/actify
|
|
35
42
|
post_install_message:
|
|
36
43
|
rdoc_options: []
|
|
37
44
|
require_paths:
|