context_spook 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8061fffaf039f19b3b37a0df7ce5ce62624c04c303fd525a6b2a96b74bbf0fd4
4
- data.tar.gz: 72b878f810bd5695aa0a09144fb3eb66475d7e12d73ba1cd1b17694e54a89c00
3
+ metadata.gz: f52806b7e9dbd38070ca282415d5e05df58824be37f36389e6d7d820030e864c
4
+ data.tar.gz: 91a2f4016d0affe3d5e0105cbd456dcc73b6a23c580b85909cfcc2190cb195ff
5
5
  SHA512:
6
- metadata.gz: f5f21ce7d81d9488732ebbe27e2b17096fa6c92afcd2e9dadf0427cad36a33eb48e4e114a7bd687a0fb60a37351297b8cbbcc035e4a6644c530a3007ee2aedc3
7
- data.tar.gz: 38bc4a4e00193b70fce74115e8ba8d230dbb06d3c6179cebb1c889b83fb10310fe3d9699f8bbc26ef4d16fbd9c646c080274ea738e56d94fe08381250c7c1a96
6
+ metadata.gz: 1b2facc2b87f0e3a880b45eeee25e0155baf713f461531343ce4906ce5e6f51a153789def95c4b1741b11f468db7c7d6a7698c8e6dda858f14811e6fd85255f7
7
+ data.tar.gz: ae47a38687a3911af559d39229ee48abaed1970abd124401d20f3bf8392c7790a765793d9ec5e25ab0c5460e7c41f1ac52f1377827e3414baf5815688fb18fb6
data/README.md CHANGED
@@ -8,7 +8,7 @@ be exported as structured JSON data.
8
8
  The DSL is general-purpose and can be used for any kind of project or
9
9
  collection of files, whether software development, documentation, research
10
10
  data, educational materials, creative projects, or any other type of organized
11
- information. The `contexts/project.rb` example below demonstrates how to
11
+ information. The `.contexts/project.rb` example below demonstrates how to
12
12
  describe a Ruby project, but the same principles apply across many different
13
13
  domains.
14
14
 
@@ -32,16 +32,54 @@ $ gem install context_spook
32
32
 
33
33
  ## Usage
34
34
 
35
- Create a `contexts/project.rb` file that describes your project context using
36
- the DSL in a context definition file:
35
+ ### Programmatic Usage
36
+
37
+ #### Directly in Ruby
38
+
39
+ Now you can generate context from a block directly in Ruby using the DSL:
40
+
41
+ ```ruby
42
+ context = ContextSpook::generate_context do
43
+ context do
44
+ variable branch: `git rev-parse --abbrev-ref HEAD`.chomp
45
+
46
+ namespace "structure" do
47
+ command "tree", tags: %w[ project_structure ]
48
+ end
49
+
50
+ namespace "lib" do
51
+ Dir['lib/**/*.rb'].each do |filename|
52
+ file filename, tags: 'lib'
53
+ end
54
+ end
55
+
56
+ # ... rest of your context definition, see below for full example
57
+ end
58
+ end
59
+ ```
60
+
61
+ This approach can be used to dynamically generate a context when it is not
62
+ configurable via a user context definition file, or as a fallback when users
63
+ have not yet created such files.
64
+
65
+ Afterwards you can store the context as JSON in Ruby or send it to another
66
+ application.
67
+
68
+ ```ruby
69
+ File.write 'context.json', context.to_json
70
+ ```
71
+
72
+ #### From a context definition file
73
+
74
+ Alternatively store the block's content above to a file `.contexts/project.rb`:
37
75
 
38
76
  ```ruby
39
- # contexts/project.rb
77
+ # .contexts/project.rb
40
78
  context do
41
79
  variable branch: `git rev-parse --abbrev-ref HEAD`.chomp
42
80
 
43
81
  namespace "structure" do
44
- command "tree lib", tags: %w[ project_structure ]
82
+ command "tree", tags: %w[ project_structure ]
45
83
  end
46
84
 
47
85
  namespace "lib" do
@@ -72,12 +110,11 @@ context do
72
110
  end
73
111
  ```
