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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e3985d26424ff4d447445b3d10b132cb45a578272a14b0f9439a70a1da22030
4
- data.tar.gz: e18ec85c05f64b05b22dd0623330bac0146376df4ec25daf3ba74d6157e9d93c
3
+ metadata.gz: 1728504fbc5ee4dcf6e72f18a5f0aff56fa3933f97776d9e57bca20cc8301b45
4
+ data.tar.gz: 45fa2513e7c7fc2438dabd33d91505899e7154c8ec4d91fb03008b4f22dbbc9a
5
5
  SHA512:
6
- metadata.gz: 3ee1ae6ceea846f070549ce145715d4091a012979f2830f5cd425e701dd493f9ca15eaf46a084099ee4964436e508f114fab4f274d350f522a08466a874b2156
7
- data.tar.gz: 758bce3ec8a248e43ec6273b026aa4e384ee260575d05a2150fb3a72c0e815600080f77ea68d5a9fbe6fbf7d830820ccbad6453d7fd5b956841fff4e880bb83e
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
@@ -1,8 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "minitest/test_task"
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
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+
3
+ # $CFLAGS << ' -g -fsanitize=undefined'
4
+
5
+ create_makefile 'gvars/gvars'
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Gvars
4
- VERSION = "0.1.0"
3
+ module GVars
4
+ VERSION = "0.9.0"
5
5
  end
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 Gvars
6
- class Error < StandardError; end
7
- # Your code goes here...
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 Gvars
1
+ module GVars
2
2
  VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
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.1.0
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: []
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: 3.7.0.dev
49
+ rubygems_version: 4.0.3
44
50
  specification_version: 4
45
- summary: Provides helper methods for global variables
51
+ summary: Provides utility methods for interacting with global variables
46
52
  test_files: []