ampex 1.1.1 → 1.1.2

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 +19 -7
  2. data/lib/ampex.rb +47 -18
  3. metadata +4 -4
data/README.markdown CHANGED
@@ -13,7 +13,12 @@ However the real strength in the library comes from allowing you to call methods
13
13
  [1,"2",3].select &X.is_a?(String)
14
14
  # => ["2"]
15
15
 
16
- And, as everything in ruby is a method, create readable expressions without the noise of a one-argument block:
16
+ And to chain method calls:
17
+
18
+ [1, 2, 3].map &X.to_f.to_s
19
+ # => ["1.0", "2.0", "3.0"]
20
+
21
+ As everything in Ruby is a method call, you can create readable expressions without the noise of a one-argument block:
17
22
 
18
23
  [{1 => 2}, {1 => 3}].map &X[1]
19
24
  # => [2, 3]
@@ -27,10 +32,11 @@ And, as everything in ruby is a method, create readable expressions without the
27
32
  [{}].each &X[1] = 2
28
33
  # => [{1 => 2}]
29
34
 
30
- As an added bonus, the effect is transitive you can chain method calls:
35
+ You can use this in any place a block is expected, for example to create a lambda:
31
36
 
32
- [1, 2, 3].map &X.to_f.to_s
33
- # => ["1.0", "2.0", "3.0"]
37
+ normalizer = lambda &X.to_s.downcase
38
+ normalizer.call :HelloWorld
39
+ # => "helloworld"
34
40
 
35
41
  Gotchas
36
42
  -------
@@ -64,14 +70,20 @@ Secondly, other arguments or operands will only be evaluated once, and not every
64
70
  Bugs
65
71
  ----
66
72
 
67
- If you create an assigning callable (e.g. `X[a] = b`, `X.a = b` ) without an immediate preceding `&`, then `b.class#to_proc` will return the assigning callable the first time, and only the first time, you call it. If you want to get access to an assigning callable that you've defined using `&X`, you must do: `lambda &X[a] = b` instead.
68
-
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.
69
74
 
70
75
  Epilogue
71
76
  --------
72
77
 
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.
79
+
73
80
  For bug-fixes or enhancements, please contact the author: Conrad Irwin <conrad.irwin@gmail.com>
74
81
 
75
- For an up-to-date version, try http://github.com/rapportive-oss/ampex
82
+ For an up-to-date version, try <https://github.com/rapportive-oss/ampex>
76
83
 
77
84
  This library is copyrighted under the MIT license, see LICENSE.MIT for details.
85
+
86
+ See also
87
+ --------
88
+
89
+ * <https://github.com/danielribeiro/RubyUnderscore> — which uses an underscore in place of `&X` and works by rewriting the syntax tree.
data/lib/ampex.rb CHANGED
@@ -28,7 +28,7 @@ class Metavariable < BlankSlate
28
28
  #
29
29
  def method_missing(name, *args, &block)
30
30
  mv = Metavariable.new { |x| @to_proc.call(x).send(name, *args, &block) }
31
- Metavariable.temporarily_monkeypatch(args.last.class, mv) if name.to_s =~ /[^!=]=$/
31
+ Metavariable.temporarily_monkeypatch(args.last, :to_proc) { mv.to_proc } if name.to_s =~ /[^!=<>]=$/
32
32
  mv
33
33
  end
34
34
 
@@ -49,28 +49,57 @@ class Metavariable < BlankSlate
49
49
  # :two.to_proc _/ and un-patch here
50
50
  # ary.map &_
51
51
  #
52
- # There is a risk if someone uses an amp-less X, and assigns something with to_proc
53
- # (most likely a symbol), and then uses .map(&:to_i), as &:to_i will return the
54
- # behaviour of their metavariable.
52
+ # We go to some lengths to ensure that, providing the & and the X are adjacent,
53
+ # it's not possible to get different behaviour in the rest of the program; despite
54
+ # the temporary mutation of potentially global state.
55
55
  #
56
- # There are other things that might notice us doing this, if people are listening
57
- # on various method_added hooks, or have overridden class_eval, etc. But I'm not
58
- # too worried.
56
+ # We can't really do anything if the & has been split from the X, consider:
59
57
  #
60
- def self.temporarily_monkeypatch(klass, mv)
61
- klass.send :class_variable_set, :'@@metavariable', mv
62
- klass.class_eval do
58
+ # assigner = (X[0] = :to_i)
59
+ # assigner == :to_i
60
+ # # => true
61
+ # [1,2,3].map(&:to_i)
62
+ # # => NoMethodError: undefined method `[]=' for 1:Fixnum
63
+ #
64
+ # Just strongly encourage use of:
65
+ # assigner = lambda &X = :to_i
66
+ # assigner == :to_i
67
+ # # => false
68
+ # [1,2,3].map(&:to_i)
69
+ # # => [1,2,3]
70
+ #
71
+ def self.temporarily_monkeypatch(instance, method_name, &block)
72
+
73
+ Thread.exclusive do
74
+ @monkey_patch_count = @monkey_patch_count ? @monkey_patch_count + 1 : 0
75
+ stashed_method_name = :"#{method_name}_without_metavariable_#{@monkey_patch_count}"
76
+ thread = Thread.current
77
+
78
+ # Try to get a handle on the object's singleton class, but fall back to using
79
+ # its actual class where that is not possible (i.e. for numbers and symbols)
80
+ klass = (class << instance; self; end) rescue instance.class
81
+ klass.class_eval do
82
+
83
+ alias_method(stashed_method_name, method_name) rescue nil
84
+ define_method(method_name) do
85
+
86
+ todo = block
87
+
88
+ Thread.exclusive do
89
+ if self.equal?(instance) && thread.equal?(Thread.current)
63
90
 
64
- alias_method(:to_proc_without_metavariable, :to_proc) rescue nil
65
- def to_proc
66
- self.class.class_eval do
91
+ klass.class_eval do
92
+ undef_method(method_name)
93
+ alias_method(method_name, stashed_method_name) rescue nil
94
+ undef_method(stashed_method_name) rescue nil
95
+ end
67
96
 
68
- undef to_proc
69
- alias_method(:to_proc, :to_proc_without_metavariable) rescue nil
70
- undef to_proc_without_metavariable rescue nil
97
+ else
98
+ todo = method(stashed_method_name)
99
+ end
100
+ end
71
101
 
72
- # Remove the metavariable from the class and return its proc
73
- remove_class_variable(:'@@metavariable').to_proc
102
+ todo.call
74
103
  end
75
104
  end
76
105
  end
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: 17
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 1
9
- - 1
10
- version: 1.1.1
9
+ - 2
10
+ version: 1.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Conrad Irwin
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-02 00:00:00 -08:00
18
+ date: 2010-12-04 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency