activemodel_object_info 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4fbb93d73230b877ddef2d140e3735c97b4bbf10f03273401f4be77f5540dbdd
4
- data.tar.gz: a758c1d6b7623810b01f0379d700e4e70d7ecc8d0c013c86592be06cae68b1eb
3
+ metadata.gz: 06251d26eb8e76bce7322a0828b75bddf9130227aca347632ffccd1000c8de38
4
+ data.tar.gz: 6204ace6d5d12156f491905df5b85a21a642fc2419b7029fb27071665ff5672a
5
5
  SHA512:
6
- metadata.gz: ea99c0ec6222036125acf0143a51832c70d4146f4b9b7f5e70277405d92f5819fc1d9d389ee9063d1f6b7998d06eebe873a9f465783873f7b50168dfbea6e960
7
- data.tar.gz: 8fc1a83c8c641f97de5b188dbeddeb89f7be52524074d95a515546606bff1a08ab38e244296249aebd3d8bca9f4311ad5108af788c97710030ff04e9cfa1a4ea
6
+ metadata.gz: 1e8032eeefb546d83ec9ec07b3c1812dd59fa325d6b80c9e96cd8cd52aaaa955f2f700b01ee74895db3bfab7d514d428d429bd139ba4051d1c379824f0156a55
7
+ data.tar.gz: 67e9ec9cd9fa34310b8b5fd525dbf2f2e7bd7f567351f4e87d78d0dbe9f81a55a316d283658ca95d10c3e904d6743fb406c684bafebc0dfd94c47d375ce38816
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -3,6 +3,7 @@ AllCops:
3
3
  - 'bin/**/*'
4
4
  - 'examples/**/*'
5
5
  NewCops: enable
6
+ SuggestExtensions: false
6
7
 
7
8
  # 弱ruby版本的gem,所有目前不需要检测ruby版本
8
9
  Gemspec/RequiredRubyVersion:
data/Gemfile.lock CHANGED
@@ -1,63 +1,93 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activemodel_object_info (0.1.6)
5
- activerecord
4
+ activemodel_object_info (0.2.0)
6
5
  activesupport
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
10
9
  specs:
11
- activemodel (5.2.4.1)
12
- activesupport (= 5.2.4.1)
13
- activerecord (5.2.4.1)
14
- activemodel (= 5.2.4.1)
15
- activesupport (= 5.2.4.1)
16
- arel (>= 9.0)
17
- activesupport (5.2.4.1)
10
+ activemodel (6.1.4.4)
11
+ activesupport (= 6.1.4.4)
12
+ activerecord (6.1.4.4)
13
+ activemodel (= 6.1.4.4)
14
+ activesupport (= 6.1.4.4)
15
+ activesupport (6.1.4.4)
18
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
19
- i18n (>= 0.7, < 2)
20
- minitest (~> 5.1)
21
- tzinfo (~> 1.1)
22
- arel (9.0.0)
23
- ast (2.4.1)
24
- concurrent-ruby (1.1.5)
25
- i18n (1.8.2)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
20
+ zeitwerk (~> 2.3)
21
+ ast (2.4.2)
22
+ coderay (1.1.3)
23
+ concurrent-ruby (1.1.9)
24
+ diff-lcs (1.5.0)
25
+ docile (1.4.0)
26
+ i18n (1.8.11)
26
27
  concurrent-ruby (~> 1.0)
27
- minitest (5.14.0)
28
- parallel (1.20.1)
29
- parser (3.0.0.0)
28
+ method_source (1.0.0)
29
+ minitest (5.15.0)
30
+ parallel (1.21.0)
31
+ parser (3.0.3.2)
30
32
  ast (~> 2.4.1)
33
+ pry (0.14.1)
34
+ coderay (~> 1.1)
35
+ method_source (~> 1.0)
31
36
  rainbow (3.0.0)
32
- rake (10.5.0)
33
- regexp_parser (2.0.3)
34
- rexml (3.2.4)
35
- rubocop (1.7.0)
37
+ rake (13.0.6)
38
+ regexp_parser (2.2.0)
39
+ rexml (3.2.5)
40
+ rspec (3.10.0)
41
+ rspec-core (~> 3.10.0)
42
+ rspec-expectations (~> 3.10.0)
43
+ rspec-mocks (~> 3.10.0)
44
+ rspec-core (3.10.1)
45
+ rspec-support (~> 3.10.0)
46
+ rspec-expectations (3.10.1)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.10.0)
49
+ rspec-mocks (3.10.2)
50
+ diff-lcs (>= 1.2.0, < 2.0)
51
+ rspec-support (~> 3.10.0)
52
+ rspec-support (3.10.3)
53
+ rubocop (1.24.0)
36
54
  parallel (~> 1.10)
37
- parser (>= 2.7.1.5)
55
+ parser (>= 3.0.0.0)
38
56
  rainbow (>= 2.2.2, < 4.0)
39
57
  regexp_parser (>= 1.8, < 3.0)
40
58
  rexml
41
- rubocop-ast (>= 1.2.0, < 2.0)
59
+ rubocop-ast (>= 1.15.0, < 2.0)
42
60
  ruby-progressbar (~> 1.7)
43
- unicode-display_width (>= 1.4.0, < 2.0)
44
- rubocop-ast (1.4.0)
45
- parser (>= 2.7.1.5)
61
+ unicode-display_width (>= 1.4.0, < 3.0)
62
+ rubocop-ast (1.15.1)
63
+ parser (>= 3.0.1.1)
46
64
  ruby-progressbar (1.11.0)
47
- thread_safe (0.3.6)
48
- tzinfo (1.2.6)
49
- thread_safe (~> 0.1)
50
- unicode-display_width (1.7.0)
51
- yard (0.9.20)
65
+ simplecov (0.21.2)
66
+ docile (~> 1.1)
67
+ simplecov-html (~> 0.11)
68
+ simplecov_json_formatter (~> 0.1)
69
+ simplecov-html (0.12.3)
70
+ simplecov_json_formatter (0.1.3)
71
+ tzinfo (2.0.4)
72
+ concurrent-ruby (~> 1.0)
73
+ unicode-display_width (2.1.0)
74
+ webrick (1.7.0)
75
+ yard (0.9.27)
76
+ webrick (~> 1.7.0)
77
+ zeitwerk (2.5.2)
52
78
 
53
79
  PLATFORMS
54
80
  ruby
55
81
 
56
82
  DEPENDENCIES
57
83
  activemodel_object_info!
84
+ activerecord
58
85
  bundler
59
- rake (~> 10.0)
86
+ pry
87
+ rake
88
+ rspec
60
89
  rubocop
90
+ simplecov
61
91
  yard
62
92
 
63
93
  BUNDLED WITH
data/Rakefile CHANGED
@@ -1,4 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
4
8
  task default: :spec
9
+
10
+ task :console do
11
+ ruby 'bin/console'
12
+ end
13
+ task c: :console
@@ -30,11 +30,17 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ['lib']
32
32
 
33
- spec.add_dependency 'activerecord'
34
33
  spec.add_dependency 'activesupport'
35
34
 
35
+ spec.add_development_dependency 'activerecord'
36
36
  spec.add_development_dependency 'bundler'
37
- spec.add_development_dependency 'rake', '~> 10.0'
37
+ spec.add_development_dependency 'pry'
38
+ spec.add_development_dependency 'rake'
39
+ spec.add_development_dependency 'rspec'
38
40
  spec.add_development_dependency 'rubocop'
41
+ spec.add_development_dependency 'simplecov'
39
42
  spec.add_development_dependency 'yard'
43
+ spec.metadata = {
44
+ 'rubygems_mfa_required' => 'false',
45
+ }
40
46
  end
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "activemodel/object/info"
3
+ require 'bundler/setup'
4
+ require 'activemodel_object_info'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "activemodel/object/info"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
14
- IRB.start(__FILE__)
13
+ require 'pry'
14
+ Pry.start
@@ -7,6 +7,21 @@ module ActivemodelObjectInfo
7
7
  # @author shiner527 <shiner527@hotmail.com>
