andand 1.3.1 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,12 @@
1
+ == 1.3.2
2
+
3
+ * 1 minor enhancement
4
+ * better docs
5
+ * 2 major enhancement:
6
+ * Fix 1.9 warning (patch by George MacKerron)
7
+ * 3 major enhancement:
8
+ * Remove deprecated gemspec information (patch by Anthony Panozzo)
9
+
1
10
  == 1.3.1 2008-07-12
2
11
 
3
12
  * 1 major enhancement:
File without changes
@@ -1,10 +1,12 @@
1
1
  h1. Object#andand
2
2
 
3
- h1. → 'andand'
3
+ h2. Breaking News
4
+
5
+ @Object#andand@'s functionality is also available as part of the "RewriteRails":http://github.com/raganwald/rewrite_rails plug-in. If you are using Ruby on Rails, please consider using RewriteRails instead of the andand gem.
4
6
 
5
7
  h2. What
6
8
 
7
- _Object#andand_ lets us write:
9
+ @Object#andand@ lets us write:
8
10
 
9
11
  <pre syntax="ruby">
10
12
  @phone = Location.find(:first, ...elided... ).andand.phone
@@ -24,7 +26,17 @@ entry.at('description').andand.inner_text
24
26
 
25
27
  h2. Installing
26
28
 
27
- <pre syntax="ruby">sudo gem install andand</pre>
29
+ Update to RubyGems 1.2.0 before proceeding!!
30
+
31
+ <pre syntax="ruby">sudo gem sources -a http://gems.github.com (you only have to do this once)
32
+ sudo gem install raganwald-andand</pre>
33
+
34
+ Or:
35
+
36
+ <pre syntax="ruby">git clone git://github.com/raganwald/andand.git
37
+ cd andand
38
+ rake gem
39
+ rake install_gem</pre>
28
40
 
29
41
  h2. The basics
30
42
 
@@ -55,19 +67,31 @@ Object#andand let&rsquo;s us write:
55
67
  list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }
56
68
  </pre>Object#andand emphasizes syntactic regularity: the goal was to make an @&&.@ operation that worked like @&&=@. @&&=@ looks just like normal assignment, you can use any expression on the RHS, only the semantics are different. The andand method also works just like a normal method invocation, only the semantics are modified.
57
69
 
58
- h3. Use andand to simplify your regular expression matching and extraction
70
+ h3. Block-Structured andand
71
+
72
+ You can use @andand@ with a block instead of a method:
73
+
74
+ <pre syntax="ruby">
75
+ @phone = Location.find(:first, ...elided... ).andand { |location|
76
+ YellowPages.reverse_lookup(location).phone
77
+ }
78
+ </pre>If the receiver is nil, the block is not executed and @andand@ returns @nil@. If the receiver is not nil, it is passed as a parameter to the block and @andand@ returns the value of the block. This makes it possible to perform conditional evaluation and also to make the scope of the variable really obvious.
79
+
80
+ h3. Scope
81
+
82
+ @Object#andand@ only works for one method call. For example, @fu.andand.bar.blitz@ is going to call @nil.blitz@ if @fu@ is @nil@. That's because @fu.andand.bar@ is going to evaluate to @nil@, and then we will call the method @blitz@ on it. In most cases, you want to use @fu.andand.bar.andand.blitz@. If that seems awkward, you might want to reconsider violating the Law of Demeter in an environment where you can't be sure if your receiver is @nil@ or not.
59
83
 
60
- Do you ever find yourself wanting to extract a single value from a string using a regular expression? For example, Ruby's Tempfile class creates paths to files that end in .pid.n (where pid is your process id and n is some number). Do you have a path that might be a tempfile and you want to obtain the base name?
84
+ Another example of this (pointed out by Jan Zimmek):
61
85
 
62
- Do you currently retrieve the MatchData object, check if it is nil, and get the first matching group if it isn't? How about:
86
+ <pre syntax="ruby">
87
+ x = nil
88
+ x.andand.length > 3
89
+ </pre>This results in a @NoMethodError@. Again, @x@ is @nil@, therefore @x.andand.length@ is @nil@, therefore we end up with @nil > 3@ which results in a @NoMethodError@. This can be fixed with @x.andand.length.andand > 3@ as above, or perhaps:
63
90
 
64
91
  <pre syntax="ruby">
65
- require 'tempfile'
66
- path = Tempfile.new('foo.bar').path
67
- => "/var/folders/UZ/UZyZsbVPEWqC7tTXrQBYGU+++TI/-Tmp-/foo.bar.1280.0"
68
- path.match('/([^/]+)\.[0-9]+\.[0-9]+$').andand[1]
69
- => "foo.bar"
70
- </pre>With @.andand[1]@, you extract the group in the regular expression safely: if the expression matches, you get the group. If the expression fails to match, you get nil. Which is what you want, isn't it? The contents of the group if the expression matches? Why should you need more than one line for something so simple?
92
+ x = nil
93
+ x.andand { |value| value.length > 3 }
94
+ </pre>
71
95
 
72
96
  h3. Enhanced Object#tap
73
97
 
@@ -121,7 +145,7 @@ h2. How to submit patches
121
145
 
122
146
  Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/.
123
147
 
124
- The trunk repository is @svn://rubyforge.org/var/svn/andand/trunk@ for anonymous access.
148
+ The public clone url is @git://github.com/raganwald/andand.git@. Fork you very much.
125
149
 
126
150
  h2. License
127
151
 
@@ -131,6 +155,8 @@ h2. Shout Out
131
155
 
132
156
  "Mobile Commons":http://mcommons.com/. Huge.
133
157
 
158
+ Also interesting: "Wicked":http://github.com/wideopenspaces/wicked
159
+
134
160
  h2. Contact
135
161
 
136
- Comments are welcome. Send an email to "Reginald Braithwaite":mailto:raganwald+rubyforge@gmail.com.
162
+ Comments are welcome. Send an email to "Reginald Braithwaite":mailto:raganwald@gmail.com.
@@ -98,8 +98,8 @@ class Object
98
98
  include AndAnd::ObjectGoodies
99
99
  end
100
100
 
101
- unless Module.constants.include?('BlankSlate')
102
- if Module.constants.include?('BasicObject')
101
+ unless Module.constants.map { |c| c.to_s }.include?('BlankSlate')
102
+ if Module.constants.map { |c| c.to_s }.include?('BasicObject')
103
103
  module AndAnd
104
104
  class BlankSlate < BasicObject
105
105
  end
@@ -2,7 +2,7 @@ module Andand #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
4
  MINOR = 3
5
- TINY = 1
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,133 @@
1
+ =begin
2
+
3
+ Copyright (c) 2008 Reginald Braithwaite
4
+ http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html
5
+
6
+ Permission is hereby granted, free of charge, to any person
7
+ obtaining a copy of this software and associated documentation
8
+ files (the "Software"), to deal in the Software without
9
+ restriction, including without limitation the rights to use,
10
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the
12
+ Software is furnished to do so, subject to the following
13
+ conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
+ OTHER DEALINGS IN THE SOFTWARE.
26
+
27
+ =end
28
+
29
+ require File.dirname(__FILE__) + '/test_helper.rb'
30
+
31
+ require 'andand'
32
+
33
+ class Symbol
34
+ def to_proc
35
+ Proc.new { |*args| args.shift.__send__(self, *args) }
36
+ end
37
+ end
38
+
39
+ describe AndAnd, "Basic Behaviour" do
40
+ it "should conditionally yield to a block" do
41
+ 5.andand { |n| n*n }.should == 25
42
+ 5.andand(&:succ).should == 6
43
+ nil.andand { |n| n*n }.should == nil
44
+ false.andand { |n| n*n }.should == false
45
+ end
46
+ it "should conditionally call a proc-able parameter" do
47
+ 5.andand(:succ).should == 6
48
+ nil.andand(:succ).should == nil
49
+ false.andand(:succ).should == false
50
+ end
51
+ it "should conditionally proxy methods" do
52
+ 5.andand.succ.should == 6
53
+ nil.andand.succ.should == nil
54
+ false.andand.succ.should == false
55
+ (1..10).andand.inject(&:+).should == 55
56
+ nil.andand.inject(&:+).should == nil
57
+ false.andand.inject(&:+).should == false
58
+ 'HelloWeblogReaders'.andand[7,4].should == 'blog'
59
+ nil.andand[7,4].should == nil
60
+ false.andand[7,4].should == false
61
+ 'HelloWeblogReaders'.andand.tr('Wb','Bd').should == 'HelloBedlogReaders'
62
+ nil.andand.tr('Wb','Bd').should == nil
63
+ false.andand.tr('Wb','Bd').should == false
64
+ end
65
+ it "should handle infix operators" do
66
+ (5.andand * 2).should == 10
67
+ (nil.andand * 2).should == nil
68
+ (false.andand * 2).should == false
69
+ end
70
+ end
71
+
72
+ describe AndAnd, "Me" do
73
+ it "should unconditionally yield to a block" do
74
+ 5.me { |n| n*n }.should == 5
75
+ 5.me(&:succ).should == 5
76
+ nil.me { |n| n || true }.should be_nil
77
+ false.me { |n| n || true }.should == false
78
+ end
79
+ it "should unconditionally call a proc-able parameter" do
80
+ 5.me(:to_s).should == 5
81
+ nil.me(:to_s).should == nil
82
+ false.me(:to_s).should == false
83
+ end
84
+ it "should proxy methods" do
85
+ 5.me.to_s.should == 5
86
+ nil.me.to_s.should == nil
87
+ false.me.to_s.should == false
88
+ (1..10).me.inject(&:+).should == (1..10)
89
+ 'HelloWeblogReaders'.me[7,4].should == 'HelloWeblogReaders'
90
+ 'HelloWeblogReaders'.me.tr('Wb','Bd').should == 'HelloWeblogReaders'
91
+ end
92
+ it "should handle infix operators" do
93
+ (5.me * 2).should == 5
94
+ end
95
+ end
96
+
97
+ describe AndAnd, "Mixing Me with AndAnd" do
98
+ it "should compose me.andand" do
99
+ frobbish = :blitz
100
+ :foo.me.andand do
101
+ frobbish = :bar
102
+ end.should == :foo
103
+ frobbish.should == :bar
104
+ nil.me.andand do
105
+ frobbish = :barbarella
106
+ end.should be_nil
107
+ frobbish.should == :bar
108
+ false.me.andand do
109
+ frobbish = :hope
110
+ end.should == false
111
+ frobbish.should == :bar
112
+ end
113
+ end
114
+
115
+ class Foo
116
+ def frobbish
117
+ 'fnord'
118
+ end
119
+ end
120
+
121
+ describe AndAnd, "exception handling" do
122
+ it "should not swallow NoMethodErrors" do
123
+ foo = Foo.new
124
+ lambda do
125
+ foo.andand.frobbish
126
+ nil.andand.frobbish
127
+ nil.andand.hsibborf
128
+ end.should_not raise_error
129
+ lambda do
130
+ foo.andand.hsibborf
131
+ end.should raise_error
132
+ end
133
+ end
File without changes
metadata CHANGED
@@ -1,83 +1,63 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: andand
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ prerelease:
5
+ version: 1.3.3
5
6
  platform: ruby
6
7
  authors:
7
- - Reginald Braithwaite
8
+ - Reg Braithwaite
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2008-07-13 00:00:00 -04:00
13
- default_executable:
13
+ date: 2012-03-28 00:00:00 Z
14
14
  dependencies: []
15
15
 
16
- description: adds guarded method invocation to Ruby
17
- email:
18
- - reg@braythwayt.com
16
+ description: " Maybe Monad in idiomatic Ruby."
17
+ email: reg@braythwayt.com
19
18
  executables: []
20
19
 
21
20
  extensions: []
22
21
 
23
22
  extra_rdoc_files:
24
23
  - History.txt
25
- - License.txt
26
- - Manifest.txt
27
- - README.txt
28
- - website/index.txt
24
+ - README.textile
29
25
  files:
30
26
  - History.txt
31
27
  - License.txt
32
- - Manifest.txt
33
- - README.txt
34
- - Rakefile
35
- - config/hoe.rb
36
- - config/requirements.rb
28
+ - README.textile
37
29
  - lib/andand.rb
38
30
  - lib/andand/version.rb
39
- - log/debug.log
40
- - script/destroy
41
- - script/generate
42
- - script/txt2html
43
- - setup.rb
44
- - tasks/deployment.rake
45
- - tasks/environment.rake
46
- - tasks/website.rake
47
- - test/test_andand.rb
31
+ - test/andand_spec.rb
48
32
  - test/test_helper.rb
49
- - website/index.html
50
- - website/index.txt
51
- - website/javascripts/rounded_corners_lite.inc.js
52
- - website/stylesheets/screen.css
53
- - website/template.rhtml
54
- has_rdoc: true
55
- homepage: http://andand.rubyforge.org
33
+ homepage: http://github.com/raganwald/andand/
34
+ licenses: []
35
+
56
36
  post_install_message:
57
37
  rdoc_options:
58
38
  - --main
59
- - README.txt
39
+ - README.textile
60
40
  require_paths:
61
41
  - lib
62
42
  required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
63
44
  requirements:
