rays 0.4.0 → 0.5.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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/bitmap.cpp +28 -8
  3. data/.doc/ext/rays/bounds.cpp +1 -1
  4. data/.doc/ext/rays/camera.cpp +5 -5
  5. data/.doc/ext/rays/color.cpp +1 -1
  6. data/.doc/ext/rays/color_space.cpp +10 -6
  7. data/.doc/ext/rays/font.cpp +116 -18
  8. data/.doc/ext/rays/image.cpp +27 -4
  9. data/.doc/ext/rays/matrix.cpp +1 -1
  10. data/.doc/ext/rays/painter.cpp +5 -5
  11. data/.doc/ext/rays/point.cpp +1 -1
  12. data/.doc/ext/rays/polygon.cpp +4 -4
  13. data/.doc/ext/rays/polyline.cpp +2 -2
  14. data/.doc/ext/rays/shader.cpp +2 -2
  15. data/.github/workflows/release-gem.yml +2 -49
  16. data/.github/workflows/tag.yml +5 -28
  17. data/.github/workflows/test.yml +1 -37
  18. data/ChangeLog.md +21 -0
  19. data/Gemfile.lock +13 -8
  20. data/Rakefile +2 -2
  21. data/VERSION +1 -1
  22. data/ext/rays/bitmap.cpp +28 -8
  23. data/ext/rays/bounds.cpp +1 -1
  24. data/ext/rays/camera.cpp +5 -5
  25. data/ext/rays/color.cpp +1 -1
  26. data/ext/rays/color_space.cpp +10 -6
  27. data/ext/rays/defs.h +3 -3
  28. data/ext/rays/extconf.rb +6 -5
  29. data/ext/rays/font.cpp +120 -18
  30. data/ext/rays/image.cpp +27 -4
  31. data/ext/rays/matrix.cpp +1 -1
  32. data/ext/rays/painter.cpp +5 -5
  33. data/ext/rays/point.cpp +1 -1
  34. data/ext/rays/polygon.cpp +4 -4
  35. data/ext/rays/polyline.cpp +2 -2
  36. data/ext/rays/shader.cpp +2 -2
  37. data/include/rays/bitmap.h +2 -0
  38. data/include/rays/font.h +46 -4
  39. data/include/rays/image.h +9 -5
  40. data/include/rays/painter.h +3 -1
  41. data/include/rays/ruby/color_space.h +2 -0
  42. data/include/rays/shader.h +3 -0
  43. data/lib/rays/font.rb +4 -1
  44. data/lib/rays/image.rb +2 -0
  45. data/lib/rays/painter.rb +5 -5
  46. data/rays.gemspec +3 -3
  47. data/src/bitmap.cpp +107 -0
  48. data/src/color.cpp +17 -0
  49. data/src/font.cpp +121 -25
  50. data/src/font.h +7 -5
  51. data/src/image.cpp +102 -100
  52. data/src/ios/font.mm +77 -24
  53. data/src/opengl/color_space.cpp +4 -1
  54. data/src/opengl/painter.cpp +86 -18
  55. data/src/opengl/shader.cpp +15 -13
  56. data/src/opengl/texture.cpp +2 -2
  57. data/src/opengl/win32/opengl.cpp +17 -12
  58. data/src/osx/font.mm +77 -24
  59. data/src/painter.cpp +12 -12
  60. data/src/painter.h +5 -1
  61. data/src/polygon.cpp +21 -21
  62. data/src/polyline.cpp +4 -4
  63. data/src/sdl/bitmap.cpp +16 -10
  64. data/src/sdl/font.cpp +56 -50
  65. data/src/win32/bitmap.cpp +22 -13
  66. data/src/win32/font.cpp +43 -44
  67. data/src/win32/gdi.cpp +43 -46
  68. data/src/win32/gdi.h +6 -1
  69. data/src/win32/rays.cpp +18 -1
  70. data/test/test_bitmap.rb +28 -10
  71. data/test/test_font.rb +58 -0
  72. data/test/test_image.rb +29 -6
  73. data/test/test_painter.rb +39 -0
  74. metadata +8 -8
  75. data/.github/workflows/utils.rb +0 -127
data/src/win32/gdi.h CHANGED
@@ -76,7 +76,9 @@ namespace Rays
76
76
 
77
77
  Font (HFONT handle = NULL, bool owner = false);
78
78
 
79
- Font (const char* name, coord size = 0);
79
+ Font (
80
+ const char* name, coord size = 0,
81
+ int weight = -1, bool italic = false);
80
82
 
