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,11 @@
|
|
1
|
+
module Chanko
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
initializer "chanko" do |app|
|
4
|
+
::ActionView::Base.send(:include, Helper, Invoker, UnitProxyProvider)
|
5
|
+
::ActionController::Base.send(:include, Controller, Invoker, UnitProxyProvider)
|
6
|
+
::ActiveRecord::Base.send(:include, UnitProxyProvider)
|
7
|
+
::ActiveRecord::Relation.send(:include, UnitProxyProvider)
|
8
|
+
::ActiveRecord::Associations::CollectionAssociation.send(:include, UnitProxyProvider)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/chanko/test.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Test
|
3
|
+
class << self
|
4
|
+
def activations
|
5
|
+
@activations ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def included(base)
|
9
|
+
base.send :include, UnitProxyProvider
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def enable_unit(unit_name)
|
14
|
+
Test.activations[unit_name] = true
|
15
|
+
end
|
16
|
+
alias_method :enable_ext, :enable_unit
|
17
|
+
|
18
|
+
def disable_unit(unit_name)
|
19
|
+
Test.activations[unit_name] = false
|
20
|
+
end
|
21
|
+
alias_method :disable_ext, :disable_unit
|
22
|
+
end
|
23
|
+
|
24
|
+
module Unit
|
25
|
+
module ClassMethods
|
26
|
+
def active_with_activations?(*args)
|
27
|
+
case Test.activations[unit_name]
|
28
|
+
when true
|
29
|
+
true
|
30
|
+
when false
|
31
|
+
false
|
32
|
+
else
|
33
|
+
active_without_activations?(*args)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
alias_method_chain :active?, :activations
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
RSpec.configure do |config|
|
42
|
+
config.include Chanko::Test
|
43
|
+
config.after { Chanko::Test.activations.clear }
|
44
|
+
end
|
data/lib/chanko/unit.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require "chanko/unit/extender"
|
2
|
+
require "chanko/unit/scope_finder"
|
3
|
+
|
4
|
+
module Chanko
|
5
|
+
module Unit
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
active_if { true }
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
attr_accessor :current_scope
|
14
|
+
|
15
|
+
def scope(identifier)
|
16
|
+
self.current_scope = ScopeFinder.find(identifier)
|
17
|
+
scopes[current_scope] ||= {}
|
18
|
+
yield
|
19
|
+
ensure
|
20
|
+
self.current_scope = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def function(label, &block)
|
24
|
+
functions[label] = Function.new(self, label, &block)
|
25
|
+
end
|
26
|
+
alias_method :callback, :function
|
27
|
+
|
28
|
+
def shared(label, &block)
|
29
|
+
shared_methods[label] = block
|
30
|
+
end
|
31
|
+
|
32
|
+
def helpers(&block)
|
33
|
+
Helper.define(unit_name, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def models(&block)
|
37
|
+
extender.instance_eval(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def active_if(*conditions, &block)
|
41
|
+
@active_if = ActiveIf.new(*conditions, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def active?(context, options = {})
|
45
|
+
@active_if.active?(context, options.merge(:unit => self))
|
46
|
+
end
|
47
|
+
|
48
|
+
def any(*labels)
|
49
|
+
ActiveIf::Any.new(*labels)
|
50
|
+
end
|
51
|
+
|
52
|
+
def raise_error
|
53
|
+
@raise_error = true
|
54
|
+
end
|
55
|
+
alias_method :propagates_errors, :raise_error
|
56
|
+
|
57
|
+
def raise_error?
|
58
|
+
@raise_error
|
59
|
+
end
|
60
|
+
|
61
|
+
def unit_name
|
62
|
+
@unit_name ||= name.underscore.to_sym
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_prefix
|
66
|
+
UnitProxy.generate_prefix(unit_name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def view_path
|
70
|
+
"#{Config.units_directory_path}/#{unit_name}/views"
|
71
|
+
end
|
72
|
+
|
73
|
+
def find_function(identifier, label)
|
74
|
+
scope = ScopeFinder.find(identifier)
|
75
|
+
target = scope.ancestors.find {|klass| scopes[klass] }
|
76
|
+
functions = scopes[target]
|
77
|
+
functions[label] if functions
|
78
|
+
end
|
79
|
+
|
80
|
+
def functions
|
81
|
+
scopes[current_scope]
|
82
|
+
end
|
83
|
+
|
84
|
+
def scopes
|
85
|
+
@scopes ||= {}
|
86
|
+
end
|
87
|
+
|
88
|
+
def shared_methods
|
89
|
+
@shared_methods ||= {}
|
90
|
+
end
|
91
|
+
|
92
|
+
def resolver
|
93
|
+
@resolver ||= Config.resolver.new(view_path)
|
94
|
+
end
|
95
|
+
|
96
|
+
def extender
|
97
|
+
@extender ||= Extender.new(to_prefix)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "chanko/unit/extender/active_record_class_methods"
|
2
|
+
require "chanko/unit/extender/extension"
|
3
|
+
|
4
|
+
module Chanko
|
5
|
+
module Unit
|
6
|
+
class Extender
|
7
|
+
def initialize(prefix = nil)
|
8
|
+
@prefix = prefix
|
9
|
+
end
|
10
|
+
|
11
|
+
def expand(mod, &block)
|
12
|
+
mod = mod.to_s.camelize.constantize unless mod.is_a?(Module)
|
13
|
+
extension = Extension.new(mod, @prefix, &block)
|
14
|
+
mod.class_eval do
|
15
|
+
include extension.instance_methods_module
|
16
|
+
extend extension.class_methods_module
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Unit
|
3
|
+
class Extender
|
4
|
+
module ActiveRecordClassMethods
|
5
|
+
delegate(
|
6
|
+
:apply_modules,
|
7
|
+
:arel,
|
8
|
+
:array_of_strings?,
|
9
|
+
:build_arel,
|
10
|
+
:build_joins,
|
11
|
+
:build_select,
|
12
|
+
:build_where,
|
13
|
+
:create_with,
|
14
|
+
:custom_join_sql,
|
15
|
+
:eager_load,
|
16
|
+
:extending,
|
17
|
+
:from,
|
18
|
+
:group,
|
19
|
+
:having,
|
20
|
+
:includes,
|
21
|
+
:joins,
|
22
|
+
:limit,
|
23
|
+
:lock,
|
24
|
+
:offset,
|
25
|
+
:order,
|
26
|
+
:preload,
|
27
|
+
:readonly,
|
28
|
+
:reorder,
|
29
|
+
:reverse_order,
|
30
|
+
:reverse_sql_order,
|
31
|
+
:scope,
|
32
|
+
:select,
|
33
|
+
:where,
|
34
|
+
:to => :@mod
|
35
|
+
)
|
36
|
+
|
37
|
+
%w[belongs_to has_many has_one].each do |method_name|
|
38
|
+
class_eval <<-EOS
|
39
|
+
def #{method_name}(*args, &block)
|
40
|
+
label = args.shift.to_s
|
41
|
+
name = @prefix + label
|
42
|
+
options = args.extract_options!
|
43
|
+
options = options.reverse_merge(:class_name => label.singularize.camelize)
|
44
|
+
args << options
|
45
|
+
@mod.#{method_name}(name.to_sym, *args, &block)
|
46
|
+
end
|
47
|
+
EOS
|
48
|
+
end
|
49
|
+
|
50
|
+
def scope(*args, &block)
|
51
|
+
name = @prefix + args.shift.to_s
|
52
|
+
@mod.scope(name, *args)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Unit
|
3
|
+
class Extender
|
4
|
+
class Extension < Module
|
5
|
+
include ActiveRecordClassMethods
|
6
|
+
|
7
|
+
def initialize(mod, prefix = nil, &block)
|
8
|
+
@mod = mod
|
9
|
+
@prefix = prefix
|
10
|
+
@block = block
|
11
|
+
define_methods_with_prefix(instance_methods_module, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def class_methods(&block)
|
15
|
+
define_methods_with_prefix(class_methods_module, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def instance_methods_module
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def class_methods_module
|
23
|
+
@class_methods_module ||= Module.new
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def define_methods_with_prefix(container, &block)
|
29
|
+
define_methods(container, &block).each do |added_method_name|
|
30
|
+
change_method_name_with_prefix(container, added_method_name) if @prefix.present?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_methods(container, &block)
|
35
|
+
before = container.instance_methods(false)
|
36
|
+
container.class_eval(&block)
|
37
|
+
container.instance_methods(false) - before
|
38
|
+
end
|
39
|
+
|
40
|
+
def change_method_name_with_prefix(container, method_name)
|
41
|
+
from = method_name
|
42
|
+
to = "#@prefix#{method_name}"
|
43
|
+
container.class_eval do
|
44
|
+
alias_method to, from
|
45
|
+
remove_method from
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Chanko
|
2
|
+
module Unit
|
3
|
+
class ScopeFinder
|
4
|
+
LABEL_SCOPE_MAP = {
|
5
|
+
:controller => ActionController::Base,
|
6
|
+
:model => ActiveRecord::Base,
|
7
|
+
:view => ActionView::Base,
|
8
|
+
}
|
9
|
+
|
10
|
+
def self.find(*args)
|
11
|
+
new(*args).find
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(identifier)
|
15
|
+
@identifier = identifier
|
16
|
+
end
|
17
|
+
|
18
|
+
def find
|
19
|
+
case
|
20
|
+
when class?
|
21
|
+
@identifier
|
22
|
+
when label
|
23
|
+
label
|
24
|
+
else
|
25
|
+
@identifier.to_s.constantize
|
26
|
+
end
|
27
|
+
rescue NameError
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def class?
|
33
|
+
@identifier.is_a?(Class)
|
34
|
+
end
|
35
|
+
|
36
|
+
def label
|
37
|
+
LABEL_SCOPE_MAP[@identifier]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "delegate"
|
2
|
+
|
3
|
+
module Chanko
|
4
|
+
class UnitProxy
|
5
|
+
attr_reader :unit
|
6
|
+
|
7
|
+
def self.generate_prefix(unit_name)
|
8
|
+
"__#{unit_name}_"
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(unit, context)
|
12
|
+
@unit = unit
|
13
|
+
@context = context
|
14
|
+
end
|
15
|
+
|
16
|
+
def active?(options = {})
|
17
|
+
@unit.active?(@context, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def prefix
|
23
|
+
self.class.generate_prefix(@unit.unit_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method_name, *args, &block)
|
27
|
+
@context.send("#{prefix}#{method_name}", *args, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Chanko
|
2
|
+
module UnitProxyProvider
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extend UnitProxyProvider
|
7
|
+
end
|
8
|
+
|
9
|
+
# Define #unit method in this class when #unit is called in first time.
|
10
|
+
# Change Config.proxy_method_name if you want to change this method name.
|
11
|
+
def method_missing(method_name, *args, &block)
|
12
|
+
if Array.wrap(Config.proxy_method_name).include?(method_name)
|
13
|
+
UnitProxyProvider.class_eval do
|
14
|
+
define_method(method_name) do |*_args|
|
15
|
+
name = _args.first || Function.current_unit.try(:unit_name)
|
16
|
+
if name && unit = Loader.load(name)
|
17
|
+
UnitProxy.new(unit, self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
send(method_name, args.first)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module <%= class_name %>
|
2
|
+
include Chanko::Unit
|
3
|
+
|
4
|
+
# ## active_if
|
5
|
+
# This block is used to decide if this unit is active or not.
|
6
|
+
# `context` is the receiver object of `invoke`.
|
7
|
+
# `options` is passed via `invoke(:foo, :bar, :active_if_options => { ... })`.
|
8
|
+
# By default, this is set as `active_if { true }`.
|
9
|
+
#
|
10
|
+
# ```
|
11
|
+
# active_if do |context, options|
|
12
|
+
# true
|
13
|
+
# end
|
14
|
+
# ```
|
15
|
+
|
16
|
+
# ## raise_error
|
17
|
+
# `raise_error` is used to force an unit to raise up errors occured in invoking.
|
18
|
+
# You can force to raise up errors also by `Config.raise_error`.
|
19
|
+
#
|
20
|
+
# ```
|
21
|
+
# raise_error
|
22
|
+
# ```
|
23
|
+
|
24
|
+
# ## function
|
25
|
+
# In controller or view context, you can call functions defined by `function`
|
26
|
+
# via `invoke(:<%= file_name %>, :function_name)`.
|
27
|
+
#
|
28
|
+
# ```
|
29
|
+
# scope(:controller) do
|
30
|
+
# function(:function_name) do
|
31
|
+
# "Chanko!"
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
# ```
|
35
|
+
|
36
|
+
# ## render
|
37
|
+
# In addition, the view path "<%= "#{directory}/views" %>" is added into view_paths.
|
38
|
+
# So you can render <%= "#{directory}/views/_example.html.erb" %> in invoking.
|
39
|
+
#
|
40
|
+
# ```
|
41
|
+
# scope(:view) do
|
42
|
+
# function(:function_name) do
|
43
|
+
# render "/example", :foo => "bar"
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
# ```
|
47
|
+
|
48
|
+
# ## models
|
49
|
+
# In models block, you can expand model features by `expand` method.
|
50
|
+
# The expanded methods are available via unit proxy like `User.unit.active`,
|
51
|
+
# and `User.find(params[:id]).unit.active?`, and so on.
|
52
|
+
#
|
53
|
+
# ```
|
54
|
+
# models do
|
55
|
+
# expand(:User) do
|
56
|
+
# scope :active, lambda { where(:deleted_at => nil) }
|
57
|
+
#
|
58
|
+
# def active?
|
59
|
+
# deleted_at.nil?
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
# ```
|
64
|
+
|
65
|
+
# ## shared
|
66
|
+
# You can call methods defined by `shared` in invoking.
|
67
|
+
#
|
68
|
+
# ```
|
69
|
+
# shared(:hello) do |world|
|
70
|
+
# "Hello, #{world}"
|
71
|
+
# end
|
72
|
+
# ```
|
73
|
+
|
74
|
+
# ## helpers
|
75
|
+
# You can call helpers in view via unit proxy like `unit.helper_method`
|
76
|
+
#
|
77
|
+
# ```
|
78
|
+
# helpers do
|
79
|
+
# def helper_method
|
80
|
+
# "helper method"
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
# ```
|
84
|
+
end
|