gvars 0.1.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ad79094c679e0044908f36687249abd41da98b4df01c1528a03c7832fd2fb6f
4
- data.tar.gz: d49eaba2f5462f1d6cdd10610e8c27b1207b64258ff84a624ef936309db124e7
3
+ metadata.gz: 1728504fbc5ee4dcf6e72f18a5f0aff56fa3933f97776d9e57bca20cc8301b45
4
+ data.tar.gz: 45fa2513e7c7fc2438dabd33d91505899e7154c8ec4d91fb03008b4f22dbbc9a
5
5
  SHA512:
6
- metadata.gz: 3350ee1b36efea744b2bb63c9b5da0dad533172348b998dc17a78fc7e2905de5703283390949cc7eb117d5bf727289f66c32ffc206987be7e61ee857b612696e
7
- data.tar.gz: 356f099483a5bda93da5ae6da01a71887f86dcf81974818cb1fa225447a0c6f354eb0ab3bcc62754cc24140b5fbcf5ce57a054201aa00abc52f6e4586d4cd271
6
+ metadata.gz: 0daa5d2870632bd24be477d7e561383bf89ad66ec6efe844717ef2d1e37c9c8219c22bcc9ab644e8c291e408a41c8a5559a684ecf4f70f178a2f5966963f4261
7
+ data.tar.gz: 2feac652e6098336616d4dd9f9c893add9ef8745884214297392381bf1182edad60839d8229d53e6fe97d1a2abc3c9a107ce61075ce908f25e7ca037b88fd0b6
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2025 SamW
3
+ Copyright (c) 2026 Sam Westerman
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,39 +1,33 @@
1
- # Gvars
1
+ # GVars
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ Adds in missing utilities relating to global variables in Ruby.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gvars`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- ## Installation
7
+ ## Features
8
+ ```ruby
9
+ $foo = 34
8
10
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
11
+ # Dynamically lookup globals
12
+ puts GVars.get(:$foo) #=> 34
10
13
 
11
- Install the gem and add to the application's Gemfile by executing:
14
+ # Dynamically assign globals!
15
+ GVars.set(:$foo, 99)
16
+ puts $foo #=> 99
12
17
 
13
- ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
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
- ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
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
- ## Usage
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
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
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
@@ -10,9 +10,9 @@ Rake::ExtensionTask.new('gvars') do |ext|
10
10
  ext.lib_dir = 'lib/gvars'
11
11
  end
12
12
 
13
- # Minitest::TestTask.create
13
+ Minitest::TestTask.create
14
14
 
15
- # task default: :test
15
+ task default: :test
16
16
 
17
17
  desc 'clean compiled files'
18
18
  task :clean do
data/ext/gvars/extconf.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'mkmf'
2
2
 
3
- $CFLAGS << ' -g -fsanitize=undefined'
3
+ # $CFLAGS << ' -g -fsanitize=undefined'
4
4
 
5
5
  create_makefile 'gvars/gvars'
data/ext/gvars/gvars.c CHANGED
@@ -1,97 +1,49 @@
1
1
  #include "ruby.h"
2
2
 
3
- static VALUE
4
- gvars_global_variable_get(VALUE self, VALUE name)
5
- {
6
- if (RB_SYMBOL_P(name)) name = rb_sym2str(name);
7
- return rb_gv_get(StringValueCStr(name));
8
- }
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
+ }
9
12
 
10
- static VALUE
11
- gvars_global_variable_set(VALUE self, VALUE name, VALUE value)
12
- {
13
- if (RB_SYMBOL_P(name)) name = rb_sym2str(name);
14
- return rb_gv_set(StringValueCStr(name), value);
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;
15
21
  }
16
22
 
17
23
  static VALUE
18
- gvars_global_variable_defined_p(VALUE self, VALUE name)
24
+ gvars_f_global_variable_get(VALUE self, VALUE name)
19
25
  {
20
- extern VALUE rb_gvar_defined(ID);
21
- return rb_gvar_defined(rb_check_id(&name));
26
+ return rb_gv_get(get_global_name(&name));
22
27
  }
