phaedra 0.3.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -3
- data/example/api/simple.rb +3 -3
- data/example/config.ru +1 -1
- data/example/phaedra/initializers.rb +11 -0
- data/lib/phaedra.rb +1 -4
- data/lib/phaedra/base.rb +7 -3
- data/lib/phaedra/concerns/callbacks_actionable.rb +6 -6
- data/lib/phaedra/initializers_module.rb +69 -0
- data/lib/phaedra/rack_app.rb +3 -0
- data/lib/phaedra/rack_middleware.rb +2 -0
- data/lib/phaedra/rack_middleware/not_found.rb +21 -0
- data/lib/phaedra/rack_middleware/static.rb +26 -0
- data/lib/phaedra/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1bdff92530752ce6f23f3b1e5e5763ac60ea46f0ff941147949790133a8d54e
|
4
|
+
data.tar.gz: 940607642ec362c3eeb5a88629cfd5f42125990f0d0437fd160e7e27ce0f66e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e151d4bf1a2471acf06e5331dde65dc97988403a873916062f08f46b37c6bfbc54a780e448bda0bada253cefe74747abd3811e3071ec7a8474e1346aa53cb863
|
7
|
+
data.tar.gz: 16343524b69c5d67c228f4b69154faf816a996e9b6a15b66b01d10dbaf7510a3c1e747296e1c5d8b42100e7ca01c3e7e8492f4e2b5844946967a28bc1dd20799
|
data/README.md
CHANGED
@@ -89,13 +89,14 @@ require_relative "../lib/shared_code"
|
|
89
89
|
|
90
90
|
class PhaedraFunction < Phaedra::Base
|
91
91
|
def get(params)
|
92
|
-
"Run it once! #{SharedCode.run_once}"
|
92
|
+
"Run it once! #{SharedCode.run_once} / #{Time.now}"
|
93
93
|
end
|
94
94
|
end
|
95
95
|
```
|
96
96
|
|
97
97
|
```ruby
|
98
98
|
# lib/shared_code.rb
|
99
|
+
|
99
100
|
module SharedCode
|
100
101
|
def self.run_once
|
101
102
|
@one_time ||= Time.now
|
@@ -103,7 +104,9 @@ module SharedCode
|
|
103
104
|
end
|
104
105
|
```
|
105
106
|
|
106
|
-
Now each time you invoke the function at `/api/run-it-once`, the timestamp will never change until the next redeployment.
|
107
|
+
Now each time you invoke the function at `/api/run-it-once`, the first timestamp will never change until the next redeployment.
|
108
|
+
|
109
|
+
**NOTE:** When running in a Rack-based configuration (see below), Ruby's `load` method is invoked for every request to any Phaedra function. This means Ruby has to parse and compile the code in your function each time. For small functions this happens extremely quickly, but if you find yourself writing a large function and seeing some performance slowdowns, consider extracting most of the function code to additional Ruby files and use the `require_relative` technique as mentioned above. The Ruby code in those required files will only be compiled once and all classes/modules/etc. will be saved in memory until the next redeployment.
|
107
110
|
|
108
111
|
## Deployment
|
109
112
|
|
@@ -212,7 +215,7 @@ require "phaedra"
|
|
212
215
|
run Phaedra::RackApp.new
|
213
216
|
```
|
214
217
|
|
215
|
-
Then run `rackup` in the terminal.
|
218
|
+
Then run `rackup` in the terminal, or use another Rack-compatible server like Puma or Passenger.
|
216
219
|
|
217
220
|
The settings (and their defaults) you can pass to the `new` method are as follows:
|
218
221
|
|
@@ -223,6 +226,26 @@ The settings (and their defaults) you can pass to the `new` method are as follow
|
|
223
226
|
}
|
224
227
|
```
|
225
228
|
|
229
|
+
Wondering if you can deploy a static site with an `api` folder via Nginx + Passenger? Yes, you can! Just configure your `my_site.conf` file like so:
|
230
|
+
|
231
|
+
```nginxconf
|
232
|
+
server {
|
233
|
+
listen 80;
|
234
|
+
server_name www.domain.com;
|
235
|
+
|
236
|
+
# Tell Nginx and Passenger where your site destination folder is
|
237
|
+
root /home/me/my_site/output;
|
238
|
+
|
239
|
+
# Turn on Passenger
|
240
|
+
location /api {
|
241
|
+
passenger_enabled on;
|
242
|
+
passenger_ruby /usr/local/rvm/gems/ruby-2.6.6@mysite/wrappers/ruby;
|
243
|
+
}
|
244
|
+
}
|
245
|
+
```
|
246
|
+
|
247
|
+
Change the `server_name`, `root`, and `passenger_ruby` paths to your particular setup and you'll be good to go. (If you run into any errors, double-check there's a `config.ru` in the parent folder of your site destination folder.)
|
248
|
+
|
226
249
|
### WEBrick
|
227
250
|
|
228
251
|
Integrating Phaedra into a WEBrick server is pretty straightforward. Given a `server` object, it can be accomplished thusly:
|
data/example/api/simple.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
|
1
|
+
require_relative "../phaedra/initializers"
|
2
2
|
|
3
3
|
class PhaedraFunction < Phaedra::Base
|
4
4
|
def get(params)
|
5
|
-
response["Content-Type"] = "text/html"
|
6
|
-
"<p>This is Interesting.
|
5
|
+
response["Content-Type"] = "text/html; charset=utf-8"
|
6
|
+
"<p>This is Interesting. 😁 #{Phaedra.the_time}</p>"
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
data/example/config.ru
CHANGED
data/lib/phaedra.rb
CHANGED
data/lib/phaedra/base.rb
CHANGED
@@ -7,6 +7,10 @@ module Phaedra
|
|
7
7
|
class Base
|
8
8
|
include CallbacksActionable
|
9
9
|
|
10
|
+
before_action do
|
11
|
+
Initializers.run
|
12
|
+
end
|
13
|
+
|
10
14
|
# Used by WEBrick
|
11
15
|
def self.get_instance(server, *options)
|
12
16
|
self.new(server, *options)
|
@@ -112,7 +116,7 @@ module Phaedra
|
|
112
116
|
|
113
117
|
def set_initial_status
|
114
118
|
@res.status = 200
|
115
|
-
@res["Content-Type"] = "application/json"
|
119
|
+
@res["Content-Type"] = "application/json; charset=utf-8"
|
116
120
|
end
|
117
121
|
|
118
122
|
def call_method_action(params)
|
@@ -122,8 +126,8 @@ module Phaedra
|
|
122
126
|
|
123
127
|
def complete_response
|
124
128
|
if @res.body.is_a?(String) && !@res["Content-Type"].start_with?("text/")
|
125
|
-
@res["Content-Type"] = "text/plain"
|
126
|
-
elsif @res["Content-Type"]
|
129
|
+
@res["Content-Type"] = "text/plain; charset=utf-8"
|
130
|
+
elsif @res["Content-Type"].start_with? "application/json"
|
127
131
|
@res.body = @res.body.to_json
|
128
132
|
end
|
129
133
|
end
|
@@ -11,14 +11,14 @@ module Phaedra
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module ClassMethods
|
14
|
-
def before_action(*args)
|
15
|
-
set_callback :action, :before, *args
|
14
|
+
def before_action(*args, &block)
|
15
|
+
set_callback :action, :before, *args, &block
|
16
16
|
end
|
17
|
-
def after_action(*args)
|
18
|
-
set_callback :action, :after, *args
|
17
|
+
def after_action(*args, &block)
|
18
|
+
set_callback :action, :after, *args, &block
|
19
19
|
end
|
20
|
-
def around_action(*args)
|
21
|
-
set_callback :action, :around, *args
|
20
|
+
def around_action(*args, &block)
|
21
|
+
set_callback :action, :around, *args, &block
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Phaedra
|
2
|
+
module Initializers
|
3
|
+
Registration = Struct.new(
|
4
|
+
:origin,
|
5
|
+
:priority,
|
6
|
+
:block,
|
7
|
+
keyword_init: true
|
8
|
+
) do
|
9
|
+
def to_s
|
10
|
+
"#{owner}:#{priority} for #{block}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
DEFAULT_PRIORITY = 20
|
15
|
+
|
16
|
+
PRIORITY_MAP = {
|
17
|
+
low: 10,
|
18
|
+
normal: 20,
|
19
|
+
high: 30,
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
# initial empty hooks
|
23
|
+
@registry = []
|
24
|
+
|
25
|
+
NotAvailable = Class.new(RuntimeError)
|
26
|
+
Uncallable = Class.new(RuntimeError)
|
27
|
+
|
28
|
+
# Ensure the priority is a Fixnum
|
29
|
+
def self.priority_value(priority)
|
30
|
+
return priority if priority.is_a?(Integer)
|
31
|
+
|
32
|
+
PRIORITY_MAP[priority] || DEFAULT_PRIORITY
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.register(origin, priority: DEFAULT_PRIORITY, &block)
|
36
|
+
raise Uncallable, "Initializers must respond to :call" unless block.respond_to? :call
|
37
|
+
|
38
|
+
@registry << Registration.new(
|
39
|
+
origin: origin,
|
40
|
+
priority: priority_value(priority),
|
41
|
+
block: block
|
42
|
+
)
|
43
|
+
|
44
|
+
block
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.remove(origin)
|
48
|
+
@registry.delete_if { |item| item.origin == origin }
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.run(force: false)
|
52
|
+
if !@initializers_ran || force
|
53
|
+
prioritized_initializers.each do |initializer|
|
54
|
+
initializer.block.call
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
@initializers_ran = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.prioritized_initializers
|
62
|
+
# sort initializers according to priority and load order
|
63
|
+
grouped_initializers = @registry.group_by(&:priority)
|
64
|
+
grouped_initializers.keys.sort.reverse.map do |priority|
|
65
|
+
grouped_initializers[priority]
|
66
|
+
end.flatten
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/phaedra/rack_app.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Phaedra
|
2
|
+
module Middleware
|
3
|
+
class NotFound
|
4
|
+
def initialize(app, path, content_type = 'text/html; charset=utf-8')
|
5
|
+
@app = app
|
6
|
+
@content = File.read(path)
|
7
|
+
@length = @content.bytesize.to_s
|
8
|
+
@content_type = content_type
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
response = @app.call(env)
|
13
|
+
if response[0] == 404
|
14
|
+
[404, {'Content-Type' => @content_type, 'Content-Length' => @length}, [@content]]
|
15
|
+
else
|
16
|
+
response
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Phaedra
|
2
|
+
module Middleware
|
3
|
+
# Based on Rack::TryStatic middleware
|
4
|
+
# https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/try_static.rb
|
5
|
+
|
6
|
+
class Static
|
7
|
+
def initialize(app, options)
|
8
|
+
@app = app
|
9
|
+
@try = ["", ".html", "index.html", "/index.html", *options[:try]]
|
10
|
+
@static = Rack::Static.new(
|
11
|
+
lambda { |_| [404, {}, []] },
|
12
|
+
options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
orig_path = env['PATH_INFO']
|
17
|
+
found = nil
|
18
|
+
@try.each do |path|
|
19
|
+
resp = @static.call(env.merge!({'PATH_INFO' => orig_path + path}))
|
20
|
+
break if !(403..405).include?(resp[0]) && found = resp
|
21
|
+
end
|
22
|
+
found or @app.call(env.merge!('PATH_INFO' => orig_path))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/phaedra/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phaedra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jared White
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -84,10 +84,15 @@ files:
|
|
84
84
|
- example/api/simple.rb
|
85
85
|
- example/api/the-time.rb
|
86
86
|
- example/config.ru
|
87
|
+
- example/phaedra/initializers.rb
|
87
88
|
- lib/phaedra.rb
|
88
89
|
- lib/phaedra/base.rb
|
89
90
|
- lib/phaedra/concerns/callbacks_actionable.rb
|
91
|
+
- lib/phaedra/initializers_module.rb
|
90
92
|
- lib/phaedra/rack_app.rb
|
93
|
+
- lib/phaedra/rack_middleware.rb
|
94
|
+
- lib/phaedra/rack_middleware/not_found.rb
|
95
|
+
- lib/phaedra/rack_middleware/static.rb
|
91
96
|
- lib/phaedra/version.rb
|
92
97
|
- phaedra.gemspec
|
93
98
|
homepage: https://github.com/whitefusionhq/phaedra
|
@@ -109,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
114
|
- !ruby/object:Gem::Version
|
110
115
|
version: '0'
|
111
116
|
requirements: []
|
112
|
-
rubygems_version: 3.0.
|
117
|
+
rubygems_version: 3.0.6
|
113
118
|
signing_key:
|
114
119
|
specification_version: 4
|
115
120
|
summary: Write serverless Ruby functions via a REST-like microframework compatible
|