patternrubyMinor
line_to, fill_rect, and clear_rect functions
Viewed 0 times
fill_rectclear_rectandfunctionsline_to
Problem
def line_to(x: 0, y: 0, rect: nil)
unless rect.nil?
x, y, width, height = rect.x, rect.y, rect.width, rect.height
end
`#{@context}.lineTo(#{x}, #{y})`
end
def fill_rect(x: 0, y: 0, width: 0, height: 0, rect: nil)
unless rect.nil?
x, y, width, height = rect.x, rect.y, rect.width, rect.height
end
`#{@context}.fillRect(#{x}, #{y}, #{width}, #{height})`
end
def clear_rect(x: 0, y: 0, width: 0, height: 0, rect: nil)
unless rect.nil?
x, y, width, height = rect.x, rect.y, rect.width, rect.height
end
`#{@context}.clearRect(#{x}, #{y}, #{width}, #{height})`
endI am looking for a way to refactor the above code to take out the first three lines in the methods. I don't want to use Metaprogramming in this specific case; is there any other way?
In case full code will help, see the repo.
Solution
If I understand this correctly, you want to be able to call these methods with two different signatures:
There has to be some logic in the methods to decide which signature to use. I like your current solution for that. Using metaprogramming would make things too complicated.
Since the signatures are different, you could argue they are actually two different methods:
The best solution would be to only expect a single signature in the first place.
One way to do that is to use
You'll have to make sure that
Another way to do that would be to create a second type of object to replace the keyword arguments (
method(x: .., y: .., height: .., width: ..)
method(rect: ..)There has to be some logic in the methods to decide which signature to use. I like your current solution for that. Using metaprogramming would make things too complicated.
Since the signatures are different, you could argue they are actually two different methods:
#line_to and #line_to_rectangle for example. You could simply define two different methods:def line_to(x, y)
`#{@context}.lineTo(#{x}, #{y})`
end
def line_to_rectangle(rectangle)
line_to(rectangle.x, rectangle.y)
endThe best solution would be to only expect a single signature in the first place.
One way to do that is to use
** to pass a rectangle object as keyword arguments. For this to work you have to define a #to_hash.class Rectangle
def to_hash
{ :x => self.x, :y => self.y, :width => self.width, :height => self.height }
end
end
...
line_to(**rectangle)You'll have to make sure that
#line_to takes all keys returned by Rectangle#to_hash. That means it should also a width and height keyword argument. You can do this by taking them explicitly or implicitly (def line_to(x: 0, y: 0, **discard)). If you don't take those unnecessary arguments it will raise an exception. Hardly ideal.Another way to do that would be to create a second type of object to replace the keyword arguments (
x, y, width and height). It should have the same interface as rectangle. I'd recommend not complicating things this much, though, and pick a single signature.Code Snippets
method(x: .., y: .., height: .., width: ..)
method(rect: ..)def line_to(x, y)
`#{@context}.lineTo(#{x}, #{y})`
end
def line_to_rectangle(rectangle)
line_to(rectangle.x, rectangle.y)
endclass Rectangle
def to_hash
{ :x => self.x, :y => self.y, :width => self.width, :height => self.height }
end
end
...
line_to(**rectangle)Context
StackExchange Code Review Q#80576, answer score: 2
Revisions (0)
No revisions yet.