procme 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MThlMjQxM2JhNmQ0YjZlMGFhNDQ4ZTZmODM0NDM4MDA2ZjMwYTM1ZA==
4
+ NjZiNzFlNzI2YWUxYzhkZWFkYzJiMDZlMjU2ZTBmNTYxZTc4ZWZlNg==
5
5
  data.tar.gz: !binary |-
6
- ZmExNWYyYzI0YjM3NmM3ZjliOTRlNWRlNjgwMDJiMzQ4YzI2ZWY1Zg==
6
+ ZTk3ZjUyMDhkZmY0NTVkMzAyODc4MzBmMzk3NTg5OThhMjIzMDZlMw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YTJiZmVkZjFmMTFhN2UwODM2YWIyZjJjYTJiZDFjMDE3YTYyNzg1NjkzYzUy
10
- NDZmYTJjYWYwOTYwNmJjYmFmYmE0MjZjYjhkZDdhZjg1NjlmZTFlZjNjNTQ2
11
- MDMwMDdlNjNlZDQzMjMyYzAwNWE3MTZmNjc1OTY5ZWRhYmI3NzU=
9
+ MDgzNzIyYWZjNDA1M2YzMGE2ZjFkYTVjNDEyNmUxZjQwNDYxYjMwODI0OGY1
10
+ MTk2M2IxNGQ2MzAxOTA4MTViNzU5ZGYxNTdmMDA4YWI5ZDJiMTM5MmJmYjM3
11
+ NTU3MWNlNThjODhhOWU1YjMzZDE2ZDkzMGIxYmQ1ODVjZjA1ODM=
12
12
  data.tar.gz: !binary |-
