rucy 0.3.11 → 0.3.12

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: 89db0f3be96a0564f5ed99044093f111decff6d0dd89a613251be1bda89163ca
4
- data.tar.gz: 6c7b8d8aafc090fb75d7fb2c3cfc16fe9026b8da93d4673ee5cc9b3d8e2aba6e
3
+ metadata.gz: b1729a91940f9162509a18696813859a374ccb82c4af989b4c782e6015e394fa
4
+ data.tar.gz: 645ee9505dc9178bd1aa77093f44566290e05dac58ca5d20d62193e0d7a5c0d3
5
5
  SHA512:
6
- metadata.gz: a82fd0de0e5e372e8dbb25b335c3cb27e7209c691522058e26c324dfb16204b181c72326439e5f05c2a54ed7199fb23d5315f3a02b4f8de8d35533b1e9977036
7
- data.tar.gz: 510edf2d681cc108435efc854c26446afc4560e7a0471269f68661bc6f8f9eedbf2c8d55ef2733dce46e78c1a01c5ca86b8dcb0c2b84723474a2d60cf2b3c885
6
+ metadata.gz: 2995825674988de7587c353785c032f15e974e5074412497b448fd6ac0450d0450dc4a0951b805e80ef58c66d47c92546e88da36127c4cbd0693c768b94e0b57
7
+ data.tar.gz: b7fbe367adbbcfd7de8dc7176f488a776451dbfb9658ac9c3f6a7b857aa3327cfcf5713f26b9bae709a4a3eb746c124917cb926da8df77ef728fe6701c9c1ba6
@@ -28,6 +28,30 @@ VALUE value_to_ushort(VALUE self, VALUE num)
28
28
  return value(to<unsigned short>(num));
29
29
  }
30
30
 
31
+ static
32
+ VALUE value_to_int(VALUE self, VALUE num)
33
+ {
34
+ return value(to<int>(num));
35
+ }
36
+
37
+ static
38
+ VALUE value_to_uint(VALUE self, VALUE num)
39
+ {
40
+ return value(to<unsigned int>(num));
41
+ }
42
+
43
+ static
44
+ VALUE value_to_long(VALUE self, VALUE num)
45
+ {
46
+ return value(to<long>(num));
47
+ }
48
+
49
+ static
50
+ VALUE value_to_ulong(VALUE self, VALUE num)
51
+ {
52
+ return value(to<unsigned long>(num));
53
+ }
54
+
31
55
  static
32
56
  VALUE true_to_value(VALUE self)
