jets 2.1.0 → 2.1.1

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: 7210442948a1180913859f3afbd0aebb049560adfdf53faf02357c4f299bb246
4
- data.tar.gz: b94be0bc50ec242e9c6e908050a4ddd342874e9026cdf12f28ae54e465d12303
3
+ metadata.gz: 82e56d77408579a757373a115134668315a2c47fdbcd297f8eae827951274f6a
4
+ data.tar.gz: 0152fbf8fe291033319761e987667026a77958b67398ba237d9152cc70a00615
5
5
  SHA512:
6
- metadata.gz: 95f6b7c61d0867b09c6af7f099fc84ec3de07defec86707f8aaadc8aac2da318557260b828142133384350163bd0bcbccc0a0f5bd204eb1c2645be0791e9637e
7
- data.tar.gz: 0cb91a7f2593103a557a59f0d3d8b2732f9ba196725ed2825d12b34db2f2879e72bff137e8193411aecb0e31522c704bacbf2bbf9b5329242dad514655f38b5d
6
+ metadata.gz: f638230df0a341ee7b4e0a73355a89a650a78178d7ebb46326c4215d40ea4d33d6648a3d0909a98789e416b4c03c59bae8b5c8e5a94e254c45de78915e5214c4
7
+ data.tar.gz: 5a9e606725ae25d18c3ce4b1ea901780d7062245035c20a9d5139566b0e92ab998d9c3e6d2bb14081a5e77c04bfa5bb871ed95db51ac48467c42f186292b82ab
@@ -3,6 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## [2.1.1]
7
+ - #347 Add documentation about torch vs. warm
8
+ - #348 Provide another minimal privileges example
9
+ - #349 Fix route params for specs
10
+ - #350 Fix config.autoload_paths setting
11
+ - remove the jets c warning
12
+
6
13
  ## [2.1.0]
7
14
  - #345 upgrade to use rails 6 components
8
15
 
@@ -13,8 +13,9 @@ class Jets::Application
13
13
 
14
14
  def setup!
15
15
  load_default_config
16
- autoload_paths = config.autoload_paths + config.extra_autoload_paths
17
- setup_auto_load_paths(autoload_paths)
16
+ setup_autoload_paths
17
+ setup_ignore_paths
18
+ main_loader_setup
18
19
  end
19
20
 
20
21
  def configs!
@@ -99,14 +100,29 @@ class Jets::Application
99
100
  end
100
101
  end
101
102
 
102
- def setup_auto_load_paths(autoload_paths=default_autoload_paths)
103
- loader = Jets::Autoloaders.main
103
+ def main_loader
104
+ Jets::Autoloaders.main
105
+ end
106
+
107
+ def setup_autoload_paths
108
+ autoload_paths = default_autoload_paths + config.autoload_paths
104
109
  autoload_paths.each do |path|
105
110
  next unless File.exist?(path)
106
- loader.push_dir(path)
111
+ main_loader.push_dir(path)
107
112
  end
108
- loader.enable_reloading if Jets.env.development?
109
- loader.setup
113
+ end
114
+
115
+ # Allow use to add config.ignore_paths just in case there's some case Jets hasn't considered
116
+ def setup_ignore_paths
117
+ ignore_paths = default_ignore_paths + config.ignore_paths
118
+ ignore_paths.each do |path|
119
+ main_loader.ignore("#{Jets.root}/#{path}")
120
+ end
121
+ end
122
+
123
+ def main_loader_setup
124
+ main_loader.enable_reloading if Jets.env.development?
125
+ main_loader.setup # only respected on the first call
110
126
  end
111
127
 
112
128
  def each_app_autoload_path(expression)
@@ -54,8 +54,8 @@ class Jets::Application
54
54
  config = ActiveSupport::OrderedOptions.new
55
55
  config.project_name = parse_project_name # must set early because other configs requires this
56
56
  config.cors = false
57
- config.autoload_paths = default_autoload_paths
58
- config.extra_autoload_paths = []
57
+ config.autoload_paths = [] # allows for customization
58
+ config.ignore_paths = [] # allows for customization
59
59
  config.logger = Jets::Logger.new($stderr)
60
60
 
61
61
  # function properties defaults
@@ -176,5 +176,12 @@ class Jets::Application
176
176
 
177
177
  paths
178
178
  end
179
+
180
+ def default_ignore_paths
181
+ %w[
182
+ app/functions
183
+ app/shared/functions
184
+ ]
185
+ end
179
186
  end
