DSL blocks with individual contexts? #577
Replies: 1 comment
-
I was working on a similar problem today and determined that there is no way to do this declaratively. There is a # @yieldself [SomePlugin]
def init(name, &block)
end
# now `self` is a SomePlugin instance in every `init` block Depending on your appetite for Solargraph plugins and poking at instance variables, the following should do more or less what you want: # put this somewhere solargraph can require it, then add "your_plugin" to the plugins array in .solargraph.yml
module Solargraph
class FrameworkPlugin < Convention
def local(source_map)
return EMPTY_ENVIRON unless source_map.filename =~ /framework_config.rb/ # or whatever you want
new_pins = []
# @type [Array<Pin::Block>]
blocks = source_map.pins.select { |p| p.is_a?(Pin::Block) && p.receiver.children[0] == :init }
blocks.each do |block|
# turns :some_plugin into "SomePlugin", the type we want our block to be bound to.
# if you want "SomePlugin::Config" or whatever, here's where you do that.
binder_type = block.receiver.children[0].to_s.classify
# here we have to get a bit nasty to prevent Solargraph from computing it's own binder
block.instance_variable_set(:@binder, ComplexType.parse(binder_type))
end
# we always need to return an Environ
EMPTY_ENVIRON
end
end
Convention.register(FrameworkPlugin)
end Note: I have not tested the above code, it's adapted from a convention I wrote to support an internal DSL, so it should work, but buyer beware 😉. If you intend to support a broad user base you probably want to be a bit safer when traversing into the child nodes of |
Beta Was this translation helpful? Give feedback.
-
First off, thank you for a wonderful pillar of the Ruby ecosystem…I use Solargraph extensively everywhere!
So…I'm building a DSL for initializing various plugins within a framework, with code that looks something like this:
And this itself is within an overall configuration block.
I've gotten to the point where Solargraph recognizes
init
and where that comes from, but the problem is I can't figure out a way to tell it—even with just parse or override or whatever magic comments—that the first init should pick up info foroption1
andoption2
in Context A, and the second should pick up info forother_option1
in Context B, and presumably those definitions could come from totally different gems.Any thoughts on how this might work?
Beta Was this translation helpful? Give feedback.
All reactions