sscharter 0.7.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: 1695717274c0888590e92f6a3dabf86fca4a2d34aaad9f17dc9a88ab20311207
4
- data.tar.gz: 78096695809b63551d5f48a3c11d4120ead84157c1146b4064a9f8f1262b66c7
3
+ metadata.gz: bd7619bb9674b4ec547ba0484ff931c1f39603ffa03fc0a32e826ef4e83adb46
4
+ data.tar.gz: 668322b1a02019b1ebfad49332cea047c8cd91f5f2de62be88a68dc64460a88c
5
5
  SHA512:
6
- metadata.gz: 8e64530c4c426710eae970e9bd7fd4609d307a75102cdea4920f9ed5ae8208313cc48efae86c545b95cdecaec79e6da6738d92d5db1f8861ea142b3f2b843c88
7
- data.tar.gz: 64725aa5bf3336f3ab3965f583cf4ed80e02296a18a1be9c1427542d9bc79164b602f99b19a2c7f45e243d32e8456911940971ffd3794e8027ec6e4db17d5221
6
+ metadata.gz: ec041e5ebef20b6e9794a91b842ef7446305732564bdf6e8afd25e4d5a2281d9b6cbb37787a11cee7ce29d2a581aa31bbdf513bdb9f0661f5498e4b412ea26f9
7
+ data.tar.gz: 9e10bf1ef26b57f7cade038f5cc5cf290aa14b72050c6c3136f96a0c0511dff2ce43300a0b81fb66c0d75deda496ba1da4a13a174ff53f36b2ffb6cbc4f883ad
data/Gemfile CHANGED
@@ -2,17 +2,4 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- # Specify your gem's dependencies in sscharter.gemspec
6
5
  gemspec
7
-
8
- group :develop do
9
- gem 'rake', '~> 13.0'
10
- gem 'minitest', '~> 5.0'
11
- end
12
-
13
- gem 'rubyzip', '~> 2.3'
14
- gem 'launchy', '~> 2.5'
15
- gem 'webrick', '~> 1.8'
16
- gem 'filewatcher', '~> 2.0'
17
- gem 'em-websocket', '~> 0.5'
18
- gem 'concurrent-ruby', '~> 1.3'
data/Gemfile.lock CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sscharter (0.7.0)
4
+ sscharter (0.9.0)
5
+ base64
5
6
  concurrent-ruby (~> 1.3)
6
7
  em-websocket (~> 0.5)
7
8
  filewatcher (~> 2.0)
8
9
  launchy (~> 2.5)
9
- rubyzip (~> 2.3)
10
+ rubyzip (~> 3.1)
10
11
  webrick (~> 1.8)
11
12
 
12
13
  GEM
@@ -14,7 +15,8 @@ GEM
14
15
  specs:
15
16
  addressable (2.8.7)
16
17
  public_suffix (>= 2.0.2, < 7.0)
17
- concurrent-ruby (1.3.4)
18
+ base64 (0.3.0)
19
+ concurrent-ruby (1.3.5)
18
20
  em-websocket (0.5.3)
19
21
  eventmachine (>= 0.12.9)
20
22
  http_parser.rb (~> 0)
@@ -24,27 +26,23 @@ GEM
24
26
  http_parser.rb (0.8.0)
25
27
  launchy (2.5.2)
26
28
  addressable (~> 2.8)
27
- minitest (5.25.1)
29
+ minitest (5.25.5)
28
30
  module_methods (0.1.0)
29
- public_suffix (6.0.1)
30
- rake (13.2.1)
31
- rubyzip (2.3.2)
32
- webrick (1.8.1)
31
+ public_suffix (6.0.2)
32
+ rake (13.3.0)
33
+ rubyzip (3.1.0)
34
+ webrick (1.9.1)
35
+ yard (0.9.37)
33
36
 
34
37
  PLATFORMS
35
38
  x64-mingw-ucrt
