landline 0.9.2 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cfe9c90223c0d5d2fdc054e3aa2f96e76cdfeada0e865e13ef72d87b08526ff
4
- data.tar.gz: 5a3b62e85bdafa0f9470f42d6c6789c32a4eaf9f00df686188837c3b13c570ff
3
+ metadata.gz: 3032701a4da46a02233ca8b0f1a6c48a484dc068de78b0b82ea15381bc7950f1
4
+ data.tar.gz: ab0eba5a84fb6ba20fff26baf741cdd249c018cb74301b682d74b9d8b8bc043d
5
5
  SHA512:
6
- metadata.gz: f89f80cab3f587d952a3aaca92fce4f715d7778475ffc7c36abc207b6e377a233d8450e8b051013c6bcd7c77f9271fbdf0c48b336e0961f0841437fb7fef4f07
7
- data.tar.gz: 49a13a596296b21c9a8abedc9f1aaf479f7bdda3a20e0eeff874c2cb92f064df577e6b14067b31765cb4aeddbea46c35a54804a8ce77be66f47cdbf22b371a80
6
+ metadata.gz: a60a9110562ad5098f1bb3b93daf6449df72ff1bacb08ea6bc93684e528e7787fde92c53cd3d7ac1da5b800dada5672224329e72d31acf6b092a30208e463b61
7
+ data.tar.gz: ed7cf7655fe04a805da5079d793a4c2102b926d6d854206991c706221b65ca3f50c1dd441c223aca34196b713adb58ad92a642146302bd0480c2197affd29383
data/HACKING.md CHANGED
@@ -23,8 +23,3 @@ To keep things beautiful, consider following recommendations:
23
23
  - Document classes as if the next maintainer after you has you at gunpoint.
24
24
  Document thoroughly, use YARD tags and **never** skip on public method
25
25
  docs and class docs. As an example, consider Landline::PatternMatching::Glob.
26
- - Unit tests suck for many reasons. However, if you're writing a class that
27
- does not have any dependents and which is frequently used, consider making
28
- a unit test for it. People that might have to fix things further along
29
- will be very thankful.
30
-
data/LAYOUT.md CHANGED
@@ -8,15 +8,17 @@ layout as closely as possible.
8
8
  These are core classes of Landline and they are loaded as soon as the library is loaded.
9
9
 
10
10
  - Landline::Path [path.rb]
11
- - Landline::PathBinding [path.rb]
11
+ - Landline::PathContext [path.rb]
12
12
  - Landline::Probe [probe.rb]
13
- - Landline::ProbeBinding [probe.rb]
13
+ - Landline::ProbeContext [probe.rb]
14
14
  - Landline::Node (parent of Path and Probe) [node.rb]
15
15
  - Landline::Server (Rack application interface) [server.rb]
16
- - Landline::ServerBinding [server.rb]
16
+ - Landline::ServerContext [server.rb]
17
17
  - Landline::Request (Rack request wrapper) [request.rb]
18
18
  - Landline::Response (Rack response wrapper) [response.rb]
19
19
  - Landline::Pattern [pattern\_matching.rb]
20
+ - Landline::TemplateContext [tempalte.rb]
21
+ - Landline::Template (template engine interface) [template.rb]
20
22
 
21
23
  ## Patterns
22
24
 
@@ -29,31 +31,56 @@ These are classes that Landline::Pattern can interface with to create Patterns.
29
31
 
30
32
  These are module mixins that add common methods to DSL bindings.
31
33
 
32
- - Landline::DSL::PathConstructors [dsl/path\_constructors.rb]
34
+ - Landline::DSL::PathConstructors [dsl/constructors\_path.rb]
35
+ - Landline::DSL::ProbeConstructures [dsl/constructors\_probe.rb]
36
+ - Landline::DSL::CommonMethods [dsl/methods\_common.rb]
37
+ - Landline::DSL::PathMethods [dsl/methods\_path.rb]
38
+ - Landline::DSL::ProbeMethods [dsl/methods\_probe.rb]
39
+ - Landline::DSL::TemplateMethods [dsl/methods\_template.rb]
33
40
 
