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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ac7eff901bd41a6da00ead154dc726635a7663597f5dd263fbe07c6f8df8821
4
- data.tar.gz: 3eaafe5f99657959f22bd097191329404469087fc864ea980ba85a15156c87ce
3
+ metadata.gz: c1bdff92530752ce6f23f3b1e5e5763ac60ea46f0ff941147949790133a8d54e
4
+ data.tar.gz: 940607642ec362c3eeb5a88629cfd5f42125990f0d0437fd160e7e27ce0f66e2
5
5
  SHA512:
6
- metadata.gz: 83c5681c356986221a82202728e3efdfe912f9db5c82bf66b388bb38a1e9450aac8269bda442fbca528230f64e8615446e7f8231cae9080fabd11c02fefee216
7
- data.tar.gz: 5631c0968e80834d7b571547151e1e9addcc64136e07e73c91828afcde277996763bf05b9591896ec530eefabbd2ede670f3fffbbdd902d26cadbcfe3a173138
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:
@@ -1,9 +1,9 @@
1
- require "phaedra"
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. 😁</p>"
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
 
@@ -1,3 +1,3 @@
1
- require "phaedra"
1
+ require "phaedra/rack_app"
2
2
 
3
3
  run Phaedra::RackApp.new
@@ -0,0 +1,11 @@
1
+ require "phaedra"
2
+
3
+ module Phaedra
4
+ Initializers.register self do
5
+ the_time("123")
6
+ end
7
+
8
+ def self.the_time(init = nil)
9
+ @the_time ||= "#{Time.now} + #{init}"
10
+ end
11
+ end
@@ -1,7 +1,4 @@
1
1
  require "phaedra/version"
2
-
3
2
  require "webrick"
4
- require "rack"
5
-
3
+ require "phaedra/initializers_module"
6
4
  require "phaedra/base"
7
- require "phaedra/rack_app"
@@ -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"] == "application/json"
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
@@ -1,3 +1,6 @@
1
+ require "rack"
2
+ require "phaedra"
3
+
1
4
  module Phaedra
2
5
  class Request < Rack::Request
3
6
  def query
@@ -0,0 +1,2 @@
1
+ require "phaedra/rack_middleware/not_found"
2
+ require "phaedra/rack_middleware/static"
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Phaedra
2
- VERSION = "0.3.1"
2
+ VERSION = "0.5.1"
3
3
  end
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.3.1
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-08 00:00:00.000000000 Z
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.8
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