gvars 0.1.0 → 0.9.0
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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +23 -29
- data/Rakefile +19 -2
- data/ext/gvars/extconf.rb +5 -0
- data/ext/gvars/gvars.c +63 -0
- data/ext/gvars/gvars.c-old +147 -0
- data/lib/gvars/version.rb +2 -2
- data/lib/gvars.rb +10 -3
- data/sig/gvars.rbs +15 -2
- metadata +13 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1728504fbc5ee4dcf6e72f18a5f0aff56fa3933f97776d9e57bca20cc8301b45
|
|
4
|
+
data.tar.gz: 45fa2513e7c7fc2438dabd33d91505899e7154c8ec4d91fb03008b4f22dbbc9a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0daa5d2870632bd24be477d7e561383bf89ad66ec6efe844717ef2d1e37c9c8219c22bcc9ab644e8c291e408a41c8a5559a684ecf4f70f178a2f5966963f4261
|
|
7
|
+
data.tar.gz: 2feac652e6098336616d4dd9f9c893add9ef8745884214297392381bf1182edad60839d8229d53e6fe97d1a2abc3c9a107ce61075ce908f25e7ca037b88fd0b6
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -1,39 +1,33 @@
|
|
|
1
|
-
#
|
|
1
|
+
# GVars
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Adds in missing utilities relating to global variables in Ruby.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Ever been bothered how there's `instance_variable_get`, `binding.local_variable_get`, `class_variable_get`, even `const_get`, but no `global_variable_get`? Ever resorted to `eval("$#{name} = value")` to assign a global variable? Look no further!
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Features
|
|
8
|
+
```ruby
|
|
9
|
+
$foo = 34
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
# Dynamically lookup globals
|
|
12
|
+
puts GVars.get(:$foo) #=> 34
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
# Dynamically assign globals!
|
|
15
|
+
GVars.set(:$foo, 99)
|
|
16
|
+
puts $foo #=> 99
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
18
|
+
# How about dynamically `alias`ing globals?
|
|
19
|
+
GBars.alias :$bar, :$foo
|
|
20
|
+
$bar = 12
|
|
21
|
+
puts $foo #=> 12
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
# You can also mixin `GVars` to get the methods that should be
|
|
24
|
+
# defined on Kernel:
|
|
25
|
+
include GVars
|
|
26
|
+
puts global_variable_get(:$bar) #=> 12
|
|
27
|
+
puts global_variable_set(:$bar, 19) #=> 19
|
|
21
28
|
```
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
TODO: Write usage instructions here
|
|
26
|
-
|
|
27
|
-
## Development
|
|
28
|
-
|
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
30
|
-
|
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
32
|
-
|
|
33
|
-
## Contributing
|
|
34
|
-
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/gvars.
|
|
36
|
-
|
|
37
|
-
## License
|
|
30
|
+
Up next: virtual variables, and collection methods!
|
|
38
31
|
|
|
39
|
-
|
|
32
|
+
## Known problems
|
|
33
|
+
Unfortunately, Ruby's C-level `rb_gv_get` / `rb_gv_set` methods only let you manipulate ASCII identifiers... A fix _may_ be possible, but it'll have to resort to the `eval` hack.
|
data/Rakefile
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
require 'rake/extensiontask'
|
|
5
|
+
require 'minitest/test_task'
|
|
6
|
+
|
|
7
|
+
task default: [:compile]
|
|
8
|
+
|
|
9
|
+
Rake::ExtensionTask.new('gvars') do |ext|
|
|
10
|
+
ext.lib_dir = 'lib/gvars'
|
|
11
|
+
end
|
|
5
12
|
|
|
6
13
|
Minitest::TestTask.create
|
|
7
14
|
|
|
8
15
|
task default: :test
|
|
16
|
+
|
|
17
|
+
desc 'clean compiled files'
|
|
18
|
+
task :clean do
|
|
19
|
+
require 'fileutils'
|
|
20
|
+
FileUtils.rm_rf 'ext/gvars/Makefile'
|
|
21
|
+
FileUtils.rm_rf 'ext/gvars/gvars.so'
|
|
22
|
+
FileUtils.rm_rf 'ext/gvars/gvars.bundle'
|
|
23
|
+
FileUtils.rm_rf 'lib/gvars/gvars.so'
|
|
24
|
+
FileUtils.rm_rf 'lib/gvars/gvars.bundle'
|
|
25
|
+
end
|
data/ext/gvars/gvars.c
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#include "ruby.h"
|
|
2
|
+
|
|
3
|
+
// Converts `name` to a global variable name, ensures it's valid, and returns it.
|
|
4
|
+
//
|
|
5
|
+
// for checking, it makes that `name` starts with `$`. This isn't really required, as ruby supports
|
|
6
|
+
// globals that don't start with `$` (but doesn't expose any methods to interact with them)
|
|
7
|
+
static char *get_global_name(VALUE *name) {
|
|
8
|
+
// If `name` is a symbol, get its backing string
|
|
9
|
+
if (RB_SYMBOL_P(*name)) {
|
|
10
|
+
*name = rb_sym2str(*name);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
char *namestr = StringValueCStr(*name);
|
|
14
|
+
|
|
15
|
+
// Ensure it starts with a dollar sign
|
|
16
|
+
if (namestr[0] != '$') {
|
|
17
|
+
rb_raise(rb_eNameError, "'%s' is not allowed as a global variable name", namestr);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return namestr;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static VALUE
|
|
24
|
+
gvars_f_global_variable_get(VALUE self, VALUE name)
|
|
25
|
+
{
|
|
26
|
+
return rb_gv_get(get_global_name(&name));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static VALUE
|
|
30
|
+
gvars_f_global_variable_set(VALUE self, VALUE name, VALUE value)
|
|
31
|
+
{
|
|
32
|
+
return rb_gv_set(get_global_name(&name), value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static VALUE
|
|
36
|
+
gvars_f_global_variables(VALUE self)
|
|
37
|
+
{
|
|
38
|
+
return rb_f_global_variables();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static VALUE
|
|
42
|
+
gvars_f_alias_global_variable(VALUE self, VALUE new, VALUE old)
|
|
43
|
+
{
|
|
44
|
+
ID newid = rb_intern(get_global_name(&new));
|
|
45
|
+
rb_alias_variable(newid, rb_intern(get_global_name(&old)));
|
|
46
|
+
return ID2SYM(newid);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
VALUE gvars_module;
|
|
50
|
+
|
|
51
|
+
void
|
|
52
|
+
Init_gvars(void)
|
|
53
|
+
{
|
|
54
|
+
gvars_module = rb_define_module("GVars");
|
|
55
|
+
|
|
56
|
+
// Define module-level functions that can be used as mixins
|
|
57
|
+
rb_define_module_function(gvars_module, "global_variable_get", gvars_f_global_variable_get, 1);
|
|
58
|
+
rb_define_module_function(gvars_module, "global_variable_set", gvars_f_global_variable_set, 2);
|
|
59
|
+
rb_define_module_function(gvars_module, "alias_global_variable", gvars_f_alias_global_variable, 2);
|
|
60
|
+
|
|
61
|
+
// Don't make mixin, as it exists in Kernel
|
|
62
|
+
rb_define_singleton_method(gvars_module, "global_variables", gvars_f_global_variables, 0);
|
|
63
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#include "ruby.h"
|
|
2
|
+
|
|
3
|
+
// Converts `name` to a global variable name, ensures it's valid, and returns it.
|
|
4
|
+
//
|
|
5
|
+
// for checking, it makes that `name` starts with `$`. This isn't really required, as ruby supports
|
|
6
|
+
// globals that don't start with `$` (but doesn't expose any methods to interact with them)
|
|
7
|
+
static char *get_global_name(VALUE *name) {
|
|
8
|
+
// printf("spot1\n");
|
|
9
|
+
if (RB_SYMBOL_P(*name)) *name = rb_sym2str(*name);
|
|
10
|
+
// printf("spot2\n");
|
|
11
|
+
char *namestr = StringValueCStr(*name);
|
|
12
|
+
// printf("spot3\n");
|
|
13
|
+
|
|
14
|
+
if (namestr[0] != '$') {
|
|
15
|
+
rb_raise(rb_eNameError, "'%s' is not allowed as a global variable name", namestr);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return namestr;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static VALUE
|
|
22
|
+
gvars_f_get(VALUE self, VALUE name)
|
|
23
|
+
{
|
|
24
|
+
// extern VALUE rb_gvars_get(ID);
|
|
25
|
+
return rb_gvars_get(rb_intern(get_global_name(&name)));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static VALUE
|
|
29
|
+
gvars_f_set(VALUE self, VALUE name, VALUE value)
|
|
30
|
+
{
|
|
31
|
+
return rb_gv_set(get_global_name(&name), value);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static VALUE
|
|
35
|
+
gvars_f_defined_p(VALUE self, VALUE name)
|
|
36
|
+
{
|
|
37
|
+
extern VALUE rb_gvar_defined(ID);
|
|
38
|
+
return rb_gvar_defined(rb_check_id(&name));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static VALUE
|
|
42
|
+
gvars_list(VALUE self)
|
|
43
|
+
{
|
|
44
|
+
return rb_f_global_variables();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static VALUE
|
|
48
|
+
gvars_f_alias(VALUE self, VALUE new, VALUE old)
|
|
49
|
+
{
|
|
50
|
+
ID newid = rb_intern(get_global_name(&new));
|
|
51
|
+
rb_alias_variable(newid, rb_intern(get_global_name(&old)));
|
|
52
|
+
return ID2SYM(newid);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
struct hooked_var {
|
|
56
|
+
VALUE getter, setter;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
static VALUE hooked_var_getter(ID id, VALUE *data) {
|
|
60
|
+
struct hooked_var *bv = (struct hooked_var *)data;
|
|
61
|
+
return rb_proc_call_kw(bv->getter, rb_ary_new3(1, rb_id2str(id)), RB_NO_KEYWORDS);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static void hooked_var_setter(VALUE val, ID id, VALUE *data) {
|
|
65
|
+
struct hooked_var *bv = (struct hooked_var *)data;
|
|
66
|
+
rb_proc_call_kw(bv->setter, rb_ary_new3(2, rb_id2str(id), val), RB_NO_KEYWORDS);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static VALUE
|
|
70
|
+
gvars_define_virtual_global(int argc, VALUE *argv, VALUE self)
|
|
71
|
+
{
|
|
72
|
+
VALUE name, getter, setter;
|
|
73
|
+
|
|
74
|
+
switch (rb_scan_args(argc, argv, "12", &name, &getter, &setter)) {
|
|
75
|
+
case 1:
|
|
76
|
+
getter = (rb_need_block(), rb_block_proc());
|
|
77
|
+
setter = Qnil;
|
|
78
|
+
break;
|
|
79
|
+
|
|
80
|
+
case 2:
|
|
81
|
+
setter = Qnil;
|
|
82
|
+
|
|
83
|
+
case 3:
|
|
84
|
+
if (rb_block_given_p()) {
|
|
85
|
+
rb_warn("given block not used");
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
default:
|
|
89
|
+
rb_bug("oops");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
char *name_str = get_global_name(&name);
|
|
93
|
+
|
|
94
|
+
VALUE getter_proc, setter_proc;
|
|
95
|
+
|
|
96
|
+
getter_proc = rb_convert_type(getter, T_DATA, "Proc", "to_proc");
|
|
97
|
+
if (NIL_P(getter_proc) || !rb_obj_is_proc(getter_proc)) {
|
|
98
|
+
rb_raise(rb_eTypeError, "wrong getter type %s (expected Proc)", rb_obj_classname(getter_proc));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (NIL_P(setter)) {
|
|
102
|
+
setter_proc = Qnil;
|
|
103
|
+
} else {
|
|
104
|
+
setter_proc = rb_convert_type(setter, T_DATA, "Proc", "to_proc");
|
|
105
|
+
if (NIL_P(setter_proc) || !rb_obj_is_proc(setter_proc)) {
|
|
106
|
+
rb_raise(rb_eTypeError, "wrong setter type %s (expected Proc)", rb_obj_classname(setter_proc));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// todo: not just leak memory here lol
|
|
111
|
+
struct hooked_var *hv = (struct hooked_var *)malloc(sizeof(struct hooked_var));
|
|
112
|
+
hv->getter = getter_proc;
|
|
113
|
+
hv->setter = setter_proc;
|
|
114
|
+
|
|
115
|
+
rb_define_hooked_variable(name_str, (VALUE *)hv, hooked_var_getter, setter_proc == Qnil ? rb_gvar_readonly_setter : hooked_var_setter);
|
|
116
|
+
extern void rb_gvar_ractor_local(const char *);
|
|
117
|
+
rb_gvar_ractor_local(name_str);
|
|
118
|
+
return name; //TODO: ID2SYM(id)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
VALUE gvars_module;
|
|
122
|
+
|
|
123
|
+
void
|
|
124
|
+
Init_gvars(void)
|
|
125
|
+
{
|
|
126
|
+
gvars_module = rb_define_module("GVars");
|
|
127
|
+
|
|
128
|
+
// Define module-level functions that can be used as mixins
|
|
129
|
+
rb_define_module_function(gvars_module, "global_variable_get", gvars_f_get, 1);
|
|
130
|
+
rb_define_module_function(gvars_module, "global_variable_set", gvars_f_set, 2);
|
|
131
|
+
// rb_define_module_function(gvars_module, "global_variable_defined?", gvars_f_defined_p, 1);
|
|
132
|
+
rb_define_module_function(gvars_module, "alias_global_variable", gvars_f_alias, 2);
|
|
133
|
+
|
|
134
|
+
// Don't make mixin, as it exists in Kernel
|
|
135
|
+
rb_define_singleton_method(gvars_module, "global_variables", gvars_list, 0);
|
|
136
|
+
|
|
137
|
+
// aliases at top-level
|
|
138
|
+
rb_define_alias(rb_singleton_class(gvars_module), "get", "global_variable_get");
|
|
139
|
+
rb_define_alias(rb_singleton_class(gvars_module), "set", "global_variable_set");
|
|
140
|
+
// rb_define_alias(rb_singleton_class(gvars_module), "defined?", "global_variable_defined?");
|
|
141
|
+
rb_define_alias(rb_singleton_class(gvars_module), "alias", "alias_global_variable");
|
|
142
|
+
rb_define_alias(rb_singleton_class(gvars_module), "list", "global_variables");
|
|
143
|
+
rb_define_alias(rb_singleton_class(gvars_module), "[]", "global_variable_get");
|
|
144
|
+
rb_define_alias(rb_singleton_class(gvars_module), "[]=", "global_variable_set");
|
|
145
|
+
|
|
146
|
+
// rb_define_singleton_method(gvars_module, "virtual", gvars_define_virtual_global, -1);
|
|
147
|
+
}
|
data/lib/gvars/version.rb
CHANGED
data/lib/gvars.rb
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "gvars/version"
|
|
4
|
+
require_relative "gvars/gvars"
|
|
4
5
|
|
|
5
|
-
module
|
|
6
|
-
class
|
|
7
|
-
|
|
6
|
+
module GVars
|
|
7
|
+
class << self
|
|
8
|
+
alias get global_variable_get
|
|
9
|
+
alias [] global_variable_get
|
|
10
|
+
alias set global_variable_set
|
|
11
|
+
alias []= global_variable_set
|
|
12
|
+
alias alias alias_global_variable
|
|
13
|
+
alias list global_variables
|
|
14
|
+
end
|
|
8
15
|
end
|
data/sig/gvars.rbs
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
module
|
|
1
|
+
module GVars
|
|
2
2
|
VERSION: String
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
# Mixin methods
|
|
5
|
+
def self?.global_variable_get: (interned name) -> untyped
|
|
6
|
+
def self?.global_variable_set: [T] (interned name, T value) -> T
|
|
7
|
+
def self?.alias_global_variable: (interned to_set, interned original) -> Symbol
|
|
8
|
+
|
|
9
|
+
def self.global_variables: () -> Array[Symbol]
|
|
10
|
+
|
|
11
|
+
alias self.get self.global_variable_get
|
|
12
|
+
alias self.[] self.global_variable_get
|
|
13
|
+
alias self.set self.global_variable_set
|
|
14
|
+
alias self.[]= self.global_variable_set
|
|
15
|
+
alias self.list self.global_variables
|
|
16
|
+
alias self.alias self.alias_global_variable
|
|
4
17
|
end
|
metadata
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gvars
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
8
|
-
bindir:
|
|
7
|
+
- Sam Westerman
|
|
8
|
+
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
|
-
description:
|
|
12
|
+
description: |
|
|
13
|
+
Provides methods for manupulating global variables, as well as defining custom "hooked"
|
|
14
|
+
variables
|
|
13
15
|
email:
|
|
14
16
|
- mail@sampersand.me
|
|
15
17
|
executables: []
|
|
16
|
-
extensions:
|
|
18
|
+
extensions:
|
|
19
|
+
- ext/gvars/extconf.rb
|
|
17
20
|
extra_rdoc_files: []
|
|
18
21
|
files:
|
|
19
22
|
- LICENSE.txt
|
|
20
23
|
- README.md
|
|
21
24
|
- Rakefile
|
|
25
|
+
- ext/gvars/extconf.rb
|
|
26
|
+
- ext/gvars/gvars.c
|
|
27
|
+
- ext/gvars/gvars.c-old
|
|
22
28
|
- lib/gvars.rb
|
|
23
29
|
- lib/gvars/version.rb
|
|
24
30
|
- sig/gvars.rbs
|
|
@@ -40,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
40
46
|
- !ruby/object:Gem::Version
|
|
41
47
|
version: '0'
|
|
42
48
|
requirements: []
|
|
43
|
-
rubygems_version:
|
|
49
|
+
rubygems_version: 4.0.3
|
|
44
50
|
specification_version: 4
|
|
45
|
-
summary: Provides
|
|
51
|
+
summary: Provides utility methods for interacting with global variables
|
|
46
52
|
test_files: []
|