Skip to content

Commit b55de9b

Browse files
committed
first commit
0 parents  commit b55de9b

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Orbital Ring
2+

orbital_ring.rb

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
require 'js'
2+
require 'js/require_remote'
3+
require 'erb'
4+
5+
class OrbitalRing
6+
include Singleton
7+
8+
def dir = 'app_root'
9+
10+
class Loader
11+
def self.setup
12+
new.setup OrbitalRing.instance.dir
13+
end
14+
15+
def setup(dir)
16+
Loader.define_const_missing dir, Object
17+
end
18+
19+
private
20+
21+
# const_missingを定義して、見つからない定数をリモートから読み込む
22+
def self.define_const_missing(dir, mod)
23+
mod.define_singleton_method(:const_missing) do |id|
24+
# 定数名をスネークケースに変換して、リモートから読み込む
25+
feature_name = Util.to_snake_case(id)
26+
JS::RequireRemote.instance.load("#{dir}/#{feature_name}")
27+
28+
# 読み込んだモジュールにconst_missingを定義する
29+
loaded_module = const_get(id)
30+
Loader.define_const_missing dir, loaded_module
31+
loaded_module
32+
end
33+
end
34+
end
35+
36+
module Renderer
37+
def self.included(base)
38+
# テンプレートをキャッシュする変数を定義
39+
base.define_method(:tempaltes_cache) { @tempaltes_cache ||= {} }
40+
end
41+
42+
def render(template_name, locals)
43+
tempaltes_cache[template_name] = load_template(template_name) unless tempaltes_cache[template_name]
44+
45+
if(locals[:collection])
46+
# コレクションを渡してテンプレートを呼び出すと
47+
# テンプレートからは、テンプレートと同じ名前の変数を経由してコレクションの個別のメンバーにアクセスできます。
48+
locals[:collection].map do
49+
render_one template_name,
50+
{ template_name.to_s => _1 }
51+
end.join
52+
else
53+
render_one(template_name, locals)
54+
end
55+
end
56+
57+
private
58+
59+
def load_template(template_name)
60+
# テンプレート名から、ファイル名を決定します。
61+
feature_name = "#{Util.to_snake_case(template_name)}.html.erb"
62+
path = "#{OrbitalRing.instance.dir}/templates"
63+
url = "#{path}/#{feature_name}"
64+
response = JS.global.fetch(url).await
65+
raise "Failed to fetch template: #{url}" unless response[:status].to_i == 200
66+
67+
ERB.new(response.text().await.to_s)
68+
end
69+
70+
def render_one(template_name, locals)
71+
# テンプレート内でrenderメソッドを使えるようにするために
72+
# このメソッドのbindingを指定します。
73+
b = binding
74+
locals.each { |key, value| b.local_variable_set key, value }
75+
tempaltes_cache[template_name].result b
76+
end
77+
end
78+
79+
class Routes
80+
Events = ['click', 'change', 'input']
81+
82+
def self.draw(&block)
83+
instance = self.new
84+
instance.instance_eval(&block)
85+
end
86+
87+
def initialize
88+
Events.each do |event_name|
89+
define_event event_name
90+
end
91+
end
92+
93+
private
94+
95+
def define_event(event_name)
96+
self.class.define_method(event_name) do |selectors, options|
97+
root.addEventListener event_name do |event|
98+
if event[:target].closest(selectors) != JS::Null
99+
options[:to].call event, options[:params]
100+
end
101+
end
102+
end
103+
end
104+
105+
def root
106+
document = JS.global[:document]
107+
document.getElementById OrbitalRing.instance.dir
108+
end
109+
end
110+
111+
module Util
112+
def self.to_snake_case(symbol)
113+
symbol.to_s
114+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
115+
.downcase
116+
end
117+
end
118+
end

0 commit comments

Comments
 (0)