ampex 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +19 -7
- data/lib/ampex.rb +47 -18
- 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
|
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
|
-
|
35
|
+
You can use this in any place a block is expected, for example to create a lambda:
|
31
36
|
|
32
|
-
|
33
|
-
|
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
|
-
|
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
|
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
|
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
|
-
#
|
53
|
-
#
|
54
|
-
#
|
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
|
-
#
|
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
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
97
|
+
else
|
98
|
+
todo = method(stashed_method_name)
|
99
|
+
end
|
100
|
+
end
|
71
101
|
|
72
|
-
|
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:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 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-
|
18
|
+
date: 2010-12-04 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|