mokkku 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dea0bbaeb26c51558aa530f63a7a57ea1118d5d858c46b284b0aa0eefa43fe1c
4
- data.tar.gz: 63c3ff3581a61bae6f77c9f20a11a56cd7bca662c4722f7284c8ac1523b0b4fb
3
+ metadata.gz: 04c69427e72610fa1be06c75060a255eb0ab45c64b3e1a65a5649aa2420552f7
4
+ data.tar.gz: efc88cd532cd54f28ae0dc4fb2c8cfba8fb0d3e674183494fdc47ef8adcfef15
5
5
  SHA512:
6
- metadata.gz: dc4da5ff3401d84a7c6340da54caa95a334fb548b7d33eb7194487492276c202c61bf17dc9eea471d982ea134076d5f821de7d4d23f248929cdbf67fb7a67369
7
- data.tar.gz: a8a65b0ce61a7317d43261ec44e83a47344524c4226fa8f6d78d69f27544d703b0f8b501fbb6001765ff555aec60b27f1b34d637de1960cdc8fe697ce2902f76
6
+ metadata.gz: afc7eb5280d025becdd44e0bd65412645a15bea68812ccc3c09a9179f79b2327faed3937c326c5da56f484a29cafc65e2d1f7bdf98550fff3d8a40995698f864
7
+ data.tar.gz: e07d24c250a66e1550da05e37a4961c3d4ad0e389e905aa662ca514ac9b96af48c263d3c24fab1e5281884f267381c5fbe588d8c67cd1540981388e81d707e81
data/bin/mokkku ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'mokkku'
5
+ require 'optionparser'
6
+
7
+ options = {}
8
+
9
+ OptionParser.new do |opts|
10
+ opts.banner = 'Usage: mokkku [options]'
11
+
12
+ opts.on('-m', '--model Model', 'Provide model name to generate mocks for') do |opt|
13
+ options[:models] = [opt]
14
+ end
15
+
16
+ opts.on('--models Model1,Model2', 'Provide model names to generate mocks for') do |opt|
17
+ options[:models] = opt.split(',')
18
+ end
19
+
20
+ opts.on('-a', '--api-key value', 'API key for LLM') do |opt|
21
+ options[:llm_api_key] = opt
22
+ end
23
+
24
+ opts.on('-llm', '--llm-model value', 'Type of LLM: GPT, Gemini, or Claude') do |opt|
25
+ options[:llm_model] = opt
26
+ end
27
+
28
+ opts.on('-p', '--mocks-path value', 'Location where files will be created, default to ./spec/mocks') do |opt|
29
+ options[:mocks_path] = opt
30
+ end
31
+
32
+ opts.on('-c', '--count value', 'Number of entries to generate in mock file, 10 by default') do |opt|
33
+ options[:mocks_count] = opt
34
+ end
35
+
36
+ opts.on('-l', '--language value', 'The language of mocks, english by default') do |opt|
37
+ options[:language] = opt
38
+ end
39
+ end.parse!
40
+
41
+ Mokkku::Cli::Runner.start(options)
@@ -0,0 +1,27 @@
1
+ module Mokkku
2
+ module Cli
3
+ class Prompt
4
+ IGNORED_COLUMNS = %w[id created_at updated_at].freeze
5
+
6
+ def self.generate(model_name, columns, mocks_count, language)
7
+ columns_for_prompt = columns.reject { |col| IGNORED_COLUMNS.include?(col.name) || col.name.match?(/.*\_id$/) }
8
+ .inject({}) { |hash, col| hash[col.name] = col.sql_type_metadata.type; hash }
9
+
10
+ prompt_start = "Act like a virtual assistant that generates YAML file with the test data for a given Ruby on Rails model. Generate #{mocks_count.to_i} entries for the following model named #{model_name}:"
11
+
12
+ yaml_attributes = columns_for_prompt.map do |name, type|
13
+ " #{name}: #{type}\n"
14
+ end
15
+
16
+ prompt_yaml_part = "- #{yaml_attributes.join}"
17
+ prompt_summary = 'Reply only with the content of the YAML file.'
18
+
19
+ if language != 'english'
20
+ prompt_summary += " Translate test data to #{language} language."
21
+ end
22
+
23
+ "#{prompt_start}\n\n#{prompt_yaml_part}\n\n#{prompt_summary}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'validator'
2
+ require_relative 'prompt'
3
+ require_relative '../generators/builder'
4
+ require_relative '../yaml_sanitizer'
5
+
6
+ module Mokkku
7
+ module Cli
8
+ class Runner
9
+ def self.start(options = {})
10
+ ::Mokkku::Cli::Validator.validate_options!(options)
11
+
12
+ options[:models].each do |model_name|
13
+ columns = Object.const_get(model_name).columns
14
+ prompt = ::Mokkku::Cli::Prompt.generate(model_name, columns, options.fetch(:mocks_count, 10), options.fetch(:language, 'english'))
15
+ generator = ::Mokkku::Generators::Builder.call(
16
+ generator: options[:llm_model],
17
+ api_key: options[:llm_api_key],
18
+ prompt: prompt
19
+ )
20
+
21
+ yaml_mock = generator.call(api_key: options[:llm_api_key], prompt: prompt)
22
+ mock_file_name = model_name.to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
23
+
24
+ puts "Write mocks for #{model_name} model in #{mock_file_name}.yml"
25
+ File.write(
26
+ File.join(options.fetch(:mocks_path, './spec/mocks'), "#{mock_file_name}.yml"),
27
+ ::Mokkku::YamlSanitizer.sanitize(yaml_mock)
28
+ )
29
+ end
30
+
31
+ puts 'Done!'
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ module Mokkku
2
+ module Cli
3
+ module Validator
4
+ ModelsNotProvided = Class.new(StandardError)
5
+ InvalidLlmModel = Class.new(StandardError)
6
+ LlmApiKeyNotProvided = Class.new(StandardError)
7
+
8
+ def self.validate_options!(options)
9
+ raise ModelsNotProvided if options.fetch(:models, []).empty?
10
+ raise InvalidLlmModel unless %w[gpt gemini claude].include?(options[:llm_model].to_s.downcase)
11
+ raise LlmApiKeyNotProvided if options[:llm_api_key].to_s == ''
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'gpt'
2
+ require_relative 'claude'
3
+
4
+ module Mokkku
5
+ module Generators
6
+ class Builder
7
+ UnsupportedGenerator = Class.new(StandardError)
8
+
9
+ def self.call(generator:, api_key:, prompt:)
10
+ case generator
11
+ when 'gpt'
12
+ Mokkku::Generators::Gpt
13
+ when 'claude'
14
+ Mokkku::Generators::Claude
15
+ else
16
+ raise UnsupportedGenerator
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'anthropic'
2
+
3
+ module Mokkku
4
+ module Generators
5
+ class Claude
6
+ def self.call(api_key:, prompt:)
7
+ client = Anthropic::Client.new(access_token: api_key)
8
+
9
+ response = client.messages(
10
+ parameters: {
11
+ model: 'claude-3-5-sonnet-20240620',
12
+ system: 'Respond only with code.',
13
+ messages: [
14
+ { 'role': 'user', 'content': prompt },
15
+ ],
16
+ max_tokens: 1_000
17
+ }
18
+ )
19
+
20
+ response['content'].first['text']
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ require 'openai'
2
+
3
+ module Mokkku
4
+ module Generators
5
+ class Gpt
6
+ def self.call(api_key:, prompt:)
7
+ client = OpenAI::Client.new(access_token: api_key)
8
+
9
+ response = client.completions(parameters: {
10
+ prompt: prompt,
11
+ model: 'gpt-3.5-turbo-instruct',
12
+ temperature: 0,
13
+ max_tokens: 1_000,
14
+ top_p: 1.0,
15
+ frequency_penalty: 0.0,
16
+ presence_penalty: 0.0
17
+ })
18
+
19
+ response['choices'].first['text']
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,7 +3,7 @@ module Mokkku
3
3
  module_function
