chanko 1.0.6 → 2.0.0

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.
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