cantango-core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/.document +5 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +54 -0
  4. data/Gemfile.lock +231 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.mdown +90 -0
  7. data/Rakefile +48 -0
  8. data/VERSION +1 -0
  9. data/cantango-core.gemspec +177 -0
  10. data/lib/cantango/ability.rb +5 -0
  11. data/lib/cantango/ability/base.rb +61 -0
  12. data/lib/cantango/ability/cache.rb +7 -0
  13. data/lib/cantango/ability/cache/key.rb +38 -0
  14. data/lib/cantango/ability/cached.rb +28 -0
  15. data/lib/cantango/ability/executor.rb +7 -0
  16. data/lib/cantango/ability/executor/base.rb +53 -0
  17. data/lib/cantango/ability/executor/cache_mode.rb +33 -0
  18. data/lib/cantango/ability/executor/modes.rb +52 -0
  19. data/lib/cantango/ability/executor/no_cache_mode.rb +17 -0
  20. data/lib/cantango/ability/helper.rb +11 -0
  21. data/lib/cantango/ability/helper/account.rb +13 -0
  22. data/lib/cantango/ability/helper/engine.rb +32 -0
  23. data/lib/cantango/ability/helper/role.rb +21 -0
  24. data/lib/cantango/ability/helper/role_group.rb +21 -0
  25. data/lib/cantango/ability/helper/user.rb +18 -0
  26. data/lib/cantango/cancan/rule.rb +6 -0
  27. data/lib/cantango/core.rb +84 -0
  28. data/lib/cantango/engine.rb +39 -0
  29. data/lib/cantango/filter.rb +5 -0
  30. data/lib/cantango/filter/base.rb +31 -0
  31. data/lib/cantango/helpers.rb +5 -0
  32. data/lib/cantango/helpers/debug.rb +10 -0
  33. data/lib/cantango/loader.rb +5 -0
  34. data/lib/cantango/loader/yaml.rb +33 -0
  35. data/lib/cantango/macros.rb +11 -0
  36. data/lib/cantango/macros/account.rb +14 -0
  37. data/lib/cantango/macros/user.rb +16 -0
  38. data/lib/cantango/model.rb +5 -0
  39. data/lib/cantango/model/guest.rb +25 -0
  40. data/lib/cantango/rails.rb +7 -0
  41. data/lib/cantango/rails/engine.rb +63 -0
  42. data/lib/cantango/rails/helpers/base_helper.rb +29 -0
  43. data/lib/cantango/rails/helpers/controller_helper.rb +17 -0
  44. data/lib/cantango/rails/helpers/rest_helper.rb +76 -0
  45. data/lib/cantango/rails/helpers/view_helper.rb +17 -0
  46. data/lib/cantango/rails/railtie.rb +7 -0
  47. data/lib/cantango/rspec.rb +1 -0
  48. data/lib/cantango/rspec/config.rb +3 -0
  49. data/lib/cantango/rspec/matchers.rb +1 -0
  50. data/lib/cantango/rspec/matchers/be_allowed_to.rb +28 -0
  51. data/lib/cantango/rules.rb +8 -0
  52. data/lib/cantango/rules/adaptor.rb +37 -0
  53. data/lib/cantango/rules/adaptor/active_record.rb +10 -0
  54. data/lib/cantango/rules/adaptor/data_mapper.rb +11 -0
  55. data/lib/cantango/rules/adaptor/generic.rb +16 -0
  56. data/lib/cantango/rules/adaptor/mongo.rb +19 -0
  57. data/lib/cantango/rules/adaptor/mongo_mapper.rb +10 -0
  58. data/lib/cantango/rules/adaptor/mongoid.rb +9 -0
  59. data/lib/cantango/rules/adaptor/relational.rb +13 -0
  60. data/lib/cantango/rules/dsl.rb +24 -0
  61. data/lib/cantango/rules/relation.rb +67 -0
  62. data/lib/cantango/rules/rule_class.rb +11 -0
  63. data/lib/cantango/rules/scope.rb +24 -0
  64. data/lib/cantango/scope.rb +5 -0
  65. data/lib/cantango/scope/ability.rb +20 -0
  66. data/lib/generators/cantango/install/install_generator.rb +37 -0
  67. data/lib/generators/cantango/install/templates/cantango.rb +4 -0
  68. data/lib/generators/cantango/install/templates/categories.yml +0 -0
  69. data/lib/generators/cantango/install/templates/permissions.yml +6 -0
  70. data/spec/cantango/ability/base_spec.rb +73 -0
  71. data/spec/cantango/ability/cached_spec.rb +0 -0
  72. data/spec/cantango/ability/executor/base2.rb +75 -0
  73. data/spec/cantango/ability/executor/base_spec.rb +67 -0
  74. data/spec/cantango/ability/executor/cache_mode_spec.rb +77 -0
  75. data/spec/cantango/ability/executor/modes_spec.rb +68 -0
  76. data/spec/cantango/ability/executor/no_cache_mode_spec.rb +0 -0
  77. data/spec/cantango/cancan/rule_spec.rb +0 -0
  78. data/spec/cantango/core_spec.rb +9 -0
  79. data/spec/cantango/engine_spec.rb +0 -0
  80. data/spec/cantango/filter/base_spec.rb +0 -0
  81. data/spec/cantango/helpers/debug_spec.rb +0 -0
  82. data/spec/cantango/loader/yaml_spec.rb +0 -0
  83. data/spec/cantango/macros/account_spec.rb +0 -0
  84. data/spec/cantango/macros/user_spec.rb +0 -0
  85. data/spec/cantango/rspec/be_allowed_to_spec.rb +0 -0
  86. data/spec/cantango/rules/adaptor/active_record_spec.rb +0 -0
  87. data/spec/cantango/rules/adaptor/data_mapper_spec.rb +0 -0
  88. data/spec/cantango/rules/adaptor/mongo_mapper_spec.rb +0 -0
  89. data/spec/cantango/rules/adaptor/mongoid_spec.rb +0 -0
  90. data/spec/cantango/rules/adaptor_spec.rb +0 -0
  91. data/spec/cantango/rules/dsl_spec.rb +0 -0
  92. data/spec/cantango/rules/relation_spec.rb +0 -0
  93. data/spec/cantango/rules/rule_class_spec.rb +0 -0
  94. data/spec/cantango/rules/scope_spec.rb +0 -0
  95. data/spec/cantango/rules_spec.rb +55 -0
  96. data/spec/cantango/scope/ability_spec.rb +0 -0
  97. data/spec/cantango_spec.rb +0 -0
  98. data/spec/generators/cantango/install_generator_spec.rb +42 -0
  99. data/spec/spec_helper.rb +9 -0
  100. metadata +310 -0
