domain_neutral 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +37 -0
  4. data/app/models/domain_neutral/descriptor.rb +55 -0
  5. data/config/routes.rb +2 -0
  6. data/db/migrate/20160531124022_create_domain_neutral_descriptors.rb +20 -0
  7. data/lib/domain_neutral/association.rb +21 -0
  8. data/lib/domain_neutral/engine.rb +5 -0
  9. data/lib/domain_neutral/railtie.rb +24 -0
  10. data/lib/domain_neutral/seed.rb +8 -0
  11. data/lib/domain_neutral/seeder/descriptors.rb +195 -0
  12. data/lib/domain_neutral/symbolized_class.rb +170 -0
  13. data/lib/domain_neutral/version.rb +3 -0
  14. data/lib/domain_neutral.rb +18 -0
  15. data/lib/tasks/domain_neutral_tasks.rake +10 -0
  16. data/test/domain_neutral/symbolized_class_test.rb +162 -0
  17. data/test/domain_neutral_test.rb +7 -0
  18. data/test/dummy/README.rdoc +28 -0
  19. data/test/dummy/Rakefile +6 -0
  20. data/test/dummy/app/assets/javascripts/application.js +13 -0
  21. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  22. data/test/dummy/app/controllers/application_controller.rb +5 -0
  23. data/test/dummy/app/helpers/application_helper.rb +2 -0
  24. data/test/dummy/app/models/role.rb +2 -0
  25. data/test/dummy/app/models/user.rb +3 -0
  26. data/test/dummy/app/views/layouts/application.html.erb +13 -0
  27. data/test/dummy/bin/bundle +3 -0
  28. data/test/dummy/bin/rails +4 -0
  29. data/test/dummy/bin/rake +4 -0
  30. data/test/dummy/bin/setup +29 -0
  31. data/test/dummy/config/application.rb +33 -0
  32. data/test/dummy/config/boot.rb +5 -0
  33. data/test/dummy/config/database.yml +25 -0
  34. data/test/dummy/config/environment.rb +5 -0
  35. data/test/dummy/config/environments/development.rb +41 -0
  36. data/test/dummy/config/environments/production.rb +79 -0
  37. data/test/dummy/config/environments/test.rb +44 -0
  38. data/test/dummy/config/initializers/assets.rb +11 -0
  39. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  40. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  41. data/test/dummy/config/initializers/domain_neutral.rb +5 -0
  42. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  43. data/test/dummy/config/initializers/inflections.rb +16 -0
  44. data/test/dummy/config/initializers/mime_types.rb +4 -0
  45. data/test/dummy/config/initializers/session_store.rb +3 -0
  46. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  47. data/test/dummy/config/locales/en.yml +13 -0
  48. data/test/dummy/config/locales/nb.yml +9 -0
  49. data/test/dummy/config/routes.rb +56 -0
  50. data/test/dummy/config/secrets.yml +22 -0
  51. data/test/dummy/config.ru +4 -0
  52. data/test/dummy/db/development.sqlite3 +0 -0
  53. data/test/dummy/db/migrate/20160601072742_create_domain_neutral_descriptors.domain_neutral.rb +21 -0
  54. data/test/dummy/db/migrate/20160607100350_create_users.rb +10 -0
  55. data/test/dummy/db/schema.rb +42 -0
  56. data/test/dummy/db/test.sqlite3 +0 -0
  57. data/test/dummy/log/development.log +350 -0
  58. data/test/dummy/log/test.log +5133 -0
  59. data/test/dummy/public/404.html +67 -0
  60. data/test/dummy/public/422.html +67 -0
  61. data/test/dummy/public/500.html +66 -0
  62. data/test/dummy/public/favicon.ico +0 -0
  63. data/test/dummy/tmp/cache/36E/B10/Role%2Fmap +1 -0
  64. data/test/dummy/tmp/cache/657/A10/Role%2Fuser_admin +1 -0
  65. data/test/fixtures/domain_neutral/descriptors.yml +14 -0
  66. data/test/fixtures/users.yml +9 -0
  67. data/test/integration/navigation_test.rb +8 -0
  68. data/test/models/domain_neutral/descriptor_test.rb +111 -0
  69. data/test/test_helper.rb +22 -0
  70. data/test/test_helpers/caching.rb +57 -0
  71. metadata +198 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 54827517aef3ef85bc7fc7611cc8e6e8eb2ca76d
