open_gemdocs 0.2.4 → 0.3.1

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.
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yard"
4
+ require "json"
5
+ require "fileutils"
6
+ require "tmpdir"
7
+
8
+ module OpenGemdocs
9
+ class YardJsonFormatter
10
+ def self.format_gem_docs(gem_name, object_path = nil)
11
+ # Ensure YARD server data is available
12
+ yard_db_path = find_yard_db(gem_name)
13
+
14
+ unless yard_db_path
15
+ # Try to generate the .yardoc if it doesn't exist
16
+ gem_path = find_gem_path(gem_name)
17
+ return { error: "Gem '#{gem_name}' not found" } unless gem_path
18
+
19
+ # Create a temporary .yardoc path
20
+ yard_db_path = File.join(Dir.tmpdir, "yard_#{gem_name}_#{Process.pid}", ".yardoc")
21
+ FileUtils.mkdir_p(File.dirname(yard_db_path))
22
+
23
+ # Generate YARD documentation
24
+ YARD::CLI::Yardoc.run("--no-output", "--db", yard_db_path, gem_path)
25
+ end
26
+
27
+ # Load the YARD registry
28
+ YARD::Registry.load(yard_db_path)
29
+
30
+ if object_path
31
+ # Return specific object documentation
32
+ obj = YARD::Registry.at(object_path)
33
+ return { error: "Object '#{object_path}' not found in #{gem_name}" } unless obj
34
+
35
+ begin
36
+ format_object(obj)
37
+ rescue StandardError => e
38
+ { error: "Failed to format object: #{e.message}\n#{e.backtrace.first(3).join("\n")}" }
39
+ end
40
+ else
41
+ # Return gem overview with main classes and modules
42
+ {
43
+ gem: gem_name,
44
+ summary: get_gem_summary(gem_name),
45
+ namespaces: format_namespaces,
46
+ classes: format_classes,
47
+ modules: format_modules
48
+ }
49
+ end
50
+ ensure
51
+ YARD::Registry.clear
52
+ end
53
+
54
+ private_class_method def self.find_yard_db(gem_name)
55
+ # Check common locations for .yardoc databases
56
+ possible_paths = [
57
+ File.join(Dir.home, ".yard", "gems", "#{gem_name}-*", ".yardoc"),
58
+ File.join(Gem.dir, "doc", "#{gem_name}-*", ".yardoc")
59
+ ]
60
+
61
+ possible_paths.each do |pattern|
62
+ matches = Dir.glob(pattern)
63
+ return matches.first if matches.any?
64
+ end
65
+
66
+ nil
67
+ end
68
+
69
+ private_class_method def self.find_gem_path(gem_name)
70
+ spec = Gem::Specification.find_by_name(gem_name)
71
+ spec.full_gem_path if spec
72
+ rescue Gem::LoadError
73
+ nil
74
+ end
75
+
76
+ private_class_method def self.get_gem_summary(gem_name)
77
+ spec = Gem::Specification.find_by_name(gem_name)
78
+ {
79
+ version: spec.version.to_s,
80
+ description: spec.description,
81
+ summary: spec.summary,
82
+ homepage: spec.homepage
83
+ }
84
+ rescue Gem::LoadError
85
+ {}
86
+ end
87
+
88
+ private_class_method def self.format_namespaces
89
+ YARD::Registry.all(:module, :class).select { |obj| obj.namespace.root? }.map do |obj|
90
+ {
91
+ name: obj.name.to_s,
92
+ path: obj.path,
93
+ type: obj.type.to_s
94
+ }
95
+ end
96
+ end
97
+
98
+ private_class_method def self.format_classes
99
+ YARD::Registry.all(:class).map do |obj|
100
+ {
101
+ name: obj.name.to_s,
102
+ path: obj.path,
103
+ namespace: obj.namespace.path == "" ? nil : obj.namespace.path,
104
+ superclass: obj.superclass ? obj.superclass.path : nil,
105
+ docstring: obj.docstring.to_s.empty? ? nil : obj.docstring.to_s,
106
+ methods_count: obj.meths.count
107
+ }
108
+ end
109
+ end
110
+
111
+ private_class_method def self.format_modules
112
+ YARD::Registry.all(:module).map do |obj|
113
+ {
114
+ name: obj.name.to_s,
115
+ path: obj.path,
116
+ namespace: obj.namespace.path == "" ? nil : obj.namespace.path,
117
+ docstring: obj.docstring.to_s.empty? ? nil : obj.docstring.to_s,
118
+ methods_count: obj.meths.count
119
+ }
120
+ end
121
+ end
122
+
123
+ private_class_method def self.format_object(obj)
124
+ return nil unless obj
125
+
126
+ base_info = {
127
+ name: obj.name.to_s,
128
+ path: obj.path,
129
+ type: obj.type.to_s,
130
+ namespace: obj.namespace && obj.namespace.path != "" ? obj.namespace.path : nil,
131
+ docstring: obj.docstring.to_s.empty? ? nil : obj.docstring.to_s,
132
+ tags: format_tags(obj.tags),
133
+ source: obj.file ? { file: obj.file, line: obj.line } : nil
134
+ }
135
+
136
+ case obj.type
137
+ when :class
138
+ base_info.merge!(
139
+ superclass: obj.superclass ? obj.superclass.path : nil,
140
+ includes: obj.mixins(:instance).map(&:path),
141
+ extends: obj.mixins(:class).map(&:path),
142
+ methods: format_methods(obj.meths),
143
+ attributes: format_attributes(obj.attributes)
144
+ )
145
+ when :module
146
+ base_info.merge!(
147
+ includes: obj.mixins(:instance).map(&:path),
148
+ extends: obj.mixins(:class).map(&:path),
149
+ methods: format_methods(obj.meths),
150
+ attributes: format_attributes(obj.attributes)
151
+ )
152
+ when :method
153
+ base_info.merge!(
154
+ signature: obj.signature,
155
+ parameters: format_parameters(obj.parameters),
156
+ visibility: obj.visibility.to_s,
157
+ scope: obj.scope.to_s,
158
+ aliases: obj.aliases.map(&:name).map(&:to_s)
159
+ )
160
+ end
161
+
162
+ base_info
163
+ end
164
+
165
+ private_class_method def self.format_tags(tags)
166
+ tags.map do |tag|
167
+ result = {
168
+ tag_name: tag.tag_name,
169
+ text: tag.text
170
+ }
171
+ result[:types] = tag.types if tag.respond_to?(:types)
172
+ result[:name] = tag.name if tag.respond_to?(:name)
173
+ result
174
+ end
175
+ end
176
+
177
+ private_class_method def self.format_methods(methods)
178
+ methods.map do |meth|
179
+ {
180
+ name: meth.name.to_s,
181
+ path: meth.path,
182
+ signature: meth.signature,
183
+ visibility: meth.visibility.to_s,
184
+ scope: meth.scope.to_s,
185
+ docstring: meth.docstring.to_s.empty? ? nil : meth.docstring.to_s,
186
+ parameters: format_parameters(meth.parameters),
187
+ return_type: extract_return_type(meth)
188
+ }.compact
189
+ end
190
+ end
191
+
192
+ private_class_method def self.format_parameters(params)
193
+ return [] unless params
194
+
195
+ params.map do |param|
196
+ name, default = param
197
+ {
198
+ name: name,
199
+ default: default
200
+ }
201
+ end
202
+ end
203
+
204
+ private_class_method def self.format_attributes(attrs)
205
+ attrs.map do |_name, attr|
206
+ # Handle case where both read and write might be nil (shouldn't happen but defensive)
207
+ accessor = attr[:read] || attr[:write]
208
+ next unless accessor
209
+
210
+ {
211
+ name: accessor.name.to_s.sub("=", ""),
212
+ read: !attr[:read].nil?,
213
+ write: !attr[:write].nil?,
214
+ docstring: accessor.docstring.to_s
215
+ }
216
+ end.compact
217
+ end
218
+
219
+ private_class_method def self.extract_return_type(method)
220
+ return_tag = method.tags.find { |t| t.tag_name == "return" }
221
+ return_tag ? return_tag.types : nil
222
+ end
223
+ end
224
+ end
225
+
data/lib/open_gemdocs.rb CHANGED
@@ -1,9 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'open_gemdocs/version'
4
- require_relative 'open_gemdocs/browser'
5
- require_relative 'open_gemdocs/yard'
3
+ require_relative "open_gemdocs/version"
4
+ require_relative "open_gemdocs/browser"
5
+ require_relative "open_gemdocs/yard"
6
6
 
7
7
  module OpenGemdocs
8
8
  class Error < StandardError; end
9
+
10
+ # MCP components are loaded on-demand by the executable
11
+ module MCP
12
+ # Autoload MCP components to avoid loading them unless needed
13
+ autoload :Server, "open_gemdocs/mcp/server"
14
+ autoload :Handlers, "open_gemdocs/mcp/handlers"
15
+ autoload :Tools, "open_gemdocs/mcp/tools"
16
+ end
9
17
  end
data.tar.gz.sig CHANGED
@@ -1,3 +1 @@
1
- qBb *���<S����Ekx�#-�Xk׫� ���6͊3X�{�+8hGX0�� ���J8��*���~�
2
- ��
3
- �\M'�g!GH>�;3]�ƨ:�g2+���x� 6ԭ��� ����@�3mj�]a9���W
1
+ R����GR)�N���G(�����٣)�7)�����yBLQ� ��o���{��R_j��E��* (�r^�5����,� -��LCS��ԟ�NYi��2�W�쨒��*��)N���� -��+LH���c/T �NL�Ƅ��b��ec����M�(*$F�Sfu"�A��}���r��5���6���þ���!��z����z�aG���}�H)m�\h�����gJ���O&���-�T�Q 5H��0����e9םG��7���W#0� I^7�1�����Uw�rB�\��=�4�۵<Lc�=�S�׭����3#�h������s�� 7���!���iL�ip(A8eA/2��ē���q�&��ڽ^�K��
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: open_gemdocs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean McCleary
@@ -36,6 +36,20 @@ cert_chain:
36
36
  -----END CERTIFICATE-----
37
37
  date: 1980-01-02 00:00:00.000000000 Z
38
38
  dependencies:
39
+ - !ruby/object:Gem::Dependency
40
+ name: webrick
41
+ requirement: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '1.8'
46
+ type: :runtime
47
+ prerelease: false
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '1.8'
39
53
  - !ruby/object:Gem::Dependency
40
54
  name: yard
41
55
  requirement: !ruby/object:Gem::Requirement
@@ -54,7 +68,10 @@ description: ''
54
68
  email:
55
69
  - seanmcc@gmail.com
56
70
  executables:
71
+ - document-bundle
57
72
  - open-gem-docs
73
+ - open-gem-docs-mcp
74
+ - open-gem-docs-mcp-stdio
58
75
  - open-local-docs
59
76
  extensions: []
60
77
  extra_rdoc_files: []
@@ -62,6 +79,7 @@ files:
62
79
  - ".rspec"
63
80
  - ".rubocop.yml"
64
81
  - CHANGELOG.md
82
+ - CLAUDE.md
65
83
  - LICENSE.txt
66
84
  - README.md
67
85
  - Rakefile
@@ -72,12 +90,20 @@ files:
72
90
  - checksums/open_gemdocs-0.2.2.gem.sha512
73
91
  - checksums/open_gemdocs-0.2.3.gem.sha512
74
92
  - checksums/open_gemdocs-0.2.4.gem.sha512
93
+ - checksums/open_gemdocs-0.3.1.gem.sha512
94
+ - exe/document-bundle
75
95
  - exe/open-gem-docs
96
+ - exe/open-gem-docs-mcp
97
+ - exe/open-gem-docs-mcp-stdio
76
98
  - exe/open-local-docs
77
99
  - lib/open_gemdocs.rb
78
100
  - lib/open_gemdocs/browser.rb
101
+ - lib/open_gemdocs/mcp/handlers.rb
102
+ - lib/open_gemdocs/mcp/server.rb
103
+ - lib/open_gemdocs/mcp/tools.rb
79
104
  - lib/open_gemdocs/version.rb
80
105
  - lib/open_gemdocs/yard.rb
106
+ - lib/open_gemdocs/yard_json_formatter.rb
81
107
  - sig/open_gemdocs.rbs
82
108
  homepage: https://github.com/mrinterweb/open_gemdocs
83
109
  licenses:
@@ -87,6 +113,7 @@ metadata:
87
113
  homepage_uri: https://github.com/mrinterweb/open_gemdocs
88
114
  source_code_uri: https://github.com/mrinterweb/open_gemdocs
89
115
  changelog_uri: https://github.com/mrinterweb/open_gemdocs/blob/main/CHANGELOG.md
116
+ rubygems_mfa_required: 'true'
90
117
  rdoc_options: []
91
118
  require_paths:
92
119
  - lib
@@ -101,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
128
  - !ruby/object:Gem::Version
102
129
  version: '0'
103
130
  requirements: []
104
- rubygems_version: 3.6.8
131
+ rubygems_version: 3.7.1
105
132
  specification_version: 4
106
133
  summary: Simple command line tool to open the documentation for a gem.
107
134
  test_files: []
metadata.gz.sig CHANGED
Binary file