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.
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.pre.rc7
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-03-05 00:00:00.000000000 Z
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: '1.2'
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: '1.2'
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: 1.3.1
72
+ version: '0'
221
73
  requirements: []
222
74
  rubygems_version: 3.1.6
223
75
  signing_key:
@@ -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,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'dry-validation'
4
-
5
- # Abstract class for Contract realisation in application
6
- module MvcOne
7
- class ApplicationContract < Dry::Validation::Contract
8
- end
9
- end
@@ -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,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'dry-struct'
4
-
5
- module Types
6
- include Dry.Types()
7
- end
8
-
9
- # Domain model
10
- module MvcOne
11
- class ApplicationModel < Dry::Struct
12
- end
13
- 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