procfs_rb 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 19b629e77fea8aaca91e9508f6699c0a1aaac45b4cc5bd0eb4c15673fe462225
4
+ data.tar.gz: 3fafda51d24256ba5dc465ff23faa6619867ef30878d1723bc4c54c750441c01
5
+ SHA512:
6
+ metadata.gz: 29caacfbc2428f324dbbae4c0362f9131e55a2ec6298f5e51d29e5ef38ee64774d22d8bffe4177d1b9f00ea44095548f2cd8a9681aca4f0e73077d3bb0a208ff
7
+ data.tar.gz: b15568d0cd9b6282838f9bb07172b1d7084677da80cf4bba4d65271c73840a47756ec39fbb4699e67d60e7ce0918473a2a39aa1d182f8d37104ef4bc0fb8257b
data/.opencode.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "project_name": "procfs_rb",
3
+ "instructions": "Follow the guidelines in AGENTS.md.",
4
+ "ignored_paths": [
5
+ "coverage/",
6
+ ".git/",
7
+ "tmp/",
8
+ "bin/console",
9
+ "bin/setup"
10
+ ]
11
+ }
data/AGENTS.md ADDED
@@ -0,0 +1,35 @@
1
+ # AI Agent Guidelines for procfs_rb
2
+
3
+ This project is a Ruby GEM designed to provide a programmatic interface for browsing and analyzing the `/proc` filesystem on Linux.
4
+
5
+ ## Project Context
6
+ - **Purpose:** Provide an idiomatic Ruby wrapper for Linux procfs.
7
+ - **Tech Stack:**
8
+ - Ruby >= 3.2.0
9
+ - Minitest (Testing)
10
+ - RuboCop (Linting/Styling)
11
+ - RBS (Type signatures)
12
+ - **Hosting:** Primary development and CI/CD on GitLab; mirrored on GitHub.
13
+
14
+ ## Coding Standards
15
+ - **Idiomatic Ruby:** Follow the Ruby Style Guide.
16
+ - **Linting:** All code must pass `bundle exec rubocop`.
17
+ - **Typing:** Update `.rbs` files in the `sig/` directory when adding new public methods.
18
+ - **Error Handling:** Do not swallow exceptions; provide meaningful custom error classes for procfs-specific failures (e.g., missing files in `/proc`).
19
+ - **Documentation:** Use YARD style comments for public API methods.
20
+
21
+ ## Testing Requirements
22
+ - **Framework:** Minitest.
23
+ - **Coverage:** New features must include tests. Run `rake test` to verify.
24
+ - **Environment:** Tests expect a Linux environment with a populated `/proc` filesystem.
25
+
26
+ ## Tooling
27
+ - `rake test`: Run all tests.
28
+ - `bundle exec rubocop`: Run linting.
29
+ - `bundle exec reek`: Run code smell analysis.
30
+ - `bin/console`: Interactive console for exploration.
31
+
32
+ ## Workflow
33
+ - **Branching:** Feature Branch workflow.
34
+ - **Commits:** Follow Conventional Commits.
35
+ - **Verification:** Always run linting and tests before proposing a change.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,39 @@
1
+ # Contributing to procfs_rb
2
+
3
+ Thank you for contributing to `procfs_rb`! This gem provides a Ruby interface to the Linux `/proc` filesystem.
4
+
5
+ ## Development Workflow
6
+
7
+ ### 1. Setup
8
+ Ensure you are on a Linux system. Install dependencies:
9
+ ```bash
10
+ bundle install
11
+ ```
12
+
13
+ ### 2. Feature Branching
14
+ We use a feature branch workflow. Please create a new branch for every change:
15
+ - `feat/description` for new features.
16
+ - `fix/description` for bug fixes.
17
+ - `docs/description` for documentation updates.
18
+
19
+ ### 3. Coding Standards
20
+ - **Style:** We use RuboCop for linting. Run `bundle exec rubocop` to check your code.
21
+ - **Types:** We use RBS for type signatures. Please update `sig/procfs_rb.rbs` accordingly.
22
+ - **Commits:** We follow [Conventional Commits](https://www.conventionalcommits.org/).
23
+ - Example: `feat: add memory info parsing` or `fix: resolve nil value in cpu_stats`
24
+
25
+ ### 4. Testing
26
+ All contributions must include tests.
27
+ - Run tests using: `rake test`
28
+ - Ensure that your changes do not decrease test coverage.
29
+
30
+ ### 5. Submission
31
+ 1. Push your branch to GitLab.
32
+ 2. Create a Merge Request (MR) on GitLab (the primary repository).
33
+ 3. Provide a clear description of the change and the motivation behind it.
34
+
35
+ ## Repository Structure
36
+ - `lib/`: Core logic.
37
+ - `sig/`: RBS type signatures.
38
+ - `test/`: Minitest suite.
39
+ - `bin/`: Helper scripts.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Thomas Tych
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # ProcfsRb
2
+
3
+ A Ruby interface for browsing and analyzing the Linux `/proc` filesystem.
4
+
5
+ ## Usage
6
+
7
+ Once loaded, it provides ProcFS module.
8
+
9
+ ``` ruby
10
+ require 'procfs_rb'
11
+
12
+ procfs = ProcFS.new()
13
+
14
+ # get cpuinfo
15
+ cpuinfo = procfs.cpuinfo
16
+
17
+ # get all sockets
18
+ sockets = procfs.net.tcp.sockets
19
+
20
+ ```
21
+
22
+ ## ProcFS
23
+
24
+ ### Core
25
+
26
+ * It is Virtual: /proc does not exist on disk. It is an interface to kernel data structures.
27
+ * It is Generated on Read: Files do not "contain" static text. When a read() syscall occurs, the kernel executes a handler function that formats the current state into text on the fly.
28
+ * No Cross-File Atomicity: Because each file is generated independently, reading multiple files sequentially does not guarantee a consistent point-in-time view. State may change between read 1 and read 2.
29
+
30
+ ### Node Abstractions
31
+
32
+
33
+ | Node Type | Filesystem Representation | Semantic Role | Interface Contract |
34
+ |---------------------|---------------------------|----------------------------------|-------------------------------------------------------------------------------------------------------------|
35
+ | Directory | dr-xr-xr-x | Logical grouping / Namespace. | Yields a list of child nodes. |
36
+ | Observable File | -r--r--r-- | Telemetry / State observation. | Read-only. Returns a parsed, typed data structure. |
37
+ | Control File | -rw-r--r-- | Tunable parameter / Mutation. | Read/Write. Getter returns current value; Setter applies new value and may return success/error. |
38
+ | Reference (Symlink) | lrwxrwxrwx | Resolved relationship / Pointer. | Returns the target path (string) or resolves to the target object (e.g., resolving an FD to a socket/file). |
39
+
40
+
41
+ ### Implementation rules
42
+
43
+ #### Rule 1: Explicit Snapshot Boundaries
44
+ Because /proc files are generated on the fly, an interface method like get_process_info(pid) should ideally read all required files for that specific request in a single pass, package them into a single immutable struct (a "Snapshot"), and return it.
45
+
46
+ Warning: Document clearly that even a single Snapshot is not strictly atomic across all kernel subsystems.
47
+
48
+ #### Rule 2: Handle Volatility Gracefully (Lifecycle)
49
+ Processes are born and die constantly.
50
+
51
+ A PID listed in a directory scan may cease to exist before its files are read.
52
+ The interface must treat ENOENT (No such file or directory) and ESRCH (No such process) not as fatal errors, but as expected lifecycle events (e.g., returning None, null, or throwing a specific ProcessVanishedException).
53
+
54
+ #### Rule 3: Encapsulate Raw Parsing
55
+ /proc files are notoriously difficult to parse reliably.
56
+
57
+ Example: /proc/<pid>/stat is space-separated, but the second field (comm) is wrapped in parentheses and can contain spaces or closing parentheses itself.
58
+
59
+ The interface must hide raw string parsing behind strongly-typed objects. Consumers should call process.get_memory_usage(), never parse_proc_pid_stat().
60
+
61
+ #### Rule 4: Separate Observation from Mutation
62
+ Do not mix read-only state getters with control setters in the same conceptual API surface without clear naming.
63
+
64
+ Example: process.get_oom_score() (Observation) vs process.set_oom_score_adj(500) (Mutation).
65
+
66
+ ## Implementation
67
+
68
+
69
+
70
+ ## Installation
71
+
72
+ Install the gem by executing:
73
+
74
+ ```bash
75
+ gem install procfs_rb
76
+ ```
77
+
78
+ Or add it to your Gemfile:
79
+
80
+ ```ruby
81
+ gem 'procfs_rb'
82
+ ```
83
+
84
+ ## Usage
85
+
86
+ ```ruby
87
+ require 'procfs_rb'
88
+
89
+ # Your usage examples here
90
+ ```
91
+
92
+ ## Development
93
+
94
+ Run `bin/setup` to install dependencies, `rake test` to run tests, and `bin/console` for an interactive prompt.
95
+
96
+ To install locally: `bundle exec rake install`.
97
+
98
+ ## Contributing
99
+
100
+ Bug reports and pull requests are welcome on GitLab. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
101
+
102
+ ## License
103
+
104
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+
5
+ require 'minitest/test_task'
6
+ Minitest::TestTask.create
7
+
8
+ require 'rubocop/rake_task'
9
+ RuboCop::RakeTask.new
10
+
11
+ require 'bump/tasks'
12
+
13
+ task default: %i[test rubocop]
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'parser_interface'
4
+ require 'ipaddr'
5
+ require_relative '../state/net_tcp'
6
+
7
+ module ProcFS
8
+ module Parser
9
+ class NetTcpParser
10
+ DEFAULT_SOURCE = '/proc/net/tcp'
11
+
12
+ include ParserInterface
13
+
14
+ def parse(content, source: DEFAULT_SOURCE)
15
+ read_at = Time.now
16
+ lines = content.lines.drop(1) # Skip the header line
17
+
18
+ sockets = lines.map { |line| parse_socket_line(line) }.compact
19
+
20
+ State::NetTcp.new(
21
+ sockets: sockets,
22
+ timestamp: read_at,
23
+ source: source
24
+ )
25
+ end
26
+
27
+ private
28
+
29
+ def parse_socket_line(line)
30
+ parts = line.split
31
+ return nil if parts.empty?
32
+
33
+ local_ip, local_port = parse_address(parts[1])
34
+ remote_ip, remote_port = parse_address(parts[2])
35
+
36
+ tx_hex, rx_hex = parts[4].split(':')
37
+
38
+ State::TcpSocket.new(
39
+ local_address: local_ip,
40
+ local_port: local_port,
41
+ remote_address: remote_ip,
42
+ remote_port: remote_port,
43
+ connection_state: State::TcpSocket::STATES.fetch(parts[3], :unknown),
44
+ tx_queue: tx_hex.to_i(16),
45
+ rx_queue: rx_hex.to_i(16),
46
+ uid: parts[7].to_i,
47
+ inode: parts[9].to_i
48
+ )
49
+ end
50
+
51
+ # Parses "0100007F:0050" (little-endian IPv4 hex + port hex)
52
+ # into [IPAddr, Integer]
53
+ def parse_address(hex_addr)
54
+ ip_hex, port_hex = hex_addr.split(':')
55
+
56
+ # IPv4: 8 hex chars, stored in little-endian 32-bit
57
+ ip_int = ip_hex.to_i(16)
58
+ ip_bytes = [ip_int].pack('V').unpack('C4')
59
+ ip_string = ip_bytes.join('.')
60
+
61
+ [IPAddr.new(ip_string), port_hex.to_i(16)]
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProcFS
4
+ module Parser
5
+ module ParserInterface
6
+ def parse(content)
7
+ raise NotImplementedError, 'Parser should implement #parse(content)'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ DEFAULT_PROC_FS_ROOT = '/proc'
4
+
5
+ module ProcFS
6
+ class ProcFSRoot
7
+ attr_reader :root_path
8
+
9
+ def initialize(root_path: DEFAULT_PROC_FS_ROOT)
10
+ @root_path = File.expand_path(root_path)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'snapshot'
5
+ require_relative 'timestamped'
6
+ require_relative 'tcp_socket'
7
+
8
+ module ProcFS
9
+ module State
10
+ class NetTcp
11
+ include Snapshot
12
+ include Timestamped
13
+ include Enumerable
14
+
15
+ MEMBERS = %i[sockets timestamp source].freeze
16
+
17
+ attr_reader(*MEMBERS)
18
+
19
+ def initialize(sockets:, timestamp: Time.now, source: '/proc/net/tcp')
20
+ @sockets = sockets
21
+ @timestamp = timestamp
22
+ @source = source
23
+ freeze
24
+ end
25
+
26
+ def members
27
+ MEMBERS
28
+ end
29
+
30
+ def to_h
31
+ members.to_h { |m| [m, send(m)] }
32
+ end
33
+
34
+ def with(**changes)
35
+ self.class.new(**to_h, **changes)
36
+ end
37
+
38
+ def ==(other)
39
+ other.is_a?(self.class) && to_h == other.to_h
40
+ end
41
+ alias eql? ==
42
+
43
+ def hash
44
+ [self.class, to_h].hash
45
+ end
46
+
47
+ def to_s
48
+ "TcpInfo(#{sockets.size} sockets @ #{timestamp.strftime('%H:%M:%S.%3N')})"
49
+ end
50
+
51
+ def inspect
52
+ "#<ProcFS::State::TcpInfo source=#{source.inspect} " \
53
+ "count=#{sockets.size} timestamp=#{timestamp.iso8601(3)}>"
54
+ end
55
+
56
+ def each(&)
57
+ sockets.each(&)
58
+ end
59
+
60
+ def listening
61
+ sockets.select(&:listening?)
62
+ end
63
+
64
+ def established
65
+ sockets.select(&:established?)
66
+ end
67
+
68
+ def closed
69
+ sockets.select(&:closed?)
70
+ end
71
+
72
+ def on_port(port)
73
+ sockets.select { |s| s.local_port == port || s.remote_port == port }
74
+ end
75
+
76
+ def bound_on(address)
77
+ addr = address.is_a?(IPAddr) ? address : IPAddr.new(address)
78
+ sockets.select { |s| s.local_address == addr }
79
+ end
80
+
81
+ def by_state(state)
82
+ sockets.select { |s| s.connection_state == state }
83
+ end
84
+
85
+ def empty?
86
+ sockets.empty?
87
+ end
88
+
89
+ def size
90
+ sockets.size
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProcFS
4
+ module State
5
+ module Snapshot
6
+ def snapshot?
7
+ true
8
+ end
9
+
10
+ def to_json(*)
11
+ to_h.to_json(*)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'json'
5
+ require_relative 'snapshot'
6
+
7
+ module ProcFS
8
+ module State
9
+ class TcpSocket
10
+ include Snapshot
11
+
12
+ # TCP state constants (from linux/tcp_states.h)
13
+ STATES = {
14
+ '01' => :established,
15
+ '02' => :syn_sent,
16
+ '03' => :syn_recv,
17
+ '04' => :fin_wait1,
18
+ '05' => :fin_wait2,
19
+ '06' => :time_wait,
20
+ '07' => :close,
21
+ '08' => :close_wait,
22
+ '09' => :last_ack,
23
+ '0A' => :listen,
24
+ '0B' => :closing
25
+ }.freeze
26
+
27
+ MEMBERS = %i[
28
+ local_address local_port
29
+ remote_address remote_port
30
+ connection_state
31
+ tx_queue rx_queue
32
+ uid inode
33
+ ].freeze
34
+
35
+ attr_reader(*MEMBERS)
36
+
37
+ def initialize(local_address:, local_port:, remote_address:, remote_port:,
38
+ connection_state:, tx_queue:, rx_queue:, uid:, inode:)
39
+ @local_address = local_address
40
+ @local_port = local_port
41
+ @remote_address = remote_address
42
+ @remote_port = remote_port
43
+ @connection_state = connection_state
44
+ @tx_queue = tx_queue
45
+ @rx_queue = rx_queue
46
+ @uid = uid
47
+ @inode = inode
48
+
49
+ freeze
50
+ end
51
+
52
+ # --- Value semantics ---
53
+
54
+ def members
55
+ MEMBERS
56
+ end
57
+
58
+ def to_h
59
+ members.to_h { |m| [m, send(m)] }
60
+ end
61
+
62
+ def with(**changes)
63
+ self.class.new(**to_h, **changes)
64
+ end
65
+
66
+ def ==(other)
67
+ other.is_a?(self.class) && to_h == other.to_h
68
+ end
69
+ alias eql? ==
70
+
71
+ def hash
72
+ [self.class, to_h].hash
73
+ end
74
+
75
+ def to_s
76
+ "#{local_address}:#{local_port} -> #{remote_address}:#{remote_port} [#{connection_state}]"
77
+ end
78
+
79
+ def inspect
80
+ "#<ProcFS::State::TcpSocket #{self} tx=#{tx_queue} rx=#{rx_queue} uid=#{uid} inode=#{inode}>"
81
+ end
82
+
83
+ def listening?
84
+ connection_state == :listen
85
+ end
86
+
87
+ def established?
88
+ connection_state == :established
89
+ end
90
+
91
+ def closed?
92
+ %i[close time_wait close_wait last_ack closing].include?(connection_state)
93
+ end
94
+
95
+ def ipv4?
96
+ local_address.ipv4?
97
+ end
98
+
99
+ def ipv6?
100
+ local_address.ipv6?
101
+ end
102
+
103
+ def local_endpoint
104
+ "#{local_address}:#{local_port}"
105
+ end
106
+
107
+ def remote_endpoint
108
+ "#{remote_address}:#{remote_port}"
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProcFS
4
+ module State
5
+ module Timestamped
6
+ def age
7
+ Time.now - timestamp
8
+ end
9
+
10
+ def recent?(within_seconds: 5)
11
+ age < within_seconds
12
+ end
13
+
14
+ def stale?(after_seconds: 60)
15
+ age > after_seconds
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'proc_fs/proc_fs_root'
4
+
5
+ module ProcFS
6
+ def new(**)
7
+ ProcFSRoot.new(**)
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProcfsRb
4
+ VERSION = '0.1.0'
5
+ end
data/lib/procfs_rb.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'procfs_rb/version'
4
+
5
+ require_relative 'procfs_rb/proc_fs'
6
+
7
+ module ProcfsRb
8
+ end
data/sig/procfs_rb.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module ProcfsRb
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,231 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: procfs_rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Tych
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bump
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.10.0
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.10.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: bundler
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 4.0.21
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 4.0.21
40
+ - !ruby/object:Gem::Dependency
41
+ name: byebug
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '13.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '13.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: irb
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.18'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.18'
68
+ - !ruby/object:Gem::Dependency
69
+ name: minitest
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '6.0'
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 6.0.6
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '6.0'
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: 6.0.6
88
+ - !ruby/object:Gem::Dependency
89
+ name: rake
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '13.4'
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 13.4.2
98
+ type: :development
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '13.4'
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 13.4.2
108
+ - !ruby/object:Gem::Dependency
109
+ name: reek
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: '6.5'
115
+ type: :development
116
+ prerelease: false
117
+ version_requirements: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '6.5'
122
+ - !ruby/object:Gem::Dependency
123
+ name: rubocop
124
+ requirement: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - "~>"
127
+ - !ruby/object:Gem::Version
128
+ version: '1.91'
129
+ type: :development
130
+ prerelease: false
131
+ version_requirements: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '1.91'
136
+ - !ruby/object:Gem::Dependency
137
+ name: rubocop-minitest
138
+ requirement: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: 0.40.0
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: 0.40.0
150
+ - !ruby/object:Gem::Dependency
151
+ name: rubocop-rake
152
+ requirement: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: 0.7.1
157
+ type: :development
158
+ prerelease: false
159
+ version_requirements: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "~>"
162
+ - !ruby/object:Gem::Version
163
+ version: 0.7.1
164
+ - !ruby/object:Gem::Dependency
165
+ name: simplecov
166
+ requirement: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - "~>"
169
+ - !ruby/object:Gem::Version
170
+ version: '1.3'
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: 1.3.0
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.3'
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: 1.3.0
184
+ email:
185
+ - thomas.tych@gmail.com
186
+ executables: []
187
+ extensions: []
188
+ extra_rdoc_files: []
189
+ files:
190
+ - ".opencode.json"
191
+ - AGENTS.md
192
+ - CONTRIBUTING.md
193
+ - LICENSE.txt
194
+ - README.md
195
+ - Rakefile
196
+ - lib/procfs_rb.rb
197
+ - lib/procfs_rb/proc_fs.rb
198
+ - lib/procfs_rb/proc_fs/parser/net_tcp_parser.rb
199
+ - lib/procfs_rb/proc_fs/parser/parser_interface.rb
200
+ - lib/procfs_rb/proc_fs/proc_fs_root.rb
201
+ - lib/procfs_rb/proc_fs/state/net_tcp.rb
202
+ - lib/procfs_rb/proc_fs/state/snapshot.rb
203
+ - lib/procfs_rb/proc_fs/state/tcp_socket.rb
204
+ - lib/procfs_rb/proc_fs/state/timestamped.rb
205
+ - lib/procfs_rb/version.rb
206
+ - sig/procfs_rb.rbs
207
+ homepage: https://gitlab.com/ttych/procfs_rb
208
+ licenses:
209
+ - MIT
210
+ metadata:
211
+ homepage_uri: https://gitlab.com/ttych/procfs_rb
212
+ source_code_uri: https://gitlab.com/ttych/procfs_rb
213
+ rubygems_mfa_required: 'true'
214
+ rdoc_options: []
215
+ require_paths:
216
+ - lib
217
+ required_ruby_version: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: 3.2.0
222
+ required_rubygems_version: !ruby/object:Gem::Requirement
223
+ requirements:
224
+ - - ">="
225
+ - !ruby/object:Gem::Version
226
+ version: '0'
227
+ requirements: []
228
+ rubygems_version: 4.0.21
229
+ specification_version: 4
230
+ summary: ProcFS interface.
231
+ test_files: []