64
45
  - - ">="
65
46
  - !ruby/object:Gem::Version
66
47
  version: "0"
67
- version:
68
48
  required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
69
50
  requirements:
70
51
  - - ">="
71
52
  - !ruby/object:Gem::Version
72
53
  version: "0"
73
- version:
74
54
  requirements: []
75
55
 
76
- rubyforge_project: andand
77
- rubygems_version: 1.2.0
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.11
78
58
  signing_key:
79
- specification_version: 2
80
- summary: adds guarded method invocation to Ruby
59
+ specification_version: 3
60
+ summary: The Maybe Monad in idiomatic Ruby
81
61
  test_files:
82
- - test/test_andand.rb
62
+ - test/andand_spec.rb
83
63
  - test/test_helper.rb
@@ -1,24 +0,0 @@
1
- History.txt
2
- License.txt
3
- Manifest.txt
4
- README.txt
5
- Rakefile
6
- config/hoe.rb
7
- config/requirements.rb
8
- lib/andand.rb
9
- lib/andand/version.rb
10
- log/debug.log
11
- script/destroy
12
- script/generate
13
- script/txt2html
14
- setup.rb
15
- tasks/deployment.rake
16
- tasks/environment.rake
17
- tasks/website.rake
18
- test/test_andand.rb
19
- test/test_helper.rb
20
- website/index.html
21
- website/index.txt
22
- website/javascripts/rounded_corners_lite.inc.js
23
- website/stylesheets/screen.css
24
- website/template.rhtml
data/README.txt DELETED
@@ -1,17 +0,0 @@
1
- README
2
-
3
- andand is a method that provides _guarded method invocation_, analagous to the && operator in Ruby, and especially &&=.
4
-
5
- For example:
6
-
7
- Instead of phone && phone = phone.trim, Ruby lets you say phone &&= phone.trim. So with andand, instead of:
8
-
9
- phone && phone.call
10
-
11
- We can write:
12
-
13
- phone.andand.call (A poor man's attempt to write phone&&.call)
14
-
15
- See:
16
-
17
- http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html
data/Rakefile DELETED
@@ -1,4 +0,0 @@
1
- require 'config/requirements'
2
- require 'config/hoe' # setup Hoe + all gem configuration
3
-
4
- Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -1,70 +0,0 @@
1
- require 'andand/version'
2
-
3
- AUTHOR = 'Reginald Braithwaite' # can also be an array of Authors
4
- EMAIL = "reg@braythwayt.com"
5
- DESCRIPTION = "adds guarded method invocation to Ruby"
6
- GEM_NAME = 'andand' # what ppl will type to install your gem
7
- RUBYFORGE_PROJECT = 'andand' # The unix name for your project
8
- HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
- DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
-
11
- @config_file = "~/.rubyforge/user-config.yml"
12
- @config = nil
13
- RUBYFORGE_USERNAME = "raganwald"
14
- def rubyforge_username
15
- unless @config
16
- begin
17
- @config = YAML.load(File.read(File.expand_path(@config_file)))
18
- rescue
19
- puts <<-EOS
20
- ERROR: No rubyforge config file found: #{@config_file}
21
- Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
- - See http://newgem.rubyforge.org/rubyforge.html for more details
23
- EOS
24
- exit
25
- end
26
- end
27
- RUBYFORGE_USERNAME.replace @config["username"]
28
- end
29
-
30
-
31
- REV = nil
32
- # UNCOMMENT IF REQUIRED:
33
- # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
- VERS = Andand::VERSION::STRING + (REV ? ".#{REV}" : "")
35
- RDOC_OPTS = ['--quiet', '--title', 'andand documentation',
36
- "--opname", "index.html",
37
- "--line-numbers",
38
- "--main", "README",
39
- "--inline-source"]
40
-
41
- class Hoe
42
- def extra_deps
43
- @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
- @extra_deps
45
- end
46
- end
47
-
48
- # Generate all the Rake tasks
49
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
- hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
- p.developer(AUTHOR, EMAIL)
52
- p.description = DESCRIPTION
53
- p.summary = DESCRIPTION
54
- p.url = HOMEPATH
55
- p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
56
- p.test_globs = ["test/**/test_*.rb"]
57
- p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
58
-
59
- # == Optional
60
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
61
- #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
62
-
63
- #p.spec_extras = {} # A hash of extra values to set in the gemspec.
64
-
65
- end
66
-
67
- CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
68
- PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
69
- hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
70
- hoe.rsync_args = '-av --delete --ignore-errors'