74
112
 
75
- ### Programmatic Usage
76
-
77
- Now you can generate the context from the file, and store it as JSON in Ruby.
113
+ Now you can generate the context from the file, and store it as JSON in Ruby or
114
+ send it to another application.
78
115
 
79
116
  ```ruby
80
- context = ContextSpook::generate_context('contexts/project.rb')
117
+ context = ContextSpook::generate_context('.contexts/project.rb')
81
118
  File.write 'context.json', context.to_json
82
119
  ```
83
120
 
@@ -86,13 +123,13 @@ File.write 'context.json', context.to_json
86
123
  Generate context and save to file:
87
124
 
88
125
  ```bash
89
- ./bin/context_spook contexts/project.rb > context.json
126
+ ./bin/context_spook .contexts/project.rb > context.json
90
127
  ```
91
128
 
92
129
  Or pipe directly to another tool:
93
130
 
94
131
  ```
95
- ./bin/context_spook contexts/project.rb | ollama_chat_send
132
+ ./bin/context_spook .contexts/project.rb | ollama_chat_send
96
133
  ```
97
134
 
98
135
  You will see two orange warning messages, that demonstrates how errors like
@@ -129,11 +166,13 @@ assistants understand:
129
166
  "content": "...",
130
167
  "size": 1234,
131
168
  "lines": 56,
132
- "tags": ["lib"]
169
+ "tags": [
170
+ "lib"
171
+ ]
133
172
  }
134
173
  },