8
8
  #
9
9
  module Base
10
+ # ===== 常量定义 =====
11
+
12
+ # 满格式
13
+ DATETIME_FULL = '%Y-%m-%d %H:%M:%S'
14
+ # 截止到分
15
+ DATETIME_MIN = '%Y-%m-%d %H:%M'
16
+ # 仅日期
17
+ DATETIME_DATE = '%Y-%m-%d'
18
+ # 仅年月
19
+ DATETIME_MONTH = '%Y-%m'
20
+ # 仅年份
21
+ DATETIME_YEAR = '%Y'
22
+
23
+ # ===== 方法定义 =====
24
+
10
25
  #
11
26
  # 对象信息输出。主要返回给前端一个可用的散列(会被转化为JSON格式)格式的信息并传递给前端。
12
27
  #
@@ -83,10 +98,15 @@ module ActivemodelObjectInfo
83
98
  attribute_format = current_attr_config[:format].present? ? current_attr_config[:format] : options[:datetime_format]
84
99
  result[attribute_name] = if attribute_format.to_s == 'standard' # 会被转换为标准时间日期格式
85
100
  v
86
- elsif attribute_format.present? # 按照设定的 format_date 方法的格式
87
- v.format_date(attribute_format.to_sym)
101
+ elsif attribute_format.present? # 按照设定时间日期方法的格式
102
+ # 旧有格式匹配支持
103
+ if %i[full min date month year].include?(attribute_format.to_sym)
104
+ v.strftime("::#{self.class}::DATETIME_#{attribute_format.to_s.upcase}".constantize)
105
+ else # 否则认为直接传递的是 strftime 支持的自定义格式
106
+ v.strftime(attribute_format)
107
+ end
88
108
  else # 默认使用 'yyyy-MM-dd hh:mm:ss' 的格式
89
- v.format_date(:full)
109
+ v.strftime(DATETIME_FULL)
90
110
  end
91
111
  else # 其他值类型默认赋值自己
92
112
  result[attribute_name] = v
@@ -12,8 +12,9 @@ module ActivemodelObjectInfo
12
12
  # 当被 include 关键字引入后的处理
13
13
  included do |_|
14
14
  # 定义好默认的删除查询语句
15
- deleted_field = ::Constants::Base::TABLE_COLUMN_DELETE_COLUMN
16
- deleted_value_valid = ::Constants::Base::TABLE_COLUMN_DELETE_VALID
15
+ deleted_field = 'deleted'
16
+ deleted_value_valid = 0
17
+ deleted_value_invalid = 1
17
18
  default_scope { where(deleted_field.to_sym => deleted_value_valid) }
18
19
 
19
20
  # 通用的删除过程
@@ -25,15 +26,15 @@ module ActivemodelObjectInfo
25
26
  raise ArgumentError, 'Must give user id!' if options[:user_id].blank?
26
27
 
27
28
  # 获取更新人字段,删除人字段
28
- updated_by_field = (options[:updated_by_field] || "#{::Constants::Base::TABLE_COLUMN_UPDATED_COLUMN}_by").to_sym
29
- deleted_by_field = (options[:deleted_by_field] || "#{::Constants::Base::TABLE_COLUMN_DELETE_COLUMN}_by").to_sym
30
- deleted_at_field = (options[:deleted_at_field] || "#{::Constants::Base::TABLE_COLUMN_DELETE_COLUMN}_at").to_sym
29
+ updated_by_field = (options[:updated_by_field] || 'updated_by').to_sym
30
+ deleted_by_field = (options[:deleted_by_field] || 'deleted_by').to_sym
31
+ deleted_at_field = (options[:deleted_at_field] || 'deleted_at').to_sym
31
32
  # 设置删除状态为已失效
32
- __send__("#{deleted_field}=", ::Constants::Base::TABLE_COLUMN_DELETE_INVALID)
33
+ __send__("#{deleted_field}=", deleted_value_invalid)
33
34
  # 设置删除人、删除时间和更新人
34
35
  __send__("#{deleted_by_field}=", options[:user_id]) if respond_to?(deleted_by_field)
35
36
  __send__("#{deleted_at_field}=", Time.now.localtime) if respond_to?(deleted_at_field)
36
- __send__("#{updated_by_field}=", options[:user_id]) if respond_to?(updated_by_field)
37
+ __send__("#{updated_by_field}=", options[:user_id]) if respond_to?(updated_by_field) && options[:refresh_updated]
37
38
  end
38
39
 
39
40
  # 定义删除方法,但是不覆盖 ActiveRecord 的同名方法。
@@ -64,22 +64,15 @@ module ActivemodelObjectInfo
64
64
  #
65
65
  # @param [Symbol, String] operations 对应的操作。默认会给出 +:created+ 、 +:updated+ 和 +:deleted+ 三个操作名。
66
66
  # 如果参数中的给出操作名含有 +:deleted+ 或者 +'deleted'+ 时,还会生成默认名称为 <b>deleted</b> 整形数字段,用来标识当前记录是否被删除。
67
- # 这里该字段的名称由常量 {Constants::Base::TABLE_COLUMN_DELETE_COLUMN} 设定。
68
67
  # 默认值为可用的记录标记值。由常量 {Constants::Base::TABLE_COLUMN_DELETE_DEFAULT} 设定。
69
68
  #
70
69
  def generate_operations(*operations)
71
70
  # puts "generate_operations(#{operations})"
72
71
  action_fields = operations
73
72
  # 默认只有创建、更新和删除相关的字段
74
- if action_fields.empty?
75
- action_fields = [
76
- ::Constants::Base::TABLE_COLUMN_CREATED_COLUMN,
77
- ::Constants::Base::TABLE_COLUMN_UPDATED_COLUMN,
78
- ::Constants::Base::TABLE_COLUMN_DELETE_COLUMN,
79
- ]
80
- end
73
+ action_fields = %w[created updated deleted] if action_fields.empty?
81
74
  action_fields.each do |operation|
82
- column(::Constants::Base::TABLE_COLUMN_DELETE_COLUMN, :integer, default: ::Constants::Base::TABLE_COLUMN_DELETE_DEFAULT, comment: '删除标记') if operation.to_sym == :deleted
75
+ column(operation.to_s, :integer, default: 0, comment: '删除标记') if operation.to_sym == :deleted
83
76
  operation_columns(operation)
84
77
  end
85
78
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActivemodelObjectInfo
4
4
  module Version
5
- VERSION = '0.1.6'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'activemodel_object_info/extend'
4
3
  require 'activemodel_object_info/version'
4
+ require 'active_support/all'
5
5
  require 'activemodel_object_info/base'
6
6
  require 'activemodel_object_info/table_definition'
7
7
  require 'activemodel_object_info/deleted_operation'
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemodel_object_info
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - shiner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-19 00:00:00.000000000 Z
11
+ date: 2021-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activerecord
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,13 +25,13 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activesupport
28
+ name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
- type: :runtime
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
@@ -52,20 +52,48 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - "~>"
73
+ - - ">="
60
74
  - !ruby/object:Gem::Version
61
- version: '10.0'
75
+ version: '0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - "~>"
80
+ - - ">="
67
81
  - !ruby/object:Gem::Version
68
- version: '10.0'
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: rubocop
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +108,20 @@ dependencies:
80
108
  - - ">="
81
109
  - !ruby/object:Gem::Version
82
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: yard
85
127
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +146,7 @@ extensions: []
104
146
  extra_rdoc_files: []
105
147
  files:
106
148
  - ".gitignore"
149
+ - ".rspec"
107
150
  - ".rubocop.yml"
108
151
  - ".ruby-gemset"
109
152
  - ".ruby-version"
@@ -120,17 +163,13 @@ files:
120
163
  - lib/activemodel_object_info.rb
121
164
  - lib/activemodel_object_info/base.rb
122
165
  - lib/activemodel_object_info/deleted_operation.rb
