# Ruby style programming (DRYness)

**URL:** <https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960>\
**Category:** Rails\
**Created:** [September 18, 2008, 6:20pm UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960 "2008-09-18T18:20:58Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![surge](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/4da419/32.png) [@surge](https://www.ruby-forum.com/u/surge)\
**Post date:** [September 18, 2008, 6:20pm UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960/1 "2008-09-18T18:20:58Z")

</div>

Hi everybody,

I have a line of the form:

x = hash1.reject{ |key,value| !value}.keys.join(’,’)

That worked fine but then I needed to do the same thing for hash2. So  
I had to add another line like so:

y = hash2.reject{ |key,value| !value}.keys.join(’,’)

I’m trying go DRY but I can’t think of an elegant way to do it – I’m  
a relative beginner in ruby. A function is an obvious candidate, but  
that’s probably my php thinking. Any better way to avoid the  
repetition? Some fancy loop?

Thanks!  
Sergei

---

<div class="post-metadata">

**Author:** ![surge](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/4da419/32.png) [@surge](https://www.ruby-forum.com/u/surge)\
**Post date:** [September 18, 2008, 6:42pm UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960/2 "2008-09-18T18:42:05Z")

</div>

On Sep 19, 12:19 am, surge [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I’m trying go DRY but I can’t think of an elegant way to do it – I’m  
> a relative beginner in ruby. A function is an obvious candidate, but  
> that’s probably my php thinking. Any better way to avoid the  
> repetition? Some fancy loop?
> 
> Thanks!  
> Sergei

Perhaps extending Hash would help:

# lib/hash.rb

class Hash  
def get\_non\_empty\_keys # use whatever name is appropriate  
self.reject{|k, v| !v}.keys.join(‘,’)  
end  
end

# config/environment.rb

require “lib/hash.rb”

You can now use the get\_non\_empty\_keys function on your hashes:

x = hash1.get\_non\_empty\_keys  
y = hash2.get\_non\_empty\_keys

---

<div class="post-metadata">

**Author:** ![surge](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/4da419/32.png) [@surge](https://www.ruby-forum.com/u/surge)\
**Post date:** [September 18, 2008, 7:54pm UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960/3 "2008-09-18T19:54:57Z")

</div>

Erol, that’s so cool. I like your solution a lot.

What about this one:

I allow users to filter tickets based on the module (I call them  
components) they report on. The list of components comes in  
as an array. Here’s what I do.

# Get a list of components

@components = Component.find :all

# This is the hash that will be used in a SQL statement. It will

become clear in a second.  
@filter\_components = {}

# Initialize all components to true (this is the default – we show

tickets for all components)  
@components.each { |component| @filter\_components[component.id] =  
true }

if request.xhr?  
@components.each do |component|  
# Shouldn’t happen, but if so, empty @filter\_components. This  
means no tickets will be selected.  
if params[:filter\_components].empty?  
@filter\_components = {}  
break;  
end

```
if (params[:filter_components]).include?(component.id.to_s)
  @filter_components[component.id] = true
else
  @filter_components[component.id] = false
end

```

end

# Make sure at least one component is in @filter\_components so that

we don’t have special cases.  
@filter\_components[0] = true if @filter\_components.size == 0  
end

# Now comes the line about which I was asking in my previous email.

The result of it is used in an IN() part of a SQL query  
components = @filter\_components.reject{ |key,value| !  
value}.keys.join(’,’)

It works but it’s a lot of code and the problem is I need to do the  
same for  
statuses! Any way to reduce this and make it reusable for statuses?  
BTW, the  
reason why I’m not using params[:filter\_components] directly in the  
SQL query  
(e.g. params[:filter\_components].join(’,’)) is so that the data from  
the web is  
not used in a SQL query directly. Make sense?

Thanks!!!

P.S.: I typed this twice! The first version of this was lost. Bummer.

---

<div class="post-metadata">

**Author:** ![surge](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/4da419/32.png) [@surge](https://www.ruby-forum.com/u/surge)\
**Post date:** [September 18, 2008, 8:26pm UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960/4 "2008-09-18T20:26:08Z")

</div>

On Sep 18, 6:53 pm, surge [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Erol, that’s so cool. I like your solution a lot.
> 
> What about this one:
> 
> I allow users to filter tickets based on the module (I call them  
> components) they report on. The list of components comes in  
> as an array. Here’s what I do.

Why aren’t you just doing Ticket.find :all, :conditions =\>  
{:component\_id =\> params[:component\_ids}} ?

Fred

---

<div class="post-metadata">

**Author:** ![surge](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/4da419/32.png) [@surge](https://www.ruby-forum.com/u/surge)\
**Post date:** [September 18, 2008, 9:00pm UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960/5 "2008-09-18T21:00:52Z")

</div>

Unless you wanted to add that method to the Hash class, you could  
easily do:

[hash1, hash2].collect{|hash| hash.reject{ |key,value| !  
value}.keys.join(’,’)}

Which would give you an array of the new hashes. If you wanted to  
assign these values to x and y:

x,y = [hash1, hash2].collect{|hash| hash.reject{ |key,value| !  
value}.keys.join(’,’)}

---

<div class="post-metadata">

**Author:** ![surge](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/4da419/32.png) [@surge](https://www.ruby-forum.com/u/surge)\
**Post date:** [September 19, 2008, 5:02pm UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960/6 "2008-09-19T17:02:06Z")

</div>

I thought it would be perfect too, but there’s a slight problem. The  
limitation is that that form assumes everything as AND’ed. This is  
what I came up with yesterday:

@tickets = Ticket.find :all, :conditions =\> [  
“((assignee\_id IS NULL AND reporter\_id = :reporter\_id) OR  
assignee\_id = :assignee\_id)  
AND tickets.status\_id IN(:statuses) AND  
tickets.component\_id IN(:components)”,  
{  
:assignee\_id =\> user.id,  
:reporter\_id =\> user.id,  
:statuses =\> @filter\_statuses,  
:components =\> @filter\_components  
}  
]

See that OR? I think because of it I can’t use the suggested by  
Frederick form. And with the form presented here, I couldn’t say  
tickets.component\_id = :components. Rails didn’t transform the equal  
sign into an “IN” although it did translate the array of component ids  
into a comma separated list. But it works nonetheless if I put IN  
inside the string. Then, if components are empty, it correctly  
replaces the variable with a NULL. And I think everything is properly  
escaped as well.

---

<div class="post-metadata">

**Author:** ![surge](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/4da419/32.png) [@surge](https://www.ruby-forum.com/u/surge)\
**Post date:** [September 19, 2008, 8:56am UTC](https://www.ruby-forum.com/t/ruby-style-programming-dryness/148960/7 "2008-09-19T08:56:06Z")

</div>

On Sep 19, 2:25 am, Frederick C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Why aren’t you just doing Ticket.find :all, :conditions =\>  
> {:component\_id =\> params[:component\_ids}} ?

I’d go with this one from Fred. No need to worry about using the  
params[:component\_ids] directly in the finder, the input is being  
sanitized by Rails before being used in the SQL, much like :conditions  
=\> [‘field = ?’, value] is. It generates an IN() condition if  
params[:component\_ids] is an array or an IS NULL condition if  
params[:component\_ids] is nil.
