reins-web 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 20240edf92760205c1c0c7e963b286017d07c755bee1f184eb182de326d84788
4
+ data.tar.gz: d3aa3aadaff2d9768d912324c915cf076dbb7f02aacb06354238448825c6a5dc
5
+ SHA512:
6
+ metadata.gz: 5b1f4dabb1f0ba43073319ce938f150de72110cef04303cf6c74581e5a456321d6580d7028696e5984bc962c7f9ea97c58c13d9f9391427fa1295b4c39de2be0
7
+ data.tar.gz: 4e78fb4c4a83c9c153d10f2fc390f28ea291ee3452b55aa2202c4df27cb191800464ee40bbdd93beb5c67febe83dcafa3d11e7599711a82d92330842ebfea694
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "reins"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/reins ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/reins/cli'
4
+
5
+ Reins::Cli.start(ARGV)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ class Array
2
+ def deeply_empty?
3
+ empty? || all?(&:empty?)
4
+ end
5
+ end
data/lib/reins/cli.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'thor'
2
+ require 'fileutils'
3
+ require 'puma'
4
+ require 'rack'
5
+
6
+ module Reins
7
+ class Cli < Thor
8
+ desc "new", "Create a new Reins project"
9
+ def new(name)
10
+ scaffold_project(name)
11
+ end
12
+
13
+ desc "server", "Run a local server"
14
+ def server
15
+ root = File.expand_path("#{Dir.pwd}")
16
+ config = root + "/config.ru"
17
+
18
+ app = Rack::Builder.load_file(config)
19
+
20
+ server = Puma::Server.new(app)
21
+ server.add_tcp_listener('0.0.0.0', 8000)
22
+
23
+ trap('INT') do
24
+ server.stop
25
+ puts "\nServer stopped."
26
+ exit
27
+ end
28
+
29
+ puts "Serving files from #{root} on http://localhost:8000"
30
+ server.run.join
31
+ end
32
+
33
+ private
34
+
35
+ def scaffold_project(dir)
36
+ FileUtils.mkdir(dir)
37
+ FileUtils.mkdir(dir + "/app")
38
+ FileUtils.mkdir(dir + "/app/controllers")
39
+ FileUtils.mkdir(dir + "/app/views")
40
+ FileUtils.mkdir(dir + "/app/views/welcome")
41
+ FileUtils.mkdir(dir + "/config")
42
+ FileUtils.mkdir(dir + "/public")
43
+ FileUtils.cp(File.dirname(__FILE__) + "/../../assets/500.html", "testdir/public/500.html")
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,81 @@
1
+ require 'rack'
2
+ require "reins/file_model"
3
+ require "reins/view"
4
+
5
+ module Reins
6
+ class Controller
7
+ include Reins::Model
8
+
9
+ def initialize(env)
10
+ @env = env
11
+ @routing_params = {}
12
+ end
13
+
14
+ def dispatch(action, routing_params = {})
15
+ @routing_params = routing_params
16
+ text = self.send(action)
17
+ r = get_response
18
+ if r
19
+ [r.status, r.headers, [r.body].flatten]
20
+ else
21
+ [200, {'content-type' => 'text/html'},
22
+ [text].flatten]
23
+ end
24
+ end
25
+
26
+ def self.action(act, rp = {})
27
+ proc { |e| self.new(e).dispatch(act, rp) }
28
+ end
29
+
30
+ def env
31
+ @env
32
+ end
33
+
34
+ def request
35
+ @request ||= Rack::Request.new(@env)
36
+ end
37
+
38
+ def params
39
+ request.params.merge @routing_params
40
+ end
41
+
42
+ def response(text, status = 200, headers = {})
43
+ raise "Already responded!" if @response
44
+ a = [text].flatten
45
+ @response = Rack::Response.new(a, status, headers)
46
+ end
47
+
48
+ def get_response
49
+ @response
50
+ end
51
+
52
+ def controller_name
53
+ klass = self.class
54
+ klass = klass.to_s.gsub(/Controller$/, "")
55
+ Reins.to_underscore klass
56
+ end
57
+
58
+ def instance_hash
59
+ h = {}
60
+ instance_variables.each do |i|
61
+ h[i] = instance_variable_get i
62
+ end
63
+ h
64
+ end
65
+
66
+ def render(view_name, locals = {})
67
+ filename = File.join "app", "views",
68
+ controller_name, "#{view_name}.html.erb"
69
+ template = File.read filename
70
+ v = View.new
71
+ v.set_vars instance_hash
72
+ v.evaluate template
73
+ # instance_vars = instance_variables.each_with_object({}) do |var, hash|
74
+ # hash[var.to_s.delete("@").to_sym] = instance_variable_get(var)
75
+ # end
76
+ # eruby = Erubis::Eruby.new(template)
77
+ # result = eruby.result locals.merge(instance_vars) # locals.merge(:env => env)
78
+ # response(result)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,13 @@
1
+ class Object
2
+ def self.const_missing(c)
3
+ @calling_const_missing ||= {}
4
+ return nil if @calling_const_missing[c]
5
+
6
+ @calling_const_missing[c] = true
7
+ require Reins.to_underscore(c.to_s)
8
+ klass = Object.const_get(c)
9
+ @calling_const_missing[c] = false
10
+
11
+ klass
12
+ end
13
+ end
@@ -0,0 +1,94 @@
1
+ require "multi_json"
2
+
3
+ module Reins
4
+ module Model
5
+ class FileModel
6
+ def initialize(filename)
7
+ @filename = filename
8
+ # If filename is "dir/37.json", @id is 37
9
+ basename = File.split(filename)[-1]
10
+ @id = File.basename(basename, ".json").to_i
11
+ obj = File.read(filename)
12
+ @hash = MultiJson.load(obj)
13
+ end
14
+
15
+ def [](name)
16
+ @hash[name.to_s]
17
+ end
18
+
19
+ def []=(name, value)
20
+ @hash[name.to_s] = value
21
+ end
22
+
23
+ def self.all
24
+ files = Dir["db/quotes/*.json"]
25
+ files.map { |f| FileModel.new f }
26
+ end
27
+
28
+ def self.find(id)
29
+ begin
30
+ FileModel.new("db/quotes/#{id}.json")
31
+ rescue
32
+ return nil
33
+ end
34
+ end
35
+
36
+ def self.create(attrs)
37
+ hash = {}
38
+ hash["submitter"] = attrs["submitter"] || ""
39
+ hash["quote"] = attrs["quote"] || ""
40
+ hash["attribution"] = attrs["attribution"] || ""
41
+
42
+ files = Dir["db/quotes/*.json"]
43
+ names = files.map { |f| File.split(f)[-1] }
44
+ highest = names.map { |b| b.to_i }.max
45
+
46
+ id = highest + 1
47
+ File.open("db/quotes/#{id}.json", "w") do |f|
48
+ f.write <<TEMPLATE
49
+ {
50
+ "submitter": "#{hash["submitter"]}",
51
+ "quote": "#{hash["quote"]}",
52
+ "attribution": "#{hash["attribution"]}"
53
+ }
54
+ TEMPLATE
55
+ end
56
+
57
+ FileModel.new "db/quotes/#{id}.json"
58
+ end
59
+
60
+ def self.update(attrs)
61
+ hash = {}
62
+ hash["submitter"] = attrs["submitter"] || ""
63
+ hash["quote"] = attrs["quote"] || ""
64
+ hash["attribution"] = attrs["attribution"] || ""
65
+
66
+ id = 3
67
+ File.open("db/quotes/#{id}.json", "w") do |f|
68
+ f.write <<TEMPLATE
69
+ {
70
+ "submitter": "#{hash["submitter"]}",
71
+ "quote": "#{hash["quote"]}",
72
+ "attribution": "#{hash["attribution"]}"
73
+ }
74
+ TEMPLATE
75
+ end
76
+
77
+ FileModel.new "db/quotes/#{id}.json"
78
+ end
79
+
80
+ def self.save
81
+ # TODO: use MultiJson.dump() to turn @hash into JSON
82
+ end
83
+
84
+ def self.find_all_by_submitter(submitter)
85
+ files = Dir["db/quotes/*.json"]
86
+ files.map { |f| FileModel.new f }
87
+ .select { |m| m['submitter'] == submitter }
88
+ end
89
+
90
+ # TODO: Add method_missing for things that match /^find_all_by_(.*)/
91
+ # NOTE: always override respond_to_missing? if you override method_missing
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,94 @@
1
+ module Reins
2
+ class RouteObject
3
+ def initialize
4
+ @rules = []
5
+ end
6
+
7
+ def match(url, *args)
8
+ options = {}
9
+ options = args.pop if args[-1].is_a?(Hash)
10
+ options[:default] ||= {}
11
+
12
+ dest = nil
13
+ dest = args.pop if args.size > 0
14
+ raise "Too many args!" if args.size > 0
15
+
16
+ parts = url.split("/")
17
+ parts.select! { |p| !p.empty? }
18
+
19
+ vars = []
20
+ regexp_parts = parts.map do |part|
21
+ if part[0] == ":"
22
+ vars << part[1..-1]
23
+ "([a-zA-Z0-9]+)"
24
+ elsif part[0] == "*"
25
+ vars << part[1..-1]
26
+ "(.*)"
27
+ else
28
+ part
29
+ end
30
+ end
31
+
32
+ regexp = regexp_parts.join("/")
33
+ @rules.push({
34
+ :regexp => Regexp.new("^/#{regexp}$"),
35
+ :vars => vars,
36
+ :dest => dest,
37
+ :options => options,
38
+ })
39
+ end
40
+
41
+ def check_url(url)
42
+ @rules.each do |r|
43
+ m = r[:regexp].match(url)
44
+ if m
45
+ options = r[:options]
46
+ params = options[:default].dup
47
+ r[:vars].each_with_index do |v, i|
48
+ params[v] = m.captures[i]
49
+ end
50
+ # TODO: remove dest = nil in GH code
51
+ if r[:dest]
52
+ return get_dest(r[:dest], params)
53
+ else
54
+ controller = params["controller"]
55
+ action = params["action"]
56
+ return get_dest("#{controller}" +
57
+ "##{action}", params)
58
+ end
59
+ end
60
+ end
61
+
62
+ nil
63
+ end
64
+
65
+ def get_dest(dest, routing_params = {})
66
+ return dest if dest.respond_to?(:call)
67
+ if dest =~ /^([^#]+)#([^#]+)$/
68
+ name = $1.capitalize
69
+ con = Object.const_get("#{name}Controller")
70
+ return con.action($2, routing_params)
71
+ end
72
+ raise "No destination: #{dest.inspect}!"
73
+ end
74
+ end
75
+
76
+ class Application
77
+ def route(&block)
78
+ @route_obj ||= RouteObject.new
79
+ @route_obj.instance_eval(&block)
80
+ end
81
+
82
+ def get_rack_app(env)
83
+ raise "No routes!" unless @route_obj
84
+ @route_obj.check_url env["PATH_INFO"]
85
+ end
86
+
87
+ # def get_controller_and_action(env)
88
+ # _, cont, action, _after = env["PATH_INFO"].split('/', 4)
89
+ # cont = cont.capitalize # "People"
90
+ # cont += "Controller" # "PeopleController"
91
+ # [Object.const_get(cont), action]
92
+ # end
93
+ end
94
+ end
@@ -0,0 +1,109 @@
1
+ require "sqlite3"
2
+ require "reins/util"
3
+
4
+ DB = SQLite3::Database.new "test.db"
5
+ module Reins
6
+ module Model
7
+ class SQLite
8
+ def initialize(data = nil)
9
+ @hash = data
10
+ end
11
+
12
+ def self.to_sql(val)
13
+ case val
14
+ when NilClass
15
+ 'null'
16
+ when Numeric
17
+ val.to_s
18
+ when String
19
+ "'#{val}'"
20
+ else
21
+ raise "Can't change #{val.class} to SQL!"
22
+ end
23
+ end
24
+
25
+ def self.create(values)
26
+ values.delete "id"
27
+ keys = schema.keys - ["id"]
28
+ vals = keys.map do |key|
29
+ values[key] ? to_sql(values[key]) : "null"
30
+ end
31
+ DB.execute <<SQL
32
+ INSERT INTO #{table} (#{keys.join ","})
33
+ VALUES (#{vals.join ","});
34
+ SQL
35
+ raw_vals = keys.map { |k| values[k] }
36
+ data = Hash[keys.zip raw_vals]
37
+ sql = "SELECT last_insert_rowid();"
38
+ data["id"] = DB.execute(sql)[0][0]
39
+ self.new data
40
+ end
41
+
42
+ def self.count
43
+ DB.execute(<<SQL)[0][0]
44
+ SELECT COUNT(*) FROM #{table}
45
+ SQL
46
+ end
47
+
48
+ def self.find(id)
49
+ row = DB.execute <<SQL
50
+ select #{schema.keys.join ","} from #{table}
51
+ where id = #{id};
52
+ SQL
53
+ data = Hash[schema.keys.zip row[0]]
54
+ self.new data
55
+ end
56
+
57
+ def [](name)
58
+ @hash[name.to_s]
59
+ end
60
+
61
+ def []=(name, value)
62
+ @hash[name.to_s] = value
63
+ end
64
+
65
+ def save!
66
+ fields = @hash.map do |k, v|
67
+ "#{k}=#{self.class.to_sql(v)}"
68
+ end.join ","
69
+ DB.execute <<SQL
70
+ UPDATE #{self.class.table}
71
+ SET #{fields}
72
+ WHERE id = #{@hash["id"]}
73
+ SQL
74
+ true
75
+ end
76
+
77
+ def save
78
+ self.save! rescue false
79
+ end
80
+
81
+ def self.table
82
+ Reins.to_underscore name
83
+ end
84
+
85
+ def self.all
86
+ rows = DB.execute <<SQL
87
+ select #{schema.keys.join ","} from #{table};
88
+ SQL
89
+ rows.map do |r|
90
+ data = Hash[schema.keys.zip r]
91
+ self.new data
92
+ end
93
+ end
94
+
95
+ def self.schema
96
+ return @schema if @schema
97
+ @schema = {}
98
+ DB.table_info(table) do |row|
99
+ @schema[row["name"]] = row["type"]
100
+ end
101
+ @schema
102
+ end
103
+
104
+ def method_missing(name)
105
+ self[name]
106
+ end
107
+ end
108
+ end
109
+ end
data/lib/reins/util.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Reins
2
+ def self.to_underscore(string)
3
+ string.gsub(/::/, '/').
4
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
6
+ tr("-", "_").
7
+ downcase
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Reins
4
+ VERSION = "0.1.0"
5
+ end
data/lib/reins/view.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'erubis'
2
+
3
+ module Reins
4
+ class View
5
+ def set_vars(instance_vars)
6
+ instance_vars.each do |name, value|
7
+ instance_variable_set(name, value)
8
+ end
9
+ end
10
+
11
+ def evaluate(template)
12
+ eruby = Erubis:Eruby.new(template)
13
+ eval eruby.src
14
+ end
15
+
16
+ def h(str)
17
+ URI.escape str
18
+ end
19
+ end
20
+ end
data/lib/reins.rb ADDED
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "reins/cli"
4
+ require "reins/version"
5
+ require "reins/array"
6
+ require "reins/routing"
7
+ require "reins/util"
8
+ require "reins/dependencies"
9
+ require "reins/controller"
10
+ require "reins/file_model"
11
+ require "reins/sqlite_model"
12
+
13
+ module Reins
14
+ def self.framework_root
15
+ __dir__
16
+ end
17
+
18
+ class Application
19
+ def call(env)
20
+ # `echo debug > debug.txt`;
21
+ if env['PATH_INFO'] == '/favicon.ico'
22
+ return [404, {'content-type' => 'text/html'}, []]
23
+ end
24
+
25
+ begin
26
+ rack_app = get_rack_app(env)
27
+ rack_app.call(env)
28
+ rescue
29
+ return [500, {'content-type' => 'text/html'},
30
+ [File.read('public/500.html')]]
31
+ end
32
+ # klass, act = get_controller_and_action(env)
33
+ # controller = klass.new(env)
34
+ # text = controller.send(act)
35
+ # r = controller.get_response
36
+ # if r
37
+ # [r.status, r.headers, [r.body].flatten]
38
+ # else
39
+ # controller.render(act)
40
+ # r = controller.get_response
41
+ # [r.status, r.headers, [r.body].flatten]
42
+ # end
43
+ # begin
44
+ # text = controller.send(act)
45
+ # rescue
46
+ # return [500, {'content-type' => 'text/html'},
47
+ # ['Server Error']]
48
+ # end
49
+ # [200, {'content-type' => 'text/html'},
50
+ # [text]]
51
+ end
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reins-web
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ian Johnson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-04-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: erubis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: multi_json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: thor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: puma
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rerun
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: listen
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rack-test
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: minitest
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: A Rack-based Web Framework, but with extra awesome.
154
+ email:
155
+ - tacoda@hey.com
156
+ executables:
157
+ - reins
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - bin/console
162
+ - bin/reins
163
+ - bin/setup
164
+ - lib/reins.rb
165
+ - lib/reins/array.rb
166
+ - lib/reins/cli.rb
167
+ - lib/reins/controller.rb
168
+ - lib/reins/dependencies.rb
169
+ - lib/reins/file_model.rb
170
+ - lib/reins/routing.rb
171
+ - lib/reins/sqlite_model.rb
172
+ - lib/reins/util.rb
173
+ - lib/reins/version.rb
174
+ - lib/reins/view.rb
175
+ homepage: https://www.tacoda.dev/reins/
176
+ licenses: []
177
+ metadata:
178
+ homepage_uri: https://www.tacoda.dev/reins/
179
+ source_code_uri: https://github.com/tacoda/reins
180
+ changelog_uri: https://github.com/tacoda/reins
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - bin
185
+ - lib
186
+ required_ruby_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: 2.6.0
191
+ required_rubygems_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ requirements: []
197
+ rubygems_version: 3.4.10
198
+ signing_key:
199
+ specification_version: 4
200
+ summary: A Rack-based Web Framework
201
+ test_files: []