81
83
  ~Font ();
82
84
 
@@ -87,6 +89,9 @@ namespace Rays
87
89
  bool get_extent (
88
90
  coord* width, coord* height, const char* str, HDC hdc = NULL);
89
91
 
92
+ bool get_extent (
93
+ coord* width, coord* height, const wchar_t* str, HDC hdc = NULL);
94
+
90
95
  HFONT handle () const;
91
96
 
92
97
  operator bool () const;
data/src/win32/rays.cpp CHANGED
@@ -9,14 +9,28 @@ namespace Rays
9
9
  {
10
10
 
11
11
 
12
+ typedef void (*PreInitFun) ();
13
+
14
+
12
15
  namespace global
13
16
  {
14
17
 
15
- static bool initialized = false;
18
+ static bool initialized = false;
19
+
20
+ static PreInitFun pre_init_fun = NULL;
16
21
 
17
22
  }// global
18
23
 
19
24
 
25
+ void
26
+ Rays_set_pre_init_fun (PreInitFun fun)
27
+ {
28
+ global::pre_init_fun = fun;
29
+
30
+ if (fun && global::initialized)
31
+ fun();
32
+ }
33
+
20
34
  void
21
35
  init ()
22
36
  {
@@ -25,6 +39,9 @@ namespace Rays
25
39
 
26
40
  global::initialized = true;
27
41
 
42
+ if (global::pre_init_fun)
43
+ global::pre_init_fun();
44
+
28
45
  Renderer_init();
29
46
  }
30
47
 
data/test/test_bitmap.rb CHANGED
@@ -22,13 +22,13 @@ class TestBitmap < Test::Unit::TestCase
22
22
  def test_dup()
23
23
  o = bitmap
24
24
  assert_equal color(0, 0, 0, 0), o[0, 0]
25
- o[0, 0] = color(1, 0, 0, 0)
26
- assert_equal color(1, 0, 0, 0), o[0, 0]
25
+ o[0, 0] = color(1, 0, 0, 1)
26
+ assert_equal color(1, 0, 0, 1), o[0, 0]
27
27
  x = o.dup
28
- assert_equal color(1, 0, 0, 0), x[0, 0]
29
- x[0, 0] = color(0, 1, 0, 0)
30
- assert_equal color(0, 1, 0, 0), x[0, 0]
31
- assert_equal color(1, 0, 0, 0), o[0, 0]
28
+ assert_equal color(1, 0, 0, 1), x[0, 0]
29
+ x[0, 0] = color(0, 1, 0, 1)
30
+ assert_equal color(0, 1, 0, 1), x[0, 0]
31
+ assert_equal color(1, 0, 0, 1), o[0, 0]
32
32
  end
33
33
 
34
34
  def test_pixels()
@@ -37,6 +37,10 @@ class TestBitmap < Test::Unit::TestCase
37
37
 
38
38
  bmp.pixels = [0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00]
39
39
  assert_equal [0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00], bmp.pixels
40
+
41
+ bmp.pixels = [0x80ff0000, 0x4000ff00, 0x010000ff, 0x00ffffff]
42
+ assert_equal [0x80ff0000, 0x4000ff00, 0x010000ff, 0x00000000], bmp.pixels
43
+ assert_equal_color color(1, 0, 0, 0.5), bmp[0, 0], 0.01
40
44
  end
41
45
 
42
46
  def test_pixels_float()
@@ -45,6 +49,9 @@ class TestBitmap < Test::Unit::TestCase
45
49
 
46
50
  bmp.pixels = [1,0,0,1, 0,1,0,1, 0,0,1,1, 1,1,0,1]
47
51
  assert_equal [1,0,0,1, 0,1,0,1, 0,0,1,1, 1,1,0,1], bmp.pixels
52
+
53
+ bmp.pixels = [1,0,0,0.5, 0,1,0,0.25, 0,0,1,1, 1,1,0,0]
54
+ assert_equal [1,0,0,0.5, 0,1,0,0.25, 0,0,1,1, 0,0,0,0], bmp.pixels
48
55
  end unless win32?
49
56
 
50
57
  def test_at()
@@ -57,14 +64,25 @@ class TestBitmap < Test::Unit::TestCase
57
64
  o[0, 0] = [0, 1, 0]
58
65
  assert_equal color(0, 1, 0, 1), o[0, 0]
59
66
 
60
- o[0, 0] = [0, 1, 0, 0]
61
- assert_equal color(0, 1, 0, 0), o[0, 0]
67
+ o[0, 0] = [0, 1, 0, 0.5]
68
+ assert_equal_color color(0, 1, 0, 0.5), o[0, 0], 0.01
62
69
 
63
70
  o[0, 0] = color(0, 0, 1)
64
71
  assert_equal color(0, 0, 1, 1), o[0, 0]
65
72
 
66
- o[0, 0] = color(0, 0, 1, 0)
67
- assert_equal color(0, 0, 1, 0), o[0, 0]
73
+ o[0, 0] = color(0, 0, 1, 0.5)
74
+ assert_equal_color color(0, 0, 1, 0.5), o[0, 0], 0.01
75
+ end
76
+
77
+ def test_at_with_alpha()
78
+ o = bitmap
79
+ o[0, 0] = color(1, 0.5, 0, 0.5)
80
+ assert_equal_color color(1, 0.5, 0, 0.5), o[0, 0], 0.01
81
+
82
+ # pixels are stored premultiplied, so a fully transparent color keeps no
83
+ # color of its own
84
+ o[0, 0] = color(1, 0.5, 0, 0)
85
+ assert_equal color(0, 0, 0, 0), o[0, 0]
68
86
  end
69
87
 
70
88
  def test_to_a()
data/test/test_font.rb CHANGED
@@ -9,8 +9,20 @@ class TestFont < Test::Unit::TestCase
9
9
  R::Font.new(*args)
10
10
  end
11
11
 
12
+ def test_dup()
13
+ font.tap do |f1|
14
+ f1.weight = 1
15
+ f2 = f1.dup
16
+ f1.weight = 2
17
+ assert_equal 2, f1.weight
18
+ assert_equal 1, f2.weight
19
+ end
20
+ end
21
+
12
22
  def test_name()
13
23
  assert_kind_of String, font.name
24
+ assert_equal 'menlo', font('menlo').name(false) if osx?
25
+ assert_equal 'Menlo Regular', font('menlo').name(true) if osx?
14
26
  end
15
27
 
16
28
  def test_size()
@@ -30,6 +42,44 @@ class TestFont < Test::Unit::TestCase
30
42
  assert_equal 11, f11.size
31
43
  end
32
44
 
45
+ def test_weight()
46
+ assert_equal 400, font .weight
47
+ assert_equal 100, font(weight: :thin) .weight
48
+ assert_equal 200, font(weight: :extralight) .weight
49
+ assert_equal 300, font(weight: :light) .weight
50
+ assert_equal 400, font(weight: :normal) .weight
51
+ assert_equal 500, font(weight: :medium) .weight
52
+ assert_equal 600, font(weight: :semibold) .weight
53
+ assert_equal 700, font(weight: :bold) .weight
54
+ assert_equal 800, font(weight: :extrabold) .weight
55
+ assert_equal 900, font(weight: :black) .weight
56
+ assert_equal 400, font(weight: :regular) .weight
57
+ assert_equal 400, font(weight: 'regular') .weight
58
+ assert_equal 0, font(weight: R::Font::WEIGHT_MIN).weight
59
+ assert_equal 1000, font(weight: R::Font::WEIGHT_MAX).weight
60
+ assert_equal 0, font(weight: -1) .weight
61
+ assert_equal 1000, font(weight: 1001) .weight
62
+
63
+ font.tap do |f|
64
+ f.weight = 1; assert_equal 1, f.weight
65
+ f.weight = :normal; assert_equal 400, f.weight
66
+ end
67
+
68
+ assert_raise(ArgumentError) {font weight: :unknown}
69
+ end
70
+
71
+ def test_italic?()
72
+ assert_false font .italic?
73
+ assert_true font(italic: true) .italic?
74
+ assert_false font(italic: false).italic?
75
+ end
76
+
77
+ def test_smooth?()
78
+ assert_true font .smooth?
79
+ assert_true font(smooth: true) .smooth?
80
+ assert_false font(smooth: false).smooth?
81
+ end
82
+
33
83
  def test_width()
34
84
  assert_equal 0, font.width('')
35
85
  w = font.width 'X'
@@ -46,6 +96,14 @@ class TestFont < Test::Unit::TestCase
46
96
 
47
97
  def test_families()
48
98
  assert_not R::Font.families.empty?
99
+
100
+ families = begin
101
+ GC.stress = true
102
+ R::Font.families
103
+ ensure
104
+ GC.stress = false
105
+ end
106
+ assert families.values.flatten.all? {_1.is_a? String}
49
107
  end
50
108
 
51
109
  end# TestFont
data/test/test_image.rb CHANGED
@@ -32,13 +32,13 @@ class TestImage < Test::Unit::TestCase
32
32
  def test_dup()
33
33
  o = image 10, 10
34
34
  assert_equal color(0, 0, 0, 0), o[0, 0]
35
- o[0, 0] = color(1, 0, 0, 0)
36
- assert_equal color(1, 0, 0, 0), o[0, 0]
35
+ o[0, 0] = color(1, 0, 0, 1)
36
+ assert_equal color(1, 0, 0, 1), o[0, 0]
37
37
  x = o.dup
38
- assert_equal color(1, 0, 0, 0), x[0, 0]
39
- x[0, 0] = color(0, 1, 0, 0)
40
- assert_equal color(0, 1, 0, 0), x[0, 0]
41
- assert_equal color(1, 0, 0, 0), o[0, 0]
38
+ assert_equal color(1, 0, 0, 1), x[0, 0]
39
+ x[0, 0] = color(0, 1, 0, 1)
40
+ assert_equal color(0, 1, 0, 1), x[0, 0]
41
+ assert_equal color(1, 0, 0, 1), o[0, 0]
42
42
  end
43
43
 
44
44
  def test_bitmap()
@@ -46,6 +46,13 @@ class TestImage < Test::Unit::TestCase
46
46
  assert_equal 10, image(20, 10).bitmap.height
47
47
  end
48
48
 
49
+ def test_draw_bgra_image()
50
+ img = Rays::Image.new Rays::Bitmap.new(1, 1, Rays::ColorSpace.new(:BGRA))
51
+ img[0, 0] = color 1, 0, 0, 1
52
+ assert_equal color(1, 0, 0, 1), img[0, 0]
53
+ assert_equal [0xffff0000], image(1, 1).paint {image img}.pixels
54
+ end
55
+
49
56
  def test_bitmap_with_modify_flag()
50
57
  img1 = image 1, 1
51
58
  update_texture img1
@@ -98,6 +105,22 @@ class TestImage < Test::Unit::TestCase
98
105
  assert drawn.call {|p| p.text "a"}
99
106
  end
100
107
 
108
+ def test_frozen()
109
+ img = image(2, 1).freeze
110
+ assert_equal color(0, 0, 0, 0), img[0, 0]
111
+ assert_equal [0x00000000, 0x00000000], img.pixels
112
+ assert_raise(FrozenError) {img.paint {}}
113
+ assert_raise(FrozenError) {img[0, 0] = color 1, 0, 0, 1}
114
+ assert_raise(FrozenError) {img.pixels = [0xffff0000, 0xff00ff00]}
115
+ assert_raise(FrozenError) {img.smooth = true}
116
+
117
+ dup = img.dup
118
+ assert_false dup.frozen?
119
+ dup[0, 0] = color 1, 0, 0, 1
120
+ assert_equal color(1, 0, 0, 1), dup[0, 0]
121
+ assert_equal color(0, 0, 0, 0), img[0, 0]
122
+ end
123
+
101
124
  def test_save_load()
102
125
  get_image_type = -> filename {
103
126
  `file #{filename}`.match(/#{filename}: ([^,]+),/)[1]
data/test/test_painter.rb CHANGED
@@ -379,6 +379,45 @@ class TestPainter < Test::Unit::TestCase
379
379
  end
380
380
  end
381
381
 
382
+ def test_alpha_blending()
383
+ i = image bg: color(0, 0, 0, 0) do
384
+ fill 1, 1, 1, 0.5
385
+ rect 0, 0, 2
386
+ end
387
+ assert_rgba [1, 1, 1, 0.5], i[0, 0]
388
+
389
+ i = image bg: color(0, 1, 0) do
390
+ fill 1, 1, 1, 0.5
391
+ rect 0, 0, 2
392
+ end
393
+ assert_rgba [0.5, 1, 0.5, 1], i[0, 0]
394
+ end
395
+
396
+ def test_alpha_accumulation()
397
+ i = image bg: color(0, 0, 0, 0) do
398
+ fill 1, 1, 1, 0.5
399
+ rect 0, 0, 2
400
+ rect 0, 0, 2
401
+ end
402
+ assert_rgba [1, 1, 1, 0.75], i[0, 0]
403
+ end
404
+
405
+ def test_clear_with_alpha()
406
+ i = image bg: color(1, 0, 0, 0.5)
407
+ assert_rgba [1, 0, 0, 0.5], i[0, 0]
408
+ end
409
+
410
+ def test_image_with_alpha()
411
+ src = image bg: color(0, 0, 0, 0) do
412
+ fill 1, 1, 1, 0.5
413
+ rect 0, 0, 16
414
+ end
415
+ i = image bg: color(0, 1, 0) do
416
+ image src, 0, 0
417
+ end
418
+ assert_rgba [0.5, 1, 0.5, 1], i[0, 0]
419
+ end
420
+
382
421
  def test_push()
383
422
  pa = painter
384
423
  pa.fill = [1, 0, 0]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rays
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - xordog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-04 00:00:00.000000000 Z
11
+ date: 2026-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xot
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.4.0
19
+ version: 0.5.0
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.4.0
26
+ version: 0.5.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rucy
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.4.0
33
+ version: 0.5.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.4.0
40
+ version: 0.5.0
41
41
  description: This library helps you to develop graphics application with OpenGL.
42
42
  email: xordog@gmail.com
43
43
  executables: []
@@ -85,7 +85,6 @@ files:
85
85
  - ".github/workflows/release-gem.yml"
86
86
  - ".github/workflows/tag.yml"
87
87
  - ".github/workflows/test.yml"
88
- - ".github/workflows/utils.rb"
89
88
  - CLAUDE.md
90
89
  - CONTRIBUTING.md
91
90
  - ChangeLog.md
@@ -170,6 +169,7 @@ files:
170
169
  - lib/rays/polyline.rb
171
170
  - lib/rays/shader.rb
172
171
  - rays.gemspec
172
+ - src/bitmap.cpp
173
173
  - src/bitmap.h
174
174
  - src/bounds.cpp
175
175
  - src/color.cpp
@@ -272,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
272
  - !ruby/object:Gem::Version
273
273
  version: '0'
274
274
  requirements: []
275
- rubygems_version: 3.4.19
275
+ rubygems_version: 3.5.22
276
276
  signing_key:
277
277
  specification_version: 4
278
278
  summary: A Drawing Engine using OpenGL.
@@ -1,127 +0,0 @@
1
- require 'shellwords'
2
-
3
- ALL_REPO = 'xord/all'
4
- ALL_DIR = '../all'
5
- ALL_FETCH_DEPTH = 100
6
-
7
- RENAMES = {reflex: 'reflexion'}
8
-
9
- def sh(cmd)
10
- puts cmd
11
- system cmd
12
- end
13
-
14
- def setup_dependencies(only: nil)
15
- gemspec_path = `git ls-files`.lines(chomp: true).find {|l| l =~ /\.gemspec$/}
16
- return unless gemspec_path
17
-
18
- gemspec = File.read gemspec_path
19
- name = File.basename gemspec_path, '.gemspec'
20
-
21
- exts = File.readlines('Rakefile')
22
- .map {|l| l[%r|^\s*require\W+([\w\-\_]+)/extension\W+$|, 1]}
23
- .compact
24
- .reject {|ext| ext == name}
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
76
-
77
- def setup_dependencies_via_each_repo_by_version(gemspec, exts)
78
- exts.each do |ext|
79
- gem = RENAMES[ext.to_sym].then {|s| s || ext}
80
- ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s*~>\s*([\d\.]+)\s*['"]/, 1]
81
- opts = '-c advice.detachedHead=false --depth 1'
82
- clone = "git clone #{opts} https://github.com/xord/#{ext}.git ../#{ext}"
83
-
84
- # 'rake subtree:push' pushes all subrepos, so cloning by new tag
85
- # often fails before tagging each new tag
86
- sh %( #{clone} --branch v#{ver} || #{clone} )
87
- end
88
- end
89
-
90
- def tag_versions()
91
- changes = changelogs
92
- tags = `git tag`.lines chomp: true
93
- vers = `git log --oneline ./VERSION`
94
- .lines(chomp: true)
95
- .map {|line| line.split.first[/^\w+$/]}
96
- .map {|sha| [`git cat-file -p #{sha}:./VERSION 2>/dev/null`[/[\d\.]+/], sha]}
97
- .select {|ver, sha| ver && sha}
98
- .reverse
99
- .to_h
100
-
101
- vers.to_a.reverse.each do |ver, sha|
102
- tag = "v#{ver}"
103
- break if tags.include?(tag)
104
- sh %( git tag -a -m \"#{changes[tag]&.gsub '"', '\\"'}\" #{tag} #{sha} )
105
- end
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