Last active
August 3, 2020 18:48
-
-
Save serradura/1e36a87bf0dc66dfdc05878089b74c0f to your computer and use it in GitHub Desktop.
ui-component (ActiveView::Component like)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<% if @bar %> | |
<p><%= yield %></p> | |
<% end %> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<% if @baz %> | |
<%|= @bar.render do %> | |
<span><%= yield %></span> | |
<span><%= @baz %></span> | |
<%| end %> | |
<% end %> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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