Skip to content

Instantly share code, notes, and snippets.

@danieldocki
Forked from serradura/u-ui.rb
Created April 28, 2022 12:09
Show Gist options
  • Select an option

  • Save danieldocki/ca81f8f67cdf9a30a2bd7f38111378d6 to your computer and use it in GitHub Desktop.

Select an option

Save danieldocki/ca81f8f67cdf9a30a2bd7f38111378d6 to your computer and use it in GitHub Desktop.
UI (UI::Component)
class UComponent2
module DataAccessor
def data=(value)
@data = value
end
def data; @data; end
end
def self.fn(&block)
new(block)
end
def self.call(data = {})
new.call(data)
end
def self.to_proc
-> (data = {}) { call(data) }
end
def self.template(&block)
define_method(:__template) { block }
end
def self.defaults(data = {})
define_method(:__defaults) { data }
end
def initialize(fn = nil)
@fn = fn || __template
@defaults = respond_to?(:__defaults) ? __defaults : {}
end
def call(data)
builder = Nokogiri::HTML::Builder.new
builder.context = @builder
builder.extend(DataAccessor)
builder.data = apply_defaults_to(data)
builder.instance_eval(&@fn)
builder.to_html.sub!(/<!DOCTYPE.*[^>]/, '')
end
def to_proc
-> (data) { call(data) }
end
private
def apply_defaults_to(data)
return @defaults.merge(data) if data.is_a?(Hash)
data || @defaults
end
end
class HelloWorldV2 < UComponent2
template do
span.bar.foo! {
text("Hello World")
}
end
end
HelloWorldV2.call
class GreetV2 < UComponent2
defaults name: 'John Doe'
template do
span.bar.foo! {
text("Hello #{data[:name]}")
}
end
end
GreetV2.call
GreetV2.call name: 'Rodrigo'
[{name: 'Rodrigo'}, {name: 'Talita'}, {}].map(&GreetV2)
class NumberV2 < UComponent2
template do
strong { text(data) }
end
end
NumberV2.call 1
[1,2,3,4].map(&NumberV2)
number_v2 = UComponent2.fn do
strong { text(data) }
end
number_v2.call 1
[1,2,3,4].map(&number_v2)
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!(/<!DOCTYPE.*[^>]/, '')
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
#=> "<span class=\"bold\">Hello world</span>\n"
HelloWorld2.call message: 'Olá mundo'
#=> "<span class=\"bold\">Ol&aacute; mundo</span>\n"
UComponent.call -> doc { doc.span.bold { doc.text("Hello world") } }
#=> "<span class=\"bold\">Hello world</span>\n"
UComponent.call(
-> doc, message { doc.span.bold { doc.text(message) } },
'Olá mundo'
)
#=> "<span class=\"bold\">Ol&aacute; mundo</span>\n"
Greet.call
#=> "<span class=\"bar\" id=\"foo\">Hello John Doe</span>\n"
Greet.call name: 'Serradura'
#=> "<span class=\"bar\" id=\"foo\">Hello Serradura</span>\n"
[{name: 'Rodrigo'}, {name: 'Talita'}, {}].map(&Greet)
#=> ["<span class=\"bar\" id=\"foo\">Hello Rodrigo</span>\n", "<span class=\"bar\" id=\"foo\">Hello Talita</span>\n", "<span class=\"bar\" id=\"foo\">Hello John Doe</span>\n"]
greet = UComponent.new(-> (doc, name:) do
doc.span.bar.foo! {
doc.text("Hello #{name}")
}
end)
greet.call(name: 'Bella')
#=> "<span class=\"bar\" id=\"foo\">Hello Bella</span>\n"
[{name: 'Rodrigo'}, {name: 'Talita'}].map(&greet)
#=> ["<span class=\"bar\" id=\"foo\">Hello Rodrigo</span>\n", "<span class=\"bar\" id=\"foo\">Hello Talita</span>\n"]
number = UComponent.new(-> (doc, n) do
doc.strong { doc.text(n) }
end)
[1,2,3,4].map(&number)
#=> ["<strong>1</strong>\n", "<strong>2</strong>\n", "<strong>3</strong>\n", "<strong>4</strong>\n"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment