├── .gitignore
├── init.rb
├── Gemfile
├── lib
├── acts_as_label
│ ├── version.rb
│ └── base.rb
└── acts_as_label.rb
├── Rakefile
├── test
├── test_helper.rb
└── acts_as_label_test.rb
├── MIT-LICENSE
├── acts_as_label.gemspec
├── .specification
├── Gemfile.lock
└── README.rdoc
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.gem
--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
1 | require "acts_as_label"
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "http://rubygems.org"
2 |
3 | gemspec
--------------------------------------------------------------------------------
/lib/acts_as_label/version.rb:
--------------------------------------------------------------------------------
1 | module Coroutine
2 | module ActsAsLabel
3 | VERSION = "1.1.7"
4 | end
5 | end
--------------------------------------------------------------------------------
/lib/acts_as_label.rb:
--------------------------------------------------------------------------------
1 | # acts_as_label extension
2 | require File.dirname(__FILE__) + "/acts_as_label/base"
3 |
4 |
5 | # add extensions to active record
6 | begin
7 | ::ActiveRecord::Base.send(:include, Coroutine::ActsAsLabel::Base)
8 | rescue
9 | # do nothing
10 | end
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler'
2 | Bundler::GemHelper.install_tasks
3 |
4 | require "rake"
5 | require "rake/testtask"
6 |
7 |
8 | desc "Default: run tests."
9 | task :default => [:test]
10 |
11 |
12 | desc "Test the gem."
13 | Rake::TestTask.new(:test) do |t|
14 | t.libs << ["lib", "test"]
15 | t.pattern = "test/**/*_test.rb"
16 | t.verbose = true
17 | end
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # require rails stuff
2 | require "rubygems"
3 | require "active_record"
4 | require "active_support"
5 | require "active_support/test_case"
6 | require "test/unit"
7 |
8 | # require plugin
9 | require "#{File.dirname(__FILE__)}/../init"
10 |
11 | #----------------------------------------------------------
12 | # Define global methods
13 | #----------------------------------------------------------
14 |
15 | class ActiveSupport::TestCase
16 |
17 | # This method allows us to use a convenient notation for testing
18 | # model validations.
19 | def assert_not_valid(object, msg="Object is valid when it should be invalid")
20 | assert(!object.valid?, msg)
21 | end
22 | alias :assert_invalid :assert_not_valid
23 |
24 | end
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Coroutine LLC
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.
21 |
--------------------------------------------------------------------------------
/acts_as_label.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path("../lib", __FILE__)
3 | require "acts_as_label/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "acts_as_label"
7 | s.version = Coroutine::ActsAsLabel::VERSION
8 | s.platform = Gem::Platform::RUBY
9 | s.authors = ["Coroutine", "John Dugan"]
10 | s.email = ["gems@coroutine.com"]
11 | s.homepage = "http://github.com/coroutine/acts_as_label"
12 | s.summary = %q{This acts_as extension simplifies the process of assigning mutable user-friendly labels to immutable system labels.}
13 | s.description = %q{This acts_as extension implements a system label and a friendly label on a class and centralizes the logic for performing validations and accessing items by system label.}
14 |
15 | s.add_dependency "rails", ">= 3.0.0"
16 |
17 | s.add_development_dependency "rspec", ">= 2.0.0"
18 | s.add_development_dependency "sqlite3", ">= 1.3.6"
19 |
20 | s.rubyforge_project = "acts_as_label"
21 |
22 | s.files = `git ls-files`.split("\n")
23 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25 | s.require_paths = ["lib"]
26 | end
27 |
--------------------------------------------------------------------------------
/.specification:
--------------------------------------------------------------------------------
1 | --- !ruby/object:Gem::Specification
2 | name: acts_as_label
3 | version: !ruby/object:Gem::Version
4 | prerelease:
5 | version: 1.1.0
6 | platform: ruby
7 | authors:
8 | - Coroutine
9 | - John Dugan
10 | - Rick Branson
11 | autorequire:
12 | bindir: bin
13 | cert_chain: []
14 |
15 | date: 2011-05-12 00:00:00 Z
16 | dependencies:
17 | - !ruby/object:Gem::Dependency
18 | name: activerecord
19 | prerelease: false
20 | requirement: &id001 !ruby/object:Gem::Requirement
21 | none: false
22 | requirements:
23 | - - ">="
24 | - !ruby/object:Gem::Version
25 | version: 2.3.4
26 | type: :runtime
27 | version_requirements: *id001
28 | - !ruby/object:Gem::Dependency
29 | name: activesupport
30 | prerelease: false
31 | requirement: &id002 !ruby/object:Gem::Requirement
32 | none: false
33 | requirements:
34 | - - ">="
35 | - !ruby/object:Gem::Version
36 | version: 2.3.4
37 | type: :development
38 | version_requirements: *id002
39 | description: This acts_as extension implements a system label and a friendly label on a class and centralizes the logic for performing validations and accessing items by system label.
40 | email: jdugan@coroutine.com
41 | executables: []
42 |
43 | extensions: []
44 |
45 | extra_rdoc_files:
46 | - README.rdoc
47 | files:
48 | - .specification
49 | - MIT-LICENSE
50 | - README.rdoc
51 | - Rakefile
52 | - VERSION
53 | - acts_as_label.gemspec
54 | - init.rb
55 | - lib/acts_as_label.rb
56 | - lib/acts_as_label/base.rb
57 | - rails/init.rb
58 | - test/acts_as_label_test.rb
59 | - test/test_helper.rb
60 | homepage: http://github.com/coroutine/acts_as_label
61 | licenses: []
62 |
63 | post_install_message:
64 | rdoc_options: []
65 |
66 | require_paths:
67 | - lib
68 | required_ruby_version: !ruby/object:Gem::Requirement
69 | none: false
70 | requirements:
71 | - - ">="
72 | - !ruby/object:Gem::Version
73 | version: "0"
74 | required_rubygems_version: !ruby/object:Gem::Requirement
75 | none: false
76 | requirements:
77 | - - ">="
78 | - !ruby/object:Gem::Version
79 | version: "0"
80 | requirements: []
81 |
82 | rubyforge_project:
83 | rubygems_version: 1.8.2
84 | signing_key:
85 | specification_version: 3
86 | summary: Gem version of acts_as_label Rails plugin.
87 | test_files: []
88 |
89 |
90 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | acts_as_label (1.1.6)
5 | rails (>= 3.0.0)
6 |
7 | GEM
8 | remote: http://rubygems.org/
9 | specs:
10 | actionmailer (4.0.0)
11 | actionpack (= 4.0.0)
12 | mail (~> 2.5.3)
13 | actionpack (4.0.0)
14 | activesupport (= 4.0.0)
15 | builder (~> 3.1.0)
16 | erubis (~> 2.7.0)
17 | rack (~> 1.5.2)
18 | rack-test (~> 0.6.2)
19 | activemodel (4.0.0)
20 | activesupport (= 4.0.0)
21 | builder (~> 3.1.0)
22 | activerecord (4.0.0)
23 | activemodel (= 4.0.0)
24 | activerecord-deprecated_finders (~> 1.0.2)
25 | activesupport (= 4.0.0)
26 | arel (~> 4.0.0)
27 | activerecord-deprecated_finders (1.0.3)
28 | activesupport (4.0.0)
29 | i18n (~> 0.6, >= 0.6.4)
30 | minitest (~> 4.2)
31 | multi_json (~> 1.3)
32 | thread_safe (~> 0.1)
33 | tzinfo (~> 0.3.37)
34 | arel (4.0.0)
35 | atomic (1.1.13)
36 | builder (3.1.4)
37 | diff-lcs (1.2.4)
38 | erubis (2.7.0)
39 | hike (1.2.3)
40 | i18n (0.6.5)
41 | mail (2.5.4)
42 | mime-types (~> 1.16)
43 | treetop (~> 1.4.8)
44 | mime-types (1.24)
45 | minitest (4.7.5)
46 | multi_json (1.7.9)
47 | polyglot (0.3.3)
48 | rack (1.5.2)
49 | rack-test (0.6.2)
50 | rack (>= 1.0)
51 | rails (4.0.0)
52 | actionmailer (= 4.0.0)
53 | actionpack (= 4.0.0)
54 | activerecord (= 4.0.0)
55 | activesupport (= 4.0.0)
56 | bundler (>= 1.3.0, < 2.0)
57 | railties (= 4.0.0)
58 | sprockets-rails (~> 2.0.0)
59 | railties (4.0.0)
60 | actionpack (= 4.0.0)
61 | activesupport (= 4.0.0)
62 | rake (>= 0.8.7)
63 | thor (>= 0.18.1, < 2.0)
64 | rake (10.1.0)
65 | rspec (2.14.1)
66 | rspec-core (~> 2.14.0)
67 | rspec-expectations (~> 2.14.0)
68 | rspec-mocks (~> 2.14.0)
69 | rspec-core (2.14.5)
70 | rspec-expectations (2.14.2)
71 | diff-lcs (>= 1.1.3, < 2.0)
72 | rspec-mocks (2.14.3)
73 | sprockets (2.10.0)
74 | hike (~> 1.2)
75 | multi_json (~> 1.0)
76 | rack (~> 1.0)
77 | tilt (~> 1.1, != 1.3.0)
78 | sprockets-rails (2.0.0)
79 | actionpack (>= 3.0)
80 | activesupport (>= 3.0)
81 | sprockets (~> 2.8)
82 | sqlite3 (1.3.8)
83 | thor (0.18.1)
84 | thread_safe (0.1.2)
85 | atomic
86 | tilt (1.4.1)
87 | treetop (1.4.15)
88 | polyglot
89 | polyglot (>= 0.3.1)
90 | tzinfo (0.3.37)
91 |
92 | PLATFORMS
93 | ruby
94 |
95 | DEPENDENCIES
96 | acts_as_label!
97 | rspec (>= 2.0.0)
98 | sqlite3 (>= 1.3.6)
99 |
--------------------------------------------------------------------------------
/README.rdoc:
--------------------------------------------------------------------------------
1 | = acts_as_label
2 |
3 |
4 | == Description
5 |
6 | This acts_as extension implements a system label and a friendly label on a class and centralizes
7 | the logic for performing validations and accessing items by system label.
8 |
9 | The extension is particularly useful for tabled, enumerated lists.
10 |
11 | The system label is declared as a read-only attribute, allowing models and controllers to code
12 | to the value safely, secure in the knowledge that the value will never change.
13 |
14 | The friendly value can be changed to any value required by the end-user without affecting the
15 | model/controller code in any way.
16 |
17 |
18 | == Usage
19 |
20 | If you just want validations and system label accessors, simply add acts_as_label to the model.
21 |
22 | class Role < ActiveRecord::Base
23 | acts_as_label
24 | end
25 |
26 |
27 | The plugin accepts three optional parameters.
28 |
29 | +system_label_column+:: specifies the name of the column to use for the system label (default: system_label)
30 | +label_column+:: specifies the name of the column to use for the label (default: label)
31 | +default+:: specifies the system label value to use as the default record
32 |
33 | class Role < ActiveRecord::Base
34 | acts_as_label :system_label_column => :key, :label_column => :name, :default => :guest
35 | end
36 |
37 |
38 | If you use the plugin within a single table inheritance (STI) design, the easiest way to specify a default
39 | record is by implementing a class method on the subclass.
40 |
41 | class Label < ActiveRecord::Base
42 | acts_as_label
43 | end
44 |
45 | class BillingFrequency < Label
46 | self.default
47 | BillingFrequency.monthly
48 | end
49 | end
50 |
51 |
52 | The extension also allows records to be access by system label as though the system label were
53 | a class method. The default option can be accessed in a similar manner using the class
54 | method +default+. This yields more expressive code.
55 |
56 | class Role < ActiveRecord::Base
57 | has_many :users
58 |
59 | acts_as_label :default => :guest
60 | end
61 |
62 | class User < ActiveRecord::Base
63 | belongs_to :role
64 | end
65 |
66 | Role.create!({ :system_label => "SUPERUSER", :label => "Superuser"} )
67 | Role.create!({ :system_label => "GUEST", :label => "Guest"} )
68 |
69 | User.create!({ :name => "John Dugan", :role => Role.superuser })
70 | User.create!({ :name => "Anonymous Dude", :role => Role.default })
71 |
72 |
73 | To help avoid excessive querying, the extension overrides the equality operator.
74 | This allows record comparisons in a couple of formats:
75 |
76 | u.role == Role.superuser # as you would expect
77 | u.role == :superuser # to spare a superfluous query (same as u.role.to_sym == :superuser)
78 |
79 |
80 | Other useful utility methods:
81 |
82 | +to_s+:: Returns the friendly label value
83 | +to_sym+:: Returns the downcased, symbolized system label value
84 |
85 |
86 |
87 | == Helpful Links
88 |
89 | * Repository: http://github.com/coroutine/acts_as_label
90 | * Gem: http://rubygems.org/gems/acts_as_label
91 | * Authors: http://coroutine.com
92 |
93 |
94 |
95 | == Installation (Rails 3)
96 |
97 | Install me from RubyGems.org by adding a gem dependency to your Gemfile. Bundler does
98 | the rest.
99 |
100 | gem "acts_as_label"
101 |
102 | $ bundle install
103 |
104 |
105 |
106 | == Installation (Rails 2)
107 |
108 | Install me from RubyGems.org and add a gem dependency in the appropriate file.
109 |
110 | $ gem install acts_as_label
111 |
112 | Or install me as a plugin.
113 |
114 | $ script/plugin install git://github.com/coroutine/acts_as_label.git
115 |
116 |
117 |
118 | == Gemroll
119 |
120 | Other gems by Coroutine include:
121 |
122 | * {acts_as_current}[http://github.com/coroutine/acts_as_current]
123 | * {acts_as_list_with_sti_support}[http://github.com/coroutine/acts_as_list_with_sti_support]
124 | * {delayed_form_observer}[http://github.com/coroutine/delayed_form_observer]
125 | * {kenny_dialoggins}[http://github.com/coroutine/kenny_dialoggins]
126 | * {michael_hintbuble}[http://github.com/coroutine/michael_hintbuble]
127 | * {tiny_navigation}[http://github.com/coroutine/tiny_navigation]
128 |
129 |
130 |
131 | == License
132 |
133 | Copyright (c) 2010 {Coroutine LLC}[http://coroutine.com].
134 |
135 | Permission is hereby granted, free of charge, to any person obtaining
136 | a copy of this software and associated documentation files (the
137 | "Software"), to deal in the Software without restriction, including
138 | without limitation the rights to use, copy, modify, merge, publish,
139 | distribute, sublicense, and/or sell copies of the Software, and to
140 | permit persons to whom the Software is furnished to do so, subject to
141 | the following conditions:
142 |
143 | The above copyright notice and this permission notice shall be
144 | included in all copies or substantial portions of the Software.
145 |
146 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
147 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
148 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
149 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
150 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
151 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
152 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/lib/acts_as_label/base.rb:
--------------------------------------------------------------------------------
1 | module Coroutine #:nodoc:
2 | module ActsAsLabel #:nodoc:
3 | module Base #:nodoc:
4 |
5 | def self.included(base) #:nodoc:
6 | base.extend(ClassMethods)
7 | end
8 |
9 |
10 | module ClassMethods
11 |
12 |
13 | # == Description
14 | #
15 | # This +acts_as+ extension implements a system label and a friendly label on a class and centralizes
16 | # the logic for performing validations and accessing items by system label.
17 | #
18 | #
19 | # == Usage
20 | #
21 | # Simple Example
22 | #
23 | # class BillingFrequency < ActiveRecord::Base
24 | # has_many :subscriptions
25 | # acts_as_label :default => :monthly
26 | # end
27 | #
28 | # class Subscription < ActiveRecord::Base
29 | # belongs_to :billing_frequency
30 | # end
31 | #
32 | # subscription.billing_frequency = BillingFrequency.monthly
33 | # subscription.billing_frequency = BillingFrequency.default
34 | #
35 | #
36 | # STI Example:
37 | #
38 | # class Label < ActiveRecord::Base
39 | # acts_as_label :scoped_to => :type
40 | # end
41 | #
42 | # class BillingFrequency < Label
43 | # has_many :subscriptions
44 | # def self.default
45 | # BillingFrequency.monthly
46 | # end
47 | # end
48 | #
49 | # class Subscription < ActiveRecord::Base
50 | # belongs_to :billing_frequency
51 | # end
52 | #
53 | # subscription.billing_frequency = BillingFrequency.monthly
54 | # subscription.billing_frequency = BillingFrequency.default
55 | #
56 | #
57 | # == Configuration
58 | #
59 | # * +system_label_cloumn+ - specifies the column name to use for storing the system label (default: +system_label+)
60 | # * +label_column+ - specifies the column name to use for storing the label (default: +label+)
61 | # * +default+ - specifies the system label value of the default instance (default: the first record in the default scope)
62 | #
63 | def acts_as_label(options = {})
64 |
65 | #-------------------------------------------
66 | # scrub options
67 | #-------------------------------------------
68 | options = {} unless options.is_a?(Hash)
69 | system_label = options.key?(:system_label_column) ? options[:system_label_column].to_sym : :system_label
70 | label = options.key?(:label_column) ? options[:label_column].to_sym : :label
71 | scope = options.key?(:scope) ? options[:scope] : "1 = 1"
72 | default = options.key?(:default) ? options[:default].to_sym : nil
73 |
74 |
75 | #--------------------------------------------
76 | # mix methods into class definition
77 | #--------------------------------------------
78 | class_eval do
79 |
80 | # inheritable accessors
81 | class_attribute :acts_as_label_system_label_column
82 | class_attribute :acts_as_label_label_column
83 | class_attribute :acts_as_label_scope
84 | class_attribute :acts_as_label_default_system_label
85 |
86 | self.acts_as_label_system_label_column = system_label
87 | self.acts_as_label_label_column = label
88 | self.acts_as_label_scope = scope
89 | self.acts_as_label_default_system_label = default
90 |
91 | # protect attributes
92 | attr_readonly system_label
93 |
94 | # validations
95 | validates_presence_of system_label
96 | validates_length_of system_label, :maximum => 255
97 | validates_format_of system_label, :with => /\A[A-Z][_A-Z0-9]*\Z/
98 | validates_presence_of label
99 | validates_length_of label, :maximum => 255
100 |
101 | # This method catches all undefined method calls. It first sees if any ancestor
102 | # understands the request. If not, it tries to match the method call to an
103 | # existing system label. If that is found, it lazily manufacturers a method on the
104 | # class of the same name. Otherwise, it throws the NoMethodError.
105 | #
106 | def self.method_missing(method, *args, &block)
107 | begin
108 | super
109 | rescue NoMethodError => e
110 | if has_acts_as_label_method?(method)
111 | self.__send__(method)
112 | else
113 | raise e
114 | end
115 | end
116 | end
117 |
118 |
119 | # This method determines whether or not the class has an instance with
120 | # the given system label. If it does, it also lazily creates a method
121 | # that can be accessed without all this method missing nonsense.
122 | #
123 | def self.has_acts_as_label_method?(method_name)
124 | mn = method_name.to_s.underscore
125 | sl = mn.upcase
126 |
127 | if record = by_acts_as_label_system_label(sl)
128 | eval %Q{
129 | class << self
130 | def #{mn}
131 | by_acts_as_label_system_label('#{sl}')
132 | end
133 |
134 | alias_method :#{mn.upcase}, :#{mn}
135 | end
136 | }
137 | end
138 |
139 | !!record
140 | end
141 |
142 |
143 | # This method finds an active record object for the given system label.
144 | #
145 | def self.by_acts_as_label_system_label(system_label)
146 | where("#{acts_as_label_system_label_column} = ?", system_label.to_s.upcase).first
147 | end
148 |
149 |
150 | # This block adds a class method to return the default record.
151 | #
152 | unless self.method_defined? :default
153 | if default.nil?
154 | def self.default
155 | self.first
156 | end
157 | else
158 | def self.default
159 | self.send("#{acts_as_label_default_system_label}")
160 | end
161 | end
162 | end
163 |
164 |
165 | # This method overrides the system label column writer to force
166 | # upcasing of the value.
167 | #
168 | define_method("#{acts_as_label_system_label_column}=") do |value|
169 | value = value.to_s.strip.upcase unless value.nil?
170 | write_attribute("#{acts_as_label_system_label_column}", value)
171 | end
172 |
173 |
174 | # Add all the instance methods
175 | include Coroutine::ActsAsLabel::Base::InstanceMethods
176 |
177 | end
178 | end
179 | end
180 |
181 |
182 | module InstanceMethods
183 |
184 | # This method overrides to_ary to return nil, which tells anything trying to
185 | # flatten this we are already flat. This is necessary because we are overriding
186 | # active records method missing, which must do this somewhere in the bowels
187 | # of rails.
188 | #
189 | def to_ary
190 | nil
191 | end
192 |
193 |
194 | # This method overrides the to_s method to return the friendly label value.
195 | #
196 | def to_s
197 | self.send("#{acts_as_label_label_column}")
198 | end
199 |
200 |
201 | # This method overrides the to_sym method to return the downcased symbolized
202 | # system label value. This method is particularly useful in conjunction with
203 | # role-based authorization systems.
204 | #
205 | def to_sym
206 | self.send("#{acts_as_label_system_label_column}").underscore.to_sym
207 | end
208 |
209 |
210 | # This method compares two values by running to_sym on both sides. This allows
211 | # comparisons like the following:
212 | # u.role == Role.superuser
213 | # u.role == :superuser
214 | #
215 | def ==(other)
216 | self.to_sym == (other.to_sym rescue false)
217 | end
218 |
219 | end
220 |
221 | end
222 | end
223 | end
224 |
--------------------------------------------------------------------------------
/test/acts_as_label_test.rb:
--------------------------------------------------------------------------------
1 | #---------------------------------------------------------
2 | # Requirements
3 | #---------------------------------------------------------
4 |
5 | # all generic requirements are in the helper
6 | require "test_helper"
7 |
8 |
9 | #---------------------------------------------------------
10 | # Database config
11 | #---------------------------------------------------------
12 |
13 | # establish db connection
14 | ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
15 |
16 | # define and seed tables
17 | def setup_db
18 | ActiveRecord::Schema.define(:version => 1) do
19 | create_table :labels do |t|
20 | t.string :type, :limit => 255
21 | t.string :system_label, :limit => 255
22 | t.string :label, :limit => 255
23 |
24 | t.timestamps
25 | end
26 |
27 | create_table :frameworks do |t|
28 | t.string :system_name, :limit => 255
29 | t.string :name, :limit => 255
30 |
31 | t.timestamps
32 | end
33 | end
34 |
35 | Role.create!({ :system_label => "SUPERUSER", :label => "Admin" })
36 | Role.create!({ :system_label => "EMPLOYEE", :label => "Employee" })
37 | Role.create!({ :system_label => "GUEST", :label => "Guest" })
38 |
39 | BillingFrequency.create!({ :system_label => "MONTHLY", :label => "Monthly" })
40 | BillingFrequency.create!({ :system_label => "QUARTERLY", :label => "Quarterly" })
41 | BillingFrequency.create!({ :system_label => "YEARLY", :label => "Yearly" })
42 |
43 | TaxFrequency.create!({ :system_label => "MONTHLY", :label => "Monthly" })
44 | TaxFrequency.create!({ :system_label => "QUARTERLY", :label => "Quarterly" })
45 | TaxFrequency.create!({ :system_label => "YEARLY", :label => "Yearly" })
46 |
47 | Framework.create!({ :system_name => "RUBY_ON_RAILS", :name => "Rails" })
48 | Framework.create!({ :system_name => "DJANGO", :name => "Django" })
49 | end
50 |
51 |
52 | # drop all tables
53 | def teardown_db
54 | ActiveRecord::Base.connection.tables.each do |table|
55 | ActiveRecord::Base.connection.drop_table(table)
56 | end
57 | end
58 |
59 |
60 | #---------------------------------------------------------
61 | # Model definitions
62 | #---------------------------------------------------------
63 |
64 | # Labels (STI base)
65 | class Label < ActiveRecord::Base
66 | acts_as_label
67 | end
68 |
69 |
70 | # Roles (STI extension with default)
71 | class Role < Label
72 | def self.default
73 | Role.guest
74 | end
75 | end
76 |
77 |
78 | # BillingFrequency (STI extension without default)
79 | class BillingFrequency < Label
80 | validates_uniqueness_of :system_label, :scope => :type
81 | end
82 |
83 |
84 | # TaxFrequency (STI extension for testing duplicate system labels)
85 | class TaxFrequency < Label
86 | validates_uniqueness_of :system_label, :scope => :type
87 | end
88 |
89 |
90 | # Frameworks (stand-alone model with overrides)
91 | class Framework < ActiveRecord::Base
92 | acts_as_label :system_label_column => :system_name, :label_column => :name, :default => :ruby_on_rails
93 | end
94 |
95 |
96 | #---------------------------------------------------------
97 | # Tests
98 | #---------------------------------------------------------
99 |
100 | class ActsAsLabelTest < ActiveSupport::TestCase
101 |
102 | #---------------------------------------------
103 | # setup and teardown delegations
104 | #---------------------------------------------
105 |
106 | def setup
107 | setup_db
108 | end
109 | def teardown
110 | teardown_db
111 | end
112 |
113 | #---------------------------------------------
114 | # test validations
115 | #---------------------------------------------
116 |
117 | def test_validations_with_standard_columns
118 |
119 | # get valid record
120 | record = Role.new({ :system_label => "CUSTOMER", :label => "Client" })
121 | assert record.valid?
122 |
123 | # system label cannot be null
124 | record.system_label = nil
125 | assert !record.valid?
126 |
127 | # system label cannot be blank
128 | record.system_label = ""
129 | assert !record.valid?
130 |
131 | # system label cannot be longer than 255 characters
132 | record.system_label = ""
133 | 256.times { record.system_label << "x" }
134 | assert !record.valid?
135 |
136 | # system label cannot have illegal characters
137 | record.system_label = "SUPER-USER"
138 | assert !record.valid?
139 |
140 | # reset system label
141 | record.system_label = "CUSTOMER"
142 | assert record.valid?
143 |
144 | # label cannot be null
145 | record.label = nil
146 | assert !record.valid?
147 |
148 | # label cannot be blank
149 | record.label = ""
150 | assert !record.valid?
151 |
152 | # label cannot be longer than 255 characters
153 | record.label = ""
154 | 256.times { record.label << "x" }
155 | assert !record.valid?
156 |
157 | end
158 |
159 |
160 | def test_validations_with_custom_columns
161 |
162 | # get valid record
163 | record = Framework.new({ :system_name => "SPRING", :name => "Spring" })
164 | assert record.valid?
165 |
166 | # system name cannot be null
167 | record.system_name = nil
168 | assert !record.valid?
169 |
170 | # system name cannot be blank
171 | record.system_name = ""
172 | assert !record.valid?
173 |
174 | # system name cannot be longer than 255 characters
175 | record.system_name = ""
176 | 256.times { record.system_name << "x" }
177 | assert !record.valid?
178 |
179 | # system name cannot have illegal characters
180 | record.system_name = "SPRING-JAVA"
181 | assert !record.valid?
182 |
183 | # reset system name
184 | record.system_name = "SPRING"
185 | assert record.valid?
186 |
187 | # name cannot be null
188 | record.name = nil
189 | assert !record.valid?
190 |
191 | # name cannot be blank
192 | record.name = ""
193 | assert !record.valid?
194 |
195 | # name cannot be longer than 255 characters
196 | record.name = ""
197 | 256.times { record.name << "x" }
198 | assert !record.valid?
199 |
200 | end
201 |
202 |
203 | #---------------------------------------------
204 | # test method missing
205 | #---------------------------------------------
206 |
207 | def test_method_missing_accessors
208 |
209 | # lookup database objects using syntax appropriate for version of rails
210 | begin
211 | role_superuser = Role.where("system_label = ?", "SUPERUSER").first
212 | role_guest = Role.where("system_label = ?", "GUEST").first
213 | role_fresh = Role.create!(:system_label => "FRESH", :label => "Fresh")
214 | framework_rails = Framework.where("system_name = ?", "RUBY_ON_RAILS").first
215 | rescue
216 | role_superuser = Role.find(:first, :conditions => ["system_label = ?", "SUPERUSER"])
217 | role_guest = Role.find(:first, :conditions => ["system_label = ?", "GUEST"])
218 | framework_rails = Framework.find(:first, :conditions => ["system_name = ?", "RUBY_ON_RAILS"])
219 | end
220 |
221 | # Won't have a method now
222 | assert !Role.methods.map(&:to_s).include?("fresh") # some rubies report strings, some symbols
223 |
224 | # test lookup by system label
225 | assert_equal role_fresh, Role.fresh
226 |
227 | # should have a method now
228 | assert Role.methods.map(&:to_s).include?("fresh") # some rubies report strings, some symbols
229 |
230 | # test default with implemented method
231 | assert_equal role_guest, Role.default
232 |
233 | # test default with unspecified behavior
234 | assert_equal BillingFrequency.first, BillingFrequency.default
235 |
236 | # test default with specified system label
237 | assert_equal framework_rails, Framework.default
238 | end
239 |
240 | def test_method_missing_finders
241 |
242 | # dynamic find on stand-alone model
243 | record = Framework.find_by_system_name("RUBY_ON_RAILS")
244 | assert !record.nil?
245 |
246 | #dynamic find on sti model
247 | record = Role.find_by_system_label("SUPERUSER")
248 | assert !record.nil?
249 |
250 | end
251 |
252 |
253 |
254 | #---------------------------------------------
255 | # test validations
256 | #---------------------------------------------
257 |
258 | def test_system_label_is_readonly
259 |
260 | # build valid record
261 | record = Role.new({ :system_label => "CUSTOMER", :label => "Client" })
262 | assert record.valid?
263 |
264 | # save it and remember id and system label
265 | record.save
266 | id = record.id
267 | system_label = record.system_label
268 |
269 | # system label unchanged on safe update
270 | record.label = "Customer"
271 | record.save
272 | record = Role.find(id) # we have to get the record again to verify what's in the db
273 | assert_equal system_label, record.system_label
274 |
275 | # system_label unchanged on unsafe update
276 | record.system_label = "CLIENT"
277 | record.label = "Client"
278 | record.save
279 | record = Role.find(id) # we have to get the record again to verify what's in the db
280 | assert_equal "Client", record.label
281 | assert_equal system_label, record.system_label
282 |
283 | end
284 |
285 |
286 |
287 | #---------------------------------------------
288 | # test instance methods
289 | #---------------------------------------------
290 |
291 | def test_equality
292 | r1 = Role.superuser
293 |
294 | assert (r1 == Role.superuser)
295 | assert (r1 == :superuser)
296 |
297 | assert !(r1 == false)
298 | end
299 |
300 | def test_to_s
301 | role = Role.first
302 | assert_equal role.label, role.to_s
303 | end
304 |
305 | def test_to_sym
306 | role = Role.first
307 | assert_equal role.system_label.downcase.to_sym, role.to_sym
308 | end
309 |
310 | def test_upcase_system_label_value
311 | # default system label column name
312 | record = Role.create!({ :system_label => "Customer", :label => "Client" })
313 | assert_equal record.system_label, "CUSTOMER"
314 |
315 | # custom system label column name
316 | record = Framework.create!( :system_name => "example", :name => "Example")
317 | assert_equal record.system_name, "EXAMPLE"
318 | end
319 |
320 | def test_support_upcase_accessors
321 | assert Role.SUPERUSER == Role.superuser
322 | assert Role.SUPERUSER == :superuser
323 | end
324 |
325 | end
326 |
--------------------------------------------------------------------------------