-
Notifications
You must be signed in to change notification settings - Fork 4
/
lotus.rb
155 lines (126 loc) · 3.31 KB
/
lotus.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
require 'lotus/router'
require 'lotus/controller'
require 'lotus/view'
require 'lotus/model'
module FullStackPatch
def response
[ super, self ].flatten
end
def format
Rack::Mime::MIME_TYPES.invert[content_type].gsub(/\A\./, '').to_sym
end
def to_rendering
exposures.merge(format: format)
end
end
Lotus::Action::Rack.class_eval do
prepend FullStackPatch
end
module Lotus
class Application
attr_accessor :router
def initialize(renderer = RenderingPolicy.new)
@renderer = renderer
@mappers = {}
@adapters = {}
end
def setup_router(&block)
@router = Lotus::Router.new(&block)
end
def setup_mapper(name, &block)
mapper = Lotus::Model::Mapper.new(&block)
mapper.load!
@mappers[name.to_sym] = mapper
end
def setup_adapter(&block)
initializer = AdapterInitializer.new(self, &block)
@adapters[initializer.adapter_name] = initializer.adapter
end
def mapper(name)
@mappers[name.to_sym]
end
def call(env)
_call(env).tap do |response|
@renderer.render(response)
end
end
private
def _call(env)
env['HTTP_ACCEPT'] ||= 'text/html'
@router.call(env)
end
end
class RenderingPolicy
def render(response)
if render?(response)
action = response.pop
view = view_for(action)
response[2] = Array(view.render(action.to_rendering))
else
response[2] = [] unless response[2].respond_to? :each
end
end
private
def render?(response)
case response.first
# 1xx have no body by definition
when 100..199 then return false
# 204 No Content
# 304 Not Modified
when 204, 304 then return false
# Redirects: it doesn't make sense to render views for these
when 301, 302, 307, 308 then return false
# Don't try to render views for all server errors
when 500..599 then return false
when 404 then return false
end
response.last.respond_to?(:to_rendering)
end
def view_for(action)
Object.const_get(action.class.name.gsub(/Controller/, ''))
end
end
class AdapterInitializer
attr_reader :adapter
def initialize(application, &block)
instance_eval(&block)
mapper = application.mapper(@mapper)
uri = ENV.fetch(@database) if @database
@adapter = @type.new(mapper, uri)
# is there a better way to access it?
@collections = mapper.collections
assign_attributes
assign_adapter
end
def adapter_name
@name
end
private
def name(name)
@name = name.to_sym
end
def type(type)
@type = type
end
def mapper(mapper)
@mapper = mapper.to_sym
end
def database(database)
@database = database.to_s
end
def assign_attributes
@collections.each do |name, collection|
collection.entity.attributes = collection.attributes.keys - Array(collection.identity)
end
end
def assign_adapter
repositories = @collections.map { |name, collection|
repository_name = "#{collection.entity.name}#{Lotus::Model::Mapping::Collection::REPOSITORY_SUFFIX}"
Object.const_get(repository_name)
}
repositories.each do |repository|
repository.adapter = @adapter
end
end
end
end