chanko 1.0.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +22 -0
- data/.travis.yml +5 -0
- data/Gemfile +26 -0
- data/MIT-LICENSE +22 -0
- data/README.md +168 -0
- data/Rakefile +12 -0
- data/chanko.gemspec +30 -0
- data/lib/chanko.rb +19 -0
- data/lib/chanko/active_if.rb +59 -0
- data/lib/chanko/config.rb +30 -0
- data/lib/chanko/controller.rb +31 -0
- data/lib/chanko/exception_handler.rb +10 -0
- data/lib/chanko/function.rb +85 -0
- data/lib/chanko/helper.rb +29 -0
- data/lib/chanko/invoker.rb +105 -0
- data/lib/chanko/invoker/function_finder.rb +42 -0
- data/lib/chanko/invoker/options.rb +64 -0
- data/lib/chanko/loader.rb +65 -0
- data/lib/chanko/logger.rb +67 -0
- data/lib/chanko/railtie.rb +11 -0
- data/lib/chanko/test.rb +44 -0
- data/lib/chanko/unit.rb +101 -0
- data/lib/chanko/unit/extender.rb +21 -0
- data/lib/chanko/unit/extender/active_record_class_methods.rb +57 -0
- data/lib/chanko/unit/extender/extension.rb +51 -0
- data/lib/chanko/unit/scope_finder.rb +41 -0
- data/lib/chanko/unit_proxy.rb +30 -0
- data/lib/chanko/unit_proxy_provider.rb +27 -0
- data/lib/chanko/version.rb +3 -0
- data/lib/generators/chanko/unit/templates/unit.rb.erb +84 -0
- data/lib/generators/chanko/unit/unit_generator.rb +49 -0
- data/spec/chanko/controller_spec.rb +44 -0
- data/spec/chanko/exception_handler_spec.rb +39 -0
- data/spec/chanko/function_spec.rb +60 -0
- data/spec/chanko/helper_spec.rb +26 -0
- data/spec/chanko/invoker_spec.rb +156 -0
- data/spec/chanko/loader_spec.rb +43 -0
- data/spec/chanko/logger_spec.rb +94 -0
- data/spec/chanko/test_spec.rb +28 -0
- data/spec/chanko/unit/extender_spec.rb +40 -0
- data/spec/chanko/unit/scope_finder_spec.rb +37 -0
- data/spec/chanko/unit_proxy_provider_spec.rb +68 -0
- data/spec/chanko/unit_proxy_spec.rb +23 -0
- data/spec/chanko/unit_spec.rb +181 -0
- data/spec/controllers/application_controller_spec.rb +15 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +14 -0
- data/spec/dummy/app/assets/stylesheets/main.scss +21 -0
- data/spec/dummy/app/assets/stylesheets/reset.scss +14 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/entries_controller.rb +33 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/entry.rb +3 -0
- data/spec/dummy/app/units/entry_deletion/entry_deletion.rb +37 -0
- data/spec/dummy/app/units/entry_deletion/views/_delete_link.html.slim +1 -0
- data/spec/dummy/app/views/entries/edit.html.slim +14 -0
- data/spec/dummy/app/views/entries/index.html.slim +5 -0
- data/spec/dummy/app/views/entries/show.html.slim +8 -0
- data/spec/dummy/app/views/layouts/application.html.slim +16 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +68 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/db/migrate/20130127170331_create_entries.rb +11 -0
- data/spec/dummy/db/schema.rb +24 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/fixtures/units/example_unit/example_unit.rb +77 -0
- data/spec/fixtures/units/example_unit/views/_test.html.erb +1 -0
- data/spec/fixtures/units/inactive_unit/inactive_unit.rb +11 -0
- data/spec/fixtures/units/insensitive_unit/insensitive_unit.rb +3 -0
- data/spec/fixtures/units/sensitive_unit/sensitive_unit.rb +4 -0
- data/spec/spec_helper.rb +27 -0
- metadata +339 -170
@@ -0,0 +1,85 @@
|
|
1
|
+
module Chanko
|
2
|
+
class Function
|
3
|
+
attr_reader :block, :unit, :label
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def units
|
7
|
+
@units ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def current_unit
|
11
|
+
units.last
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(unit, label, &block)
|
16
|
+
@unit = unit
|
17
|
+
@label = label
|
18
|
+
@block = block
|
19
|
+
end
|
20
|
+
|
21
|
+
def invoke(context, options = {})
|
22
|
+
with_unit_stack(context) do
|
23
|
+
with_unit_view_path(context) do
|
24
|
+
capture_exception(context) do
|
25
|
+
result = context.instance_eval(&block)
|
26
|
+
result = decorate(result, context, options[:type]) if context.view? && result.present?
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def css_classes
|
34
|
+
if Config.compatible_css_class
|
35
|
+
%W[
|
36
|
+
extension
|
37
|
+
ext_#{unit.unit_name}
|
38
|
+
ext_#{unit.unit_name}-#{label}
|
39
|
+
]
|
40
|
+
else
|
41
|
+
%W[
|
42
|
+
unit
|
43
|
+
unit__#{unit.unit_name}
|
44
|
+
unit__#{unit.unit_name}__#{label}
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def with_unit_stack(context)
|
52
|
+
context.units << @unit
|
53
|
+
self.class.units << @unit
|
54
|
+
yield
|
55
|
+
ensure
|
56
|
+
self.class.units.pop
|
57
|
+
context.units.pop
|
58
|
+
end
|
59
|
+
|
60
|
+
def with_unit_view_path(context)
|
61
|
+
context.view_paths.unshift unit.resolver if context.respond_to?(:view_paths)
|
62
|
+
yield
|
63
|
+
ensure
|
64
|
+
context.view_paths.paths.shift if context.respond_to?(:view_paths)
|
65
|
+
end
|
66
|
+
|
67
|
+
def capture_exception(context)
|
68
|
+
yield
|
69
|
+
rescue Exception => exception
|
70
|
+
ExceptionHandler.handle(exception, unit)
|
71
|
+
context.run_default
|
72
|
+
end
|
73
|
+
|
74
|
+
def decorate(str, context, type)
|
75
|
+
case type
|
76
|
+
when :plain
|
77
|
+
str
|
78
|
+
when :inline
|
79
|
+
context.content_tag(:span, str, :class => css_classes)
|
80
|
+
else
|
81
|
+
context.content_tag(:div, str, :class => css_classes)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Helper
|
3
|
+
class << self
|
4
|
+
def define(unit_name, &block)
|
5
|
+
prefix = UnitProxy.generate_prefix(unit_name)
|
6
|
+
define_methods_with_prefix(prefix, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def define_methods_with_prefix(prefix, &block)
|
10
|
+
define_methods(&block).each do |name|
|
11
|
+
change_method_name(name, "#{prefix}#{name}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def define_methods(&block)
|
16
|
+
before = instance_methods(false)
|
17
|
+
self.class_eval(&block)
|
18
|
+
instance_methods(false) - before
|
19
|
+
end
|
20
|
+
|
21
|
+
def change_method_name(from, to)
|
22
|
+
class_eval do
|
23
|
+
alias_method to, from
|
24
|
+
remove_method from
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "chanko/invoker/options"
|
2
|
+
require "chanko/invoker/function_finder"
|
3
|
+
|
4
|
+
module Chanko
|
5
|
+
module Invoker
|
6
|
+
def invoke(*args, &block)
|
7
|
+
options = Options.new(*args)
|
8
|
+
__with_default_stack(block) do
|
9
|
+
__with_unit_locals_stack(options.locals) do
|
10
|
+
if function = FunctionFinder.find(self, options)
|
11
|
+
function.invoke(self, options.invoke_options)
|
12
|
+
else
|
13
|
+
run_default
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def units
|
20
|
+
@units ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
def view?
|
24
|
+
is_a?(ActionView::Base)
|
25
|
+
end
|
26
|
+
|
27
|
+
def run_default
|
28
|
+
__invoke_default_block if __has_default_block?
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def method_missing(method_name, *args, &block)
|
34
|
+
if shared_method = __find_shared_method(method_name)
|
35
|
+
instance_exec(*args, &shared_method)
|
36
|
+
elsif args.empty? && __find_unit_local(method_name)
|
37
|
+
__fetch_unit_local(method_name)
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def __find_unit_local(method_name)
|
44
|
+
__current_unit_locals.has_key?(method_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def __fetch_unit_local(method_name)
|
48
|
+
__current_unit_locals[method_name]
|
49
|
+
end
|
50
|
+
|
51
|
+
def __current_unit_locals
|
52
|
+
__unit_locals_stack.last || {}
|
53
|
+
end
|
54
|
+
|
55
|
+
def __unit_locals_stack
|
56
|
+
@__unit_locals_stack ||= []
|
57
|
+
end
|
58
|
+
|
59
|
+
def __find_shared_method(method_name)
|
60
|
+
__current_shared_methods[method_name]
|
61
|
+
end
|
62
|
+
|
63
|
+
def __current_shared_methods
|
64
|
+
__current_unit.try(:shared_methods) || {}
|
65
|
+
end
|
66
|
+
|
67
|
+
def __current_unit
|
68
|
+
units.last
|
69
|
+
end
|
70
|
+
|
71
|
+
def __defaults_stack
|
72
|
+
@__defaults_stack ||= []
|
73
|
+
end
|
74
|
+
|
75
|
+
def __default_block
|
76
|
+
__defaults_stack.last
|
77
|
+
end
|
78
|
+
|
79
|
+
def __has_default_block?
|
80
|
+
!!__default_block
|
81
|
+
end
|
82
|
+
|
83
|
+
def __invoke_default_block
|
84
|
+
if view?
|
85
|
+
capture(&__default_block)
|
86
|
+
else
|
87
|
+
instance_exec(&__default_block)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def __with_default_stack(default)
|
92
|
+
__defaults_stack << default
|
93
|
+
yield
|
94
|
+
ensure
|
95
|
+
__defaults_stack.pop
|
96
|
+
end
|
97
|
+
|
98
|
+
def __with_unit_locals_stack(locals)
|
99
|
+
__unit_locals_stack << locals
|
100
|
+
yield
|
101
|
+
ensure
|
102
|
+
__unit_locals_stack.pop
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Invoker
|
3
|
+
class FunctionFinder
|
4
|
+
def self.find(context, options)
|
5
|
+
new(context, options).find
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :context, :options
|
9
|
+
|
10
|
+
delegate :active_if_options, :as, :label, :unit_name, :to => :options
|
11
|
+
|
12
|
+
def initialize(context, options)
|
13
|
+
@context = context
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
def find
|
18
|
+
active? && find_function
|
19
|
+
end
|
20
|
+
|
21
|
+
def scope
|
22
|
+
as || context.class
|
23
|
+
end
|
24
|
+
|
25
|
+
def unit
|
26
|
+
Loader.load(unit_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_function
|
30
|
+
unit.find_function(scope, label)
|
31
|
+
end
|
32
|
+
|
33
|
+
def active?
|
34
|
+
if unit
|
35
|
+
unit.active?(context, active_if_options)
|
36
|
+
else
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Invoker
|
3
|
+
class Options
|
4
|
+
CANDIDATES = {
|
5
|
+
:active_if_options => true,
|
6
|
+
:as => true,
|
7
|
+
:capture => true,
|
8
|
+
:locals => true,
|
9
|
+
:type => true,
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
@raw_options = args.extract_options!
|
14
|
+
@args = args
|
15
|
+
end
|
16
|
+
|
17
|
+
def unit_name
|
18
|
+
@args[0]
|
19
|
+
end
|
20
|
+
|
21
|
+
def label
|
22
|
+
@args[1]
|
23
|
+
end
|
24
|
+
|
25
|
+
def locals
|
26
|
+
(options[:locals] || {}).symbolize_keys
|
27
|
+
end
|
28
|
+
|
29
|
+
def active_if_options
|
30
|
+
options[:active_if_options] || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def as
|
34
|
+
options[:as]
|
35
|
+
end
|
36
|
+
|
37
|
+
def capture
|
38
|
+
options.has_key?(:capture) ? capture[:capture] : true
|
39
|
+
end
|
40
|
+
|
41
|
+
def type
|
42
|
+
options[:type]
|
43
|
+
end
|
44
|
+
|
45
|
+
def invoke_options
|
46
|
+
{ :capture => capture, :type => type }
|
47
|
+
end
|
48
|
+
|
49
|
+
def options
|
50
|
+
@options ||= begin
|
51
|
+
if short_hand_options?
|
52
|
+
{ :locals => @raw_options }
|
53
|
+
else
|
54
|
+
@raw_options
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def short_hand_options?
|
60
|
+
@raw_options.any? && @raw_options.keys.all? {|key| !CANDIDATES[key] }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Chanko
|
4
|
+
class Loader
|
5
|
+
class << self
|
6
|
+
def load(unit_name)
|
7
|
+
new(unit_name).load
|
8
|
+
end
|
9
|
+
|
10
|
+
def cache
|
11
|
+
@cache ||= {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(name)
|
16
|
+
@name = name
|
17
|
+
end
|
18
|
+
|
19
|
+
def load
|
20
|
+
if loaded?
|
21
|
+
load_from_cache
|
22
|
+
else
|
23
|
+
load_from_file
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def loaded?
|
28
|
+
cache[@name] != nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def load_from_cache
|
32
|
+
cache[@name]
|
33
|
+
end
|
34
|
+
|
35
|
+
def load_from_file
|
36
|
+
add_autoload_path
|
37
|
+
cache[@name] = constantize
|
38
|
+
rescue Exception => exception
|
39
|
+
ExceptionHandler.handle(exception)
|
40
|
+
cache[@name] = false
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_autoload_path
|
45
|
+
ActiveSupport::Dependencies.autoload_paths << autoload_path
|
46
|
+
ActiveSupport::Dependencies.autoload_paths.uniq!
|
47
|
+
end
|
48
|
+
|
49
|
+
def autoload_path
|
50
|
+
Rails.root.join("#{directory_path}/#@name").to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def directory_path
|
54
|
+
Config.units_directory_path
|
55
|
+
end
|
56
|
+
|
57
|
+
def constantize
|
58
|
+
@name.to_s.camelize.constantize
|
59
|
+
end
|
60
|
+
|
61
|
+
def cache
|
62
|
+
self.class.cache
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Logger
|
3
|
+
|
4
|
+
class << self
|
5
|
+
::Logger::Severity.constants.each do |level|
|
6
|
+
method_name = level.downcase
|
7
|
+
define_method(method_name) do |message|
|
8
|
+
logger.try(method_name, decorate(message)) if Config.enable_logger
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def decorate(message)
|
13
|
+
Message.new(message).to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def logger
|
17
|
+
Rails.logger
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Message
|
22
|
+
PREFIX = " [Chanko]"
|
23
|
+
|
24
|
+
def initialize(object)
|
25
|
+
@object = object
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
prefix(content)
|
30
|
+
end
|
31
|
+
|
32
|
+
def prefix(str)
|
33
|
+
str.split("\n").map {|line| "#{PREFIX} #{line}" }.join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
def content
|
37
|
+
if @object.is_a?(Exception)
|
38
|
+
"#{klass}#{body}#{backtrace}"
|
39
|
+
else
|
40
|
+
@object.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def body
|
45
|
+
unless @object.message.empty?
|
46
|
+
" - #@object"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def klass
|
51
|
+
@object.class
|
52
|
+
end
|
53
|
+
|
54
|
+
def backtrace
|
55
|
+
if has_backtrace?
|
56
|
+
lines = @object.backtrace[0...Config.backtrace_limit]
|
57
|
+
str = lines.map {|line| " #{line}" }.join("\n")
|
58
|
+
"\n#{str}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def has_backtrace?
|
63
|
+
@object.backtrace
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|