4
+ data.tar.gz: 4daf91bc5ef08666fb404936acf55b862392a444
5
+ SHA512:
6
+ metadata.gz: 8a63fe76ae198a714472a9abb3414000ef66f9243369b8095c483ac0c70a4cf3f0b4fdc65a795a0d198027eb2390622a3a6b1a88a2d9a57d7ca9f1642309b8f3
7
+ data.tar.gz: f83b2574943c1a25f9abb0efcb74c8b1ad8c3b44b55cbfdf8d43f57eba69a9134348f354a4b30a99df93e131adc1281dcc00bfc4167eda3a4ea5dea29d61c0b4
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 knut
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'DomainNeutral'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,55 @@
1
+ #require 'descriptor_model/symbolized_class'
2
+ module DomainNeutral
3
+ class Descriptor < ActiveRecord::Base
4
+ include SymbolizedClass
5
+ include Comparable
6
+ # Enable caching by default
7
+
8
+ belongs_to :parent, :polymorphic => true
9
+ validates_presence_of :name, :symbol
10
+ validates_uniqueness_of :symbol, scope: :type
11
+
12
+ class << self
13
+ def symbols
14
+ @symbols ||= begin
15
+ # ensure that we really have some items stored. This method may be called before fixtures are loaded in test environment
16
+ s = all.map(&:symbol)
17
+ s.size.zero? ? nil : s
18
+ end
19
+ end
20
+ end
21
+
22
+ def <=>(other)
23
+ index <=> other.index
24
+ end
25
+
26
+ def ==(other)
27
+ self.class == other.class && symbol == other.symbol
28
+ end
29
+
30
+ def !=(other)
31
+ self.class == other.class && symbol != other.symbol
32
+ end
33
+
34
+ def to_i
35
+ id
36
+ end
37
+
38
+ def name
39
+ t :name
40
+ end
41
+
42
+ def description
43
+ t :description
44
+ end
45
+
46
+ protected
47
+ def i18n_scope
48
+ @i18n_scope ||= [:descriptors, self.class.to_s.underscore, to_sym ]
49
+ end
50
+
51
+ def t(attribute)
52
+ I18n.t( attribute, scope: i18n_scope, default: self[attribute] || '') # || '' here is used to fix validation
53
+ end
54
+ end
55
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,20 @@
1
+ class CreateDomainNeutralDescriptors < ActiveRecord::Migration
2
+ def change
3
+ table_name = DomainNeutral::Descriptor.table_name
4
+ create_table table_name, :force => true do |t|
5
+ t.string "type"
6
+ t.string "parent_type"
7
+ t.integer "parent_id"
8
+ t.string "symbol"
9
+ t.string "name"
10
+ t.text "description"
11
+ t.integer "index"
12
+ t.integer "value"
13
+ t.timestamps null: false
14
+ end
15
+
16
+ add_index table_name, ["type", "symbol"], name: "index_#{table_name}_on_type_and_symbol"
17
+ add_index table_name, ["type", "index"], name: "index_#{table_name}_on_type_and_index"
18
+ add_index table_name, ["parent_type", "parent_id"], name: "index_#{table_name}_on_parent_type_and_parent_id"
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module DomainNeutral
2
+ module Association
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def has_descriptor(name, options = {})
7
+ # TODO: add delegate method
8
+ belongs_to name, options
9
+ r = reflect_on_association(name)
10
+ class_eval <<-CODE, __FILE__, __LINE__
11
+ def #{name}
12
+ #{r.klass}.find(#{r.foreign_key})
13
+ end
14
+ CODE
15
+ end
16
+ end
17
+ end
18
+ end
19
+ class ActiveRecord::Base
20
+ include DomainNeutral::Association
21
+ end
@@ -0,0 +1,5 @@
1
+ module DomainNeutral
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace DomainNeutral
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ require "rails"
2
+
3
+ module DomainNeutral
4
+ # = Domain Neutral Railtie
5
+ class Railtie < Rails::Railtie
6
+ config.domain_neutral = ActiveSupport::OrderedOptions.new
7
+ config.domain_neutral.seed = ActiveSupport::OrderedOptions.new
8
+
9
+
10
+ config.domain_neutral.table_prefix = 'domain_neutral' # Table prefix
11
+ config.domain_neutral.cache = true # Use cache
12
+ config.domain_neutral.seed.master_locale = :en # Default master data locale. Language used for seeding
13
+ config.domain_neutral.seed.locale_alternatives = [] # Alternative locale data. These will be parsed and checked for consistency with the master
14
+ config.domain_neutral.seed.verbose = true # Display progress when seeding
15
+ config.domain_neutral.seed.create_fixtures = true # Create fixtures from master file
16
+
17
+ initializer 'domain_neutral.configure' do |app|
18
+ DomainNeutral::Descriptor.table_name = app.config.domain_neutral.table_prefix.blank? ?
19
+ 'descriptors' : "#{app.config.domain_neutral.prefix}_#{table_name}"
20
+ DomainNeutral::Descriptor.caching_enabled = app.config.domain_neutral.cache
21
+ DomainNeutral.seed_options = config.domain_neutral.seed
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ require 'domain_neutral/seeder/descriptors'
2
+ module DomainNeutral
3
+ class Seed
4
+ def descriptors(callee)
5
+ Seeder::Descriptors.seed(callee)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,195 @@
1
+ # Seeds descriptors from yml file, using norwegian as default
2
+ module DomainNeutral
3
+ module Seeder
4
+ class Descriptors
5
+ def self.seed(context)
6
+ seeder = new(context)
7
+ seeder.setup
8
+ seeder.load_master_data
9
+ seeder.validate_master
10
+ seeder.validate_locale_alternatives
11
+ seeder.create_fixtures_file
12
+ seeder.seed_parents
13
+ seeder.seed_everything_else
14
+ end
15
+
16
+ def initialize(context)
17
+ @context = context
18
+ end
19
+
20
+ def seed_options
21
+ DomainNeutral.seed_options
22
+ end
23
+
24
+ delegate :verbose, :master_locale, :locale_alternatives, :create_fixtures, to: :seed_options
25
+
26
+ def setup
27
+ if DomainNeutral.rails_generation < 4
28
+ Descriptor.attr_accessible :name, :description, :index, :externalid, :parent, :value
29
+ end
30
+ Descriptor.enable_caching false
31
+ end
32
+
33
+ attr_reader :master
34
+
35
+ # Load master descriptors from yaml file
36
+ def load_master_data
37
+ #@master = load_yaml(DomainNeutral.master_locale, :master)
38
+ @master = load_yaml(master_locale, :master)
39
+ end
40
+
41
+ def seed_parents
42
+ # Collect parents
43
+ log "Collect parents"
44
+ parents = []
45
+ master.each do |descriptor_set, descriptors|
46
+ parents << descriptors[:parent] if descriptors[:parent]
47
+ end
48
+ log "Parents collected: #{parents.inspect}"
49
+ # Seed parents
50
+ return if parents.empty?
51
+ log "Seed parents"
52
+ parents.map { |p| p.split('.')[0].underscore }.uniq.each do |parent|
53
+ klass = parent.classify.constantize
54
+ # Create only objects of Descriptor class
55
+ if klass.new.is_a?( Descriptor) && section = master.delete(parent)
56
+ seed_descriptor_set parent, section
57
+ end
58
+ end
59
+ end
60
+
61
+ def seed_everything_else
62
+ # seed rest
63
+ master.each do |descriptor_set, descriptors|
64
+ seed_descriptor_set descriptor_set, descriptors
65
+ end
66
+ end
67
+
68
+ # Validate descriptors in master yaml file
69
+ def validate_master
70
+ log 'Validating master locale file'
71
+ undefined = []
72
+ master.each do |descriptor_set, descriptors|
73
+ descriptors.reject { |k,v| k == 'parent' }.each do |symbol, descriptor|
74
+ unless descriptor[:name]
75
+ undefined << "Name not defined for #{descriptor_set}"
76
+ end
77
+ end
78
+ end
79
+ abort undefined if undefined.size > 0
80
+ end
81
+
82
+ def validate_locale_alternatives
83
+ undefined = []
84
+ #DomainNeutral.locale_alternatives.each do |locale|
85
+ locale_alternatives.each do |locale|
86
+ log "Validating alternative locale file: #{locale}"
87
+ loc_descriptors = load_yaml(locale, 'locale_alternative')
88
+ master.each do |descriptor_set, descriptors|
89
+ unless loc_descriptors[descriptor_set]
90
+ undefined << "Locale: #{locale}. Keys not defined for '#{descriptor_set}'"
91
+ next
92
+ end
93
+ descriptors.keys.reject{ |k| k == 'parent' }.each do |descriptor|
94
+ unless loc_descriptors[descriptor_set][descriptor]
95
+ undefined << "Locale: #{locale}. Key not defined for '#{descriptor}' in '#{descriptor_set}'"
96
+ next
97
+ end
98
+ %w(name description).each do |key|
99
+ if descriptors[descriptor][key] && !loc_descriptors[descriptor_set][descriptor][key]
100
+ undefined << "Locale: #{locale}. Attribute '#{key}' not defined for '#{descriptor}' in '#{descriptor_set}'"
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ abort undefined if undefined.size > 0
107
+ end
108
+
109
+ def create_fixtures_file
110
+ return unless create_fixtures
111
+ fixtures = {}
112
+ master.each do |descriptor_set, descriptors|
113
+ base = {type: descriptor_set.classify}
114
+ if parent = descriptors[:parent]
115
+ abort "Parent for fixtures not yet implemented.", descriptors.inspect
116
+ base[:parent] = parent
117
+ end
118
+ descriptors.reject { |k,v| k == 'parent' }.each do |symbol, descriptor|
119
+ fixtures["#{descriptor_set}_#{symbol}"] = descriptor.merge(base.merge(symbol: symbol)).to_hash
120
+ end
121
+ end
122
+ path = fixtures_path.join('domain_neutral', 'descriptors.yml')
123
+ FileUtils.mkdir_p path.dirname
124
+ File.open(path, 'w') do |f|
125
+ f.write fixtures.to_yaml
126
+ end
127
+ log "Seeders file created (#{path}):"
128
+ end
129
+
130
+ private
131
+ def load_yaml(locale, type)
132
+ file = locate_locale_file(locale, type)
133
+ yml = HashWithIndifferentAccess.new YAML.load_file(file.to_s)
134
+ yml[locale.to_sym][:descriptors]
135
+ end
136
+
137
+ def locate_locale_file(locale, type)
138
+ alternative_locations = [
139
+ Rails.root.join('config', 'locales', locale.to_s, "descriptors.yml"),
140
+ Rails.root.join('config', 'locales', "#{locale}.descriptors.yml"),
141
+ Rails.root.join('config', 'locales', "#{locale}.yml"),
142
+ Rails.root.join('config', 'locales', "descriptors.yml")
143
+ ]
144
+ unless file = alternative_locations.select { |fname| fname.exist? }.first
145
+ abort "Could not load #{type} file for descriptors. Expected to find any of the following files:\n" +
146
+ alternative_locations.map { |fname| "\t'#{fname}'" }.join("\n")
147
+ end
148
+ file
149
+ end
150
+
151
+ def seed_descriptor_set(descriptor_set, descriptors, default_parent = nil)
152
+ log "seed_descriptor_set: #{descriptor_set.inspect}, descriptors: #{descriptors.inspect}"
153
+ klass = descriptor_set.classify.constantize
154
+ default_parent = descriptors.delete('parent')
155
+ descriptors.each do |descriptor, keypairs|
156
+ log "descriptor: #{descriptor.inspect}, keypairs: #{keypairs.inspect}"
157
+ parent = keypairs['parent'] || default_parent || 'nil'
158
+ unless object = klass[descriptor]
159
+ if DomainNeutral.rails_generation < 4
160
+ klass.create! keypairs.merge(symbol: descriptor, parent: eval(parent)), without_protection: true
161
+ else
162
+ klass.create! keypairs.merge(symbol: descriptor, parent: eval(parent))
163
+ end
164
+ else
165
+ if DomainNeutral.rails_generation < 4
166
+ object.update_attributes(keypairs.merge(parent: eval(parent)), without_protection: true)
167
+ else
168
+ object.update_attributes(keypairs.merge(parent: eval(parent)))
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ def fixtures_path
175
+ if ENV['FIXTURES_PATH']
176
+ Rails.root.join(ENV['FIXTURES_PATH'])
177
+ else
178
+ Rails.root.join('test', 'fixtures')
179
+ end
180
+ end
181
+ def abort(*messages)
182
+ raise "#{self.class.name}: #{messages.join("\n")}"
183
+ end
184
+
185
+ def log(message)
186
+ # @context.say message if DomainNeutral.verbose_seed
187
+ if verbose
188
+ @messenger ||= @context.is_a?( ActiveRecord::Migration) ? :say : :puts
189
+ @context.send @messenger, message
190
+ end
191
+ end
192
+
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,170 @@
1
+ module DomainNeutral
2
+ module SymbolizedClass
3
+ # = Domain Neutral SymbolizedClass
4
+ #
5
+ # This mudule implements two important features:
6
+ # * access (finding) to objects, using a symbol
7
+ # * cache of objects that imcludes this module, if enabled
8
+ #
9
+ # A requirement for including this module is that the class has an attribute named symbol.
10
+ #
11
+ # Usage:
12
+ #
13
+ # class MySymbolizedClass < ActiveRecord::Base
14
+ # include DomainNeutral::SymbolizedClass
15
+ # ...
16
+ # end
17
+
18
+
19
+ extend ActiveSupport::Concern
20
+
21
+ included do
22
+ class_attribute :caching_enabled
23
+ after_save :flush_cache, if: :caching_enabled
24
+ end
25
+
26
+ module ClassMethods
27
+ # Access descriptor by symbol, e.g.
28
+ #
29
+ # Role[:manager]
30
+ # => Manager role
31
+ # Same as Role.where(symbol: :manager).first
32
+ def [](symbol)
33
+ find_by_symbol(symbol)
34
+ end
35
+
36
+ # Access like Role.manager
37
+ #
38
+ # Role.manager
39
+ # => Manager role
40
+ # Same as Role.where(symbol: :manager).first
41
+ def method_missing(method, *args)
42
+ begin
43
+ if method != :find_by_symbol
44
+ if obj = find_by_symbol(method)
45
+ redefine_method method do
46
+ find_by_symbol(method)
47
+ end
48
+ return obj
49
+ end
50
+ end
51
+ rescue
52
+ # Ignore errors, and call super
53
+ end
54
+ super
55
+ end
56
+
57
+ # Overrides find by using cache.
58
+ # The key in cache is [class_name, id] or ':class_name/:id', e.g. 'Role/1'
59
+ def find(id)
60
+ if caching_enabled
61
+ Rails.cache.fetch([name, id]) { super }
62
+ else
63
+ super
64
+ end
65
+ end
66
+
67
+ # Find object by symbol
68
+ #
69
+ # See also
70
+ # Descriptor[:symbol]
71
+ # Descriptor.symbol
72
+ def find_by_symbol(symbol)
73
+ if caching_enabled
74
+ Rails.cache.fetch([name, symbol.to_s]) do
75
+ where(symbol: symbol).first
76
+ end
77
+ else
78
+ where(symbol: symbol).first
79
+ end
80
+ end
81
+
82
+ # Role.collection(:site_admin, :user_admin, :admin)
83
+ # => Role[] consisting of Role.site_admin, Role.user_admin, Role.admin
84
+ def collection(*syms)
85
+ syms.flatten.map { |s| self[s] }
86
+ end
87
+
88
+
89
+ # Turn cache on or off
90
+ # Calling enable_caching without parameter or true will turn on caching
91
+ # By default cache is off.
92
+ #
93
+ # Example - enabling caching
94
+ # class MySymbolizedClass < ActiveRecord::Base
95
+ # include DomainNeutral::SymbolizedClass
96
+ # enable_caching
97
+ # ...
98
+ # end
99
+ #
100
+ # Example - disable caching
101
+ # class MySymbolizedClass < ActiveRecord::Base
102
+ # include DomainNeutral::SymbolizedClass
103
+ # enable_caching false
104
+ # ...
105
+ # end
106
+
107
+ def enable_caching(*args)
108
+ self.caching_enabled = args.size > 0 ? args.first : true
109
+ end
110
+ end
111
+
112
+ # Store symbol
113
+ def symbol=(name)
114
+ write_attribute(:symbol, name.to_s)
115
+ end
116
+
117
+ # Retrieve symbol
118
+ def symbol
119
+ @symbol ||= begin
120
+ s = read_attribute(:symbol)
121
+ s && s.to_sym
122
+ end
123
+ end
124
+
125
+ def to_sym
126
+ symbol
127
+ end
128
+
129
+ # Role.admin.is_one_of?(:admin, :site_admin)
130
+ # => true
131
+ # Role.admin.is_one_of?(:site_admin, :user_admin)
132
+ # => false
133
+ def is_one_of?(*syms)
134
+ syms.flatten.include?(to_sym)
135
+ end
136
+
137
+ # Role.admin.is_none_of?(:site_admin, :user_admin)
138
+ # => true
139
+ # Role.admin.is_none_of?(:admin, :site_admin)
140
+ # => false
141
+ def is_none_of?(*syms)
142
+ !syms.flatten.include?(to_sym)
143
+ end
144
+
145
+ # Allow to test for a specific role or similar like Role.accountant?
146
+ def method_missing(method, *args)
147
+ if method.to_s =~ /^(\w+)\?$/
148
+ v = self.class.find_by_symbol($1)
149
+ raise NameError unless v
150
+ other = v.to_sym
151
+ self.class.class_eval { define_method(method) { self.to_sym == other }}
152
+ return self.to_sym == other
153
+ end
154
+ super
155
+ end
156
+
157
+ def respond_to?(meth, include_private = false) # :nodoc
158
+ if m = /^(\w+)\?$/.match(meth.to_s)
159
+ return true if self.to_sym == m[1].to_sym
160
+ end
161
+ super
162
+ end
163
+
164
+ # Flushes cache if record is saved
165
+ def flush_cache
166
+ Rails.cache.delete([self.class.name, symbol_was.to_s])
167
+ Rails.cache.delete([self.class.name, id])
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,3 @@
1
+ module DomainNeutral
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'domain_neutral/symbolized_class'
2
+ require "domain_neutral/engine"
3
+ require 'domain_neutral/railtie' if defined?(Rails)
4
+ require 'domain_neutral/association'
5
+ module DomainNeutral
6
+ mattr_accessor :seed_options
7
+ # Identifies the Rails generation version
8
+ # Rails.version "4.2.1"
9
+ # => 4
10
+ def self.rails_generation
11
+ @@__generation ||= Rails.version.split('.')[0].to_i
12
+ end
13
+
14
+ def self.seed
15
+ require 'domain_neutral/seed'
16
+ Seed.new
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ namespace :domain_neutral do
2
+ namespace :seed do
3
+ desc 'Seed descriptors directly without migration'
4
+ task :descriptors => :environment do
5
+ require 'domain_neutral/seeder/descriptors'
6
+ DomainNeutral::Seeder::Descriptors.seed self
7
+ end
8
+ end
9
+ end
10
+