180
187
  end
@@ -27,7 +27,8 @@ module Jets
27
27
  Zeitwerk::Loader.new.tap do |loader|
28
28
  loader.tag = "jets.main"
29
29
  # loader.inflector = Inflector.new # TODO: allow custom app inflector
30
- loader.ignore("#{Jets.root}/app/shared/functions")
30
+ # The main loader is configured later on in Jets::Application#setup_autoload_paths
31
+ # because it needs access to Jets.root and Jets.config settings
31
32
  end
32
33
  end
33
34
  memoize :main
@@ -11,7 +11,7 @@ class Jets::Booter
11
11
 
12
12
  Jets.application.setup!
13
13
 
14
- # Turbines are loaded after setup_auto_load_paths in Jets.application.setup! Some Turbine options are defined
14
+ # Turbines are loaded after setup_autoload_paths in Jets.application.setup! Some Turbine options are defined
15
15
  # in the project so setup must happen before internal Turbines are loaded.
16
16
  load_internal_turbines
17
17
 
@@ -25,7 +25,7 @@ class Jets::Booter
25
25
 
26
26
  setup_db # establish db connections in Lambda Execution Context.
27
27
  # The eager load calls connects_to in models and establish those connections in Lambda Execution Context also.
28
- Jets::Autoloaders.main.eager_load # Eager load project code. Rather have user find out early than later on AWS Lambda.
28
+ eager_load
29
29
 
30
30
  # TODO: Figure out how to build middleware during Jets.boot without breaking jets new and webpacker:install
31
31
  # build_middleware_stack
@@ -33,6 +33,22 @@ class Jets::Booter
33
33
  @booted = true
34
34
  end
35
35
 
36
+ def eager_load
37
+ preload_extensions
38
+ Jets::Autoloaders.main.eager_load # Eager load project code. Rather have user find out early than later on AWS Lambda.
39
+ end
40
+
41
+ def preload_extensions
42
+ base_path = "#{Jets.root}/app/extensions"
43
+ Dir.glob("#{base_path}/**/*.rb").each do |path|
44
+ next unless File.file?(path)
45
+
46
+ class_name = path.sub("#{base_path}/", '').sub(/\.rb/,'').camelize
47
+ klass = class_name.constantize # autoload
48
+ Jets::Lambda::Functions.extend(klass)
49
+ end
50
+ end
51
+
36
52
  # Using ActiveRecord outside of Rails, so we need to set up the db connection ourself.
37
53
  #
38
54
  # Only connects to database for ActiveRecord and when config/database.yml exists.
@@ -78,8 +78,7 @@ class Jets::CLI
78
78
 
79
79
  # jets generate is a special command requires doesn't puts out the help menu automatically when
80
80
  # `jets generate` is called without additional args. We'll take it over early and fix it here.
81
- autocomplete_command = Jets::Commands::Base.autocomplete(args[0])
82
- generate = autocomplete_command == "generate"
81
+ generate = full_command == "generate"
83
82
 
84
83
  if generate && ((args.size == 1 || help_flags.include?(args.last)) || args.size == 2)
85
84
  puts Jets::Generator.help
@@ -138,7 +138,6 @@ class Jets::Commands::Base < Thor
138
138
  def eager_load!
139
139
  return if Jets::Turbo.afterburner?
140
140
 
141
- Jets.application.setup_auto_load_paths # in case an app/extension is defined
142
141
  Jets::Autoloaders.once.eager_load
143
142
  end
144
143
  memoize :eager_load!
@@ -12,7 +12,7 @@ Jets.application.configure do
12
12
  <% end -%>
13
13
 
14
14
  # config.env_extra = 2 # can also set this with JETS_ENV_EXTRA
15
- # config.extra_autoload_paths = []
15
+ # config.autoload_paths = []
16
16
 
17
17
  # config.asset_base_url = 'https://cloudfront.domain.com/assets' # example
18
18
 
@@ -14,6 +14,7 @@ module Jets::Commands
14
14
  inject_csrf_meta_tags
15
15
  update_crud_js
16
16
  update_config_application_rb
17
+ update_autoload_paths_config
17
18
  puts "Upgrade complete."
18
19
  end
19
20
 
@@ -75,5 +76,30 @@ module Jets::Commands
75
76
  IO.write(app_rb, content)
76
77
  puts "Update: #{app_rb} with default_protect_from_forgery"
