viva 0.42.1337

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a01b0d14ea32240f6880c8f285b4ffc5d1ef16fc
4
+ data.tar.gz: af40b3a31343a9d7088d153ccdabb660f89a10d5
5
+ SHA512:
6
+ metadata.gz: 48c2b43fefcee481edae7284894ccf1a7efd2c1230df3347476bfb17994ceca0e0aebbfce159371fe5614ffb9b7b16f5cf963d6d6cc69743cd1bb8c80ca055a1
7
+ data.tar.gz: ecf62bfa07e1830d2341550931c24be0d78071013525efee13d374760b8a407746eb65af7faaa21c4df1840aa13dee388a18c48c26a1bc1893e8be094e75467a
@@ -0,0 +1,9 @@
1
+ ,---. ,---.-./`) ,---. .--. ____ .-'''-. .--. .--. ____ ,---. .--.
2
+ | \ / \ .-.')| \ | | .' __ `. / _ \| |_ | | .' __ `.| \ | |
3
+ | , \/ , / `-' \| , \ | |/ ' \ \ (`' )/`--'| _( )_ | |/ ' \ \ , \ | |
4
+ | |\_ /| |`-'`"`| |\_ \| ||___| / |(_ o _). |(_ o _) | ||___| / | |\_ \| |
5
+ | _( )_/ | |.---. | _( )_\ | _.-` | (_,_). '. | (_,_) \ | | _.-` | _( )_\ |
6
+ | (_ o _) | || | | (_ o _) |.' _ |.---. \ :| |/ \| |.' _ | (_ o _) |
7
+ | (_,_) | || | | (_,_)\ || _( )_ |\ `-' || ' /\ ` || _( )_ | (_,_)\ |
8
+ | | | || | | | | |\ (_ o _) / \ / | / \ |\ (_ o _) / | | |
9
+ '--' '--''---' '--' '--' '.(_,_).' `-...-' `---' `---` '.(_,_).''--' '--'
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION, AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
@@ -0,0 +1,135 @@
1
+ <p align="center">
2
+ <img src="http://i.imgur.com/OzCBizi.png" />
3
+ </p>
4
+
5
+ ## What's this?
6
+
7
+ **Viva** is a little C extension that exposes the **vi**rtual **va**riable API to Ruby land for science and the lulz.
8
+
9
+ ### What's that?
10
+
11
+ Contrary to popular misconception, many of Ruby's global variables are in fact not. Consider the case of `$~` (known to [`English`](http://ruby-doc.org/stdlib-2.3.0/libdoc/English/rdoc/English.html) speakers as `$LAST_MATCH_INFO`):
12
+
13
+ ```ruby
14
+ def foo
15
+ 'foo'.match /\w+/ and p $~
16
+ end
17
+
18
+ 'bar'.match /\w+/
19
+
20
+ p $~ # "bar" from the current scope
21
+ foo # "foo" from #foo's scope
22
+ p $~ # "bar" again
23
+ ```
24
+
25
+ It's evident that something tricksy is going on here; if this allegedly "global" variable doesn't maintain its value across scopes, whence does it come? I'll spare you the gory details: it's defined in terms of [a pair of C functions](https://git.io/vzwAN). Referring to `$~` will invoke `match_getter()` to obtain a value and *assigning to `$~`* will cause the provided `MatchData` instance to be used for `$~` and all of its descendants (of which there are [potentially thousands](https://git.io/vzwxR)).
26
+
27
+ #### Cool story, bro.
28
+
29
+ That's all well and good, yeah? "vvars" are scoped and pretty much do The Right Thing™. What's more, there's nothing stopping you from digging in and defining your own. But who wants to write C? [Bestest](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&cad=rja&uact=8&ved=0ahUKEwjqlvHc4L_KAhVF4iYKHRAZAxMQFggzMAM&url=http%3A%2F%2Fwww.merriam-webster.com%2Fdictionary%2Fbestest&usg=AFQjCNF5NASit_I0DsFXBB2l4baH0n7nFQ&bvm=bv.112454388,d.eWE) of all would be if we could define virtual getters and setters with Ruby callables, and so I've made that a thing.
30
+
31
+ ### La raison d'être
32
+
33
+ There's an old shell variable in Zsh—I know it's in Bash, it's probably in Zsh—called `RANDOM`, and the tin's not lying:
34
+
35
+ ```bash
36
+ $ echo $RANDOM $RANDOM $RANDOM
37
+ 8784 15644 1499
38
+ ```
39
+
40
+ [How neat is that?](http://i.imgur.com/SCRFkTZ.png) Let's give Ruby a `$RANDOM` that's neater still:
41
+
42
+ ```ruby
43
+ require 'viva'
44
+
45
+ max = 32768 # Be like Bash... for now.
46
+ getter = -> { rand max }
47
+ setter = -> spec { max = spec }
48
+
49
+ Viva.define :RANDOM, getter, setter
50
+
51
+ p Array.new(4) { $RANDOM }
52
+ # => [31791, 5045, 21337, 14134]
53
+
54
+ $RANDOM = 1..6
55
+
56
+ p Array.new(4) { $RANDOM }
57
+ # => [3, 5, 6, 2]
58
+ ```
59
+
60
+ Bash's offering looks positively static in comparison. ¡Viva la Rubylución!
61
+
62
+ ## Usage
63
+
64
+ `Viva.define` is the primary interface. It accepts exactly three arguments: a name for the virtual variable to be defined and two callables (instances of `Method` or `Proc`) to be used as the getter and setter thereof, respectively.
65
+
66
+ The name is coerced via `Kernel#String`; preceded with a `'$'`; and subjected to the rules for global identifiers, with the additional stipulation that numeric names may only be between `-9` and `0`, inclusively. This constraint is informed by the parser rather than enforced by the virtual variable API: `$-10` and below are outright syntax errors, and assignment to the positives is explicitly forbidden. We can *refer* to them just fine, but they're "super-virtual" and will, at present, simply ignore any efforts to tailor their behavior to one's wily whim. I consider the inability to use them to be a :bug: in **Viva**.
67
+
68
+ **TL;DR;SMAT**:
69
+
70
+ valid |invalid
71
+ :-----:|:-----:
72
+ `0` |`1`
73
+ `-4` |`-10`
74
+ `"$"` |`" "`
75
+ `"-_"` |`"_-"`
76
+ `Viva` |`nil`
77
+ `:*` |`:^`
78
+
79
+ The getter can be defined to take an argument, which will be the "actual" value of the requested variable. Likewise, the setter receives the value that was assigned. The point, of course, is that you're free to do with these values what you will.
80
+
81
+ Invoking `Viva.define` with a falsy value instead of a callable will undefine it and restore that operation to its regularly scheduled programming (bog-standard retrieval and assignment); regrettably, this holds true for variables which previously had some special meaning (pretty much everything in `English`). This is another :bug:.
82
+
83
+ `define_getter` and `define_setter` are convenience methods that take blocks and leave their better halves in place:
84
+
85
+ ```ruby
86
+ Viva.define_setter('$') do |pid|
87
+ p "Someone wanted our PID to be #{pid}."
88
+ end
89
+
90
+ %w[$ PID PROCESS_ID].each do |name|
91
+ Viva.define_getter(name) { 1337 }
92
+ end
93
+
94
+ $$ = 42 # => "Someone wanted our PID to be 42."
95
+ p $$ # => 1337
96
+ ```
97
+
98
+ Just for laughs, **Viva** provides a bit of syntactic sugalt for defining both accessors simultaneously using "two blocks":
99
+
100
+ ```ruby
101
+ Viva(:MoL).--> v { v * 2 } { |v| v * 7 }
102
+
103
+ $MoL = 3
104
+ p $MoL # => 42
105
+ ```
106
+
107
+ That you have to put the parameter in different places makes it look pretty silly, which I argue is a feature.
108
+
109
+ Finally, there's `undef_getter` and `undef_setter` which, while perfectly self-explanatory, go a long way toward revealing what's actually going on here:
110
+
111
+ ```ruby
112
+ def undef_getter var
113
+ Getters.delete "$#{var}"
114
+ end
115
+ ```
116
+
117
+ No effort has been made to conceal the internals from the user. This one's for you, [`FrozenCore`](https://youtu.be/SBdqCYKWISU?t=463).
118
+
119
+ ### FQAs
120
+
121
+ * Is this real life?
122
+
123
+ Likelier than not, but perhaps one of the solipsists has the right of it.
124
+
125
+ * Why is this happening?
126
+
127
+ Some men just want to watch the world-writable variables burn with the glory of a thousand suns. <sup><sup>If only I could be so grossly incandescent...</sup></sup>
128
+
129
+ * Should I use this?
130
+
131
+ I'm inclined to think [_why would've liked it](http://favstar.fm/users/_why/status/1231698950); your team are liable to [respond less positively](https://www.youtube.com/watch?v=H07zYvkNYL8). Horses for courses and the like.
132
+
133
+ ### Contributing
134
+
135
+ You are strongly but gently advised to reconsider. If you simply won't be deterred, may the fork be with you.
@@ -0,0 +1,14 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new :spec do |t|
4
+ t.test_files = ['spec/viva_spec.rb']
5
+ end
6
+
7
+ task :default do
8
+ IO.new(0).puts <<JOKE
9
+
10
+ rm: it is dangerous to operate recursively on '/'
11
+ rm: use --no-preserve-root to override this failsafe
12
+
13
+ JOKE
14
+ end
@@ -0,0 +1,8 @@
1
+ require 'viva'
2
+
3
+ c = -1
4
+ Viva(:COUNTER).--> { c += 1 } { |v| c = v }
5
+
6
+ p Array.new(3) { $COUNTER } # => [0, 1, 2]
7
+ $COUNTER = 10
8
+ p Array.new(3) { $COUNTER } # => [11, 12, 13]
@@ -0,0 +1,6 @@
1
+ require 'viva'
2
+
3
+ Viva(:MoL).--> v { v * 2 } { |v| v * 7 }
4
+
5
+ $MoL = 3
6
+ p $MoL # => 42
@@ -0,0 +1,12 @@
1
+ require 'viva'
2
+
3
+ Viva.define_setter('$') do |pid|
4
+ p "Someone wanted our PID to be #{pid}."
5
+ end
6
+
7
+ %w[$ PID PROCESS_ID].each do |name|
8
+ Viva.define_getter(name) { 1337 }
9
+ end
10
+
11
+ $$ = 42 # => "Someone wanted our PID to be 42."
12
+ p $$ # => 1337
@@ -0,0 +1,11 @@
1
+ require 'viva'
2
+
3
+ max = 32768
4
+ getter = -> { rand max }
5
+ setter = -> spec { max = spec }
6
+
7
+ Viva.define :RANDOM, getter, setter
8
+
9
+ p Array.new(4) { $RANDOM }
10
+ $RANDOM = 1..6
11
+ p Array.new(4) { $RANDOM }
@@ -0,0 +1,60 @@
1
+ #include <ruby.h>
2
+
3
+ static VALUE mViva, getters, setters;
4
+ static ID id_call;
5
+
6
+ /* `struct rb_global_variable` doesn't get exported from variable.c, but this
7
+ * should suffice to have everything in the right place when we go looking. */
8
+ struct gvar { int _, __; void *val; };
9
+
10
+ static VALUE
11
+ viva_getter(ID id, void *data)
12
+ {
13
+ VALUE getter = rb_hash_aref(getters, rb_id2str(id));
14
+ VALUE val = data ? data : Qnil; /* the old value, if any */
15
+
16
+ if (RTEST(getter))
17
+ return rb_funcall(getter, id_call, abs(rb_proc_arity(getter)), val);
18
+ return val;
19
+ }
20
+
21
+ static void
22
+ viva_setter(VALUE val, ID id, void *_, struct gvar *var)
23
+ {
24
+ VALUE setter = rb_hash_aref(setters, rb_id2str(id));
25
+
26
+ var->val = RTEST(setter) ? rb_funcall(setter, id_call, 1, val) : val;
27
+ }
28
+
29
+ #define error_msg "`%s`is not allowed as a virtual variable name"
30
+
31
+ static VALUE
32
+ viva_define(VALUE self, VALUE var, VALUE getter, VALUE setter)
33
+ {
34
+ char *str;
35
+ var = rb_String(var);
36
+ rb_str_update(var, 0, 0, rb_str_new("$", 1));
37
+ str = StringValueCStr(var);
38
+
39
+ /* Reject invalid global identifiers and fully digital ones other than $0,
40
+ * since the former would be syntax errors and the latter inaccessible. */
41
+ if (!rb_is_global_id(rb_intern(str)) || atoi(str + 1) > 0)
42
+ rb_raise(rb_eNameError, error_msg, str);
43
+
44
+ rb_hash_aset(getters, var, getter);
45
+ rb_hash_aset(setters, var, setter);
46
+ rb_define_virtual_variable(str, viva_getter, viva_setter);
47
+
48
+ return rb_str_intern(var);
49
+ }
50
+
51
+ void
52
+ Init_core()
53
+ {
54
+ mViva = rb_define_module("Viva");
55
+ id_call = rb_intern("call");
56
+
57
+ rb_define_const(mViva, "Getters", getters = rb_hash_new());
58
+ rb_define_const(mViva, "Setters", setters = rb_hash_new());
59
+ rb_define_singleton_method(mViva, "define", viva_define, 3);
60
+ }
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile 'viva/core'
@@ -0,0 +1,31 @@
1
+ require 'viva/core'
2
+
3
+ module Viva
4
+ module_function
5
+
6
+ def define_getter var
7
+ define var, proc, Setters["$#{var}"]
8
+ end
9
+
10
+ def define_setter var
11
+ define var, Getters["$#{var}"], proc
12
+ end
13
+
14
+ def undef_getter var
15
+ Getters.delete "$#{var}"
16
+ end
17
+
18
+ def undef_setter var
19
+ Setters.delete "$#{var}"
20
+ end
21
+
22
+ def - getter, &setter
23
+ define @var, getter, setter
24
+ end
25
+ end
26
+
27
+ module Kernel
28
+ module_function def Viva var
29
+ Viva.tap { |v| v.instance_variable_set :@var, var }
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Viva
2
+ VERSION = '0.42.1337'
3
+ end
@@ -0,0 +1,50 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/pride'
3
+ require 'viva'
4
+
5
+ describe Viva do
6
+ describe '.define' do
7
+ describe 'when given a valid virtual variable name' do
8
+ it 'should return its name as a globalized Symbol' do
9
+ [0, -4, '$', '-_', Viva, :*].each do |name|
10
+ expected = :"$#{name}"
11
+ Viva.define(name, nil, nil).must_equal expected
12
+ end
13
+ end
14
+ end
15
+
16
+ describe 'when given an invalid virtual variable name' do
17
+ it 'should complain and refrain (inaccessible < useless)' do
18
+ [1, -10, ' ', '_-', nil, :^,].each do |name|
19
+ -> { Viva.define name, nil, nil }.must_raise NameError
20
+ end
21
+ end
22
+ end
23
+
24
+ # NOTE: These next two specs are essentially identical.
25
+ # How does one verify that nonexistent code didn't run?
26
+
27
+ it 'should be able to create a getter with no setter' do
28
+ Viva.define :a, -> actual { actual * 2 }, nil
29
+ $a = 21
30
+ $a.must_equal 42
31
+ end
32
+
33
+ it 'should be able to create a setter with no getter' do
34
+ Viva.define :b, nil, -> actual { actual * 2 }
35
+ $b = 21
36
+ $b.must_equal 42
37
+ end
38
+ end
39
+
40
+ # This more or less runs the thing through its paces, so let's stop here.
41
+
42
+ it "should be able to emulate GCC's __COUNTER__ (with bonus reset)" do
43
+ c = -1
44
+ Viva(:COUNTER).--> { c += 1 } { |v| c = v }
45
+
46
+ Array.new(3) { $COUNTER }.must_equal [0, 1, 2]
47
+ $COUNTER = 10
48
+ Array.new(3) { $COUNTER }.must_equal [11, 12, 13]
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ $:.unshift File.expand_path '../lib', __FILE__
2
+ require 'viva/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'viva'
6
+ s.version = Viva::VERSION
7
+ s.author = 'D.E. Akers'
8
+ s.email = '0x0dea@gmail.com'
9
+
10
+ s.summary = 'Viva exposes the virtual variable API to Ruby land.'
11
+ s.homepage = 'https://github.com/0x0dea/viva'
12
+ s.license = 'WTFPL'
13
+
14
+ s.files = `git ls-files`.split
15
+ s.extensions = %w[ext/viva/extconf.rb Rakefile]
16
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: viva
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.42.1337
5
+ platform: ruby
6
+ authors:
7
+ - D.E. Akers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-25 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: 0x0dea@gmail.com
15
+ executables: []
16
+ extensions:
17
+ - ext/viva/extconf.rb
18
+ - Rakefile
19
+ extra_rdoc_files: []
20
+ files:
21
+ - CODE_OF_CONDUCT
22
+ - LICENSE
23
+ - README.md
24
+ - Rakefile
25
+ - examples/counter.rb
26
+ - examples/mol.rb
27
+ - examples/pid.rb
28
+ - examples/random.rb
29
+ - ext/viva/core.c
30
+ - ext/viva/extconf.rb
31
+ - lib/viva.rb
32
+ - lib/viva/version.rb
33
+ - spec/viva_spec.rb
34
+ - viva.gemspec
35
+ homepage: https://github.com/0x0dea/viva
36
+ licenses:
37
+ - WTFPL
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.5.1
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Viva exposes the virtual variable API to Ruby land.
59
+ test_files: []