class UComponent
def self.defaults
{}
end
def self.build(_doc, _options)
raise NotImplementedError
end
def self.call(*args)
fn = args[0].is_a?(Proc) ? args[0] : method(:build)
options = args[0].is_a?(Hash) ? args[0] : (args[1] || {})
new.call(options, fn)
end
def self.to_proc
-> (*args) { call(*args) }
end
def initialize(fn = nil)
@fn = fn
end
def call(opt = {}, fn = nil)
func = @fn || fn
options = opt.is_a?(Hash) ? self.class.defaults.merge(opt) : opt
builder = Nokogiri::HTML::Builder.new do |doc|
func.arity == 1 ? func.(doc) : func.(doc, options)
end
builder.to_html.sub!(/]/, '')
end
def to_proc
-> (options) { call(options) }
end
end
class HelloWorld < UComponent
def self.build(doc)
doc.span.bold {
doc.text("Hello world")
}
end
end
class HelloWorld2 < UComponent
def self.build(doc, message:)
doc.span.bold {
doc.text(message)
}
end
end
class Greet < UComponent
def self.defaults
{ name: 'John Doe' }
end
def self.build(doc, name:)
doc.span.bar.foo! {
doc.text("Hello #{name}")
}
end
end
# == Examples ==
HelloWorld.call
#=> "Hello world\n"
HelloWorld2.call message: 'Olá mundo'
#=> "Olá mundo\n"
UComponent.call -> doc { doc.span.bold { doc.text("Hello world") } }
#=> "Hello world\n"
UComponent.call(
-> doc, message { doc.span.bold { doc.text(message) } },
'Olá mundo'
)
#=> "Olá mundo\n"
Greet.call
#=> "Hello John Doe\n"
Greet.call name: 'Serradura'
#=> "Hello Serradura\n"
[{name: 'Rodrigo'}, {name: 'Talita'}, {}].map(&Greet)
#=> ["Hello Rodrigo\n", "Hello Talita\n", "Hello John Doe\n"]
greet = UComponent.new(-> (doc, name:) do
doc.span.bar.foo! {
doc.text("Hello #{name}")
}
end)
greet.call(name: 'Bella')
#=> "Hello Bella\n"
[{name: 'Rodrigo'}, {name: 'Talita'}].map(&greet)
#=> ["Hello Rodrigo\n", "Hello Talita\n"]
number = UComponent.new(-> (doc, n) do
doc.strong { doc.text(n) }
end)
[1,2,3,4].map(&number)
#=> ["1\n", "2\n", "3\n", "4\n"]