memorable 0.1.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 +7 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/lib/memorable.rb +22 -0
- data/lib/memorable/configuration.rb +47 -0
- data/lib/memorable/controller.rb +111 -0
- data/lib/memorable/error.rb +7 -0
- data/lib/memorable/model.rb +35 -0
- data/lib/memorable/template_engine.rb +99 -0
- data/lib/memorable/templates/en_US.yml +9 -0
- data/lib/memorable/version.rb +3 -0
- data/memorable.gemspec +27 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d7fb95cbd8bfc993b815802ff41abe3abf913f4f
|
4
|
+
data.tar.gz: 52fe4c06f792b75c26a461057ceb477b206ee30d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 746e7e131f7f1cd71c11e53a19ae00bc7e26eeb467af2026a59c400554555129d06c7a1fe765c5249264d2c688299d825eae0226e69ec809d02b52fac878f61e
|
7
|
+
data.tar.gz: 3a728d5a5021dee59581388cbd8493c554e95db98b86ce73c68906d1f222b3dc21b884f7f6d463537c71194f6ac66ffabd84d0e61ca8679487899190e5418267
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Xiaoguang Chen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/memorable.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
require 'memorable/version'
|
4
|
+
require 'memorable/error'
|
5
|
+
require 'memorable/configuration'
|
6
|
+
require 'memorable/template_engine'
|
7
|
+
require 'memorable/model'
|
8
|
+
require 'memorable/controller'
|
9
|
+
|
10
|
+
module Memorable
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def setup(&block)
|
14
|
+
Configuration.class_eval(&block) if block_given?
|
15
|
+
|
16
|
+
Configuration.journals_model.send :include, Memorable::Model
|
17
|
+
ActionController::Base.send :include, Memorable::Controller
|
18
|
+
|
19
|
+
TemplateEngine.load!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Memorable
|
2
|
+
class Configuration
|
3
|
+
@register_actions = {}
|
4
|
+
@journals_model = nil
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_reader :register_actions, :journals_model
|
8
|
+
|
9
|
+
def journals_model=(model)
|
10
|
+
model_klass = Object.const_get model.capitalize
|
11
|
+
@journals_model = model_klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def register(action_names, controller_name, options, condition_proc)
|
15
|
+
register_actions[controller_name] ||= {}
|
16
|
+
register_actions[controller_name][:actions] ||= []
|
17
|
+
register_actions[controller_name][:actions].concat([action_names].flatten)
|
18
|
+
register_actions[controller_name][:options] ||= {}
|
19
|
+
register_actions[controller_name][:options].merge! options
|
20
|
+
register_actions[controller_name][:condition_proc] ||= condition_proc
|
21
|
+
end
|
22
|
+
|
23
|
+
def registered?(key, name)
|
24
|
+
register_actions[key] && register_actions[key][:actions].include?(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def condition_matched?(controller)
|
28
|
+
condition = condition_proc(controller.controller_name)
|
29
|
+
return true unless condition
|
30
|
+
return controller.instance_eval(&condition)
|
31
|
+
end
|
32
|
+
|
33
|
+
def controller_options(key)
|
34
|
+
register_actions[key][:options] rescue nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def condition_proc(key)
|
38
|
+
register_actions[key][:condition_proc] rescue nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Controller Options Helpers
|
42
|
+
def resource_name(key)
|
43
|
+
register_actions[key][:options][:resource_name] rescue nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Memorable
|
2
|
+
module Controller
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
append_after_filter :memorize_callback
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def memorize_callback
|
12
|
+
return unless memorable?
|
13
|
+
|
14
|
+
# prepare locals for action
|
15
|
+
locals = extract_memorable_locals
|
16
|
+
|
17
|
+
# write to database
|
18
|
+
Configuration.journals_model.create_with_options!(locals)
|
19
|
+
|
20
|
+
rescue Exception => e
|
21
|
+
raise e if Rails.env.development? # for debug
|
22
|
+
Rails.logger.error e.message
|
23
|
+
end
|
24
|
+
|
25
|
+
def memorable?
|
26
|
+
Configuration.registered?(controller_name, action_name) &&
|
27
|
+
Configuration.condition_matched?(self) &&
|
28
|
+
response.successful?
|
29
|
+
end
|
30
|
+
|
31
|
+
def extract_memorable_locals
|
32
|
+
locals = ActiveSupport::HashWithIndifferentAccess.new ({
|
33
|
+
controller: controller_name,
|
34
|
+
action: action_name,
|
35
|
+
user_id: current_user.id
|
36
|
+
})
|
37
|
+
|
38
|
+
if memorable_resource
|
39
|
+
locals.merge! Hash[memorable_resource.previous_changes.map {|key, value| ["previous_#{key}", value[0]]}]
|
40
|
+
locals.merge! memorable_resource.attributes
|
41
|
+
locals.merge!({
|
42
|
+
resource_id: memorable_resource.id,
|
43
|
+
resource_type: memorable_resource.class.to_s
|
44
|
+
})
|
45
|
+
end
|
46
|
+
|
47
|
+
# # Journals Model is free to override the behavior of this method
|
48
|
+
# if journal.respond_to? :set_attributes_for_event
|
49
|
+
# journal.set_attributes_for_event(controller)
|
50
|
+
# end
|
51
|
+
|
52
|
+
custom_method_name = "memorable_#{action_name}"
|
53
|
+
|
54
|
+
if respond_to? custom_method_name
|
55
|
+
custom_locals = self.send custom_method_name
|
56
|
+
locals.merge!(custom_locals)
|
57
|
+
end
|
58
|
+
|
59
|
+
locals
|
60
|
+
end
|
61
|
+
|
62
|
+
def memorable_resource
|
63
|
+
@memorable_resource ||= self.instance_variable_get("@#{memorable_resource_name}") || self.send(:resource) rescue nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def memorable_resource_name
|
67
|
+
Configuration.resource_name(controller_name) || controller_name.singularize
|
68
|
+
end
|
69
|
+
|
70
|
+
module ClassMethods
|
71
|
+
def memorize(options = {}, &block)
|
72
|
+
raise InvalidOptionsError, "if and unless cannot appear at the sametime" if options[:if] && options[:unless]
|
73
|
+
|
74
|
+
if condition = (options[:if] || options[:unless])
|
75
|
+
if_condition = !!options[:if]
|
76
|
+
if condition.is_a?(Symbol)
|
77
|
+
condition_proc = proc { |c| if_condition ? c.send(condition) : !c.send(condition) }
|
78
|
+
elsif condition.is_a? Proc
|
79
|
+
condition_proc = proc { |c| if_condition ? condition.call(c) : !condition.call(c) }
|
80
|
+
else
|
81
|
+
raise InvalidOptionsError, "#{condition} is not a valid Proc or controller method."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
raise InvalidOptionsError, "except and only cannot appear at the sametime" if options[:except] && options[:only]
|
86
|
+
|
87
|
+
specified_actions = [options[:except] || options[:only]].flatten.compact.map(&:to_s)
|
88
|
+
actions =
|
89
|
+
if options.delete(:only)
|
90
|
+
specified_actions
|
91
|
+
elsif options.delete(:except)
|
92
|
+
all_actions - specified_actions
|
93
|
+
else
|
94
|
+
all_actions
|
95
|
+
end
|
96
|
+
|
97
|
+
memorize_actions actions, options, condition_proc
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def memorize_actions(action_names, options, condition_proc)
|
103
|
+
Configuration.register action_names, controller_name, options, condition_proc
|
104
|
+
end
|
105
|
+
|
106
|
+
def all_actions
|
107
|
+
@all_actions ||= action_methods.map(&:to_s)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Memorable
|
2
|
+
|
3
|
+
module Model
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def write_content(options)
|
7
|
+
current_locale = I18n.locale
|
8
|
+
|
9
|
+
TemplateEngine.assemble(options).each do |template|
|
10
|
+
I18n.locale = template[0]
|
11
|
+
content = template[1]
|
12
|
+
end
|
13
|
+
|
14
|
+
I18n.locale = current_locale
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def create_with_options!(options={})
|
19
|
+
journal = self.build_with_options(options)
|
20
|
+
journal.save!
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_with_options(options)
|
24
|
+
journal = self.new
|
25
|
+
|
26
|
+
journal.user_id = options.delete :user_id
|
27
|
+
journal.resource_id = options.delete :resource_id
|
28
|
+
journal.resource_type = options.delete :resource_type
|
29
|
+
|
30
|
+
journal.write_content(options)
|
31
|
+
journal
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Memorable
|
5
|
+
class TemplateEngine
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
attr_reader :load_path, :templates
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@load_path = []
|
12
|
+
@templates = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def store_templates
|
16
|
+
load_path.each do |filename|
|
17
|
+
locale = File.basename(filename, ".yml")
|
18
|
+
data = load_yml filename
|
19
|
+
templates[locale.to_sym] = data
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Loads a YAML template file. The data must have locales as
|
24
|
+
# toplevel keys.
|
25
|
+
def load_yml(filename)
|
26
|
+
begin
|
27
|
+
YAML.load_file(filename)
|
28
|
+
rescue TypeError, ScriptError, StandardError => e
|
29
|
+
raise InvalidYAMLData.new(filename, e.inspect)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def assemble(options)
|
34
|
+
action_templates(options[:controller], options[:action], options[:template_key]).map do |locale, template|
|
35
|
+
content = render_template(template, options)
|
36
|
+
[locale, content]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def render_template(template, locals)
|
43
|
+
if locals
|
44
|
+
I18n.interpolate(template, locals)
|
45
|
+
else
|
46
|
+
template
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def action_templates(controller, action, sub_key)
|
51
|
+
sub_key ||= 'base'
|
52
|
+
raw_templates = catch(:template_found) do
|
53
|
+
parse_entry(controller, action, sub_key)
|
54
|
+
parse_entry(controller, 'other', sub_key)
|
55
|
+
parse_entry('defaults', action, sub_key)
|
56
|
+
parse_entry('defaults', 'other', sub_key)
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
raise TemplateNotFound, "Template: #{controller} #{action} #{sub_key} not found" unless raw_templates
|
60
|
+
raw_templates
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_entry(controller, action, sub_key)
|
64
|
+
raw_templates = templates.map do |locale, template_data|
|
65
|
+
template = template_data[controller][action][sub_key] rescue nil
|
66
|
+
template ? [locale, template] : nil
|
67
|
+
end.compact
|
68
|
+
throw :template_found, raw_templates unless raw_templates.blank?
|
69
|
+
end
|
70
|
+
|
71
|
+
# Class Methods
|
72
|
+
# ----------------------
|
73
|
+
#
|
74
|
+
def self.load!
|
75
|
+
pattern = self.pattern_from I18n.available_locales
|
76
|
+
|
77
|
+
add("templates/#{pattern}.yml")
|
78
|
+
add("app/views/memorable/#{pattern}.yml", Rails.root) if defined?(Rails)
|
79
|
+
|
80
|
+
instance.store_templates
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.assemble(*args)
|
84
|
+
instance.assemble(*args)
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
def self.add(pattern, base_dir=File.dirname(__FILE__))
|
90
|
+
files = Dir[File.join(base_dir, pattern)]
|
91
|
+
instance.load_path.concat(files)
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.pattern_from(args)
|
95
|
+
array = Array(args || [])
|
96
|
+
array.blank? ? '*' : "{#{array.join ','}}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/memorable.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'memorable/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "memorable"
|
8
|
+
spec.version = Memorable::VERSION
|
9
|
+
spec.authors = ["Cxg"]
|
10
|
+
spec.email = ["xg.chen87@gmail.com"]
|
11
|
+
spec.summary = "A Rails logging system based on actions."
|
12
|
+
spec.description = %q{A Rails logging system based on actions, not model
|
13
|
+
callbacks. Customizable ready-to-run configurations
|
14
|
+
and built-in I18n support.}
|
15
|
+
spec.homepage = "https://github.com/serco-chen/memorable"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0") - %w[.gitignore]
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency 'activesupport', '>= 3.2.8', "< 5.0"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: memorable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cxg
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-26 00:00:00.000000000 Z
|
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: 3.2.8
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.8
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.7'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.7'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
description: |-
|
62
|
+
A Rails logging system based on actions, not model
|
63
|
+
callbacks. Customizable ready-to-run configurations
|
64
|
+
and built-in I18n support.
|
65
|
+
email:
|
66
|
+
- xg.chen87@gmail.com
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE
|
73
|
+
- lib/memorable.rb
|
74
|
+
- lib/memorable/configuration.rb
|
75
|
+
- lib/memorable/controller.rb
|
76
|
+
- lib/memorable/error.rb
|
77
|
+
- lib/memorable/model.rb
|
78
|
+
- lib/memorable/template_engine.rb
|
79
|
+
- lib/memorable/templates/en_US.yml
|
80
|
+
- lib/memorable/version.rb
|
81
|
+
- memorable.gemspec
|
82
|
+
homepage: https://github.com/serco-chen/memorable
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.4.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: A Rails logging system based on actions.
|
106
|
+
test_files: []
|