@@ -0,0 +1,7 @@
1
+ module CanTango
2
+ module Rails
3
+ module Helpers
4
+ autoload_modules :ControllerHelper, :ViewHelper, :BaseHelper, :RestHelper
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,63 @@
1
+ module CanTango
2
+ # Include helpers in the given scope to AC and AV.
3
+ # "Borrowed" from devise
4
+ def self.include_helpers(scope)
5
+ # Seems like the order of initializers is important! ActiveRecord should go first!
6
+ ActiveSupport.on_load(:active_record) do
7
+ RailsAutoLoader.load_models! if CanTango.config.autoload.models?
8
+ end
9
+
10
+ ActiveSupport.on_load(:action_controller) do
11
+ include scope::Rails::Helpers::ControllerHelper
12
+ end
13
+
14
+ ActiveSupport.on_load(:action_view) do
15
+ include scope::Rails::Helpers::ViewHelper
16
+ end
17
+ end
18
+
19
+ # http://edgeguides.rubyonrails.org/configuring.html
20
+ # - before_configuration: This is run as soon as the application constant inherits from Rails::Application. The config calls are evaluated before this happens.
21
+ # - before_initialize: This is run directly before the initialization process of the application occurs with the :bootstrap_hook initializer near the beginning of the Rails initialization process.
22
+ # - to_prepare: Run after the initializers are ran for all Railties (including the application itself), but before eager loading and the middleware stack is built. More importantly, will run upon every request in development, but only once (during boot-up) in production and test.
23
+ # - before_eager_load: This is run directly before eager loading occurs, which is the default behaviour for the production environment and not for the development environment.
24
+ # - after_initialize: Run directly after the initialization of the application, but before the application initializers are run.
25
+ class RailsEngine < ::Rails::Engine
26
+ initializer "cantango.helpers" do
27
+ CanTango.include_helpers(CanTango)
28
+
29
+ # load all models
30
+ # this is needed in order to register all users and accounts with CanTango using the user/account macros!
31
+ end
32
+
33
+ config.to_prepare do
34
+ CanTango.to_prepare
35
+
36
+ # load all permits (development mode: EVERY request!)
37
+ RailsAutoLoader.load_permits! if CanTango.config.autoload.permits?
38
+ end
39
+
40
+ config.after_initialize do
41
+ CanTango.after_initialize
42
+ end
43
+ end
44
+
45
+ module RailsAutoLoader
46
+ def self.load_models!
47
+ load_files! :models
48
+ end
49
+
50
+ def self.load_permits!
51
+ load_files! :permits
52
+ end
53
+
54
+ private
55
+
56
+ def self.load_files! path
57
+ Dir[::Rails.root + "app/#{path}/**/*.rb"].each do |path|
58
+ require_dependency path
59
+ end
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,29 @@
1
+ module CanTango
2
+ module Rails
3
+ module Helpers
4
+ module BaseHelper
5
+ def self.included(base)
6
+ include_apis(base)
7
+ # base.send :include, CanTango::Rails::Helpers::RestHelper
8
+ base.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ def include_apis(clazz)
13
+ return if !respond_to?(:apis) || !apis
14
+ apis.each do |api|
15
+ # puts "include API: #{api}"
16
+ clazz.send :include, "CanTango::Api::User::#{api}".constantize
17
+ clazz.send :include, "CanTango::Api::UserAccount::#{api}".constantize
18
+ end
19
+ end
20
+
21
+ def apis
22
+ [:Can, :Scope, :Ability, :Session]
23
+ end
24
+ end
25
+ extend ClassMethods
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module CanTango
2
+ module Rails
3
+ module Helpers
4
+ module ControllerHelper
5
+ include CanTango::Rails::Helpers::BaseHelper
6
+
7
+ def self.included(base)
8
+ include_apis(self)
9
+ end
10
+
11
+ def self.apis
12
+ [] # [:Can, :Active, :Scope]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,76 @@
1
+ module CanTango::Rails::Helpers::RestHelper
2
+ CanTango.config.models.actions.registered.each_pair do |model, actions|
3
+ actions.actions_for :member do |member_action|
4
+ class_eval %{
5
+ def #{member_action}_#{model.to_s.underscore}_path obj, options = {}
6
+ return unless can_perform_action?(user_type, :#{member_action}, obj)
7
+ # use i18n translation on label
8
+ link_to t(".#{member_action}"), rest_obj_action(obj, :#{member_action}, options)
9
+ end
10
+ }
11
+ end
12
+
13
+ actions.actions_for :collection do |collection_action|
14
+ class_eval %{
15
+ def #{collection_action}_#{model.to_s.underscore}_path obj, options = {}
16
+ clazz = obj.kind_of?(Class) ? obj : obj.class
17
+ return unless can_perform_action?(user_type, :#{collection_action}, clazz)
18
+ # use i18n translation on label
19
+ link_to t(".#{collection_action}"), send(action_method clazz, :#{collection_action}, options)
20
+ end
21
+ }
22
+ end
23
+ end
24
+
25
+ CanTango.config.models.available_models.each do |model|
26
+ class_eval %{
27
+ def delete_#{model.to_s.underscore}_path obj, options = {}
28
+ #{model}_path obj, {:method => 'delete'}.merge(options)
29
+ end
30
+ }
31
+ end
32
+
33
+ def link_to_new obj, user_type, options = {}
34
+ clazz = obj.kind_of?(Class) ? obj : obj.class
35
+ return unless can_perform_action?(user_type, :create, clazz)
36
+ # use i18n translation on label
37
+ link_to t(".create"), send(action_method clazz, :new, options)
38
+ end
39
+
40
+ def link_to_delete obj, user_type, options = {}
41
+ return unless can_perform_action?(user_type, :delete, obj)
42
+ # use i18n translation on label
43
+ link_to t(".delete"), rest_obj_action(obj, :delete, options)
44
+ end
45
+
46
+ def link_to_edit obj, user_type, options = {}
47
+ return unless can_perform_action?(user_type, :edit, obj)
48
+ # use i18n translation on label
49
+ link_to t(".edit"), rest_obj_action(obj, :edit, options)
50
+ end
51
+
52
+ def link_to_view obj, user_type, options = {}
53
+ return unless can_perform_action?(user_type, :view, obj)
54
+ # use i18n translation on label
55
+ link_to t(".view"), send(view_method(obj), obj, options)
56
+ end
57
+
58
+ protected
59
+
60
+ def can_perform_action? user_type, action, obj
61
+ send(:"#{user_type}_can?", action, obj)
62
+ end
63
+
64
+ def view_method obj
65
+ "#{obj.class.to_s.underscore}_path"
66
+ end
67
+
68
+ def rest_obj_action obj, action, options
69
+ send action_method(obj, :edit), obj, options
70
+ end
71
+
72
+ def action_method obj, action
73
+ "#{action}_#{obj.class.to_s.underscore}_path"
74
+ end
75
+ end
76
+
@@ -0,0 +1,17 @@
1
+ module CanTango
2
+ module Rails
3
+ module Helpers
4
+ module ViewHelper
5
+ include CanTango::Rails::Helpers::BaseHelper
6
+
7
+ def self.included(base)
8
+ include_apis(self)
9
+ end
10
+
11
+ def self.apis
12
+ [] # [:Can, :Active, :Scope]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module CanTango
2
+ class Railtie < Rails::Railtie
3
+ initializer "cantango" do |app|
4
+ # puts "initializing CanTango..."
5
+ end
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ require 'cantango/rspec/config'
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+ require 'code-spec'
3
+ require 'cantango/rspec/matchers'
@@ -0,0 +1 @@
1
+ require 'cantango/rspec/matchers/be_allowed_to'
@@ -0,0 +1,28 @@
1
+ # http://solnic.eu/2011/01/14/custom-rspec-2-matchers.html
2
+
3
+
4
+ RSpec::Matchers.define :be_allowed_to do |action, objects|
5
+ chain :with_options do |options|
6
+ @options = options
7
+ end
8
+
9
+ match do |subject|
10
+ @options ? subject.can?(action, objects, @options) : subject.can?(action, objects)
11
+ end
12
+
13
+ failure_message_for_should do |subject|
14
+ %{expected that #{subject} could #{action} the #{objects}
15
+ #{subject.send :rules}}
16
+ end
17
+
18
+ failure_message_for_should_not do |actual|
19
+ %{did not expect that #{subject} could #{action} the #{objects}
20
+ #{subject.send :rules}}
21
+ end
22
+
23
+ description do
24
+ "be allowed to #{action} the #{objects}"
25
+ end
26
+ end
27
+
28
+
@@ -0,0 +1,8 @@
1
+ module CanTango
2
+ module Rules
3
+ autoload_modules :Adaptor, :Dsl, :RuleClass, :Scope, :Relation
4
+
5
+ include Dsl
6
+ include CanCan::Ability
7
+ end
8
+ end
@@ -0,0 +1,37 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ autoload_modules :Generic, :Relational, :Mongo
5
+ autoload_modules :ActiveRecord, :DataMapper, :Mongoid, :MongoMapper
6
+
7
+ # include adaptor depending on which ORM the object inherits from or includes
8
+ def use_adaptor! base, object
9
+ orm_map.each_pair do |orm, const|
10
+ begin
11
+ base.class.send :include, get_adapter(object, const.constantize, orm)
12
+ rescue
13
+ next
14
+ end
15
+ end
16
+ end
17
+
18
+ def get_adapter object, adaptor_class, orm
19
+ object.kind_of?(adaptor_class) ? adaptor_for(orm) : adaptor_for(:generic)
20
+ end
21
+
22
+ def adaptor_for orm
23
+ "CanTango::Rules::Adaptor::#{orm.to_s.camelize}".constantize
24
+ end
25
+
26
+ def orm_map
27
+ {
28
+ :active_record => "ActiveRecord::Base",
29
+ :data_mapper => "DataMapper::Resource",
30
+ :mongoid => "Mongoid::Document",
31
+ :mongo_mapper => "MongoMapper::Document"
32
+ }
33
+ end
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,10 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ module ActiveRecord
5
+ include CanTango::Rules::Adaptor::Relational
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,11 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ module DataMapper
5
+ include CanTango::Rules::Adaptor::Relational
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+
@@ -0,0 +1,16 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ module Generic
5
+
6
+ def attribute_condition attribute, user_scope
7
+ Proc.new { |model| model.send(attribute) == user_scope }
8
+ end
9
+
10
+ def include_condition attribute, user_scope
11
+ Proc.new { |model| model.send(attribute).include? user_scope }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ module Mongo
5
+ #include CanTango::Rules::Adaptor::Generic
6
+ # using #in on Hash (Mongoid query)
7
+ def include_condition attribute, user_scope
8
+ { attribute.to_sym.in => user_scope.send(attribute) }
9
+ end
10
+
11
+ def attribute_condition attribute, user_scope
12
+ { attribute.to_sym => user_scope.send(attribute) }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+
@@ -0,0 +1,10 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ module MongoMapper
5
+ include module CanTango::Rules::Adaptor::Mongo
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,9 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ module Mongoid
5
+ include module CanTango::Rules::Adaptor::Mongo
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module CanTango
2
+ module Rules
3
+ module Adaptor
4
+ module Relational
5
+ def attribute_condition attribute, user_scope
6
+ { attribute.to_sym => user_scope.send(attribute) }
7
+ end
8
+ alias_method :include_condition, :attribute_condition
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,24 @@
1
+ module CanTango
2
+ module Rules
3
+ module Dsl
4
+ def self.included(base)
5
+ ::CanTango.config.user.relations.each do |relationship|
6
+ base.class_eval %{
7
+ def #{relationship}_of *models, &block
8
+ options = models.extract_options!
9
+ scope = options[:scope] || :user_account
10
+ relation = UserRelation.new :#{relationship}, self, scope, *models, &block
11
+ yield relation if block
12
+ relation
13
+ end
14
+ }
15
+ end
16
+ end
17
+
18
+ # creates a scope that enforces either using the user or user_account for determining relationship matches on the models
19
+ def scope name, &block
20
+ yield CanTango::Rules::Scope.new name, self, &block
21
+ end
22
+ end
23
+ end
24
+ end