How do I monkey-patch ruby's URI.parse method - ruby

Some popular blog sites typically use square brackets in their URLs but ruby's built-in URI.parse() method chokes on them, raising a nasty exception, as per:
http://redmine.ruby-lang.org/issues/show/1466
I'm trying to write a simple monkey-patch that gracefully handles URLs with the square bracket. The following is what I have so far:
require 'uri'
module URI
def self.parse_with_safety(uri)
safe_uri = uri.replace('[', '%5B')
safe_uri = safe_uri.replace(']', '%5D')
URI.parse_without_safety(safe_uri)
end
alias_method_chain :parse, :safety
end
But when run, this generates an error:
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/core_ext/module/aliasing.rb:33:in alias_method: NameError: undefined method 'parse' for module 'URI'
How can I successfully monkey-patch URI.parse?

alias_method_chain is executed on the module level so it only affects instance methods.
What you have to do is execute it on the module's class level:
require 'uri'
module URI
class << self
def parse_with_safety(uri)
parse_without_safety uri.gsub('[', '%5B').gsub(']', '%5D')
end
alias parse_without_safety parse
alias parse parse_with_safety
end
end

#nil his comment is very helpful, we ended up with the following:
def parse_with_safety(uri)
begin
parse_without_safety uri.gsub(/([{}|\^\[\]\#`])/) {|s| URI.escape(s)}
rescue
parse_without_safety '/'
end
end

Related

Parsed_response in Ruby from HTTP

How can i get parsed_response from here?
require 'HTTParty'
require 'httparty/request'
require 'httparty/response/headers'
class CRUD
include HTTParty
def retrieve
##response = CRUD.get('http://dummy.restapiexample.com/api/v1/employee/id')
end
end
{"id":"719","employee_name":"test","employee_salary":"123","employee_age":"23","profile_image":""}
puts #manter_user.retrieve.parsed_response['employee_name'] -- dont work
puts CRUD.class_variable_get(:##response).parsed_response['employee_name'] -- dont work
It's an instance method, it means that you need to create an instance. And you don't need global variable. And it is bad idea to name class with all uppercase letters - this style is used for constants. Classes and modules use MixedCase and have no underscores, each word starts with an uppercase letter.
class Crud
include HTTParty
def retrieve
self.class.get('http://dummy.restapiexample.com/api/v1/employee/id')
end
end
> Crud.new.retrieve.parsed_response
Since you are getting the JSON response, you can parsed it back as
require 'json'
foo = JSON['{"id":"719","employee_name":"test","employee_salary":"123","employee_age":"23","profile_image":""}']
puts foo['employee_name'] # => test

Handling a method from outside of a mixin module in ruby and rspec

I have a class that looks like this:
module ReusableBitlyLinks
def shorten_url url, *args
ShortenedUrl.shorten_url_with_bitly( url, email.user )
end
end
I have a test that looks like this:
require File.expand_path("../../../../app/decorators/mixins/reusable_bitly_links", __FILE__)
include ReusableBitlyLinks
describe ReusableBitlyLinks do
describe "shorten_url" do
it "works" do
ReusableBitlyLinks.shorten_url('asdf').should == 'asdf'
end
end
end
When I run the test I get an error that says:
uninitialized constant ReusableBitlyLinks::ShortenedUrl
How do I mock stub ReusableBitlyLinks::ShortenedUrl?
Is ShortenedUrl defined inside ReusableBitlyLinks module? If not - try to access it with ::ShortenedUrl.shorten_url_with_bitly.
Not sure what stubbing has to do with it...
In your mixin module, you need to tell it that ShortenedUrl is from outside the module by prepending :::
module ReusableBitlyLinks
def shorten_url(url, *args)
::ShortenedUrl.shorten_url_with_bitly(url, email.user)
end
end
You may also need to do a require inside the mixin file to load whatever file it is that defines ShortenedUrl.
Further, in your test file, the line:
require File.expand_path("../../../../app/decorators/mixins/reusable_bitly_links", __FILE__)
could be simplified to:
require_relative '../../../../app/decorators/mixins/reusable_bitly_links'

Can't call module method

I'm writing a Chef cookbook to deploy and application and create users. It doesn't have an API, and uses an odd hashing method, so I've written a short library module for it. I've included only the makeSalt() method below for the sake of brevity.
module Foo_packagist
module Password
def makeSalt(len=31)
require 'securerandom'
return Digest.hexencode(SecureRandom.random_bytes((len*6/8.0).ceil)).to_i(16).to_s(36)[0..len-1]
end
end
end
The trouble is that in every Chef run I get:
NoMethodError
-------------
undefined method `makeSalt' for Foo_packagist::Password:Module
and debugging in chef-shell I get:
chef (12.4.0)> puts ::Foo_packagist::Password.instance_methods()
makeSalt
encodePassword
chef (12.4.0)> puts ::Foo_packagist::Password.makeSalt()
NoMethodError: undefined method `makeSalt' for Foo_packagist::Password:Module
chef (12.4.0)> puts ::Foo_packagist::Password::makeSalt()
NoMethodError: undefined method `makeSalt' for Foo_packagist::Password:Module
What is the right way to call this method?
Change that to def self.makeSalt. That's the Ruby syntax for a module-level method.
Try this ->
module Foo_packagist
module Password
def self.makeSalt(len=31)
require 'securerandom'
return Digest.hexencode(SecureRandom.random_bytes((len*6/8.0).ceil)).to_i(16).to_s(36)[0..len-1]
end
end
end
Then to call it would be this->
Foo_packagist::Password.makeSalt()

Why do I get the error uninitialized constant Stuff::HTTParty?

I have the HTTParty gem on my system and I can use it from within rails.
Now I want to use it standalone.
I am trying:
class Stuff
include HTTParty
def self.y
HTTParty.get('http://www.google.com')
end
end
Stuff.y
but I get
$ ruby test_httparty.rb
test_httparty.rb:2:in `<class:Stuff>': uninitialized constant Stuff::HTTParty (NameError)
from test_httparty.rb:1:in `<main>'
07:46:52 durrantm Castle2012 /home/durrantm/Dropnot/_/rails_apps/linker 73845718_get_method
$
You have to require 'httparty':
require 'httparty'
class Stuff
include HTTParty
# ...
end
Its all because of the include which exists with in the class
If you include a class with a module, that means you're "bringing in" the module's methods as instance methods.
If you need more clarity on include and require
I request you to refer to this wonderful SO Posting
What is the difference between include and require in Ruby?
Here is an example which I have taken from the same posting
module A
def say
puts "this is module A"
end
end
class B
include A
end
class C
extend A
end
B.say => undefined method 'say' for B:Class
B.new.say => this is module A
C.say => this is module A
C.new.say => undefined method 'say' for C:Class

Ruby require loop

I have the following code (simplified):
decorator.rb
require 'decoratable'
class Decorator < SimpleDelegator
include Decoratable
end
decoratable.rb
require 'decorator_builder'
module Decoratable
def decorate(*decorators)
decorators.inject(DecoratorBuilder.new(self)) do |builder, decorator|
builder.public_send(decorator)
end.build
end
end
decorator_builder.rb
require 'rare_decorator'
class DecoratorBuilder
def initialize(card)
#card = card
#decorators = []
end
def rare
#decorators << ->(card) { RareDecorator.new(card) }
self
end
def build
#decorators.inject(#card) do |card, decorator|
decorator.call(card)
end
end
end
rare_decorator.rb
require 'decorator'
class RareDecorator < Decorator
# Stuff here
end
When I require decorator.rb, it causes RareDecorator to be declared before Decorator is declared, which is a problem since RareDecorator inherits from Decorator.
A possible solution is to split up decorator.rb like so:
class Decorator < SimpleDelegator; end
require 'decoratable'
class Decorator
include Decoratable
end
However, declaring dependencies in the middle of a file doesn't seem doesn't seem like a very clean solution to me.
Is there a better solution to this problem?
Instead of specifying requirements within every file, create one file which will require all the the application's requirements. Call it for example environment.rb:
require 'decoratable'
require 'decorator'
require 'decorator_builder'
require 'rare_decorator'
You don't need to worry about Decoratable not knowing what DecoratorBuilder is, as it is used within the method and the check for the constant will be executed when this method is called. Since you require decorator moment later, all will work.

Resources