mvc_one 0.1.0.pre.rc7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|