jetski 0.4.7 → 0.4.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59cc948a27a477850ced800437233d2106f046a70eef581011efc407b29469ce
4
- data.tar.gz: 52dee7630e6efac75428fc46a5e18b3c2374323d0d77dd793cb77f3554f994fd
3
+ metadata.gz: 147bd3b0e3d8cbbf54b2a4163fe00af53e3941e99942c6d91324e034aaee7f88
4
+ data.tar.gz: 21042af9af87651f01bc4b3b01ed6bb95d45990abcc9ff6fa1bea68b8b38bd68
5
5
  SHA512:
6
- metadata.gz: 9f5780959202dac7113a038c9793863851147156fcda7d9ca0efa8b837afc8aaeb37f9f65a7ef266e4b3693dd2acfef48e1987f376e869d88640ec2fcad6c19e
7
- data.tar.gz: 76ca2114bc78e15d8fdac21a9f39b137cbf66fa0f3faf45948a245ffdf92722712a9099d55a285cbf0b83f886540b8c02fcc35730a08b91d9e418b2afefd2812
6
+ metadata.gz: 7b045263bc0e38b3e733d0552d7884a5648351a38ba422e8aee9f2604f56d94ef8a9409113aaa377d4828888787587e6b98bc90e6693e7cfcaf63bd5e11a99e6
7
+ data.tar.gz: 6c82897a30e17b21c3b7cb0a626b2cf5240124da8ea197e91c18ff3527e2da93965f456feffcd26c760d40e56534e13c770206de1b712998d2e8c0e4f3496237
data/bin/jetski CHANGED
@@ -5,6 +5,10 @@ require 'optparse'
5
5
  require 'thor'
6
6
  require "pry"
7
7
 
8
+ require_relative './jetski_cli_helpers/generators/controller.rb'
9
+ require_relative './jetski_cli_helpers/generators/model.rb'
10
+ require_relative './jetski_cli_helpers/destroyers/controller.rb'
11
+ require_relative './jetski_cli_helpers/destroyers/model.rb'
8
12
  require_relative './jetski_cli_helpers/shared_methods.rb'
9
13
  require_relative './jetski_cli_helpers/generate.rb'
10
14
  require_relative './jetski_cli_helpers/destroy.rb'
@@ -1,4 +1,3 @@
1
- require 'thor'
2
1
  module JetskiCLIHelpers
3
2
  class Database < Thor
4
3
  include Thor::Actions, JetskiCLIHelpers::SharedMethods,
@@ -1,20 +1,15 @@
1
- require 'thor'
2
1
  module JetskiCLIHelpers
3
2
  class Destroy < Thor
4
- include Thor::Actions
3
+ include Thor::Actions, JetskiCLIHelpers::Destroyers::Controller,
4
+ JetskiCLIHelpers::Destroyers::Model
5
5
  desc "controller NAME ACTION_NAMES", "Destroys a controller"
6
6
  def controller(name, *actions)
7
- controller_file_path = "app/controllers/#{name}_controller.rb"
8
- remove_file(controller_file_path)
9
- view_folder = "app/views/#{name}"
10
- remove_dir(view_folder)
7
+ destroy_controller(name)
11
8
  end
12
9
 
13
10
  desc "model NAME ACTION_NAMES", "Destroys a model"
14
11
  def model(name, *actions)
15
- model_file_path = "app/models/#{name}.rb"
16
- remove_file(controller_file_path)
17
- # TODO: Remove from db.
12
+ destroy_model(name)
18
13
  end
19
14
  end
20
15
  end
@@ -0,0 +1,18 @@
1
+ module JetskiCLIHelpers
2
+ module Destroyers
3
+ module Controller
4
+ def destroy_controller(name)
5
+ pluralized_name = if name[-1] == 's'
6
+ name
7
+ else
8
+ name + 's'
9
+ end
10
+
11
+ controller_file_path = "app/controllers/#{pluralized_name}_controller.rb"
12
+ remove_file(controller_file_path)
13
+ view_folder = "app/views/#{pluralized_name}"
14
+ remove_dir(view_folder)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ module JetskiCLIHelpers
2
+ module Destroyers
3
+ module Model
4
+ def destroy_model(name)
5
+ model_file_path = "app/models/#{name}.rb"
6
+ remove_file(controller_file_path)
7
+ # TODO: Remove from db.
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,52 +1,23 @@
1
- require 'thor'
2
1
  module JetskiCLIHelpers
3
2
  class Generate < Thor
4
3
  include Thor::Actions, JetskiCLIHelpers::SharedMethods,
5
- Jetski::Database::Base
4
+ Jetski::Database::Base, JetskiCLIHelpers::Generators::Controller,
5
+ JetskiCLIHelpers::Generators::Model
6
6
  desc "controller NAME ACTION_NAMES", "Create a controller with matching actions"
