gyoza-languages 1.0.1

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: 6ce01cc539ead25cf2994d84a0c608f5cf306e34d5fbfed03962abe710eb4a74
4
+ data.tar.gz: 1311b5faa6581735afd68f06bd3b8f509d3bfef28642c35faf52ce34ee9123a7
5
+ SHA512:
6
+ metadata.gz: 58bfae9ae6149021ee01bce0f03db9f97e8c8205b32307fc88d9e997dd83c0c254826c0e8c5493afaf9b0d8009d15689ef43d875f55923fa6a0ec17bc359a66f
7
+ data.tar.gz: 86e644db920232c5f8f31639647914761444c85f0e6eb6fededb8f459ee1d06168004d5c3998c688536a994f5a9e33fe412382c8aefc9419626d777b6f1fa6ae
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake', '~> 13.0'
6
+ gem 'erb', '~> 4.0.0'
7
+
8
+ gem 'rspec', '~> 3.0'
9
+
10
+ gem 'github-linguist', '~> 9.0.0'
11
+
12
+ gem 'puma', '~> 6.5.0'
13
+ gem 'rack', '~> 3.1.8'
14
+ gem 'rackup', '~> 2.2.1'
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ <p align="center">
2
+ <img src="https://img.shields.io/gem/v/gyoza-languages?color=aa0000" alt="">
3
+ <img src="https://img.shields.io/github/actions/workflow/status/git-gyoza/gyoza-languages/gem-push.yml?label=tests" alt="">
4
+ </p>
5
+
6
+ **gyoza-languages** is a simple interface that combines the
7
+ speed of [GitHub Linguist](https://github.com/github-linguist/linguist)
8
+ with the highly efficient Ruby web server [Puma](https://github.com/puma/puma).
9
+
10
+ It allows to query an **HTTP Rest API** to retrieve the languages data from one
11
+ or many repositories in a **JSON** format.
12
+
13
+ | Table of Contents |
14
+ |-------------------|
15
+ | [Usage](#usage) |
16
+ | [API](#api) |
17
+
18
+ # Usage
19
+
20
+ The application requires only a few arguments, but they are essential
21
+ for its correct functioning.
22
+
23
+ ```
24
+ A Ruby implementation of the Github linguist project with an integrated simple HTTP web server.
25
+
26
+ Usage: gyoza-languages [options]
27
+
28
+ -p, --port PORT Starts the server with the specified port.
29
+ -d, --directory DIRECTORY Manually specifies the repositories directory.
30
+ -h, --help Show this message
31
+
32
+ If the -d argument is not specified, a REPOSITORIES_DIRECTORY environment variable will be necessary.
33
+ ```
34
+
35
+ The most important (and mandatory) parameter is the `--directory`:
36
+ this represents the directory where all the repositories are stored.
37
+ Defining a correct directory is crucial for **managing** the web server **endpoints**.
38
+
39
+ You can set one by either creating an **environment variable** with name
40
+ **REPOSITORIES_DIRECTORY** or by directly specifying it using **--directory** (or **-d**).
41
+
42
+ Let's assume that the folder structure you choose looks like this:
43
+
44
+ ```python
45
+ repositories_directory:
46
+ images:
47
+ # a bunch of images
48
+ gyoza-languages:
49
+ # a clone of this repository
50
+ my_repositories:
51
+ super_awesome_repo:
52
+ # another Git repository
53
+ ```
54
+
55
+ This means that all the directories in the folder will become endpoints,
56
+ but only a few will be valid:
57
+
58
+ - `/images` will answer with **404 Not Found**, as it is not a **valid repository**;
59
+ - `/gyoza-languages` is a valid repository and will return the correct answer;
60
+ - `/my_repositories` is **NOT** a valid repository, even though it contains other repositories.
61
+ As such, it will answer with **404 Not Found**;
62
+ - `/my_repositories/super_awesome_repo` is a valid repository.
63
+
64
+ Along with that, the query parameter `branch` is also available,
65
+ meaning that it is possible to obtain the languages count from another branch.
66
+ An example is: `/myrepositories/super_awesome_repo?branch=dev` (if not existing, a **404 Not found**
67
+ message will be returned).
68
+
69
+ # API
70
+
71
+ **gyoza-languages** also provides an **API** for general purposes and one to interact with
72
+ the server started by the application itself.
73
+
74
+ After importing the module using `require 'gyoza-languages'`, two core classes are available:
75
+
76
+ - [GyozaApp](../main/lib/gyoza-languages/gyoza_app.rb).
77
+ This class offers five different methods that correspond to the **HTTP request methods**:
78
+
79
+ - `get(path, query, env)`;
80
+ - `post(path, query, env)`;
81
+ - `put(path, query, env)`;
82
+ - `patch(path, query, env)`;
83
+ - `delete(path, query, env)`.
84
+
85
+ By overriding these methods, it is possible to implement custom responses for each one
86
+ of the requests. The arguments passed are:
87
+
88
+ - `path`: the corresponding path in a string format;
89
+ - `query`: a hash that corresponds to the queried parameters;
90
+ - `env`: a hash comprehending all the current environment variables and more data.
91
+
92
+ If the **HTTP method** is not among the listed above, by overriding the `call(env)`
93
+ function it is possible to access directly to the core responding function, and
94
+ retrieve the method with `env[REQUEST_METHOD]`;
95
+
96
+ - [GyozaLanguageApp](../main/lib/gyoza-languages/gyoza_language_app.rb).
97
+ This class is the heart of the application. It extends
98
+ [GyozaApp](../main/lib/gyoza-languages/gyoza_app.rb) to provide support for
99
+ [GitHub Linguist](https://github.com/github-linguist/linguist) when a
100
+ **GET request** is done to the server.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gyoza-languages'
4
+
5
+ def usage
6
+ binary_name = GyozaLanguages::SPEC_NAME
7
+ env_var_name = GyozaLanguages::REPOSITORIES_DIRECTORY_ENV_NAME
8
+
9
+ puts(
10
+ "#{binary_name} #{GyozaLanguages::VERSION}
11
+ #{GyozaLanguages::SPEC_DESCRIPTION}.
12
+
13
+ Usage: #{binary_name} [options]
14
+
15
+ -p, --port PORT Starts the server with the specified port.
16
+ -d, --directory DIRECTORY Manually specifies the repositories directory.
17
+ -h, --help Show this message
18
+
19
+ If the -d argument is not specified, a #{env_var_name} environment variable will be necessary.")
20
+ end
21
+
22
+ def parse_arguments(parsed, args)
23
+ if args.length == 0
24
+ return
25
+ end
26
+
27
+ arg = args[0]
28
+ if arg == '-h' || arg == '--help'
29
+ usage
30
+ exit 0
31
+ end
32
+
33
+ if args.length == 1
34
+ puts("You did not specify enough arguments for argument #{arg}")
35
+ usage
36
+ exit 1
37
+ end
38
+
39
+ arg = arg.downcase
40
+ if arg == '-p'
41
+ arg = '--port'
42
+ elsif arg == '-d'
43
+ arg = '--directory'
44
+ else
45
+ unless arg == '--port' || arg == '--directory'
46
+ puts("Invalid argument: #{arg}")
47
+ exit 2
48
+ end
49
+ end
50
+
51
+ arg = arg[2..-1]
52
+ unless parsed.has_key?(arg)
53
+ parsed[arg] = args[1]
54
+ end
55
+ parse_arguments(parsed, args[2..-1])
56
+ end
57
+
58
+ def main(args)
59
+ parsed = {}
60
+ parse_arguments(parsed, args)
61
+
62
+ port = nil
63
+ if parsed.include?('port')
64
+ begin
65
+ port = parsed['port']
66
+ port = Integer(port)
67
+ if port < 1 || port > 65535
68
+ raise ArgumentError
69
+ end
70
+ rescue ArgumentError
71
+ puts("Invalid port \"#{port}\". Expected an integer between 1 and 65535")
72
+ exit 2
73
+ end
74
+ end
75
+
76
+ if parsed.include?('directory')
77
+ repo_directory = parsed['directory']
78
+ else
79
+ env_var_name = GyozaLanguages::REPOSITORIES_DIRECTORY_ENV_NAME
80
+ repo_directory = ENV[env_var_name]
81
+ if repo_directory.nil?
82
+ puts("No repositories directory specified.")
83
+ puts("You can specify one by using --directory or by defining the environment variable: #{env_var_name}")
84
+ exit 1
85
+ end
86
+ end
87
+
88
+ app = GyozaLanguageApp.new(repo_directory)
89
+ if port.nil?
90
+ app.start
91
+ else
92
+ app.start(port)
93
+ end
94
+ end
95
+
96
+ main(ARGV)
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rackup'
4
+ require 'rugged'
5
+ require 'linguist'
6
+ require 'json'
7
+
8
+ require_relative './string_utils'
9
+
10
+ # A wrapper for a web server.
11
+ # Works with rackup to start a new HTTP server.
12
+ class GyozaApp
13
+ attr_accessor :handler, :port
14
+
15
+ # Starts a new server at the specified port
16
+ # using a Rackup handler which is stored in the 'handler' attribute.
17
+ #
18
+ # If the server is already running (A.K.A. the handler attribute is set),
19
+ # a GyozaError is raised.
20
+ #
21
+ # Arguments:
22
+ # port: the port to start the server at (9172 by default)
23
+ def start(port = GyozaLanguages::DEFAULT_PORT)
24
+ if @handler.nil?
25
+ @handler = Rackup::Handler.default
26
+ @port = port
27
+ @handler.run(self, :Port => port)
28
+ else
29
+ raise GyozaError.serverAlreadyStarted(port)
30
+ end
31
+ end
32
+
33
+ # Stops the server.
34
+ #
35
+ # If the server is not running (A.K.A. the handler attribute is not set),
36
+ # a GyozaError is raised.
37
+ def stop
38
+ if @handler.nil?
39
+ raise GyozaError.serverNotStarted
40
+ else
41
+ @handler.stop
42
+ @handler = nil
43
+ @port = nil
44
+ end
45
+ end
46
+
47
+ # The method invoked by Puma when receiving
48
+ # an HTTP request.
49
+ #
50
+ # Uses get, post, put, patch and delete methods to
51
+ # separate requests.
52
+ # If the REQUEST_METHOD does not match any
53
+ # of the previously mentioned methods,
54
+ # returns the 405 HTTP status code.
55
+ #
56
+ # Arguments:
57
+ # env: the environment variables at the time of receiving the request
58
+ def call(env)
59
+ method = env['REQUEST_METHOD']
60
+ path = env['REQUEST_PATH']
61
+ query = StringUtils.query_string_to_hash(env['QUERY_STRING'])
62
+ case method
63
+ when 'GET'
64
+ get(path, query, env)
65
+ when 'POST'
66
+ post(path, query, env)
67
+ when 'PUT'
68
+ put(path, query, env)
69
+ when 'PATCH'
70
+ patch(path, query, env)
71
+ when 'DELETE'
72
+ delete(path, query, env)
73
+ else
74
+ response 405
75
+ end
76
+ end
77
+
78
+ # The response to a GET request.
79
+ # By default, returns the 405 HTTP status code.
80
+ #
81
+ # Arguments:
82
+ # path: the path of the repository
83
+ # query: a hash containing all the query parameters
84
+ # env: the environment variables at the time of receiving the request
85
+ protected def get(path, query, env)
86
+ response 405
87
+ end
88
+
89
+ # The response to a POST request.
90
+ # By default, returns the 405 HTTP status code.
91
+ #
92
+ # Arguments:
93
+ # path: the path of the repository
94
+ # query: a hash containing all the query parameters
95
+ # env: the environment variables at the time of receiving the request
96
+ protected def post(path, query, env)
97
+ response 405
98
+ end
99
+
100
+ # The response to a PUT request.
101
+ # By default, returns the 405 HTTP status code.
102
+ #
103
+ # Arguments:
104
+ # path: the path of the repository
105
+ # query: a hash containing all the query parameters
106
+ # env: the environment variables at the time of receiving the request
107
+ protected def put(path, query, env)
108
+ response 405
109
+ end
110
+
111
+ # The response to a PATCH request.
112
+ # By default, returns the 405 HTTP status code.
113
+ #
114
+ # Arguments:
115
+ # path: the path of the repository
116
+ # query: a hash containing all the query parameters
117
+ # env: the environment variables at the time of receiving the request
118
+ protected def patch(path, query, env)
119
+ response 405
120
+ end
121
+
122
+ # The response to a DELETE request.
123
+ # By default, returns the 405 HTTP status code.
124
+ #
125
+ # Arguments:
126
+ # path: the path of the repository
127
+ # query: a hash containing all the query parameters
128
+ # env: the environment variables at the time of receiving the request
129
+ protected def delete(path, query, env)
130
+ response 405
131
+ end
132
+
133
+ # Formats a new HTTP response from the given HTTP status code.
134
+ #
135
+ # Arguments:
136
+ # code: the status code
137
+ # body: the data sent to the client. The method will first try to
138
+ # convert the data in Json (unless it is String). If it fails,
139
+ # it will return the data accordingly
140
+ # headers: the headers to pass to the response.
141
+ # By default, this value is empty, and will be populated
142
+ # with the server name and current date
143
+ def response(code, body = nil, headers = {})
144
+ if code < 100 || code > 599
145
+ raise GyozaError.invalidStatusCode(code)
146
+ end
147
+
148
+ actual_headers = {}
149
+ headers.each do |key, value|
150
+ actual_headers[key.to_s.titleize] = value
151
+ end
152
+ headers = actual_headers
153
+
154
+ headers['Server'] = GyozaLanguages::SERVER_NAME
155
+ headers['Date'] = Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
156
+
157
+ unless body.nil?
158
+ if body.is_a?(String)
159
+ headers['Content-Type'] = 'text/plain'
160
+ else
161
+ body = JSON.dump(body)
162
+ headers['Content-Type'] = 'application/json'
163
+ end
164
+ end
165
+
166
+ [code, headers, body.nil? ? [] : [body]]
167
+ end
168
+
169
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Represents a general RuntimeError during the application execution
4
+ class GyozaError < RuntimeError
5
+
6
+ def self.invalidDirectory(directory)
7
+ return GyozaError.new("\"#{directory}\" is not a valid directory.")
8
+ end
9
+
10
+ def self.serverAlreadyStarted(port)
11
+ return GyozaError.new("Server is already listening on port #{port}.")
12
+ end
13
+
14
+ def self.serverNotStarted
15
+ return GyozaError.new('Server has not been started yet.')
16
+ end
17
+
18
+ def self.invalidStatusCode(code)
19
+ return GyozaError.new("Invalid status code #{code}. Expecting value between 100 and 599.")
20
+ end
21
+
22
+ end
23
+
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rugged'
4
+ require 'linguist'
5
+
6
+ require_relative 'gyoza_app'
7
+
8
+ # An implementation of GyozaApp that works with GitHub linguist.
9
+ class GyozaLanguageApp < GyozaApp
10
+ attr_accessor :repo_directory
11
+
12
+ # Initializes the Gyoza Language App.
13
+ #
14
+ # Arguments:
15
+ # repo_directory: the location where all the repositories are stored
16
+ def initialize(repo_directory)
17
+ if File.directory?(repo_directory)
18
+ @repo_directory = repo_directory
19
+ else
20
+ raise GyozaError.invalidDirectory(repo_directory)
21
+ end
22
+ end
23
+
24
+ def start(port = GyozaLanguages::DEFAULT_PORT)
25
+ puts("Starting gyoza-languages server on port #{port} with repositories directory: #{@repo_directory}")
26
+ super
27
+ end
28
+
29
+ # Checks in the repositories directory for the given repository
30
+ # in the path. If found, uses GitHub linguist to compute the
31
+ # used languages and returns them in a Json format.
32
+ # Otherwise, 404 'Not Found' is returned.
33
+ #
34
+ # Arguments:
35
+ # path: the path of the repository
36
+ # query: a hash of arguments. If the "branch" argument is specified, then
37
+ # the languages will be looked for that particular branch. However,
38
+ # if not found a 404 'Not Found' error is returned
39
+ # env: the environment variables at the time of receiving the request
40
+ protected def get(path, query, env)
41
+ repository = "#{@repo_directory}/#{path}"
42
+ unless File.directory?(repository)
43
+ return not_found('repository', path)
44
+ end
45
+
46
+ begin
47
+ repo = Rugged::Repository.new(repository)
48
+ rescue Rugged::RepositoryError
49
+ return not_found('repository', path)
50
+ end
51
+
52
+ target_id = repo.head.target_id
53
+ if query.include? 'branch'
54
+ begin
55
+ branch = query['branch']
56
+ target_id = repo.rev_parse_oid(branch)
57
+ rescue Rugged::ReferenceError
58
+ return not_found('branch', branch)
59
+ end
60
+ end
61
+
62
+ project = Linguist::Repository.new(repo, target_id)
63
+ languages = project.languages
64
+
65
+ response(200, languages)
66
+ end
67
+
68
+ private def not_found(type, name)
69
+ response(404, {
70
+ 'message' => "Could not find #{type}: #{name}"
71
+ })
72
+ end
73
+
74
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A collection of utilities for strings.
4
+ module StringUtils
5
+
6
+ # Converts the given query String to a Hash object.
7
+ # A query string is identified by a set of
8
+ # key-value pairs in the format "{key}={value}"
9
+ # separated by the '&' character.
10
+ #
11
+ # Arguments:
12
+ # string: the string to convert
13
+ def self.query_string_to_hash(string)
14
+ dict = {}
15
+ string.split('&').map do |pair|
16
+ key, value = pair.split('=')
17
+ dict[key] = value.sub('+', ' ')
18
+ end
19
+ dict
20
+ end
21
+
22
+ end
23
+
24
+ class String
25
+
26
+ # Capitalizes every word of the given String.
27
+ def titleize
28
+ self.split('-').map(&:capitalize).join('-')
29
+ end
30
+
31
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GyozaLanguages
4
+ VERSION = '1.0.1'
5
+ # The content sent as the HTTP Server header
6
+ SERVER_NAME = "Gyoza-Languages/#{VERSION}"
7
+ DEFAULT_PORT = 9172
8
+
9
+ SPEC_NAME = $PROGRAM_NAME.split('/').last
10
+ SPEC_DESCRIPTION = 'A Ruby implementation of the Github linguist project with an integrated simple HTTP web server'
11
+ REPOSITORIES_DIRECTORY_ENV_NAME = 'REPOSITORIES_DIRECTORY'
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'gyoza-languages/version'
4
+
5
+ module GyozaLanguages
6
+
7
+ require_relative 'gyoza-languages/gyoza_app'
8
+ require_relative 'gyoza-languages/gyoza_language_app'
9
+ require_relative 'gyoza-languages/gyoza_error'
10
+ require_relative 'gyoza-languages/string_utils'
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gyoza-languages
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Fulminazzo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-01-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '13.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: erb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 4.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 4.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: github-linguist
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 9.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 9.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: puma
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 6.5.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 6.5.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 3.1.8
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 3.1.8
97
+ - !ruby/object:Gem::Dependency
98
+ name: rackup
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 2.2.1
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 2.2.1
111
+ description: This Gem acts as a bridge between a simple Rest API and the Github linguist
112
+ program, to allow for languages retrieval with easy and parameterized requests.
113
+ email:
114
+ - gyoza@fulminazzo.it
115
+ executables:
116
+ - gyoza-languages
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - Gemfile
121
+ - README.md
122
+ - Rakefile
123
+ - bin/gyoza-languages
124
+ - lib/gyoza-languages.rb
125
+ - lib/gyoza-languages/gyoza_app.rb
126
+ - lib/gyoza-languages/gyoza_error.rb
127
+ - lib/gyoza-languages/gyoza_language_app.rb
128
+ - lib/gyoza-languages/string_utils.rb
129
+ - lib/gyoza-languages/version.rb
130
+ homepage: https://git.fulminazzo.it
131
+ licenses:
132
+ -
133
+ metadata:
134
+ homepage_uri: https://git.fulminazzo.it
135
+ source_code_uri: https://github.com/git-gyoza/gyoza-languages
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 3.1.0
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 3.5.22
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: A Ruby implementation of the Github linguist project with an integrated simple
155
+ HTTP web server
156
+ test_files: []