23
28
 
24
29
  static VALUE
25
- gvars_global_variables(VALUE self)
30
+ gvars_f_global_variable_set(VALUE self, VALUE name, VALUE value)
26
31
  {
27
- return rb_f_global_variables();
32
+ return rb_gv_set(get_global_name(&name), value);
28
33
  }
29
34
 
30
35
  static VALUE
31
- gvars_alias_global_variable(VALUE self, VALUE new, VALUE old)
36
+ gvars_f_global_variables(VALUE self)
32
37
  {
33
- if (RB_SYMBOL_P(new)) new = rb_sym2str(new);
34
- if (RB_SYMBOL_P(old)) old = rb_sym2str(old);
35
-
36
- // ID newid = rb_intern_str(new);
37
- // ID newid = rb_check_id(&new);
38
- // ID oldid = rb_check_id(&old);
39
-
40
- rb_alias_variable(rb_intern_str(new), rb_intern_str(old));
41
- return new;
42
- }
43
-
44
- struct hooked_var {
45
- VALUE getter, setter;
46
- };
47
-
48
- static VALUE hooked_var_getter(ID id, VALUE *data) {
49
- struct hooked_var *bv = (struct hooked_var *)data;
50
- return rb_proc_call_kw(bv->getter, rb_ary_new3(1, rb_id2str(id)), RB_NO_KEYWORDS);
51
- }
52
-
53
- static void hooked_var_setter(VALUE val, ID id, VALUE *data) {
54
- struct hooked_var *bv = (struct hooked_var *)data;
55
- rb_proc_call_kw(bv->setter, rb_ary_new3(2, rb_id2str(id), val), RB_NO_KEYWORDS);
38
+ return rb_f_global_variables();
56
39
  }
57
40
 
58
41
  static VALUE
59
- gvars_define_virtual_global(int argc, VALUE *argv, VALUE self)
42
+ gvars_f_alias_global_variable(VALUE self, VALUE new, VALUE old)
60
43
  {
61
- VALUE name, getter, setter;
62
-
63
- switch (rb_scan_args(argc, argv, "12", &name, &getter, &setter)) {
64
- case 1: getter = (rb_need_block(), rb_block_proc());
65
- case 2: setter = Qnil;
66
- case 3: break;
67
- default: rb_bug("oops");
68
- }
69
-
70
- const char *name_str = rb_id2name(rb_check_id(&name));
71
-
72
- VALUE getter_proc, setter_proc;
73
-
74
- getter_proc = rb_convert_type(getter, T_DATA, "Proc", "to_proc");
75
- if (NIL_P(getter_proc) || !rb_obj_is_proc(getter_proc)) {
76
- rb_raise(rb_eTypeError, "wrong getter type %s (expected Proc)", rb_obj_classname(getter_proc));
77
- }
78
-
79
- if (NIL_P(setter)) {
80
- setter_proc = Qnil;
81
- } else {
82
- setter_proc = rb_convert_type(setter, T_DATA, "Proc", "to_proc");
83
- if (NIL_P(setter_proc) || !rb_obj_is_proc(setter_proc)) {
84
- rb_raise(rb_eTypeError, "wrong setter type %s (expected Proc)", rb_obj_classname(setter_proc));
85
- }
86
- }
87
-
88
- // todo: not just leak memory here lol
89
- struct hooked_var *hv = (struct hooked_var *)malloc(sizeof(struct hooked_var));
90
- hv->getter = getter_proc;
91
- hv->setter = setter_proc;
92
-
93
- rb_define_hooked_variable(name_str, (VALUE *)hv, hooked_var_getter, setter_proc == Qnil ? rb_gvar_readonly_setter : hooked_var_setter);
94
- return name;
44
+ ID newid = rb_intern(get_global_name(&new));
45
+ rb_alias_variable(newid, rb_intern(get_global_name(&old)));
46
+ return ID2SYM(newid);
95
47
  }
96
48
 
97
49
  VALUE gvars_module;
@@ -102,24 +54,10 @@ Init_gvars(void)
102
54
  gvars_module = rb_define_module("GVars");
