Module: ProcMe

Extended by:
ProcMe
Included in:
ProcMe
Defined in:
lib/procme.rb

Overview

ProcMe is DRY and clean blocks for your code.

It provides four methods:

#fltr - checks object attribute values

['test', 'me', 'please'].select(&fltr(length: 4))
# => ['test']

#get - get object attribute values

['test', 'me', 'please'].map(&get(:upcase, :length))
# => [['TEST', 4], ['ME', 2'], ['PLEASE', 6]]

#call - call methods on object

['test', 'me', 'please'].map(&call(gsub: ['e', '*']))
# => ['t*st', 'm*', 'pl*as*']

#set - set object attribute values

S = Struct.new(:name)
arr = [S.new('test'), S.new('me')]
arr.each(&set(name: 'please'))
arr # => [#<struct S name="please">, #<struct S name="please">]

You can use the module as is:

['test', 'me', 'please'].select(&ProcMe.fltr(length: 4))

or include it and then use:

include ProcMe

['test', 'me', 'please'].select(&fltr(length: 4))

Instance Method Summary collapse

Instance Method Details

#call(*methods) ⇒ Proc

Constructs block, able to call methods on object

Use it like this:

some_array.each(&call(:method, other_method: [args]))

If you call only one method, block will return just a result of call for each object:

['test', 'me'].map(&call(sub: ['e', '*'])) # => ['t*st', 'm*']

If you call several methods, it would be array of results for each object:

['test', 'me'].map(&call(sub: ['e', '*'], index: 'e'))
# => [['t*st', 2], ['m*', 2]]

The latter example also shows that #call sends each method to object itself, not the result of previous method call.

Parameters:

  • methods

    list of symbols or {method => args} pairs

Returns:

  • (Proc)

    block, accepting any object and returning results of sending methods to it.



115
116
117
118
119
120
121
122
# File 'lib/procme.rb', line 115

def call(*methods)
  h = methods.last.is_a?(Hash) ? methods.pop : {}
  hash = Hash[*methods.flat_map{|sym| [sym, []]}].merge(h)

  lambda do |o|
    ProcMe._singularize(hash.map{|k, v| o.send(k, *v)})
  end
end

#filter(attrs) ⇒ Proc Also known as: fltr

Constructs block, able to check objects attribute values

Use it like this:

some_array.select(&fltr(attr: value, other_attr: other_value))

values are checked with #=== method, so you can do something like:

['some', 'strings'].select(&fltr(length: 3..5)) # => ['some']

or like this:

['other', 'strings'].select(&fltr(upcase: /^S/)) # => ['strings']

This approach has one gotcha:

# wrong
['some', 'strings'].select(&fltr(class: String)) # => []

# right
['some', 'strings'].select(&fltr(itself: String)) # => ['some', 'strings']

Parameters:

  • attrs (Hash)

    hash of {attribute name => value}

Returns:

  • (Proc)

    block accepting any object and returning true or false



67
68
69
70
71
# File 'lib/procme.rb', line 67

def filter(attrs)
  lambda do |o|
    attrs.all?{|k, v| v === o.send(k)} # rubocop:disable Style/CaseEquality
  end
end

#get(*attrs) ⇒ Proc

Constructs block, able to receive attribute values from object

Use it like this:

some_array.map(&get(:attr, :other))

Extremely useful for sorting:

['John', 'Alice', 'jane'].sort_by(&get(:length, :downcase)
# => ['jane', 'John', 'Alice']

As with #call, ‘#get` returns array of results for several methods and one result for only one method (with is not very useful anyways, as `map(&get(:length))` is a full equivalent of `map(&:length)`).

Parameters:

  • attrs

    list of symbols

Returns:

  • (Proc)

    block, accepting any object and returning its attr values.



143
144
145
146
147
# File 'lib/procme.rb', line 143

def get(*attrs)
  lambda do |o|
    ProcMe._singularize(attrs.map{|v| o.send(*v)})
  end
end

#set(attrs) ⇒ Proc

Constructs block, able to set objects attribute values

Use it like this:

some_array.each(&set(attr: value))

Parameters:

  • attrs (Hash)

    hash of {attribute name => value}

Returns:

  • (Proc)

    block, accepting any object and returning it



84
85
86
87
88
89
# File 'lib/procme.rb', line 84

def set(attrs)
  lambda do |o|
    attrs.each{|k, v| o.send("#{k}=", v)}
    o
  end
end