mvc_one 0.1.0.pre.rc7 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.idea/mvc_one.iml +5 -33
- data/.rubocop.yml +9 -32
- data/CHANGELOG.md +0 -1
- data/Gemfile +6 -7
- data/Gemfile.lock +3 -89
- data/Rakefile +3 -3
- data/exe/mvc_one +7 -86
- data/lib/mvc_one/version.rb +1 -1
- data/lib/mvc_one.rb +3 -3
- data/mvc_one.gemspec +15 -25
- metadata +8 -156
- data/lib/mvc_one/application.rb +0 -56
- data/lib/mvc_one/contracts/application_contract.rb +0 -9
- data/lib/mvc_one/controllers/application_controller.rb +0 -75
- data/lib/mvc_one/models/application_model.rb +0 -13
- data/lib/mvc_one/regexp_router.rb +0 -131
- data/lib/mvc_one/repositories/application_relation.rb +0 -37
- data/lib/mvc_one/repositories/application_repository.rb +0 -20
- data/lib/mvc_one/serializers/application_serializer.rb +0 -143
- data/lib/mvc_one/views/404.slim +0 -12
- data/templates/app/application_layout.slim +0 -9
- data/templates/app/controller_template.erb +0 -50
- data/templates/app/model_template.erb +0 -5
- data/templates/app/welcome_controller_rb.erb +0 -7
- data/templates/app/welcome_index.slim +0 -2
- data/templates/config/routes_rb.erb +0 -12
- data/templates/general/application_rb.erb +0 -7
- data/templates/general/config_ru.erb +0 -11
- data/templates/general/database_yml.erb +0 -12
- data/templates/general/gemfile.erb +0 -7
- data/templates/general/rakefile.erb +0 -75
- data/templates/general/secrets_yml.erb +0 -4
metadata
CHANGED
@@ -1,155 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mvc_one
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evgenii Sendziuk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bcrypt
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '3.1'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '3.1'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: dry-struct
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.5'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1.5'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: dry-transaction
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.14'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0.14'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: dry-validation
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.9'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.9'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rack
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '3'
|
76
|
-
type: :runtime
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '3'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rack-session
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '2'
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '2'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: sequel
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '5.60'
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '5.60'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: slim
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '5'
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '5'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: sqlite3
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - "~>"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '1.5'
|
132
|
-
type: :runtime
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - "~>"
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '1.5'
|
139
13
|
- !ruby/object:Gem::Dependency
|
140
14
|
name: thor
|
141
15
|
requirement: !ruby/object:Gem::Requirement
|
142
16
|
requirements:
|
143
|
-
- - "
|
17
|
+
- - ">="
|
144
18
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
19
|
+
version: '0'
|
146
20
|
type: :runtime
|
147
21
|
prerelease: false
|
148
22
|
version_requirements: !ruby/object:Gem::Requirement
|
149
23
|
requirements:
|
150
|
-
- - "
|
24
|
+
- - ">="
|
151
25
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
26
|
+
version: '0'
|
153
27
|
description: Simple mvc framework, not for production purposes
|
154
28
|
email:
|
155
29
|
- evgeniisendziuk@taxdome.com
|
@@ -173,37 +47,15 @@ files:
|
|
173
47
|
- Rakefile
|
174
48
|
- exe/mvc_one
|
175
49
|
- lib/mvc_one.rb
|
176
|
-
- lib/mvc_one/application.rb
|
177
|
-
- lib/mvc_one/contracts/application_contract.rb
|
178
|
-
- lib/mvc_one/controllers/application_controller.rb
|
179
|
-
- lib/mvc_one/models/application_model.rb
|
180
|
-
- lib/mvc_one/regexp_router.rb
|
181
|
-
- lib/mvc_one/repositories/application_relation.rb
|
182
|
-
- lib/mvc_one/repositories/application_repository.rb
|
183
|
-
- lib/mvc_one/serializers/application_serializer.rb
|
184
50
|
- lib/mvc_one/version.rb
|
185
|
-
- lib/mvc_one/views/404.slim
|
186
51
|
- mvc_one.gemspec
|
187
52
|
- sig/mvc_one.rbs
|
188
|
-
- templates/app/application_layout.slim
|
189
|
-
- templates/app/controller_template.erb
|
190
|
-
- templates/app/model_template.erb
|
191
|
-
- templates/app/welcome_controller_rb.erb
|
192
|
-
- templates/app/welcome_index.slim
|
193
|
-
- templates/config/routes_rb.erb
|
194
|
-
- templates/general/application_rb.erb
|
195
|
-
- templates/general/config_ru.erb
|
196
|
-
- templates/general/database_yml.erb
|
197
|
-
- templates/general/gemfile.erb
|
198
|
-
- templates/general/rakefile.erb
|
199
|
-
- templates/general/secrets_yml.erb
|
200
53
|
homepage:
|
201
54
|
licenses:
|
202
55
|
- MIT
|
203
56
|
metadata:
|
204
57
|
source_code_uri: https://github.com/senzpo/mvc_one.git
|
205
58
|
changelog_uri: https://github.com/senzpo/mvc_one.git
|
206
|
-
rubygems_mfa_required: 'true'
|
207
59
|
post_install_message:
|
208
60
|
rdoc_options: []
|
209
61
|
require_paths:
|
@@ -215,9 +67,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
215
67
|
version: 2.6.0
|
216
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
217
69
|
requirements:
|
218
|
-
- - "
|
70
|
+
- - ">="
|
219
71
|
- !ruby/object:Gem::Version
|
220
|
-
version:
|
72
|
+
version: '0'
|
221
73
|
requirements: []
|
222
74
|
rubygems_version: 3.1.6
|
223
75
|
signing_key:
|
data/lib/mvc_one/application.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'yaml'
|
4
|
-
require 'rack'
|
5
|
-
require 'rack/session'
|
6
|
-
|
7
|
-
module MvcOne
|
8
|
-
# Rack friendly launcher for project
|
9
|
-
class Application
|
10
|
-
# Main application config
|
11
|
-
class Config
|
12
|
-
def self.env
|
13
|
-
ENV.fetch('APP_ENV', 'development')
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.test?
|
17
|
-
env == 'test'
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.secrets
|
21
|
-
YAML.load_file('config/secrets.yml')[Application::Config.env]
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.db_config
|
25
|
-
YAML.load_file('config/database.yml')[Application::Config.env]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def initialize
|
30
|
-
@router = RegexpRouter.new(File.join('app', 'config', 'routes.rb'))
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.launch
|
34
|
-
Rack::Builder.new do |builder|
|
35
|
-
builder.use Rack::Session::Cookie, domain: 'localhost', path: '/', expire_after: 3600 * 24,
|
36
|
-
secret: Application::Config.secrets['session_cookie']
|
37
|
-
builder.run Application.new
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def call(env)
|
42
|
-
request = Rack::Request.new(env)
|
43
|
-
result = @router.resolve(request.path, request.request_method)
|
44
|
-
controller = result.controller.new(env, result.params, request)
|
45
|
-
controller.resolve(result.action)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
require_relative 'regexp_router'
|
51
|
-
require_relative 'contracts/application_contract'
|
52
|
-
require_relative 'controllers/application_controller'
|
53
|
-
require_relative 'models/application_model'
|
54
|
-
require_relative 'repositories/application_relation'
|
55
|
-
require_relative 'repositories/application_repository'
|
56
|
-
require_relative 'serializers/application_serializer'
|
@@ -1,75 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'slim/include'
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
# All app controllers must be subclasses of ApplicationController
|
7
|
-
module MvcOne
|
8
|
-
class ApplicationController
|
9
|
-
DEFAULT_LAYOUT = './app/views/application_layout.slim'
|
10
|
-
DEFAULT_HTTP_CODE = 200
|
11
|
-
|
12
|
-
attr_accessor :env
|
13
|
-
attr_reader :action, :params, :request
|
14
|
-
|
15
|
-
def self.before_action(*methods)
|
16
|
-
define_method :before_action do
|
17
|
-
methods.each { |method| send(method) }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def initialize(env, params, request)
|
22
|
-
@env = env
|
23
|
-
@params = params
|
24
|
-
@request = request
|
25
|
-
end
|
26
|
-
|
27
|
-
def resolve(action)
|
28
|
-
before_action if respond_to?(:before_action)
|
29
|
-
|
30
|
-
@action = action
|
31
|
-
send(action)
|
32
|
-
end
|
33
|
-
|
34
|
-
def render(code: DEFAULT_HTTP_CODE, headers: {}, body: nil, layout: DEFAULT_LAYOUT, template: nil)
|
35
|
-
return [code, headers, [body]] unless body.nil?
|
36
|
-
|
37
|
-
body = prepare_body(layout, template || template_path(action))
|
38
|
-
[code, headers, [body]]
|
39
|
-
end
|
40
|
-
|
41
|
-
def head(code, headers: {})
|
42
|
-
[code, headers, []]
|
43
|
-
end
|
44
|
-
|
45
|
-
def request_params
|
46
|
-
return @request_params if defined?(@request_params)
|
47
|
-
return @request_params = {} if request.body.nil?
|
48
|
-
|
49
|
-
@request_params =
|
50
|
-
case request.content_type
|
51
|
-
when 'application/json' then JSON.parse(request.body.read).transform_keys(&:to_sym)
|
52
|
-
else request.params.transform_keys(&:to_sym)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def render_partial(name, options = {}, &block)
|
57
|
-
Slim::Template.new("#{name}.slim", options).render(self, &block)
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def template_path(action)
|
63
|
-
path = self.class.to_s.delete_suffix('Controller').split('::').map(&:downcase).join('/')
|
64
|
-
"./app/views/#{path}/#{action}.slim"
|
65
|
-
end
|
66
|
-
|
67
|
-
def prepare_body(layout, template)
|
68
|
-
return Slim::Template.new(template).render(self) if layout.nil?
|
69
|
-
|
70
|
-
Slim::Template.new(layout).render(self) do
|
71
|
-
Slim::Template.new(template).render(self)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,131 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Simple router based on dsl
|
4
|
-
# lambda do
|
5
|
-
# get '/users/:id', to: 'web#users#show'
|
6
|
-
# post '/users', to: 'web#users#create'
|
7
|
-
# end
|
8
|
-
# get, post, delete, etc - HTTP methods
|
9
|
-
# '/user', '/users/:id' - regexp, :id - params, available with result
|
10
|
-
# to: 'web#users#create' - route request to Web::UsersController create method
|
11
|
-
module MvcOne
|
12
|
-
class RegexpRouter
|
13
|
-
HTTP_METHODS = %w[get post patch put delete options head].freeze
|
14
|
-
|
15
|
-
# concrete route
|
16
|
-
class Route
|
17
|
-
ANY_METHOD = 'any'
|
18
|
-
attr_reader :controller, :action, :pattern, :method
|
19
|
-
|
20
|
-
def initialize(controller:, action:, pattern:, method:)
|
21
|
-
@controller = controller
|
22
|
-
@action = action
|
23
|
-
@pattern = pattern
|
24
|
-
@method = method
|
25
|
-
end
|
26
|
-
|
27
|
-
def matched?(path, http_method)
|
28
|
-
return true if method == ANY_METHOD
|
29
|
-
return false unless method.to_s == http_method.to_s
|
30
|
-
|
31
|
-
pattern_split = pattern.split('/')
|
32
|
-
path_split = path.split('/')
|
33
|
-
return false if pattern_split.length != path_split.length
|
34
|
-
|
35
|
-
pattern_matched_with?(pattern_split, path_split)
|
36
|
-
end
|
37
|
-
|
38
|
-
def params(path)
|
39
|
-
pattern_split = pattern.split('/')
|
40
|
-
path_split = path.split('/')
|
41
|
-
|
42
|
-
result = {}
|
43
|
-
|
44
|
-
pattern_split.each_with_index do |e, index|
|
45
|
-
if e.start_with?(':')
|
46
|
-
key = e.delete(':').to_sym
|
47
|
-
result[key] = path_split[index]
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
result
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def pattern_matched_with?(pattern_split, path_split)
|
57
|
-
matched = true
|
58
|
-
pattern_split.each_with_index do |e, index|
|
59
|
-
next if e.start_with?(':')
|
60
|
-
|
61
|
-
if e != path_split[index]
|
62
|
-
matched = false
|
63
|
-
break
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
matched
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# result of searching right route, has controller, action, params from path
|
72
|
-
class Result
|
73
|
-
attr_reader :route, :path
|
74
|
-
|
75
|
-
def initialize(route, path)
|
76
|
-
@route = route
|
77
|
-
@path = path
|
78
|
-
end
|
79
|
-
|
80
|
-
def controller
|
81
|
-
instance_eval "#{route.controller}Controller", __FILE__, __LINE__ # Return class of matched controller
|
82
|
-
end
|
83
|
-
|
84
|
-
def action
|
85
|
-
route.action
|
86
|
-
end
|
87
|
-
|
88
|
-
def params
|
89
|
-
route.params(path)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
attr_reader :routes
|
94
|
-
|
95
|
-
def initialize(route_path)
|
96
|
-
@routes = []
|
97
|
-
load_routes(route_path)
|
98
|
-
end
|
99
|
-
|
100
|
-
def resolve(path, method)
|
101
|
-
route = routes.find { |r| r.matched?(path, method.downcase) }
|
102
|
-
|
103
|
-
Result.new(route, path) if route
|
104
|
-
end
|
105
|
-
|
106
|
-
private
|
107
|
-
|
108
|
-
def load_routes(route_path)
|
109
|
-
return unless File.file?(route_path)
|
110
|
-
|
111
|
-
instance_eval(File.read(route_path), route_path.to_s).call
|
112
|
-
end
|
113
|
-
|
114
|
-
HTTP_METHODS.each do |method|
|
115
|
-
define_method method do |pattern, options|
|
116
|
-
register_route(method, pattern, options)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def any(to:)
|
121
|
-
register_route('any', '', to: to)
|
122
|
-
end
|
123
|
-
|
124
|
-
def register_route(method, pattern, options)
|
125
|
-
path_pieces = options[:to].split('#')
|
126
|
-
controller = path_pieces.slice(0..-2).map(&:capitalize).join('::')
|
127
|
-
action = path_pieces.last
|
128
|
-
@routes << Route.new(controller: controller, action: action, pattern: pattern, method: method)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Base relation object
|
4
|
-
module MvcOne
|
5
|
-
class ApplicationRelation
|
6
|
-
def self.wrap(klass)
|
7
|
-
define_method :wrapped_class do
|
8
|
-
instance_eval klass.to_s.capitalize, __FILE__, __LINE__ # Return wrapped class
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
attr_reader :target, :attributes
|
13
|
-
|
14
|
-
def initialize(attributes)
|
15
|
-
raise 'Please define wrapped class with wrap class method' unless respond_to?(:wrapped_class)
|
16
|
-
|
17
|
-
@target = wrapped_class.new(attributes)
|
18
|
-
@attributes = attributes
|
19
|
-
end
|
20
|
-
|
21
|
-
def method_missing(method)
|
22
|
-
target.send(method)
|
23
|
-
end
|
24
|
-
|
25
|
-
def respond_to?(method)
|
26
|
-
methods.include?(method) || target.respond_to?(method)
|
27
|
-
end
|
28
|
-
|
29
|
-
def respond_to_missing?(method)
|
30
|
-
target.respond_to_missing?(method)
|
31
|
-
end
|
32
|
-
|
33
|
-
def class
|
34
|
-
target.class
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'sequel'
|
4
|
-
|
5
|
-
# Main gateway for persisted storage
|
6
|
-
module MvcOne
|
7
|
-
class ApplicationRepository
|
8
|
-
class NotFoundRecord < StandardError; end
|
9
|
-
|
10
|
-
attr_reader :table_name
|
11
|
-
|
12
|
-
def self.db_config
|
13
|
-
Application::Config.db_config
|
14
|
-
end
|
15
|
-
|
16
|
-
DB = Sequel.connect(db_config['db']['connection_line'])
|
17
|
-
DB.loggers << Logger.new($stdout)
|
18
|
-
DB.sql_log_level = :debug
|
19
|
-
end
|
20
|
-
end
|
@@ -1,143 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# All app serializers must be subclasses of ApplicationSerializer
|
4
|
-
module MvcOne
|
5
|
-
class ApplicationSerializer
|
6
|
-
class << self
|
7
|
-
def attributes(*args)
|
8
|
-
define_method :attributes do
|
9
|
-
args
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def type(type)
|
14
|
-
define_method :type do
|
15
|
-
type.to_s
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def id
|
20
|
-
raise ArgumentError, 'No block given' unless block_given?
|
21
|
-
|
22
|
-
define_method :id do
|
23
|
-
yield data
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def links
|
28
|
-
raise ArgumentError, 'No block given' unless block_given?
|
29
|
-
|
30
|
-
define_method :links do
|
31
|
-
yield data
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def has_one(relation)
|
36
|
-
raise ArgumentError, 'No block given' unless block_given?
|
37
|
-
|
38
|
-
define_method relation do
|
39
|
-
yield data
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
attr_reader :data
|
45
|
-
|
46
|
-
def initialize(data, include: [])
|
47
|
-
@data = data
|
48
|
-
@include = include
|
49
|
-
end
|
50
|
-
|
51
|
-
def serialize
|
52
|
-
result = {}
|
53
|
-
if data.is_a?(Enumerable)
|
54
|
-
result[:data] = data.map { |e| self.class.new(e, include: @include).serialize_data }
|
55
|
-
included = data.flat_map { |e| self.class.new(e, include: @include).included_serialization }.compact
|
56
|
-
result[:included] = included if included.any?
|
57
|
-
else
|
58
|
-
result[:data] = data_serialization
|
59
|
-
result[:included] = included_serialization if included_serialization
|
60
|
-
end
|
61
|
-
result
|
62
|
-
end
|
63
|
-
|
64
|
-
def serialize_data
|
65
|
-
data_serialization
|
66
|
-
end
|
67
|
-
|
68
|
-
def data_serialization
|
69
|
-
raise NoMethodError if data.is_a?(Enumerable)
|
70
|
-
|
71
|
-
result = {}
|
72
|
-
add_type(result)
|
73
|
-
add_id(result)
|
74
|
-
add_attributes(result)
|
75
|
-
add_links(result)
|
76
|
-
add_relatioship(result)
|
77
|
-
result
|
78
|
-
end
|
79
|
-
|
80
|
-
def included_serialization
|
81
|
-
return nil if @include.empty?
|
82
|
-
|
83
|
-
@include.map do |include|
|
84
|
-
raise(NoMethodError, "Undefined #{include} include") unless respond_to?(include)
|
85
|
-
|
86
|
-
send(include)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
def add_relatioship(result)
|
93
|
-
result[:relationships] = {} unless @include.empty?
|
94
|
-
@include.each do |include|
|
95
|
-
raise(NoMethodError, "Undefined #{include} include") unless respond_to?(include)
|
96
|
-
|
97
|
-
included_entity = send(include)
|
98
|
-
included_relationship = {}
|
99
|
-
included_relationship[:data] = included_entity.slice(:id, :type)
|
100
|
-
result[:relationships][include] = included_relationship
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def add_links(result)
|
105
|
-
result[:links] = links if respond_to?(:links)
|
106
|
-
end
|
107
|
-
|
108
|
-
def add_type(result)
|
109
|
-
result[:type] = respond_to?(:type) ? type : default_type
|
110
|
-
end
|
111
|
-
|
112
|
-
def add_id(result)
|
113
|
-
result[:id] = respond_to?(:id) ? id : default_id
|
114
|
-
end
|
115
|
-
|
116
|
-
def add_attributes(result)
|
117
|
-
return unless respond_to?(:attributes)
|
118
|
-
|
119
|
-
result_attributes = attributes.each_with_object({}) do |attr, acc|
|
120
|
-
acc[attr] = get_attribute(attr)
|
121
|
-
end
|
122
|
-
result[:attributes] = result_attributes
|
123
|
-
end
|
124
|
-
|
125
|
-
def default_type
|
126
|
-
data.class.to_s.downcase
|
127
|
-
end
|
128
|
-
|
129
|
-
def default_id
|
130
|
-
data.id.to_s
|
131
|
-
end
|
132
|
-
|
133
|
-
def get_attribute(attr)
|
134
|
-
if respond_to?(attr)
|
135
|
-
send(attr)
|
136
|
-
elsif data.respond_to?(attr)
|
137
|
-
data.send(attr)
|
138
|
-
else
|
139
|
-
raise NoMethodError, "Undefined serialize key #{attr}"
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|