34
41
  ## Utilities
35
42
 
36
43
  These are self-contained classes and methods that add extra functionality to Landline.
37
44
 
38
45
  - Landline::Util::Lookup [util/lookup.rb]
46
+ - Landline::PatternMatching [pattern\_matching/util.rb]
47
+ - Landline::Cookie (class) [util/cookie.rb]
48
+ - Landline::Error (class) [util/errors.rb]
49
+ - Landline::ParsingError (class) [util/errors.rb]
50
+ - Landline::Util (html/http utilities) [util/html.rb]
51
+ - Landline::MIME (MIME extension to type association) [util/mime.rb]
52
+ - Landline::Util::ParserSorting (functions for sorting form/query hashes) [util/parsesorting.rb]
53
+ - Landline::Util::Query (query class) [util/query.rb]
54
+ - Landline::Util::FormPart (formparser struct) [util/multipart.rb]
55
+ - Landline::Util::MultipartParser (multipart form parser) [util/multipart.rb]
56
+ - Landline::Util::HeaderRegexp (helper regexps for headers) [util/parseutils.rb]
57
+ - Landline::Util (parser methods) [util/parseutils.rb]
39
58
 
40
59
  ## Probe subclasses
41
60
 
42
61
  These are reactive request handlers with their own semantics, if needed.
43
62
 
44
- - Landline::Handler [probe/handler.rb]
45
- - Landline::GETHandler [probe/http\_method.rb]
46
- - Landline::POSTHandler [probe/http\_method.rb]
47
- - Landline::HEADHandler [probe/http\_method.rb]
48
- - Landline::PUTHandler [probe/http\_method.rb]
49
- - Landline::DELETEHandler [probe/http\_method.rb]
50
- - Landline::CONNECTHandler [probe/http\_method.rb]
51
- - Landline::OPTIONSHandler [probe/http\_method.rb]
52
- - Landline::TRACEHandler [probe/http\_method.rb]
53
- - Landline::PATCHHandler [probe/http\_method.rb]
63
+ - Landline::Handlers::Handler [probe/handler.rb]
64
+ - Landline::Handlers::GETHandler [probe/http\_method.rb]
65
+ - Landline::Handlers::POSTHandler [probe/http\_method.rb]
66
+ - Landline::Handlers::HEADHandler [probe/http\_method.rb]
67
+ - Landline::Handlers::PUTHandler [probe/http\_method.rb]
68
+ - Landline::Handlers::DELETEHandler [probe/http\_method.rb]
69
+ - Landline::Handlers::CONNECTHandler [probe/http\_method.rb]
70
+ - Landline::Handlers::OPTIONSHandler [probe/http\_method.rb]
71
+ - Landline::Handlers::TRACEHandler [probe/http\_method.rb]
72
+ - Landline::Handlers::PATCHHandler [probe/http\_method.rb]
73
+ - Landline::Handlers::Serve
54
74
 
55
75
  ## Path subclasses
56
76
 
57
77
  These are navigation handlers with their own semantics.
58
78
 
59
79
  (currently none)
80
+
81
+ ## Template engine interfaces
82
+
83
+ These are uniform interfaces for various templating engines.
84
+
85
+ - Landline::Templates::ERB [template/erb.rb]
86
+ - Landline::Templates::Erubi [template/erubi.rb]
data/README.md CHANGED
@@ -142,7 +142,7 @@ For things to render correctly, please install the `redcarpet` gem.
142
142
 
