poke-your-api 0.2.7 → 0.4.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 +4 -4
- data/lib/poke/cli.rb +13 -0
- data/lib/poke/commands/curl.rb +9 -10
- data/lib/poke/commands/env.rb +5 -61
- data/lib/poke/commands/new.rb +109 -0
- data/lib/poke/commands/speed.rb +9 -11
- data/lib/poke/curl_parser.rb +156 -0
- data/lib/poke/group_config.rb +4 -0
- data/lib/poke/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 54d9c5d820d46a25b19322bf0b8208a79bff75aff71854354a1f755e3ed998f5
|
|
4
|
+
data.tar.gz: f343b6aa3e2d9e4c44f5e4a1273d7d3632fbb5799f67c0d56091254c524174a7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f1809cfd27e99c1a1f1742b79f3b405b548ea0d87fe1e1b403b557677c4f60b41beab68d5613271b5891b8b4532e8f961421d6bdb8f958ee2529e8b25bebed8
|
|
7
|
+
data.tar.gz: d89ddcce79212dfafe919eceb3106aef349ce15209ce39c10d4424d2c80bf690dede87b5e485b5b96397a07ab81a254515ee72ff39d618a505b644a02cc3fd4f
|
data/lib/poke/cli.rb
CHANGED
|
@@ -24,6 +24,8 @@ module Poke
|
|
|
24
24
|
desc 'env', 'Display and edit environments'
|
|
25
25
|
method_option :help, aliases: '-h', type: :boolean,
|
|
26
26
|
desc: 'Display usage information'
|
|
27
|
+
method_option :open, aliases: '-o', type: :boolean,
|
|
28
|
+
desc: 'Open config in the editor'
|
|
27
29
|
def env(*)
|
|
28
30
|
if options[:help]
|
|
29
31
|
invoke :help, ['env']
|
|
@@ -33,6 +35,17 @@ module Poke
|
|
|
33
35
|
end
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
desc 'new', 'Create a new request'
|
|
39
|
+
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
|
40
|
+
def new(*)
|
|
41
|
+
if options[:help]
|
|
42
|
+
invoke :help, ['new']
|
|
43
|
+
else
|
|
44
|
+
require_relative 'commands/new'
|
|
45
|
+
Poke::Commands::New.new(options).execute
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
36
49
|
desc 'curl', 'Find and execute a request'
|
|
37
50
|
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
|
38
51
|
method_option :env, aliases: '-e', type: :string, desc: 'Set target environment'
|
data/lib/poke/commands/curl.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative '../group'
|
|
|
5
5
|
require_relative '../config'
|
|
6
6
|
require_relative '../paint'
|
|
7
7
|
require_relative '../last_recently_used'
|
|
8
|
+
require_relative '../curl_parser'
|
|
8
9
|
|
|
9
10
|
require 'pathname'
|
|
10
11
|
require 'pastel'
|
|
@@ -96,16 +97,14 @@ module Poke
|
|
|
96
97
|
end
|
|
97
98
|
|
|
98
99
|
def build_command(path)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
[command_lines.join(" \\\n "), comments]
|
|
100
|
+
content = File.read(path)
|
|
101
|
+
parser = CurlParser.new(content)
|
|
102
|
+
|
|
103
|
+
# Add our additional curl parameters
|
|
104
|
+
parser.add_argument("-o #{Poke::Config.response_path}")
|
|
105
|
+
parser.add_argument('-w "%{json}"')
|
|
106
|
+
|
|
107
|
+
[parser.to_command_with_line_continuation, parser.comments.join("\n")]
|
|
109
108
|
end
|
|
110
109
|
|
|
111
110
|
# rubocop:disable Style/FormatStringToken
|
data/lib/poke/commands/env.rb
CHANGED
|
@@ -2,16 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../command'
|
|
4
4
|
require_relative '../group'
|
|
5
|
-
require_relative '../paint'
|
|
6
5
|
|
|
7
|
-
require '
|
|
8
|
-
|
|
9
|
-
require 'tty-box'
|
|
10
|
-
require 'tty-command'
|
|
11
|
-
require 'tty-cursor'
|
|
6
|
+
require 'json'
|
|
12
7
|
require 'tty-editor'
|
|
13
8
|
require 'tty-prompt'
|
|
14
|
-
require 'tty-table'
|
|
15
9
|
|
|
16
10
|
module Poke
|
|
17
11
|
module Commands
|
|
@@ -23,60 +17,10 @@ module Poke
|
|
|
23
17
|
group_name = TTY::Prompt.new.select('Select the group', groups.map(&:name), filter: true, quiet: true)
|
|
24
18
|
group = groups.find { |g| g.name == group_name }
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@cursor ||= TTY::Cursor
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def pastel
|
|
34
|
-
@pastel ||= Pastel.new
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def manage_group_config(output:, group:)
|
|
38
|
-
output << cursor.save
|
|
39
|
-
|
|
40
|
-
render(output, group)
|
|
41
|
-
|
|
42
|
-
loop do
|
|
43
|
-
case TTY::Prompt.new.keypress('', quiet: true)
|
|
44
|
-
when 'c'
|
|
45
|
-
group.config.default_env = TTY::Prompt.new.select(
|
|
46
|
-
'Select new default environment', group.config.envs,
|
|
47
|
-
filter: true, quiet: true
|
|
48
|
-
)
|
|
49
|
-
group.save_config!
|
|
50
|
-
|
|
51
|
-
render(output, group)
|
|
52
|
-
when 'e'
|
|
53
|
-
TTY::Editor.open(group.config_path)
|
|
54
|
-
break
|
|
55
|
-
when 'q'
|
|
56
|
-
break
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def render(output, group)
|
|
62
|
-
output << cursor.restore
|
|
63
|
-
output << cursor.clear_screen_down
|
|
64
|
-
|
|
65
|
-
title = ['| ', pastel.decorate(group.name.upcase, :yellow, :underline, :bold), ' |'].join
|
|
66
|
-
footer = '| q → quit | c → change default env | e → edit config file |'
|
|
67
|
-
table = TTY::Table.new(
|
|
68
|
-
header: ['env \\ var', *group.config.variables(group.config.default_env).keys],
|
|
69
|
-
rows: group.config.envs.map do |name|
|
|
70
|
-
[name, *group.config.variables(name).values]
|
|
71
|
-
end
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
# output << "\n"
|
|
75
|
-
output << TTY::Box.frame(align: :center, title: { top_center: title, bottom_center: footer }) do
|
|
76
|
-
[
|
|
77
|
-
"(default env: #{group.config.default_env})\n\n",
|
|
78
|
-
table.render(:unicode, multiline: true, padding: [0, 1, 0, 1])
|
|
79
|
-
].join('')
|
|
20
|
+
if @options[:open]
|
|
21
|
+
TTY::Editor.open(group.config_path)
|
|
22
|
+
else
|
|
23
|
+
output.puts JSON.pretty_generate(group.config.to_h)
|
|
80
24
|
end
|
|
81
25
|
end
|
|
82
26
|
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../command'
|
|
4
|
+
require_relative '../config'
|
|
5
|
+
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
require 'pathname'
|
|
8
|
+
require 'tty-editor'
|
|
9
|
+
require 'tty-prompt'
|
|
10
|
+
|
|
11
|
+
module Poke
|
|
12
|
+
module Commands
|
|
13
|
+
class New < Poke::Command
|
|
14
|
+
CREATE_NEW_DIR = :create_new_dir
|
|
15
|
+
TEMPLATE = "curl $BASE_URL/get -G -d foo=bar\n".freeze
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def run(output: $stdout, errors: $stderr)
|
|
20
|
+
unless Config.valid?
|
|
21
|
+
errors << "Config not initialized. Run `poke init` first.\n"
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
prompt = TTY::Prompt.new(interrupt: :exit)
|
|
26
|
+
directory = choose_directory(prompt)
|
|
27
|
+
filename = choose_filename(prompt)
|
|
28
|
+
request_path = build_request_path(directory, filename)
|
|
29
|
+
|
|
30
|
+
if File.exist?(request_path) && !prompt.yes?('Request exists. Overwrite?')
|
|
31
|
+
output << "Canceled.\n"
|
|
32
|
+
return
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
File.write(request_path, TEMPLATE)
|
|
36
|
+
TTY::Editor.open(request_path)
|
|
37
|
+
output << "Created request: #{request_path}\n"
|
|
38
|
+
rescue ArgumentError => e
|
|
39
|
+
errors << "#{e.message}\n"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def choose_directory(prompt)
|
|
43
|
+
choices = discover_directories
|
|
44
|
+
labeled_choices = choices.map { |path| { name: relative_path(path), value: path } }
|
|
45
|
+
labeled_choices << { name: '[Create new directory]', value: CREATE_NEW_DIR }
|
|
46
|
+
|
|
47
|
+
selection = prompt.select(
|
|
48
|
+
'Select directory under ~/.poke',
|
|
49
|
+
labeled_choices,
|
|
50
|
+
filter: true,
|
|
51
|
+
quiet: true
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return selection unless selection == CREATE_NEW_DIR
|
|
55
|
+
|
|
56
|
+
input = prompt.ask('New directory path under ~/.poke', required: true)
|
|
57
|
+
target = build_target_path(input)
|
|
58
|
+
FileUtils.mkdir_p(target)
|
|
59
|
+
target
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def choose_filename(prompt)
|
|
63
|
+
input = prompt.ask('Request name', required: true)&.strip
|
|
64
|
+
raise ArgumentError, 'Request name cannot be empty' if input.nil? || input.empty?
|
|
65
|
+
raise ArgumentError, 'Request name must not include path separators' if input.include?('/')
|
|
66
|
+
|
|
67
|
+
name = input.gsub(/\.curl\z/, '')
|
|
68
|
+
"#{name}.curl"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def discover_directories
|
|
72
|
+
root = File.expand_path(Config.root_path)
|
|
73
|
+
|
|
74
|
+
Dir.glob("#{root}/**/")
|
|
75
|
+
.map { |path| File.expand_path(path).sub(%r{/\z}, '') }
|
|
76
|
+
.uniq
|
|
77
|
+
.reject { |path| path == root }
|
|
78
|
+
.sort
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def build_request_path(directory, filename)
|
|
82
|
+
target = Pathname.new(File.join(directory, filename)).cleanpath.to_s
|
|
83
|
+
ensure_inside_root!(target)
|
|
84
|
+
target
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def build_target_path(relative_input)
|
|
88
|
+
target = Pathname.new(File.expand_path(File.join(Config.root_path, relative_input.to_s))).cleanpath.to_s
|
|
89
|
+
|
|
90
|
+
raise ArgumentError, 'Directory must be a subdirectory of ~/.poke' if target == File.expand_path(Config.root_path)
|
|
91
|
+
|
|
92
|
+
ensure_inside_root!(target)
|
|
93
|
+
target
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def ensure_inside_root!(path)
|
|
97
|
+
root = File.expand_path(Config.root_path)
|
|
98
|
+
root_prefix = "#{root}/"
|
|
99
|
+
return if path.start_with?(root_prefix)
|
|
100
|
+
|
|
101
|
+
raise ArgumentError, 'Path must stay inside ~/.poke'
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def relative_path(path)
|
|
105
|
+
Pathname.new(path).relative_path_from(Pathname.new(File.expand_path(Config.root_path))).to_s
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/poke/commands/speed.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative '../group'
|
|
|
5
5
|
require_relative '../config'
|
|
6
6
|
require_relative '../paint'
|
|
7
7
|
require_relative '../last_recently_used'
|
|
8
|
+
require_relative '../curl_parser'
|
|
8
9
|
|
|
9
10
|
require 'pathname'
|
|
10
11
|
require 'pastel'
|
|
@@ -76,18 +77,15 @@ module Poke
|
|
|
76
77
|
errors << "Run count: #{count}\nAverage time: #{format('%.2fms', (times.sum / times.size * 1000))}\n\n"
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
# extract
|
|
80
80
|
def build_command(path)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
[command_lines.join(" \\\n "), comments]
|
|
81
|
+
content = File.read(path)
|
|
82
|
+
parser = CurlParser.new(content)
|
|
83
|
+
|
|
84
|
+
# Add our additional curl parameters
|
|
85
|
+
parser.add_argument("-o #{Poke::Config.response_path}")
|
|
86
|
+
parser.add_argument('-w "%{json}"')
|
|
87
|
+
|
|
88
|
+
[parser.to_command_with_line_continuation, parser.comments.join("\n")]
|
|
91
89
|
end
|
|
92
90
|
|
|
93
91
|
# rubocop:disable Style/FormatStringToken
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Poke
|
|
6
|
+
class CurlParser
|
|
7
|
+
attr_reader :comments, :arguments, :url
|
|
8
|
+
|
|
9
|
+
def initialize(content)
|
|
10
|
+
@content = content
|
|
11
|
+
@comments = []
|
|
12
|
+
@arguments = []
|
|
13
|
+
@url = nil
|
|
14
|
+
parse
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_command
|
|
18
|
+
parts = ['curl']
|
|
19
|
+
parts.concat(@arguments)
|
|
20
|
+
parts << @url if @url
|
|
21
|
+
parts.join(' ')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_command_with_line_continuation
|
|
25
|
+
parts = ['curl']
|
|
26
|
+
parts.concat(@arguments)
|
|
27
|
+
parts << @url if @url
|
|
28
|
+
|
|
29
|
+
# Join with line continuation for better readability
|
|
30
|
+
parts.join(" \\\n ")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def add_argument(arg)
|
|
34
|
+
@arguments << arg
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def remove_argument(pattern)
|
|
38
|
+
@arguments.reject! { |arg| arg.match?(pattern) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def replace_argument(pattern, replacement)
|
|
42
|
+
@arguments.map! do |arg|
|
|
43
|
+
arg.match?(pattern) ? replacement : arg
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def parse
|
|
50
|
+
# Normalize line endings and ensure content ends with newline
|
|
51
|
+
content = @content.gsub(/\r\n/, "\n").gsub(/\r/, "\n")
|
|
52
|
+
content += "\n" unless content.end_with?("\n")
|
|
53
|
+
|
|
54
|
+
# First, extract comments
|
|
55
|
+
extract_comments(content)
|
|
56
|
+
|
|
57
|
+
# Then parse the curl command
|
|
58
|
+
parse_curl_content(content)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def extract_comments(content)
|
|
62
|
+
content.each_line do |line|
|
|
63
|
+
stripped = line.strip
|
|
64
|
+
@comments << stripped if stripped.start_with?('#')
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def parse_curl_content(content)
|
|
69
|
+
# Remove comments and empty lines
|
|
70
|
+
curl_lines = content.lines.reject do |line|
|
|
71
|
+
line.strip.empty? || line.strip.start_with?('#')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
return if curl_lines.empty?
|
|
75
|
+
|
|
76
|
+
# Join lines with continuations
|
|
77
|
+
curl_content = join_continuations(curl_lines)
|
|
78
|
+
|
|
79
|
+
# Parse the curl command
|
|
80
|
+
parse_curl_command(curl_content)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def join_continuations(lines)
|
|
84
|
+
result = ""
|
|
85
|
+
i = 0
|
|
86
|
+
|
|
87
|
+
while i < lines.length
|
|
88
|
+
line = lines[i].chomp
|
|
89
|
+
|
|
90
|
+
# Check if this line ends with continuation
|
|
91
|
+
if line.end_with?('\\')
|
|
92
|
+
result += line[0...-1] + " "
|
|
93
|
+
i += 1
|
|
94
|
+
else
|
|
95
|
+
result += line + " "
|
|
96
|
+
i += 1
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
result.strip
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def parse_curl_command(content)
|
|
104
|
+
# Remove 'curl' command if present
|
|
105
|
+
content = content.sub(/^\s*curl\s+/, '')
|
|
106
|
+
|
|
107
|
+
# Split arguments while preserving quoted strings
|
|
108
|
+
args = split_arguments(content)
|
|
109
|
+
|
|
110
|
+
args.each do |arg|
|
|
111
|
+
if arg.start_with?('-')
|
|
112
|
+
@arguments << arg
|
|
113
|
+
elsif @url.nil?
|
|
114
|
+
@url = arg
|
|
115
|
+
else
|
|
116
|
+
# Additional arguments after URL
|
|
117
|
+
@arguments << arg
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def split_arguments(line)
|
|
123
|
+
args = []
|
|
124
|
+
current_arg = ""
|
|
125
|
+
in_quotes = false
|
|
126
|
+
quote_char = nil
|
|
127
|
+
i = 0
|
|
128
|
+
|
|
129
|
+
while i < line.length
|
|
130
|
+
char = line[i]
|
|
131
|
+
|
|
132
|
+
if !in_quotes && char.match?(/\s/)
|
|
133
|
+
if !current_arg.empty?
|
|
134
|
+
args << current_arg
|
|
135
|
+
current_arg = ""
|
|
136
|
+
end
|
|
137
|
+
elsif !in_quotes && (char == '"' || char == "'")
|
|
138
|
+
in_quotes = true
|
|
139
|
+
quote_char = char
|
|
140
|
+
current_arg += char
|
|
141
|
+
elsif in_quotes && char == quote_char
|
|
142
|
+
in_quotes = false
|
|
143
|
+
quote_char = nil
|
|
144
|
+
current_arg += char
|
|
145
|
+
else
|
|
146
|
+
current_arg += char
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
i += 1
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
args << current_arg unless current_arg.empty?
|
|
153
|
+
args
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
data/lib/poke/group_config.rb
CHANGED
data/lib/poke/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: poke-your-api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jan Bator
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-04-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pastel
|
|
@@ -129,9 +129,11 @@ files:
|
|
|
129
129
|
- lib/poke/commands/lru.rb
|
|
130
130
|
- lib/poke/commands/lru/cat.rb
|
|
131
131
|
- lib/poke/commands/lru/reset.rb
|
|
132
|
+
- lib/poke/commands/new.rb
|
|
132
133
|
- lib/poke/commands/response.rb
|
|
133
134
|
- lib/poke/commands/speed.rb
|
|
134
135
|
- lib/poke/config.rb
|
|
136
|
+
- lib/poke/curl_parser.rb
|
|
135
137
|
- lib/poke/group.rb
|
|
136
138
|
- lib/poke/group_config.rb
|
|
137
139
|
- lib/poke/last_recently_used.rb
|