chanko 1.0.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.gitignore +22 -0
  2. data/.travis.yml +5 -0
  3. data/Gemfile +26 -0
  4. data/MIT-LICENSE +22 -0
  5. data/README.md +168 -0
  6. data/Rakefile +12 -0
  7. data/chanko.gemspec +30 -0
  8. data/lib/chanko.rb +19 -0
  9. data/lib/chanko/active_if.rb +59 -0
  10. data/lib/chanko/config.rb +30 -0
  11. data/lib/chanko/controller.rb +31 -0
  12. data/lib/chanko/exception_handler.rb +10 -0
  13. data/lib/chanko/function.rb +85 -0
  14. data/lib/chanko/helper.rb +29 -0
  15. data/lib/chanko/invoker.rb +105 -0
  16. data/lib/chanko/invoker/function_finder.rb +42 -0
  17. data/lib/chanko/invoker/options.rb +64 -0
  18. data/lib/chanko/loader.rb +65 -0
  19. data/lib/chanko/logger.rb +67 -0
  20. data/lib/chanko/railtie.rb +11 -0
  21. data/lib/chanko/test.rb +44 -0
  22. data/lib/chanko/unit.rb +101 -0
  23. data/lib/chanko/unit/extender.rb +21 -0
  24. data/lib/chanko/unit/extender/active_record_class_methods.rb +57 -0
  25. data/lib/chanko/unit/extender/extension.rb +51 -0
  26. data/lib/chanko/unit/scope_finder.rb +41 -0
  27. data/lib/chanko/unit_proxy.rb +30 -0
  28. data/lib/chanko/unit_proxy_provider.rb +27 -0
  29. data/lib/chanko/version.rb +3 -0
  30. data/lib/generators/chanko/unit/templates/unit.rb.erb +84 -0
  31. data/lib/generators/chanko/unit/unit_generator.rb +49 -0
  32. data/spec/chanko/controller_spec.rb +44 -0
  33. data/spec/chanko/exception_handler_spec.rb +39 -0
  34. data/spec/chanko/function_spec.rb +60 -0
  35. data/spec/chanko/helper_spec.rb +26 -0
  36. data/spec/chanko/invoker_spec.rb +156 -0
  37. data/spec/chanko/loader_spec.rb +43 -0
  38. data/spec/chanko/logger_spec.rb +94 -0
  39. data/spec/chanko/test_spec.rb +28 -0
  40. data/spec/chanko/unit/extender_spec.rb +40 -0
  41. data/spec/chanko/unit/scope_finder_spec.rb +37 -0
  42. data/spec/chanko/unit_proxy_provider_spec.rb +68 -0
  43. data/spec/chanko/unit_proxy_spec.rb +23 -0
  44. data/spec/chanko/unit_spec.rb +181 -0
  45. data/spec/controllers/application_controller_spec.rb +15 -0
  46. data/spec/dummy/README.rdoc +261 -0
  47. data/spec/dummy/Rakefile +7 -0
  48. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  49. data/spec/dummy/app/assets/stylesheets/application.css +14 -0
  50. data/spec/dummy/app/assets/stylesheets/main.scss +21 -0
  51. data/spec/dummy/app/assets/stylesheets/reset.scss +14 -0
  52. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  53. data/spec/dummy/app/controllers/entries_controller.rb +33 -0
  54. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  55. data/spec/dummy/app/mailers/.gitkeep +0 -0
  56. data/spec/dummy/app/models/.gitkeep +0 -0
  57. data/spec/dummy/app/models/entry.rb +3 -0
  58. data/spec/dummy/app/units/entry_deletion/entry_deletion.rb +37 -0
  59. data/spec/dummy/app/units/entry_deletion/views/_delete_link.html.slim +1 -0
  60. data/spec/dummy/app/views/entries/edit.html.slim +14 -0
  61. data/spec/dummy/app/views/entries/index.html.slim +5 -0
  62. data/spec/dummy/app/views/entries/show.html.slim +8 -0
  63. data/spec/dummy/app/views/layouts/application.html.slim +16 -0
  64. data/spec/dummy/config.ru +4 -0
  65. data/spec/dummy/config/application.rb +68 -0
  66. data/spec/dummy/config/boot.rb +10 -0
  67. data/spec/dummy/config/database.yml +25 -0
  68. data/spec/dummy/config/environment.rb +5 -0
  69. data/spec/dummy/config/environments/development.rb +37 -0
  70. data/spec/dummy/config/environments/production.rb +67 -0
  71. data/spec/dummy/config/environments/test.rb +37 -0
  72. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  73. data/spec/dummy/config/initializers/inflections.rb +15 -0
  74. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  75. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  76. data/spec/dummy/config/initializers/session_store.rb +8 -0
  77. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  78. data/spec/dummy/config/locales/en.yml +5 -0
  79. data/spec/dummy/config/routes.rb +5 -0
  80. data/spec/dummy/db/migrate/20130127170331_create_entries.rb +11 -0
  81. data/spec/dummy/db/schema.rb +24 -0
  82. data/spec/dummy/lib/assets/.gitkeep +0 -0
  83. data/spec/dummy/log/.gitkeep +0 -0
  84. data/spec/dummy/public/404.html +26 -0
  85. data/spec/dummy/public/422.html +26 -0
  86. data/spec/dummy/public/500.html +25 -0
  87. data/spec/dummy/public/favicon.ico +0 -0
  88. data/spec/dummy/script/rails +6 -0
  89. data/spec/fixtures/units/example_unit/example_unit.rb +77 -0
  90. data/spec/fixtures/units/example_unit/views/_test.html.erb +1 -0
  91. data/spec/fixtures/units/inactive_unit/inactive_unit.rb +11 -0
  92. data/spec/fixtures/units/insensitive_unit/insensitive_unit.rb +3 -0
  93. data/spec/fixtures/units/sensitive_unit/sensitive_unit.rb +4 -0
  94. data/spec/spec_helper.rb +27 -0
  95. 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