acts_as_label 0.1.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.
@@ -0,0 +1 @@
1
+ .DS_Store
@@ -0,0 +1,20 @@
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.
@@ -0,0 +1,48 @@
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
+
10
+
11
+ == Usage
12
+
13
+ If you just want validations and system label accessors, simply add acts_as_label to the model.
14
+
15
+ class Role < ActiveRecord::Base
16
+ acts_as_label
17
+ end
18
+
19
+
20
+ The plugin accepts three optional parameters.
21
+
22
+ +system_label_column+:: specifies the name of the column to use for the system label (default: system_label)
23
+ +label_column+:: specifies the name of the column to use for the label (default: label)
24
+ +default+:: specifies the system label value to use as the default record
25
+
26
+ class Role < ActiveRecord::Base
27
+ acts_as_label :system_label_column => :key, :label_column => :name, :default => :guest
28
+ end
29
+
30
+
31
+ If you use the plugin within a single table inheritance (STI) design, the easiest way to specify a default
32
+ record is by implementing a class method on the subclass.
33
+
34
+ class Label < ActiveRecord::Base
35
+ acts_as_label
36
+ end
37
+
38
+ class BillingFrequency < Label
39
+ self.default
40
+ BillingFrequency.monthly
41
+ end
42
+ end
43
+
44
+
45
+
46
+ == License
47
+
48
+ Copyright (c) 2010 Coroutine LLC, released under the MIT license
@@ -0,0 +1,43 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'jeweler'
5
+
6
+
7
+ desc 'Default: run tests.'
8
+ task :default => [:test]
9
+
10
+
11
+ desc 'Test the plugin.'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'lib'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+
19
+ desc 'Generate documentation for the plugin.'
20
+ Rake::RDocTask.new(:rdoc) do |rdoc|
21
+ rdoc.rdoc_dir = 'rdoc'
22
+ rdoc.title = 'acts_as_label'
23
+ rdoc.options << '--line-numbers --inline-source'
24
+ rdoc.rdoc_files.include('README')
25
+ rdoc.rdoc_files.include('lib/**/*.rb')
26
+ end
27
+
28
+
29
+ begin
30
+ Jeweler::Tasks.new do |gemspec|
31
+ gemspec.name = "acts_as_label"
32
+ gemspec.summary = "Gem version of acts_as_label Rails plugin."
33
+ gemspec.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."
34
+ gemspec.email = "jdugan@coroutine.com"
35
+ gemspec.homepage = "http://github.com/coroutine/acts_as_label"
36
+ gemspec.authors = ["John Dugan"]
37
+ gemspec.add_dependency "activesupport"
38
+ end
39
+ Jeweler::GemcutterTasks.new
40
+ rescue LoadError
41
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
42
+ end
43
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'acts_as_label'
2
+
3
+ ActiveRecord::Base.class_eval do
4
+ include Coroutine::Acts::Label
5
+ end
@@ -0,0 +1,164 @@
1
+ module Coroutine #:nodoc:
2
+ module Acts #:nodoc:
3
+ module Label #: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
+ # Add inheritable accessors
81
+ write_inheritable_attribute :acts_as_label_system_label_column, system_label
82
+ class_inheritable_reader :acts_as_label_system_label_column
83
+ write_inheritable_attribute :acts_as_label_label_column, label
84
+ class_inheritable_reader :acts_as_label_label_column
85
+ write_inheritable_attribute :acts_as_label_scope, scope
86
+ class_inheritable_reader :acts_as_label_scope
87
+ write_inheritable_attribute :acts_as_label_default_system_label, default
88
+ class_inheritable_reader :acts_as_label_default_system_label
89
+
90
+
91
+ # Add validations
92
+ validates_presence_of system_label
93
+ validates_length_of system_label, :maximum => 255
94
+ validates_format_of system_label, :with => /^[A-Z][_A-Z0-9]*$/
95
+ validates_presence_of label
96
+ validates_length_of label, :maximum => 255
97
+
98
+
99
+ # Add method missing, if needed
100
+ unless self.method_defined? :method_missing
101
+ def self.method_missing(method, *args, &block)
102
+ super
103
+ end
104
+ end
105
+
106
+ # Add custom method missing functionality to perform find by system label lookup. If
107
+ # nothing is found, it delegates the call to the original method_missing.
108
+ def self.method_missing_with_label(method, *args, &block)
109
+ record = self.find(:first, :conditions => ["#{acts_as_label_system_label_column} = ?", method.to_s.upcase])
110
+ if record
111
+ return record
112
+ else
113
+ method_missing_without_label(method, *args, &block)
114
+ end
115
+ end
116
+
117
+ # Add method missing alias
118
+ class << self
119
+ alias_method_chain :method_missing, :label
120
+ end
121
+
122
+ # Add class method to return default record, if needed
123
+ unless self.method_defined? :default
124
+ if default.nil?
125
+ def self.default
126
+ self.first
127
+ end
128
+ else
129
+ def self.default
130
+ self.send("#{acts_as_label_default_system_label}")
131
+ end
132
+ end
133
+ end
134
+
135
+
136
+ # Add all the instance methods
137
+ include Coroutine::Acts::Label::InstanceMethods
138
+
139
+ end
140
+ end
141
+ end
142
+
143
+
144
+ module InstanceMethods
145
+
146
+ # This method updates the system label attribute writer to ensure it is uppercase.
147
+ #
148
+ def system_label=(value)
149
+ value = value.to_s.strip.upcase unless value.nil?
150
+ write_attribute("#{acts_as_label_system_label_column}", value)
151
+ end
152
+
153
+
154
+ # This method overrides the to_s method to return the friendly label value.
155
+ #
156
+ def to_s
157
+ self.send("#{acts_as_label_label_column}")
158
+ end
159
+
160
+ end
161
+
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,259 @@
1
+ #---------------------------------------------------------
2
+ # Requirements
3
+ #---------------------------------------------------------
4
+
5
+ # all generic requirements are in the helper
6
+ require "test/test_helper"
7
+
8
+
9
+
10
+ #---------------------------------------------------------
11
+ # Database config
12
+ #---------------------------------------------------------
13
+
14
+ # establish db connection
15
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
16
+
17
+
18
+ # define and seed tables
19
+ def setup_db
20
+ ActiveRecord::Schema.define(:version => 1) do
21
+ create_table :labels do |t|
22
+ t.string :type, :limit => 255
23
+ t.string :system_label, :limit => 255
24
+ t.string :label, :limit => 255
25
+
26
+ t.timestamps
27
+ end
28
+
29
+ create_table :frameworks do |t|
30
+ t.string :system_name, :limit => 255
31
+ t.string :name, :limit => 255
32
+
33
+ t.timestamps
34
+ end
35
+ end
36
+
37
+ Role.create!({ :system_label => "SUPERUSER", :label => "Admin" })
38
+ Role.create!({ :system_label => "EMPLOYEE", :label => "Employee" })
39
+ Role.create!({ :system_label => "GUEST", :label => "Guest" })
40
+
41
+ BillingFrequency.create!({ :system_label => "MONTHLY", :label => "Monthly" })
42
+ BillingFrequency.create!({ :system_label => "QUARTERLY", :label => "Quarterly" })
43
+ BillingFrequency.create!({ :system_label => "YEARLY", :label => "Yearly" })
44
+
45
+ TaxFrequency.create!({ :system_label => "MONTHLY", :label => "Monthly" })
46
+ TaxFrequency.create!({ :system_label => "QUARTERLY", :label => "Quarterly" })
47
+ TaxFrequency.create!({ :system_label => "YEARLY", :label => "Yearly" })
48
+
49
+ Framework.create!({ :system_name => "RUBY_ON_RAILS", :name => "Rails" })
50
+ Framework.create!({ :system_name => "DJANGO", :name => "Django" })
51
+ end
52
+
53
+
54
+ # drop all tables
55
+ def teardown_db
56
+ ActiveRecord::Base.connection.tables.each do |table|
57
+ ActiveRecord::Base.connection.drop_table(table)
58
+ end
59
+ end
60
+
61
+
62
+
63
+ #---------------------------------------------------------
64
+ # Model definitions
65
+ #---------------------------------------------------------
66
+
67
+ # Labels (STI base)
68
+ class Label < ActiveRecord::Base
69
+ acts_as_label
70
+ end
71
+
72
+
73
+ # Roles (STI extension with default)
74
+ class Role < Label
75
+ def self.default
76
+ Role.guest
77
+ end
78
+ end
79
+
80
+
81
+ # BillingFrequency (STI extension without default)
82
+ class BillingFrequency < Label
83
+ validates_uniqueness_of :system_label, :scope => :type
84
+ end
85
+
86
+
87
+ # TaxFrequency (STI extension for testing duplicate system labels)
88
+ class TaxFrequency < Label
89
+ validates_uniqueness_of :system_label, :scope => :type
90
+ end
91
+
92
+
93
+ # Frameworks (stand-alone model with overrides)
94
+ class Framework < ActiveRecord::Base
95
+ acts_as_label :system_label_column => :system_name, :label_column => :name, :default => :ruby_on_rails
96
+ end
97
+
98
+
99
+
100
+ #---------------------------------------------------------
101
+ # Tests
102
+ #---------------------------------------------------------
103
+
104
+ class ActsAsLabelTest < ActiveSupport::TestCase
105
+
106
+ #---------------------------------------------
107
+ # setup and teardown delegations
108
+ #---------------------------------------------
109
+
110
+ def setup
111
+ setup_db
112
+ end
113
+ def teardown
114
+ teardown_db
115
+ end
116
+
117
+
118
+
119
+ #---------------------------------------------
120
+ # test validations
121
+ #---------------------------------------------
122
+
123
+ def test_validations_with_standard_columns
124
+
125
+ # get valid record
126
+ record = Role.new({ :system_label => "CUSTOMER", :label => "Client" })
127
+ assert record.valid?
128
+
129
+ # system label cannot be null
130
+ record.system_label = nil
131
+ assert !record.valid?
132
+
133
+ # system label cannot be blank
134
+ record.system_label = ""
135
+ assert !record.valid?
136
+
137
+ # system label cannot be longer than 255 characters
138
+ record.system_label = ""
139
+ 256.times { record.system_label << "x" }
140
+ assert !record.valid?
141
+
142
+ # system label cannot have illegal characters
143
+ record.system_label = "SUPER-USER"
144
+ assert !record.valid?
145
+
146
+ # reset system label
147
+ record.system_label = "CUSTOMER"
148
+ assert record.valid?
149
+
150
+ # label cannot be null
151
+ record.label = nil
152
+ assert !record.valid?
153
+
154
+ # label cannot be blank
155
+ record.label = ""
156
+ assert !record.valid?
157
+
158
+ # label cannot be longer than 255 characters
159
+ record.label = ""
160
+ 256.times { record.label << "x" }
161
+ assert !record.valid?
162
+
163
+ end
164
+
165
+
166
+ def test_validations_with_custom_columns
167
+
168
+ # get valid record
169
+ record = Framework.new({ :system_name => "SPRING", :name => "Spring" })
170
+ assert record.valid?
171
+
172
+ # system name cannot be null
173
+ record.system_name = nil
174
+ assert !record.valid?
175
+
176
+ # system name cannot be blank
177
+ record.system_name = ""
178
+ assert !record.valid?
179
+
180
+ # system name cannot be longer than 255 characters
181
+ record.system_name = ""
182
+ 256.times { record.system_name << "x" }
183
+ assert !record.valid?
184
+
185
+ # system name cannot have illegal characters
186
+ record.system_name = "SPRING-JAVA"
187
+ assert !record.valid?
188
+
189
+ # reset system name
190
+ record.system_name = "SPRING"
191
+ assert record.valid?
192
+
193
+ # name cannot be null
194
+ record.name = nil
195
+ assert !record.valid?
196
+
197
+ # name cannot be blank
198
+ record.name = ""
199
+ assert !record.valid?
200
+
201
+ # name cannot be longer than 255 characters
202
+ record.name = ""
203
+ 256.times { record.name << "x" }
204
+ assert !record.valid?
205
+
206
+ end
207
+
208
+
209
+ #---------------------------------------------
210
+ # test method missing
211
+ #---------------------------------------------
212
+
213
+ def test_method_missing_accessors
214
+
215
+ # test lookup by system label
216
+ assert_equal Role.find(:first, :conditions => ["system_label = ?", "SUPERUSER"]), Role.superuser
217
+
218
+ # test default with implemented method
219
+ assert_equal Role.find(:first, :conditions => ["system_label = ?", "GUEST"]), Role.default
220
+
221
+ # test default with unspecified behavior
222
+ assert_equal BillingFrequency.first, BillingFrequency.default
223
+
224
+ # test default with specified system label
225
+ assert_equal Framework.find(:first, :conditions => ["system_name = ?", "RUBY_ON_RAILS"]), Framework.default
226
+
227
+ end
228
+
229
+
230
+ def test_method_missing_finders
231
+
232
+ # dynamic find on stand-alone model
233
+ record = Framework.find_by_system_name("RUBY_ON_RAILS")
234
+ assert !record.nil?
235
+
236
+ #dynamic find on sti model
237
+ record = Role.find_by_system_label("SUPERUSER")
238
+ assert !record.nil?
239
+
240
+ end
241
+
242
+
243
+
244
+ #---------------------------------------------
245
+ # test instance methods
246
+ #---------------------------------------------
247
+
248
+ def test_to_s
249
+ role = Role.first
250
+ assert_equal role.label, role.to_s
251
+ end
252
+
253
+
254
+ def test_upcase_system_label_value
255
+ record = Role.create!({ :system_label => "Customer", :label => "Client" })
256
+ assert_equal record.system_label, "CUSTOMER"
257
+ end
258
+
259
+ end
@@ -0,0 +1,26 @@
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
+
13
+ #----------------------------------------------------------
14
+ # Define global methods
15
+ #----------------------------------------------------------
16
+
17
+ class ActiveSupport::TestCase
18
+
19
+ # This method allows us to use a convenient notation for testing
20
+ # model validations.
21
+ def assert_not_valid(object, msg="Object is valid when it should be invalid")
22
+ assert(!object.valid?, msg)
23
+ end
24
+ alias :assert_invalid :assert_not_valid
25
+
26
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_label
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - John Dugan
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-10 00:00:00 -06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activesupport
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ 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.
33
+ email: jdugan@coroutine.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - README.rdoc
40
+ files:
41
+ - .gitignore
42
+ - MIT-LICENSE
43
+ - README.rdoc
44
+ - Rakefile
45
+ - VERSION
46
+ - init.rb
47
+ - lib/acts_as_label.rb
48
+ - test/acts_as_label_test.rb
49
+ - test/test_helper.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/coroutine/acts_as_label
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.6
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Gem version of acts_as_label Rails plugin.
80
+ test_files:
81
+ - test/acts_as_label_test.rb
82
+ - test/test_helper.rb