squared 0.4.0 → 0.4.1
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 +4 -4
- data/CHANGELOG.md +32 -2
- data/README.ruby.md +5 -2
- data/lib/squared/common/format.rb +11 -6
- data/lib/squared/common/utils.rb +14 -1
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/project/base.rb +8 -2
- data/lib/squared/workspace/project/docker.rb +63 -13
- data/lib/squared/workspace/project/git.rb +35 -11
- data/lib/squared/workspace/project/node.rb +0 -2
- data/lib/squared/workspace/project/python.rb +0 -1
- data/lib/squared/workspace/project/ruby.rb +2 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0ee3da01c8f4091c2363f6c8b0821cbc742d7dd95a4fda4e6a26e949ce0c61f
|
4
|
+
data.tar.gz: 4642f0e308608a80077cddb81ecc3c03ff58a6baaa066b644c1ae8b922d13668
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33f08fcd47d1ac5896a5cc231e8466de17f2edbd2d987fb411c21b8db8cf734b880fefbb4454a69e610a35aa86609e94bac4dc44264e3a10a3cd69efd6429186
|
7
|
+
data.tar.gz: 5e424cb159c5a00512eca6ea9d8a0328082ecb85a30c9e769cd67bbd21d95b16a5d6f906a22a2f2c2d9fecbad5da2721ee1cc4b09722ffbdcbbcbb0a39d0c985
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.4.1] - 2025-03-20
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Status logger messages are written to file.
|
8
|
+
- Docker command image action push was implemented.
|
9
|
+
- Git command show action textconv was implemented.
|
10
|
+
- Docker mounts for container command run is supported.
|
11
|
+
|
12
|
+
### Removed
|
13
|
+
|
14
|
+
- Git batch commands pull+s and rebase+s were removed.
|
15
|
+
|
16
|
+
## [0.3.6] - 2025-03-12
|
17
|
+
|
18
|
+
### Added
|
19
|
+
|
20
|
+
- Git command stash action clear was implemented.
|
21
|
+
|
22
|
+
### Fixed
|
23
|
+
|
24
|
+
- Git command stash did not validate index argument.
|
25
|
+
- Project graph command does not require arguments.
|
26
|
+
- Ruby gem command exec did not add project name.
|
27
|
+
|
3
28
|
## [0.4.0] - 2025-03-06
|
4
29
|
|
5
30
|
### Added
|
@@ -37,13 +62,16 @@
|
|
37
62
|
|
38
63
|
- Node copy method will only override when key exists.
|
39
64
|
- Base command copy and clean can accept a hash.
|
40
|
-
- Character methods in Shell common module were removed.
|
41
65
|
- ENV build options are merged with base options.
|
42
|
-
- Git command diff action cached was removed.
|
43
66
|
- Git log and diff uses H0 alias for HEAD~n commit.
|
44
67
|
- Project events support multiple associated routines.
|
45
68
|
- Git command restore was relocated to "git" task namespace.
|
46
69
|
|
70
|
+
### Removed
|
71
|
+
|
72
|
+
- Character methods in Shell common module were removed.
|
73
|
+
- Git command diff action cached was removed.
|
74
|
+
|
47
75
|
### Fixed
|
48
76
|
|
49
77
|
- Git base class did not check for null Logger instance.
|
@@ -352,7 +380,9 @@
|
|
352
380
|
|
353
381
|
- Changelog was created.
|
354
382
|
|
383
|
+
[0.4.1]: https://github.com/anpham6/squared/releases/tag/v0.4.1-ruby
|
355
384
|
[0.4.0]: https://github.com/anpham6/squared/releases/tag/v0.4.0-ruby
|
385
|
+
[0.3.6]: https://github.com/anpham6/squared/releases/tag/v0.3.6-ruby
|
356
386
|
[0.3.5]: https://github.com/anpham6/squared/releases/tag/v0.3.5-ruby
|
357
387
|
[0.3.4]: https://github.com/anpham6/squared/releases/tag/v0.3.4-ruby
|
358
388
|
[0.3.3]: https://github.com/anpham6/squared/releases/tag/v0.3.3-ruby
|
data/README.ruby.md
CHANGED
@@ -105,8 +105,11 @@ Workspace::Application
|
|
105
105
|
variable_set :clean, ["build/sqd/"]
|
106
106
|
end
|
107
107
|
.with(:docker, pass: ["unpack"]) do
|
108
|
-
.add("squared", "docker", file: "Dockerfile", context: ".", tag: "latest",
|
109
|
-
|
108
|
+
.add("squared", "docker", file: "Dockerfile", context: ".", tag: "latest", registry: "localhost:5000", username: "squared",
|
109
|
+
args: "--ssh=default",
|
110
|
+
secrets: ["id=github,env=GITHUB_TOKEN"],
|
111
|
+
mounts: ["src=.,dst=/project,ro,bind-propagation=rshared"]) do # Docker
|
112
|
+
series(:clean) do # run | depend | doc | lint | test | copy | clean
|
110
113
|
File.read(basepath("docker-bake.hcl"))
|
111
114
|
.scan(/\btags\s+=\s+\["([^"]+)"\]/)
|
112
115
|
.each { |val| image(:rm, tag: val.first) }
|
@@ -118,7 +118,7 @@ module Squared
|
|
118
118
|
if !val.is_a?(::Numeric)
|
119
119
|
val = val.to_sym
|
120
120
|
ret << val if colors.key?(val) || TEXT_STYLE.include?(val)
|
121
|
-
elsif val
|
121
|
+
elsif val.between?(0, 256)
|
122
122
|
ret << val
|
123
123
|
elsif val < 0 && (b = val.to_s.split('.')[1])
|
124
124
|
b = b[0, 3]
|
@@ -170,10 +170,15 @@ module Squared
|
|
170
170
|
color ? sub_style(ret, *styles) : ret
|
171
171
|
end
|
172
172
|
|
173
|
-
def log_message(level, *args, subject: nil, hint: nil, color: ARG[:COLOR], pass: false)
|
174
|
-
return false if !pass && level.is_a?(::Numeric) && level < ARG[:LEVEL]
|
175
|
-
|
173
|
+
def log_message(level, *args, subject: nil, hint: nil, color: ARG[:COLOR], append: true, pass: false)
|
176
174
|
args = args.map(&:to_s)
|
175
|
+
if level.is_a?(::Numeric)
|
176
|
+
if append && respond_to?(:log)
|
177
|
+
ref = log rescue nil
|
178
|
+
ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(Logger)
|
179
|
+
end
|
180
|
+
return false if !pass && level < ARG[:LEVEL]
|
181
|
+
end
|
177
182
|
if args.size > 1 && !hint
|
178
183
|
title = log_title(level, color: false)
|
179
184
|
sub = { pat: /^(#{title})(.+)$/, styles: __get__(:theme)[:logger][log_sym(level)] } if color
|
@@ -209,8 +214,8 @@ module Squared
|
|
209
214
|
|
210
215
|
module_function
|
211
216
|
|
212
|
-
def message(*args, hint: nil, empty: false)
|
213
|
-
(empty ? args.reject { |val| val.nil? || val.empty? } : args).join(
|
217
|
+
def message(*args, hint: nil, empty: false, space: ARG[:SPACE])
|
218
|
+
(empty ? args.reject { |val| val.nil? || val.empty? } : args).join(space) + (hint ? " (#{hint})" : '')
|
214
219
|
end
|
215
220
|
|
216
221
|
def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, border: nil, pipe: nil)
|
data/lib/squared/common/utils.rb
CHANGED
@@ -12,6 +12,19 @@ module Squared
|
|
12
12
|
val.split(/\s*(?<!\\)#{char}\s*/o)
|
13
13
|
end
|
14
14
|
|
15
|
+
def split_option(val)
|
16
|
+
val = val.strip
|
17
|
+
return [val, '', ''] unless (i = val.index('='))
|
18
|
+
|
19
|
+
last = val[i + 1..-1].strip
|
20
|
+
quote = ''
|
21
|
+
if last =~ /^(["'])(.+)\1$/
|
22
|
+
last = $2
|
23
|
+
quote = $1
|
24
|
+
end
|
25
|
+
[val[0..i - 1], last, quote]
|
26
|
+
end
|
27
|
+
|
15
28
|
def task_invoke(*cmd, args: [], exception: true, warning: true)
|
16
29
|
cmd.each { |name| Rake::Task[name].invoke(*args) }
|
17
30
|
rescue StandardError => e
|
@@ -141,7 +154,7 @@ module Squared
|
|
141
154
|
return ret.to_i
|
142
155
|
end
|
143
156
|
when ::Numeric
|
144
|
-
return key if key
|
157
|
+
return key if key.between?(0, 2)
|
145
158
|
end
|
146
159
|
default
|
147
160
|
end
|
data/lib/squared/version.rb
CHANGED
@@ -264,7 +264,7 @@ module Squared
|
|
264
264
|
|
265
265
|
format_desc action, flag, '(-)project*'
|
266
266
|
task flag do |_, args|
|
267
|
-
args =
|
267
|
+
args = args.to_a.reject { |val| name == val.to_s }
|
268
268
|
if flag == :run
|
269
269
|
graph args
|
270
270
|
else
|
@@ -871,7 +871,7 @@ module Squared
|
|
871
871
|
log&.warn "ENV was discarded: #{var}" if var
|
872
872
|
task_invoke(cmd, exception: exception, warning: warning?)
|
873
873
|
else
|
874
|
-
print_item format_banner(cmd, banner: banner) if sync
|
874
|
+
print_item format_banner(cmd, banner: banner) if sync && !env('BANNER', equals: '0')
|
875
875
|
args = var.is_a?(Hash) ? [var, cmd] : [cmd]
|
876
876
|
shell(*args, chdir: chdir, exception: exception)
|
877
877
|
end
|
@@ -970,7 +970,13 @@ module Squared
|
|
970
970
|
next if pass.include?(meth)
|
971
971
|
|
972
972
|
if workspace.task_defined?(cmd = task_join(proj.name, meth))
|
973
|
+
if ENV.key?(key = "BANNER_#{proj.name.upcase}")
|
974
|
+
key = nil
|
975
|
+
else
|
976
|
+
ENV[key] = '0'
|
977
|
+
end
|
973
978
|
run(cmd, sync: false, banner: false)
|
979
|
+
ENV.delete(key) if key
|
974
980
|
elsif proj.has?(meth, tasks || group ? nil : workspace.baseref)
|
975
981
|
proj.__send__(meth.to_sym, sync: sync)
|
976
982
|
end
|
@@ -42,7 +42,7 @@ module Squared
|
|
42
42
|
env-file=p expose=e gpus=q group-add=b health-cmd=q health-interval=b health-retries=i
|
43
43
|
health-start-interval=b health-start-period=b health-timeout=b h|hostname=e io-maxbandwidth=b
|
44
44
|
io-maxiops=b ip=b ip6=e ipc=b isolation=b kernel-memory=b l|label=q label-file=p link=b
|
45
|
-
link-local-ip=b log-driver=b log-opt=q mac-address=e memory-swappiness=b mount=
|
45
|
+
link-local-ip=b log-driver=b log-opt=q mac-address=e memory-swappiness=b mount=qq name=b network=b
|
46
46
|
network-alias=b oom-score-adj=b pid=b platform=b p|publish=e pull=b restart=b runtime=b
|
47
47
|
security-opt=q shm-size=b sig-proxy=b? stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q
|
48
48
|
ulimit=q user=e userns=b uts=b v|volume=q volume-driver=b volumes-from=b w|workdir=q].freeze,
|
@@ -61,11 +61,17 @@ module Squared
|
|
61
61
|
}.freeze,
|
62
62
|
image: {
|
63
63
|
list: %w[a|all digests no-trunc f|filter=q format=q].freeze,
|
64
|
-
push: %w[disable-content-trust=b? platform=b q|quiet].freeze,
|
64
|
+
push: %w[a|all-tags disable-content-trust=b? platform=b q|quiet].freeze,
|
65
65
|
rm: %w[f|force no-prune].freeze
|
66
66
|
}.freeze
|
67
67
|
}.freeze
|
68
|
-
|
68
|
+
VAL_DOCKER = {
|
69
|
+
run: {
|
70
|
+
bind: %w[type source src destination dst target readonly ro bind-propagation].freeze,
|
71
|
+
tmpfs: %w[type destination dst target tmpfs-size tmpfs-mode].freeze
|
72
|
+
}.freeze
|
73
|
+
}.freeze
|
74
|
+
private_constant :COMPOSEFILE, :BAKEFILE, :OPT_DOCKER, :VAL_DOCKER
|
69
75
|
|
70
76
|
class << self
|
71
77
|
def tasks
|
@@ -82,7 +88,7 @@ module Squared
|
|
82
88
|
@@tasks[ref] = {
|
83
89
|
'build' => %i[tag context bake].freeze,
|
84
90
|
'compose' => %i[build run exec up].freeze,
|
85
|
-
'image' => %i[list rm].freeze,
|
91
|
+
'image' => %i[list rm push].freeze,
|
86
92
|
'container' => %i[run exec update commit inspect diff start stop restart pause unpause top stats kill
|
87
93
|
rm].freeze
|
88
94
|
}.freeze
|
@@ -90,14 +96,15 @@ module Squared
|
|
90
96
|
attr_reader :context
|
91
97
|
attr_accessor :tag
|
92
98
|
|
93
|
-
def initialize(*, file: nil, context: nil, tag: nil, secrets: nil, registry: nil, **kwargs)
|
99
|
+
def initialize(*, file: nil, context: nil, tag: nil, secrets: nil, mounts: [], registry: nil, **kwargs)
|
94
100
|
super
|
95
101
|
return unless dockerfile(file).exist?
|
96
102
|
|
97
103
|
@context = context
|
98
104
|
@tag = tag || "#{@project}:latest"
|
105
|
+
@mounts = mounts
|
99
106
|
@secrets = secrets
|
100
|
-
@registry = registry
|
107
|
+
@registry = [registry, kwargs[:username]].compact.join('/')
|
101
108
|
initialize_ref Docker.ref
|
102
109
|
initialize_logger(**kwargs)
|
103
110
|
initialize_env(**kwargs)
|
@@ -169,9 +176,18 @@ module Squared
|
|
169
176
|
end
|
170
177
|
end
|
171
178
|
when 'image'
|
172
|
-
|
173
|
-
|
174
|
-
|
179
|
+
case flag
|
180
|
+
when :push
|
181
|
+
format_desc action, flag, 'tag,registry/username?,opts*'
|
182
|
+
task flag, [:tag] do |_, args|
|
183
|
+
tag = param_guard(action, flag, args: args, key: :tag)
|
184
|
+
image(flag, args.to_a.drop(1), id: tag)
|
185
|
+
end
|
186
|
+
else
|
187
|
+
format_desc(action, flag, flag == :rm ? 'id*,opts*' : 'opts*,args*')
|
188
|
+
task flag do |_, args|
|
189
|
+
image flag, args.to_a
|
190
|
+
end
|
175
191
|
end
|
176
192
|
end
|
177
193
|
end
|
@@ -299,7 +315,39 @@ module Squared
|
|
299
315
|
out = option_sanitize(opts, list, first: flag == :exec).first
|
300
316
|
from = :"container:#{flag}"
|
301
317
|
case flag
|
302
|
-
when :
|
318
|
+
when :run, :exec
|
319
|
+
if flag == :run && !session_arg?('mount')
|
320
|
+
run = VAL_DOCKER[:run]
|
321
|
+
both = run[:bind] + run[:tmpfs]
|
322
|
+
diff = run[:bind].reject { |val| run[:tmpfs].include?(val) }
|
323
|
+
delim = Regexp.new(",\\s*(?=#{both.join('|')})")
|
324
|
+
as_a(@mounts).each do |val|
|
325
|
+
args = []
|
326
|
+
tmpfs = true
|
327
|
+
val.split(delim).each do |opt|
|
328
|
+
k, v, q = split_option(opt)
|
329
|
+
next unless both.include?(k)
|
330
|
+
|
331
|
+
if k == 'type'
|
332
|
+
tmpfs = false if v == 'bind'
|
333
|
+
next
|
334
|
+
elsif diff.include?(k)
|
335
|
+
tmpfs = false
|
336
|
+
end
|
337
|
+
case k
|
338
|
+
when 'readonly', 'ro'
|
339
|
+
args << k
|
340
|
+
next
|
341
|
+
when 'source', 'src', 'destination', 'dst', 'target'
|
342
|
+
v = basepath(v)
|
343
|
+
v = shell_quote(v, option: false, force: false) if q == ''
|
344
|
+
tmpfs = false if k[0] == 's'
|
345
|
+
end
|
346
|
+
args << "#{k}=#{q + v + q}"
|
347
|
+
end
|
348
|
+
cmd << "--mount type=#{tmpfs ? 'tmpfs' : 'bind'},#{args.join(',')}"
|
349
|
+
end
|
350
|
+
end
|
303
351
|
append_command(flag, id.to_s.empty? ? tag : id, out, target: cmd, from: from)
|
304
352
|
when :update
|
305
353
|
raise_error('missing container', hint: from) if out.empty?
|
@@ -405,12 +453,14 @@ module Squared
|
|
405
453
|
end
|
406
454
|
when :push
|
407
455
|
id ||= tag
|
456
|
+
registry ||= out.shift || @registry
|
408
457
|
raise_error(id ? "unknown args: #{out.join(', ')}" : 'no id/tag given', hint: from) unless id && out.empty?
|
409
|
-
|
410
|
-
|
458
|
+
raise_error('username/registry not provided', hint: from) unless registry
|
459
|
+
registry.chomp!('/')
|
460
|
+
uri = shell_quote("#{registry}/#{id}")
|
411
461
|
cmd << uri
|
412
462
|
img = docker_output 'image', 'tag', id, uri
|
413
|
-
return unless confirm_command(img.to_s, cmd.to_s, target: id, as:
|
463
|
+
return unless confirm_command(img.to_s, cmd.to_s, target: id, as: registry, title: from)
|
414
464
|
|
415
465
|
run(img, exception: true, sync: false, banner: false)
|
416
466
|
end
|
@@ -145,6 +145,8 @@ module Squared
|
|
145
145
|
|
146
146
|
module Project
|
147
147
|
class Git < Base
|
148
|
+
include Prompt
|
149
|
+
|
148
150
|
OPT_GIT = {
|
149
151
|
common: %w[bare p|paginate P|no-pager glob-pathspecs icase-pathspecs literal-pathspecs no-optional-locks
|
150
152
|
no-replace-objects noglob-pathspecs c=q config-env=q exec-path=p namespace=p].freeze,
|
@@ -300,10 +302,6 @@ module Squared
|
|
300
302
|
%i[pull rebase fetch clone stash status branch revbuild].freeze
|
301
303
|
end
|
302
304
|
|
303
|
-
def batchargs
|
304
|
-
[ref, { 'pull+s': %i[stash pull], 'rebase+s': %i[stash rebase] }]
|
305
|
-
end
|
306
|
-
|
307
305
|
def config?(val)
|
308
306
|
return false unless (val = as_path(val))
|
309
307
|
|
@@ -326,8 +324,8 @@ module Squared
|
|
326
324
|
'refs' => %i[heads tags remote].freeze,
|
327
325
|
'reset' => %i[commit index patch mode].freeze,
|
328
326
|
'rev' => %i[commit branch output parseopt build].freeze,
|
329
|
-
'show' => %i[format oneline].freeze,
|
330
|
-
'stash' => %i[push pop apply drop list].freeze,
|
327
|
+
'show' => %i[format oneline textconv].freeze,
|
328
|
+
'stash' => %i[push pop apply drop clear list].freeze,
|
331
329
|
'tag' => %i[add delete list].freeze
|
332
330
|
}.freeze
|
333
331
|
|
@@ -579,12 +577,18 @@ module Squared
|
|
579
577
|
when :oneline
|
580
578
|
format_desc action, flag, 'opts*,object*'
|
581
579
|
task flag do |_, args|
|
582
|
-
show
|
580
|
+
show flag, args.to_a.push('abbrev-commit')
|
583
581
|
end
|
584
582
|
when :format
|
585
583
|
format_desc action, flag, 'format?,opts*,object*'
|
586
584
|
task flag, [:format] do |_, args|
|
587
|
-
show args.
|
585
|
+
show(flag, args.extras, format: args.format)
|
586
|
+
end
|
587
|
+
when :textconv
|
588
|
+
format_desc action, flag, 'files+'
|
589
|
+
task flag do |_, args|
|
590
|
+
files = param_guard(action, flag, args: args.to_a)
|
591
|
+
show(flag, files: files)
|
588
592
|
end
|
589
593
|
end
|
590
594
|
when 'rebase', 'merge'
|
@@ -783,8 +787,15 @@ module Squared
|
|
783
787
|
when :push
|
784
788
|
append_pathspec refs
|
785
789
|
when :pop, :apply, :drop
|
786
|
-
|
787
|
-
|
790
|
+
unless refs.empty?
|
791
|
+
cmd << shell_escape(refs.pop)
|
792
|
+
option_clear refs
|
793
|
+
end
|
794
|
+
when :clear
|
795
|
+
if confirm("Remove #{sub_style('all', styles: theme[:active])} the stash entries? [y/N] ", 'N')
|
796
|
+
source(stdout: true)
|
797
|
+
end
|
798
|
+
return
|
788
799
|
when :list
|
789
800
|
out, banner, from = source(io: true)
|
790
801
|
print_item banner
|
@@ -1218,8 +1229,21 @@ module Squared
|
|
1218
1229
|
source(stdout: stdout)
|
1219
1230
|
end
|
1220
1231
|
|
1221
|
-
def show(
|
1232
|
+
def show(flag, opts = [], format: nil, files: [])
|
1222
1233
|
cmd, opts = git_session('show', opts: opts)
|
1234
|
+
case flag
|
1235
|
+
when :textconv
|
1236
|
+
cmd << '--textconv'
|
1237
|
+
files = files.map { |val| Dir[val] }
|
1238
|
+
.flatten
|
1239
|
+
.select { |val| projectpath?(val) }
|
1240
|
+
.map { |val| shell_quote("HEAD:#{val}") }
|
1241
|
+
append_value files
|
1242
|
+
source(banner: false)
|
1243
|
+
return
|
1244
|
+
when :oneline
|
1245
|
+
format = flag.to_s
|
1246
|
+
end
|
1223
1247
|
if format
|
1224
1248
|
case (val = format.downcase)
|
1225
1249
|
when 'oneline', 'short', 'medium', 'full', 'fuller', 'reference', 'email', 'raw'
|
@@ -39,7 +39,6 @@ module Squared
|
|
39
39
|
|
40
40
|
class << self
|
41
41
|
def populate(*); end
|
42
|
-
def batchargs(*); end
|
43
42
|
|
44
43
|
def tasks
|
45
44
|
[:outdated].freeze
|
@@ -155,7 +154,7 @@ module Squared
|
|
155
154
|
when 'gem'
|
156
155
|
case flag
|
157
156
|
when :outdated, :build, :push, :exec
|
158
|
-
format_desc
|
157
|
+
format_desc(action, flag, 'opts*', before: flag == :exec ? 'command+' : nil)
|
159
158
|
task flag do |_, args|
|
160
159
|
gemx flag, args.to_a
|
161
160
|
end
|
@@ -471,7 +470,7 @@ module Squared
|
|
471
470
|
end
|
472
471
|
when :exec
|
473
472
|
raise_error('no command given', hint: flag) if out.empty?
|
474
|
-
cmd << out.join(' ')
|
473
|
+
cmd << project << out.join(' ')
|
475
474
|
else
|
476
475
|
raise_error('no gemname given', hint: flag) if out.empty? && !session_arg?('system')
|
477
476
|
if flag == :pristine
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: squared
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- An Pham
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-21 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rake
|