[OpenAPI]: Refactor: replace Prism AST parser with Blueprinter Reflection API#323
Conversation
Switch the Blueprinter parser from Prism-based AST parsing to Blueprinter's built-in Reflection API. This removes the need for a Visitor pattern, temp file parsing, and manual AST traversal. The Reflection API provides direct access to fields, views, and associations making the parser significantly simpler.
| @context = VisitorContext.new | ||
| yield | ||
| @context | ||
| view.instance_variable_get(:@view_collection).instance_variable_get(:@views)[view_name].instance_variable_get(:@fields).each_with_object({}) do |(_, field), hash| |
There was a problem hiding this comment.
At first I was using something like this:
reflections = klass.reflections
identifier_fields = {}
default_fields = {}
# identifier fields
if (identifier_view = reflections[:identifier])
identifier_view.fields.each do |_, field|
identifier_fields[field.name.to_s] = { "type" => "string" }
end
end
# default view fields
if (default_view = reflections[:default])
default_view.fields.each do |_, field|
default_fields[field.name.to_s] = { "type" => "string" }
end
endBut .fields of Relection API seems to break for
fields "first_name", :last_name
or for this too
field :email, name: "login"
There was a problem hiding this comment.
fields "first_name", :last_name
This seems to work fine for me with Blueprinter 1.2.1. But in any way, with this approach, we should only be relying on the official API. If some cases are not supported by the reflection API, it's safe to ignore them.
|
@rsamoilov I have refactor Blueprinter parser using
|
|
Only works with
|
| end | ||
|
|
||
| klass = Class.new(parent) | ||
| klass.class_eval(block.call) if block |
There was a problem hiding this comment.
This is the only newly added line. Rest is same as mocked_classes.rb
There was a problem hiding this comment.
It should be safe to add this line to mocked_classes.rb. And you won't need a separate context then.
The Reflection API requires DSL calls to be evaluated in the class context at runtime. Updated let_class to call class_eval with the block's string content when the parent is a Blueprinter class, while preserving the original behavior for all other classes (Alba, controllers, etc). Switched blueprinter_spec to use mocked_classes instead of the separate mocked_blueprinter_classes context, and removed mocked_blueprinter_classes from spec_helper since it's no longer needed. Also switched to view.fields official API using field.display_name instead of instance_variable_get hacks, and dropped unsupported mixed string/symbol field test cases.
b125ebf to
87977ff
Compare
|
@rsamoilov PR is ready to be reviewed again. Thank you!
|
| if block | ||
| if defined?(Blueprinter::Base) && parent.ancestors.include?(Blueprinter::Base) | ||
| klass.class_eval(block.call) | ||
| else | ||
| klass.class_eval(&block) | ||
| end | ||
| end |
There was a problem hiding this comment.
| if block | |
| if defined?(Blueprinter::Base) && parent.ancestors.include?(Blueprinter::Base) | |
| klass.class_eval(block.call) | |
| else | |
| klass.class_eval(&block) | |
| end | |
| end | |
| if block | |
| if defined?(Blueprinter::Base) && parent.ancestors.include?(Blueprinter::Base) | |
| klass.class_eval(block.call) | |
| end | |
| end |
The else branch doesn't seem to be used, so it'd be better to remove it in the next PR.
What this PR does?
Switch the Blueprinter parser from Prism-based AST parsing to Blueprinter's built-in Reflection API. This removes the need for a Visitor pattern, temp file parsing, and manual AST traversal. The Reflection API provides direct access to fields, views, and associations making the parser significantly simpler.
Example Code and Screenshot for basic Blueprinter fields: identifier, field, and fields
routes.rbproducts_controller.rbuser_blueprint.rbExample Code and Screnshoot of Blueprinter Inheritance
routes.rbdata_mining_controller.rbdata_mining_base.rbdata_mining.rbBlueprinter Response for route /data_miningOpenAPI response output for # @response DataMining