4
4
 
5
5
  def to_s
6
- '0.0.1'
6
+ '0.0.3'
7
7
  end
8
8
  end
9
9
  end
@@ -0,0 +1,13 @@
1
+ module Mokkku
2
+ class YamlSanitizer
3
+ def self.sanitize(yaml_content)
4
+ # Some LLMs ignore the instructions and return YAML with additions
5
+ yaml_lines = yaml_content.split("\n")
6
+ yaml_lines.shift if yaml_lines.first.start_with?("`")
7
+ yaml_lines.pop if yaml_lines.last.start_with?("`")
8
+ yaml_lines.shift unless yaml_lines.first.strip.start_with?('-')
9
+
10
+ yaml_lines.join("\n")
11
+ end
12
+ end
13
+ end
data/lib/mokkku.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'mokkku/utils'
2
+ require_relative 'mokkku/cli/runner'
2
3
 
3
4
  module Mokkku
4
5
  extend Mokkku::Utils
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mokkku
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paweł Dąbrowski
@@ -44,16 +44,53 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: ruby-openai
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 7.1.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 7.1.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: anthropic
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.3.0
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 0.3.0
47
75
  description: Generate mock data that is unique for your application
48
76
  email: contact@paweldabrowski.com
49
- executables: []
77
+ executables:
78
+ - mokkku
50
79
  extensions: []
51
80
  extra_rdoc_files: []
52
81
  files:
82
+ - bin/mokkku
53
83
  - lib/mokkku.rb
84
+ - lib/mokkku/cli/prompt.rb
85
+ - lib/mokkku/cli/runner.rb
86
+ - lib/mokkku/cli/validator.rb
87
+ - lib/mokkku/generators/builder.rb
88
+ - lib/mokkku/generators/claude.rb
89
+ - lib/mokkku/generators/gpt.rb
54
90
  - lib/mokkku/mocked_object.rb
55
91
  - lib/mokkku/utils.rb
56
92
  - lib/mokkku/version.rb
93
+ - lib/mokkku/yaml_sanitizer.rb
57
94
  homepage:
58
95
  licenses: []
59
96
  metadata: {}