troles 0.5.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 (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