7
7
  def controller(name, *actions)
8
- controller_file_path = "app/controllers/#{name}_controller.rb"
9
- create_file controller_file_path
10
- append_to_file controller_file_path, <<~CONTROLLER
11
- class #{name.capitalize}Controller < Jetski::BaseController
12
-
13
- end
14
- CONTROLLER
15
-
16
- actions.each.with_index do |action_name, idx|
17
- action_content = <<~ACTION_CONTENT
18
- def #{action_name}
19
-
20
- end
21
- ACTION_CONTENT
22
- action_nl_seperator = ((idx + 1) != actions.size) ? "\n\n" : ""
23
- insert_into_file(controller_file_path, "#{indent_code(action_content, 1)}#{action_nl_seperator}", before: "\nend")
24
-
25
- if !["create", "create", "update", "destroy"].include?(action_name)
26
- path_to_view = "app/views/#{name}/#{action_name}.html.erb"
27
-
28
- empty_directory("app/views/#{name}")
29
- create_file(path_to_view)
30
- append_to_file path_to_view, <<~EXAMPLEFILE
31
- <h1> #{name}##{action_name} </h1>
32
- <p> edit the content of this page at app/views/#{path_to_view}/#{action_name}.html.erb </p>
33
- EXAMPLEFILE
34
-
35
- say "🌊 View your new page at http://localhost:8000/#{name}/#{action_name}"
36
- end
37
- end
8
+ generate_controller(name, *actions)
38
9
  end
39
10
 
40
11
  desc "model NAME FIELD_NAMES", "Creates a model with matching fields"
41
12
  def model(name, *field_names)
42
- db.execute create_table_sql(table_name: name, field_names: field_names)
43
- model_file_path = "app/models/#{name}.rb"
44
- create_file model_file_path
45
- append_to_file model_file_path, <<~MODEL
46
- class #{name.capitalize} < Jetski::Model
47
-
48
- end
49
- MODEL
13
+ generate_model(name, *field_names)
14
+ end
15
+
16
+ desc "resource NAME FIELD_NAMES", "Creates a resource with model and controller and crud routes"
17
+ def resource(name, *field_names)
18
+ crud_actions = %w(new create show index edit update destroy)
19
+ generate_model(name, *field_names)
20
+ generate_controller(name, *crud_actions)
50
21
  end
51
22
  end
52
23
  end
@@ -0,0 +1,45 @@
1
+ module JetskiCLIHelpers
2
+ module Generators
3
+ module Controller
4
+ def generate_controller(name, *actions)
5
+ pluralized_name = if name[-1] == 's'
6
+ name
7
+ else
8
+ name + 's'
9
+ end
10
+
11
+ formatted_controller_name = pluralized_name.split("_").map(&:capitalize).join
12
+ controller_file_path = "app/controllers/#{pluralized_name}_controller.rb"
13
+ create_file controller_file_path
14
+ append_to_file controller_file_path, <<~CONTROLLER
15
+ class #{formatted_controller_name}Controller < Jetski::BaseController
16
+
17
+ end
18
+ CONTROLLER
19
+
20
+ actions.each.with_index do |action_name, idx|
21
+ action_content = <<~ACTION_CONTENT
22
+ def #{action_name}
23
+
24
+ end
25
+ ACTION_CONTENT
26
+ action_nl_seperator = ((idx + 1) != actions.size) ? "\n\n" : ""
27
+ insert_into_file(controller_file_path, "#{indent_code(action_content, 1)}#{action_nl_seperator}", before: "\nend")
28
+
29
+ if !["create", "create", "update", "destroy"].include?(action_name)
30
+ path_to_view = "app/views/#{pluralized_name}/#{action_name}.html.erb"
31
+
32
+ empty_directory("app/views/#{pluralized_name}")
33
+ create_file(path_to_view)
34
+ append_to_file path_to_view, <<~EXAMPLEFILE
35
+ <h1> #{pluralized_name}##{action_name} </h1>
36
+ <p> edit the content of this page at app/views/#{path_to_view}/#{action_name}.html.erb </p>
37
+ EXAMPLEFILE
38
+
39
+ say "🌊 View your new page at http://localhost:8000/#{pluralized_name}/#{action_name}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ module JetskiCLIHelpers
2
+ module Generators
3
+ module Model
4
+ def generate_model(name, *field_names)
5
+ db.execute create_table_sql(table_name: name, field_names: field_names)
6
+ model_file_path = "app/models/#{name}.rb"
7
+ create_file model_file_path
8
+ append_to_file model_file_path, <<~MODEL
9
+ class #{name.capitalize} < Jetski::Model
10
+
11
+ end
12
+ MODEL
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -1,6 +1,6 @@
1
1
  module Jetski
