# Represents standard HTML attributes, such as class="myclass"
class HTMLAttributes
attr_reader :content
def initialize(new = nil)
@content = {}
self << new
end
def [](key)
@content[key.to_sym]
end
def to_s
return_string = ''
@content.each_pair do |k, v|
# If an attribute has no values, we need to introduce an empty string to
# the array in order to get the correct format (alt="", for example):
v << '' if v.empty?
return_string << "#{k}=\"#{v.join ' '}\" "
end
return_string.strip
end
# This is the only way we add new attributes. Flexible about what you give
# it-- accepts both strings and symbols for the keys, and both strings and
# arrays for the values.
def <<(new)
# Don't break everything if this is passed an empty value:
return self unless new
if new.is_a? Hash
add_hash(new)
else
add_string(new)
end
self
end
def delete(trash)
# accepts an array or a single element
[trash].flatten
.map(&:to_sym)
.each { |k| @content.delete k }
self
end
def replace(new)
formatted_new = if new.is_a? String
hashify_input(new)
else
new.transform_keys(&:to_sym)
end
delete formatted_new.keys
add_hash formatted_new
self
end
def empty?
@content.empty?
end
def method_missing(method, arg = nil)
if method[-1] == '='
raise 'must supply new value' unless arg
replace(method[0..-2] => arg)
elsif @content.key? method
@content[method].join(' ')
else
super
end
end
def respond_to_missing?(method, include_private = false)
(method[-1] == '=') ||
(@content.key? method) ||
super
end
private
def add_string(new_string)
add_hash hashify_input new_string
end
# Input: Keys are attribute names (either strings or symbols), values are
# attribute values (either a string or an array of strings)
def add_hash(new_hash)
formatted_new = {}
new_hash.each_pair do |k, v|
v = v.split(' ') if v.is_a? String
formatted_new[k.to_sym] = v
end
@content.merge!(formatted_new) do |_key, oldval, newval|
oldval.concat(newval)
end
self
end
def hashify_input(new_string)
# looking for something like:
# 'class="something something-else" id="my-id" alt=""'
new_hash = {}
new_string.scan(/ ?([^="]+)="([^"]*)"/).each do |match|
# Returns something like:
# [['class','something something-else'],['id','my-id'],['alt', '']]
key, val = *match
if new_hash[key]
new_hash[key] << ' ' + val
else
new_hash[key] = val
end
end
new_hash
end
end