135
174
  "commands": {
136
- "tree lib": {
175
+ "tree": {
137
176
  "namespace": "structure",
138
177
  "output": "lib\n├── context_spook\n│ └── generator.rb\n└── context_spook.rb\n\n2 directories, 3 files",
139
178
  "exit_code": 0,
@@ -142,7 +181,7 @@ assistants understand:
142
181
  },
143
182
  "metadata": {
144
183
  "ruby": "ruby 3.1.0 ...",
145
- "code_coverage": { ... }
184
+ "code_coverage": {}
146
185
  },
147
186
  "variables": {
148
187
  "branch": "main"
data/Rakefile CHANGED
@@ -19,9 +19,9 @@ GemHadar do
19
19
  test_dir 'spec'
20
20
  ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle',
21
21
  '.yardoc', 'doc', 'tags', 'errors.lst', 'cscope.out', 'coverage', 'tmp',
22
- 'yard'
22
+ 'yard', 'TODO.md'
23
23
  package_ignore '.all_images.yml', '.tool-versions', '.gitignore', 'VERSION',
24
- '.rspec', *Dir.glob('.github/**/*', File::FNM_DOTMATCH)
24
+ '.rspec', '.github'
25
25
  readme 'README.md'
26
26
 
27
27
  required_ruby_version '~> 3.1'
@@ -29,8 +29,10 @@ GemHadar do
29
29
  dependency 'tins', '~>1.39'
30
30
  dependency 'json', '~>2.0'
31
31
  dependency 'term-ansicolor', '~> 1.11'
32
- development_dependency 'all_images', '~> 0.6'
33
- development_dependency 'rspec', '~> 3.2'
32
+ dependency 'mize', '~> 0.6'
33
+ dependency 'mime-types', '~> 3.0'
34
+ development_dependency 'all_images', '~> 0.6'
35
+ development_dependency 'rspec', '~> 3.2'
34
36
  development_dependency 'debug'
35
37
  development_dependency 'simplecov'
36
38
 
data/bin/context_spook CHANGED
@@ -4,8 +4,4 @@ require 'context_spook'
4
4
 
5
5
  filename = ARGV.shift or fail 'require context definition file as first argument'
6
6
  context_json = ContextSpook.generate_context(filename).to_json
7
- context_json_size = Tins::Unit.format(
8
- context_json.size, format: '%.2f %U', unit: ?b, prefix: 1024
9
- )
10
- STDERR.puts "Now outputting #{context_json_size} of JSON context in total."
11
7
  puts context_json
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: context_spook 0.1.0 ruby lib
2
+ # stub: context_spook 0.3.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "context_spook".freeze
6
- s.version = "0.1.0".freeze
6
+ s.version = "0.3.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.specification_version = 4
26
26
 
27
- s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 2.0".freeze])
27
+ s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 2.1".freeze])
28
28
  s.add_development_dependency(%q<all_images>.freeze, ["~> 0.6".freeze])
29
29
  s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2".freeze])
30
30
  s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
@@ -32,4 +32,6 @@ Gem::Specification.new do |s|
32
32
  s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.39".freeze])
33
33
  s.add_runtime_dependency(%q<json>.freeze, ["~> 2.0".freeze])
34
34
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
35
+ s.add_runtime_dependency(%q<mize>.freeze, ["~> 0.6".freeze])
36
+ s.add_runtime_dependency(%q<mime-types>.freeze, ["~> 3.0".freeze])
35
37
  end
data/contexts/project.rb CHANGED
@@ -2,7 +2,7 @@ context do
2
2
  variable branch: `git rev-parse --abbrev-ref HEAD`.chomp
3
3
 
4
4
  namespace "structure" do
5
- command "tree lib", tags: %w[ project_structure ]
5
+ command "tree", tags: %w[ project_structure ]
6
6
  end
7
7
 
8
8
  namespace "lib" do
@@ -1,7 +1,8 @@
1
1
  require 'tins/xt'
2
2
  require 'term/ansicolor'
3
3
  require 'json'
4
-
4
+ require 'mize'
5
+ require 'mime-types'
5
6
 
6
7
  # The ContextSpook module serves as a namespace container for collecting and
7
8
  # organizing project information for AI assistance.
@@ -19,8 +20,16 @@ module ContextSpook
19
20
  #
20
21
  # @return [ ContextSpook::Generator::Context ] the context object generated
21
22
  # from the file contents
22
- def self.generate_context(filename)
23
- Generator.send(:new).send(:parse, File.read(filename)).context
23
+ def self.generate_context(filename = nil, &block)
24
+ filename.present? ^ block or
25
+ raise ArgumentError, 'need either a filename or a &block argument'
26
+ generator = if filename
27
+ Generator.send(:new).send(:parse, File.read(filename))
28
+ else
29
+ Generator.send(:new, &block)
30
+ end
31
+ generator.output_context_size
32
+ generator.context
24
33
  end
25
34
 
26
35
  # The Generator class provides a DSL parser that interprets context
@@ -52,6 +61,20 @@ module ContextSpook
52
61
  end
53
62
  end
54
63
 
64
+ # The output_context_size method prints the total size of the generated
65
+ # context JSON representation.
66
+ #
67
+ # This method calculates the size of the context object when serialized to
68
+ # JSON, formats it using binary units (KiB, MiB, etc.), and outputs the
69
+ # result to standard error.
70
+ def output_context_size
71
+ context_size = @context&.size.to_i
72
+ json_content_size = Tins::Unit.format(
73
+ context_size, format: '%.2f %U', unit: ?b, prefix: 1024
74
+ )
75
+ STDERR.puts "Built #{json_content_size} of JSON context in total."
76
+ end
77
+
55
78
  # The Context class represents and manages project context data, providing
56
79
  # structured storage for file contents, command outputs, variables, and
57
80
  # metadata that can be serialized to JSON for AI assistance.
@@ -164,6 +187,7 @@ module ContextSpook
164
187
  content:,
165
188
  size: content.size,
166
189
  lines: content.lines.size,
190
+ content_types: MIME::Types.type_for(filename).map(&:content_type).full?,
167
191
  tags: (Array(tags) if tags),
168
192
  }.compact
169
193
  file_size = Tins::Unit.format(
@@ -214,6 +238,7 @@ module ContextSpook
214
238
  # The to_json method converts the object to a JSON representation by
215
239
  # first generating its hash form and then serializing that hash into JSON
216
240
  # format.
241
+ memoize method:
217
242
  def to_json(*)
218
243
  as_json.to_json(*)
219
244
  end
@@ -230,6 +255,19 @@ module ContextSpook
230
255
  variables:
231
256
  }
232
257
  end
258
+
259
+ # The size method calculates and returns the byte size of the JSON
260
+ # representation of the context.
261
+ #
262
+ # This method determines the size in bytes of the JSON-serialized version
263
+ # of the context object, which is useful for understanding the total data
264
+ # payload being sent to an AI assistant.
265
+ #
266
+ # @return [ Integer ] the size in bytes of the JSON representation of the
267
+ # context
268
+ def size
269
+ to_json.size
270
+ end
233
271
  end
234
272
 
235
273
  private
@@ -1,6 +1,6 @@
1
1
  module ContextSpook
2
2
  # ContextSpook version
3
- VERSION = '0.1.0'
3
+ VERSION = '0.3.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -5,19 +5,46 @@ describe ContextSpook::Generator do
5
5
  ContextSpook.generate_context('contexts/project.rb')
6
6
  end
7
7
 
8
- it 'context can be generated' do
8
+ it 'context can be generated from block' do
9
+ expect_any_instance_of(described_class).to\
10
+ receive(:output_context_size).and_call_original
11
+ context = ContextSpook.generate_context do
12
+ context do
13
+ variable foo: 'bar'
14
+ metadata version: '1.0'
15
+ end
16
+ end
17
+ expect(context).to be_a described_class::Context
18
+ expect(context.variables[:foo]).to eq 'bar'
19
+ expect(context.metadata[:version]).to eq '1.0'
20
+ end
21
+
22
+ it 'context can be generated from filename' do
23
+ expect_any_instance_of(described_class).to\
24
+ receive(:output_context_size).and_call_original
9
25
  expect(context).to be_a described_class::Context
10
26
  expect(context.metadata[:ruby]).to eq RUBY_DESCRIPTION
11
27
  end
12
28
 
29
+ it 'could handle premature output_context_size calls' do
30
+ expect_any_instance_of(described_class).to\
31
+ receive(:output_context_size).and_call_original
32
+ described_class.send(:new).output_context_size
33
+ end
34
+
35
+ it 'cannot do from block and filename' do
36
+ expect {
37
+ ContextSpook.generate_context('contexts/project.rb') { }
38
+ }.to raise_error(ArgumentError, /need either a filename or a &block/)
39
+ end
40
+
13
41
  it 'context be transformed to JSON if loaded' do
14
42
  context_as_json = context.to_json
15
- expect(context_as_json.size).to be > 1024
43
+ expect(context.size).to be > 1024
16
44
  expect(JSON(context_as_json)).to be_a Hash
17
45
  end
18
46
 
19
47
  describe 'Context' do
20
-
21
48
  it 'can have variables' do
22
49
  expect(context.variables[:branch]).to be_present
23
50
  end
@@ -26,6 +53,7 @@ describe ContextSpook::Generator do
26
53
  file = context.files['lib/context_spook.rb']
27
54
  expect(file).to be_present
28
55
  expect(file[:content]).to be_present
56
+ expect(file[:content_types]).to be_present
29
57
  expect(file[:size]).to be > 0
30
58
  expect(file[:lines]).to be > 0
31
59
  expect(file[:namespace]).to eq :lib
@@ -33,7 +61,7 @@ describe ContextSpook::Generator do
33
61
  end
34
62
 
35
63
  it 'can have commands' do
36
- command = context.commands['tree lib']
64
+ command = context.commands['tree']
37
65
  expect(command).to be_present
38
66
  expect(command[:working_directory]).to eq Dir.pwd
39
67
  expect(command[:exit_code]).to be_present
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: context_spook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '2.0'
18
+ version: '2.1'
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '2.0'
25
+ version: '2.1'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: all_images
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -121,6 +121,34 @@ dependencies:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
123
  version: '1.11'
124
+ - !ruby/object:Gem::Dependency
125
+ name: mize
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.6'
131
+ type: :runtime
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '0.6'
138
+ - !ruby/object:Gem::Dependency
139
+ name: mime-types
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '3.0'
145
+ type: :runtime
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '3.0'
124
152
  description: |
125
153
  context_spook is a library that collects and organizes project
126
154
  information to help AI assistants understand codebases better.