troles 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +26 -0
  3. data/Gemfile.lock +161 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.textile +686 -0
  6. data/Rakefile +48 -0
  7. data/VERSION +1 -0
  8. data/config/database.yml +4 -0
  9. data/development.sqlite3 +0 -0
  10. data/lib/trole/adapters/active_record/config.rb +23 -0
  11. data/lib/trole/adapters/active_record/storage.rb +0 -0
  12. data/lib/trole/adapters/active_record/strategy.rb +0 -0
  13. data/lib/trole/adapters/active_record.rb +8 -0
  14. data/lib/trole/adapters/mongoid/config.rb +34 -0
  15. data/lib/trole/adapters/mongoid/storage.rb +0 -0
  16. data/lib/trole/adapters/mongoid/strategy.rb +0 -0
  17. data/lib/trole/adapters/mongoid.rb +0 -0
  18. data/lib/trole/api/cache.rb +9 -0
  19. data/lib/trole/api/config.rb +12 -0
  20. data/lib/trole/api/core.rb +20 -0
  21. data/lib/trole/api/event.rb +9 -0
  22. data/lib/trole/api/read.rb +14 -0
  23. data/lib/trole/api/validation.rb +9 -0
  24. data/lib/trole/api/write.rb +25 -0
  25. data/lib/trole/api.rb +41 -0
  26. data/lib/trole/config.rb +15 -0
  27. data/lib/trole/macros.rb +5 -0
  28. data/lib/trole/operations/read.rb +12 -0
  29. data/lib/trole/operations/write.rb +11 -0
  30. data/lib/trole/operations.rb +34 -0
  31. data/lib/trole/storage/base_one.rb +46 -0
  32. data/lib/trole/storage/bit_one.rb +43 -0
  33. data/lib/trole/storage/embed_one.rb +36 -0
  34. data/lib/trole/storage/ref_one.rb +39 -0
  35. data/lib/trole/storage/string_one.rb +50 -0
  36. data/lib/trole/storage.rb +14 -0
  37. data/lib/trole/strategy.rb +35 -0
  38. data/lib/trole.rb +10 -0
  39. data/lib/troles/adapters/active_record/Design Notes.textile +4 -0
  40. data/lib/troles/adapters/active_record/config.rb +51 -0
  41. data/lib/troles/adapters/active_record/storage/embed_many.rb +8 -0
  42. data/lib/troles/adapters/active_record/storage.rb +5 -0
  43. data/lib/troles/adapters/active_record/strategy.rb +11 -0
  44. data/lib/troles/adapters/active_record.rb +8 -0
  45. data/lib/troles/adapters/mongoid/Design Notes.textile +3 -0
  46. data/lib/troles/adapters/mongoid/config.rb +45 -0
  47. data/lib/troles/adapters/mongoid.rb +8 -0
  48. data/lib/troles/api/cache.rb +4 -0
  49. data/lib/troles/api/config.rb +9 -0
  50. data/lib/troles/api/core.rb +9 -0
  51. data/lib/troles/api/event.rb +4 -0
  52. data/lib/troles/api/read.rb +4 -0
  53. data/lib/troles/api/validation.rb +4 -0
  54. data/lib/troles/api/write.rb +4 -0
  55. data/lib/troles/api.rb +40 -0
  56. data/lib/troles/common/api/cache.rb +12 -0
  57. data/lib/troles/common/api/config.rb +4 -0
  58. data/lib/troles/common/api/core.rb +52 -0
  59. data/lib/troles/common/api/event.rb +39 -0
  60. data/lib/troles/common/api/read.rb +44 -0
  61. data/lib/troles/common/api/validation.rb +44 -0
  62. data/lib/troles/common/api/write.rb +76 -0
  63. data/lib/troles/common/api.rb +28 -0
  64. data/lib/troles/common/config/schema.rb +72 -0
  65. data/lib/troles/common/config/schema_helpers.rb +95 -0
  66. data/lib/troles/common/config/static_roles.rb +14 -0
  67. data/lib/troles/common/config/valid_roles.rb +21 -0
  68. data/lib/troles/common/config.rb +96 -0
  69. data/lib/troles/common/dependencies.rb +9 -0
  70. data/lib/troles/common/event_manager.rb +40 -0
  71. data/lib/troles/common/macros/configuration/base_loader.rb +40 -0
  72. data/lib/troles/common/macros/configuration/config_loader.rb +19 -0
  73. data/lib/troles/common/macros/configuration/storage_loader.rb +20 -0
  74. data/lib/troles/common/macros/configuration/strategy_loader.rb +38 -0
  75. data/lib/troles/common/macros/configuration.rb +89 -0
  76. data/lib/troles/common/macros/static_roles.rb +9 -0
  77. data/lib/troles/common/macros/strategy_options.rb +21 -0
  78. data/lib/troles/common/macros.rb +38 -0
  79. data/lib/troles/common/marshaller/bitmask.rb +43 -0
  80. data/lib/troles/common/marshaller/generic.rb +24 -0
  81. data/lib/troles/common/marshaller.rb +14 -0
  82. data/lib/troles/common/operations/read.rb +28 -0
  83. data/lib/troles/common/operations/write.rb +42 -0
  84. data/lib/troles/common/operations.rb +33 -0
  85. data/lib/troles/common/storage.rb +73 -0
  86. data/lib/troles/common.rb +17 -0
  87. data/lib/troles/config.rb +15 -0
  88. data/lib/troles/macros.rb +7 -0
  89. data/lib/troles/meta.rb +5 -0
  90. data/lib/troles/operations/read.rb +6 -0
  91. data/lib/troles/operations/write.rb +6 -0
  92. data/lib/troles/operations.rb +12 -0
  93. data/lib/troles/storage/base_many.rb +25 -0
  94. data/lib/troles/storage/bit_many.rb +56 -0
  95. data/lib/troles/storage/embed_many.rb +58 -0
  96. data/lib/troles/storage/ref_many.rb +44 -0
  97. data/lib/troles/storage/string_many.rb +41 -0
  98. data/lib/troles/storage.rb +13 -0
  99. data/lib/troles/strategy.rb +34 -0
  100. data/lib/troles.rb +11 -0
  101. data/playbox/old_rake +25 -0
  102. data/spec/Guide to running specs.textile +16 -0
  103. data/spec/active_record/migrations/many/bit_many.rb +16 -0
  104. data/spec/active_record/migrations/many/ref_many.rb +31 -0
  105. data/spec/active_record/migrations/many/string_many.rb +16 -0
  106. data/spec/active_record/migrations/one/bit_one.rb +14 -0
  107. data/spec/active_record/migrations/one/ref_one.rb +20 -0
  108. data/spec/active_record/migrations/one/string_one.rb +14 -0
  109. data/spec/active_record/models/ref_many.rb +10 -0
  110. data/spec/active_record/models/ref_one.rb +10 -0
  111. data/spec/active_record/models/role.rb +2 -0
  112. data/spec/active_record/models/user.rb +5 -0
  113. data/spec/active_record/models.rb +2 -0
  114. data/spec/active_record/strategies/many/bit_many_spec.rb +41 -0
  115. data/spec/active_record/strategies/many/ref_many_spec.rb +45 -0
  116. data/spec/active_record/strategies/many/string_many_spec.rb +39 -0
  117. data/spec/active_record/strategies/one/bit_one_spec.rb +35 -0
  118. data/spec/active_record/strategies/one/ref_one_spec.rb +41 -0
  119. data/spec/active_record/strategies/one/string_one_spec.rb +35 -0
  120. data/spec/active_record/strategy_helper.rb +4 -0
  121. data/spec/active_record_helper.rb +50 -0
  122. data/spec/db/database.yml +4 -0
  123. data/spec/dummy/Gemfile.lock +108 -0
  124. data/spec/dummy/Rakefile +7 -0
  125. data/spec/dummy/app/assets/images/rails.png +0 -0
  126. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  127. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  128. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  129. data/spec/dummy/app/controllers/main_controller.rb +16 -0
  130. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  131. data/spec/dummy/app/mailers/.gitkeep +0 -0
  132. data/spec/dummy/app/models/.gitkeep +0 -0
  133. data/spec/dummy/app/models/ref_many_user.rb +7 -0
  134. data/spec/dummy/app/models/ref_one_user.rb +3 -0
  135. data/spec/dummy/app/models/role.rb +4 -0
  136. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  137. data/spec/dummy/app/views/main/index.html.erb +3 -0
  138. data/spec/dummy/config/application.rb +54 -0
  139. data/spec/dummy/config/boot.rb +10 -0
  140. data/spec/dummy/config/database.yml +25 -0
  141. data/spec/dummy/config/environment.rb +5 -0
  142. data/spec/dummy/config/environments/development.rb +24 -0
  143. data/spec/dummy/config/environments/production.rb +52 -0
  144. data/spec/dummy/config/environments/test.rb +39 -0
  145. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  146. data/spec/dummy/config/initializers/inflections.rb +10 -0
  147. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  148. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  149. data/spec/dummy/config/initializers/session_store.rb +8 -0
  150. data/spec/dummy/config/initializers/troles.rb +3 -0
  151. data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
  152. data/spec/dummy/config/locales/en.yml +5 -0
  153. data/spec/dummy/config/routes.rb +60 -0
  154. data/spec/dummy/config.ru +4 -0
  155. data/spec/dummy/db/migrate/01_create_roles.rb +14 -0
  156. data/spec/dummy/db/migrate/02_create_ref_many_users.rb +20 -0
  157. data/spec/dummy/db/schema.rb +32 -0
  158. data/spec/dummy/db/seeds.rb +4 -0
  159. data/spec/dummy/log/.gitkeep +0 -0
  160. data/spec/dummy/public/404.html +26 -0
  161. data/spec/dummy/public/422.html +26 -0
  162. data/spec/dummy/public/500.html +26 -0
  163. data/spec/dummy/public/favicon.ico +0 -0
  164. data/spec/dummy/script/rails +6 -0
  165. data/spec/dummy_spec_helper.rb +33 -0
  166. data/spec/factories.rb +8 -0
  167. data/spec/generic/models/accounts/admin_account.rb +7 -0
  168. data/spec/generic/models/accounts/blogger_account.rb +7 -0
  169. data/spec/generic/models/accounts/user_account.rb +7 -0
  170. data/spec/generic/models/accounts.rb +1 -0
  171. data/spec/generic/models/base_user.rb +27 -0
  172. data/spec/generic/models/role.rb +37 -0
  173. data/spec/generic/models/user.rb +7 -0
  174. data/spec/generic/models.rb +3 -0
  175. data/spec/integration/navigation_spec.rb +9 -0
  176. data/spec/integration/troles/Running dummy tests.textile +35 -0
  177. data/spec/integration/troles/navigation_spec.rb +49 -0
  178. data/spec/mongoid/models/ref_many.rb +15 -0
  179. data/spec/mongoid/models/ref_one.rb +15 -0
  180. data/spec/mongoid/models/role.rb +5 -0
  181. data/spec/mongoid/models/user.rb +9 -0
  182. data/spec/mongoid/models.rb +2 -0
  183. data/spec/mongoid/strategies/many/bit_many_spec.rb +35 -0
  184. data/spec/mongoid/strategies/many/ref_many_spec.rb +35 -0
  185. data/spec/mongoid/strategies/many/string_many_spec.rb +30 -0
  186. data/spec/mongoid/strategies/one/bit_one_spec.rb +26 -0
  187. data/spec/mongoid/strategies/one/ref_one_spec.rb +31 -0
  188. data/spec/mongoid/strategies/one/string_one_spec.rb +26 -0
  189. data/spec/mongoid/strategy_helper.rb +4 -0
  190. data/spec/mongoid_helper.rb +19 -0
  191. data/spec/playbox/rspec_examples.rb +381 -0
  192. data/spec/support/shared_examples.rb +1 -0
  193. data/spec/trole/Trole Design.textile +4 -0
  194. data/spec/trole/api/cache_api_spec.rb +2 -0
  195. data/spec/trole/api/core_api_spec.rb +4 -0
  196. data/spec/trole/api/event_api.rb +2 -0
  197. data/spec/trole/api/operations_api_spec.rb +2 -0
  198. data/spec/trole/api/read_api_spec.rb +5 -0
  199. data/spec/trole/api/validation_api_spec.rb +2 -0
  200. data/spec/trole/api/write_api_spec.rb +2 -0
  201. data/spec/trole/api_spec.rb +60 -0
  202. data/spec/trole/multi_roles_spec.rb +163 -0
  203. data/spec/trole/operations/read_spec.rb +18 -0
  204. data/spec/trole/operations/write_spec.rb +0 -0
  205. data/spec/trole/playbox/shared_examples.rb +107 -0
  206. data/spec/trole/strategies/bit_one_spec.rb +22 -0
  207. data/spec/trole/strategies/embed_one_spec.rb +32 -0
  208. data/spec/trole/strategies/ref_one_spec.rb +29 -0
  209. data/spec/trole/strategies/string_one_spec.rb +26 -0
  210. data/spec/trole/strategy_helper.rb +3 -0
  211. data/spec/trole/two_roles_spec.rb +76 -0
  212. data/spec/trole_spec.rb +12 -0
  213. data/spec/trole_spec_helper.rb +20 -0
  214. data/spec/troles/api/cache_api_spec.rb +2 -0
  215. data/spec/troles/api/core_api_spec.rb +4 -0
  216. data/spec/troles/api/event_api.rb +2 -0
  217. data/spec/troles/api/read_api_spec.rb +2 -0
  218. data/spec/troles/api/validation_api_spec.rb +2 -0
  219. data/spec/troles/api/write_api_spec.rb +2 -0
  220. data/spec/troles/api_spec.rb +41 -0
  221. data/spec/troles/common/api/cache_api_spec.rb +31 -0
  222. data/spec/troles/common/api/config_api.rb +0 -0
  223. data/spec/troles/common/api/core_api_spec.rb +14 -0
  224. data/spec/troles/common/api/event_api_spec.rb +9 -0
  225. data/spec/troles/common/api/operations_api_spec.rb +55 -0
  226. data/spec/troles/common/api/read_api_spec.rb +23 -0
  227. data/spec/troles/common/api/validation_api_spec.rb +46 -0
  228. data/spec/troles/common/api/write_api_spec.rb +81 -0
  229. data/spec/troles/common/api_spec.rb +101 -0
  230. data/spec/troles/common/config_spec.rb +11 -0
  231. data/spec/troles/common/multi_roles_spec.rb +142 -0
  232. data/spec/troles/marshaller/bitmask_spec.rb +14 -0
  233. data/spec/troles/operations/read_ops_spec.rb +0 -0
  234. data/spec/troles/operations/write_ops_spec.rb +0 -0
  235. data/spec/troles/playbox/shared_examples.rb +68 -0
  236. data/spec/troles/strategies/bit_many_spec.rb +30 -0
  237. data/spec/troles/strategies/embed_many_spec.rb +35 -0
  238. data/spec/troles/strategies/ref_many_spec.rb +36 -0
  239. data/spec/troles/strategies/string_many_spec.rb +32 -0
  240. data/spec/troles/strategy_helper.rb +3 -0
  241. data/spec/troles_spec.rb +10 -0
  242. data/troles.gemspec +325 -0
  243. metadata +469 -0
