views:

129

answers:

4

In web dev I come across these problems a lot.

For example, we have a giant list of URLs that are in this format:

/businesses  
/businesses/food  
/businesses/food/wendys  
/businesses/food/wendys/chili  
/businesses/food/wendys/fries  
/businesses/food/wendys/chicken-nuggets  
/businesses/pharmacy/cvs  
/businesses/pharmacy/cvs/toothpaste  
/businesses/pharmacy/cvs/toothpaste/brand  
...

and then we need to output each one, where the parent category is in h1 tags, the child is in h2 tags, and the children of that are in h3 tags.

I can handle this but I feel my code is messy. I'm sure there is a design pattern I can use? Langs are ruby/php usually. how would you handle this?

A: 

Not exactly sure what kind of solution you're after but I'd start in this direction, first make a tree out of your url list:

s = '/businesses  
/businesses/food  
/businesses/food/wendys  
/businesses/food/wendys/chili  
/businesses/food/wendys/fries  
/businesses/food/wendys/chicken-nuggets  
/businesses/pharmacy/cvs  
/businesses/pharmacy/cvs/toothpaste  
/businesses/pharmacy/cvs/toothpaste/brand'
h = {}
s.split("\n").map(&:strip).each do |row|
  lh = h
  row[1..-1].split('/').each do |item|
    lh[item] ||= {}
    lh = lh[item]
  end
end

and then print it recursively, not using tags > H3:

def rprint h, level=1
  h.each do |k,v|
    puts "<li><h#{level}>#{k}</h#{level}>"
    unless v.empty?
      puts "<ul>"
      rprint(v, level == 3 ? 3 : level + 1)
      puts "</ul>"
    end
    puts "</li>"
  end
end

rprint h

Of course, this printing logic would go to a view, using decent templating language instead of composing HTML like this, but the idea should be same.

Mladen Jablanović
Thanks. I had a somewhat similar solution but yours is far more elegant. However, one major hurdle is that each child is within a list of the parent. so there should be a <ul> ... </ul> between the h3, h4 tags. I'm having trouble figuring out how/when to close the list tags
I've edited the code to wrap the children with `ul` tags. Check it out.
Mladen Jablanović
+1  A: 

This one is a little compressed, but I hope it makes sense. Of course you can benchmark it to tune it for most optimized result.

s.each { |row|
  puts row[1..-1].split('/')[0..2].each_with_index \
  {|v,i| 
    tag = "h#{i+1}";
    print "<#{tag}>#{v}</#{tag}> "
  }
}

more detailed

s.each do |row|                             # 'each' will split each row
  row = row[1..-1]                          # string of the row without '/'
  words = row.split('/')                    # split into words
  words = words[0..2]                       # we just need first 3 tags
  words.each_with_index do |word, index|    # get index and value of each element in word array
    tag = "h#{index+1}"                       # use index to dynamically generate tag
    print "<#{tag}>#{word}</#{tag}> "       # use the tag and word to generate output
  end
end

You should

  1. put the method in a library of appropriate place
  2. collect the values in an array
  3. loop through the array in the view and generate tags

ramonrails
Short, clean, working. +1
dimitko
A: 

Check this out:

Recursive Tree Structures in PHP

Alex
A: 

This obviously needs some more love, but maybe it gets you started:

>> path = "/businesses/pharmacy/cvs/toothpaste/brand" 
>> path.split('/',4)[1..-1].each_with_index { |el,i| puts "<h#{i+1}>#{el}</h#{i+1}>" }
<h1>businesses</h1>
<h2>pharmacy</h2>
<h3>cvs/toothpaste/brand</h3>

edit: Here's another way I can think of:

>> [*0..2].zip(path.split('/',4).drop(1)).each { |i,el| puts "<h#{i}>#{el}</h#{i}>" }
Michael Kohl