2
2
  module Autoloader
3
- include Jetski::Router::SharedMethods
3
+ include Jetski::Router::FilePathHelper
4
4
  extend self
5
5
  # Responsibility is to load all models in app.
6
6
  def call
@@ -8,7 +8,12 @@ module Jetski
8
8
  require_relative path_to_model
9
9
  # Call method to define model attributes after loading
10
10
  model_name = path_to_model.split("app/models/")[-1]
11
- .gsub(".rb", "").capitalize
11
+ .gsub(".rb", "")
12
+ .split("/")
13
+ .map(&:capitalize)
14
+ .join("::")
15
+ # posts/comment
16
+ # Post/comment
12
17
  model_class = Object.const_get(model_name)
13
18
  model_class.define_attribute_methods
14
19
  end
@@ -3,11 +3,11 @@ module Jetski
3
3
  class BaseController
4
4
  RESERVED_INSTANCE_VARIABLES = [
5
5
  :@res, :@performed_render, :@action_name,
6
- :@controller_name, :@controller_path, :@cookies, :@root,
7
- :@request_method, :@path
6
+ :@controller_name, :@controller_path, :@cookies
8
7
  ]
9
8
 
10
9
  include ReactiveForm
10
+ extend Jetski::Helpers::RouteHelpers
11
11
  attr_accessor :action_name, :controller_name, :controller_path,
12
12
  :params, :cookies
13
13
  attr_reader :res, :performed_render
@@ -19,8 +19,6 @@ module Jetski
19
19
  end
20
20
 
21
21
  # Method to render matching view with controller_name/action_name
22
- # TODO: Make render available in view as seperate method.
23
-
24
22
  def render(**args)
25
23
  @performed_render = true
26
24
  request_status = args[:status] || 200
@@ -52,17 +50,5 @@ module Jetski
52
50
  def get_cookie(name)
53
51
  cookies&.find { |c| c.name == name.to_s }&.value
54
52
  end
55
-
56
- def is_root?
57
- @root == true
58
- end
59
-
60
- def custom_path
61
- @path
62
- end
63
-
64
- def custom_request_method
65
- @request_method
66
- end
67
53
  end
68
54
  end
@@ -18,7 +18,6 @@ module Jetski
18
18
  _gen_sql += "create table #{pluralized_table_name} (\n"
19
19
 
20
20
  # Default fields on all models
21
-
22
21
  _gen_sql += " created_at datetime,\n"
23
22
  _gen_sql += " updated_at datetime,\n"
24
23
  _gen_sql += " id integer,\n"
