Skip to content

Instantly share code, notes, and snippets.

@mrkurt
Created July 21, 2010 20:20
Show Gist options
  • Save mrkurt/485056 to your computer and use it in GitHub Desktop.
Save mrkurt/485056 to your computer and use it in GitHub Desktop.
class Rule
def self.type(t)
@type = t
Rules.register(self)
end
def self.required_attributes(*attrs)
@attributes ||= {}
@attributes[:required] = attrs.map(&:to_s)
end
def self.optional_attributes(*attrs)
@attributes ||= {}
@attributes[:optional] = attrs.map(&:to_s)
end
def self.allowed_attributes
@attributes ||= {}
[@attributes[:required], @attributes[:optional]].flatten.reject(&:nil?)
end
def self.processor
@processor
end
def self.process(&block)
@processor = block
end
def self.tag(tag = false)
@tag = tag if tag
@tag
end
def self.validate(element)
allowed = allowed_attributes
invalid = element.attributes.keys.reject{ |a| allowed.include?(a.to_s) }
raise "Invalid attribute(s) for #{tag} tag: #{invalid.join(', ')}" if invalid.length > 0
required = required_attributes.reject{ |a| element.attributes.has_key?(a.to_s) }
raise "Missing required attribute(s) for #{tag} tag: #{required.join(', ')}" if invalid.length > 0
end
end
class Rules
def self.all
@rules ||= []
end
def self.register(rule)
all << rule unless all.include?(rule)
end
def self.process(elements)
elements.map do |e|
rule = find_element_rule(e)
rule.validate(e)
if rule.processor
rule.processor.call(e)
else
"Processing #{rule.tag} with #{rule}"
end
end
end
def self.find_element_rule(element)
rule = all.select{ |r| r.tag.to_s == element.name }
raise "No matching rule found for #{element.name}" unless rule.length > 0
rule.first
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment