coaster 1.4.28 → 1.4.30

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: e53b6e577599120b7264569f9164e783b61563cd90255c55fc4608554c78d001
4
- data.tar.gz: f7f410d4712a9ebfc57a44ebd1bd239471ec04222e25e79964b180a35ab14178
3
+ metadata.gz: d39beeaee29be2896e13ec86ba9e0a9c581a424d8886757e3478fe7283350276
4
+ data.tar.gz: dec06f3400a4e5be9f95987fddca45d04ed41cdc991070455361bb2463d91cb0
5
5
  SHA512:
6
- metadata.gz: 2a16047f7c323c9baca6b71b13b410d3fb26639951457d6ab71c756e9dc3bac613fb0bc19afb352ce9613924b6283cc9f4d6da206355a76791af7a354b411c1b
7
- data.tar.gz: 3a5806e48fdc46c314d60cb4e2926561e7ef2e31a642c2e0eb52cf34fbb6507bc012b6b4b0949232d9b7c1fcf72abf60dc6fc29dbfc5befe954c8ba832488c9d
6
+ metadata.gz: 384a1e5564c587f06901aecceb71de37b70fb51353f205067b966cd525dfda3b16c81a7bbd3830740da68c448a3b0c756f117e372d0343bc8f871e5b8192c204
7
+ data.tar.gz: ac1b741ff50422d42335e96ba32e6c2362571452c5c425d27b27bb72822c9f99932540eacb37f19e908b51c3f160cf3fe9d8b2300ad3deb651a6b8c100cdb881
@@ -8,15 +8,4 @@ class Array
8
8
  true
9
9
  end
10
10
  end
11
-
12
- def deep_key_count(**options)
13
- sum do |v|
14
- case v
15
- when Hash, Array
16
- v.deep_key_count
17
- else
18
- 1
19
- end
20
- end
21
- end
22
11
  end
@@ -0,0 +1,43 @@
1
+ module Coaster
2
+ module CssHashString
3
+ module HashToStyle
4
+ def to_css_style(**defaults)
5
+ to_css_hash(**defaults).map do |k, v|
6
+ k = k.gsub(/_/, '-')
7
+ v.present? ? "#{k}:#{v}" : nil
8
+ end.compact.join(';')
9
+ end
10
+
11
+ def to_css_hash(**defaults)
12
+ defaults = defaults.map do |k, v|
13
+ k = k.to_s.gsub(/_/, '-')
14
+ v.present? ? [k, v] : nil
15
+ end.compact.to_h
16
+ h = self.map do |k, v|
17
+ k = k.to_s.gsub(/_/, '-')
18
+ v.present? ? [k, v] : nil
19
+ end.compact.to_h
20
+ defaults.merge(h)
21
+ end
22
+ end
23
+ ::Hash.send(:include, HashToStyle)
24
+ ::ActiveSupport::HashWithIndifferentAccess.send(:include, HashToStyle)
25
+
26
+ module StringToStyle
27
+ def to_css_style(**defaults)
28
+ return self unless defaults.present?
29
+ to_css_hash(**defaults).to_css_style
30
+ end
31
+
32
+ def to_css_hash(**defaults)
33
+ defaults.with_indifferent_access.merge(
34
+ self.split(';').map do |pair|
35
+ k, v = pair.split(':')
36
+ [k.strip, v.strip]
37
+ end.to_h
38
+ )
39
+ end
40
+ end
41
+ ::String.send(:include, StringToStyle)
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ module Coaster
2
+ module DeepKeyCount
3
+ module HashCnt
4
+ def deep_key_count(**options)
5
+ keys.size + values.sum do |v|
6
+ case v
7
+ when Hash
8
+ v.deep_key_count(**options)
9
+ when Array
10
+ if options[:array_is_element]
11
+ 0
12
+ else
13
+ v.deep_key_count(**options)
14
+ end
15
+ else
16
+ 0
17
+ end
18
+ end
19
+ end
20
+ end
21
+ ::Hash.send(:include, HashCnt)
22
+ ::ActiveSupport::HashWithIndifferentAccess.send(:include, HashCnt)
23
+
24
+ module ArrayCnt
25
+ def deep_key_count(**options)
26
+ sum do |v|
27
+ case v
28
+ when Hash
29
+ v.deep_key_count(**options)
30
+ when Array
31
+ if options[:array_is_element]
32
+ 1
33
+ else
34
+ v.deep_key_count(**options)
35
+ end
36
+ else
37
+ 1
38
+ end
39
+ end
40
+ end
41
+ end
42
+ ::Array.send(:include, ArrayCnt)
43
+ end
44
+ end
@@ -1,18 +1,2 @@
1
1
  class Hash
2
- def deep_key_count(**options)
3
- keys.size + values.sum do |v|
4
- case v
5
- when Hash
6
- v.deep_key_count(**options)
7
- when Array
8
- if options[:array_is_element]
9
- 0
10
- else
11
- v.deep_key_count(**options)
12
- end
13
- else
14
- 0
15
- end
16
- end
17
- end
18
2
  end
@@ -0,0 +1,85 @@
1
+ require 'objspace'
2
+
3
+ class Object
4
+ def memory_size(depth: 2, object_ids: [])
5
+ res = {nil => ObjectSpace.memsize_of(self)}
6
+ instance_variables.each do |var|
7
+ iv = instance_variable_get(var)
8
+ if object_ids.include?(iv.object_id)
9
+ res[var] = nil
10
+ else
11
+ object_ids << iv.object_id
12
+ if depth > 0
13
+ res[var] = iv.memory_size(depth: depth - 1, object_ids:)
14
+ else
15
+ res[var] = iv.memory_size_total(object_ids:)
16
+ end
17
+ end
18
+ end
19
+ res
20
+ end
21
+
22
+ def memory_size_total(object_ids: [])
23
+ sum = 0
24
+ memory_size(depth: 0, object_ids:).each do |k, v|
25
+ case v
26
+ when Hash, Array then sum += v._memory_size_total
27
+ when nil then next
28
+ else sum += v
29
+ end
30
+ end
31
+ sum
32
+ end
33
+ end
34
+
35
+ class Array
36
+ def memory_size(depth: 2, object_ids: [])
37
+ res = {nil => super}
38
+ each_with_index do |item, x|
39
+ if depth > 0
40
+ res[x] = item.memory_size(depth: depth - 1, object_ids:)
41
+ else
42
+ res[x] = item.memory_size_total(object_ids:)
43
+ end
44
+ end
45
+ res
46
+ end
47
+
48
+ def _memory_size_total
49
+ sum = 0
50
+ each do |item|
51
+ case item
52
+ when Hash, Array then sum += item._memory_size_total
53
+ when nil then next
54
+ else sum += item
55
+ end
56
+ end
57
+ sum
58
+ end
59
+ end
60
+
61
+ class Hash
62
+ def memory_size(depth: 2, object_ids: [])
63
+ res = {nil => super}
64
+ each do |k, v|
65
+ if depth > 0
66
+ res[k] = [k.memory_size(depth: depth - 1, object_ids:), v.memory_size(depth: depth - 1, object_ids:)]
67
+ else
68
+ res[k] = k.memory_size_total(object_ids:) + v.memory_size_total(object_ids:)
69
+ end
70
+ end
71
+ res
72
+ end
73
+
74
+ def _memory_size_total
75
+ sum = 0
76
+ each do |k, v|
77
+ case v
78
+ when Hash, Array then sum += v._memory_size_total
79
+ when nil then next
80
+ else sum += v
81
+ end
82
+ end
83
+ sum
84
+ end
85
+ end
@@ -3,6 +3,33 @@ module Coaster
3
3
  class DuplicatedProperty < StandardError; end
4
4
  class InvalidProperty < StandardError; end
5
5
 
6
+ def self.extended(base)
7
+ base.class_eval do
8
+ def sprop_changes = self.class.serialized_property_changes(changes)
9
+ def sprop_change(key) = sprop_changes[key.to_s]
10
+ def sprop_changed?(key) = sprop_change(key).present?
11
+ def sprop_was(key) = (ch = sprop_change(key)).present? ? ch[0] : nil
12
+
13
+ def sprop_saved_changes = self.class.serialized_property_changes(saved_changes)
14
+ def sprop_saved_change(key) = sprop_saved_changes[key.to_s]
15
+
16
+ def sprop_previous_changes = self.class.serialized_property_changes(previous_changes)
17
+ def sprop_previous_change(key) = sprop_previous_changes[key.to_s]
18
+ def sprop_previously_changed?(key) = sprop_previous_change(key).present?
19
+ def sprop_previously_was(key) = (ch = sprop_previous_change(key)).present? ? ch[0] : nil
20
+ end
21
+ end
22
+
23
+ def serialized_property_changes(changes)
24
+ serialized_property_settings.each_with_object({}) do |(key, prop), result|
25
+ prop_ch = changes[prop[:column].to_s]
26
+ next if prop_ch.blank?
27
+ before = prop_ch[0] && prop_ch[0][key.to_s]
28
+ after = prop_ch[1] && prop_ch[1][key.to_s]
29
+ result[key.to_s] = [before, after] if before != after
30
+ end
31
+ end
32
+
6
33
  def serialized_property_settings
7
34
  @serialized_property_settings ||= {}
8
35
  end
@@ -27,7 +54,7 @@ module Coaster
27
54
 
28
55
  def serialized_property(serialize_column, key, type: nil, comment: nil, getter: nil, setter: nil, setter_callback: nil, default: nil, rescuer: nil)
29
56
  raise DuplicatedProperty, "#{self.name}##{key} duplicated\n#{caller[0..5].join("\n")}" if serialized_property_settings[key.to_sym]
30
- serialized_property_settings[key.to_sym] = {type: type, comment: comment, getter: getter, setter: setter, setter_callback: setter_callback, default: default, rescuer: rescuer}
57
+ serialized_property_settings[key.to_sym] = {column: serialize_column.to_sym, type: type, comment: comment, getter: getter, setter: setter, setter_callback: setter_callback, default: default, rescuer: rescuer}
31
58
  _typed_serialized_property(serialize_column, key, type: type, getter: getter, setter: setter, setter_callback: setter_callback, default: default, rescuer: rescuer)
32
59
  end
33
60
 
@@ -118,6 +145,7 @@ module Coaster
118
145
  elsif type.respond_to?(:serialized_property_serializer) && (serializer = type.serialized_property_serializer)
119
146
  _define_serialized_property(serialize_column, key, getter: serializer[:getter], setter: serializer[:setter], setter_callback: serializer[:setter_callback], default: default)
120
147
  elsif (type.is_a?(Symbol) && (t = type.to_s.constantize rescue nil)) || (type.is_a?(Class) && type < ActiveRecord::Base && (t = type))
148
+ serialized_property_settings["#{key}_id".to_sym] = serialized_property_settings.delete(key.to_sym) # rename key from setting
121
149
  _define_serialized_property serialize_column, "#{key}_id", default: default
122
150
 
123
151
  define_method key.to_sym do
@@ -218,6 +246,25 @@ module Coaster
218
246
  send("#{key}_without_callback=".to_sym, val)
219
247
  end
220
248
  end
249
+
250
+ define_method "#{key}_change".to_sym do
251
+ send("sprop_change", key)
252
+ end
253
+ define_method "#{key}_changed?".to_sym do
254
+ send("sprop_changed?", key)
255
+ end
256
+ define_method "#{key}_was".to_sym do
257
+ send("sprop_was", key)
258
+ end
259
+ define_method "#{key}_previous_change".to_sym do
260
+ send("sprop_previous_change", key)
261
+ end
262
+ define_method "#{key}_previously_changed?".to_sym do
263
+ send("sprop_previously_changed?", key)
264
+ end
265
+ define_method "#{key}_previously_was".to_sym do
266
+ send("sprop_previously_was", key)
267
+ end
221
268
  end
222
269
  end
223
270
  end
@@ -1,3 +1,3 @@
1
1
  module Coaster
2
- VERSION = '1.4.28'
2
+ VERSION = '1.4.30'
3
3
  end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+ require 'minitest/autorun'
3
+ require 'coaster/core_ext/css_hash_string'
4
+
5
+ module Coaster
6
+ class TestCssHashString < Minitest::Test
7
+ def setup
8
+ end
9
+
10
+ def teardown
11
+ end
12
+
13
+ def test_hash_to_style
14
+ assert_equal "font-size:12px;color:red", {"font-size" => '12px', color: 'red'}.to_css_style
15
+ assert_equal "font-size:12px;color:red", {font_size: '12px', color: 'red'}.to_css_style
16
+ assert_equal "font-size:12px;color:red", {font_size: '12px', color: 'red'}.with_indifferent_access.to_css_style
17
+ end
18
+
19
+ def test_string_to_css_hash
20
+ assert_equal({"font-size" => '12px', "color" => 'red'}, "font-size: 12px; color: red".to_css_hash)
21
+ assert_equal({"font-size" => '12px', "color" => 'red'}, "font-size: 12px".to_css_hash(color: 'red'))
22
+ assert_equal({"font-size" => '12px', "color" => 'blue'}, "font-size: 12px; color: blue".to_css_hash(color: 'red'))
23
+ end
24
+ end
25
+ end
@@ -1,5 +1,6 @@
1
1
  require 'test_helper'
2
2
  require 'minitest/autorun'
3
+ require 'coaster/core_ext/deep_key_count'
3
4
 
4
5
  module Coaster
5
6
  class TestDeepKeyCount < Minitest::Test
@@ -25,9 +26,10 @@ module Coaster
25
26
 
26
27
  assert_equal 2, [1, 2].deep_key_count(array_is_element: true)
27
28
  assert_equal 2, [1, {b: 2}].deep_key_count(array_is_element: true)
28
- assert_equal 3, [1, {b: 2, c: [1, 2]}].deep_key_count(array_is_element: true)
29
29
 
30
30
  assert_equal 3, [1, {b: 2}, 3].deep_key_count(array_is_element: true)
31
+
32
+ assert_equal 3, [1, {b: 2, c: [1, 2]}].deep_key_count(array_is_element: true)
31
33
  assert_equal 3, [1, {b: 2}, [3, 4]].deep_key_count(array_is_element: true)
32
34
  end
33
35
  end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'minitest/autorun'
3
+ require 'coaster/core_ext/memory_size'
4
+
5
+ module Coaster
6
+ class TestMemorySize < Minitest::Test
7
+ class Some
8
+ attr_accessor :aa, :bb, :cc
9
+ end
10
+
11
+ def setup
12
+ end
13
+
14
+ def teardown
15
+ end
16
+
17
+ def test_memory_size
18
+ h = {"aa" => 1, "bb" => [2, 3], "cc" => {"dd" => 4}}
19
+ # assert_equal 10, {"aa" => 1, "bb" => [2, 3], "cc" => {"dd" => 4}}.memory_size
20
+ assert_equal({nil => {nil => 160}, "aa" => 40, "bb" => 80, "cc" => 240}, h.memory_size(depth: 0))
21
+ assert_equal 520, h.memory_size_total
22
+ some = Some.new
23
+ some.aa = h
24
+ some.bb = [1, 2, 3]
25
+ some.cc = {"dd" => 4, "ee" => [5, 6]}
26
+ depth_0 = some.memory_size(depth: 0)
27
+ depth_1 = some.memory_size(depth: 1)
28
+ assert_equal({nil => 40, "@aa": 520, "@bb": 40, "@cc": 280}, depth_0)
29
+ assert_equal({nil => 40,
30
+ "@aa": {nil => {nil => 160}, "aa" => 40, "bb" => 80, "cc" => 240},
31
+ "@bb": {nil => {nil => 40}, 0 => 0, 1 => 0, 2 => 0},
32
+ "@cc": {nil => {nil => 160}, "dd" => 40, "ee" => 80}}, depth_1)
33
+ assert_equal 880, some.memory_size_total
34
+ end
35
+ end
36
+ end
@@ -11,6 +11,7 @@ module Coaster
11
11
 
12
12
  def test_serialized
13
13
  user = User.create(name: 'abc')
14
+ assert_equal([:appendix, :father_id, :mother_id], User.serialized_property_settings.keys)
14
15
  user.init_appendix
15
16
  assert_equal 0, user.appendix['test_key1']
16
17
  assert_equal 0, user.appendix['test_key2']
@@ -23,7 +24,13 @@ module Coaster
23
24
  assert_equal mother, user.mother
24
25
  assert_equal mother.id, user.mother_id
25
26
  assert_equal({"appendix"=>{"test_key1"=>0, "test_key2"=>0}, "father_id"=>father.id, "mother_id"=>mother.id}, user.data)
27
+ assert_equal({"appendix" => [nil, {"test_key1" => 0, "test_key2" => 0}], "father_id" => [nil, 2], "mother_id" => [nil, 3]}, user.sprop_changes)
28
+ assert_equal(true, user.mother_id_changed?)
29
+ assert_equal(nil, user.mother_id_was)
26
30
  user.save!
31
+ assert_equal(false, user.mother_id_changed?)
32
+ assert_equal(true, user.mother_id_previously_changed?)
33
+ assert_equal(nil, user.mother_id_previously_was)
27
34
  user = User.find(user.id)
28
35
  assert_equal({"appendix"=>{"test_key1"=>0, "test_key2"=>0}, "father_id"=>father.id, "mother_id"=>mother.id}, user.data)
29
36
  assert_equal mother, user.mother
@@ -211,25 +211,24 @@ module Coaster
211
211
  detail_front = <<-LOG
212
212
  [Coaster::TestStandardError::ExampleError] status:20
213
213
  MESSAGE: Test example error (Coaster::TestStandardError::ExampleError) cause{Test sample error (Coaster::TestStandardError::SampleError)}
214
- @attributes: {\"frog\"=>\"rams\", \"wat\"=>\"cha\"}
214
+ @attributes: {\"frog\" => \"rams\", \"wat\" => \"cha\"}
215
215
  @coaster: true
216
216
  @digest_backtrace: #{e.digest_backtrace}
217
217
  @digest_message: a8c7c1
218
218
  @fingerprint: ["a8c7c1"]
219
- @ins_var: [\"Coaster::TestStandardError::SampleError\", {\"h\"=>1}]
220
- @ins_varr: {\"dd\"=>true}
219
+ @ins_var: [\"Coaster::TestStandardError::SampleError\", {\"h\" => 1}]
220
+ @ins_varr: {\"dd\" => true}
221
221
  @level: \"error\"
222
222
  @raven: {}
223
223
  @tags: {}
224
224
  @tkey: nil
225
225
  BACKTRACE:
226
- #{__FILE__}:193:in `rescue in test_to_detail'
227
- #{__FILE__}:187:in `test_to_detail'
226
+ #{__FILE__}:193:in 'Coaster::TestStandardError#test_to_detail'
228
227
  LOG
229
228
  detail_cause_front = <<-LOG
230
229
  CAUSE: [Coaster::TestStandardError::SampleError] status:10
231
230
  MESSAGE: Test sample error (Coaster::TestStandardError::SampleError)
232
- @attributes: {"frog"=>"rams"}
231
+ @attributes: {"frog" => "rams"}
233
232
  @coaster: true
234
233
  @digest_backtrace: #{e.cause.digest_backtrace}
235
234
  @digest_message: cbe233
@@ -239,7 +238,7 @@ CAUSE: [Coaster::TestStandardError::SampleError] status:10
239
238
  @tags: {}
240
239
  @tkey: nil
241
240
  BACKTRACE:
242
- #{__FILE__}:188:in `test_to_detail'
241
+ #{__FILE__}:188:in 'Coaster::TestStandardError#test_to_detail'
243
242
  LOG
244
243
  assert detail.start_with?(detail_front)
245
244
  cause_ix = (detail =~ /CAUSE/)
@@ -331,7 +330,7 @@ LOG
331
330
  assert_equal 999999, e.to_hash['status']
332
331
  assert_equal 500, e.to_hash['http_status']
333
332
  assert_equal "standard error translation (#{e.digest_message} #{bt})", e.user_message
334
- assert_match(/undefined local variable or method `aa'/, e.to_hash['message'])
333
+ assert_match(/undefined local variable or method 'aa'/, e.to_hash['message'])
335
334
  end
336
335
 
337
336
  def test_descriptions
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.28
4
+ version: 1.4.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - buzz jung
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-27 00:00:00.000000000 Z
11
+ date: 2025-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -194,8 +194,11 @@ files:
194
194
  - lib/coaster/cmd_options.rb
195
195
  - lib/coaster/core_ext.rb
196
196
  - lib/coaster/core_ext/array.rb
197
+ - lib/coaster/core_ext/css_hash_string.rb
197
198
  - lib/coaster/core_ext/date.rb
199
+ - lib/coaster/core_ext/deep_key_count.rb
198
200
  - lib/coaster/core_ext/hash.rb
201
+ - lib/coaster/core_ext/memory_size.rb
199
202
  - lib/coaster/core_ext/month.rb
200
203
  - lib/coaster/core_ext/object_translation.rb
201
204
  - lib/coaster/core_ext/require_more.rb
@@ -221,12 +224,14 @@ files:
221
224
  - test/support/schema.rb
222
225
  - test/test_action_view.rb
223
226
  - test/test_backtrace.rb
227
+ - test/test_css_hash_string.rb
224
228
  - test/test_date.rb
225
229
  - test/test_deep_key_count.rb
226
230
  - test/test_git.rb
227
231
  - test/test_git_options.rb
228
232
  - test/test_git_repository.rb
229
233
  - test/test_helper.rb
234
+ - test/test_memory_size.rb
230
235
  - test/test_month.rb
231
236
  - test/test_object_translation.rb
232
237
  - test/test_serialized_property.rb
@@ -264,12 +269,14 @@ test_files:
264
269
  - test/support/schema.rb
265
270
  - test/test_action_view.rb
266
271
  - test/test_backtrace.rb
272
+ - test/test_css_hash_string.rb
267
273
  - test/test_date.rb
268
274
  - test/test_deep_key_count.rb
269
275
  - test/test_git.rb
270
276
  - test/test_git_options.rb
271
277
  - test/test_git_repository.rb
272
278
  - test/test_helper.rb
279
+ - test/test_memory_size.rb
273
280
  - test/test_month.rb
274
281
  - test/test_object_translation.rb
275
282
  - test/test_serialized_property.rb