36
39
  x86_64-linux
37
40
 
38
41
  DEPENDENCIES
39
- concurrent-ruby (~> 1.3)
40
- em-websocket (~> 0.5)
41
- filewatcher (~> 2.0)
42
- launchy (~> 2.5)
43
42
  minitest (~> 5.0)
44
43
  rake (~> 13.0)
45
- rubyzip (~> 2.3)
46
44
  sscharter!
47
- webrick (~> 1.8)
45
+ yard (~> 0.9)
48
46
 
49
47
  BUNDLED WITH
50
- 2.5.17
48
+ 2.7.1
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 sunniesnow
3
+ Copyright (c) 2025 sunniesnow
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,4 +1,4 @@
1
- # Sscharter
1
+ # sscharter
2
2
 
3
3
  A Ruby DSL for writing Sunniesnow charts.
4
4
 
@@ -7,7 +7,7 @@ A Ruby DSL for writing Sunniesnow charts.
7
7
  [Install Ruby](https://www.ruby-lang.org/en/documentation/installation/).
8
8
  Then, run
9
9
 
10
- ```shell
10
+ ```
11
11
  gem install sscharter
12
12
  ```
13
13
 
@@ -27,4 +27,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/sunnie
27
27
 
28
28
  ## Code of Conduct
29
29
 
30
- Everyone interacting in the Sscharter project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/sscharter/blob/master/CODE_OF_CONDUCT.md).
30
+ Everyone interacting in the sscharter project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/sunniesnow/sscharter/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,12 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rake/testtask"
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+ require 'yard'
5
6
 
6
- Rake::TestTask.new(:test) do |t|
7
- t.libs << "test"
8
- t.libs << "lib"
9
- t.test_files = FileList["test/**/test_*.rb"]
7
+ Rake::TestTask.new :test do |t|
8
+ t.libs << 'test'
9
+ t.libs << 'lib'
10
+ t.test_files = FileList['test/**/test_*.rb']
11
+ end
12
+
13
+ YARD::Rake::YardocTask.new do |t|
14
+ t.files.concat %w[README.md]
15
+ t.options.concat %w[--title sscharter --output-dir doc --exclude lib/sscharter/cli.rb --readme]
10
16
  end
11
17
 
12
18
  task default: :test
@@ -2,14 +2,41 @@
2
2
 
3
3
  require 'json'
4
4
 
5
+ # A class to represent a chart.
6
+ # Basically a wrapper around the metadata and events ({Sunniesnow::Event}) of a chart.
7
+ # The main method is {#to_json}, which converts the chart to a JSON string
8
+ # that is actually recognizable by Sunniesnow.
5
9
  class Sunniesnow::Chart
6
10
 
7
11
  using Sunniesnow::Utils
8
12
 
9
- attr_accessor :title, :artist, :charter
10
- attr_accessor :difficulty_name, :difficulty_color, :difficulty, :difficulty_sup
13
+ # The schema URL for the output JSON.
14
+ # This will be set as the `$schema` property in the generated JSON.
15
+ SCHEMA = 'https://sunniesnow.github.io/schema/chart-1.0.json'
16
+
17
+ # The title of the music.
18
+ # This is one of the metadata of the chart which will be reflected in the generated JSON.
19
+ # Also, see
20
+ # {chart file specifications}[https://sunniesnow.github.io/doc/chart.html#title]
21
+ # for more info.
22
+ attr_accessor :title
23
+
24
+ attr_accessor :artist
25
+ attr_accessor :charter
26
+ attr_accessor :difficulty_name
27
+ attr_accessor :difficulty_color
28
+ attr_accessor :difficulty
29
+ attr_accessor :difficulty_sup
30
+
31
+ # An array of Sunniesnow::Event.
11
32
  attr_reader :events
12
33
 
34
+ # @param [Integer] live_reload_port The port to use for live reload.
35
+ # It is useless if +production+ is +true+.
36
+ # @param [Boolean] production Whether the chart is in production or not.
37
+ # If +true+, the generated JSON (see {#to_json}) will not contain
38
+ # necessary information for sscharter integration in Sunniesnow
39
+ # (such as the live reload feature and reverse search feature).
13
40
  def initialize live_reload_port: 31108, production: false
14
41
  @title = ''
15
42
  @artist = ''
@@ -23,8 +50,13 @@ class Sunniesnow::Chart
23
50
  @production = production
24
51
  end
25
52
 
53
+ ##
54
+ # Convert to JSON.
55
+ # A Sunniesnow chart is always a JSON file in the level file.
56
+ # This method is used to generate that JSON file.
26
57
  def to_json *args
27
58
  hash = {
59
+ '$schema': SCHEMA,
28
60
  title: @title,
29
61
  artist: @artist,
30
62
  charter: @charter,
@@ -38,7 +70,7 @@ class Sunniesnow::Chart
38
70
  version: Sunniesnow::Charter::VERSION,
39
71
  port: @live_reload_port
40
72
  } unless @production
41
- hash.to_json
73
+ hash.to_json *args
42
74
  end
43
75
  end
44
76
 
data/lib/sscharter/cli.rb CHANGED
@@ -22,13 +22,12 @@ module Sunniesnow
22
22
  module_function
23
23
 
24
24
  def config
25
- config_filename = File.join PROJECT_DIR, '.sscharter.yml'
26
- config_filename = File.join PROJECT_DIR, '.sscharter.yaml' unless File.exist? config_filename
27
- unless File.exist? config_filename
28
- puts 'No .sscharter.yml found'
25
+ filenames = %w[sscharter.yml sscharter.yaml .sscharter.yml .sscharter.yaml].map { File.join PROJECT_DIR, _1 }
26
+ unless filename = filenames.find { File.exist? _1 }
27
+ $stderr.puts 'Config file sscharter.yml not found'
29
28
  return nil
30
29
  end
31
- YAML.load_file config_filename, symbolize_names: true
30
+ YAML.load_file filename, symbolize_names: true
32
31
  end
33
32
 
34
33
  singleton_class.attr_reader :commands
@@ -87,20 +86,18 @@ Sunniesnow::Charter::CLI::Subcommand.new :init, option_parser do |project_dir =
87
86
  FileUtils.cp_r files, files_dir
88
87
  FileUtils.cd project_dir do
89
88
  File.write 'Gemfile', <<~GEMFILE
90
- # frozen_string_literal: true
91
89
  source 'https://rubygems.org'
92
90
  gem 'sscharter', '~> #{Sunniesnow::Charter::VERSION}'
93
91
  gem 'rake', '~> #{Rake::VERSION}'
94
92
  gem 'bundler', '~> #{Bundler::VERSION}'
95
93
  GEMFILE
96
94
  File.write 'Rakefile', <<~RAKEFILE
97
- # frozen_string_literal: true
98
95
  task default: :build
99
96
  task :build do
100
97
  exec 'bundle exec sscharter build'
101
98
  end
102
99
  task :serve do
103
- exec 'bundle exec sscharter serve'
100
+ exec 'bundle exec sscharter serve --no-open-browser'
104
101
  end
105
102
  RAKEFILE
106
103
  File.write '.gitignore', <<~GITIGNORE
@@ -108,7 +105,7 @@ Sunniesnow::Charter::CLI::Subcommand.new :init, option_parser do |project_dir =
108
105
  /tmp/
109
106
  /build/
110
107
  GITIGNORE
111
- File.write '.sscharter.yml', <<~SSCHARTER
108
+ File.write 'sscharter.yml', <<~SSCHARTER
112
109
  ---
113
110
  project_name: #{File.basename project_dir}
114
111
  build_dir: build
@@ -136,21 +133,19 @@ Sunniesnow::Charter::CLI::Subcommand.new :init, option_parser do |project_dir =
136
133
  README
137
134
  FileUtils.mkdir_p 'src'
138
135
  File.write 'src/master.rb', <<~CHART
139
- # frozen_string_literal: true
140
-
141
136
  Sunniesnow::Charter.open 'master' do
142
137
 
143
138
  title 'The title of the music'
144
139
  artist 'The artist of the music'
145
140
  charter 'Your name'
146
141
  difficulty_name 'Master'
147
- difficulty_color '#8c68f3'
142
+ difficulty_color :master
148
143
  difficulty '12'
149
144
 
150
145
  offset 0
151
146
  bpm 120
152
147
 
153
- tp_chain 0, 0, 1 do
148
+ tp_chain 0, 100, 1 do
154
149
  t -50, 0, 'hello'
155
150
  b 1 # proceed by 1 beat
156
151
  t 50, 0, 'world'
@@ -162,7 +157,7 @@ Sunniesnow::Charter::CLI::Subcommand.new :init, option_parser do |project_dir =
162
157
  puts "Project initialized at #{project_dir}"
163
158
  end
164
159
 
165
- def build **opts
160
+ def build compression_level: Zip.default_compression, **opts, &block
166
161
  return 1 unless config = Sunniesnow::Charter::CLI.config
167
162
  dir = Sunniesnow::Charter::PROJECT_DIR
168
163
  project_name = config[:project_name] || File.basename(dir)
@@ -171,17 +166,21 @@ def build **opts
171
166
  sources_dir = File.join dir, config[:sources_dir] || 'src'
172
167
  include_files = (config[:include] || []).map { File.join dir, _1 }
173
168
  Sunniesnow::Charter.charts.clear
169
+ time = Time.now
174
170
  Dir.glob File.join sources_dir, '*.rb' do |filename|
175
171
  load filename
176
172
  rescue Exception => e
177
173
  puts "Error loading #{filename}:"
178
174
  puts e.full_message
175
+ puts "Build aborted (took #{Time.now - time} seconds)"
179
176
  return 1
180
177
  end
178
+ puts "Built #{Sunniesnow::Charter.charts.size} chart(s) (took #{Time.now - time} seconds)"
179
+ time = Time.now
181
180
  FileUtils.mkdir_p build_dir
182
181
  build_filename = File.join build_dir, "#{project_name}.ssc"
183
182
  FileUtils.rm build_filename if File.exist? build_filename
184
- Zip::File.open build_filename, create: true do |zip_file|
183
+ Zip::File.open build_filename, compression_level:, create: true do |zip_file|
185
184
  Dir.glob File.join files_dir, '**', '*' do |filename|
186
185
  zip_file.add filename["#{files_dir}/".length..], filename
187
186
  end
@@ -192,25 +191,33 @@ def build **opts
192
191
  end
193
192
  Sunniesnow::Charter.charts.each do |name, chart|
194
193
  begin
195
- output = chart.output_json **opts
194
+ sunniesnow_chart = chart.to_sunniesnow **opts
196
195
  rescue => e
197
196
  puts 'An error happened. Report if this is a bug of sscharter.'
198
197
  puts e.full_message
199
198
  return 2
200
199
  end
200
+ block.(name, sunniesnow_chart) if block
201
201
  zip_file.get_output_stream "#{name}.json" do |file|
202
- file.write output
202
+ file.write sunniesnow_chart.to_json
203
+ rescue => e
204
+ puts 'An error happened. Report if this is a bug of sscharter.'
205
+ puts e.full_message
206
+ return 2
203
207
  end
204
208
  end
209
+ zip_file.each { _1.time = Time.at 0 }
205
210
  end
211
+ puts "Created #{project_name}.ssc (took #{Time.now - time} seconds)"
206
212
  0
207
213
  end
208
214
 
209
215
  option_parser = OptionParser.new do |o|
210
216
  o.banner = 'Usage: sscharter build'
217
+ o.on '--compression-level=LEVEL', Integer, 'Compression level (0-9)'
211
218
  end
212
- Sunniesnow::Charter::CLI::Subcommand.new :build, option_parser do
213
- build production: true
219
+ Sunniesnow::Charter::CLI::Subcommand.new :build, option_parser do |compression_level: Zip.default_compression|
220
+ build compression_level:, production: true
214
221
  end
215
222
 
216
223
  option_parser = OptionParser.new do |o|
@@ -221,8 +228,17 @@ option_parser = OptionParser.new do |o|
221
228
  o.on '--live-reload-port=PORT', Integer, 'live reload port number'
222
229
  o.on '--[no-]production', 'Disable live reload'
223
230
  o.on '--[no-]open-browser', 'Open browser'
231
+ o.on '--compression-level=LEVEL', Integer, 'Compression level (0-9)'
224
232
  end
225
- Sunniesnow::Charter::CLI::Subcommand.new :serve, option_parser do |host: '0.0.0.0', exposed_host: 'localhost', port: 8011, live_reload_port: 31108, production: false, open_browser: true|
233
+ Sunniesnow::Charter::CLI::Subcommand.new :serve, option_parser do |\
234
+ host: '0.0.0.0',
235
+ exposed_host: 'localhost',
236
+ port: 8011,
237
+ live_reload_port: 31108,
238
+ production: false,
239
+ open_browser: true,
240
+ compression_level: (production ? Zip.default_compression : 0)
241
+ |
226
242
  return 1 unless config = Sunniesnow::Charter::CLI.config
227
243
  dir = Sunniesnow::Charter::PROJECT_DIR
228
244
  project_name = config[:project_name] || File.basename(dir)
@@ -268,18 +284,23 @@ Sunniesnow::Charter::CLI::Subcommand.new :serve, option_parser do |host: '0.0.0.
268
284
  end
269
285
  end
270
286
  end
271
- url = "http://#{exposed_host}:#{port}/#{project_name}.ssc"
287
+ base_url = "http://#{exposed_host}:#{port}"
288
+ url = URI.join base_url, "#{project_name}.ssc"
272
289
  filewatcher = Filewatcher.new [files_dir, sources_dir, *include_files]
273
290
  Launchy.open "https://sunniesnow.github.io/game/?level-file=online&level-file-online=#{CGI.escape url}" if open_browser
274
- build_proc = ->is_first do
291
+ build_proc = ->is_first, only_charts do
275
292
  puts is_first ? 'Building...' : 'Rebuilding...'
276
- success = build(live_reload_port:, production:) == 0
277
- puts success ? is_first ? "Finished; access at #{url}" : 'Finished' : 'Failed'
278
- live_reload_clients.each { _1.send JSON.generate type: 'update' } unless production
293
+ build_result = build(live_reload_port:, production:, compression_level:) do |name, chart|
294
+ live_reload_clients.each { _1.send JSON.generate type: 'chartUpdate', name:, chart: } unless production
295
+ end
296
+ puts build_result == 0 ? is_first ? "Finished; access at #{url}" : 'Finished' : 'Failed'
297
+ live_reload_clients.each { _1.send JSON.generate type: 'update', onlyCharts: only_charts } unless production
279
298
  end
280
299
  filewatcher_thread = Thread.new do
281
- build_proc.(true)
282
- filewatcher.watch { |changes| build_proc.(false) }
300
+ build_proc.(true, false)
301
+ filewatcher.watch do |changes|
302
+ build_proc.(false, changes.all? { |filename, event| filename.start_with? sources_dir + '/' })
303
+ end
283
304
  server.shutdown
284
305
  EM.stop unless production
285
306
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sunniesnow
4
4
  class Charter
5
- VERSION = "0.7.0"
5
+ VERSION = "0.9.0"
6
6
  end
7
7
  end