gretl 1.0.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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/gretl.rb +122 -0
  3. metadata +43 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 125347cb9702505790be6258d05cc6423ee35ea7eefab6d45f40a7bcba533605
4
+ data.tar.gz: c785a560021af5505094db888107c20e5f5a8f5fffd77629f2a3aa6f73777cb6
5
+ SHA512:
6
+ metadata.gz: ba05270b3e2d771e10db4e164860f8a4d223263b1db275957e2a2720c55d53d53b03871dd747dd8e98b33611d92c40e8410bac636d685c959ed5a3733b194cd2
7
+ data.tar.gz: 30f4c52dfa7bef423a9716ff815d6a7dba57d4b8c7c2fccfd6eb3deb6b6c32b88ad074908ffc8b62b27af1dbc2180751244d4bcf0c465dd063512bb09d14e42e
data/lib/gretl.rb ADDED
@@ -0,0 +1,122 @@
1
+ require "net/http"
2
+ require "json"
3
+ require "uri"
4
+
5
+ module Gretl
6
+ BASE = "http://127.0.0.1:27892"
7
+
8
+ PortInfo = Struct.new(
9
+ :port, :name, :active, :pid, :process,
10
+ :has_command, :group, :is_docker, :links,
11
+ keyword_init: true
12
+ ) do
13
+ def running? = active
14
+ def stopped? = !active
15
+ def to_s = "#<PortInfo #{name.inspect} :#{port} #{active ? "running" : "stopped"}>"
16
+ end
17
+
18
+ module_function
19
+
20
+ def _request(method, path)
21
+ uri = URI("#{BASE}#{path}")
22
+ http = Net::HTTP.new(uri.host, uri.port)
23
+ http.open_timeout = 5
24
+ http.read_timeout = 5
25
+ req = case method
26
+ when :get then Net::HTTP::Get.new(uri)
27
+ when :post then Net::HTTP::Post.new(uri)
28
+ when :delete then Net::HTTP::Delete.new(uri)
29
+ end
30
+ res = http.request(req)
31
+ JSON.parse(res.body, symbolize_names: true)
32
+ rescue Errno::ECONNREFUSED
33
+ raise "Cannot connect to Gretl. Make sure the app is running."
34
+ end
35
+
36
+ def _fetch_ports
37
+ _request(:get, "/ports").map { |d| PortInfo.new(**d.slice(*PortInfo.members)) }
38
+ end
39
+
40
+ def _resolve(query)
41
+ all = _fetch_ports
42
+ if query.match?(/\A\d+\z/)
43
+ exact = all.select { |p| p.port == query.to_i }
44
+ return exact unless exact.empty?
45
+ end
46
+ q = query.downcase
47
+ all.select { |p| p.name.downcase.include?(q) }
48
+ end
49
+
50
+ class Client
51
+ def ports = Gretl._fetch_ports
52
+ def port(query) = Gretl._resolve(query)
53
+ def active = _fetch_ports.select(&:active)
54
+ def inactive = _fetch_ports.reject(&:active)
55
+
56
+ def start(query)
57
+ matches = Gretl._resolve(query)
58
+ raise ArgumentError, "No port found matching #{query.inspect}" if matches.empty?
59
+ matches.each do |p|
60
+ Gretl._request(:post, "/ports/#{p.port}/start") if !p.active && p.has_command
61
+ end
62
+ matches
63
+ end
64
+
65
+ def stop(query)
66
+ matches = Gretl._resolve(query)
67
+ raise ArgumentError, "No port found matching #{query.inspect}" if matches.empty?
68
+ matches.each do |p|
69
+ Gretl._request(:post, "/ports/#{p.port}/stop") if p.active
70
+ end
71
+ matches
72
+ end
73
+
74
+ def start_group(group)
75
+ matches = Gretl._fetch_ports.select { |p| p.group&.downcase == group.downcase }
76
+ raise ArgumentError, "No ports found in group #{group.inspect}" if matches.empty?
77
+ matches.each { |p| Gretl._request(:post, "/ports/#{p.port}/start") if !p.active && p.has_command }
78
+ matches
79
+ end
80
+
81
+ def stop_group(group)
82
+ matches = Gretl._fetch_ports.select { |p| p.group&.downcase == group.downcase }
83
+ raise ArgumentError, "No ports found in group #{group.inspect}" if matches.empty?
84
+ matches.each { |p| Gretl._request(:post, "/ports/#{p.port}/stop") if p.active }
85
+ matches
86
+ end
87
+
88
+ def status_group(group)
89
+ matches = Gretl._fetch_ports.select { |p| p.group&.downcase == group.downcase }
90
+ raise ArgumentError, "No ports found in group #{group.inspect}" if matches.empty?
91
+ matches
92
+ end
93
+
94
+ def remove(query)
95
+ matches = Gretl._resolve(query)
96
+ raise ArgumentError, "No port found matching #{query.inspect}" if matches.empty?
97
+ matches.each { |p| Gretl._request(:delete, "/ports/#{p.port}") }
98
+ matches
99
+ end
100
+
101
+ def wait_for_active(query, timeout: 30, interval: 0.5)
102
+ deadline = Time.now + timeout
103
+ while Time.now < deadline
104
+ Gretl._resolve(query).each { |p| return p if p.active }
105
+ sleep interval
106
+ end
107
+ raise "Port matching #{query.inspect} did not become active within #{timeout}s"
108
+ end
109
+
110
+ def wait_for_inactive(query, timeout: 30, interval: 0.5)
111
+ deadline = Time.now + timeout
112
+ while Time.now < deadline
113
+ Gretl._resolve(query).each { |p| return p if p.stopped? }
114
+ sleep interval
115
+ end
116
+ raise "Port matching #{query.inspect} did not become inactive within #{timeout}s"
117
+ end
118
+ end
119
+
120
+ # Default client
121
+ PA = Client.new
122
+ end
metadata ADDED
@@ -0,0 +1,43 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gretl
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - SlowDutch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-05-04 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/gretl.rb
20
+ homepage: https://github.com/slowdutch/Gretl
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.7'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubygems_version: 3.4.1
40
+ signing_key:
41
+ specification_version: 4
42
+ summary: Ruby SDK for Gretl — control local services by name or port number
43
+ test_files: []