1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/README Sun Aug 10 12:36:05 2008 +0200
1.3 @@ -0,0 +1,40 @@
1.4 += Constantize with Care
1.5 +
1.6 +== License
1.7 +Copyright (c) 2008 Henryk Gerach, released under the MIT license
1.8 +see lib/constantize_with_care.rb
1.9 +
1.10 +== Homepage
1.11 +http://www.littleimpact.de/hg/constantize_with_care/
1.12 +
1.13 +== Description
1.14 +Constantize wit Care protects the constantize against 'class injection'
1.15 +(i.e. the constantization of unintended classes) by checking the to be
1.16 +constantized string against a whitelist of +allowed_classes+.
1.17 +
1.18 +The whitelist of +allowed_classes+ may be a set (optimized performance) or
1.19 +an array of strings, a set or an array of classes or a regular expression
1.20 +(disrecommend since difficult).
1.21 +
1.22 +If the string is not allowed to be constantized an exception is raised.
1.23 +The +exception+ defaults to RuntimeError and can be overidden.
1.24 +
1.25 +The method constantize_with_care is added to the String class.
1.26 +
1.27 +== Examples:
1.28 + # A Set of strings should be the fastest implementation:
1.29 + # ConstantSetOfStringsOfAllowedClasses = Set.new ["String","Fixnum"]
1.30 + # or possibly more convenient:
1.31 + ConstantSetOfStringsOfAllowedClasses = Set.new [String,Fixnum].map(&:to_s)
1.32 +
1.33 + "String".constantize_with_care(ConstantSetOfStringsOfAllowedClasses) #=> String
1.34 + "Float".constantize_with_care(ConstantSetOfStringsOfAllowedClasses) #=> raises RuntimeError
1.35 +
1.36 + # For the lazy
1.37 + "String".constantize_with_care([String,Fixnum]) #=> String
1.38 + "Float".constantize_with_care([String,Fixnum], Exception) #=> raises Exception
1.39 +
1.40 + # For the daring
1.41 + # Everything that starts with S is okay:
1.42 + "String".constantize_with_care(/^S/) #=> String
1.43 + "Float".constantize_with_care(/^S/) #=> raises RuntimeError
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/Rakefile Sun Aug 10 12:36:05 2008 +0200
2.3 @@ -0,0 +1,10 @@
2.4 +require 'rake'
2.5 +require 'rake/testtask'
2.6 +
2.7 +desc "Default task"
2.8 +task :default => [ :test ]
2.9 +
2.10 +Rake::TestTask.new do |t|
2.11 + t.test_files = Dir["test/**/*_test.rb"]
2.12 + t.verbose = true
2.13 +end
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/init.rb Sun Aug 10 12:36:05 2008 +0200
3.3 @@ -0,0 +1,2 @@
3.4 +require 'constantize_with_care'
3.5 +String.send :include, ConstantizeWithCare
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/lib/constantize_with_care.rb Sun Aug 10 12:36:05 2008 +0200
4.3 @@ -0,0 +1,39 @@
4.4 +# Copyright (c) 2008 Henryk Gerlach
4.5 +#
4.6 +# Permission is hereby granted, free of charge, to any person obtaining
4.7 +# a copy of this software and associated documentation files (the
4.8 +# "Software"), to deal in the Software without restriction, including
4.9 +# without limitation the rights to use, copy, modify, merge, publish,
4.10 +# distribute, sublicense, and/or sell copies of the Software, and to
4.11 +# permit persons to whom the Software is furnished to do so, subject to
4.12 +# the following conditions:
4.13 +#
4.14 +# The above copyright notice and this permission notice shall be
4.15 +# included in all copies or substantial portions of the Software.
4.16 +#
4.17 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4.18 +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4.19 +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4.20 +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4.21 +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4.22 +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4.23 +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4.24 +module ConstantizeWithCare
4.25 + def constantize_with_care(allowed_classes, exception="I'm not allowed to constantize \`#{self}'!")
4.26 + ok = false
4.27 + if allowed_classes.respond_to? :include? and allowed_classes.include?(self)
4.28 + ok = true
4.29 + elsif not ok and allowed_classes.is_a? Regexp and allowed_classes =~ self
4.30 + ok = true
4.31 + elsif not ok and allowed_classes.respond_to? :each
4.32 + allowed_classes.each do |klass|
4.33 + if self == klass.to_s
4.34 + ok = true
4.35 + break
4.36 + end
4.37 + end
4.38 + end
4.39 + raise exception unless ok
4.40 + self.constantize
4.41 + end
4.42 +end
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/test/constantize_with_care_test.rb Sun Aug 10 12:36:05 2008 +0200
5.3 @@ -0,0 +1,71 @@
5.4 +require 'test/unit'
5.5 +require 'set'
5.6 +begin
5.7 + require 'active_support'
5.8 +rescue LoadError
5.9 + if ENV['ACTIVESUPPORT_PATH'].nil?
5.10 + abort <<END
5.11 +Please set the ACTIVESUPPORT_PATH environment variable to the directory
5.12 +containing the active_support.rb file.
5.13 +END
5.14 + else
5.15 + $LOAD_PATH.unshift ENV['ACTIVESUPPORT_PATH']
5.16 + begin
5.17 + require 'active_support'
5.18 + rescue LoadError
5.19 + abort "ActiveSupport could not be found."
5.20 + end
5.21 + end
5.22 +end
5.23 +
5.24 +require "#{File.dirname(__FILE__)}/../lib/constantize_with_care"
5.25 +String.send :include, ConstantizeWithCare
5.26 +
5.27 +class ConstantizeWithCareTest< Test::Unit::TestCase
5.28 +
5.29 + class MyException < Exception
5.30 + end
5.31 +
5.32 + def test_default_exception
5.33 + e = assert_raise(RuntimeError) {
5.34 + "Float".constantize_with_care(["String","Fixnum"])
5.35 + }
5.36 + assert_equal "I'm not allowed to constantize `Float'!", e.to_s
5.37 + end
5.38 +
5.39 + def test_exception_override
5.40 + assert_raise(MyException) {
5.41 + "Float".constantize_with_care(["String","Fixnum"], MyException)
5.42 + }
5.43 + end
5.44 +
5.45 + def test_set_of_strings
5.46 + set_of_strings = [String,Fixnum].map{|k| k.to_s}.to_set
5.47 + assert_equal String, "String".constantize_with_care(set_of_strings)
5.48 + assert_raise(RuntimeError) {"Float".constantize_with_care(set_of_strings)}
5.49 + end
5.50 +
5.51 + def test_set_of_classes
5.52 + set_of_classes= [String,Fixnum].to_set
5.53 + assert_equal String, "String".constantize_with_care(set_of_classes)
5.54 + assert_raise(RuntimeError) {"Float".constantize_with_care(set_of_classes)}
5.55 + end
5.56 +
5.57 + def test_array_of_strings
5.58 + array_of_strings = [String,Fixnum].map{|k| k.to_s}
5.59 + assert_equal String, "String".constantize_with_care(array_of_strings)
5.60 + assert_raise(RuntimeError) {"Float".constantize_with_care(array_of_strings)}
5.61 + end
5.62 +
5.63 + def test_array_of_classes
5.64 + array_of_classes= [String,Fixnum]
5.65 + assert_equal String, "String".constantize_with_care(array_of_classes)
5.66 + assert_raise(RuntimeError) {"Float".constantize_with_care(array_of_classes)}
5.67 + end
5.68 +
5.69 + def test_regexp
5.70 + regexp= /^Str/
5.71 + assert_equal String, "String".constantize_with_care(regexp)
5.72 + assert_raise(RuntimeError) {"Float".constantize_with_care(regexp)}
5.73 + end
5.74 +end