33
57
  {
@@ -84,6 +108,10 @@ Init_value ()
84
108
  rb_define_method(mTester, "value_to_uchar", RUBY_METHOD_FUNC(value_to_uchar), 1);
85
109
  rb_define_method(mTester, "value_to_short", RUBY_METHOD_FUNC(value_to_short), 1);
86
110
  rb_define_method(mTester, "value_to_ushort", RUBY_METHOD_FUNC(value_to_ushort), 1);
111
+ rb_define_method(mTester, "value_to_int", RUBY_METHOD_FUNC(value_to_int), 1);
112
+ rb_define_method(mTester, "value_to_uint", RUBY_METHOD_FUNC(value_to_uint), 1);
113
+ rb_define_method(mTester, "value_to_long", RUBY_METHOD_FUNC(value_to_long), 1);
114
+ rb_define_method(mTester, "value_to_ulong", RUBY_METHOD_FUNC(value_to_ulong), 1);
87
115
 
88
116
  rb_define_method(mTester, "true_to_value", RUBY_METHOD_FUNC(true_to_value), -1);
89
117
  rb_define_method(mTester, "false_to_value", RUBY_METHOD_FUNC(false_to_value), -1);
@@ -4,6 +4,9 @@ on:
4
4
  push:
5
5
  tags: ['v[0-9]*']
6
6
 
7
+ permissions:
8
+ contents: write
9
+
7
10
  jobs:
8
11
  release:
9
12
  runs-on: macos-latest
@@ -1,3 +1,9 @@
1
+ require 'shellwords'
2
+
3
+ ALL_REPO = 'xord/all'
4
+ ALL_DIR = '../all'
5
+ ALL_FETCH_DEPTH = 100
6
+
1
7
  RENAMES = {reflex: 'reflexion'}
2
8
 
3
9
  def sh(cmd)
@@ -5,7 +11,7 @@ def sh(cmd)
5
11
  system cmd
6
12
  end
7
13
 
8
- def setup_dependencies(build: true, only: nil)
14
+ def setup_dependencies(only: nil)
9
15
  gemspec_path = `git ls-files`.lines(chomp: true).find {|l| l =~ /\.gemspec$/}
10
16
  return unless gemspec_path
11
17
 
@@ -13,44 +19,109 @@ def setup_dependencies(build: true, only: nil)
13
19
  name = File.basename gemspec_path, '.gemspec'
14
20
 
15
21
  exts = File.readlines('Rakefile')
16
- .map {|l| l[%r|^\s*require\W+(\w+)/extension\W+$|, 1]}
22
+ .map {|l| l[%r|^\s*require\W+([\w\-\_]+)/extension\W+$|, 1]}
17
23
  .compact
18
24
  .reject {|ext| ext == name}
19
25
  exts = exts & [only].flatten.map(&:to_s) if only
26
+ return if exts.empty?
27
+
28
+ unless setup_dependencies_via_monorepo(exts)
29
+ setup_dependencies_via_each_repo_by_version(gemspec, exts)
30
+ end
31
+
32
+ exts.each {|ext| sh %( cd ../#{ext} && rake ext )}
33
+ end
34
+
35
+ def setup_dependencies_via_monorepo(exts)
36
+ return false unless checkout_monorepo
37
+ exts.each {|ext| sh %( ln -snf all/#{ext} ../#{ext} )}
38
+ true
39
+ end
40
+
41
+ def checkout_monorepo()
42
+ uuid = `git log -1 --format=%B`[/^\[\[([0-9a-fA-F-]+)\]\]$/, 1]
43
+ return false unless uuid
44
+
45
+ commit = setup_monorepo uuid
46
+ return false unless commit
47
+
48
+ Dir.chdir(ALL_DIR) {sh %( git checkout -q #{commit} )}
49
+ true
50
+ end
51
+
52
+ def setup_monorepo(uuid)
53
+ unless File.directory? ALL_DIR
54
+ url = "https://github.com/#{ALL_REPO}.git"
55
+ sh %( git clone --no-tags --depth #{ALL_FETCH_DEPTH} #{url} #{ALL_DIR} )
56
+ end
57
+ loop do
58
+ commit = find_monorepo_commit uuid
59
+ return commit if commit
60
+
61
+ deepened = Dir.chdir ALL_DIR do
62
+ before = `git rev-list --count HEAD`.to_i
63
+ sh %( git fetch --deepen #{ALL_FETCH_DEPTH} )
64
+ `git rev-list --count HEAD`.to_i > before
65
+ end
66
+ return nil unless deepened
67
+ end
68
+ end
69
+
70
+ def find_monorepo_commit(uuid)
71
+ Dir.chdir ALL_DIR do
72
+ out = `git log origin/HEAD -F --grep="[[#{uuid}]]" --format=%H -1`.strip
73
+ out.empty? ? nil : out
74
+ end
75
+ end
20
76
 
77
+ def setup_dependencies_via_each_repo_by_version(gemspec, exts)
21
78
  exts.each do |ext|
22
79
  gem = RENAMES[ext.to_sym].then {|s| s || ext}
23
- ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s*>=\s*([\d\.]+)\s*['"]/, 1]
80
+ ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s*~>\s*([\d\.]+)\s*['"]/, 1]
24
81
  opts = '-c advice.detachedHead=false --depth 1'
25
82
  clone = "git clone #{opts} https://github.com/xord/#{ext}.git ../#{ext}"
26
83
 
27
84
  # 'rake subtree:push' pushes all subrepos, so cloning by new tag
28
85
  # often fails before tagging each new tag
29
86
  sh %( #{clone} --branch v#{ver} || #{clone} )
30
- sh %( cd ../#{ext} && rake ext )
31
87
  end
32
88
  end
33
89
 
34
90
  def tag_versions()
35
- tags = `git tag`.lines chomp: true
36
- vers = `git log --oneline ./VERSION`
91
+ changes = changelogs
92
+ tags = `git tag`.lines chomp: true
93
+ vers = `git log --oneline ./VERSION`
37
94
  .lines(chomp: true)
38
95
  .map {|line| line.split.first[/^\w+$/]}
39
- .map {|hash| [`git cat-file -p #{hash}:./VERSION 2>/dev/null`[/[\d\.]+/], hash]}
40
- .select {|ver, hash| ver && hash}
96
+ .map {|sha| [`git cat-file -p #{sha}:./VERSION 2>/dev/null`[/[\d\.]+/], sha]}
97
+ .select {|ver, sha| ver && sha}
41
98
  .reverse
42
99
  .to_h
43
100
 
44
- changes = File.read('ChangeLog.md')
45
- .split(/^\s*##\s*\[\s*v([\d\.]+)\s*\].*$/)
46
- .slice(1..-1)
47
- .each_slice(2)
48
- .to_h
49
- .transform_values(&:strip!)
50
-
51
- vers.to_a.reverse.each do |ver, hash|
101
+ vers.to_a.reverse.each do |ver, sha|
52
102
  tag = "v#{ver}"
53
103
  break if tags.include?(tag)
54
- sh %( git tag -a -m \"#{changes[ver]&.gsub '"', '\\"'}\" #{tag} #{hash} )
104
+ sh %( git tag -a -m \"#{changes[tag]&.gsub '"', '\\"'}\" #{tag} #{sha} )
55
105
  end
56
106
  end
107
+
108
+ def release(*paths)
109
+ tag = ENV['GITHUB_REF']&.sub(%r|^refs/tags/|, '') || raise('GITHUB_REF tag not set')
110
+ notes = (changelogs[tag] || '').shellescape
111
+ paths = paths.flatten.join ' '
112
+
113
+ sh(%( gh release create #{tag} #{paths} --notes #{notes} )) ||
114
+ sh(%( gh release upload #{tag} #{paths} --clobber )) ||
115
+ raise('failed to upload to releases')
116
+ end
117
+
118
+ def changelogs()
119
+ File.read('ChangeLog.md')
120
+ .split(/^\s*##\s*\[\s*(v[\d\.]+)\s*\].*$/)
121
+ .slice(1..)
122
+ .each_slice(2)
123
+ .to_h
124
+ .transform_values(&:strip!)
125
+ rescue Errno::ENOENT
126
+ raise 'failed to get changelogs'
127
+ end
data/ChangeLog.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # rucy ChangeLog
2
2
 
3
3
 
4
+ ## [v0.3.12] - 2026-05-10
5
+
6
+ - Migrate to TypedData API for Ruby 4.x compatibility
7
+ - Enable WB_PROTECTED for TypedData with no mark function
8
+ - Add range checks to integer value_to conversions
9
+ - Add Value::respond_to wrapping rb_respond_to
10
+ - Use hint_memory_usage callback for external memory GC integration
11
+ - Remove deprecated has_rdoc= from gemspecs
12
+
13
+
4
14
  ## [v0.3.11] - 2026-04-17
5
15
 
6
16
  - Fix ANYARGS function pointer warnings in module bindings
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.11
1
+ 0.3.12
data/ext/rucy/value.cpp CHANGED
@@ -32,6 +32,34 @@ RUCY_DEF1(value_to_ushort, num)
32
32
  }
33
33
  RUCY_END
34
34
 
35
+ static
36
+ RUCY_DEF1(value_to_int, num)
37
+ {
38
+ return value(to<int>(num));
39
+ }
40
+ RUCY_END
41
+
42
+ static
43
+ RUCY_DEF1(value_to_uint, num)
44
+ {
45
+ return value(to<unsigned int>(num));
46
+ }
47
+ RUCY_END
48
+
49
+ static
50
+ RUCY_DEF1(value_to_long, num)
51
+ {
52
+ return value(to<long>(num));
53
+ }
54
+ RUCY_END
55
+
56
+ static
57
+ RUCY_DEF1(value_to_ulong, num)
58
+ {
59
+ return value(to<unsigned long>(num));
60
+ }
61
+ RUCY_END
62
+
35
63
  static
36
64
  RUCY_DEFN(true_to_value)
37
65
  {
@@ -89,10 +117,14 @@ Init_value ()
89
117
  Module mRucy = define_module("Rucy");
90
118
  Module mTester = mRucy.define_module("Tester");
91
119
 
92
- mTester.define_method("value_to_char", value_to_char);
93
- mTester.define_method("value_to_uchar", value_to_uchar);
120
+ mTester.define_method("value_to_char", value_to_char);
121
+ mTester.define_method("value_to_uchar", value_to_uchar);
94
122
  mTester.define_method("value_to_short", value_to_short);
95
123
  mTester.define_method("value_to_ushort", value_to_ushort);
124
+ mTester.define_method("value_to_int", value_to_int);
125
+ mTester.define_method("value_to_uint", value_to_uint);
126
+ mTester.define_method("value_to_long", value_to_long);
127
+ mTester.define_method("value_to_ulong", value_to_ulong);
96
128
 
97
129
  mTester.define_method("true_to_value", true_to_value);
98
130
  mTester.define_method("false_to_value", false_to_value);
@@ -4,6 +4,7 @@
4
4
  #define __RUCY_EXTENSION_H__
5
5
 
6
6
 
7
+ #include <typeinfo>
7
8
  #include <xot/ref.h>
8
9
  #include <xot/string.h>
9
10
  #include <rucy/defs.h>
@@ -384,81 +385,101 @@ namespace Rucy
384
385
  };// ClassWrapper
385
386
 
386
387
 
387
- template <typename T> inline void delete_type (void* p)
388
+ template <typename T>
389
+ inline void delete_type (void* p)
388
390
  {
389
391
  delete (T*) p;
390
392
  }
391
393
 
392
- template <typename T> inline void release_ref (void* p)
394
+ template <typename T>
395
+ inline void release_ref (void* p)
393
396
  {
394
397
  if (p) ((T*) p)->release();
395
398
  }
396
399
 
397
- template <typename T> inline void release_wrapper (void* p)
400
+ template <typename T>
401
+ inline void release_wrapper (void* p)
398
402
  {
399
403
  if (p) ((T*) p)->release(true);
400
404
  }
401
405
 
402
406
 
403
- template <typename T> inline Value new_type (
404
- Value klass, T* ptr,
405
- RUBY_DATA_FUNC mark = NULL,
406
- RUBY_DATA_FUNC free = delete_type<T>)
407
+ template <typename T, RUBY_DATA_FUNC mark, RUBY_DATA_FUNC free>
408
+ inline const rb_data_type_t* get_data_type ()
409
+ {
410
+ static const rb_data_type_t data_type = {
411
+ typeid(T).name(),
412
+ {mark, free, NULL, NULL, {NULL}},
413
+ NULL, NULL,
414
+ RUBY_TYPED_FREE_IMMEDIATELY |
415
+ (mark == nullptr ? RUBY_TYPED_WB_PROTECTED : 0)
416
+ };
417
+ return &data_type;
418
+ }
419
+
420
+
421
+ template <
422
+ typename T,
423
+ RUBY_DATA_FUNC mark = nullptr,
424
+ RUBY_DATA_FUNC free = delete_type<T>>
425
+ inline Value new_type (Value klass, T* ptr)
407
426
  {
408
427
  if (!ptr) return nil();
409
- return Data_Wrap_Struct(klass, mark, free, ptr);
428
+ return rb_data_typed_object_wrap(klass, ptr, get_data_type<T, mark, free>());
410
429
  }
411
430
 
412
- template <typename T> inline Value new_type (
413
- Value klass,
414
- RUBY_DATA_FUNC mark = NULL,
415
- RUBY_DATA_FUNC free = delete_type<T>)
431
+ template <
432
+ typename T,
433
+ RUBY_DATA_FUNC mark = nullptr,
434
+ RUBY_DATA_FUNC free = delete_type<T>>
435
+ inline Value new_type (Value klass)
416
436
  {
417
- return new_type(klass, new T, mark, free);
437
+ return new_type<T, mark, free>(klass, new T);
418
438
  }
419
439
 
420
- template <typename T> inline Value new_ref (
421
- Value klass, T* ptr,
422
- RUBY_DATA_FUNC mark = NULL,
423
- RUBY_DATA_FUNC free = release_ref<T>)
440
+ template <
441
+ typename T,
442
+ RUBY_DATA_FUNC mark = nullptr,
443
+ RUBY_DATA_FUNC free = release_ref<T>>
444
+ inline Value new_ref (Value klass, T* ptr)
424
445
  {
425
446
  if (ptr) ptr->retain();
426
- return new_type(klass, ptr, mark, free);
447
+ return new_type<T, mark, free>(klass, ptr);
427
448
  }
428
449
 
429
- template <typename T> inline Value new_ref (
430
- Value klass,
431
- RUBY_DATA_FUNC mark = NULL,
432
- RUBY_DATA_FUNC free = release_ref<T>)
450
+ template <
451
+ typename T,
452
+ RUBY_DATA_FUNC mark = nullptr,
453
+ RUBY_DATA_FUNC free = release_ref<T>>
454
+ inline Value new_ref (Value klass)
433
455
  {
434
- return new_ref(klass, new T, mark, free);
456
+ return new_ref<T, mark, free>(klass, new T);
435
457
  }
436
458
 
437
- template <typename T> inline Value new_wrapper (
438
- Value klass, T* ptr,
439
- RUBY_DATA_FUNC mark = NULL,
440
- RUBY_DATA_FUNC free = release_wrapper<T>)
459
+ template <
460
+ typename T,
461
+ RUBY_DATA_FUNC mark = nullptr,
462
+ RUBY_DATA_FUNC free = release_wrapper<T>>
463
+ inline Value new_wrapper (Value klass, T* ptr)
441
464
  {
442
465
  if (ptr) ptr->retain(true);
443
- return new_type(klass, ptr, mark, free);
466
+ return new_type<T, mark, free>(klass, ptr);
444
467
  }
445
468
 
446
- template <typename T> inline Value new_wrapper (
447
- Value klass,
448
- RUBY_DATA_FUNC mark = NULL,
449
- RUBY_DATA_FUNC free = release_wrapper<T>)
469
+ template <
470
+ typename T,
471
+ RUBY_DATA_FUNC mark = nullptr,
472
+ RUBY_DATA_FUNC free = release_wrapper<T>>
473
+ inline Value new_wrapper (Value klass)
450
474
  {
451
- return new_wrapper(klass, new T, mark, free);
475
+ return new_wrapper<T, mark, free>(klass, new T);
452
476
  }
453
477
 
454
478
 
455
479
  template <typename T> inline T* get_type_ptr (Value obj, Value klass = nil())
456
480
  {
457
481
  if (!klass.is_nil()) check_class(obj, klass);
458
- RubyValue o = obj.value();
459
- T* p = NULL;
460
- Data_Get_Struct(o, T, p);
461
- return p;
482
+ return (T*) DATA_PTR(obj.value());
462
483
  }
463
484
 
464
485
 
@@ -109,6 +109,8 @@ namespace Rucy
109
109
 
110
110
  bool is_a (Value klass) const;
111
111
 
112
+ bool respond_to (Symbol name) const;
113
+
112
114
  Value inspect () const;
113
115
 
114
116
  // String
data/include/rucy.h CHANGED
@@ -1,7 +1,7 @@
1
1
  // -*- c++ -*-
2
2
  #pragma once
3
- #ifndef __RUCY_H__
4
- #define __RUCY_H__
3
+ #ifndef __RUCY_ALL_H__
4
+ #define __RUCY_ALL_H__
5
5
 
6
6
 
7
7
  #include <rucy/ruby.h>
@@ -5,8 +5,10 @@ module Rucy
5
5
 
6
6
  module_function
7
7
 
8
- def name()
9
- super.split('::')[-2]
8
+ def name(downcase = false)
9
+ super().split('::')[-2].then {|s|
10
+ downcase ? s.gsub(/([a-z])([A-Z])/) {"#{$1}-#{$2}"}.downcase : s
11
+ }
10
12
  end
11
13
 
12
14
  def version()
@@ -29,6 +31,10 @@ module Rucy
29
31
  root_dir 'ext'
30
32
  end
31
33
 
34
+ def lib_name()
35
+ name true
36
+ end
37
+
32
38
  end# Extension
33
39
 
34
40
 
data/rucy.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  end
11
11
 
12
12
  ext = Rucy::Extension
13
- name = ext.name.downcase
13
+ name = ext.name true
14
14
  rdocs = glob.call *%w[README .doc/ext/**/*.cpp]
15
15
 
16
16
  s.name = name
@@ -25,13 +25,12 @@ Gem::Specification.new do |s|
25
25
  s.platform = Gem::Platform::RUBY
26
26
  s.required_ruby_version = '>= 3.0.0'
27
27
 
28
- s.add_dependency 'xot', '~> 0.3.11'
28
+ s.add_dependency 'xot', '~> 0.3.12'
29
29
 
30
30
  s.files = `git ls-files`.split $/
31
31
  s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
32
32
  s.test_files = s.files.grep %r{^(test|spec|features)/}
33
33
  s.extra_rdoc_files = rdocs.to_a
34
- s.has_rdoc = true
35
34
 
36
35
  s.extensions << 'Rakefile'
37
36
  end
data/src/rucy.cpp CHANGED
@@ -2,6 +2,7 @@
2
2
  #include "rucy/rucy.h"
3
3
 
4
4
 
5
+ #include <xot/util.h>
5
6
  #include "rucy/exception.h"
6
7
 
7
8
 
@@ -9,6 +10,18 @@ namespace Rucy
9
10
  {
10
11
 
11
12
 
13
+ static void
14
+ hint_memory_usage (ssize_t size)
15
+ {
16
+ rb_gc_adjust_memory_usage(size);
17
+
18
+ // rb_gc_adjust_memory_usage() uses MEMOP_TYPE_REALLOC internally,
19
+ // which increases malloc_increase but does not check the GC trigger.
20
+ // A tiny ruby_xmalloc() goes through MEMOP_TYPE_MALLOC and triggers
21
+ // GC when malloc_increase exceeds malloc_limit.
22
+ if (size > 0) ruby_xfree(ruby_xmalloc(1));
23
+ }
24
+
12
25
  void
13
26
  init ()
14
27
  {
@@ -16,6 +29,8 @@ namespace Rucy
16
29
  if (done) return;
17
30
  done = true;
18
31
 
32
+ Xot::set_hint_memory_usage_fun(hint_memory_usage);
33
+
19
34
  rucy_module();
20
35
  native_error_class();
21
36
  invalid_state_error_class();
data/src/value.cpp.erb CHANGED
@@ -308,6 +308,12 @@ namespace Rucy
308
308
  return rb_obj_is_kind_of(val, klass);
309
309
  }
310
310
 
311
+ bool
312
+ Value::respond_to (Symbol name) const
313
+ {
314
+ return rb_respond_to(val, name.symbol());
315
+ }
316
+
311
317
  Value
312
318
  Value::inspect () const
313
319
  {
@@ -646,29 +652,16 @@ namespace Rucy
646
652
  return (bool) obj;
647
653
  }
648
654
 
649
- template <> int
650
- value_to<int> (Value obj, bool convert)
651
- {
652
- if (convert) obj = obj.to_i();
653
- return NUM2INT(obj.value());
654
- }
655
-
656
- template <> unsigned int
657
- value_to<unsigned int> (Value obj, bool convert)
658
- {
659
- if (convert) obj = obj.to_i();
660
- return NUM2UINT(obj.value());
661
- }
662
-
663
655
  template <> char
664
656
  value_to<char> (Value obj, bool convert)
665
657
  {
666
- int n = value_to<int>(obj, convert);
658
+ if (convert) obj = obj.to_i();
659
+ int n = NUM2INT(obj.value());
667
660
  if (
668
661
  n < std::numeric_limits<char>::min() ||
669
662
  n > std::numeric_limits<char>::max())
670
663
  {
671
- range_error(__FILE__, __LINE__, "cannot cast '%d' to char");
664
+ range_error(__FILE__, __LINE__, "cannot cast '%d' to char", n);
672
665
  }
673
666
  return (char) n;
674
667
  }
@@ -676,12 +669,13 @@ namespace Rucy
676
669
  template <> unsigned char
677
670
  value_to<unsigned char> (Value obj, bool convert)
678
671
  {
679
- int n = value_to<int>(obj, convert);
672
+ if (convert) obj = obj.to_i();
673
+ int n = NUM2INT(obj.value());
680
674
  if (
681
675
  n < std::numeric_limits<unsigned char>::min() ||
682
676
  n > std::numeric_limits<unsigned char>::max())
683
677
  {
684
- range_error(__FILE__, __LINE__, "cannot cast '%d' to unsigned char");
678
+ range_error(__FILE__, __LINE__, "cannot cast '%d' to unsigned char", n);
685
679
  }
686
680
  return (unsigned char) n;
687
681
  }
@@ -689,12 +683,13 @@ namespace Rucy
689
683
  template <> short
690
684
  value_to<short> (Value obj, bool convert)
691
685
  {
692
- int n = value_to<int>(obj, convert);
686
+ if (convert) obj = obj.to_i();
687
+ int n = NUM2INT(obj.value());
693
688
  if (
694
689
  n < std::numeric_limits<short>::min() ||
695
690
  n > std::numeric_limits<short>::max())
696
691
  {
697
- range_error(__FILE__, __LINE__, "cannot cast '%d' to short");
692
+ range_error(__FILE__, __LINE__, "cannot cast '%d' to short", n);
698
693
  }
699
694
  return (short) n;
700
695
  }
@@ -702,28 +697,67 @@ namespace Rucy
702
697
  template <> unsigned short
703
698
  value_to<unsigned short> (Value obj, bool convert)
704
699
  {
705
- int n = value_to<int>(obj, convert);
700
+ if (convert) obj = obj.to_i();
701
+ int n = NUM2INT(obj.value());
706
702
  if (
707
703
  n < std::numeric_limits<unsigned short>::min() ||
708
704
  n > std::numeric_limits<unsigned short>::max())
709
705
  {
710
- range_error(__FILE__, __LINE__, "cannot cast '%d' to unsigned short");
706
+ range_error(__FILE__, __LINE__, "cannot cast '%d' to unsigned short", n);
711
707
  }
712
708
  return (unsigned short) n;
713
709
  }
714
710
 
711
+ template <> int
712
+ value_to<int> (Value obj, bool convert)
713
+ {
714
+ if (convert) obj = obj.to_i();
715
+ long long n = NUM2LL(obj.value());
716
+ if (
717
+ n < std::numeric_limits<int>::min() ||
718
+ n > std::numeric_limits<int>::max())
719
+ {
720
+ range_error(__FILE__, __LINE__, "cannot cast '%lld' to int", n);
721
+ }
722
+ return (int) n;
723
+ }
724
+
725
+ template <> unsigned int
726
+ value_to<unsigned int> (Value obj, bool convert)
727
+ {
728
+ if (convert) obj = obj.to_i();
729
+ long long n = NUM2LL(obj.value());
730
+ if (
731
+ n < std::numeric_limits<unsigned int>::min() ||
732
+ n > std::numeric_limits<unsigned int>::max())
733
+ {
734
+ range_error(__FILE__, __LINE__, "cannot cast '%lld' to unsigned int", n);
735
+ }
736
+ return (unsigned int) n;
737
+ }
738
+
715
739
  template <> long
716
740
  value_to<long> (Value obj, bool convert)
717
741
  {
718
742
  if (convert) obj = obj.to_i();
719
- return NUM2LONG(obj.value());
743
+ long long n = NUM2LL(obj.value());
744
+ if (
745
+ n < std::numeric_limits<long>::min() ||
746
+ n > std::numeric_limits<long>::max())
747
+ {
748
+ range_error(__FILE__, __LINE__, "cannot cast '%lld' to long", n);
749
+ }
750
+ return (long) n;
720
751
  }
721
752
 
722
753
  template <> unsigned long
723
754
  value_to<unsigned long> (Value obj, bool convert)
724
755
  {
725
756
  if (convert) obj = obj.to_i();
726
- return NUM2ULONG(obj.value());
757
+ long long n = NUM2LL(obj.value());
758
+ if (n < 0)
759
+ range_error(__FILE__, __LINE__, "cannot cast '%lld' to unsigned long", n);
760
+ return (unsigned long) n;
727
761
  }
728
762
 
729
763
  template <> long long
@@ -737,6 +771,9 @@ namespace Rucy
737
771
  value_to<unsigned long long> (Value obj, bool convert)
738
772
  {
739
773
  if (convert) obj = obj.to_i();
774
+ long long n = NUM2LL(obj.value());
775
+ if (n < 0)
776
+ range_error(__FILE__, __LINE__, "cannot cast '%lld' to unsigned long long", n);
740
777
  return NUM2ULL(obj.value());
741
778
  }
742
779
 
data/test/test_value.rb CHANGED
@@ -8,31 +8,46 @@ class TestFunction < Test::Unit::TestCase
8
8
  def test_value_to_char()
9
9
  assert_equal 0, value_to_char( 0)
10
10
  assert_equal 127, value_to_char( 127)
11
- assert_equal -128, value_to_char(-128)
12
11
  assert_raise(RangeError) {value_to_char 128}
13
- assert_raise(RangeError) {value_to_char -129}
12
+ assert_equal(-128, value_to_char(-128))
13
+ assert_raise(RangeError) {value_to_char(-129)}
14
14
  end
15
15
 
16
16
  def test_value_to_uchar()
17
- assert_equal 0, value_to_uchar( 0)
18
17
  assert_equal 255, value_to_uchar(255)
19
18
  assert_raise(RangeError) {value_to_uchar 256}
20
- assert_raise(RangeError) {value_to_uchar -1}
19
+ assert_equal 0, value_to_uchar( 0)
20
+ assert_raise(RangeError) {value_to_uchar( -1)}
21
21
  end
22
22
 
23
23
  def test_value_to_short()
24
- assert_equal 0, value_to_short( 0)
24
+ assert_equal 0, value_to_short( 0)
25
25
  assert_equal 32767, value_to_short( 32767)
26
- assert_equal -32768, value_to_short(-32768)
27
26
  assert_raise(RangeError) {value_to_short 32768}
28
- assert_raise(RangeError) {value_to_short -32769}
27
+ assert_equal(-32768, value_to_short(-32768))
28
+ assert_raise(RangeError) {value_to_short(-32769)}
29
29
  end
30
30
 
31
31
  def test_value_to_ushort()
32
- assert_equal 0, value_to_ushort( 0)
33
32
  assert_equal 65535, value_to_ushort(65535)
34
33
  assert_raise(RangeError) {value_to_ushort 65536}
35
- assert_raise(RangeError) {value_to_ushort -1}
34
+ assert_equal 0, value_to_ushort( 0)
35
+ assert_raise(RangeError) {value_to_ushort( -1)}
36
+ end
37
+
38
+ def test_value_to_int()
39
+ assert_equal 0, value_to_int( 0)
40
+ assert_equal 2147483647, value_to_int( 2147483647)
41
+ assert_raise(RangeError) {value_to_int 2147483648}
42
+ assert_equal(-2147483648, value_to_int(-2147483648))
43
+ assert_raise(RangeError) {value_to_int(-2147483649)}
44
+ end
45
+
46
+ def test_value_to_uint()
47
+ assert_equal 4294967295, value_to_uint(4294967295)
48
+ assert_raise(RangeError) {value_to_uint 4294967296}
49
+ assert_equal 0, value_to_uint( 0)
50
+ assert_raise(RangeError) {value_to_uint( -1)}
36
51
  end
37
52
 
38
53
  def test_to_value()
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rucy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.11
4
+ version: 0.3.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - xordog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-17 00:00:00.000000000 Z
11
+ date: 2026-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xot
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.11
19
+ version: 0.3.12
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.11
26
+ version: 0.3.12
27
27
  description: This library helps you to develop Ruby Extension by C++.
28
28
  email: xordog@gmail.com
29
29
  executables: