Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/interfaces/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Proxy

attr_reader :name

def_delegators :@source, :file_path, :lines, :lines=, :start_line, :end_line, :scope
def_delegators :@source, :file_path, :lines, :lines=, :start_line, :end_line, :start_index, :scope
def_delegators :@source, :wrap, :export

def initialize(name:, source:)
Expand Down
2 changes: 0 additions & 2 deletions lib/models/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ def export
lines[start_index..end_index].join
end

private

def start_index
start_line - 1
end
Expand Down
9 changes: 9 additions & 0 deletions lib/proxies/method_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ def tagged_params(tag)
@tagged_params[tag] || []
end

def rewrite_signature
old_line = lines[start_index]
scope_prefix = old_line.match?(/def self\./) ? 'def self.' : 'def '

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a blocker but I wonder if a method proxy already has info on whether it's a class method or not

all_params = @params.map { |p| p.expression ? p.export(typed: false) : p.name.to_s }
return_suffix = @return_proxy ? " #{@return_proxy.export}" : ''
indent = old_line[/^\s*/]
lines[start_index] = "#{indent}#{scope_prefix}#{@name}(#{all_params.join(', ')})#{return_suffix}\n"
end

def expressions?
@params.any?(&:expression) || @return_proxy
end
Expand Down
37 changes: 36 additions & 1 deletion lib/proxies/param_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,42 @@ def initialize(name:, source:, type:, position: nil, value: :LOWKEY_UNDEFINED, e
end

def required?
@value == :LOWKEY_UNDEFINED
@value == :LOWKEY_UNDEFINED || @value == ':LOWKEY_UNDEFINED'
end

def export(typed: true)
return @source.export if typed
return untyped_keyword_param if %i[key_req key_opt].include?(@type)

untyped_positional_param
end

private

def untyped_keyword_param
default = resolved_default
default.nil? ? "#{@name}:" : "#{@name}: #{default}"
end

def untyped_positional_param
default = resolved_default
default.nil? ? @name.to_s : "#{@name} = #{default}"
end

def resolved_default
if @expression
return nil if @expression.default_value == :LOW_TYPE_UNDEFINED
return nil if @expression.default_value.nil? && required?

value = @expression.default_value
return value.value.inspect if value.is_a?(ValueExpression)

return value.inspect
end

return nil if @value == :LOWKEY_UNDEFINED || @value == ':LOWKEY_UNDEFINED'

@value
end
end
end
36 changes: 36 additions & 0 deletions spec/units/method_proxy_rewrite_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

require 'prism'
require_relative '../../lib/lowkey'

RSpec.describe Lowkey::MethodProxy do
subject(:file_proxy) { Lowkey.load('spec/fixtures/mock_node.rbx') }

let(:method_proxy) { file_proxy['Lowkey::MockNode'][:render] }

describe '#rewrite_signature' do
it 'replaces the signature line in the shared lines array' do
original_line = method_proxy.lines[method_proxy.start_index].dup
method_proxy.rewrite_signature
rewritten = method_proxy.lines[method_proxy.start_index]
expect(rewritten).not_to eq(original_line)
end

it 'removes type annotations from the signature' do
method_proxy.rewrite_signature
rewritten = method_proxy.lines[method_proxy.start_index]
expect(rewritten).not_to match(/String|Integer|Symbol/)
end

it 'preserves the method name' do
method_proxy.rewrite_signature
rewritten = method_proxy.lines[method_proxy.start_index]
expect(rewritten).to include('def render')
end

it 'is reflected in file_proxy.export since lines are shared' do
method_proxy.rewrite_signature
expect(file_proxy.export).to include(method_proxy.lines[method_proxy.start_index].strip)
end
end
end
46 changes: 46 additions & 0 deletions spec/units/param_proxy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

require 'prism'
require_relative '../../lib/lowkey'

RSpec.describe Lowkey::ParamProxy do
subject(:file_proxy) { Lowkey.load('spec/fixtures/mock_node.rbx') }

let(:method_proxy) { file_proxy['Lowkey::MockNode'][:render] }

describe '#export' do
context 'typed: true (default)' do
it 'returns the raw source for a positional param' do
param = method_proxy[:one]
expect(param.export).to eq(param.export(typed: true))
end

it 'returns the raw source for a keyword param' do
param = method_proxy[:three]
expect(param.export).to eq(param.export(typed: true))
end
end

context 'typed: false with no expression set' do
it 'returns plain name for a required positional param' do
param = method_proxy[:one]
expect(param.export(typed: false)).to eq('one')
end

it 'returns plain name for a required keyword param' do
param = method_proxy[:three]
expect(param.export(typed: false)).to eq('three:')
end

it 'returns name with default for an optional positional param' do
param = method_proxy[:two]
expect(param.export(typed: false)).to eq("two = 'mock value'")
end

it 'returns name with default for an optional keyword param' do
param = method_proxy[:four]
expect(param.export(typed: false)).to eq("four: 'mock value'")
end
end
end
end