103
55
 
104
56
  // Define module-level functions that can be used as mixins
105
- rb_define_module_function(gvars_module, "global_variable_get", gvars_global_variable_get, 1);
106
- rb_define_module_function(gvars_module, "global_variable_set", gvars_global_variable_set, 2);
107
- rb_define_module_function(gvars_module, "global_variable_defined?", gvars_global_variable_defined_p, 1);
108
- rb_define_module_function(gvars_module, "alias_global_variable", gvars_alias_global_variable, 2);
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);
109
60
 
110
61
  // Don't make mixin, as it exists in Kernel
111
- rb_define_singleton_method(gvars_module, "global_variables", gvars_global_variables, 0);
112
-
113
- // aliases at top-level
114
- rb_define_alias(rb_singleton_class(gvars_module), "get", "global_variable_get");
115
- rb_define_alias(rb_singleton_class(gvars_module), "set", "global_variable_set");
116
- rb_define_alias(rb_singleton_class(gvars_module), "defined?", "global_variable_defined?");
117
- rb_define_alias(rb_singleton_class(gvars_module), "alias", "alias_global_variable");
118
- rb_define_alias(rb_singleton_class(gvars_module), "list", "global_variables");
119
- rb_define_alias(rb_singleton_class(gvars_module), "[]", "global_variable_get");
120
- rb_define_alias(rb_singleton_class(gvars_module), "[]=", "global_variable_set");
121
-
122
- rb_define_singleton_method(gvars_module, "define_virtual_global", gvars_define_virtual_global, -1);
123
-
124
- // Virtual methods: TODO
62
+ rb_define_singleton_method(gvars_module, "global_variables", gvars_f_global_variables, 0);
125
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GVars
4
- VERSION = "0.1.3"
4
+ VERSION = "0.9.0"
5
5
  end
data/lib/gvars.rb CHANGED
@@ -2,3 +2,14 @@
2
2
 
3
3
  require_relative "gvars/version"
4
4
  require_relative "gvars/gvars"
5
+
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
15
+ end
data/sig/gvars.rbs CHANGED
@@ -1,10 +1,12 @@
1
1
  module GVars
2
2
  VERSION: String
3
3
 
4
+ # Mixin methods
4
5
  def self?.global_variable_get: (interned name) -> untyped
5
6
  def self?.global_variable_set: [T] (interned name, T value) -> T
6
- def self?.alias_global_variable: (interned to_set, interned original) -> __todo__
7
- def self?.global_variables: () -> Array[Symbol]
7
+ def self?.alias_global_variable: (interned to_set, interned original) -> Symbol
8
+
9
+ def self.global_variables: () -> Array[Symbol]
8
10
 
9
11
  alias self.get self.global_variable_get
10
12
  alias self.[] self.global_variable_get
@@ -12,9 +14,4 @@ module GVars
12
14
  alias self.[]= self.global_variable_set
13
15
  alias self.list self.global_variables
14
16
  alias self.alias self.alias_global_variable
15
-
16
- def self.define_virtual_global: (interned name) { (Symbol name) -> untyped } -> void
17
- | (interned name, proc getter, ?proc setter) -> void
18
-
19
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
20
17
  end
metadata CHANGED
@@ -1,15 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gvars
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
- - SamW
8
- bindir: exe
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: 'TO DO: Write a longer description or delete this line.'
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: []
@@ -22,6 +24,7 @@ files:
22
24
  - Rakefile
23
25
  - ext/gvars/extconf.rb
24
26
  - ext/gvars/gvars.c
27
+ - ext/gvars/gvars.c-old
25
28
  - lib/gvars.rb
26
29
  - lib/gvars/version.rb
27
30
  - sig/gvars.rbs
@@ -43,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
46
  - !ruby/object:Gem::Version
44
47
  version: '0'
45
48
  requirements: []
46
- rubygems_version: 3.7.0.dev
49
+ rubygems_version: 4.0.3
47
50
  specification_version: 4
48
- summary: Provides helper methods for global variables
51
+ summary: Provides utility methods for interacting with global variables
49
52
  test_files: []