0

I have the following code creates a Parser class which has many parse_something methods. Then finally they are merged in the parse method:

class Parser
  def parse(html)
    @data = Nokogiri.HTML(open(html))
    merged_hashes = {}

    array_of_hashes = [
      parse_department,
      parse_super_saver,
      parse_new_arrivals,
      parse_out_of_stock,
      parse_categories,
      parse_results
    ]
    array_of_hashes.inject(merged_hashes,:update)

    return merged_hashes
  end

  def parse_department  
    department = @data.css('#ref_2619534011')

    @department_hash = {}
    department.css('li').drop(1).each do | department |
      department_title = department.css('.refinementLink').text
      department_count = department.css('.narrowValue').text[/[\d,]+/].delete(",").to_i
      @department_hash[:department] ||= {}
      @department_hash[:department]["Pet Supplies"] ||= {}
      @department_hash[:department]["Pet Supplies"][department_title] = department_count
    end 

    return @department_hash
  end 

  def parse_super_saver  

(etc...)

So right now, I'm using it like this:

def html_pet_supplies
  File.open("amazon_pet_supplies.html")
end

Parser.new.parse html_pet_supplies

But I would like to use it like this instead: Parser.parse html_pet_supplies

I tried removing new but I got this error:

NoMethodError: undefined method `parse' for Parser:Class

What's the simplest way of changing the code so that I just do Parser.parse?

0

2 Answers 2

1

Instead of rewriting all your methods to class methods, you could create a Parser instance and call Parser#parse from Parser.parse:

class Parser
  def self.parse(html)
    self.class.new.parse(html)
  end

  def parse(html)
    @data = Nokogiri.HTML(open(html))
    # ...
  end
  #...
end

Now Parser.parse(html) is equivalent to Parser.new.parse(html).

Sign up to request clarification or add additional context in comments.

3 Comments

I added self. in front of all the other methods and worked. That was also an option, right?
Sure, although writing tests for instance methods is usually easier (you do write tests, don't you?).
yeah I didn't change anything in the tests. They passed anyway.
1

Use static method declaration

class Parser
  def self.parse(html)
    #Parsing logic
  end
end

You could then invoke it by Parser.parse filename

Update You have instance variable declared in your parsing logic @data so you cannot get it working with current logic. You would have to create instance to be able to call parse_department.

** Further Update **

Short answer Your current logic is just fine.

Long answer It's more about OOP. In Parser#parse method you have @data instance variable declaration. @data can exist only for an object not for class, which in turn means that you can have it only in an instance method and not in static method. When you call Parser.new it create an object and that is when @data can exist. While static methods can be invoked on a class directly without creating an object. Read more Understanding Ruby class vs instance methods

4 Comments

Strange I changed it to self.parse but now both Parser.parse and Parser.new.parse stopped working: Failure/Error: let(:department_hash) { Parser.parse html_pet_supplies } NoMethodError: undefined method parse_department' for Parser:Class # ./parser.rb:9:in parse'
That's because you made only one method static and not the other one. If you have methods specific to object, then you cannot declare static methods to get your work done. You would have to live with creating new instances. It's more about OOP so I would suggest you read about static methods and object methods to get the understanding and to know it would work for you.
Sorry, I'm not very familiar with creating classes and static methods could you give me an example of this? You would have to create instance to be able to call parse_department.
I would not be able spend a lot of time explaining this, because it might take a lot of time. You could refer to the updated answer above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.