spawnpoint 0.2.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 +7 -0
- data/.gitignore +5 -0
- data/Gemfile +8 -0
- data/LICENSE +21 -0
- data/README.md +153 -0
- data/Rakefile +10 -0
- data/docs/2026-08-14-spawnpoint-gem-design.md +90 -0
- data/docs/2026-08-15-spawnpoint-gem-plan.md +1223 -0
- data/exe/spwn +6 -0
- data/lib/spawnpoint/cli.rb +342 -0
- data/lib/spawnpoint/synchronizer.rb +244 -0
- data/lib/spawnpoint/version.rb +5 -0
- data/lib/spawnpoint.rb +4 -0
- data/spawnpoint.gemspec +26 -0
- data/test/test_cli.rb +38 -0
- data/test/test_helper.rb +2 -0
- data/test/test_synchronizer.rb +95 -0
- data/test/test_version.rb +12 -0
- metadata +59 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "tmpdir"
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "spawnpoint/synchronizer"
|
|
5
|
+
|
|
6
|
+
class TestSynchronizer < Minitest::Test
|
|
7
|
+
def setup
|
|
8
|
+
@dir = Dir.mktmpdir
|
|
9
|
+
@lesson = File.join(@dir, "lesson")
|
|
10
|
+
@game = File.join(@dir, "game")
|
|
11
|
+
FileUtils.mkdir_p(@lesson)
|
|
12
|
+
FileUtils.mkdir_p(@game)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def teardown
|
|
16
|
+
FileUtils.remove_entry(@dir)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def write(folder, name, content)
|
|
20
|
+
File.write(File.join(folder, name), content)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def sync(*extra)
|
|
24
|
+
Spawnpoint::Synchronizer.new.run([@lesson, "--into", @game, *extra])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def marker_paths
|
|
28
|
+
marker = File.join(@game, ".spwn_synced_paths")
|
|
29
|
+
File.exist?(marker) ? File.readlines(marker).map(&:strip) : []
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_run_without_arguments_exits_one
|
|
33
|
+
capture_io { @status = Spawnpoint::Synchronizer.new.run([]) }
|
|
34
|
+
assert_equal 1, @status
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_run_without_into_exits_one
|
|
38
|
+
capture_io { @status = Spawnpoint::Synchronizer.new.run([@lesson]) }
|
|
39
|
+
assert_equal 1, @status
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_run_with_missing_source_exits_one
|
|
43
|
+
capture_io { @status = Spawnpoint::Synchronizer.new.run(["nope", "--into", @game]) }
|
|
44
|
+
assert_equal 1, @status
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_copies_new_files
|
|
48
|
+
write(@lesson, "main.rb", "puts :hi")
|
|
49
|
+
capture_io { @status = sync }
|
|
50
|
+
assert_equal 0, @status
|
|
51
|
+
assert_equal "puts :hi", File.read(File.join(@game, "main.rb"))
|
|
52
|
+
assert_includes marker_paths, "main.rb"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_force_replaces_existing_file
|
|
56
|
+
write(@game, "main.rb", "old")
|
|
57
|
+
write(@lesson, "main.rb", "new")
|
|
58
|
+
capture_io { @status = sync("--force") }
|
|
59
|
+
assert_equal 0, @status
|
|
60
|
+
assert_equal "new", File.read(File.join(@game, "main.rb"))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_rollback_restores_replaced_and_removes_created_files
|
|
64
|
+
write(@game, "main.rb", "old")
|
|
65
|
+
write(@lesson, "main.rb", "new")
|
|
66
|
+
write(@lesson, "enemy.rb", "enemy code")
|
|
67
|
+
capture_io { sync("--force") }
|
|
68
|
+
assert_equal "new", File.read(File.join(@game, "main.rb"))
|
|
69
|
+
|
|
70
|
+
capture_io { @status = Spawnpoint::Synchronizer.new.rollback(["--into", @game]) }
|
|
71
|
+
assert_equal 0, @status
|
|
72
|
+
assert_equal "old", File.read(File.join(@game, "main.rb"))
|
|
73
|
+
refute File.exist?(File.join(@game, "enemy.rb"))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_rollback_without_backup_exits_one
|
|
77
|
+
capture_io { @status = Spawnpoint::Synchronizer.new.rollback(["--into", @game]) }
|
|
78
|
+
assert_equal 1, @status
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_marker_keeps_paths_accepted_in_earlier_lessons
|
|
82
|
+
# Lesson 1 introduces main.rb.
|
|
83
|
+
write(@lesson, "main.rb", "v1")
|
|
84
|
+
capture_io { sync }
|
|
85
|
+
assert_includes marker_paths, "main.rb"
|
|
86
|
+
|
|
87
|
+
# Lesson 2 introduces only enemy.rb; main.rb must not be forgotten.
|
|
88
|
+
FileUtils.rm(File.join(@lesson, "main.rb"))
|
|
89
|
+
write(@lesson, "enemy.rb", "enemy code")
|
|
90
|
+
capture_io { sync }
|
|
91
|
+
|
|
92
|
+
assert_includes marker_paths, "main.rb"
|
|
93
|
+
assert_includes marker_paths, "enemy.rb"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "spawnpoint/version"
|
|
3
|
+
|
|
4
|
+
class TestVersion < Minitest::Test
|
|
5
|
+
def test_version_format
|
|
6
|
+
assert_match(/\A\d+\.\d+\.\d+\z/, Spawnpoint::VERSION)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_version_is_0_2_0
|
|
10
|
+
assert_equal "0.2.0", Spawnpoint::VERSION
|
|
11
|
+
end
|
|
12
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: spawnpoint
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- bebekim
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: spwn is a thin wrapper around Git that renames Git commands into friendlier,
|
|
13
|
+
game-like language for kids learning game programming.
|
|
14
|
+
executables:
|
|
15
|
+
- spwn
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- ".gitignore"
|
|
20
|
+
- Gemfile
|
|
21
|
+
- LICENSE
|
|
22
|
+
- README.md
|
|
23
|
+
- Rakefile
|
|
24
|
+
- docs/2026-08-14-spawnpoint-gem-design.md
|
|
25
|
+
- docs/2026-08-15-spawnpoint-gem-plan.md
|
|
26
|
+
- exe/spwn
|
|
27
|
+
- lib/spawnpoint.rb
|
|
28
|
+
- lib/spawnpoint/cli.rb
|
|
29
|
+
- lib/spawnpoint/synchronizer.rb
|
|
30
|
+
- lib/spawnpoint/version.rb
|
|
31
|
+
- spawnpoint.gemspec
|
|
32
|
+
- test/test_cli.rb
|
|
33
|
+
- test/test_helper.rb
|
|
34
|
+
- test/test_synchronizer.rb
|
|
35
|
+
- test/test_version.rb
|
|
36
|
+
homepage: https://github.com/bebekim/spawnpoint
|
|
37
|
+
licenses:
|
|
38
|
+
- MIT
|
|
39
|
+
metadata:
|
|
40
|
+
source_code_uri: https://github.com/bebekim/spawnpoint
|
|
41
|
+
rubygems_mfa_required: 'true'
|
|
42
|
+
rdoc_options: []
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '3.0'
|
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
requirements: []
|
|
56
|
+
rubygems_version: 4.0.16
|
|
57
|
+
specification_version: 4
|
|
58
|
+
summary: A child-friendly Git mask for learning game programming
|
|
59
|
+
test_files: []
|