hyrum 0.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: 6af9ff6689127c74e41729fbd056dadf9a811ec19a74f14ccd6a61413d2b3c0b
4
+ data.tar.gz: 900a08d6f56ad8e8cdf70f60fcf5782859b78420c95c9afaf0c86f78815ab449
5
+ SHA512:
6
+ metadata.gz: 14adcecb5a38a2fe356e5c9eb27e5fc254d1ce45953bfe32d595ad909813a49ea5a641a99f9b64daae75f3322f09f0bfa8891d9885990f8b1159d7f6f40fbead
7
+ data.tar.gz: 19537c266190bcf175f8a340d8828fd354f974fbdb80639018e0d8862103a81bd792967b144afa4e2f5bc2cad78fd94e185bc30f7044cf8db62c1c004278cf55
data/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # Hyrum's Message Generator
2
+
3
+ ✨ A multi-language code generator to cope with Hyrum's law ✨
4
+
5
+ Hyrum's message generator (hyrum) generates a method in the chosen language that
6
+ returns one of several variations of a provided message at random.
7
+
8
+ ![Tests](https://github.com/grymoire7/hyrum/actions/workflows/ruby.yml/badge.svg?branch=main)
9
+ ![Ruby Version](https://img.shields.io/badge/Ruby-3.3.5-green?logo=Ruby&logoColor=red&label=Ruby%20version&color=green)
10
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/grymoire7/hyrum/blob/main/LICENSE.txt)
11
+
12
+ ## Explanation
13
+ [Hyrum's law][hd] states that all observable behaviors of your system will be
14
+ depended on by somebody. Some nice examples can be found [here][he].
15
+
16
+ One example that seems a little more difficult to handle is the case where a
17
+ status/error message is being returned to the user. How can you vary the message
18
+ so the user doesn't become dependent on the exact wording of the message?
19
+ Also, we don't want to spend a lot of time writing variations of the same message.
20
+
21
+ This is the use case Hyrum tries to solve. It uses an AI service (openai,
22
+ ollama, etc.) to generate variations of a provided message. The generated
23
+ variations are also formatted in the language/format of your choice (ruby,
24
+ json, etc.).
25
+
26
+ ## Example
27
+
28
+ ```bash
29
+ hyrum --service openai --key e418 --format ruby \
30
+ --message "The server refuses the attempt to brew coffee with a teapot"
31
+ ```
32
+
33
+ ```ruby
34
+ # frozen_string_literal: true
35
+
36
+ module Messages
37
+ MESSAGES = {
38
+ e418: [
39
+ "Invalid Brewing Method",
40
+ "Teapot not designed for coffee brewing",
41
+ "Please use a suitable brewing device",
42
+ "Coffee and tea are two distinct beverages with different requirements",
43
+ "Check your equipment and try again"
44
+ ]
45
+ }.freeze
46
+
47
+ def self.message(key)
48
+ MESSAGES[key].sample
49
+ end
50
+ end
51
+
52
+ if $PROGRAM_NAME == __FILE__
53
+ puts Messages.message(ARGV[0].to_sym)
54
+ end
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ```
60
+ ❯ hyrum --help # OR from the repo as `./exe/hyrum --help`
61
+ Usage: hyrum [options]
62
+ -v, --[no-]verbose Run verbosely
63
+ -f, --format FORMAT Output format. Supported formats are:
64
+ ruby, javascript, python, java, text, json
65
+ -m, --message MESSAGE Status message
66
+ -k, --key KEY Message key
67
+ -s, --service SERVICE AI service: one of openai, ollama, fake
68
+ -d, --model MODEL AI model: must be a valid model for the selected service
69
+ -h, --help Show this message
70
+ --version Show version
71
+ ```
72
+
73
+ ## Installation
74
+ NOTE: This gem is not yet available on rubygems.org. You can install it from the
75
+ repository with `bundle exec rake install`. In the future, you can...
76
+
77
+ Install the gem and add to the application's Gemfile by executing:
78
+
79
+ $ bundle add hyrum
80
+
81
+ If bundler is not being used to manage dependencies, install the gem by executing:
82
+
83
+ $ gem install hyrum
84
+
85
+ ## Run without configuration
86
+ Hyrum normally requires configuration to access an AI service provider. However,
87
+ if you want to see output quickly, you can use the `-s fake` option to use a fake
88
+ service provider that will generate stock responses.
89
+
90
+ ```bash
91
+ hyrum -s fake -f ruby -m "anything here"
92
+ ```
93
+
94
+ You don't even need to install the gem to use Hyrum, fake service provider or not.
95
+ You can run the executable directly from a cloned repository.
96
+
97
+ ```bash
98
+ ./exec/hyrum -s fake -f ruby -m "anything here"
99
+ ```
100
+
101
+ ## Configruation
102
+
103
+ ### OpenAI (`--service openai`)
104
+ Hyrum requires an OpenAI API token to access the language models. The API token should be
105
+ set as an environment variable as shown below.
106
+
107
+ ```bash
108
+ export OPENAI_ACCESS_TOKEN=your_open_ai_token
109
+ ```
110
+
111
+ If you specify the `openai` service but no model, Hyrum will use the `gpt-o4-mini`.
112
+
113
+ ### Ollama (`--service ollama`)
114
+ If you specify the `ollama` service, Hyrum will attempt to use the Ollama API
115
+ running at `http://localhost:11434`. You can set the `OLLAMA_URL` environment
116
+ variable to specify a different URL.
117
+
118
+ Make sure your ollama server is running before using the `ollama` service.
119
+
120
+ ```bash
121
+ ollama serve
122
+ ```
123
+
124
+ Use `ollama list` to see the available models. For more information on using
125
+ ollama and downloading models, see the [ollama repository](http://ollama.com).
126
+
127
+ ## Supported formats and AI services
128
+
129
+ See [Usage](#usage) for a list of supported formats and AI services.
130
+
131
+ ## Compatibility
132
+
133
+ This gem is compatible with Ruby 3.1 or greater.
134
+
135
+ ## Development
136
+
137
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
138
+ `rake spec` to run the tests.
139
+
140
+ To install this gem onto your local machine, run `bundle exec rake install`. To
141
+ release a new version, update the version number in `version.rb`, and then run
142
+ `bundle exec rake release`, which will create a git tag for the version, push
143
+ git commits and the created tag, and push the `.gem` file to
144
+ [rubygems.org](https://rubygems.org).
145
+
146
+ ## Contributing
147
+
148
+ Bug reports and pull requests are welcome on GitHub at
149
+ https://github.com/grymoire7/hyrum. This project is intended to be a safe,
150
+ welcoming space for collaboration, and contributors are expected to adhere to the
151
+ [code of conduct](https://github.com/grymoire7/hyrum/blob/main/CODE_OF_CONDUCT.md).
152
+
153
+ [hd]: https://www.laws-of-software.com/laws/hyrum/
154
+ [he]: https://abenezer.org/blog/hyrum-law-in-golang
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'hyrum'
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
+ require 'irb'
11
+ IRB.start(__FILE__)
data/bin/hyrum ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
5
+
6
+ require 'bundler/setup'
7
+ require 'hyrum'
8
+
9
+ # Hyrum::CLI.start(ARGV)
10
+ Hyrum.run(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,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrum
4
+ module Formats
5
+ FORMATS = %i[ruby javascript python java text json].freeze
6
+
7
+ class Formatter
8
+ attr_reader :options
9
+
10
+ def initialize(options)
11
+ @options = options
12
+ end
13
+
14
+ def format(messages)
15
+ template_file = File.join(__dir__, 'templates', "#{options[:format]}.erb")
16
+ template = ERB.new(File.read(template_file), trim_mode: '-')
17
+ template.result_with_hash(messages: messages)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ import java.util.HashMap;
2
+ import java.util.List;
3
+ import java.util.Random;
4
+
5
+ public class Messages {
6
+ private static final HashMap<String, List<String>> MESSAGES = new HashMap<>();
7
+
8
+ static {
9
+ <% messages.each do |key, values| -%>
10
+ MESSAGES.put("<%= key %>", List.of(
11
+ <%= values.map { |message| "\"#{message}\"" }.join(",\n ") %>
12
+ ));
13
+ <% end -%>
14
+ }
15
+
16
+ public static String message(String key) {
17
+ List<String> messages = MESSAGES.get(key);
18
+ if (messages != null && !messages.isEmpty()) {
19
+ Random random = new Random();
20
+ return messages.get(random.nextInt(messages.size()));
21
+ }
22
+ return null;
23
+ }
24
+
25
+ public static void main(String[] args) {
26
+ if (args.length > 0) {
27
+ System.out.println(message(args[0]));
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,19 @@
1
+ const Messages = {
2
+ MESSAGES: {
3
+ <% messages.each do |key, values| -%>
4
+ <%= key %>: [
5
+ <%= values.map { |message| "\"#{message}\"" }.join(",\n ") %>
6
+ ]<%= "," unless key == messages.keys.last %>
7
+ <% end -%>
8
+ },
9
+
10
+ message(key) {
11
+ const messages = this.MESSAGES[key];
12
+ return messages[Math.floor(Math.random() * messages.length)];
13
+ }
14
+ };
15
+
16
+ if (require.main === module) {
17
+ const key = process.argv[2];
18
+ console.log(Messages.message(key));
19
+ }
@@ -0,0 +1 @@
1
+ <%= JSON.pretty_generate(messages) %>
@@ -0,0 +1,18 @@
1
+ import random
2
+ import sys
3
+
4
+ class Messages:
5
+ MESSAGES = {
6
+ <% messages.each do |key, values| -%>
7
+ '<%= key %>': [
8
+ <%= values.map { |message| "\"#{message}\"" }.join(",\n ") %>
9
+ ]<%= "," unless key == messages.keys.last %>
10
+ <% end -%>
11
+ }
12
+
13
+ @staticmethod
14
+ def message(key):
15
+ return random.choice(Messages.MESSAGES[key])
16
+
17
+ if __name__ == "__main__":
18
+ print(Messages.message(sys.argv[1]))
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Messages
4
+ MESSAGES = {
5
+ <% messages.each do |key, values| -%>
6
+ <%= key %>: [
7
+ <%= values.map { |message| "\"#{message}\"" }.join(",\n ") %>
8
+ ]<%= "," unless key == messages.keys.last %>
9
+ <% end -%>
10
+ }.freeze
11
+
12
+ def self.message(key)
13
+ MESSAGES[key].sample
14
+ end
15
+ end
16
+
17
+ if $PROGRAM_NAME == __FILE__
18
+ puts Messages.message(ARGV[0].to_sym)
19
+ end
@@ -0,0 +1,6 @@
1
+ <% messages.each do |key, values| -%>
2
+ Messages for <%= key %>:
3
+ <% values.each do |msg| -%>
4
+ - <%= msg %>
5
+ <% end %>
6
+ <% end %>
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrum
4
+ module Generators
5
+ class FakeGenerator
6
+ FAKE_MESSAGES = %(
7
+ {
8
+ "e404": [
9
+ "We couldn't locate the resource you were looking for.",
10
+ "The resource you requested is not available at this time.",
11
+ "Unfortunately, we were unable to find the specified resource.",
12
+ "It seems the resource you're searching for does not exist.",
13
+ "The item you are trying to access is currently missing."
14
+ ],
15
+ "e418": [
16
+ "I'm a teapot",
17
+ "The server refuses the attempt to brew coffee with a teapot",
18
+ "Coffee brewing denied: a teapot is not suitable for this operation.",
19
+ "Request failed: the server cannot process coffee with a teapot.",
20
+ "Brewing error: teapots are incompatible with coffee preparation.",
21
+ "Action halted: using a teapot to brew coffee is not permitted.",
22
+ "Invalid request: please use a coffee maker instead of a teapot."
23
+ ],
24
+ "e500": [
25
+ "Internal Server Error",
26
+ "An unexpected condition was encountered"
27
+ ],
28
+ "e503": [
29
+ "Service Unavailable",
30
+ "The server is currently unavailable"
31
+ ],
32
+ "e504": [
33
+ "Gateway Timeout",
34
+ "The server is currently unavailable"
35
+ ]
36
+ }
37
+ )
38
+
39
+ attr_reader :options
40
+
41
+ def initialize(options)
42
+ @options = options
43
+ @ai_service = options[:ai_service]
44
+ end
45
+
46
+ def generate
47
+ JSON.parse(FAKE_MESSAGES)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrum
4
+ module Generators
5
+ AI_SERVICES = %i[openai ollama fake].freeze
6
+
7
+ AI_MODEL_DEFAULTS = {
8
+ openai: :'gpt-4o-mini',
9
+ ollama: :llama3,
10
+ fake: :fake
11
+ }.freeze
12
+
13
+ GENERATOR_CLASSES = {
14
+ openai: OpenaiGenerator,
15
+ ollama: OpenaiGenerator,
16
+ fake: FakeGenerator
17
+ }.freeze
18
+
19
+ class MessageGenerator
20
+ def self.create(options)
21
+ generator_class = GENERATOR_CLASSES[options[:ai_service].to_sym]
22
+
23
+ # Add error handling for invalid format
24
+ generator_class.new(options)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openai'
4
+ require 'json'
5
+ require 'erb'
6
+
7
+ module Hyrum
8
+ module Generators
9
+ class OpenaiGenerator
10
+ attr_reader :options
11
+
12
+ def initialize(options)
13
+ @options = options
14
+ configure
15
+ @client = OpenAI::Client.new
16
+ end
17
+
18
+ def generate
19
+ if options[:ai_model] == :fake
20
+ return JSON.parse(canned_content)
21
+ end
22
+
23
+ response = get_response(prompt)
24
+ puts "Response: #{JSON.pretty_generate(response)}" if options[:verbose]
25
+ content = response.dig('choices', 0, 'message', 'content')
26
+ JSON.parse(content)
27
+ end
28
+
29
+ private
30
+
31
+ def prompt
32
+ prompt = <<~PROMPT
33
+ Please provide 5 alternative status messages for the following message:
34
+ `<%= message %>`. The messages should be unique and informative. The messages
35
+ should be returned as json in the format: `{ "<%= key %>": ['list', 'of', 'messages']}`
36
+ The key should be `"<%= key %>"` followed by the list of messages.
37
+ PROMPT
38
+ erb_hash = { key: options[:key], message: options[:message] }
39
+ template = ERB.new(prompt, trim_mode: '-')
40
+ template.result_with_hash(erb_hash)
41
+ end
42
+
43
+ def get_response(prompt)
44
+ @client.chat(
45
+ parameters: {
46
+ model: options[:ai_model],
47
+ response_format: { type: 'json_object' },
48
+ messages: [{ role: 'user', content: prompt}],
49
+ temperature: 0.7
50
+ }
51
+ )
52
+ rescue OpenAI::Error => e
53
+ puts "OpenAI::Error: #{e.message}"
54
+ exit
55
+ rescue Faraday::Error => e
56
+ puts "Faraday::Error: #{e.message}"
57
+ puts "Please check that the #{options[:ai_model]} model is valid."
58
+ exit
59
+ end
60
+
61
+ def configure
62
+ OpenAI.configure do |config|
63
+ config.access_token = ENV.fetch('OPENAI_ACCESS_TOKEN') if options[:ai_service] == :openai
64
+ # config.log_errors = true # Use for development
65
+ config.organization_id = ENV['OPENAI_ORGANIZATION_ID'] if ENV['OPENAI_ORGANIZATION_ID']
66
+ config.request_timeout = 240
67
+ if options[:ai_service] == :ollama
68
+ config.uri_base = ENV['OLLAMA_URL'] || 'http://localhost:11434'
69
+ end
70
+ end
71
+ rescue KeyError => e
72
+ puts "Error: #{e.message}"
73
+ puts "Please set the OPENAI_ACCESS_TOKEN environment variable."
74
+ exit
75
+ end
76
+
77
+ def canned_content
78
+ FakeGenerator::FAKE_MESSAGES
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module Hyrum
6
+ class ScriptOptions
7
+ MANDATORY_OPTIONS = %i[message].freeze
8
+
9
+ attr_reader :options
10
+
11
+ def initialize(args)
12
+ @options = {}
13
+ @args = args
14
+ end
15
+
16
+ def parse
17
+ OptionParser.new do |parser|
18
+ define_options(parser)
19
+ parser.parse!(@args)
20
+ end
21
+ enforce_mandatory_options
22
+ options
23
+ rescue OptionParser::InvalidOption => e
24
+ err = "Invalid option: #{e.message}"
25
+ rescue OptionParser::MissingArgument => e
26
+ err = "Missing argument for option: #{e.message}"
27
+ rescue OptionParser::InvalidArgument => e
28
+ err = "Invalid argument for option: #{e.message}"
29
+ ensure
30
+ if err
31
+ puts err
32
+ exit
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def enforce_mandatory_options
39
+ missing = MANDATORY_OPTIONS.select { |param| options[param].nil? }
40
+ return if missing.empty?
41
+
42
+ raise OptionParser::MissingArgument, missing.join(', ')
43
+ end
44
+
45
+ def define_options(parser)
46
+ parser.banner = 'Usage: hyrum [options]'
47
+
48
+ verbosity_options(parser)
49
+ format_options(parser)
50
+ message_options(parser)
51
+ message_key_options(parser)
52
+ ai_service_options(parser)
53
+ on_tail_options(parser)
54
+ end
55
+
56
+ def on_tail_options(parser)
57
+ parser.on_tail('-h', '--help', 'Show this message') do
58
+ puts parser
59
+ exit
60
+ end
61
+
62
+ parser.on_tail('--version', 'Show version') do
63
+ puts Hyrum::VERSION
64
+ exit
65
+ end
66
+ end
67
+
68
+ def ai_service_options(parser)
69
+ description = "AI service: one of #{Generators::AI_SERVICES.join(', ')}"
70
+ parser.on('-s SERVICE', '--service SERVICE', Generators::AI_SERVICES, description) do |service|
71
+ options[:ai_service] = service.to_sym
72
+ end
73
+ options[:ai_service] ||= :fake
74
+
75
+ default_model = Generators::AI_MODEL_DEFAULTS[options[:ai_service]]
76
+ description = 'AI model: must be a valid model for the selected service'
77
+ parser.on('-d MODEL', '--model MODEL', description) do |model|
78
+ options[:ai_model] = model.to_sym
79
+ end
80
+ options[:ai_model] ||= default_model
81
+ end
82
+
83
+ def message_key_options(parser)
84
+ parser.on('-k KEY', '--key KEY', 'Message key') do |key|
85
+ options[:key] = key
86
+ end
87
+ options[:key] ||= 'status'
88
+ end
89
+
90
+ def message_options(parser)
91
+ parser.on('-m MESSAGE', '--message MESSAGE', 'Status message') do |message|
92
+ options[:message] = message
93
+ end
94
+ end
95
+
96
+ def verbosity_options(parser)
97
+ parser.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
98
+ options[:verbose] = v
99
+ end
100
+ end
101
+
102
+ def format_options(parser)
103
+ formats = Formats::FORMATS
104
+ description = 'Output format. Supported formats are:'
105
+ supported = formats.join(', ')
106
+ parser.on('-f FORMAT', '--format FORMAT', formats, description, supported) do |format|
107
+ options[:format] = format
108
+ end
109
+ options[:format] ||= :text
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrum
4
+ VERSION = '0.0.1'
5
+ end
data/lib/hyrum.rb ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'zeitwerk'
5
+ loader = Zeitwerk::Loader.for_gem
6
+ loader.setup
7
+
8
+ module Hyrum
9
+ def self.run(args)
10
+ options = ScriptOptions.new(args).parse
11
+ generator_opts = options.slice(:message, :key, :ai_service, :ai_model, :verbose)
12
+ formatter_opts = options.slice(:format, :verbose)
13
+
14
+ puts "Options: #{options.inspect}" if options[:verbose]
15
+ formatter = Formats::Formatter.new(formatter_opts)
16
+ message_generator = Generators::MessageGenerator.create(generator_opts)
17
+ messages = message_generator.generate
18
+ output = formatter.format(messages)
19
+ puts output
20
+ end
21
+ end
22
+
23
+ loader.eager_load
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hyrum
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tracy Atteberry
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-openai
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: zeitwerk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
41
+ description: A multi-language code generator to cope with Hyrum's law
42
+ email:
43
+ - tracy@tracyatteberry.com
44
+ executables:
45
+ - hyrum
46
+ extensions: []
47
+ extra_rdoc_files:
48
+ - README.md
49
+ files:
50
+ - README.md
51
+ - bin/console
52
+ - bin/hyrum
53
+ - bin/setup
54
+ - lib/hyrum.rb
55
+ - lib/hyrum/formats/formatter.rb
56
+ - lib/hyrum/formats/templates/java.erb
57
+ - lib/hyrum/formats/templates/javascript.erb
58
+ - lib/hyrum/formats/templates/json.erb
59
+ - lib/hyrum/formats/templates/python.erb
60
+ - lib/hyrum/formats/templates/ruby.erb
61
+ - lib/hyrum/formats/templates/text.erb
62
+ - lib/hyrum/generators/fake_generator.rb
63
+ - lib/hyrum/generators/message_generator.rb
64
+ - lib/hyrum/generators/openai_generator.rb
65
+ - lib/hyrum/script_options.rb
66
+ - lib/hyrum/version.rb
67
+ homepage: https://github.com/grymoire7/hyrum
68
+ licenses:
69
+ - MIT
70
+ metadata:
71
+ rubygems_mfa_required: 'true'
72
+ changelog_uri: https://github.com/grymoire7/hyrum/blob/main/CHANGELOG.md
73
+ post_install_message:
74
+ rdoc_options:
75
+ - "--title"
76
+ - Hyrum - Hyrum's Law Code Generator
77
+ - "--main"
78
+ - README.md
79
+ - "--line-numbers"
80
+ - "--inline-source"
81
+ - "--quiet"
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 3.1.0
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 3.5.23
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: A simple Ruby gem
99
+ test_files: []