77
78
  end
79
+
80
+ def update_autoload_paths_config
81
+ app_rb = "config/application.rb"
82
+ lines = IO.readlines(app_rb)
83
+
84
+ new_config = lines.find { |l| l.include?('config.autoload_paths') }
85
+ return if new_config
86
+
87
+ old_config = lines.find { |l| l.include?('config.extra_autoload_paths') }
88
+ return unless old_config
89
+
90
+ lines.map! do |line|
91
+ md = line.match(/config\.extra_autoload_paths(.*)/)
92
+ if md
93
+ rest = md[1]
94
+ " config.autoload_paths#{rest}"
95
+ else
96
+ line
97
+ end
98
+ end
99
+
100
+ content = lines.join
101
+ IO.write(app_rb, content)
102
+ puts "Update: #{app_rb} with config.autoload_paths"
103
+ end
78
104
  end
79
105
  end
@@ -5,102 +5,18 @@ class Jets::Controller::Middleware::Local
5
5
  end
6
6
 
7
7
  def find_route
8
- reset_routes!
9
- # Precedence:
10
- # 1. Routes with no captures get highest precedence: posts/new
11
- # 2. Then we consider the routes with captures: post/:id
12
- #
13
- # Within these 2 groups we consider the routes with the longest path first
14
- # since posts/:id and posts/:id/edit can both match.
15
- routes = router.ordered_routes
16
- route = routes.find do |r|
17
- route_found?(r)
18
- end
19
- route
8
+ Jets::Router::Finder.new(method, path).run
20
9
  end
21
10
 
22
- # "hot reload" for development
23
- def reset_routes!
24
- return unless Jets.env.development?
11
+ private
12
+ attr_reader :env
25
13
 
26
- Jets::Router.clear!
27
- Jets.application.load_routes(refresh: true)
14
+ def path
15
+ env["REQUEST_METHOD"] || "GET"
28
16
  end
29
17
 