@@ -0,0 +1,17 @@
1
+ # This is responsible for methods for routing in base_controller like the route class method
2
+
3
+ module Jetski
4
+ module Helpers
5
+ module RouteHelpers
6
+ def route(method_name, root: false, path: nil, request_method: nil)
7
+ @custom_route_opts ||= {}
8
+ @custom_route_opts[method_name] = {
9
+ method_name: method_name,
10
+ root: root,
11
+ path: path,
12
+ request_method: request_method,
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,9 +2,95 @@ module Jetski
2
2
  module Helpers
3
3
  module ViewHelpers
4
4
  # Expecting a relative path.
5
- def render(partial_path)
6
- path_to_file = File.join(Jetski.app_root, 'app/views', path_to_controller, "_#{partial_path}.html.erb")
7
- File.read(path_to_file)
5
+ def render(partial_path, **locals)
6
+ path_to_file = File.join(Jetski.app_root, 'app/views',
7
+ path_to_controller, "_#{partial_path}.html.erb")
8
+ content = File.read(path_to_file)
9
+ bind = binding
10
+ locals.each do |k, v|
11
+ bind.local_variable_set k, v
12
+ end
13
+ template = ERB.new(content)
14
+ template.result(bind)
15
+ end
16
+
17
+ # link_to "New post", "/posts/new"
18
+ def link_to(link_text, url, **html_opts)
19
+ # TODO: Allow passing block to link_to
20
+ "<a href='#{url}' #{format_html_options(**html_opts)}>#{link_text}</a>"
21
+ end
22
+
23
+ # button_to("Click me", class: "cool-btn")
24
+ def button_to(button_text, url = nil, **html_opts)
25
+ if url
26
+ _method = html_opts[:method] || 'POST'
27
+ # Create form with button inside lol
28
+ _form = "<form action='#{url}' method='#{_method}'>"
29
+ _form += "<button type='submit' #{format_html_options(**html_opts)}>#{button_text}</button>"
30
+ _form += "</form>"
31
+ _form
32
+ else
33
+ _button = "<button #{format_html_options(**html_opts)}>#{button_text}</button>"
34
+ end
35
+ end
36
+
37
+ def input_tag(input_name = nil, **html_opts)
38
+ html_opts[:name] ||= input_name
39
+ "<input #{format_html_options(**html_opts)}>"
40
+ end
41
+
42
+ def label_tag(text, **html_opts)
43
+ "<label #{format_html_options(**html_opts)}>#{text}</label>"
44
+ end
45
+
46
+ def textarea_tag(name = nil, value = nil, **html_opts)
47
+ html_opts[:name] ||= name
48
+ value ||= html_opts[:value]
49
+ "<textarea #{format_html_options(**html_opts.except(:value))}>#{value}</textarea>"
50
+ end
51
+
52
+ def image_tag(image_path, **html_opts)
53
+ abs_url = process_url(image_path)
54
+ "<img src='#{abs_url}' #{format_html_options(**html_opts)}></img>"
55
+ end
56
+
57
+ def favicon_tag(url, **html_opts)
58
+ abs_url = process_url(url)
59
+ "<link rel='icon' type='image/x-icon' #{format_html_options(**html_opts)} href='#{abs_url}'>"
60
+ end
61
+
62
+ def stylesheet_tag(url, **html_opts)
63
+ abs_url = process_url(url)
64
+ "<link rel='stylesheet' #{format_html_options(**html_opts)} href='#{abs_url}'>"
65
+ end
66
+
67
+ def javascript_include_tag(url, **html_opts)
68
+ abs_url = process_url(url)
69
+ "<script src='#{abs_url}' #{format_html_options(**html_opts)}></script>"
70
+ end
71
+
72
+ def javascript_tag(**html_opts)
73
+ "<script #{format_html_options(**html_opts)}>#{yield}</script>"
74
+ end
75
+
76
+ def truncate(text, limit)
77
+ text[0..limit]
78
+ end
79
+
80
+ def format_html_options(**html_opts)
81
+ html_opts.map do |k, v|
82
+ formatted_key = k.to_s.gsub("_", "-")
83
+ "#{formatted_key}='#{v}'"
84
+ end.join(" ")
85
+ end
86
+ private
87
+ def process_url(url)
88
+ # Need to ensure urls start with / to avoid relative requests
89
+ if url[0] == '/'
90
+ url
91
+ else
92
+ "/#{url}"
93
+ end
8
94
  end
9
95
  end
10
96
  end
data/lib/jetski/model.rb CHANGED
@@ -3,16 +3,13 @@ module Jetski
3
3
  extend Jetski::Database::Base
4
4
 
5
5
  def initialize(**args)
6
- # TODO: Need to fix code
7
- # Cannot redefine methods every time we initialize a new object.
8
- # need to define available methods on post when loading model
9
6
  @virtual_attributes = args
10
7
  end
11
8
 
12
9
  def inspect
13
10
  post_obj_id = object_id
14
- inspect_str = "#<Post:#{post_obj_id}"
15
- self.class.model_attributes.each do |attribute_name|
11
+ inspect_str = "#<#{self.class.to_s}:#{post_obj_id}"
12
+ self.class.attributes.each do |attribute_name|
16
13
  attribute_value = @virtual_attributes[attribute_name]
17
14
  inspect_str += " #{attribute_name}=\"#{attribute_value}\""
18
15
  end
@@ -30,7 +27,13 @@ module Jetski
30
27
  end
31
28
 
32
29
  class << self
33
- def create(**args)
30
+ def create(hash_args = nil, **key_args)
31
+ args = if hash_args && hash_args.is_a?(Hash)
32
+ hash_args
33
+ else
34
+ key_args
35
+ end
36
+
34
37
  return puts "#{table_name.capitalize}.create was called with no args" if args.size == 0
35
38
  data_values = args.map { |k,v| v }
36
39
  key_names = args.map { |k, v| k }
@@ -66,7 +69,7 @@ module Jetski
66
69
  end
67
70
 
68
71
  def define_attribute_methods
69
- model_attributes.each do |attribute|
72
+ attributes.each do |attribute|
70
73
  define_method attribute do
71
74
  @virtual_attributes[attribute]
72
75
  end
@@ -91,6 +94,7 @@ module Jetski
91
94
  end
92
95
 
93
96
  def attributes
97
+ # TODO: Find a more performant way to get the column names from a table
94
98
  columns, *rows = db.execute2( "select * from #{pluralized_table_name}" )
95
99
  columns
96
100
  end
@@ -102,6 +106,12 @@ module Jetski
102
106
  def first
103
107
  format_model_obj(pluck_rows.first)
104
108
  end
109
+
110
+ def find(id)
111
+ id_as_integer = id.to_i
112
+ columns, *rows = db.execute2( "select * from #{pluralized_table_name} WHERE id=?", id_as_integer)
113
+ format_model_obj(rows.last, columns)
114
+ end
105
115
 
106
116
  def table_name
107
117
  self.to_s.downcase
@@ -114,11 +124,6 @@ module Jetski
114
124
  table_name + "s"
115
125
  end
116
126
  end
117
-
118
- def model_attributes
119
- attributes.concat(["id", "created_at", "updated_at"])
120
- end
121
-
122
127
  private
123
128
  def format_model_obj(row, columns = nil)
124
129
  return unless row
@@ -1,6 +1,6 @@
1
1
  module Jetski
2
2
  class Router
3
- module SharedMethods
3
+ module FilePathHelper
4
4
  def controller_file_paths
5
5
  Dir.glob([File.join(Jetski.app_root, 'app', 'controllers', '**', '*_controller.rb')])
6
6
  end
@@ -0,0 +1,58 @@
1
+ module Jetski
2
+ class Router
3
+ module Host
4
+ class Base
5
+ attr_reader :server, :errors, :served_url, :request_method, :req, :res,
6
+ :controller_classname, :controller_file_name, :controller_path,
7
+ :controller_name, :action_name, :controller_class, :all_server_options
8
+
9
+ attr_writer :res, :req
10
+
11
+ def initialize(server, **server_options)
12
+ @server = server
13
+ @errors = []
14
+ @all_server_options = server_options
15
+ @served_url = server_options[:url]
16
+ @request_method = server_options[:method]
17
+ @controller_file_name = server_options[:controller_file_name]
18
+ @controller_path = server_options[:controller_path]
19
+ @controller_classname = server_options[:controller_classname]
20
+ @controller_name = server_options[:controller_name]
21
+ @action_name = server_options[:action_name]
22
+ end
23
+
24
+ def call
25
+ server.mount_proc served_url do |req, res|
26
+ @req = req
27
+ @res = res
28
+ check_request_url
29
+ yield
30
+ if errors.any?
31
+ res.body = errors.join(", ")
32
+ end
33
+ end
34
+ end
35
+ protected
36
+ def fetch_controller_class
37
+ path_to_defined_controller = File.join(Jetski.app_root, "app/controllers/#{controller_file_name}")
38
+ require_relative path_to_defined_controller
39
+ begin
40
+ @controller_class = Object.const_get(controller_classname)
41
+ rescue NameError
42
+ @errors << "#{controller_classname} is not defined. Please create a file app/controllers/#{controller_file_name}"
43
+ end
44
+ end
45
+ private
46
+
47
+ def check_request_url
48
+ if req.request_uri.path != served_url
49
+ # Silently fail to avoid printing error to page
50
+ res.status = 404
51
+ res.body = "Not Found"
52
+ #@errors << "Wrong url was used for request. Bad url: #{req.request_uri}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,57 @@
1
+ module Jetski
2
+ class Router
3
+ module Host
4
+ class Controller < Base
5
+ # Responsibility is to host the route with methods to route url to controller action
6
+ # URL -> Controller#Action
7
+ # Uses controller class name and action name to serve request
8
+
9
+ def initialize(server, **server_options)
10
+ super(server, **server_options)
11
+ end
12
+
13
+ def call
14
+ super do
15
+ fetch_controller_class if errors.empty?
16
+ call_controller if errors.empty?
17
+ end
18
+ end
19
+
20
+ def call_controller
21
+ controller = controller_class.new(res)
22
+ controller.action_name = action_name
23
+ controller.controller_name = controller_name
24
+ controller.controller_path = controller_path
25
+ params_hash = {}
26
+ id_crud_actions = ["show", "edit", "destroy"]
27
+ if id_crud_actions.include?(action_name)
28
+ # Need to set id value from url. if available.
29
+ auto_id_param = req.path.split("#{controller_path}/")[-1].split("/")[0]
30
+ params_hash[:id] ||= auto_id_param
31
+ end
32
+ if req.body
33
+ parsed_body = parse_body(req.body, req.content_type)
34
+ params_hash = parsed_body.merge(params_hash)
35
+ end
36
+ controller.params = OpenStruct.new(params_hash)
37
+ controller.cookies = req.cookies
38
+ controller.send(action_name)
39
+ if !controller.performed_render && (request_method.upcase == "GET")
40
+ controller.render
41
+ end
42
+ end
43
+
44
+ def parse_body(body, content_type = '')
45
+ case content_type
46
+ when "application/x-www-form-urlencoded"
47
+ Rack::Utils.parse_nested_query body
48
+ when "application/json"
49
+ JSON.parse(body)
50
+ else
51
+ body
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,73 @@
1
+ module Jetski
2
+ class Router
3
+ module Host
4
+ class Crud < Base
5
+ # Responsible for hosting auto crud routes
6
+ attr_reader :custom_route_options
7
+ attr_accessor :handle_controller_render
8
+ def initialize(server, controller_routes, **server_options)
9
+ server_options[:url] = server_options[:controller_path]
10
+ super(server, **server_options)
11
+ @handle_controller_render = true
12
+ end
13
+
14
+ def call
15
+ super do
16
+ @custom_route_options = all_server_options.dup.except(:action_name, :method)
17
+ determine_action_from_url
18
+ if handle_controller_render
19
+ @controller_host = Jetski::Router::Host::Controller.new(server, **custom_route_options)
20
+ @controller_host.res = res
21
+ @controller_host.req = req
22
+ @controller_host.fetch_controller_class
23
+ @controller_host.call_controller
24
+ end
25
+ end
26
+ end
27
+ private
28
+ def determine_action_from_url
29
+ # TODO: Handle checking for url params.
30
+ req_path = req.request_uri.path
31
+ custom_route_options.tap do |opts|
32
+ case req_path
33
+ when controller_path # /posts
34
+ # check request method for create action
35
+ if req.request_method == "POST"
36
+ opts[:action_name] = "create"
37
+ opts[:method] = "POST"
38
+ else
39
+ opts[:action_name] = "index"
40
+ opts[:method] = "GET"
41
+ end
42
+ when "#{controller_path}/new"
43
+ opts[:action_name] = "new"
44
+ opts[:method] = "GET"
45
+ else
46
+ url_param = req_path.split("#{controller_path}/")[-1]
47
+ case
48
+ when url_param.match(/\d(\/edit)/)
49
+ # Edit page
50
+ opts[:action_name] = "edit"
51
+ opts[:method] = "GET"
52
+ when url_param.match(/\d\z/)
53
+ # matches only id 5 with no additional characters
54
+ # Determine if show/update/destroy from request_method
55
+ opts[:method] = req.request_method
56
+ case req.request_method
57
+ when "GET"
58
+ opts[:action_name] = "show"
59
+ when "PUT"
60
+ opts[:action_name] = "update"
61
+ when "DELETE"
62
+ opts[:action_name] = "destroy"
63
+ end
64
+ else
65
+ handle_controller_render = false
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,7 +1,7 @@
1
1
  module Jetski
2
2
  class Router
3
3
  module Parser
4
- include Jetski::Router::SharedMethods
4
+ include Jetski::Router::FilePathHelper
5
5
  extend self
6
6
  def compile_routes
7
7
  auto_found_routes = []
@@ -20,16 +20,32 @@ module Jetski
20
20
  action_names = controller_class.instance_methods(false)
21
21
  base_opts = {
22
22
  controller_classname: controller_classname,
23
- controller_file_name: controller_file_name,
24
23
  controller_name: controller_name,
25
24
  controller_path: controller_path,
25
+ controller_file_name: controller_file_name,
26
26
  }
27
+ route_opts_hash = controller_class.instance_variable_get(:@custom_route_opts) || {}
27
28
  action_names.each do |action_name|
28
29
  action_name = action_name.to_s
30
+ route_opts = route_opts_hash.fetch(action_name.to_sym, {})
31
+ custom_request_method = route_opts.fetch(:request_method, nil)
32
+ is_root = route_opts.fetch(:root, nil)
33
+ custom_path = route_opts.fetch(:path, nil)
34
+
35
+ url_to_use = proc do |url|
36
+ if is_root
37
+ "/"
38
+ elsif custom_path
39
+ custom_path
40
+ else
41
+ url
42
+ end
43
+ end
44
+
29
45
  case action_name
30
46
  when "new"
31
47
  auto_found_routes << base_opts.merge({
32
- url: controller_path + "/new",
48
+ url: url_to_use.call(controller_path + "/new"),
33
49
  method: "GET",
34
50
  action_name: action_name,
35
51
  })
@@ -63,11 +79,13 @@ module Jetski
63
79
  method: "DELETE",
64
80
  action_name: action_name,
65
81
  })