13
- NzYzMTZmNGM2M2VlZmVmZGZhOWNlM2M3NjEzNjkyZDdkOTY1ZDE5ZTJjNjk2
14
- NjZjNDU4ZDBjNDM1YTNkN2M2MmZmZjUwZjBkMmRhYTA1MTJiYWFiYTZjZTVm
15
- NjdmZTZlMTI0YzFlYTAzMzEwN2I1NWY1MTNmM2NhMzUyOGY0ODg=
13
+ ZjA2MzNmZmJjZjQwZWE5NTg2M2U2Y2Q2NmFmN2M0NmI1ZDczN2Y3YjE4NWU1
14
+ ZGUxZjFlODBhNDRmNTNmYjMwMjE2NzQ5MDVhYjEzMjBmN2E0Njc3MDVjYTJj
15
+ NDlkYjAzZWU2OGYzYzQyOTkyMGU1YzI5YjZiNDAzMTA2YTI2MWE=
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ lib/procme.rb
2
+ --no-private
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014-15 Victor 'Zverok' Shepelev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,19 +1,34 @@
1
1
  # ProcMe
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/procme.svg)](http://badge.fury.io/rb/procme)
4
+
3
5
  ## Install
4
- With Bundler (brand new and yet unpublished to RubyGems):
6
+ With Bundler:
5
7
 
8
+ ```ruby
9
+ gem 'procme'
6
10
  ```
7
- gem 'procme', git: 'git://github.com/zverok/procme.git'
11
+
12
+ in your Gemfile, then `bundle install`.
13
+
14
+ Or without:
8
15
  ```
16
+ gem install procme
17
+ ```
18
+
19
+ [YARD docs](http://www.rubydoc.info/gems/procme)
9
20
 
10
21
  ## Usage
11
22
 
12
23
  ```ruby
13
- # Giving you have
24
+ # Given you have
14
25
  class Person < Struct.new(:name, :age, :gender)
15
26
  def greet(who)
16
- puts "#{name}: Hello, #{who}!"
27
+ "#{name}: Hello, #{who}!"
28
+ end
29
+
30
+ def greet!(who)
31
+ puts greet(name)
17
32
  end
18
33
 
19
34
  def inspect
@@ -48,12 +63,25 @@ p people.map(&set(gender: 'female'))
48
63
  # => [#<John, female, 30>, #<Jane, female, 23>, #<Jake, female, 48>, #<Judith, female, 16>]
49
64
 
50
65
  # ProcMe::call(method: args) - bulk call method with arguments:
51
- people.each(&call(greet: 'Ellis'))
66
+ people.each(&call(greet!: 'Ellis'))
52
67
  # Output:
53
68
  # John: Hello, Ellis!
54
69
  # Jane: Hello, Ellis!
55
70
  # Jake: Hello, Ellis!
56
71
  # Judith: Hello, Ellis!
72
+
73
+ # also works with #map:
74
+ people.map(&call(greet: 'Ellis'))
75
+ # => ["John: Hello, Ellis!", "Jane: Hello, Ellis!", "Jake: Hello, Ellis!", "Judith: Hello, Ellis!"]
76
+
77
+ # ...and with several arguments:
78
+ p people.map(&:name).map(&call(sub: ['J', 'F']))
79
+ # => ["Fohn", "Fane", "Fake", "Fudith"]
80
+
81
+ # ...and even several method you can call!
82
+ p people.map(&:name).map(&call(:downcase, :'+' => ', hello'))
83
+ # => [["john", "John, hello"], ["jane", "Jane, hello"], ["jake", "Jake, hello"], ["judith", "Judith, hello"]]
84
+ # Note that each method call is performed on ORIGINAL object
57
85
  ```
58
86
 
59
87
  ## Rationale
@@ -94,3 +122,37 @@ P = ProcMe # to be short
94
122
 
95
123
  people.select(&P.fltr(gender: 'female'))
96
124
  ```
125
+
126
+ ## Should you use it?
127
+
128
+ Frankly, I don't know. Things that mimic core language features can be
129
+ extremely useful, yet potentially they make your code more obscure for
130
+ reader. Though I think that ProcMe's syntax is pretty self-explanatory,
131
+ you colleagues may have other opinion.
132
+
133
+ As for me, since invention of this little thingy I've found it extremely
134
+ handy and useful.
135
+
136
+ ## Small gotchas
137
+
138
+ `ProcMe.fltr` uses `#===` while comparing values. This way you can filter
139
+ strings by regular expressions or numbers by ranges. One counterintuitive
140
+ things is going on when you try to filter by object class:
141
+
142
+ ```ruby
143
+ ['test', 'me'].select(&fltr(class: String)) # => []
144
+ ```
145
+
146
+ It's because you should check object itself, not its class, to match with
147
+ `===`. The solution is simple:
148
+
149
+ ```ruby
150
+ ['test', 'me'].select(&fltr(itself: String)) # => []
151
+ ```
152
+
153
+ `#itself` method is available in Ruby >= 2.0, and easily backported to
154
+ earlier versions.
155
+
156
+ ## License
157
+
158
+ MIT
data/examples/example.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  # encoding: utf-8
2
2
  require_relative '../lib/procme'
3
3
 
4
- # Giving you have
4
+ # Given you have
5
5
  class Person < Struct.new(:name, :age, :gender)
6
6
  def greet(who)
7
- puts "#{name}: Hello, #{who}!"
7
+ "#{name}: Hello, #{who}!"
8
+ end
9
+
10
+ def greet!(who)
11
+ puts greet(name)
8
12
  end
9
13
 
10
14
  def inspect
@@ -39,9 +43,22 @@ p people.map(&set(gender: 'female'))
39
43
  # => [#<John, female, 30>, #<Jane, female, 23>, #<Jake, female, 48>, #<Judith, female, 16>]
40
44
 
41
45
  # ProcMe::call(method: [args]) - bulk call method with arguments:
42
- people.each(&call(greet: 'Ellis'))
46
+ people.each(&call(greet!: 'Ellis'))
43
47
  # Output:
44
48
  # John: Hello, Ellis!
45
49
  # Jane: Hello, Ellis!
46
50
  # Jake: Hello, Ellis!
47
51
  # Judith: Hello, Ellis!
52
+
53
+ # also works with #map:
54
+ p people.map(&call(greet: 'Ellis'))
55
+ # => ["John: Hello, Ellis!", "Jane: Hello, Ellis!", "Jake: Hello, Ellis!", "Judith: Hello, Ellis!"]
56
+
57
+ # ...and with several arguments:
58
+ p people.map(&:name).map(&call(sub: ['J', 'F']))
59
+ # => ["Fohn", "Fane", "Fake", "Fudith"]
60
+
61
+ # ...and even several method you can call!
62
+ p people.map(&:name).map(&call(:downcase, :'+' => ', hello'))
63
+ # => [["john", "John, hello"], ["jane", "Jane, hello"], ["jake", "Jake, hello"], ["judith", "Judith, hello"]]
64
+ # Note that each method call is performed on ORIGINAL object
data/lib/procme.rb CHANGED
@@ -1,7 +1,70 @@
1
1
  # encoding: utf-8
2
- # ProcMe: DRY and clean blocks for your code
2
+
3
+ # ProcMe is DRY and clean blocks for your code.
4
+ #
5
+ # It provides four methods:
6
+ #
7
+ # {#fltr} - checks object attribute values
8
+ #
9
+ # ['test', 'me', 'please'].select(&fltr(length: 4))
10
+ # # => ['test']
11
+ #
12
+ # {#get} - get object attribute values
13
+ #
14
+ # ['test', 'me', 'please'].map(&get(:upcase, :length))
15
+ # # => [['TEST', 4], ['ME', 2'], ['PLEASE', 6]]
16
+ #
17
+ # {#call} - call methods on object
18
+ #
19
+ # ['test', 'me', 'please'].map(&call(gsub: ['e', '*']))
20
+ # # => ['t*st', 'm*', 'pl*as*']
21
+ #
22
+ # {#set} - set object attribute values
23
+ #
24
+ # S = Struct.new(:name)
25
+ # arr = [S.new('test'), S.new('me')]
26
+ # arr.each(&set(name: 'please'))
27
+ # arr # => [#<struct S name="please">, #<struct S name="please">]
28
+ #
29
+ # You can use the module as is:
30
+ #
31
+ # ['test', 'me', 'please'].select(&ProcMe.fltr(length: 4))
32
+ #
33
+ # or include it and then use:
34
+ #
35
+ # include ProcMe
36
+ #
37
+ # ['test', 'me', 'please'].select(&fltr(length: 4))
38
+ #
39
+ #
3
40
  module ProcMe
4
- def filter(hash)
41
+ # Constructs block, able to check objects attribute values
42
+ #
43
+ # @param attrs [Hash] hash of !{attribute name => value}
44
+ # @return [Proc] block accepting any object and returning +true+ or
45
+ # +false+
46
+ #
47
+ # Use it like this:
48
+ #
49
+ # some_array.select(&fltr(attr: value, other_attr: other_value))
50
+ #
51
+ # values are checked with +#===+ method, so you can do something like:
52
+ #
53
+ # ['some', 'strings'].select(&fltr(length: 3..5)) # => ['some']
54
+ #
55
+ # or like this:
56
+ #
57
+ # ['other', 'strings'].select(&fltr(upcase: /^S/)) # => ['strings']
58
+ #
59
+ # This approach has one gotcha:
60
+ #
61
+ # # wrong
62
+ # ['some', 'strings'].select(&fltr(class: String)) # => []
63
+ #
64
+ # # right
65
+ # ['some', 'strings'].select(&fltr(itself: String)) # => ['some', 'strings']
66
+ #
67
+ def filter(attrs)
5
68
  lambda do |o|
6
69
  hash.all?{|k, v| v === o.send(k)} # rubocop:disable Style/CaseEquality
7
70
  end
@@ -9,26 +72,85 @@ module ProcMe
9
72
 
10
73
  alias_method :fltr, :filter
11
74
 
12
- def set(hash)
75
+ # Constructs block, able to set objects attribute values
76
+ #
77
+ # @param attrs [Hash] hash of !{attribute name => value}
78
+ # @return [Proc] block, accepting any object and returning it
79
+ #
80
+ # Use it like this:
81
+ #
82
+ # some_array.each(&set(attr: value))
83
+ #
84
+ def set(attrs)
13
85
  lambda do |o|
14
- hash.each{|k, v| o.send("#{k}=", v)}
86
+ attrs.each{|k, v| o.send("#{k}=", v)}
15
87
  o
16
88
  end
17
89
  end
18
90
 
19
- def call(hash)
91
+ # Constructs block, able to call methods on object
92
+ #
93
+ # @param methods list of symbols or !{method => args} pairs
94
+ # @return [Proc] block, accepting any object and returning results of
95
+ # sending methods to it.
96
+ #
97
+ # Use it like this:
98
+ #
99
+ # some_array.each(&call(:method, other_method: [args]))
100
+ #
101
+ # If you call only one method, block will return just a result of call
102
+ # for each object:
103
+ #
104
+ # ['test', 'me'].map(&call(sub: ['e', '*'])) # => ['t*st', 'm*']
105
+ #
106
+ # If you call several methods, it would be array of results for each
107
+ # object:
108
+ #
109
+ # ['test', 'me'].map(&call(sub: ['e', '*'], index: 'e'))
110
+ # # => [['t*st', 2], ['m*', 2]]
111
+ #
112
+ # The latter example also shows that +#call+ sends each method to object
113
+ # itself, not the result of previous method call.
114
+ #
115
+ def call(*methods)
116
+ h = methods.last.is_a?(Hash) ? methods.pop : {}
117
+ hash = Hash[*methods.flat_map{|sym| [sym, []]}].merge(h)
118
+
20
119
  lambda do |o|
21
- hash.each{|k, v| o.send(k, *v)}
22
- o
120
+ ProcMe._singularize(hash.map{|k, v| o.send(k, *v)})
23
121
  end
24
122
  end
25
123
 
26
- def get(*array)
124
+ # Constructs block, able to receive attribute values from object
125
+ #
126
+ # @param attrs list of symbols
127
+ # @return [Proc] block, accepting any object and returning its attr
128
+ # values.
129
+ #
130
+ # Use it like this:
131
+ #
132
+ # some_array.map(&get(:attr, :other))
133
+ #
134
+ # Extremely useful for sorting:
135
+ #
136
+ # ['John', 'Alice', 'jane'].sort_by(&get(:length, :downcase)
137
+ # # => ['jane', 'John', 'Alice']
138
+ #
139
+ # As with {#call}, `#get` returns array of results for several methods
140
+ # and one result for only one method (with is not very useful anyways,
141
+ # as `map(&get(:length))` is a full equivalent of `map(&:length)`).
142
+ #
143
+ def get(*attrs)
27
144
  lambda do |o|
28
- array.map{|v| o.send(*v)}
145
+ ProcMe._singularize(attrs.map{|v| o.send(*v)})
29
146
  end
30
147
  end
31
148
 
32
149
  # now we can use both include ProcMe & no include approach
33
150
  extend self # rubocop:disable Style/ModuleFunction
151
+
152
+ # @private
153
+ def _singularize(arr)
154
+ arr.length == 1 ? arr.first : arr
155
+ end
34
156
  end
data/procme.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'procme'
3
- s.version = '0.0.1'
3
+ s.version = '0.0.2'
4
4
  s.authors = ['Victor Shepelev']
5
5
  s.email = 'zverok.offline@gmail.com'
6
6
  s.homepage = 'https://github.com/zverok/procme'
@@ -25,5 +25,8 @@ Gem::Specification.new do |s|
25
25
  end
26
26
  s.require_paths = ["lib"]
27
27
 
28
+ s.has_rdoc = 'yard'
29
+
28
30
  s.add_development_dependency 'rubocop', '~> 0.30'
31
+ s.add_development_dependency 'rspec', '~> 3'
29
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Shepelev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-15 00:00:00.000000000 Z
11
+ date: 2015-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.30'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3'
27
41
  description: ! " ProcMe provides you with methods for DRY and clean processing
28
42
  of\n enumerables.\n"
29
43
  email: zverok.offline@gmail.com
@@ -31,6 +45,8 @@ executables: []
31
45
  extensions: []
32
46
  extra_rdoc_files: []
33
47
  files:
48
+ - .yardopts
49
+ - LICENSE.txt
34
50
  - README.md
35
51
  - examples/example.rb
36
52
  - lib/procme.rb
@@ -60,3 +76,4 @@ signing_key:
60
76
  specification_version: 4
61
77
  summary: Useful DRY proc-s for Ruby
62
78
  test_files: []
79
+ has_rdoc: yard