reachable 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,6 @@
1
+ Version 0.2.1
2
+ * Added recursion, so that arrays within reachable arrays are treated as
3
+ reachable arrays themselves
4
+ Version 0.3.0
5
+ * Changed the name of the gem to reachable, to avoid naming
6
+ conflict with the reach rubygem.
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "> 1.0.0"
10
+ gem "jeweler", "> 1.6.0"
11
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Ben J Woodcroft
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,70 @@
1
+ Copyright (C) 2008-2012 Ben J Woodcroft <donttrustben somewhere near gmail.com>
2
+
3
+ This software is BETA! Use at your own risk.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/wwood/bioruby-krona.png)](http://travis-ci.org/wwood/reachable)
6
+
7
+ # Reachable
8
+
9
+ Reachable is a small Ruby liby that extends the Array class so that Arrays are more transparent
10
+ to methods. For instance, a ReachableArray of Book objects can not only take normal Array methods such as
11
+ collect and sum, but also methods that operate Book objects, such as author and title.
12
+
13
+ ## Example
14
+
15
+ Say I have an regular ActiveRecord driven database, that has Bookshelf, Book, and Author classes. Bookshelves have many books, and books have many authors.
16
+
17
+ Say I want all the books.
18
+
19
+ ```ruby
20
+ Book.all
21
+ ```
22
+
23
+ Then I want to find all the bookshelves from those that contain those books.
24
+
25
+ ```ruby
26
+ Book.all.collect{|book| book.bookshelf} #=> array of bookshelves.
27
+ ```
28
+
29
+ From personal experience, running a single method on each array element and collecting the results is quite common, especially in Rails. The idea, then, is to make the arrays not just responsive to the methods that apply to the Array itself, but to methods that apply to the +members+ of that array. That is, make the array reachable (caution: made up word). In the case above we want to run the 'bookshelf' method on each of the book objects in the array.
30
+
31
+ To make an array reachable, convert it into a ReachableArray object, by calling the reach method of Array, which is added by the inclusion of the reach library.
32
+
33
+ ```ruby
34
+ require 'reachable'
35
+ Book.all.reach #=> ReachableArray of books
36
+ ```
37
+
38
+ Now getting the corresponding array of bookshelves requires less typing:
39
+
40
+ ```
41
+ require 'reachable'
42
+ Book.all.reach.bookshelf #=> ReachableArray of Bookshelf objects
43
+ ```
44
+
45
+ Notice that a ReachableArray is returned by the bookshelf method, not an Array. This means you can chain reaches together:
46
+
47
+ ```ruby
48
+ require 'reachable'
49
+ Author.all.reach.book.bookshelf #=> ReachableArray of Bookshelf objects
50
+ ```
51
+
52
+ Removing reachability from the array, or retracting, is equally as simple - just use the retract method:
53
+
54
+ ```ruby
55
+ require 'reachable'
56
+ Book.all.reach.bookshelf.retract #=> Array of Bookshelf objects
57
+ ```
58
+
59
+ ### Slap
60
+
61
+ Like reach, the slap method is another method added to the Array class to make it mroe transparent. The difference is that reach looks to see if the given method operates on the Array class, and if not then applies it to each member of that array. The slap method bypasses the first step, and just applies the given method to each member. For instance
62
+
63
+ ```ruby
64
+ require 'reachable'
65
+ [[1,2,3],[4]].slap.length.retract #=> [1,3]
66
+ ```
67
+
68
+ ## Caution
69
+
70
+ When operating on a ReachableArray, methods that operate on the Array itself take precedence over methods that apply to array members.
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "reachable"
18
+ gem.homepage = "http://github.com/wwood/reachable"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Reachable is a small Ruby liby that extends the Array class so that Arrays are more transparent
21
+ to methods.}
22
+ gem.description = %Q{For instance, a ReachableArray of Book objects can not only take normal Array methods such as
23
+ collect and sum, but also methods that operate Book objects, such as author and title. }
24
+ gem.email = "gmail.com after donttrustben"
25
+ gem.authors = ["Ben J Woodcroft"]
26
+ # dependencies defined in Gemfile
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ task :default => :test
38
+
39
+ require 'rdoc/task'
40
+ Rake::RDocTask.new do |rdoc|
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "reach #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
@@ -0,0 +1,113 @@
1
+ # Copyright (c) 2008 Ben Woodcroft <donttrustben somewhere near gmail.com>
2
+ #
3
+ # This program is free software.
4
+ # You can distribute/modify this program under the terms of
5
+ # the GNU General Public License version 3.
6
+
7
+ # The point of this is that the
8
+ # Bookshelf.all.reach.books.each do {|book| puts book.name}
9
+ # instead of
10
+ # Bookshelf.all.each do |bookshelf|
11
+ # bookshelf.books.each do |book|
12
+ # puts book.name
13
+ # end
14
+ # end
15
+
16
+ # Bookshelf.all.reach is a ReachableArray
17
+ # the books is an array (bookshelves) of arrays (books)
18
+ class Array
19
+ def reach
20
+ ReachingArray.new(self)
21
+ end
22
+
23
+ def slap
24
+ SlappingArray.new(self)
25
+ end
26
+ end
27
+
28
+ class ReachingArray
29
+ # The array that this reaching array is extending. This might
30
+ # be a real Array, or a ReachingArray
31
+ attr_accessor :retract
32
+
33
+ def initialize(retract)
34
+ @retract = retract
35
+ end
36
+
37
+ # The method could be missing from the array, the members, or both.
38
+ # Try to pass the method to each, in that order, accepting the first taker
39
+ def method_missing(method, *args, &block)
40
+ if @retract.respond_to?(method)
41
+ # If this is an array method, just use that
42
+ r = @retract.send(method, *args, &block)
43
+ return r
44
+ else
45
+ # If this is an object-specific method, run an each on it.
46
+ # A simple each won't work because that doesn't modify the
47
+ # array elements in place as we want, so have to use collect
48
+ # instead.
49
+ @retract = @retract.collect do |o|
50
+ unless o.kind_of?(Array)
51
+ o.send(method, *args, &block)
52
+ else
53
+ # Update in 0.2.1: If the element of the array is an array
54
+ # itself, then operate on it as a ReachingArray as well.
55
+ o.reach.send(method, *args, &block).retract
56
+ end
57
+ end
58
+ return self
59
+ end
60
+ end
61
+
62
+ # Equality test - equality of the underlying retract
63
+ # arrays is all that matter
64
+ def ==(another)
65
+ @retract <=> another.retract
66
+ end
67
+
68
+ def to_s
69
+ method_missing(:to_s)
70
+ end
71
+
72
+ def slap
73
+ retract.slap
74
+ end
75
+ end
76
+
77
+ class SlappingArray
78
+ # The array that this reaching array is extending. This might
79
+ # be a real Array, or a ReachingArray
80
+ attr_accessor :retract
81
+
82
+ def initialize(retract)
83
+ @retract = retract
84
+ end
85
+
86
+ # Try to pass the method to each of the array members
87
+ def method_missing(method, *args, &block)
88
+ @retract = @retract.collect do |o|
89
+ unless o.kind_of?(Array)
90
+ o.send(method, *args, &block)
91
+ else
92
+ # Update in 0.2.1: If the element of the array is an array
93
+ # itself, then operate on it as a ReachingArray as well.
94
+ o.slap.send(method, *args, &block).retract
95
+ end
96
+ end
97
+ return self
98
+ end
99
+
100
+ # Equality test - equality of the underlying retract
101
+ # arrays is all that matter
102
+ def ==(another)
103
+ @retract <=> another.retract
104
+ end
105
+
106
+ def to_s
107
+ method_missing(:to_s)
108
+ end
109
+
110
+ def reach
111
+ retract.reach
112
+ end
113
+ end
data/rdoc.sh ADDED
@@ -0,0 +1 @@
1
+ rdoc --main README.rdoc --inline *.rdoc lib/*
@@ -0,0 +1,52 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "reachable"
8
+ s.version = "0.3.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ben J Woodcroft"]
12
+ s.date = "2012-08-13"
13
+ s.description = "For instance, a ReachableArray of Book objects can not only take normal Array methods such as\ncollect and sum, but also methods that operate Book objects, such as author and title. "
14
+ s.email = "gmail.com after donttrustben"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ "CHANGES",
21
+ "Gemfile",
22
+ "LICENSE.txt",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/reachable.rb",
27
+ "rdoc.sh",
28
+ "reachable.gemspec",
29
+ "test/test_reach.rb"
30
+ ]
31
+ s.homepage = "http://github.com/wwood/reachable"
32
+ s.licenses = ["MIT"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = "1.8.17"
35
+ s.summary = "Reachable is a small Ruby liby that extends the Array class so that Arrays are more transparent to methods."
36
+
37
+ if s.respond_to? :specification_version then
38
+ s.specification_version = 3
39
+
40
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
41
+ s.add_development_dependency(%q<bundler>, ["> 1.0.0"])
42
+ s.add_development_dependency(%q<jeweler>, ["> 1.6.0"])
43
+ else
44
+ s.add_dependency(%q<bundler>, ["> 1.0.0"])
45
+ s.add_dependency(%q<jeweler>, ["> 1.6.0"])
46
+ end
47
+ else
48
+ s.add_dependency(%q<bundler>, ["> 1.0.0"])
49
+ s.add_dependency(%q<jeweler>, ["> 1.6.0"])
50
+ end
51
+ end
52
+
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2008 Ben Woodcroft <donttrustben somewhere near gmail.com>
2
+ #
3
+ # This program is free software.
4
+ # You can distribute/modify this program under the terms of
5
+ # the GNU Lesser General Public License version 3.
6
+
7
+
8
+ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
9
+
10
+ require 'test/unit'
11
+ require 'reachable'
12
+
13
+ class ReachTest < Test::Unit::TestCase
14
+ def setup
15
+ @one_level = %w(a b c)
16
+ @two_level = [[1,2,3],[5]]
17
+ end
18
+
19
+ def test_normality
20
+ # Test arrays seem normal - this is kinda pointless I would say
21
+ index = 0
22
+ @one_level.each { |n|
23
+ assert_equal @one_level[index], n
24
+ index += 1
25
+ }
26
+ end
27
+
28
+ def test_simple_method
29
+ out = @one_level.reach.succ!
30
+ assert_kind_of ReachingArray, out
31
+ assert_equal ReachingArray.new(%w(b c d)), out
32
+ end
33
+
34
+ def test_scoping_one
35
+ assert_equal ReachingArray.new(%w(c d e)), @one_level.reach.succ!.succ!
36
+ end
37
+
38
+ def test_collect
39
+ assert_equal %w(b c d), @one_level.reach.collect{|c| c.succ}
40
+ end
41
+
42
+ # Catches if the array elements are not modified within the reach
43
+ def test_double_scope
44
+ # make sure my assumptions are correct about the
45
+ # classes being tested
46
+ assert 1.respond_to?(:zero?)
47
+ assert_equal false, '1'.respond_to?(:zero?)
48
+
49
+ # make sure that the array elements are being reversed
50
+ str = ['0','2','3']
51
+ assert_equal [0,2,3], str.reach.to_i.retract
52
+ assert_equal [true, false, false], str.reach.to_i.zero?.retract
53
+ end
54
+
55
+ def test_block_accepted
56
+ assert_equal %w(d e f), @one_level.reach.succ.collect{|c| c.succ.succ}
57
+ end
58
+
59
+ def test_to_s
60
+ assert_equal [1,2].to_s, [1,2].reach.to_s
61
+ end
62
+
63
+ def test_recursive
64
+ assert_equal [1,[2,3],[[5]]],
65
+ ['1',['2','3'],[['5']]].reach.to_i.retract
66
+ end
67
+ end
68
+
69
+ class SlapTest < Test::Unit::TestCase
70
+ def setup
71
+ @one_level = %w(a b c)
72
+ @two_level = [[1,2,3],[5]]
73
+ end
74
+
75
+ def test_simple
76
+ assert_kind_of SlappingArray, @two_level.slap
77
+
78
+ assert_equal [['1','2','3'],['5']], @two_level.slap.to_s.retract
79
+ end
80
+
81
+ def test_mutate
82
+ assert_kind_of ReachingArray, @two_level.slap.reach
83
+ assert_equal [[1,2,3],[5]], @two_level.slap.reach.retract
84
+ end
85
+
86
+ def test_array_method_fail
87
+ assert_raise NoMethodError do
88
+ @one_level.slap.join(' ')
89
+ end
90
+ end
91
+
92
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reachable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben J Woodcroft
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &75534190 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>'
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *75534190
25
+ - !ruby/object:Gem::Dependency
26
+ name: jeweler
27
+ requirement: &75533890 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>'
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *75533890
36
+ description: ! 'For instance, a ReachableArray of Book objects can not only take normal
37
+ Array methods such as
38
+
39
+ collect and sum, but also methods that operate Book objects, such as author and
40
+ title. '
41
+ email: gmail.com after donttrustben
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files:
45
+ - LICENSE.txt
46
+ - README.md
47
+ files:
48
+ - CHANGES
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - VERSION
54
+ - lib/reachable.rb
55
+ - rdoc.sh
56
+ - reachable.gemspec
57
+ - test/test_reach.rb
58
+ homepage: http://github.com/wwood/reachable
59
+ licenses:
60
+ - MIT
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ segments:
72
+ - 0
73
+ hash: -120248467
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 1.8.17
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Reachable is a small Ruby liby that extends the Array class so that Arrays
86
+ are more transparent to methods.
87
+ test_files: []