ampex 1.2.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.markdown +13 -10
  2. data/lib/ampex.rb +2 -80
  3. metadata +6 -8
@@ -1,4 +1,4 @@
1
- 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.
1
+ 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 about creating lazy enumerators in ruby.
2
2
 
3
3
  Usage
4
4
  -----
@@ -29,9 +29,6 @@ As everything in Ruby is a method call, you can create readable expressions with
29
29
  ["a", "b", "c"].map &(X * 2)
30
30
  # => ["aa", "bb", "cc"]
31
31
 
32
- [{}].each &X[1] = 2
33
- # => [{1 => 2}]
34
-
35
32
  You can use this in any place a block is expected, for example to create a lambda:
36
33
 
37
34
  normalizer = lambda &X.to_s.downcase
@@ -67,15 +64,10 @@ Secondly, other arguments or operands will only be evaluated once, and not every
67
64
  [1, 2].map{ |x| x + (i += 1) }
68
65
  # => [2, 4]
69
66
 
70
- Bugs
71
- ----
72
-
73
- In normal usage there are no known bugs. That said, if you accidentally miss the `&` from in front of the `X`, in an expression that ends in an assignment (e.g. `X.formatter = :inspect`); then the `#to_proc` method of the object assigned will respond with the expression generated by that `X` the next time you call it from anywhere else in the same thread.
74
-
75
67
  Epilogue
76
68
  --------
77
69
 
78
- `&X` has been tested on MRI ruby 1.8.6, 1.8.7 and 1.9.2 and jruby 1.5.3. It is thread-safe.
70
+ `&X` has been tested on MRI ruby 1.8.6, 1.8.7, 1.9.2, 1.9.3, jruby, and rubinius.
79
71
 
80
72
  For bug-fixes or enhancements, please contact the author: Conrad Irwin <conrad.irwin@gmail.com>
81
73
 
@@ -83,7 +75,18 @@ For an up-to-date version, try <https://github.com/rapportive-oss/ampex>
83
75
 
84
76
  This library is copyrighted under the MIT license, see LICENSE.MIT for details.
85
77
 
78
+
79
+ Backwards compatibility breakages
80
+ ---------------------------------
81
+
82
+ Between version 1.2.1 and version 2.0.0, the support for assignment operations was removed from
83
+ ampex. These had a very non-obvious implementation, and it was impossible to support
84
+ assigning of falsey values; and did not work on rubinius.
85
+
86
86
  See also
87
87
  --------
88
88
 
89
+ * <https://cirw.in/blog/ampex> — a blog post that describes the ideas.
89
90
  * <https://github.com/danielribeiro/RubyUnderscore> — which uses an underscore in place of `&X` and works by rewriting the syntax tree.
91
+ * <https://gist.github.com/1224361> — a patch for Rubinius that enables the underscore in a similar way.
92
+ * <http://blog.railsware.com/2012/03/13/ruby-2-0-enumerablelazy/> — The upcoming lazy enumerable support for Ruby 2.0.
@@ -14,10 +14,6 @@ else
14
14
  end
15
15
 
16
16
  class Metavariable < superclass
17
- # Take a local copy of these as constant lookup is destroyed by BasicObject.
18
- Metavariable = self
19
- Thread = ::Thread
20
-
21
17
  # When you pass an argument with & in ruby, you're actually calling #to_proc
22
18
  # on the object. So it's Symbol#to_proc that makes the &:to_s trick work,
23
19
  # and Metavariable#to_proc that makes &X work.
@@ -39,9 +35,8 @@ class Metavariable < superclass
39
35
  # }
40
36
  #
41
37
  def method_missing(name, *args, &block)
42
- mv = Metavariable.new { |x| @to_proc.call(x).__send__(name, *args, &block) }
43
- Metavariable.temporarily_monkeypatch(args.last, :to_proc) { mv.to_proc } if name.to_s =~ /[^!=<>]=$/
44
- mv
38
+ raise ::NotImplementedError, "(&X = 'foo') is unsupported in ampex > 2.0.0" if name.to_s =~ /[^!=<>]=$/
39
+ ::Metavariable.new { |x| @to_proc.call(x).__send__(name, *args, &block) }
45
40
  end