123
- - lib/activemodel_object_info/extend.rb
124
- - lib/activemodel_object_info/extends/ruby_generals.rb
125
166
  - lib/activemodel_object_info/table_definition.rb
126
167
  - lib/activemodel_object_info/version.rb
127
168
  homepage: https://github.com/shiner527/activemodel-object-info
128
169
  licenses:
129
170
  - MIT
130
171
  metadata:
131
- homepage_uri: https://github.com/shiner527/activemodel-object-info
132
- source_code_uri: https://github.com/shiner527/activemodel-object-info.git
133
- changelog_uri: https://github.com/shiner527/activemodel-object-info/CHANGELOG
172
+ rubygems_mfa_required: 'false'
134
173
  post_install_message:
135
174
  rdoc_options: []
136
175
  require_paths:
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # 加载扩展
4
- ::Dir.glob('extends/**/*.rb').sort.each do |filename|
5
- require_relative filename
6
- end
@@ -1,99 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # 时间类型相关类通用实例方法定义模块。
5
- #
6
- # @author shiner527 <shiner527@hotmail.com>
7
- #
8
- module TimeInstance
9
- #
10
- # 时间格式化为指定的字符串。
11
- #
12
- # @param [Symbol] type 指定需要转换的具体格式。默认为 +:date+ 类型的格式。
13
- #
14
- # @return [String] 返回转换后的字符串。
15
- #
16
- def format_date(type = :date)
17
- case type
18
- when :full
19
- strftime('%Y-%m-%d %H:%M:%S')
20
- when :min
21
- strftime('%Y-%m-%d %H:%M')
22
- when :date
23
- strftime('%Y-%m-%d')
24
- when :year
25
- strftime('%Y')
26
- end
27
- end
28
- end
29
-
30
- #
31
- # 扩展 Date 类
32
- #
33
- class Date
34
- include ::TimeInstance
35
- end
36
-
37
- #
38
- # 扩展 Time 类
39
- #
40
- class Time
41
- include ::TimeInstance
42
- end
43
-
44
- #
45
- # 扩展 DateTime 类
46
- #
47
- class DateTime
48
- include ::TimeInstance
49
- end
50
-
51
- #
52
- # 扩展 Array 类
53
- #
54
- class Array
55
- #
56
- # 找到数组中为空的元素,并将去掉空元素的结果返回为一个新数组。空的定义由 +blank?+ 方法确定。本方法<b>不会改变</b>数组自身。
57
- #
58
- # @return [Array] 返回不包含空元素的数组作为结果。
59
- #
60
- def compact_blank
61
- result = []
62
- each { |item| result << item unless item.blank? }
63
- result
64
- end
65
-
66
- #
67
- # 去掉空元素并将去掉后的数组作为结果返回。空的定义由 +blank?+ 方法确定。本方法<b>会改变</b>数组自身。
68
- #
69
- # @return [Array] 返回不包含空元素的数组作为结果。
70
- #
71
- def compact_blank!
72
- delete_if(&:blank?)
73
- end
74
- end
75
-
76
- #
77
- # 扩展 Array 类
78
- #
79
- class Hash
80
- #
81
- # 找到散列中键值对的值为空的元素,并将去掉这样的键值对的结果返回为一个新散列。空的定义由 +blank?+ 方法确定。本方法<b>不会改变</b>散列自身。
82
- #
83
- # @return [Array] 返回不包含键值对中值为空元素的散列作为结果。
84
- #
85
- def compact_blank
86
- result = {}
87
- each { |k, v| result[k] = v unless v.blank? }
88
- result
89
- end
90
-
91
- #
92
- # 去掉散列中键值对的值为空的键值对,并将去掉后的散列作为结果返回。空的定义由 +blank?+ 方法确定。本方法<b>会改变</b>散列自身。
93
- #
94
- # @return [Array] 返回不包含键值对中值为空元素的散列作为结果。
95
- #
96
- def compact_blank!
97
- delete_if { |_k, v| v.blank? }
98
- end
99
- end