Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Commit version 0.1 of &X

  • Loading branch information...
commit 5a3591903ff435dfe3b64359f29409d049009962 0 parents
@ConradIrwin ConradIrwin authored
Showing with 180 additions and 0 deletions.
  1. +19 −0 LICENSE.MIT
  2. +59 −0 README.markdown
  3. +12 −0 ampex.gemspec
  4. +90 −0 lib/ampex.rb
19 LICENSE.MIT
@@ -0,0 +1,19 @@
+Copyright (c) 2010 Conrad Irwin <conrad.irwin@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
59 README.markdown
@@ -0,0 +1,59 @@
+The Ampex (&X) library provides a Metavariable X that can be used in conjunction with the unary ampersand to create anonymous blocks in a slightly more readable way than the default. It was inspired by the clever `Symbol#to_proc` method which handles the most common case very elegantly, and discussion with Sam Stokes who created an earlier version.
+
+At its simplest, &X can be used as a drop-in replacement for `Symbol#to_proc`:
+
+ [1,2,3].map &X.to_s
+ # => ["1", "2", "3"]
+
+However the real strength in the library comes from allowing you to call methods:
+
+ [1,"2",3].select &X.is_a?(String)
+ # => ["2"]
+
+And, as everything in ruby is a method, create readable expressions without the noise of a one-argument block:
+
+ [{1 => 2}, {1 => 3}].map &X[1]
+ # => [2, 3]
+
+ [1,2,3].map &-X
+ # => [-1, -2, -3]
+
+ ["a", "b", "c"].map &(X * 2)
+ # => ["aa", "bb", "cc"]
+
+As an added bonus, the effect is transitive — you can chain method calls:
+
+ [1, 2, 3].map &X.to_f.to_s
+ # => ["1.0", "2.0", "3.0"]
+
+There are two things to watch out for:
+
+Firstly, &X can only appear on the left:
+
+ [1, 2, 3].map &(X + 1)
+ # => [2, 3, 4]
+
+ [1, 2, 3].map &(1 + X) # WRONG
+ # => TypeError, "coerce must return [x, y]"
+
+ [[1],[2]].map &X.concat([2])
+ # => [[1, 2], [2, 2]]
+
+ [[1],[2]].map &[2].concat(X) # WRONG
+ # => TypeError, "Metavariable#to_ary should return Array"
+
+Secondly, the arguments or operands will only be evaluated once, and not every time:
+
+ i = 0
+ [1, 2].map &(X + (i += 1)) # WRONG
+ # => [2, 3]
+
+ i = 0
+ [1, 2].map{ |x| x + (i += 1) }
+ # => [2, 4]
+
+
+For bug-fixes or enhancements, please contact the author: Conrad Irwin <conrad.irwin@gmail.com>
+For an up-to-date version, try http://github.com/rapportive-oss/ampex
+
+This library is copyrighted under the MIT license, see LICENSE.MIT for details.
12 ampex.gemspec
@@ -0,0 +1,12 @@
+Gem::Specification.new do |s|
+ s.name = "ampex"
+ s.version = "0.1"
+ s.platform = Gem::Platform::RUBY
+ s.author = "Conrad Irwin"
+ s.email = "conrad.irwin@gmail.com"
+ s.homepage = "http://github.com/rapportive-oss/ampex"
+ s.summary = "Provides a meta-variable X which can be used to create procs more prettily"
+ s.description = "Why would you want to write { |x| x['one'] } when you can write &X['one'], why indeed."
+ s.files = ["lib/ampex.rb", "README.markdown", "LICENSE.MIT"]
+ s.require_path = "lib"
+end
90 lib/ampex.rb
@@ -0,0 +1,90 @@
+require 'blankslate'
+
+# The Ampex library provides a metavariable X that can be used in conjunction
+# with the unary ampersand to create anonymous blocks in a slightly more
+# readable way than the default. It was inspired by the clever `Symbol#to_proc`
+# method which handles the most common case very elegantly, and discussion with
+# Sam Stokes who implemented an earlier version of the idea.
+#
+# At its simplest, &X can be used as a drop-in replacement for
+# `Symbol#to_proc`:
+#
+# [1,2,3].map &X.to_s
+# # => ["1", "2", "3"]
+#
+# However the real strength in the library comes from allowing you to call
+# methods:
+#
+# [1,"2",3].select &X.is_a?(String)
+# # => ["2"]
+#
+# And, as everything in ruby is a method, create readable expressions without
+# the noise of a one-argument block:
+#
+# [{1 => 2}, {1 => 3}].map &X[1]
+# # => [2, 3]
+#
+# [1,2,3].map &-X
+# # => [-1, -2, -3]
+#
+# ["a", "b", "c"].map &(X * 2)
+# # => ["aa", "bb", "cc"]
+#
+# As an added bonus, the effect is transitive — you can chain method calls:
+#
+# [1, 2, 3].map &X.to_f.to_s
+# # => ["1.0", "2.0", "3.0"]
+#
+# There are two things to watch out for:
+#
+# Firstly, &X can only appear on the left:
+#
+# [1, 2, 3].map &(X + 1)
+# # => [2, 3, 4]
+#
+# [1, 2, 3].map &(1 + X) # WRONG
+# # => TypeError, "coerce must return [x, y]"
+#
+# [[1],[2]].map &X.concat([2])
+# # => [[1, 2], [2, 2]]
+#
+# [[1],[2]].map &[2].concat(X) # WRONG
+# # => TypeError, "Metavariable#to_ary should return Array"
+#
+# Secondly, the arguments or operands will only be evaluated once, and not
+# every time:
+#
+# i = 0 [1, 2].map &(X + (i += 1)) # WRONG
+# # => [2, 3]
+#
+# i = 0 [1, 2].map{ |x| x + (i += 1) }
+# # => [2, 4]
+#
+# For bug-fixes or enhancements, please contact the author:
+# Conrad Irwin <conrad.irwin@gmail.com>
+#
+# This library is copyrighted under the MIT license, see LICENSE.MIT.
+
+class Metavariable < BlankSlate
+ def initialize(parent=nil, &block)
+ @block = block
+ @parent = parent
+ end
+
+ def method_missing(name, *args, &block)
+ Metavariable.new(self) { |x| x.send(name, *args, &block) }
+ end
+
+ def to_proc
+ lambda do |x|
+ if @block
+ x = @parent.to_proc.call(x) if @parent
+ @block.call x
+ else
+ x
+ end
+ end
+ end
+end
+
+X = Metavariable.new
Please sign in to comment.
Something went wrong with that request. Please try again.