46
41
 
47
42
  # BlankSlate and BasicObject have different sets of methods that you don't want.
@@ -49,79 +44,6 @@ class Metavariable < superclass
49
44
  instance_methods.each do |method|
50
45
  undef_method method unless %w(method_missing to_proc __send__ __id__).include? method.to_s
51
46
  end
52
-
53
- private
54
-
55
- # In order to support assignment via &X (expressions of the form &X['one'] = 2),
56
- # we need to add 2.to_proc (because assignment in ruby always returns the operand)
57
- #
58
- # Luckily, we only need to do this for a very short time.
59
- #
60
- # When given an expression such as:
61
- #
62
- # ary.map(&X[args(a)] = :two)
63
- #
64
- # the order of execution is:
65
- # args(a)
66
- # X[_] = :two \_ need to patch here
67
- # :two.to_proc _/ and un-patch here
68
- # ary.map &_
69
- #
70
- # We go to some lengths to ensure that, providing the & and the X are adjacent,
71
- # it's not possible to get different behaviour in the rest of the program; despite
72
- # the temporary mutation of potentially global state.
73
- #
74
- # We can't really do anything if the & has been split from the X, consider:
75
- #
76
- # assigner = (X[0] = :to_i)
77
- # assigner == :to_i
78
- # # => true
79
- # [1,2,3].map(&:to_i)
80
- # # => NoMethodError: undefined method `[]=' for 1:Fixnum
81
- #
82
- # Just strongly encourage use of:
83
- # assigner = lambda &X = :to_i
84
- # assigner == :to_i
85
- # # => false
86
- # [1,2,3].map(&:to_i)
87
- # # => [1,2,3]
88
- #
89
- def self.temporarily_monkeypatch(instance, method_name, &block)
90
-
91
- Thread.exclusive do
92
- @monkey_patch_count = @monkey_patch_count ? @monkey_patch_count + 1 : 0
93
- stashed_method_name = :"#{method_name}_without_metavariable_#{@monkey_patch_count}"
94
- thread = Thread.current
95
-
96
- # Try to get a handle on the object's singleton class, but fall back to using
97
- # its actual class where that is not possible (i.e. for numbers and symbols)
98
- klass = (class << instance; self; end) rescue instance.class
99
- klass.class_eval do
100
-
101
- alias_method(stashed_method_name, method_name) rescue nil
102
- define_method(method_name) do
103
-
104
- todo = block
105
-
106
- Thread.exclusive do
107
- if self.equal?(instance) && thread.equal?(Thread.current)
108
-
109
- klass.class_eval do
110
- undef_method(method_name)
111
- alias_method(method_name, stashed_method_name) rescue nil
112
- undef_method(stashed_method_name) rescue nil
113
- end
114
-
115
- else
116
- todo = method(stashed_method_name)
117
- end
118
- end
119
-
120
- todo.call
121
- end
122
- end
123
- end
124
- end
125
47
  end
126
48
 
127
49
  X = Metavariable.new
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ampex
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
- - 1
8
7
  - 2
9
- - 1
10
- version: 1.2.1
8
+ - 0
9
+ - 0
10
+ version: 2.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Conrad Irwin
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-07-23 00:00:00 -07:00
19
- default_executable:
18
+ date: 2012-05-20 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: blankslate
@@ -44,7 +43,6 @@ files:
44
43
  - lib/ampex.rb
45
44
  - README.markdown
46
45
  - LICENSE.MIT
47
- has_rdoc: true
48
46
  homepage: http://github.com/rapportive-oss/ampex
49
47
  licenses: []
50
48
 
@@ -74,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
72
  requirements: []
75
73
 
76
74
  rubyforge_project:
77
- rubygems_version: 1.6.2
75
+ rubygems_version: 1.8.21
78
76
  signing_key:
79
77
  specification_version: 3
80
78
  summary: Provides a meta-variable X which can be used to create procs more prettily