johnsbrn-classy-inheritance 0.6.3

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.
data/History.txt ADDED
@@ -0,0 +1,34 @@
1
+ == 0.6.3 2009-01-13
2
+ * Fixed validations for prefix and postfix - johnsbrn
3
+ == 0.6.2 2008-09-25
4
+ * Added back validates_associated override.
5
+ == 0.6.1 2008-07-21
6
+ * Removed validates_associated override, was causing issues.
7
+ == 0.6.0 2008-07-18
8
+ * Add: new option: postfix
9
+ * Add: Expanded prefix,postfix functionality to either accept true or values to prefix/postix attribute with.
10
+ * Add: Tests to support new options
11
+ == 0.5.0 2008-07-08
12
+ * Add: new options: validates_presence_if, validates_associated_if to allow for greater control over validation use.
13
+ * Add: Basic test cases of classy-inheritance depends_on functionality.
14
+ == 0.4.4 2008-06-24
15
+ * Fix: :class_name attribute was not being recognized
16
+ == 0.4.3 2008-06-24
17
+ * Fix: :prefix option was not being removed before passing option to has_one/belongs_to
18
+ == 0.4.2 2008-06-24
19
+ * Fix: has_one only saves for a create, not update. added in save for update.
20
+ == 0.4.1 2008-06-23
21
+ * Fix: removed extra save call for polymorphic associations. rails handles the save on a has_one relationship
22
+ == 0.4.0 2008-06-23
23
+ * Add: support for other options such as :dependent and :class_name
24
+ == 0.3.0 2008-06-12
25
+ * Add: :prefix parameter to depends_on call. So if you have User.depends_on(:profile, :attrs => [:first_name], :prefix => true), your user model will have @user.profile_first_name. This is to avoid name collisions with requisite classes.
26
+ == 0.2.1 2008-06-09
27
+ * Add: exposed :can_be method. Can now define what the polymorphic class can be with these methods. This will add the "is_a_<model>?" and "as_a_<model>" methods.
28
+ * Add: respond_to? :can_be test before adding to requisite class
29
+ == 0.2.0 2008-06-02
30
+ * Add: When defining a depends_on that is polymorhic the requisite class has two methods added: "is_a_<model>?" and "as_a_<model>".
31
+ == 0.1.1 2008-05-30
32
+ * Fix: Merge when other conditionals are passed to the find_with method was incorrectly called without bang!
33
+ == 0.1.0 2008-05-29
34
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 FIXME full name
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/Manifest.txt ADDED
@@ -0,0 +1,26 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ PostInstall.txt
5
+ README
6
+ README.txt
7
+ Rakefile
8
+ config/hoe.rb
9
+ config/requirements.rb
10
+ lib/classy-inheritance.rb
11
+ lib/classy-inheritance/version.rb
12
+ script/console
13
+ script/destroy
14
+ script/generate
15
+ script/txt2html
16
+ setup.rb
17
+ tasks/deployment.rake
18
+ tasks/environment.rake
19
+ tasks/website.rake
20
+ test/test_classy-inheritance.rb
21
+ test/test_helper.rb
22
+ website/index.html
23
+ website/index.txt
24
+ website/javascripts/rounded_corners_lite.inc.js
25
+ website/stylesheets/screen.css
26
+ website/template.html.erb
data/PostInstall.txt ADDED
File without changes
data/README ADDED
File without changes
data/README.txt ADDED
@@ -0,0 +1,48 @@
1
+ = classy-inheritance
2
+
3
+ * FIX (url)
4
+
5
+ == DESCRIPTION:
6
+
7
+ FIX (describe your package)
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * FIX (list of features or problems)
12
+
13
+ == SYNOPSIS:
14
+
15
+ FIX (code sample of usage)
16
+
17
+ == REQUIREMENTS:
18
+
19
+ * FIX (list of requirements)
20
+
21
+ == INSTALL:
22
+
23
+ * FIX (sudo gem install, anything else)
24
+
25
+ == LICENSE:
26
+
27
+ (The MIT License)
28
+
29
+ Copyright (c) 2008 FIX
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining
32
+ a copy of this software and associated documentation files (the
33
+ 'Software'), to deal in the Software without restriction, including
34
+ without limitation the rights to use, copy, modify, merge, publish,
35
+ distribute, sublicense, and/or sell copies of the Software, and to
36
+ permit persons to whom the Software is furnished to do so, subject to
37
+ the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be
40
+ included in all copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
43
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
45
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
46
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
47
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
48
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/config/hoe.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'classy-inheritance/version'
2
+
3
+ AUTHOR = 'Andrew Stone' # can also be an array of Authors
4
+ EMAIL = "andy@stonean.com"
5
+ DESCRIPTION = "Adds a depends_on class method to your ActiveRecord model so that you can define requisite objects."
6
+ GEM_NAME = 'classy-inheritance' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'classyinherit' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+ EXTRA_DEPENDENCIES = [
11
+ # ['activesupport', '>= 1.3.1']
12
+ ] # An array of rubygem dependencies [name, version]
13
+
14
+ @config_file = "~/.rubyforge/user-config.yml"
15
+ @config = nil
16
+ RUBYFORGE_USERNAME = "astone"
17
+ def rubyforge_username
18
+ unless @config
19
+ begin
20
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
21
+ rescue
22
+ puts <<-EOS
23
+ ERROR: No rubyforge config file found: #{@config_file}
24
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
25
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
26
+ EOS
27
+ exit
28
+ end
29
+ end
30
+ RUBYFORGE_USERNAME.replace @config["username"]
31
+ end
32
+
33
+
34
+ REV = nil
35
+ # UNCOMMENT IF REQUIRED:
36
+ # REV = YAML.load(`svn info`)['Revision']
37
+ VERS = ClassyInheritance::VERSION::STRING + (REV ? ".#{REV}" : "")
38
+ RDOC_OPTS = ['--quiet', '--title', 'classy-inheritance documentation',
39
+ "--opname", "index.html",
40
+ "--line-numbers",
41
+ "--main", "README",
42
+ "--inline-source"]
43
+
44
+ class Hoe
45
+ def extra_deps
46
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
47
+ @extra_deps
48
+ end
49
+ end
50
+
51
+ # Generate all the Rake tasks
52
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
53
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
54
+ p.developer(AUTHOR, EMAIL)
55
+ p.description = DESCRIPTION
56
+ p.summary = DESCRIPTION
57
+ p.url = HOMEPATH
58
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
59
+ p.test_globs = ["test/**/test_*.rb"]
60
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
61
+
62
+ # == Optional
63
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
64
+ #p.extra_deps = EXTRA_DEPENDENCIES
65
+
66
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
67
+ end
68
+
69
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
70
+ #PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
71
+ PATH = RUBYFORGE_PROJECT
72
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
73
+ #$hoe.rsync_args = '-av --delete --ignore-errors'
74
+ $hoe.rsync_args = '-av --delete'
75
+ $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
@@ -0,0 +1,198 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+
5
+ module ActiveRecord::Validations::ClassMethods
6
+ def validates_associated_dependent(model_sym, options, configuration = {})
7
+ configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }.update(configuration)
8
+
9
+ validates_each(model_sym, configuration) do |record, attr_name, value|
10
+ associate = record.send(attr_name)
11
+ if associate && !associate.valid?
12
+ associate.errors.each do |key, value|
13
+ if options[:prefix]
14
+ key = (options[:prefix] == true) ? "#{model_sym}_#{key}" : "#{options[:prefix]}_#{key}"
15
+ end
16
+ if options[:postfix]
17
+ key = (options[:postfix] == true) ? "#{key}_#{model_sym}" : "#{key}_#{options[:postfix]}"
18
+ end
19
+ record.errors.add(key, value)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+ module Stonean
28
+ module ClassyInheritance
29
+ def self.included(base)
30
+ base.extend Stonean::ClassyInheritance::ClassMethods
31
+ end
32
+
33
+ module ClassMethods
34
+ def depends_on(model_sym, options = {})
35
+ define_relationship(model_sym,options)
36
+
37
+ # Optional presence of handling
38
+ if options.has_key?(:validates_presence_if) && options[:validates_presence_if] != true
39
+ if [Symbol, String, Proc].include?(options[:validates_presence_if].class)
40
+ validates_presence_of model_sym, :if => options[:validates_presence_if]
41
+ end
42
+ else
43
+ validates_presence_of model_sym
44
+ end
45
+
46
+ if options.has_key?(:validates_associated_if) && options[:validates_associated_if] != true
47
+ if [Symbol, String, Proc].include?(options[:validates_associated_if].class)
48
+ validates_associated_dependent model_sym, options, :if => options[:validates_associated_if]
49
+ end
50
+ else
51
+ validates_associated_dependent model_sym, options
52
+ end
53
+
54
+ # Before save functionality to create/update the requisite object
55
+ define_save_method(model_sym, options[:as])
56
+
57
+ # Adds a find_with_<model_sym> class method
58
+ define_find_with_method(model_sym)
59
+
60
+ if options[:as]
61
+ define_can_be_method_on_requisite_class(options[:class_name] || model_sym, options[:as])
62
+ end
63
+
64
+ options[:attrs].each{|attr| define_accessors(model_sym, attr, options)}
65
+ end
66
+
67
+
68
+ def can_be(model_sym, options = {})
69
+ unless options[:as]
70
+ raise ArgumentError, ":as attribute required when calling can_be"
71
+ end
72
+
73
+ klass = model_sym.to_s.classify
74
+
75
+ define_method "is_a_#{model_sym}?" do
76
+ eval("self.#{options[:as]}_type == '#{klass}'")
77
+ end
78
+
79
+ find_with_method = "find_with_#{self.name.underscore}"
80
+
81
+ define_method "as_a_#{model_sym}" do
82
+ eval("#{klass}.send(:#{find_with_method},self.#{options[:as]}_id)")
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def classy_options
89
+ [:as, :attrs, :prefix, :postfix, :validates_presence_if, :validates_associated_if]
90
+ end
91
+
92
+ def delete_classy_options(options, *keepers)
93
+ options.delete_if do |key,value|
94
+ classy_options.include?(key) && !keepers.include?(key)
95
+ end
96
+ options
97
+ end
98
+
99
+ def define_relationship(model_sym, options)
100
+ opts = delete_classy_options(options.dup, :as)
101
+ if opts[:as]
102
+ as_opt = opts.delete(:as)
103
+ opts = polymorphic_constraints(as_opt).merge(opts)
104
+ has_one model_sym, opts
105
+ else
106
+ belongs_to model_sym, opts
107
+ end
108
+ end
109
+
110
+ def define_save_method(model_sym, polymorphic_name = nil)
111
+ define_method "save_requisite_#{model_sym}" do
112
+ # Return unless the association exists
113
+ eval("return unless self.#{model_sym}")
114
+
115
+ # Set the polymorphic type and id before saving
116
+ if polymorphic_name
117
+ eval("self.#{model_sym}.#{polymorphic_name}_type = self.class.name")
118
+ eval("self.#{model_sym}.#{polymorphic_name}_id = self.id")
119
+ end
120
+
121
+ if polymorphic_name
122
+ # Save only if it's an update, has_one creates automatically
123
+ eval <<-SAVEIT
124
+ unless self.#{model_sym}.new_record?
125
+ self.#{model_sym}.save
126
+ end
127
+ SAVEIT
128
+ else
129
+ eval("self.#{model_sym}.save")
130
+ end
131
+ end
132
+
133
+ before_save "save_requisite_#{model_sym}".to_sym
134
+ end
135
+
136
+ def define_find_with_method(model_sym)
137
+ self.class.send :define_method, "find_with_#{model_sym}" do |*args|
138
+ eval <<-CODE
139
+ if args[1] && args[1].is_a?(Hash)
140
+ if args[1].has_key?(:include)
141
+ inc_val = args[1][:include]
142
+ new_val = inc_val.is_a?(Array) ? inc_val.push(:#{:model_sym}) : [inc_val, :#{model_sym}]
143
+ args[1][:include] = new_val
144
+ else
145
+ args[1].merge!({:include => :#{model_sym}})
146
+ end
147
+ else
148
+ args << {:include => :#{model_sym}}
149
+ end
150
+ find(*args)
151
+ CODE
152
+ end
153
+ end
154
+
155
+ def define_accessors(model_sym, attr, options)
156
+ accessor_method_name = attr
157
+
158
+ if options[:prefix]
159
+ accessor_method_name = (options[:prefix] == true) ? "#{model_sym}_#{accessor_method_name}" : "#{options[:prefix]}_#{accessor_method_name}"
160
+ end
161
+
162
+ if options[:postfix]
163
+ accessor_method_name = (options[:postfix] == true) ? "#{accessor_method_name}_#{model_sym}" : "#{accessor_method_name}_#{options[:postfix]}"
164
+ end
165
+
166
+ define_method accessor_method_name do
167
+ eval("self.#{model_sym} ? self.#{model_sym}.#{attr} : nil")
168
+ end
169
+
170
+ define_method "#{accessor_method_name}=" do |val|
171
+ model_defined = eval("self.#{model_sym}")
172
+
173
+ unless model_defined
174
+ klass = options[:class_name] || model_sym.to_s.classify
175
+ eval("self.#{model_sym} = #{klass}.new")
176
+ end
177
+
178
+ eval("self.#{model_sym}.#{attr}= val")
179
+ end
180
+ end
181
+
182
+ def define_can_be_method_on_requisite_class(model_sym, polymorphic_name)
183
+ klass = model_sym.to_s.classify
184
+ requisite_klass = eval(klass)
185
+ unless requisite_klass.respond_to?(self.name.underscore.to_sym)
186
+ requisite_klass.send :can_be, self.name.underscore,
187
+ :as => polymorphic_name
188
+ end
189
+ end
190
+
191
+ def polymorphic_constraints(polymorphic_name)
192
+ { :foreign_key => "#{polymorphic_name}_id",
193
+ :conditions => "#{polymorphic_name}_type = '#{self.name}'"}
194
+ end
195
+ end # ClassMethods
196
+ end # ClassyInheritance module
197
+ end # Stonean module
198
+ ActiveRecord::Base.send :include, Stonean::ClassyInheritance
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/classy-inheritance.rb'}"
9
+ puts "Loading classy-inheritance gem"
10
+ exec "#{irb} #{libs} --simple-prompt"