phaedra 0.3.2 → 0.5.2

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: 7f0e4c33ad4a5241f2a6b7455522db8389a1bc2323ef4542ad75546b2b874a08
4
- data.tar.gz: 42f380fa9cb7a620da9591862c7fd7abbd4022e8046c1ed8f089e902a052c1c2
3
+ metadata.gz: 00d5ba6f3bc10860baef3bf63867665db4ef610b7cf14a8281495cf929339bc3
4
+ data.tar.gz: 5d1c500a8cbe79a89182497e7881fdeba3d129e5e2f2ddcce19012f9ae713171
5
5
  SHA512:
6
- metadata.gz: 0003a862d70c030695b33c1318c69c14eb3f0eda149590e485083827d6c703c06d68dbf8daa6c39e911274b5a5527c2e043aa327e18759bdb8ff970179e764cd
7
- data.tar.gz: a5a22957adcb6c3e1fbce24e39e4c7b582381936b3d832d23ea32813888d5789ea779e89116fb3b16ac1a7122db97ac77d6de2fdd909ee791d351629f3c7dfcb
6
+ metadata.gz: 3f3a8145df4a02f5362dfffb66f1de44ccd650425504007f2f49fa666c68bd9d228d0e8ade98daa2d318c57b220013009bd2c9b37d10d375a7cecca2cee0c4ac
7
+ data.tar.gz: f0effbf926248e56c67da411bd688cc3f6783d7710bdedf141029d523b4e55667df18b1e509cb68aa55795a01b74369ac8e007a91754ac9b3c6046741d166258
data/README.md CHANGED
@@ -118,7 +118,13 @@ All you have to do is create a static site repo ([Bridgetown](https://www.bridge
118
118
 
119
119
  We recommend using OpenFaaS' dockerfile template so you can define your own `Dockerfile` to book Rack + Phaedra using the Puma web server. This also allows you to customize the Docker image configuration to install and configure other tools as necessary.
120
120
 
121
- First, make sure you've pulled down the template:
121
+ First make sure you've added Puma to your Gemfile:
122
+
123
+ ```
124
+ gem "puma"
125
+ ```
126
+
127
+ Then make sure you've pulled down the OpenFaaS template:
122
128
 
123
129
  ```sh
124
130
  faas-cli template store pull dockerfile
@@ -174,7 +180,7 @@ Next add the `config.ru` file to boot Rack:
174
180
  ```ruby
175
181
  # testphaedra/config.ru
176
182
 
177
- require "phaedra"
183
+ require "phaedra/rack_app"
178
184
 
179
185
  run Phaedra::RackApp.new
180
186
  ```
@@ -210,7 +216,7 @@ In case you're wondering: yes, with Phaedra you can write multiple Ruby function
210
216
  Booting Phaedra up as Rack app is very simple. All you need to do is add a `config.ru` file alongside your `api` folder:
211
217
 
212
218
  ```ruby
213
- require "phaedra"
219
+ require "phaedra/rack_app"
214
220
 
215
221
  run Phaedra::RackApp.new
216
222
  ```
@@ -0,0 +1,46 @@
1
+ FROM ruby:2.6-alpine3.11 as builder
2
+
3
+ RUN apk add --no-cache --virtual \\
4
+ #
5
+ # required
6
+ bash tzdata build-base libffi-dev \\
7
+ #
8
+ # nice to haves
9
+ curl git
10
+
11
+ FROM builder as phaedra-app
12
+
13
+ # This is to fix an issue on Linux with permissions issues
14
+ ARG USER_ID=${USER_ID:-1000}
15
+ ARG GROUP_ID=${GROUP_ID:-1000}
16
+ ARG DOCKER_USER=${DOCKER_USER:-user}
17
+ ARG APP_DIR=${APP_DIR:-/home/user/phaedra-app}
18
+
19
+ # Change with --build-arg PHAEDRA_ENV=production
20
+ ARG PHAEDRA_ENV=staging
21
+ ENV PHAEDRA_ENV=$PHAEDRA_ENV
22
+
23
+ # Create a non-root user
24
+ RUN addgroup -g $GROUP_ID -S $GROUP_ID
25
+ RUN adduser --disabled-password -G $GROUP_ID --uid $USER_ID -S $DOCKER_USER
26
+
27
+ # Create and then own the directory to fix permissions issues
28
+ RUN mkdir -p $APP_DIR
29
+ RUN chown -R $USER_ID:$GROUP_ID $APP_DIR
30
+
31
+ # Define the user running the container
32
+ USER $USER_ID:$GROUP_ID
33
+
34
+ # . now == $APP_DIR
35
+ WORKDIR $APP_DIR
36
+
37
+ # COPY is run as a root user, not as the USER defined above, so we must chown it
38
+ COPY --chown=$USER_ID:$GROUP_ID Gemfile* ./
39
+ RUN gem install bundler
40
+ RUN bundle install
41
+
42
+ COPY --chown=$USER_ID:$GROUP_ID . .
43
+
44
+ EXPOSE 8080
45
+
46
+ CMD ["bundle", "exec", "rackup", "-p", "8080", "-o", "0.0.0.0"]
@@ -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
5
  response["Content-Type"] = "text/html; charset=utf-8"
6
- "<p>This is Interesting. 😁</p>"
6
+ "<p>😁 #{Phaedra.the_time} - #{ENV["PHAEDRA_ENV"]} - #{Time.new}</p>"
7
7
  end
8
8
  end
9
9
 
@@ -1,10 +1,10 @@
1
- require "phaedra"
1
+ require_relative "../phaedra/initializers"
2
2
 
3
3
  class PhaedraFunction < Phaedra::Base
4
4
  before_action :earlier_stuff
5
5
 
6
6
  def get(params)
7
- "The Current Time is: #{Time.new} and Search Param is #{params[:search]}."
7
+ "The ?search param is #{params[:search]}"
8
8
  end
9
9
 
10
10
  def post(params)
@@ -1,3 +1,3 @@
1
- require "phaedra"
1
+ require "phaedra/rack_app"
2
2
 
3
3
  run Phaedra::RackApp.new
@@ -0,0 +1,8 @@
1
+ version: '3'
2
+ services:
3
+ web:
4
+ build: .
5
+ ports:
6
+ - "8080:8080"
7
+ environment:
8
+ - PHAEDRA_ENV
@@ -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,5 @@
1
1
  require "phaedra/version"
2
-
3
2
  require "webrick"
4
- require "rack"
5
-
3
+ require "phaedra/initializers_module"
4
+ require "phaedra/startup_initializers"
6
5
  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)
@@ -123,7 +127,7 @@ module Phaedra
123
127
  def complete_response
124
128
  if @res.body.is_a?(String) && !@res["Content-Type"].start_with?("text/")
125
129
  @res["Content-Type"] = "text/plain; charset=utf-8"
126
- elsif @res["Content-Type"] == "application/json"
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
@@ -0,0 +1,9 @@
1
+ module Phaedra
2
+ Initializers.register self, priority: :high do
3
+ environment
4
+ end
5
+
6
+ def self.environment
7
+ @environment ||= ENV.fetch("PHAEDRA_ENV", :development).to_sym
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Phaedra
2
- VERSION = "0.3.2"
2
+ VERSION = "0.5.2"
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.2
4
+ version: 0.5.2
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-09 00:00:00.000000000 Z
11
+ date: 2020-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -80,14 +80,22 @@ files:
80
80
  - LICENSE.txt
81
81
  - README.md
82
82
  - Rakefile
83
+ - example/Dockerfile
83
84
  - example/Gemfile
84
85
  - example/api/simple.rb
85
86
  - example/api/the-time.rb
86
87
  - example/config.ru
88
+ - example/docker-compose.yml
89
+ - example/phaedra/initializers.rb
87
90
  - lib/phaedra.rb
88
91
  - lib/phaedra/base.rb
89
92
  - lib/phaedra/concerns/callbacks_actionable.rb
93
+ - lib/phaedra/initializers_module.rb
90
94
  - lib/phaedra/rack_app.rb
95
+ - lib/phaedra/rack_middleware.rb
96
+ - lib/phaedra/rack_middleware/not_found.rb
97
+ - lib/phaedra/rack_middleware/static.rb
98
+ - lib/phaedra/startup_initializers.rb
91
99
  - lib/phaedra/version.rb
92
100
  - phaedra.gemspec
93
101
  homepage: https://github.com/whitefusionhq/phaedra
@@ -109,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
117
  - !ruby/object:Gem::Version
110
118
  version: '0'
111
119
  requirements: []
112
- rubygems_version: 3.0.6
120
+ rubygems_version: 3.0.8
113
121
  signing_key:
114
122
  specification_version: 4
115
123
  summary: Write serverless Ruby functions via a REST-like microframework compatible