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.
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