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,22 @@
1
+ log/*.log
2
+ spec/dummy/db/*.sqlite3
3
+ spec/dummy/log/*.log
4
+ spec/dummy/tmp/
5
+ spec/dummy/.sass-cache
6
+ *.gem
7
+ *.rbc
8
+ .bundle
9
+ .config
10
+ .yardoc
11
+ Gemfile.lock
12
+ InstalledFiles
13
+ _yardoc
14
+ coverage
15
+ doc/
16
+ lib/bundler/man
17
+ pkg
18
+ rdoc
19
+ spec/reports
20
+ test/tmp
21
+ test/version_tmp
22
+ tmp
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,26 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test, :production do
6
+ gem "jquery-rails"
7
+ gem "quiet_assets"
8
+ gem "rails", ">= 3.0.10"
9
+ gem "slim"
10
+ gem "sqlite3"
11
+ end
12
+
13
+ group :test do
14
+ gem "rspec-rails", "2.12.2"
15
+ end
16
+
17
+ group :development, :test do
18
+ gem "pry-rails"
19
+ gem "thin"
20
+ end
21
+
22
+ group :assets do
23
+ gem "sass-rails", ">= 3.0.10"
24
+ gem "coffee-rails", ">= 3.0.10"
25
+ gem "uglifier"
26
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ryo Nakamura
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.
@@ -0,0 +1,168 @@
1
+ # Chanko
2
+ Chanko provides a simple framework for rapidly and safely prototyping new
3
+ features in your production Rails app, and exposing these prototypes to
4
+ specified segments of your user base.
5
+
6
+ With Chanko, you can release many concurrent features and independently manage
7
+ which users see them. If there are errors with any chanko, it will be
8
+ automatically removed, without impacting your site.
9
+
10
+
11
+ ## Requirements
12
+ * Ruby >= 1.8.7
13
+ * Rails >= 3.0.10
14
+
15
+
16
+ ## Usage
17
+ Add to your Gemfile.
18
+
19
+ ```ruby
20
+ gem "chanko"
21
+ ```
22
+
23
+ ## Files
24
+ Chanko provides a generator to create a template of unit.
25
+
26
+ ```
27
+ $ rails generate chanko:install example_unit
28
+ ```
29
+
30
+ ## Invoke
31
+ You can invoke the logics defined in your units via `invoke` and `unit` methods.
32
+ In controller class context, `unit_action` utility is also provided.
33
+ The block passed to `invoke` is a fallback executed if any problem occurs in invoking.
34
+
35
+ ```ruby
36
+ # app/controllers/users_controller.rb
37
+ class UsersController < ApplicationController
38
+ unit_action :example_unit, :show
39
+
40
+ def index
41
+ invoke(:example_unit, :index) do
42
+ @users = User.all
43
+ end
44
+ end
45
+ end
46
+ ```
47
+
48
+ ```
49
+ -# app/views/examples/index.html.slim
50
+ = unit.helper_method
51
+ = invoke(:example_unit, :render_example)
52
+ ```
53
+
54
+ ```
55
+ -# app/units/example_unit/views/_example.html.slim
56
+ = foo
57
+ ```
58
+
59
+ ## Unit
60
+
61
+ ### module
62
+ You can define your MVC code here.
63
+
64
+ ```ruby
65
+ # app/units/example_unit/example_unit.rb
66
+ module ExampleUnit
67
+ include Chanko::Unit
68
+ ...
69
+ end
70
+ ```
71
+
72
+ ### active_if
73
+ This block is used to decide if this unit is active or not.
74
+ `context` is the receiver object of `invoke`.
75
+ `options` is passed via `invoke(:foo, :bar, :active_if_options => { ... })`.
76
+ By default, this is set as `active_if { true }`.
77
+
78
+ ```ruby
79
+ active_if do |context, options|
80
+ true
81
+ end
82
+ ```
83
+
84
+ ### raise_error
85
+ By default, any error raised in production env is ignored.
86
+ `raise_error` is used to force an unit to raise up errors occured in invoking.
87
+ You can force all units to raise up errors by `Config.raise_error = true`.
88
+
89
+ ```ruby
90
+ raise_error
91
+ ```
92
+
93
+ ### function
94
+ In controller or view context, you can call functions defined by `function`
95
+ via `invoke(:example_unit, :function_name)`.
96
+
97
+ ```ruby
98
+ scope(:controller) do
99
+ function(:show) do
100
+ @user = User.find(params[:id])
101
+ end
102
+
103
+ function(:index) do
104
+ @users = User.active
105
+ end
106
+ end
107
+ ```
108
+
109
+ ### render
110
+ The view path app/units/example_unit/views is added into view_paths in invoking.
111
+ So you can render app/units/example_unit/views/_example.html.slim in invoking.
112
+
113
+ ```ruby
114
+ scope(:view) do
115
+ function(:render_example) do
116
+ render "/example", :foo => hello("world")
117
+ end
118
+ end
119
+ ```
120
+
121
+ ### models
122
+ In models block, you can expand model features by `expand` method.
123
+ The expanded methods are available via unit proxy like `User.unit.active`,
124
+ and `User.find(params[:id]).unit.active?`, and so on.
125
+
126
+ ```ruby
127
+ models do
128
+ expand(:User) do
129
+ scope :active, lambda { where(:deleted_at => nil) }
130
+
131
+ def active?
132
+ deleted_at.nil?
133
+ end
134
+ end
135
+ end
136
+ ```
137
+
138
+ ### shared
139
+ You can call methods defined by `shared` in invoking.
140
+
141
+ ```ruby
142
+ shared(:hello) do |world|
143
+ "Hello, #{world}"
144
+ end
145
+ ```
146
+
147
+ ### helpers
148
+ You can call helpers in view via unit proxy like `unit.helper_method`.
149
+
150
+ ```ruby
151
+ helpers do
152
+ def helper_method
153
+ "helper method"
154
+ end
155
+ end
156
+ ```
157
+
158
+
159
+ ## Example
160
+ https://github.com/cookpad/chanko/tree/master/spec/dummy
161
+ Chanko provides an example rails application in spec/dummy directory.
162
+
163
+ ```
164
+ $ git clone git@github.com:cookpad/chanko.git
165
+ $ cd chanko/spec/dummy
166
+ $ rails s
167
+ $ open http://localhost:3000
168
+ ```
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = "spec/**/*_spec.rb"
7
+ spec.rspec_opts = ["-cfs"]
8
+ end
9
+ rescue LoadError => e
10
+ end
11
+
12
+ task :default => :spec
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "chanko/version"
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "chanko"
7
+ gem.version = Chanko::VERSION
8
+ gem.authors = ["Ryo Nakamura"]
9
+ gem.email = ["r7kamura@gmail.com"]
10
+ gem.description = "Chanko is a Rails extension tool"
11
+ gem.summary = "Rails extension tool"
12
+ gem.homepage = "https://github.com/cookpad/chanko"
13
+
14
+ gem.files = `git ls-files`.split($/)
15
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_dependency "rails", ">= 3.0.10"
20
+ gem.add_development_dependency "coffee-rails", ">= 3.0.10"
21
+ gem.add_development_dependency "jquery-rails"
22
+ gem.add_development_dependency "pry"
23
+ gem.add_development_dependency "rspec-rails", "2.12.2"
24
+ gem.add_development_dependency "sass-rails", ">= 3.0.10"
25
+ gem.add_development_dependency "simplecov"
26
+ gem.add_development_dependency "slim"
27
+ gem.add_development_dependency "sqlite3"
28
+ gem.add_development_dependency "thin"
29
+ gem.add_development_dependency "uglifier"
30
+ end
@@ -0,0 +1,19 @@
1
+ require "action_controller"
2
+ require "action_view"
3
+ require "active_record"
4
+ require "active_support/all"
5
+ require "rails"
6
+
7
+ require "chanko/active_if"
8
+ require "chanko/config"
9
+ require "chanko/controller"
10
+ require "chanko/exception_handler"
11
+ require "chanko/function"
12
+ require "chanko/helper"
13
+ require "chanko/invoker"
14
+ require "chanko/loader"
15
+ require "chanko/logger"
16
+ require "chanko/railtie"
17
+ require "chanko/unit"
18
+ require "chanko/unit_proxy"
19
+ require "chanko/unit_proxy_provider"
@@ -0,0 +1,59 @@
1
+ module Chanko
2
+ class ActiveIf
3
+ class << self
4
+ def define(label, &block)
5
+ definitions[label] = block
6
+ end
7
+
8
+ def find(label)
9
+ definitions[label]
10
+ end
11
+
12
+ def definitions
13
+ @definitions ||= {}
14
+ end
15
+
16
+ def clear
17
+ definitions.clear
18
+ end
19
+ end
20
+
21
+ attr_reader :conditions, :options
22
+
23
+ def initialize(*conditions, &block)
24
+ @options = conditions.extract_options!
25
+ @conditions = conditions
26
+ @block = block
27
+ end
28
+
29
+ def active?(context, options = {})
30
+ blocks.all? {|block| block.call(context, options) }
31
+ end
32
+
33
+ def blocks
34
+ @blocks ||= begin
35
+ conditions.map do |condition|
36
+ condition.is_a?(Any) ? condition.to_block : self.class.find(condition)
37
+ end << @block
38
+ end.compact
39
+ end
40
+
41
+ class Any
42
+ def initialize(*labels)
43
+ @labels = labels
44
+ end
45
+
46
+ def to_block
47
+ proc do |context, options|
48
+ definitions.any? do |definition|
49
+ definition.call(context, options)
50
+ end
51
+ end
52
+ end
53
+
54
+ def definitions
55
+ @labels.map {|label| ActiveIf.find(label) }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,30 @@
1
+ module Chanko
2
+ module Config
3
+ class << self
4
+ attr_accessor(
5
+ :auto_reload,
6
+ :backtrace_limit,
7
+ :cache_units,
8
+ :compatible_css_class,
9
+ :enable_logger,
10
+ :proxy_method_name,
11
+ :raise_error,
12
+ :resolver,
13
+ :units_directory_path
14
+ )
15
+
16
+ def reset
17
+ self.auto_reload = Rails.env.development? || Rails.env.test?
18
+ self.backtrace_limit = 10
19
+ self.compatible_css_class = false
20
+ self.enable_logger = true
21
+ self.proxy_method_name = :unit
22
+ self.raise_error = Rails.env.development?
23
+ self.resolver = ActionView::OptimizedFileSystemResolver
24
+ self.units_directory_path = "app/units"
25
+ end
26
+ end
27
+
28
+ reset
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module Chanko
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ private
7
+
8
+ def inherited(base)
9
+ if Config.auto_reload && base.name == "ApplicationController"
10
+ base.class_eval do
11
+ prepend_before_filter do
12
+ Chanko::Loader.cache.clear
13
+ end
14
+ end
15
+ end
16
+ super
17
+ end
18
+
19
+ def unit_action(unit_name, *function_names, &block)
20
+ options = function_names.extract_options!
21
+ block ||= Proc.new { head 400 }
22
+ Array.wrap(function_names).each do |function_name|
23
+ define_method(function_name) do
24
+ invoke(unit_name, function_name, options, &block)
25
+ end
26
+ end
27
+ end
28
+ alias_method :ext_action, :unit_action
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module Chanko
2
+ module ExceptionHandler
3
+ class << self
4
+ def handle(exception, unit = nil)
5
+ Logger.debug(exception)
6
+ raise exception if unit.try(:raise_error?) || Config.raise_error
7
+ end
8
+ end
9
+ end
10
+ end