82
+ when "index"
83
+ auto_found_routes << base_opts.merge({
84
+ url: url_to_use.call(controller_path),
85
+ method: "GET",
86
+ action_name: action_name,
87
+ })
66
88
  else
67
- tmp_controller_instance = controller_class.new("")
68
- tmp_controller_instance.send(action_name)
69
- is_root = tmp_controller_instance.is_root?
70
- custom_path = tmp_controller_instance.custom_path
71
89
  url_to_use = if is_root
72
90
  "/"
73
91
  elsif custom_path
@@ -76,7 +94,6 @@ module Jetski
76
94
  url_friendly_action_name = action_name.split("_").join("-")
77
95
  controller_path + "/#{url_friendly_action_name}"
78
96
  end
79
- custom_request_method = tmp_controller_instance.custom_request_method
80
97
 
81
98
  auto_found_routes << base_opts.merge({
82
99
  url: url_to_use,
data/lib/jetski/router.rb CHANGED
@@ -1,60 +1,38 @@
1
1
  module Jetski
2
2
  class Router
3
3
  include Parser
4
- attr_reader :server
4
+ attr_reader :server, :routes, :crud_routes
5
5
  def initialize(server)
6
6
  @server = server
7
+ @crud_routes = []
7
8
  end
8
9
 
9
10
  def call
10
- host_routes && host_assets
11
+ browser_support
12
+ fetch_routes
13
+ host_routes
14
+ host_crud_routes
15
+ host_assets
11
16
  end
12
17
 
13
18
  def host_routes
14
- routes = compile_routes
19
+ crud_actions = %w(new create show index edit update destroy)
15
20
  routes.each do |af_route|
16
- served_url = af_route[:url]
17
- request_method = af_route[:method]
18
- controller_classname = af_route[:controller_classname]
19
- controller_name = af_route[:controller_name]
20
- action_name = af_route[:action_name]
21
- controller_file_name = af_route[:controller_file_name]
22
- controller_path = af_route[:controller_path]
23
-
24
- server.mount_proc served_url do |req, res|
25
- errors = []
26
- if (request_method!= req.request_method)
27
- errors << "Wrong request was performed"
28
- end
29
- if errors.empty?
30
- path_to_defined_controller = File.join(Jetski.app_root, "app/controllers/#{controller_file_name}")
31
- require_relative path_to_defined_controller
32
- begin
33
- controller_class = Object.const_get(controller_classname)
34
- rescue NameError
35
- errors << "#{controller_classname} is not defined. Please create a file app/controllers/#{controller_file_name}"
36
- end
37
- end
38
-
39
- if errors.empty?
40
- controller = controller_class.new(res)
41
- controller.action_name = action_name
42
- controller.controller_name = controller_name
43
- controller.controller_path = controller_path
44
- if req.body
45
- controller.params = parse_body(req.body, req.content_type)
46
- end
47
- controller.cookies = req.cookies
48
- controller.send(action_name)
49
- if !controller.performed_render && (request_method.upcase == "GET")
50
- controller.render
51
- end
52
- end
53
-
54
- if errors.any?
55
- res.body = errors.join(", ")
56
- end
21
+ if crud_actions.include?(af_route[:action_name]) && (af_route[:url] != '/')
22
+ @crud_routes << af_route
23
+ next
24
+ # We need to have only one server block for routes with handle crud enabled
57
25
  end
26
+ Host::Controller.new(server, **af_route).call
27
+ end
28
+ end
29
+
30
+ def host_crud_routes
31
+ # TODO: Build server block to handle custom crud routes
32
+ crud_routes_for_controller = crud_routes.group_by { |route| route[:controller_path] }
33
+ crud_routes_for_controller.each do |controller_path, controller_routes|
34
+ # TODO: Implement base level server block and checking.
35
+ Host::Crud.new(server, controller_routes, **controller_routes.first).call
58
36
  end
59
37
  end
60
38
 
@@ -107,16 +85,16 @@ module Jetski
107
85
  res.body = File.read(File.join(__dir__, 'frontend/reactive_form.js'))
108
86
  end
109
87
  end
110
- private
111
- def parse_body(body, content_type = '')
112
- case content_type
113
- when "application/x-www-form-urlencoded"
114
- Rack::Utils.parse_nested_query body
115
- when "application/json"
116
- OpenStruct.new(JSON.parse(body))
117
- else
118
- body
88
+
89
+ # routes to help browser default requests etc. prevent breakage
90
+ def browser_support
91
+ server.mount_proc "/favicon.ico" do |req, res|
92
+ res.status = 204 # No Content
119
93
  end
120
94
  end
95
+ private
96
+ def fetch_routes
97
+ @routes ||= compile_routes
98
+ end
121
99
  end
122
100
  end
@@ -1,3 +1,3 @@
1
1
  module Jetski
2
- VERSION = "0.4.7"
2
+ VERSION = "0.4.9"
3
3
  end
@@ -13,7 +13,9 @@ module Jetski
13
13
 
14
14
  def call
15
15
  res.content_type = "text/html"
16
- view_render = perform_view_render&.gsub("\n</head>", "#{content_for_head}\n</head>")
16
+ _rendered_view = perform_view_render
17
+ sanitized_view_render = _rendered_view.split("\n").map(&:strip).join("\n")
18
+ view_render = sanitized_view_render.gsub("\n</head>", "#{content_for_head}\n</head>")
17
19
  return error_screen if errors.any?
18
20
  res.body = view_render
19
21
  end
@@ -24,9 +26,9 @@ module Jetski
24
26
  end
25
27
 
26
28
  def perform_view_render
27
- process_erb(File.read(File.join(views_folder, "layouts/application.html.erb"))) do
28
- process_erb(File.read(File.join(views_folder, path_to_controller, "#{action_name}.html.erb")))
29
- end
29
+ template_content = File.read(template_path)
30
+ layout_content = File.read(layout_path)
31
+ process_erb(layout_content) { process_erb(template_content) }
30
32
  end
31
33
 
32
34
  def process_erb(content)
@@ -37,6 +39,9 @@ module Jetski
37
39
  grab_instance_variables
38
40
  template.result(binding)
39
41
  rescue => e
42
+ # TODO: Add a better error screen like rails show a snapshot of the template and get the line number of error
43
+ # Also using template error doesnt account for errors inside of partials so need a new way of getting this
44
+ @errors << "Error in #{local_template_path}"
40
45
  @errors << e
41
46
  nil
42
47
  end
@@ -86,6 +91,18 @@ module Jetski
86
91
  File.join(Jetski.app_root, 'app/assets')
87
92
  end
88
93
 
94
+ def layout_path
95
+ File.join(views_folder, "layouts/application.html.erb")
96
+ end
97
+
98
+ def template_path
99
+ File.join(views_folder, local_template_path)
100
+ end
101
+
102
+ def local_template_path
103
+ File.join(path_to_controller, "#{action_name}.html.erb")
104
+ end
105
+
89
106
  def path_to_controller
90
107
  controller_path[1..-1]
91
108
  end
data/lib/jetski.rb CHANGED
@@ -6,17 +6,21 @@ require "rack"
6
6
  require "sqlite3"
7
7
 
8
8
  require_relative './jetski/version'
9
- require_relative './jetski/frontend/reactive_form'
10
9
  require_relative './jetski/helpers/view_helpers'
10
+ require_relative './jetski/helpers/route_helpers'
11
+ require_relative './jetski/helpers/delegatable'
12
+ require_relative './jetski/frontend/reactive_form'
11
13
  require_relative './jetski/base_controller'
12
- require_relative './jetski/router/shared_methods'
14
+ require_relative './jetski/router/file_path_helper'
13
15
  require_relative './jetski/router/parser'
16
+ require_relative './jetski/router/host/base'
17
+ require_relative './jetski/router/host/controller'
18
+ require_relative './jetski/router/host/crud'
14
19
  require_relative './jetski/router'
15
20
  require_relative './jetski/autoloader'
16
21
  require_relative './jetski/server'
17
22
  require_relative './jetski/database/base'
18
23
  require_relative './jetski/model'
19
- require_relative './jetski/helpers/delegatable'
20
24
  require_relative './jetski/view_renderer'
21
25
 
22
26
  module Jetski
@@ -1,5 +1,5 @@
1
1
  class PagesController < Jetski::BaseController
2
+ route :home, root: true
2
3
  def home
3
- @root = true
4
4
  end
5
5
  end
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title> APP_NAME </title>
7
- <link rel="icon" type="image/x-icon" href="/jetski-logo.png">
7
+ <%= favicon_tag "jetski-logo.png" %>
8
8
  </head>
9
9
  <body>
10
10
  <%= yield %>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jetski
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Indigo Tech Tutorials
@@ -118,7 +118,11 @@ files:
118
118
  - bin/jetski
119
119
  - bin/jetski_cli_helpers/database.rb
120
120
  - bin/jetski_cli_helpers/destroy.rb
121
+ - bin/jetski_cli_helpers/destroyers/controller.rb
122
+ - bin/jetski_cli_helpers/destroyers/model.rb
121
123
  - bin/jetski_cli_helpers/generate.rb
124
+ - bin/jetski_cli_helpers/generators/controller.rb
125
+ - bin/jetski_cli_helpers/generators/model.rb
122
126
  - bin/jetski_cli_helpers/shared_methods.rb
123
127
  - lib/jetski.rb
124
128
  - lib/jetski/autoloader.rb
@@ -127,11 +131,15 @@ files:
127
131
  - lib/jetski/frontend/reactive_form.js
128
132
  - lib/jetski/frontend/reactive_form.rb
129
133
  - lib/jetski/helpers/delegatable.rb
134
+ - lib/jetski/helpers/route_helpers.rb
130
135
  - lib/jetski/helpers/view_helpers.rb
131
136
  - lib/jetski/model.rb
132
137
  - lib/jetski/router.rb
138
+ - lib/jetski/router/file_path_helper.rb
139
+ - lib/jetski/router/host/base.rb
140
+ - lib/jetski/router/host/controller.rb
141
+ - lib/jetski/router/host/crud.rb
133
142
  - lib/jetski/router/parser.rb
134
- - lib/jetski/router/shared_methods.rb
135
143
  - lib/jetski/server.rb
136
144
  - lib/jetski/version.rb
137
145
  - lib/jetski/view_renderer.rb