Skip to content

Instantly share code, notes, and snippets.

@serradura
Last active August 3, 2020 18:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save serradura/1e36a87bf0dc66dfdc05878089b74c0f to your computer and use it in GitHub Desktop.
Save serradura/1e36a87bf0dc66dfdc05878089b74c0f to your computer and use it in GitHub Desktop.
ui-component (ActiveView::Component like)
<% if @bar %>
<p><%= yield %></p>
<% end %>
require_relative 'ui-component'
require_relative 'foo'
class Bar < UI::Component
def initialize(bar:)
@bar = bar
end
end
# result = Bar.new(bar: true).render do
# Foo[foo: true]
# end
# puts result
<% if @baz %>
<%|= @bar.render do %>
<span><%= yield %></span>
<span><%= @baz %></span>
<%| end %>
<% end %>
require_relative 'ui-component'
require_relative 'bar'
class Baz < UI::Component
attr_reader :baz, :bar
validates! :baz, :bar, presence: true
def initialize(baz:, bar:)
@baz = baz
@bar = bar
end
end
bar = Bar.new(bar: true)
result = Baz.new(baz: :ok, bar: bar).render do
Foo.render(foo: true)
end
puts result
puts
puts '-------------'
puts
bar = Bar.new(bar: true)
result = Baz.render(baz: nil, bar: bar) do
Foo[foo: true]
end
puts result
require_relative 'ui-component'
class Foo < UI::Component
TEMPLATE = <<-HTML
<% if @foo %>
<h1>OK!</h1>
<% end %>
HTML
def initialize(foo:)
@foo = foo
end
end
# puts Foo.new(foo: 1).call
require_relative 'ui-component'
class Ul < UI::Component
TEMPLATE = <<-HTML
<ul><%= yield.join %></ul>
HTML
def initialize(*); end
end
class Ol < UI::Component
TEMPLATE = <<-HTML
<ol><%= @items %></ol>
HTML
def initialize(items)
@items = items.join
end
end
class Li < UI::Component
TEMPLATE = <<-HTML
<% if @foo %>
<li><%= @foo %></li>
<% end %>
HTML
def initialize(foo:)
@foo = foo
end
end
items_data = [{foo: 1}, {foo: nil}, {foo: 2}]
html = Ul.render { items_data.map(&Li) }
puts html
puts
puts '-------------'
puts
puts items_data.map(&Li).then(&Ol)
puts
puts '-------------'
puts
puts Ol.render(items_data.map(&Li))
puts Ol[items_data.map(&Li)]
puts
puts '-------------'
puts
items = items_data.map(&Li)
html2 = Ol[items]
puts html2
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'erubi', '~> 1.8'
gem 'activemodel', '~> 3.2', '>= 3.2.20'
gem 'u-thenable', '~> 1.0', '>= 1.0.1', require: 'u-thenable-ext'
end
require 'erubi'
require 'erubi/capture_end'
require 'active_model'
module UI
class Component
include ActiveModel::Validations
def self.template
filename = instance_method(:initialize).source_location[0]
raise NotImplementedError.new("Subclasses of UI::Component must implement #initialize") if filename == __FILE__
return const_get(:TEMPLATE) if const_defined?(:TEMPLATE)
filename_without_extension = filename[0..-(File.extname(filename).length + 1)]
erb_template_path = filename_without_extension+".html.erb"
if File.file?(erb_template_path)
File.read(erb_template_path)
else
raise NotImplementedError.new("Could not find template, expected #{erb_template_path} to define it")
end
end
def self.compile
@compiled ||= nil
return if @compiled
class_eval(
"private def build; " +
Erubi::CaptureEndEngine.new(template).src +
"; end"
)
@compiled = true
end
def self.render(arg = nil, &block)
component = new(arg)
block ? component.render(&block) : component.render
end
class << self
alias_method :call, :render
end
def self.[](arg)
render(arg)
end
def self.to_proc
-> (arg = nil) { self[arg] }
end
def initialize(*); end
def render(&block)
self.class.compile
run_validations!
block ? build(&block) : build
end
alias_method :call, :render
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment