-
Notifications
You must be signed in to change notification settings - Fork 31
Refactor towards simple data/config classes #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Also, implement `Annotations#to_h`
tests stuff
@koic asked the following on #48, which is also relevant here, so I'm transcribing it:
|
My original motivation for this was that as a consumer I found the API confusing: why define a class that will never be instantiated and only have singleton methods? In addition, the existing approach has (IMO) a higher implementation complexity because of the various "macros" for setting/getting the configured values, as well as the unusual In this new approach, we maintain a clear separation between the "schema" and the behaviour (isolated in the handler block):
Technically, this gem's README says it follows Semantic Versioning, and since we're still on a 0.x version, we're "free to make breaking changes at any time", and perhaps we should consider if it makes more sense to rapidly iterate towards a feature complete 1.0 release. That said, if we want to go the deprecation warning route, I think we would do something like the following:
Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One comment I had seeing this PR in general... I think it might be more idiomatic and simpler to just use actual Data classes offered by Ruby
@kfischer-okarin I flip-flopped on using I gave it a shot based on your feedback (sambostock/mcp-ruby-sdk@data...sambostock:mcp-ruby-sdk:data-define), and based on what I found, I think it's still preferable to stick to POROs:
To expand on the last point # frozen_string_literal: true
require "minitest/autorun"
class UsingPORO
attr_reader :required_positional, :optional_keyword
def initialize(required_positional, optional_keyword: nil)
@required_positional = required_positional
@optional_keyword = optional_keyword
end
end
UsingData = Data.define(:required_positional, :optional_keyword) do
def initialize(required_positional:, optional_keyword: nil) = super(required_positional:, optional_keyword:)
end
class MixedPositionalAndKeywordTest < Minitest::Test
[UsingPORO, UsingData].each do |klass|
define_method "test_#{klass.name}.new('positional') works" do
klass.new("positional")
end
define_method "test_#{klass.name}.new('positional', 'optional') raises ArgumentError" do
assert_raises(ArgumentError) { klass.new("positional", "optional") }
end
define_method "test_#{klass.name}.new('positional', optional_keyword: 'optional') works" do
klass.new("positional", optional_keyword: "optional")
end
end
end $ ruby data.rb
Run options: --seed 26182
# Running:
F.E...
Finished in 0.000440s, 13636.3644 runs/s, 4545.4548 assertions/s.
1) Failure:
MixedPositionalAndKeywordTest#test_UsingData.new('positional', 'optional') raises ArgumentError [data.rb:25]:
ArgumentError expected but nothing was raised.
2) Error:
MixedPositionalAndKeywordTest#test_UsingData.new('positional', optional_keyword: 'optional') works:
ArgumentError: wrong number of arguments (given 2, expected 0)
data.rb:29:in 'UsingData.new'
data.rb:29:in 'block (2 levels) in <class:MixedPositionalAndKeywordTest>'
6 runs, 2 assertions, 1 failures, 1 errors, 0 skips IMO given the simplicity of the API we're trying to offer, I think it's simplest to stick to POROs. |
@sambostock Ok, good reasonable points about not choosing the Data class approach - I can get behind that 👍🏻 It would be nice if the examples/docs were also updated to reflect the new API I was wondering if it would also be a good idea to make resources and resource templates also take blocks as I also think it's okay to be not sooo careful about breaking changes since we're before v1.0.0 - the error message and the necessary rewrite are both straightforward enough. If you wanted to be a bit nicer, you could offer a little mini code rewrite example right inside the error message. Or give those examples in longer form in a Changelog entry and refer to that in the error message. |
I agree with all of the above. Incidentally, if merged, #55 would enforce the examples are updated. I'll explore the resource changes you mentioned next week. 👍 |
This PR is an alternative to #48, with the same underlying motivations. It explores the idea of having tools and prompts be defined as simple data/config/value objects, and drops support for the current inheritance based approach.
It is a work in progress, but I have opted to open a draft now to get feedback, especially as it relates to other PRs, such as #54.
Motivation and Context
How Has This Been Tested?
Breaking Changes
Types of changes
Checklist
Additional context