30
- def route_found?(route)
31
- request_method = @env["REQUEST_METHOD"] || "GET"
32
- actual_path = @env["PATH_INFO"].sub(/^\//,'') # remove beginning slash
33
-
34
- # Immediately stop checking when the request method: GET, POST, ANY, etc
35
- # doesnt match.
36
- return false if request_method != route.method and route.method != "ANY"
37
-
38
- path = route.path
39
-
40
- if actual_path == path
41
- # regular string match detection
42
- return true # exact route matches are highest precedence
43
- end
44
-
45
- # Check path for route capture and wildcard matches:
46
- # A colon (:) means the variable has a variable
47
- if path.include?(':') # 2nd highest precedence
48
- capture_detection(path, actual_path) # early return true or false
49
- # A star (*) means the variable has a glob
50
- elsif path.include?('*') # lowest precedence
51
- proxy_detection(path, actual_path) # early return true or false
52
- else
53
- false # reach here, means no route matched
54
- end
55
- end
56
-
57
- # catchall/globbing/wildcard/proxy routes. Examples:
58
- #
59
- # get "files/*path", to: "files#show"
60
- # get "others/*rest", to: "others#show"
61
- # get "*catchall", to: "public_files#show" # last catchall route for Jets
62
- #
63
- def proxy_detection(route_path, actual_path)
64
- # drop the proxy_segment
65
- leading_path = route_path.split('/')[0..-2].join('/')
66
-
67
- # get "*catchall", to: "public_files#show"
68
- if leading_path.empty? # This is the last catchall route "*catchall"
69
- return true # always return true here because the entire path
70
- # will always match
71
- end
72
-
73
- # Other types of wildcard route:
74
- #
75
- # get "files/*path", to: "files#show"
76
- # get "others/*rest", to: "others#show"
77
- unless leading_path.ends_with?('/')
78
- # Ensure trailing slash to make pattern matching stricter
79
- leading_path = "#{leading_path}/"
80
- end
81
-
82
- pattern = "^#{leading_path}"
83
- regexp = Regexp.new(pattern)
84
- !!regexp.match(actual_path) # could be true or false
85
- end
86
-
87
- def capture_detection(route_path, actual_path)
88
- # changes path to a string used for a regexp
89
- # posts/:id/edit => posts\/(.*)\/edit
90
-
91
- regexp_string = route_path.split('/').map do |s|
92
- s.include?(':') ? Jets::Router::Route::CAPTURE_REGEX : s
93
- end.join('\/')
94
- # make sure beginning and end of the string matches
95
- regexp_string = "^#{regexp_string}$"
96
-
97
- regexp = Regexp.new(regexp_string)
98
- !!regexp.match(actual_path) # could be true or false
99
- end
100
-
101
- def router
102
- return @router if @router
103
- @router = Jets.application.routes
18
+ def method
19
+ env["PATH_INFO"].sub(/^\//,'')
104
20
  end
105
21
  end
106
22
  end
@@ -401,19 +401,4 @@ module Jets::Lambda::Dsl
401
401
  end
402
402
  end # end of class << self
403
403
  end # end of included
404
-
405
- def self.add_custom_resource_extensions(base)
406
- base_path = "#{Jets.root}/app/extensions"
407
- Dir.glob("#{base_path}/**/*.rb").each do |path|
408
- next unless File.file?(path)
409
-
410
- class_name = path.sub("#{base_path}/", '').sub(/\.rb/,'').camelize
411
- klass = class_name.constantize # autoload
412
- base.extend(klass)
413
- end
414
- end
415
-
416
- def self.included(base)
417
- add_custom_resource_extensions(base)
418
- end
419
404
  end
@@ -0,0 +1,47 @@
1
+ class Jets::Router
2
+ class Finder
3
+ extend Memoist
4
+
5
+ def initialize(path, method)
6
+ @path = path
7
+ @method = method.to_s.upcase
8
+ end
9
+
10
+ def run
11
+ reset_routes!
12
+ # Precedence:
13
+ # 1. Routes with no captures get highest precedence: posts/new
14
+ # 2. Then we consider the routes with captures: post/:id
15
+ #
16
+ # Within these 2 groups we consider the routes with the longest path first
17
+ # since posts/:id and posts/:id/edit can both match.
18
+ routes = router.ordered_routes
19
+ route = routes.find do |r|
20
+ matcher.match?(r)
21
+ end
22
+ route
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :path, :method
28
+
29
+ # "hot reload" for development
30
+ def reset_routes!
31
+ return unless Jets.env.development?
32
+
33
+ Jets::Router.clear!
34
+ Jets.application.load_routes(refresh: true)
35
+ end
36
+
37
+ def matcher
38
+ Jets::Router::Matcher.new(path, method)
39
+ end
40
+ memoize :matcher
41
+
42
+ def router
43
+ Jets.application.routes
44
+ end
45
+ memoize :router
46
+ end
47
+ end
@@ -0,0 +1,81 @@
1
+ class Jets::Router
2
+ class Matcher
3
+ def initialize(path, method)
4
+ @path = path.sub(/^\//,'')
5
+ @method = method.to_s.upcase
6
+ end
7
+
8
+ def match?(route)
9
+ # Immediately stop checking when the request method: GET, POST, ANY, etc
10
+ # doesnt match.
11
+
12
+ return false if method != route.method && route.method != "ANY"
13
+
14
+ route_path = route.path
15
+
16
+ if path == route_path
17
+ # regular string match detection
18
+ return true # exact route matches are highest precedence
19
+ end
20
+
21
+ # Check path for route capture and wildcard matches:
22
+ # A colon (:) means the variable has a variable
23
+ if route_path.include?(':') # 2nd highest precedence
24
+ capture_detection(route_path, path) # early return true or false
25
+ # A star (*) means the variable has a glob
26
+ elsif route_path.include?('*') # lowest precedence
27
+ proxy_detection(route_path, path) # early return true or false
28
+ else
29
+ false # reach here, means no route matched
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :path, :method
36
+
37
+ # catchall/globbing/wildcard/proxy routes. Examples:
38
+ #
39
+ # get "files/*path", to: "files#show"
40
+ # get "others/*rest", to: "others#show"
41
+ # get "*catchall", to: "public_files#show" # last catchall route for Jets
42
+ #
43
+ def proxy_detection(route_path, actual_path)
44
+ # drop the proxy_segment
45
+ leading_path = route_path.split('/')[0..-2].join('/')
46
+
47
+ # get "*catchall", to: "public_files#show"
48
+ if leading_path.empty? # This is the last catchall route "*catchall"
49
+ return true # always return true here because the entire path
50
+ # will always match
51
+ end
52
+
53
+ # Other types of wildcard route:
54
+ #
55
+ # get "files/*path", to: "files#show"
56
+ # get "others/*rest", to: "others#show"
57
+ unless leading_path.ends_with?('/')
58
+ # Ensure trailing slash to make pattern matching stricter
59
+ leading_path = "#{leading_path}/"
60
+ end
61
+
62
+ pattern = "^#{leading_path}"
63
+ regexp = Regexp.new(pattern)
64
+ !!regexp.match(actual_path) # could be true or false
65
+ end
66
+
67
+ def capture_detection(route_path, actual_path)
68
+ # changes path to a string used for a regexp
69
+ # posts/:id/edit => posts\/(.*)\/edit
70
+ regexp_string = route_path.split('/').map do |s|
71
+ s.include?(':') ? Jets::Router::Route::CAPTURE_REGEX : s
72
+ end.join('\/')
73
+ # make sure beginning and end of the string matches
74
+ regexp_string = "^#{regexp_string}$"
75
+
76
+ regexp = Regexp.new(regexp_string)
77
+
78
+ !!regexp.match(actual_path) # could be true or false
79
+ end
80
+ end
81
+ end
@@ -1,5 +1,7 @@
1
1
  module Jets::SpecHelpers::Controllers
2
2
  class Request
3
+ extend Memoist
4
+
3
5
  attr_accessor :method, :path, :headers, :params
4
6
  def initialize(method, path, headers={}, params={})
5
7
  @method, @path, @headers, @params = method, path, headers, params
@@ -7,14 +9,14 @@ module Jets::SpecHelpers::Controllers
7
9
 
8
10
  def event
9
11
  json = {}
10
- id_params = path.scan(%r{:([^/]+)}).flatten
12
+ id_params = route.path.scan(%r{:([^/]+)}).flatten
11
13
  expanded_path = path.dup
12
14
  path_parameters = {}
13
15
 
14
16
  id_params.each do |id_param|
15
- raise "missing param: :#{id_param}" unless params.path_params.include? id_param.to_sym
17
+ raise "missing param: :#{id_param}" unless path_params.include? id_param.to_sym
16
18
 
17
- path_param_value = params.path_params[id_param.to_sym]
19
+ path_param_value = path_params[id_param.to_sym]
18
20
  raise "Path param :#{id_param} value cannot be blank" if path_param_value.blank?
19
21
 
20
22
  expanded_path.gsub!(":#{id_param}", path_param_value.to_s)
@@ -50,19 +52,28 @@ module Jets::SpecHelpers::Controllers
50
52
  json
51
53
  end
52
54
 
53
- def find_route!
55
+ def path_params
56
+ params.path_params.reverse_merge(extract_parameters)
57
+ end
58
+ memoize :path_params
59
+
60
+ def extract_parameters
61
+ route.extract_parameters(normalized_path).symbolize_keys
62
+ end
63
+
64
+ def normalized_path
54
65
  path = self.path
55
66
  path = path[0..-2] if path.end_with? '/'
56
67
  path = path[1..-1] if path.start_with? '/'
68
+ path
69
+ end
57
70
 
58
- route = Jets::Router.routes.find { |r| r.path == path && r.method == method.to_s.upcase }
59
- raise "Route not found: #{method.to_s.upcase} #{path}" if route.blank?
60
-
61
- route
71
+ def route
72
+ Jets::Router::Finder.new(normalized_path, method).run
62
73
  end
74
+ memoize :route
63
75
 
64
76
  def dispatch!
65
- route = find_route!
66
77
  klass = Object.const_get(route.controller_name)
67
78
  controller = klass.new(event, {}, route.action_name)
68
79
  response = controller.process! # response is API Gateway Hash
@@ -1,3 +1,3 @@
1
1
  module Jets
2
- VERSION = "2.1.0"
2
+ VERSION = "2.1.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jets
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-18 00:00:00.000000000 Z
11
+ date: 2019-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionmailer
@@ -895,9 +895,11 @@ files:
895
895
  - lib/jets/router.rb
896
896
  - lib/jets/router/dsl.rb
897
897
  - lib/jets/router/error.rb
898
+ - lib/jets/router/finder.rb
898
899
  - lib/jets/router/helpers.rb
899
900
  - lib/jets/router/helpers/core_helper.rb
900
901
  - lib/jets/router/helpers/named_routes_helper.rb
902
+ - lib/jets/router/matcher.rb
901
903
  - lib/jets/router/method_creator.rb
902
904
  - lib/jets/router/method_creator/code.rb
903
905
  - lib/jets/router/method_creator/edit.rb