@@ -0,0 +1,95 @@
1
+ module Troles::Common
2
+ class Config
3
+ module SchemaHelpers
4
+ def valid_field_name? name
5
+ return false if !name || name.empty?
6
+ raise ArgumentException, "Role field must not be named role or roles as these names are reserved by troles!" if [:role, :roles].include? name.to_sym
7
+ true
8
+ end
9
+
10
+ def boolean? value
11
+ [true, false].include? value
12
+ end
13
+
14
+ # TODO: Needs extraction into helper module!
15
+
16
+ def belongs_to_for from, to, options = {}
17
+ make_relationship :belongs_to, from, to, options
18
+ end
19
+
20
+ def has_many_for from, to, options = {}
21
+ make_relationship :has_many, from, to, options
22
+ end
23
+
24
+ def has_one_for from, to, options = {}
25
+ make_relationship :has_one, from, to, options
26
+ end
27
+
28
+ # To setup sth like this:
29
+ #
30
+ # class UserAccount < ActiveRecord::Base
31
+ # has_and_belongs_to_many :troles, :class_name => 'Role'
32
+ # end
33
+ #
34
+ # class Role < ActiveRecord::Base
35
+ # has_and_belongs_to_many :user_accounts, :class_name => 'User'
36
+ # end
37
+ def has_and_belongs_many from, to, options = {}
38
+ make_relationship :has_and_belongs_to_many, from, to, :key => role_field
39
+ make_relationship :has_and_belongs_to_many, to, from, options
40
+ end
41
+
42
+ def get_model_type class_name
43
+ return :user if class_name == clazz
44
+ return :role if class_name == role_model
45
+ raise "Not a known model: #{class_name}"
46
+ end
47
+
48
+ # options:
49
+ # - :opts, extras options, fx to set the :through relationship
50
+ # - :key (usually to enforce use of role_field as key name)
51
+ def make_relationship type, from, to, options = {}
52
+ # puts "type: #{type}, #{from}, #{to}"
53
+ from_type = get_model_type from
54
+ to_type = get_model_type to
55
+
56
+ model_key = options[:key] ? options[:key] : send("#{from_type}_key")
57
+
58
+ class_name = send "#{to_type}_class_name"
59
+
60
+ options = {:class_name => class_name}
61
+ options.merge!(options[:opts]) if options[:opts]
62
+ puts "#{from}.#{type} :#{model_key}, #{options.inspect}" if log_on?
63
+ from.send(type, model_key, options)
64
+ end
65
+
66
+ def user_class_name
67
+ clazz.to_s
68
+ end
69
+
70
+ def user_key
71
+ make_key user_class_name
72
+ end
73
+
74
+ def join_class_name
75
+ join_model.to_s
76
+ end
77
+
78
+ def join_key
79
+ make_key join_class_name
80
+ end
81
+
82
+ def role_class_name
83
+ role_model.to_s
84
+ end
85
+
86
+ def role_key
87
+ make_key role_class_name
88
+ end
89
+
90
+ def make_key name
91
+ name.gsub(/::/, '__').underscore.pluralize
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,14 @@
1
+ module Troles::Common
2
+ class Config
3
+ module StaticRoles
4
+ def static_roles_for_class= value
5
+ raise ArgumentError, "Must be a boolean" if !boolean?(value)
6
+ @static_roles_for_class = value
7
+ end
8
+
9
+ def static_roles_for_class?
10
+ @static_roles_for_class || false
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module Troles::Common
2
+ class Config
3
+ module ValidRoles
4
+ def add_valid_roles *roles
5
+ valid_roles =valid_roles & roles
6
+ end
7
+
8
+ def valid_roles= *roles
9
+ vrs = roles.flatten.map{|r| r.to_s.alpha_numeric}.map(&:to_sym).uniq
10
+ raise ArgumentError, "The #{strategy} strategy can only accept 2 valid roles" if (vrs.size > 2) && strategy == :bit_one
11
+ raise ArgumentError, "The role names you want to be valid are not valid role names. Must be alphanumeric, was: #{roles.flatten}" if vrs.empty?
12
+ @valid_roles ||= vrs
13
+ end
14
+
15
+ def valid_roles
16
+ raise "No valid roles defined" if !@valid_roles || @valid_roles.empty?
17
+ @valid_roles
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,96 @@
1
+ module Troles::Common
2
+ class Config
3
+ autoload :ValidRoles, 'troles/common/config/valid_roles'
4
+ autoload :StaticRoles, 'troles/common/config/static_roles'
5
+ autoload :Schema, 'troles/common/config/schema'
6
+ autoload :SchemaHelpers, 'troles/common/config/schema_helpers'
7
+
8
+ def self.sub_modules
9
+ [:valid_roles, :static_roles, :schema]
10
+ end
11
+
12
+ sub_modules.each do |name|
13
+ send :include, "Troles::Common::Config::#{name.to_s.camelize}".constantize
14
+ end
15
+
16
+ attr_accessor :clazz, :strategy, :log_on, :generic
17
+ attr_writer :orm
18
+
19
+ def initialize clazz, options = {}
20
+ @clazz = clazz
21
+ # set instance var for each pair in options
22
+ apply_options! options
23
+ end
24
+
25
+ class << self
26
+ attr_reader :default_orm, :auto_load
27
+ attr_accessor :log_on
28
+
29
+ def log_on?
30
+ log_on || false
31
+ end
32
+
33
+ def default_orm= orm
34
+ @default_orm ||= orm
35
+ end
36
+
37
+ def auto_load= mode
38
+ raise "Autoload must be set to true or false" if ![true, false].include? mode
39
+ @auto_load = mode
40
+ end
41
+
42
+ def auto_load?
43
+ @auto_load
44
+ end
45
+ end
46
+
47
+ def log_on?
48
+ log_on || Troles::Config.log_on
49
+ end
50
+
51
+ def role_field
52
+ @role_field ||= begin
53
+ default_role_field
54
+ end
55
+ end
56
+
57
+ def role_field= field_name
58
+ name = field_name.to_s.alpha_numeric.to_sym
59
+ raise ArgumentException, "Not a valid role field name: #{field_name}" if !valid_field_name?(name)
60
+ @role_field ||= name
61
+ end
62
+
63
+ def default_role_field
64
+ singularity == :many ? :troles : :trole
65
+ end
66
+
67
+ def orm
68
+ @orm || self.class.default_orm
69
+ end
70
+
71
+ def apply_options! options = {}
72
+ options.each_pair do |key, value|
73
+ send("#{key}=", value) if self.respond_to?(:"#{key}")
74
+ end
75
+ end
76
+
77
+ def singularity
78
+ @singularity ||= (strategy =~ /_many$/) ? :many : :one
79
+ end
80
+
81
+ # def singularity= value
82
+ # raise ArgumentError, "Must be :many or :one" if ![:one, :many].include?(value)
83
+ # @singularity ||= value
84
+ # end
85
+
86
+ def configure! options = {}
87
+ apply_options! options
88
+ configure_role_field
89
+ end
90
+
91
+ def generic?
92
+ return true if orm.nil?
93
+ @generic.nil? ? false : @generic
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,9 @@
1
+ require 'sugar-high/kind_of'
2
+ require 'sugar-high/string'
3
+ require 'sugar-high/array'
4
+ require 'sugar-high/class_ext'
5
+ require 'active_support/inflector'
6
+ require 'troles/meta'
7
+
8
+
9
+
@@ -0,0 +1,40 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Handles event handlinm/publication for when the roles of a role subject change
5
+ # This is currently a singleton (class methods only) by design
6
+ #
7
+ module Troles::Common
8
+ module EventManager
9
+ def self.included(base)
10
+ base.extend ClassMethods
11
+ end
12
+
13
+ # TODO:
14
+ module ClassMethods
15
+ attr_accessor :subscribers
16
+
17
+ def subscribers
18
+ @subscribers ||= []
19
+ end
20
+
21
+ def publish_change event, options
22
+ # from = options[:from]
23
+ subscribers.each do |subscriber|
24
+ subscriber.notify(event) if subscriber.respond_to?(:notify)
25
+ end
26
+ true
27
+ end
28
+
29
+ def add_subscribers subscribers
30
+ self.subscribers << subscribers
31
+ end
32
+
33
+ def remove_subscribers subscribers
34
+ self.subscribers - subscribers
35
+ end
36
+ end
37
+
38
+ extend ClassMethods
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ module Troles::Macros
2
+ class Configuration
3
+ class BaseLoader
4
+ attr_reader :strategy, :orm
5
+
6
+ def initialize strategy, orm
7
+ @strategy = strategy
8
+ @orm = orm || Troles::Config.default_orm
9
+ end
10
+
11
+ def singularity
12
+ (strategy =~ /_many$/) ? :many : :one
13
+ end
14
+
15
+ def try_module full_name
16
+ begin
17
+ full_name.constantize
18
+ true
19
+ rescue
20
+ # puts "module #{full_name} not found!"
21
+ false
22
+ end
23
+ end
24
+
25
+ def base_class
26
+ "Base#{singularity.to_s.camelize}"
27
+ end
28
+
29
+ def namespace
30
+ singularity == :many ? 'Troles' : 'Trole'
31
+ end
32
+
33
+ def orm_namespace
34
+ ns = namespace
35
+ ns << "::#{orm.to_s.camelize}" if orm
36
+ ns
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ module Troles::Macros
2
+ class Configuration
3
+ class ConfigLoader < BaseLoader
4
+
5
+ def initialize strategy, orm
6
+ super
7
+ end
8
+
9
+ def config_class
10
+ begin
11
+ "#{orm_namespace}::Config".constantize
12
+ rescue
13
+ # use generic if no ORM specific strategy found!
14
+ "#{namespace}::Config".constantize
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module Troles::Macros
2
+ class Configuration
3
+ class StorageLoader < BaseLoader
4
+
5
+ def initialize strategy, orm
6
+ super
7
+ end
8
+
9
+ def storage_class
10
+ begin
11
+ "#{orm_namespace}::Storage::#{strategy.to_s.camelize}".constantize
12
+ rescue
13
+ # use generic if no ORM specific strategy found!
14
+ "#{namespace}::Storage::#{strategy.to_s.camelize}".constantize
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,38 @@
1
+ module Troles::Macros
2
+ class Configuration
3
+ class StrategyLoader < BaseLoader
4
+
5
+ def initialize strategy, orm
6
+ super
7
+ end
8
+
9
+ def strategy_module
10
+ @strategy_module ||= orm_strategy_module || generic_strategy_module
11
+ end
12
+
13
+ protected
14
+
15
+ def orm_strategy_module
16
+ @orm_strategy_module ||= begin
17
+ mods_found = ["#{orm_namespace}::Strategy::#{strategy.to_s.camelize}", "#{namespace}::Strategy::#{base_class}"].select do |full_name|
18
+ try_module(full_name)
19
+ end
20
+ !mods_found.empty? ? mods_found.first.constantize : nil
21
+ end
22
+ end
23
+
24
+ def generic_strategy_module strategy_name, options
25
+ @generic_module ||= begin
26
+ base_class = base_name(strategy_name)
27
+
28
+ # use generic if no ORM specific strategy found!
29
+ ns = namespace(strategy_name, options)
30
+ mods_found = ["#{namespace}::Strategy::#{strategy.to_s.camelize}", "#{namespace}::Strategy::#{base_class}"].select do |full_name|
31
+ try_module(full_name)
32
+ end
33
+ !mods_found.empty? ? mods_found.first.constantize : nil
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,89 @@
1
+ module Troles
2
+ module Macros
3
+ class Configuration
4
+ autoload :BaseLoader, 'troles/common/macros/configuration/base_loader'
5
+ autoload :ConfigLoader, 'troles/common/macros/configuration/config_loader'
6
+ autoload :StrategyLoader, 'troles/common/macros/configuration/strategy_loader'
7
+ autoload :StorageLoader, 'troles/common/macros/configuration/storage_loader'
8
+
9
+ attr_reader :strategy, :singularity, :orm, :auto_load, :options, :role_subject_class
10
+
11
+ def initialize role_subject_class, strategy, options = {}
12
+ @role_subject_class = role_subject_class
13
+ @strategy = strategy
14
+ @orm = options[:orm] || Troles::Config.default_orm
15
+ @auto_load = options[:auto_load] || Troles::Config.auto_load?
16
+ options[:strategy] = strategy
17
+ @options = options
18
+ end
19
+
20
+ def strategy_module
21
+ strategy_loader.strategy_module
22
+ end
23
+
24
+ def load_adapter
25
+ return false if !auto_load?
26
+
27
+ path = "#{namespace}/adapters/#{orm.to_s.underscore}"
28
+ begin
29
+ require path
30
+ rescue
31
+ raise "Adapter for :#{orm} could not be found at: #{path}"
32
+ end
33
+ end
34
+
35
+ def apply_strategy_options!
36
+ role_subject_class.troles_config.apply_options! options
37
+
38
+ # StrategyOptions.new(clazz)
39
+ # extract_macros(options).each{|m| apply_macro m}
40
+ end
41
+
42
+ def define_hooks
43
+ storage_class = storage_loader.storage_class
44
+ role_subject_class.send :define_method, :storage do
45
+ @storage ||= storage_class
46
+ end
47
+
48
+ config_class = config_loader.config_class
49
+ puts "config_class: #{config_class}" if Troles::Config.log_on
50
+ role_subject_class.singleton_class.class_eval %{
51
+ def troles_config
52
+ @troles_config ||= #{config_class}.new #{role_subject_class}, #{options.inspect}
53
+ end
54
+ }
55
+ end
56
+
57
+ protected
58
+
59
+ def namespace
60
+ singularity == :many ? 'troles' : 'trole'
61
+ end
62
+
63
+ def singularity
64
+ @singularity ||= (strategy =~ /_many$/) ? :many : :one
65
+ end
66
+
67
+ def storage_loader
68
+ @storage_loader ||= StorageLoader.new strategy, orm
69
+ end
70
+
71
+ def config_loader
72
+ @config_loader ||= ConfigLoader.new strategy, orm
73
+ end
74
+
75
+ def strategy_loader
76
+ @strategy_loader ||= StrategyLoader.new strategy, orm
77
+ end
78
+
79
+
80
+ def auto_load?
81
+ (auto_load && orm) || false
82
+ end
83
+
84
+ # def extract_macros options = {}
85
+ # [:static_role].select {|o| options[o]}
86
+ # end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,9 @@
1
+ module Troles
2
+ module Macros
3
+ module StaticRoles
4
+ def static_roles?
5
+ true
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module Troles
2
+ module Macros
3
+ class StrategyOptions
4
+ attr_reader :clazz
5
+
6
+ def initialize clazz
7
+ @clazz = clazz
8
+ end
9
+
10
+ # @param [Symbol] name of the macro to run
11
+ def apply_macro name
12
+ # overrides default method that returns false
13
+ begin
14
+ clazz.send :include, "Troles::Macros::#{strategy_name.to_s.camelize}".constantize
15
+ rescue
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,38 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Macros that can be used directly on the role subject class
5
+ # These methods are added to the ruby core 'Module' module
6
+ #
7
+ # Usage:
8
+ # class User
9
+ # troles_strategy :bit_many
10
+ #
11
+
12
+ puts "Troles macros enabled!"
13
+
14
+ module Troles
15
+ module Macros
16
+ autoload :Configuration, 'troles/common/macros/configuration'
17
+
18
+ def troles_strategy strategy, options = {}, &block
19
+ configuration = Configuration.new self, strategy, options
20
+
21
+ configuration.load_adapter
22
+ # puts "strategy module: #{configuration.strategy_module}"
23
+ send :include, configuration.strategy_module
24
+
25
+ configuration.define_hooks
26
+ configuration.apply_strategy_options!
27
+
28
+ if strategy == :bit_one
29
+ troles_config.valid_roles = [:user, :admin] # default binary roles
30
+ end
31
+
32
+ yield troles_config if block_given?
33
+ troles_config
34
+ end
35
+ end
36
+ end
37
+
38
+ Module.send :include, Troles::Macros
@@ -0,0 +1,43 @@
1
+ # require 'troles/common/marshaller/generic'
2
+
3
+ module Troles::Common
4
+ module Marshaller
5
+ class Bitmask < Generic
6
+ attr_reader :role_subject, :valid_roles
7
+
8
+ def initialize role_subject
9
+ super
10
+ end
11
+
12
+ def read
13
+ valid_roles.reject do |r|
14
+ num = as_number(ds_field_value)
15
+ ((num || 0) & calc_index(r)).zero?
16
+ end
17
+ end
18
+
19
+ def write *roles
20
+ roles = roles.uniq.compact
21
+ return as_number(false) if roles.empty?
22
+ roles.to_symbols.map { |r| calc_index(r) }.inject { |sum, bitvalue| sum + bitvalue }
23
+ end
24
+
25
+ protected
26
+
27
+ def as_number value
28
+ case value
29
+ when TrueClass, FalseClass
30
+ value ? 2 : 1
31
+ when Fixnum
32
+ value
33
+ else
34
+ raise ArgumentError, "Cant be converted to a bit index, #{value}"
35
+ end
36
+ end
37
+
38
+ def calc_index(r)
39
+ 2**valid_roles.index(r)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ module Troles::Common
2
+ module Marshaller
3
+ class Generic
4
+ attr_reader :role_subject, :valid_roles
5
+
6
+ def initialize role_subject
7
+ raise "The roles subject is not valid: #{role_subject}" if !role_subject || !role_subject.respond_to?(:has_role?)
8
+ @role_subject = role_subject
9
+ @valid_roles = role_subject.class.valid_roles
10
+ end
11
+
12
+ protected
13
+
14
+ def ds_field_value
15
+ role_subject.send ds_field_name
16
+ end
17
+
18
+ def ds_field_name
19
+ @ds_field_name ||= role_subject.class.role_field
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,14 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Marshallers can be used by Storages to handle conversion from
5
+ # between a role list of symbols and the data format stored in the datastore
6
+ # One example is the Bitmask marshaller, which converts between an Integer and a role list
7
+ # One could imagine other custom marshallers, such as using encrypted strings etc.
8
+ #
9
+ module Troles::Common
10
+ module Marshaller
11
+ autoload :Generic, 'troles/common/marshaller/generic'
12
+ autoload :Bitmask, 'troles/common/marshaller/bitmask'
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ module Troles::Common
2
+ class Operations
3
+ module Read
4
+ # The roles list of the role subject
5
+ # @return [Array<Symbol>] the list of roles
6
+ def list
7
+ role_subject.role_list
8
+ end
9
+
10
+ # Test if the role subject has exactly the given roles
11
+ # @param [Array<Symbol>] role list to test
12
+ # @return [true, false] true if role subject has exactly those roles, false otherwise
13
+ def has? *roles
14
+ list == roles.to_symbols_uniq
15
+ end
16
+
17
+ # Which of the given roles are used by the role subject
18
+ # @param [Array<Symbol>] roles to test for inclusion
19
+ #
20
+ # Usage:
21
+ # - user.roles.used(:admin, :editor).include? :editor
22
+ #
23
+ def used *roles
24
+ list & roles.to_symbols_uniq
25
+ end
26
+ end
27
+ end
28
+ end