143
143
  ```plain
144
144
  Landline - an HTTP request pattern matching system
145
- Copyright (C) 2022 yessiest (yessiest@memeware.net)
145
+ Copyright (C) 2022 yessiest (yessiest@text.512mb.org)
146
146
 
147
147
  This program is free software: you can redistribute it and/or modify
148
148
  it under the terms of the GNU General Public License as published by
@@ -5,23 +5,25 @@ module Landline
5
5
  # Probe (and subclasses) DSL construct
6
6
  module ProbeConstructors
7
7
  # Create a new erb template
8
- # @see {Landline::Template#new}
8
+ # @see Landline::Template#new
9
9
  def erb(input, vars = {})
10
10
  Landline::Templates::ERB.new(input,
11
- vars,
12
- parent: @origin)
11
+ vars,
12
+ parent: @origin,
13
+ filename: caller_locations[0].path)
13
14
  end
14
15
 
15
16
  # Create a new erb template using Erubi engine
16
- # @see {Landline::Template#new}
17
+ # @see Landline::Template#new
17
18
  # @param freeze [Boolean] whether to use frozen string literal
18
19
  # @param capture [Boolean] whether to enable output capturing
19
20
  def erubi(input, vars = {}, freeze: true, capture: false)
20
21
  Landline::Templates::Erubi.new(input,
21
- vars,
22
- parent: @origin,
23
- freeze: freeze,
24
- capture: capture)
22
+ vars,
23
+ parent: @origin,
24
+ freeze: freeze,
25
+ capture: capture,
26
+ filename: caller_locations[0].path)
25
27
  end
26
28
  end
27
29
  end
@@ -5,6 +5,27 @@ module Landline
5
5
  module DSL
6
6
  # Common path methods
7
7
  module PathMethods
8
+ # Bounce request if no handler found instead of issuing 404
9
+ def bounce
10
+ @origin.bounce = true
11
+ end
12
+
13
+ # Create a status code handler on path.
14
+ # Recursively applies to all paths unless overridden.
15
+ # @param code [Integer, nil] Specify a status code to handle
16
+ # @param block [#call] Block to run on given code
17
+ def handle(code = nil, &block)
18
+ @origin.properties["handle.#{code || 'default'}"] = block
19
+ end
20
+
21
+ # Insert a pass-through pipeline into request processing
22
+ # (i.e. for error handling purposes).
23
+ # Passed block should yield request (and return yielded data back).
24
+ # @param block [#call] block that yields request
25
+ def pipeline(&block)
26
+ @origin.pipeline = block
27
+ end
28
+
8
29
  # Set path index
9
30
  # @param index [Array,String]
10
31
  def index(index)
@@ -67,7 +88,9 @@ module Landline
67
88
 
68
89
  object
69
90
  end
70
- @origin.children.append(self.instance_eval(File.read(filename)))
91
+ @origin.children.append(
92
+ self.instance_eval(File.read(filename), filename)
93
+ )
71
94
  self.singleton_class.undef_method :run
72
95
  end
73
96
  end
@@ -8,8 +8,17 @@ module Landline
8
8
  # Common methods for template contexts
9
9
  module TemplateMethods
10
10
  # Import a template part
11
+ # @param filepath [String, File] path to the file (or the file itself)
12
+ # @return [String] compiled template
11
13
  def import(filepath)
12
- @parent_template.import(file(filepath)).run
14
+ template = if filepath.is_a? File
15
+ filepath
16
+ elsif filepath.start_with? "/"
17
+ File.open(filepath)
18
+ else
19
+ file(filepath)
20
+ end
21
+ @parent_template.import(template).run
13
22
  end
14
23
  end
15
24
  end
data/lib/landline/node.rb CHANGED
@@ -35,7 +35,7 @@ module Landline
35
35
  end
36
36
 
37
37
  # Try to navigate the path. Run method callback in response.
38
- # @param [Landline::Request]
38
+ # @param request [Landline::Request]
39
39
  # @return [Boolean]
40
40
  def go(request)
41
41
  # rejected at pattern
@@ -43,7 +43,8 @@ module Landline
43
43
 
44
44
  request.push_state
45
45
  path, splat, param = @pattern.match(request.path)
46
- do_filepath(request, request.path.delete_suffix(path))
46
+ do_filepath(request, request.path.delete_suffix('/')
47
+ .delete_suffix(path))
47
48
  request.path = path
48
49
  request.splat.append(*splat)
49
50
  request.param.merge!(param)
data/lib/landline/path.rb CHANGED
@@ -5,12 +5,16 @@ require_relative 'node'
5
5
  require_relative 'dsl/constructors_path'
6
6
  require_relative 'dsl/methods_path'
7
7
  require_relative 'dsl/methods_common'
8
+ require_relative 'dsl/methods_probe'
9
+ require_relative 'dsl/constructors_probe'
8
10
  require_relative 'util/lookup'
9
11
 
10
12
  module Landline
11
13
  # Execution context for filters and preprocessors.
12
14
  class ProcessorContext
13
15
  include Landline::DSL::CommonMethods
16
+ include Landline::DSL::ProbeMethods
17
+ include Landline::DSL::ProbeConstructors
14
18
 
15
19
  def initialize(path)
16
20
  @origin = path
@@ -54,21 +58,11 @@ module Landline
54
58
  # @return [Boolean] true if further navigation will be done
55
59
  # @raise [UncaughtThrowError] by default throws :response if no matches found.
56
60
  def process(request)
57
- return false unless run_filters(request)
58
-
59
- run_preprocessors(request)
60
- enqueue_postprocessors(request)
61
- @children.each do |x|
62
- if (value = x.go(request))
63
- return value
64
- end
61
+ if @pipeline
62
+ @pipeline.call(request) { |inner_req| process_wrapped(inner_req) }
63
+ else
64
+ process_wrapped(request)
65
65
  end
66
- value = index(request)
67
- return value if value
68
-
69
- _die(404)
70
- rescue StandardError => e
71
- _die(500, backtrace: [e.to_s] + e.backtrace)
72
66
  end
73
67
 
74
68
  # Add a preprocessor to the path.
@@ -95,7 +89,9 @@ module Landline
95
89
  @filters.append(block)
96
90
  end
97
91
 
98
- attr_reader :children, :properties
92
+ attr_reader :children, :properties, :request
93
+
94
+ attr_accessor :bounce, :pipeline
99
95
 
100
96
  private
101
97
 
@@ -123,6 +119,31 @@ module Landline
123
119
  request.postprocessors.append(*@postprocessors)
124
120
  end
125
121
 
122
+ # Method callback on successful request navigation.
123
+ # Finds the next appropriate path to go to.
124
+ # (inner pipeline-wrapped handler)
125
+ # @return [Boolean] true if further navigation will be done
126
+ # @raise [UncaughtThrowError] by default throws :response if no matches found.
127
+ def process_wrapped(request)
128
+ @request = request
129
+ return false unless run_filters(request)
130
+
131
+ run_preprocessors(request)
132
+ enqueue_postprocessors(request)
133
+ @children.each do |x|
134
+ value = x.go(request)
135
+ return value if value
136
+ end
137
+ value = index(request)
138
+ return value if value
139
+
140
+ @bounce ? false : _die(404)
141
+ rescue StandardError => e
142
+ _die(500, backtrace: [e.to_s] + e.backtrace)
143
+ ensure
144
+ @request = nil
145
+ end
146
+
126
147
  # Try to perform indexing on the path if possible
127
148
  # @param request [Landline::Request]
128
149
  # @return [Boolean] true if indexing succeeded
@@ -146,11 +167,12 @@ module Landline
146
167
  # @raise [UncaughtThrowError] throws :finish to stop processing
147
168
  def _die(errorcode, backtrace: nil)
148
169
  throw :finish, [errorcode].append(
149
- *(@properties["handle.#{errorcode}"] or
150
- @properties["handle.default"]).call(
151
- errorcode,
152
- backtrace: backtrace
153
- )
170
+ *@proccontext.instance_exec(
171
+ errorcode,
172
+ backtrace: backtrace,
173
+ &(@properties["handle.#{errorcode}"] or
174
+ @properties["handle.default"])
175
+ )
154
176
  )
155
177
  end
156
178
  end
@@ -52,7 +52,7 @@ module Landline
52
52
  # - underscores
53
53
  # - dashes
54
54
  class Glob
55
- # @param input [String] Glob pattern
55
+ # @param pattern [String] Glob pattern
56
56
  def initialize(pattern)
57
57
  pattern = Landline::PatternMatching.canonicalize(pattern)
58
58
  pieces = pattern.split(TOKENS)
@@ -39,7 +39,7 @@ module Landline
39
39
  end
40
40
 
41
41
  # Test if input is convertible and if it should be converted.
42
- # @param input
42
+ # @param string [String] input to test conversion on
43
43
  # @return [Boolean] Input can be safely converted to Glob
44
44
  def self.can_convert?(string)
45
45
  string.is_a? Regexp
@@ -7,7 +7,7 @@ module Landline
7
7
  # Probe that executes a callback on request
8
8
  class Handler < Landline::Probe
9
9
  # @param path [Object]
10
- # @param parent [Landline::Node]
10
+ # @param args [Hash] hashed parameters to passthrough to Probe
11
11
  # @param exec [#call]
12
12
  def initialize(path, **args, &exec)
13
13
  super(path, **args)
@@ -15,10 +15,10 @@ module Landline
15
15
  @context = Landline::ProbeContext.new(self)
16
16
  @response = nil
17
17
  end
18
-
18
+
19
19
  attr_accessor :response
20
20
  attr_reader :request
21
-
21
+
22
22
  # Method callback on successful request navigation.
23
23
  # Runs block supplied with object initialization.
24
24
  # Request's #splat and #param are passed to block.
@@ -9,7 +9,6 @@ module Landline
9
9
  class Serve < Landline::Probe
10
10
  # @param path [Object]
11
11
  # @param parent [Landline::Node]
12
- # @param exec [#call]
13
12
  def initialize(path, parent:)
14
13
  super(path, parent: parent, filepath: true)
15
14
  end
@@ -7,8 +7,8 @@ module Landline
7
7
  module Templates
8
8
  # ERB Template language adapter
9
9
  class ERB < Landline::Template
10
- # @see {Landline::Template#new}
11
- def initialize(input, vars = nil, parent:)
10
+ # (see Landline::Template#new)
11
+ def initialize(input, vars = nil, parent:, filename:)
12
12
  super
13
13
  varname = "_part_#{SecureRandom.hex(10)}".to_sym
14
14
  while @binding.local_variable_defined? varname
@@ -20,6 +20,7 @@ module Landline
20
20
 
21
21
  # Run the template.
22
22
  def run
23
+ @template.filename = @filename
23
24
  @template.result @binding
24
25
  end
25
26
  end
@@ -7,29 +7,27 @@ module Landline
7
7
  module Templates
8
8
  # Erubi (ERB) template language adapter
9
9
  class Erubi < Landline::Template
10
- # @see {Landline::Template#new}
10
+ # (see Landline::Template#new)
11
11
  def initialize(input,
12
12
  vars = nil,
13
- parent:,
14
- freeze: true,
15
- capture: false)
16
- super(input, vars, parent: parent)
13
+ **ext)
14
+ super(input, vars, parent: ext[:parent], filename: ext[:filename])
17
15
  varname = "_part_#{SecureRandom.hex(10)}"
18
16
  while @binding.local_variable_defined? varname.to_sym
19
17
  varname = "_part_#{SecureRandom.hex(10)}"
20
18
  end
21
19
  properties = {
22
- filename: input.is_a?(File) ? input.path : "(Inline)",
23
20
  bufvar: varname,
24
- freeze: freeze
21
+ freeze: ext.fetch(:freeze, true)
25
22
  }
23
+ capture = ext.fetch(:capture, false)
26
24
  engine = capture ? ::Erubi::CaptureEndEngine : ::Erubi::Engine
27
25
  @template = engine.new(@template, properties)
28
26
  end
29
27
 
30
28
  # Run the template.
31
29
  def run
32
- @binding.eval(@template.src)
30
+ @binding.eval(@template.src, @filename)
33
31
  end
34
32
  end
35
33
  end
@@ -36,8 +36,13 @@ module Landline
36
36
  # @param input [String, File] template text
37
37
  # @param vars [Hash] local variables for tempalte
38
38
  # @param parent [Landline::Node] parent node
39
- def initialize(input, vars = {}, parent:)
40
- @template = input.is_a?(File) ? input.read : input
39
+ # @param filename [String] filename for eval if input is a string
40
+ def initialize(input, vars = {}, parent:, filename:)
41
+ @template, @filename = if input.is_a?(File)
42
+ [input.read, input.path]
43
+ else
44
+ [input, filename]
45
+ end
41
46
  @context = TemplateContext.new(parent, self)
42
47
  @parent = parent
43
48
  input.close if input.is_a? File
@@ -81,9 +86,14 @@ module Landline
81
86
  # ... (stub)
82
87
  end
83
88
 
84
- # Import a template from within current template
85
- def import(filepath)
86
- newtemp = self.class.new(filepath, {}, parent: @parent)
89
+ # Import a template from within current template.
90
+ # @param file [File] template file to import
91
+ # @return [Landline::Template] loaded tempalte
92
+ def import(file)
93
+ newtemp = self.class.new(file,
94
+ {},
95
+ parent: @parent,
96
+ filename: file.path)
87
97
  newtemp.binding = @binding
88
98
  newtemp
89
99
  end
@@ -1267,7 +1267,7 @@ module Landline
1267
1267
  }.freeze
1268
1268
 
1269
1269
  # Get MIME type by file extension
1270
- # @param ext [String] filename
1270
+ # @param file [String] filename
1271
1271
  # @return [String] MIME type, defaults to "application/octet-stream"
1272
1272
  def self.get_mime_type(file)
1273
1273
  MIME[file.match(/\.(\w+)$/)&.[](1)] or "application/octet-stream"
@@ -9,6 +9,8 @@ require_relative 'html'
9
9
 
10
10
  module Landline
11
11
  module Util
12
+ FormPart = Struct.new(:data, :name, :filename,
13
+ :filetype, :tempfile, :headers)
12
14
  # Valid element of form data with headers
13
15
  # @!attribute headers [Hash] headers recevied from form data
14
16
  # @!attribute name [String] name of the form part
@@ -16,8 +18,7 @@ module Landline
16
18
  # @!attribute filename [String,nil] Original name of the sent file
17
19
  # @!attribute filetype [String,nil] MIME-type of the file
18
20
  # @!attribute tempfile [File,nil] Temporary file for storing sent file data.
19
- FormPart = Struct.new(:data, :name, :filename,
20
- :filetype, :tempfile, :headers) do
21
+ class FormPart
21
22
  # Is this form part a file or plain data?
22
23
  # @return [Boolean]
23
24
  def file?
@@ -135,7 +136,8 @@ module Landline
135
136
  end
136
137
 
137
138
  # Setup file metadata
138
- # @part part [FormPart]
139
+ # @param part [Landline::Util::FormPart]
140
+ # @return [void]
139
141
  def setup_file_meta(part)
140
142
  part.name = part.headers.dig("content-disposition", 1, "name")
141
143
  part.filename = part.headers.dig("content-disposition", 1, "filename")
@@ -144,7 +146,8 @@ module Landline
144
146
  end
145
147
 
146
148
  # Setup plain metadata
147
- # @part part [FormPart]
149
+ # @param part [Landline::Util::FormPart]
150
+ # @return [void]
148
151
  def setup_data_meta(part)
149
152
  part.name = part.headers.dig("content-disposition", 1, "name")
150
153
  end
data/lib/landline.rb CHANGED
@@ -10,10 +10,10 @@ require_relative 'landline/template'
10
10
  # Landline is a hideously simple ruby web framework
11
11
  module Landline
12
12
  # Landline version
13
- VERSION = '0.9 "Moonsong" (beta/rewrite)'
13
+ VERSION = '0.10 "Node graph out of date. Rebuilding..." (beta)'
14
14
 
15
15
  # Landline branding and version
16
- VLINE = "Landline/#{Landline::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})\n"
16
+ VLINE = "Landline/#{Landline::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})\n".freeze
17
17
 
18
18
  # Landline copyright
19
19
  COPYRIGHT = "Copyright 2023 Yessiest"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: landline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yessiest
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-22 00:00:00.000000000 Z
11
+ date: 2023-10-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Landline is a no-hard-dependencies HTTP routing DSL that was made entirely for fun.
@@ -71,7 +71,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: '0'
74
+ version: 3.0.6
75
75
  required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  requirements:
77
77
  - - ">="