Skip to content

Instantly share code, notes, and snippets.

@nnabeyang
Created July 25, 2012 13:15
Show Gist options
  • Select an option

  • Save nnabeyang/3176144 to your computer and use it in GitHub Desktop.

Select an option

Save nnabeyang/3176144 to your computer and use it in GitHub Desktop.
validatesの簡易版
class Class
def class_attribute name
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.#{name}() nil end
def self.#{name}=(val)
singleton_class.class_eval {
undef_method :#{name}
define_method(:#{name}) { val }
}
val
end
RUBY
end
end
module MyRails
module Concern
def self.extended(base)
base.instance_variable_set("@dependencies", [])
end
def append_features(base)
if base.instance_variable_defined?("@dependencies")
base.instance_variable_get("@dependencies") << self
else
super
@dependencies.each {|dep| base.send(:include, dep)}
base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
end
end
end
module Callbacks
extend Concern
class Callback
@@_callback_sequence = 0
attr_reader :filter
def initialize(callback_name, callback_obj, callbacks_class)
@filter = "_callback_#{callback_name}_#{next_id}"
callbacks_class.send(:define_method, "#{@filter}_object") { callback_obj }
callbacks_class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{@filter}
#{@filter}_object.#{callback_name}(self)
end
RUBY_EVAL
end
def next_id
@@_callback_sequence += 1
end
end
def run_callbacks(callback_name)
self.class.send("_#{callback_name}_callbacks").each do|callback|
send(callback.filter)
end
end
module ClassMethods
def define_callback(callback_name)
attr_name = "_#{callback_name}_callbacks"
class_attribute attr_name
send("#{attr_name}=", Array.new)
end
def set_callback(callback_name, callback_obj)
send("_#{callback_name}_callbacks").push(Callback.new(callback_name, callback_obj, self))
end
end
end
module Validations
extend Concern
include Callbacks
attr_reader :errors
def initialize
@errors = []
end
def valid?
@errors.clear
run_callbacks(:validate)
return @errors.empty?
end
module ClassMethods
def validates(*attributes)
validations = extract_validations! attributes
validations.each do|validation|
validator_class = const_get "#{validation.to_s.camelize}Validator"
validate_with(validator_class, attributes)
end
end
def extract_validations! attributes
attributes.pop if attributes.last.kind_of? Hash
end
def validate_with(validator_class, attributes)
attributes.each do|attribute|
set_callback(:validate, validator_class.new(attributes))
end
end
end
class PresenceValidator
def initialize attributes
@attributes = attributes
end
def validate validations
@attributes.each do|attribute|
validations.errors.push("#{attribute} can't be blank") if !validations.send(attribute.to_sym)
end
end
end
end
end
class String
def camelize
"Presence"
end
end
require 'myrails'
require 'test/unit'
require 'stringio'
class C
class_attribute :name
end
class CallbackObj
def callback_method(record)
record.log.push(1)
end
end
class CallbackObj2
def callback_method(record)
record.log.push(2)
end
end
class Callbacks
include MyRails::Callbacks
attr_reader :log
def initialize
@log = []
end
define_callback :callback_method
set_callback(:callback_method, CallbackObj.new)
set_callback(:callback_method, CallbackObj2.new)
end
class Validations
include MyRails::Validations
attr_accessor :name
define_callback :validate
validates :name, :presence => true
end
class MyRailsTests < Test::Unit::TestCase
def test_validations_extract_attributes
inp = [:name, :presence => true]
validations = Validations.extract_validations! inp
assert_equal [:name], inp
assert_equal({:presence => true}, validations)
end
def test_string_camelize
assert_equal "Presence", "presence".camelize
end
def test_validations_validates
obj = Validations.new
assert !obj.valid?
assert_equal ["name can't be blank"], obj.errors
obj.name = "nabeyang"
assert obj.valid?
end
def test_class_attribute
name = "nabeyang"
assert_equal name, (C.name = name)
assert_equal name, C.name
end
def test_callbacks_set_callback
assert_equal 2, Callbacks._callback_method_callbacks.size
end
def test_callbacks_run_callback
obj = Callbacks.new
s = StringIO.new
obj.run_callbacks(:callback_method)
assert_equal [1, 2], obj.log
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment