Created
January 21, 2021 23:19
-
-
Save delonnewman/d0d5f3607bd6b3ac0603b8894da05b40 to your computer and use it in GitHub Desktop.
This file contains 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 'stringio' | |
require 'erb' | |
class Event | |
end | |
class MorphList | |
include Enumerable | |
def self.empty | |
new([]) | |
end | |
def initialize(morphs) | |
@morphs = morphs | |
end | |
def each(&block) | |
@morphs.each(&block) | |
self | |
end | |
def remove(morph) | |
@morphs.delete(morph) | |
end | |
def <<(morph) | |
@morphs << morph | |
end | |
def size | |
@morphs.size | |
end | |
end | |
class SubmorphEvent < Event | |
attr_reader :owner, :morph | |
def initialize(owner:, morph:) | |
@owner = owner | |
@morph = morph | |
end | |
end | |
class MorphRemovedEvent < SubmorphEvent | |
def call | |
owner.world.render | |
end | |
end | |
class MorphAddedEvent < SubmorphEvent | |
def call | |
owner.world.render | |
end | |
end | |
class Morph | |
include Enumerable | |
attr_reader :submorphs | |
attr_accessor :owner, :world, :name, :position, :extent | |
def initialize(name: nil, position: nil, extent: nil, owner: nil, world: nil, submorphs: MorphList.empty) | |
@ower = owner if owner | |
@world = world if world | |
@name = name if name | |
@position = position if position | |
@extent = extent if extent | |
@submorphs = submorphs | |
@events = [] | |
end | |
def in_world? | |
[email protected]? | |
end | |
def submorph_count | |
@submorphs.size | |
end | |
def each_submorph(&block) | |
@submorphs.each(&block) | |
self | |
end | |
alias_method :each, :each_submorph | |
def each_morph(&block) | |
block.call(self) | |
each_submorph(&block) | |
end | |
def delete! | |
owner.remove_morph(self) if owner | |
self | |
end | |
def add_morph!(morph) | |
@submorphs << morph | |
morph.owner = self | |
morph.world = world | |
trigger_event!(MorphAddedEvent.new(owner: self, morph: morph)) | |
end | |
def remove_morph!(morph) | |
morph.owner = nil | |
@submorphs.remove(morph) | |
trigger_event!(MorphRemovedEvent.new(owner: self, morph: morph)) | |
end | |
def trigger_event!(event) | |
@events << event | |
end | |
def proccess_events_now | |
events = @events.dup | |
@events = [] | |
events.each do |event| | |
event.call | |
end | |
end | |
def copy | |
new(owner: @owner, world: @world) | |
end | |
def deep_copy | |
new(owner: @owner, world: @world, submorphs: @submorphs) | |
end | |
def render | |
raise 'not implmented' | |
end | |
end | |
class Point | |
def self.[](x, y) | |
new(x: x, y: y) | |
end | |
def initialize(x:, y:) | |
@x = x | |
@y = y | |
end | |
def to_s | |
"#{x}@#{y}" | |
end | |
alias_method :inspect, :to_s | |
end | |
class WorldState < Morph | |
def initialize(**args) | |
super(**args.merge(world: self)) | |
end | |
def render | |
reduce(StringIO.new) do |buffer, morph| | |
buffer.write(morph.render) | |
buffer | |
end.string | |
end | |
end | |
class HTML5Document < Morph | |
TEMPLATE = <<~HTML | |
<!doctype html> | |
<html lang="en"> | |
<head> | |
<!-- Required meta tags --> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<!-- Bootstrap CSS --> | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> | |
<title><%= title %></title> | |
</head> | |
<body> | |
<% each_submorph do |morph| %> | |
<%= morph.render %> | |
<% end %> | |
<!-- Optional JavaScript; choose one of the two! --> | |
<!-- Option 1: Bootstrap Bundle with Popper --> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> | |
<!-- Option 2: Separate Popper and Bootstrap JS --> | |
<!-- | |
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script> | |
--> | |
</body> | |
</html> | |
HTML | |
attr_reader :title | |
def intialize(title:) | |
@title = title | |
end | |
def render | |
ERB.new(TEMPLATE).result(binding) | |
end | |
end | |
module Bootstrap5 | |
class Container < Morph | |
def render | |
buffer = StringIO.new | |
each_submorph do |morph| | |
buffer.write(morph.render) | |
end | |
"<div class=\"container\">#{buffer.string}</div>" | |
end | |
end | |
class Row < Morph | |
def render | |
end | |
end | |
class Element < Morph | |
def element_id | |
"element-#{object_id}" | |
end | |
def render | |
"<div id=\"#{element_id}\">#{name || element_id}</div>" | |
end | |
end | |
end | |
World = WorldState.new | |
document = HTML5Document.new(title: 'Test Application') | |
World.add_morph!(document) | |
container = Bootstrap5::Container.new | |
container.add_morph!(Bootstrap5::Element.new(name: 'test')) | |
document.add_morph!(container) | |
puts World.render |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment